source: rtems/bsps/m68k/gen68360/console/console.c @ 753873e5

Last change on this file since 753873e5 was 753873e5, checked in by Joel Sherrill <joel@…>, on 03/22/22 at 20:03:30

Update Eric Norum contact info and start to normalize file headers

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 *  SMC1 raw console serial I/O.
3 *
4 *  This driver is an example of `POLLING' or `INTERRUPT' I/O.
5 *
6 *  To run with interrupt-driven I/O, ensure m360_smc1_interrupt
7 *  is set before calling the initialization routine.
8 */
9
10/*
11 * Copyright (c) 1996 Eric Norum <eric@norum.ca>
12 *
13 * COPYRIGHT (c) 1989-1999.
14 * On-Line Applications Research Corporation (OAR).
15 *
16 * The license and distribution terms for this file may be
17 * found in the file LICENSE in this distribution or at
18 * http://www.rtems.org/license/LICENSE.
19 */
20
21#include <termios.h>
22#include <bsp.h>
23#include <rtems/libio.h>
24#include <rtems/console.h>
25#include <rtems/termiostypes.h>
26#include <rtems/m68k/m68360.h>
27
28/*
29 * Declare clock speed -- may be overwritten by downloader or debugger
30 */
31int m360_clock_rate  = 25000000;
32
33/*
34 * Interrupt-driven input buffer
35 * Declare console baud rate -- may also be overwritten
36 */
37int console_baud_rate = 9600;
38
39/*
40 */
41#define RXBUFSIZE  16
42
43/*
44 * Interrupt-driven callback
45 */
46static int m360_smc1_interrupt = 1;
47static void *smc1ttyp;
48
49/*
50 * I/O buffers and pointers to buffer descriptors
51 */
52static volatile char rxBuf[RXBUFSIZE];
53static volatile m360BufferDescriptor_t *smcRxBd, *smcTxBd;
54
55/*
56 * Device-specific routines
57 */
58
59/*
60 * Compute baud-rate-generator configuration register value
61 */
62static int
63smc1BRGC (int baud)
64{
65  int divisor;
66  int div16 = 0;
67
68  divisor = ((m360_clock_rate / 16) + (baud / 2)) / baud;
69  if (divisor > 4096) {
70    div16 = 1;
71    divisor = (divisor + 8) / 16;
72  }
73  return M360_BRG_EN | M360_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
74}
75
76/*
77 * Hardware-dependent portion of tcsetattr().
78 */
79static int
80smc1SetAttributes (int minor, const struct termios *t)
81{
82  int baud;
83
84  baud = rtems_termios_baud_to_number(t->c_ospeed);
85  if (baud > 0)
86    m360.brgc1 = smc1BRGC (baud);
87  return 0;
88}
89
90/*
91 * Interrupt handler
92 */
93static rtems_isr
94smc1InterruptHandler (rtems_vector_number v)
95{
96  /*
97   * Buffer received?
98   */
99  if (m360.smc1.smce & 0x1) {
100    m360.smc1.smce = 0x1;
101    while ((smcRxBd->status & M360_BD_EMPTY) == 0) {
102      rtems_termios_enqueue_raw_characters (smc1ttyp,
103              (char *)smcRxBd->buffer,
104              smcRxBd->length);
105      smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
106    }
107  }
108
109  /*
110   * Buffer transmitted?
111   */
112  if (m360.smc1.smce & 0x2) {
113    m360.smc1.smce = 0x2;
114    if ((smcTxBd->status & M360_BD_READY) == 0)
115      rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
116  }
117  m360.cisr = 1UL << 4;  /* Clear SMC1 interrupt-in-service bit */
118}
119
120static int
121smc1Initialize (int major, int minor, void *arg)
122{
123  /*
124   * Allocate buffer descriptors
125   */
126  smcRxBd = M360AllocateBufferDescriptors (1);
127  smcTxBd = M360AllocateBufferDescriptors (1);
128
129  /*
130   * Configure port B pins to enable SMTXD1 and SMRXD1 pins
131   */
132  m360.pbpar |=  0xC0;
133  m360.pbdir &= ~0xC0;
134  m360.pbodr &= ~0xC0;
135
136  /*
137   * Set up BRG1 (9,600 baud)
138   */
139  m360.brgc1 = M360_BRG_RST;
140  m360.brgc1 = smc1BRGC (console_baud_rate);
141
142  /*
143   * Put SMC1 in NMSI mode, connect SMC1 to BRG1
144   */
145  m360.simode |= M360_SI_SMC1_BRG1;
146
147  /*
148   * Set up SMC1 parameter RAM common to all protocols
149   */
150  m360.smc1p.rbase = (char *)smcRxBd - (char *)&m360;
151  m360.smc1p.tbase = (char *)smcTxBd - (char *)&m360;
152  m360.smc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
153  m360.smc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
154  if (m360_smc1_interrupt)
155    m360.smc1p.mrblr = RXBUFSIZE;
156  else
157    m360.smc1p.mrblr = 1;
158
159  /*
160   * Set up SMC1 parameter RAM UART-specific parameters
161   */
162  m360.smc1p.un.uart.max_idl = 10;
163  m360.smc1p.un.uart.brklen = 0;
164  m360.smc1p.un.uart.brkec = 0;
165  m360.smc1p.un.uart.brkcr = 0;
166
167  /*
168   * Set up the Receive Buffer Descriptor
169   */
170  smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
171  smcRxBd->length = 0;
172  smcRxBd->buffer = rxBuf;
173
174  /*
175   * Setup the Transmit Buffer Descriptor
176   */
177  smcTxBd->status = M360_BD_WRAP;
178
179  /*
180   * Set up SMC1 general and protocol-specific mode registers
181   */
182  m360.smc1.smce = ~0;  /* Clear any pending events */
183  m360.smc1.smcm = 0;  /* Mask all interrupt/event sources */
184  m360.smc1.smcmr = M360_SMCMR_CLEN(9) | M360_SMCMR_SM_UART;
185
186  /*
187   * Send "Init parameters" command
188   */
189  M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SMC1);
190
191  /*
192   * Enable receiver and transmitter
193   */
194  m360.smc1.smcmr |= M360_SMCMR_TEN | M360_SMCMR_REN;
195
196  if (m360_smc1_interrupt) {
197  rtems_isr_entry old_handler;
198
199  (void) rtems_interrupt_catch (smc1InterruptHandler,
200            (m360.cicr & 0xE0) | 0x04,
201            &old_handler);
202  m360.smc1.smcm = 3;  /* Enable SMC1 TX and RX interrupts */
203  m360.cimr |= 1UL << 4;  /* Enable SMC1 interrupts */
204  }
205
206  return 0;
207}
208
209static int
210smc1PollRead (int minor)
211{
212  unsigned char c;
213
214  if (smcRxBd->status & M360_BD_EMPTY)
215    return -1;
216  c = rxBuf[0];
217  smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP;
218  return c;
219}
220
221/*
222 * Device-dependent write routine
223 * Interrupt-driven devices:
224 *  Begin transmission of as many characters as possible (minimum is 1).
225 * Polling devices:
226 *  Transmit all characters.
227 */
228static ssize_t
229smc1InterruptWrite (int minor, const char *buf, size_t len)
230{
231  if (len > 0) {
232    smcTxBd->buffer = (char *)buf;
233    smcTxBd->length = len;
234    smcTxBd->status = M360_BD_READY | M360_BD_WRAP | M360_BD_INTERRUPT;
235  }
236
237  return 0;
238}
239
240static ssize_t
241smc1PollWrite (int minor, const char *buf, size_t len)
242{
243  size_t retval = len;
244  while (len--) {
245    static char txBuf;
246    while (smcTxBd->status & M360_BD_READY)
247      continue;
248    txBuf = *buf++;
249    smcTxBd->buffer = &txBuf;
250    smcTxBd->length = 1;
251    smcTxBd->status = M360_BD_READY | M360_BD_WRAP;
252  }
253  return retval;
254}
255
256/*
257 ***************
258 * BOILERPLATE *
259 ***************
260 */
261
262/*
263 * Reserve resources consumed by this driver
264 *
265 * NOTE: This is in another file to reduce dependencies on the minimum size.
266 */
267
268/*
269 * Initialize and register the device
270 */
271rtems_device_driver console_initialize(
272  rtems_device_major_number  major,
273  rtems_device_minor_number  minor,
274  void                      *arg
275)
276{
277  rtems_status_code status;
278
279  /*
280   * Set up TERMIOS
281   */
282  rtems_termios_initialize ();
283
284  /*
285   * Register the device
286   */
287  status = rtems_io_register_name ("/dev/console", major, 0);
288  if (status != RTEMS_SUCCESSFUL)
289    rtems_fatal_error_occurred (status);
290  return RTEMS_SUCCESSFUL;
291}
292
293/*
294 * Open the device
295 */
296rtems_device_driver console_open(
297  rtems_device_major_number major,
298  rtems_device_minor_number minor,
299  void                    * arg
300)
301{
302  rtems_status_code sc;
303  static const rtems_termios_callbacks intrCallbacks = {
304    smc1Initialize,    /* firstOpen */
305    NULL,      /* lastClose */
306    NULL,      /* pollRead */
307    smc1InterruptWrite,  /* write */
308    smc1SetAttributes,  /* setAttributes */
309    NULL,      /* stopRemoteTx */
310    NULL,      /* startRemoteTx */
311    1      /* outputUsesInterrupts */
312  };
313  static const rtems_termios_callbacks pollCallbacks = {
314    smc1Initialize,    /* firstOpen */
315    NULL,      /* lastClose */
316    smc1PollRead,    /* pollRead */
317    smc1PollWrite,    /* write */
318    smc1SetAttributes,  /* setAttributes */
319    NULL,      /* stopRemoteTx */
320    NULL,      /* startRemoteTx */
321    0      /* outputUsesInterrupts */
322  };
323
324  /*
325   * Do generic termios initialization
326   */
327  if (m360_smc1_interrupt) {
328    rtems_libio_open_close_args_t *args = arg;
329
330    sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
331    smc1ttyp = args->iop->data1;
332  }
333  else {
334    sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
335  }
336  return sc;
337}
338
339/*
340 * Close the device
341 */
342rtems_device_driver console_close(
343  rtems_device_major_number major,
344  rtems_device_minor_number minor,
345  void                    * arg
346)
347{
348  return rtems_termios_close (arg);
349}
350
351/*
352 * Read from the device
353 */
354rtems_device_driver console_read(
355  rtems_device_major_number major,
356  rtems_device_minor_number minor,
357  void                    * arg
358)
359{
360  return rtems_termios_read (arg);
361}
362
363/*
364 * Write to the device
365 */
366rtems_device_driver console_write(
367  rtems_device_major_number major,
368  rtems_device_minor_number minor,
369  void                    * arg
370)
371{
372  return rtems_termios_write (arg);
373}
374
375/*
376 * Handle ioctl request.
377 */
378rtems_device_driver console_control(
379  rtems_device_major_number major,
380  rtems_device_minor_number minor,
381  void                    * arg
382)
383{
384  return rtems_termios_ioctl (arg);
385}
Note: See TracBrowser for help on using the repository browser.