source: rtems/c/src/lib/libbsp/m68k/mcf5329/console/console.c @ 6dde5d68

Last change on this file since 6dde5d68 was 6dde5d68, checked in by Joel Sherrill <joel@…>, on Mar 29, 2016 at 7:05:34 PM

m68k/mcf5329/console/console.c: Remove unneeded include of <rtems/mw_uid.h>

  • Property mode set to 100644
File size: 20.7 KB
Line 
1 /*
2  *  Multi UART console serial I/O.
3  *
4  * TO DO: Add DMA input/output
5  */
6
7#include <stdio.h>
8#include <fcntl.h>
9#include <termios.h>
10#include <malloc.h>
11
12#include <rtems/libio.h>
13#include <rtems/termiostypes.h>
14#include <rtems/console.h>
15#include <rtems/bspIo.h>
16
17#include <bsp.h>
18
19#define UART_INTC0_IRQ_VECTOR(x) (64+26+(x))
20
21#define MCF_UART_USR_ERROR ( MCF_UART_USR_RB | \
22                             MCF_UART_USR_FE | \
23                             MCF_UART_USR_PE | \
24                             MCF_UART_USR_OE )
25
26static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
27static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len);
28
29static void _BSP_null_char(char c)
30{
31  int level;
32
33  if (c == '\n')
34    _BSP_null_char('\r');
35  rtems_interrupt_disable(level);
36  while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
37    continue;
38  MCF_UART_UTB(CONSOLE_PORT) = c;
39  while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
40    continue;
41  rtems_interrupt_enable(level);
42}
43
44BSP_output_char_function_type     BSP_output_char = _BSP_null_char;
45BSP_polling_getchar_function_type BSP_poll_char = NULL;
46
47#define MAX_UART_INFO     3
48#define RX_BUFFER_SIZE    512
49
50struct IntUartInfoStruct
51{
52  int iomode;
53  volatile int uimr;
54  int baud;
55  int databits;
56  int parity;
57  int stopbits;
58  int hwflow;
59  int rx_in;
60  int rx_out;
61  char rx_buffer[RX_BUFFER_SIZE];
62  void *ttyp;
63};
64
65struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
66
67/***************************************************************************
68   Function : IntUartSet
69
70   Description : This updates the hardware UART settings.
71 ***************************************************************************/
72static void
73IntUartSet(int minor, int baud, int databits, int parity, int stopbits,
74           int hwflow)
75{
76  int divisor;
77  uint32_t clock_speed;
78  uint8_t umr1 = 0;
79  uint8_t umr2 = 0;
80  struct IntUartInfoStruct *info = &IntUartInfo[minor];
81  int level;
82
83  rtems_interrupt_disable(level);
84
85  /* disable interrupts, clear RTS line, and disable the UARTS */
86  MCF_UART_UIMR(minor) = 0;
87  MCF_UART_UOP0(minor) = 1;
88  MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
89
90  /* save the current values */
91  info->uimr = 0;
92  info->baud = baud;
93  info->databits = databits;
94  info->parity = parity;
95  info->stopbits = stopbits;
96  info->hwflow = hwflow;
97
98  clock_speed = bsp_get_BUS_clock_speed();
99  /* determine the baud divisor value */
100  divisor = ((clock_speed) / (32 * baud));
101  if (divisor < 2)
102    divisor = 2;
103
104  /* check to see if doing hardware flow control */
105  if (hwflow) {
106    /* set hardware flow options */
107    umr1 |= MCF_UART_UMR_RXRTS;
108    umr2 |= MCF_UART_UMR_TXCTS;
109  }
110
111  /* determine the new umr values */
112  umr1 |= (parity | databits);
113  umr2 |= (stopbits);
114
115  /* reset the uart */
116  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_ERROR;
117  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_RX;
118  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_TX;
119
120  /* reset the uart mode register and update values */
121  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_MR;
122  MCF_UART_UMR(minor) = umr1;
123  MCF_UART_UMR(minor) = umr2;
124
125  /* set the baud rate values */
126  MCF_UART_UCSR(minor) =
127    (MCF_UART_UCSR_RCS_SYS_CLK | MCF_UART_UCSR_TCS_SYS_CLK);
128  MCF_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
129  MCF_UART_UBG2(minor) = (divisor & 0x00ff);
130
131  /* enable the uart */
132  MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
133
134  /* check to see if interrupts need to be enabled */
135  if (info->iomode != TERMIOS_POLLED) {
136    /* enable rx interrupts */
137    info->uimr |= MCF_UART_UIMR_RXRDY_FU;
138    MCF_UART_UIMR(minor) = info->uimr;
139  }
140
141  /* check to see if doing hardware flow control */
142  if (hwflow) {
143    /* assert the RTS line */
144    MCF_UART_UOP1(minor) = 1;
145  }
146
147  rtems_interrupt_enable(level);
148
149}
150
151/***************************************************************************
152   Function : IntUartSetAttributes
153
154   Description : This provides the hardware-dependent portion of tcsetattr().
155   value and sets it. At the moment this just sets the baud rate.
156
157   Note: The highest baudrate is 115200 as this stays within
158   an error of +/- 5% at 25MHz processor clock
159 ***************************************************************************/
160static int IntUartSetAttributes(int minor, const struct termios *t)
161{
162  /* set default index values */
163  int baud = (int) 19200;
164  int databits = (int) MCF_UART_UMR_BC_8;
165  int parity = (int) MCF_UART_UMR_PM_NONE;
166  int stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_1;
167  int hwflow = (int) 0;
168  struct IntUartInfoStruct *info = &IntUartInfo[minor];
169
170  /* check to see if input is valid */
171  if (t != (const struct termios *) 0) {
172    /* determine baud rate index */
173    baud = rtems_termios_baud_to_number(t->c_cflag & CBAUD);
174
175    /* determine data bits */
176    switch (t->c_cflag & CSIZE) {
177      case CS5:
178        databits = (int) MCF_UART_UMR_BC_5;
179        break;
180      case CS6:
181        databits = (int) MCF_UART_UMR_BC_6;
182        break;
183      case CS7:
184        databits = (int) MCF_UART_UMR_BC_7;
185        break;
186      case CS8:
187        databits = (int) MCF_UART_UMR_BC_8;
188        break;
189    }
190
191    /* determine if parity is enabled */
192    if (t->c_cflag & PARENB) {
193      if (t->c_cflag & PARODD) {
194        /* odd parity */
195        parity = (int) MCF_UART_UMR_PM_ODD;
196      } else {
197        /* even parity */
198        parity = (int) MCF_UART_UMR_PM_EVEN;
199      }
200    }
201
202    /* determine stop bits */
203    if (t->c_cflag & CSTOPB) {
204      /* two stop bits */
205      stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_2;
206    }
207
208    /* check to see if hardware flow control */
209    if (t->c_cflag & CRTSCTS) {
210      hwflow = 1;
211    }
212  }
213
214  /* check to see if values have changed */
215  if ((baud != info->baud) ||
216      (databits != info->databits) ||
217      (parity != info->parity) ||
218      (stopbits != info->stopbits) || (hwflow != info->hwflow)) {
219
220    /* call function to set values */
221    IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
222  }
223
224  return (RTEMS_SUCCESSFUL);
225
226}
227
228/***************************************************************************
229   Function : IntUartInterruptHandler
230
231   Description : This is the interrupt handler for the internal uart. It
232   determines which channel caused the interrupt before queueing any received
233   chars and dequeueing chars waiting for transmission.
234 ***************************************************************************/
235static rtems_isr IntUartInterruptHandler(rtems_vector_number v)
236{
237  unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
238  struct IntUartInfoStruct *info = &IntUartInfo[chan];
239
240  /* check to see if received data */
241  if (MCF_UART_UISR(chan) & MCF_UART_UISR_RXRDY_FU) {
242    /* read data and put into the receive buffer */
243    while (MCF_UART_USR(chan) & MCF_UART_USR_RXRDY) {
244
245      if (MCF_UART_USR(chan) & MCF_UART_USR_ERROR) {
246        /* clear the error */
247        MCF_UART_UCR(chan) = MCF_UART_UCR_RESET_ERROR;
248      }
249      /* put data in rx buffer and check for errors */
250      info->rx_buffer[info->rx_in] = MCF_UART_URB(chan);
251
252      /* update buffer values */
253      info->rx_in++;
254
255      if (info->rx_in >= RX_BUFFER_SIZE) {
256        info->rx_in = 0;
257      }
258    }
259    /* Make sure the port has been opened */
260    if (info->ttyp) {
261
262      /* check to see if task driven */
263      if (info->iomode == TERMIOS_TASK_DRIVEN) {
264        /* notify rx task that rx buffer has data */
265        rtems_termios_rxirq_occured(info->ttyp);
266      } else {
267        /* Push up the received data */
268        rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer,
269                                             info->rx_in);
270        info->rx_in = 0;
271      }
272    }
273  }
274
275  /* check to see if data needs to be transmitted */
276  if ((info->uimr & MCF_UART_UIMR_TXRDY) &&
277      (MCF_UART_UISR(chan) & MCF_UART_UISR_TXRDY)) {
278
279    /* disable tx interrupts */
280    info->uimr &= ~MCF_UART_UIMR_TXRDY;
281    MCF_UART_UIMR(chan) = info->uimr;
282
283    /* tell upper level that character has been sent */
284    if (info->ttyp)
285      rtems_termios_dequeue_characters(info->ttyp, 1);
286  }
287}
288
289/***************************************************************************
290   Function : IntUartInitialize
291
292   Description : This initialises the internal uart hardware for all
293   internal uarts. If the internal uart is to be interrupt driven then the
294   interrupt vectors are hooked.
295 ***************************************************************************/
296static void IntUartInitialize(void)
297{
298  unsigned int chan;
299  struct IntUartInfoStruct *info;
300  rtems_isr_entry old_handler;
301  int level;
302
303  for (chan = 0; chan < MAX_UART_INFO; chan++) {
304    info = &IntUartInfo[chan];
305
306    info->ttyp = NULL;
307    info->rx_in = 0;
308    info->rx_out = 0;
309    info->baud = -1;
310    info->databits = -1;
311    info->parity = -1;
312    info->stopbits = -1;
313    info->hwflow = -1;
314    info->iomode = TERMIOS_POLLED;                /*polled console io */
315
316    MCF_UART_UACR(chan) = 0;
317    MCF_UART_UIMR(chan) = 0;
318    if (info->iomode != TERMIOS_POLLED) {
319      rtems_interrupt_catch(IntUartInterruptHandler,
320                            UART_INTC0_IRQ_VECTOR(chan), &old_handler);
321    }
322
323    /* set uart default values */
324    IntUartSetAttributes(chan, NULL);
325
326    /* unmask interrupt */
327    rtems_interrupt_disable(level);
328    switch (chan) {
329      case 0:
330        MCF_INTC0_ICR26 = MCF_INTC_ICR_IL(UART0_IRQ_LEVEL);
331        MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK26);
332        break;
333
334      case 1:
335        MCF_INTC0_ICR27 = MCF_INTC_ICR_IL(UART1_IRQ_LEVEL);
336        MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK27);
337        break;
338
339      case 2:
340        MCF_INTC0_ICR28 = MCF_INTC_ICR_IL(UART2_IRQ_LEVEL);
341        MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK28);
342        break;
343    }
344    rtems_interrupt_enable(level);
345
346  }                                               /* of chan loop */
347
348}                                                 /* IntUartInitialise */
349
350/***************************************************************************
351   Function : IntUartInterruptWrite
352
353   Description : This writes a single character to the appropriate uart
354   channel. This is either called during an interrupt or in the user's task
355   to initiate a transmit sequence. Calling this routine enables Tx
356   interrupts.
357 ***************************************************************************/
358static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len)
359{
360  if (len > 0) {
361    /* write out character */
362    MCF_UART_UTB(minor) = *buf;
363
364    /* enable tx interrupt */
365    IntUartInfo[minor].uimr |= MCF_UART_UIMR_TXRDY;
366    MCF_UART_UIMR(minor) = IntUartInfo[minor].uimr;
367  }
368
369  return (0);
370}
371
372/***************************************************************************
373   Function : IntUartInterruptOpen
374
375   Description : This enables interrupts when the tty is opened.
376 ***************************************************************************/
377static int IntUartInterruptOpen(int major, int minor, void *arg)
378{
379  struct IntUartInfoStruct *info = &IntUartInfo[minor];
380
381  /* enable the uart */
382  MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
383
384  /* check to see if interrupts need to be enabled */
385  if (info->iomode != TERMIOS_POLLED) {
386    /* enable rx interrupts */
387    info->uimr |= MCF_UART_UIMR_RXRDY_FU;
388    MCF_UART_UIMR(minor) = info->uimr;
389  }
390
391  /* check to see if doing hardware flow control */
392  if (info->hwflow) {
393    /* assert the RTS line */
394    MCF_UART_UOP1(minor) = 1;
395  }
396
397  return (0);
398}
399
400/***************************************************************************
401   Function : IntUartInterruptClose
402
403   Description : This disables interrupts when the tty is closed.
404 ***************************************************************************/
405static int IntUartInterruptClose(int major, int minor, void *arg)
406{
407  struct IntUartInfoStruct *info = &IntUartInfo[minor];
408
409  /* disable the interrupts and the uart */
410  MCF_UART_UIMR(minor) = 0;
411  MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
412
413  /* reset values */
414  info->ttyp = NULL;
415  info->uimr = 0;
416  info->rx_in = 0;
417  info->rx_out = 0;
418
419  return (0);
420}
421
422/***************************************************************************
423   Function : IntUartTaskRead
424
425   Description : This reads all available characters from the internal uart
426   and places them into the termios buffer.  The rx interrupts will be
427   re-enabled after all data has been read.
428 ***************************************************************************/
429static int IntUartTaskRead(int minor)
430{
431  char buffer[RX_BUFFER_SIZE];
432  int count;
433  int rx_in;
434  int index = 0;
435  struct IntUartInfoStruct *info = &IntUartInfo[minor];
436
437  /* determine number of values to copy out */
438  rx_in = info->rx_in;
439  if (info->rx_out <= rx_in) {
440    count = rx_in - info->rx_out;
441  } else {
442    count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
443  }
444
445  /* copy data into local buffer from rx buffer */
446  while ((index < count) && (index < RX_BUFFER_SIZE)) {
447    /* copy data byte */
448    buffer[index] = info->rx_buffer[info->rx_out];
449    index++;
450
451    /* increment rx buffer values */
452    info->rx_out++;
453    if (info->rx_out >= RX_BUFFER_SIZE) {
454      info->rx_out = 0;
455    }
456  }
457
458  /* check to see if buffer is not empty */
459  if (count > 0) {
460    /* set characters into termios buffer  */
461    rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
462  }
463
464  return (EOF);
465}
466
467/***************************************************************************
468   Function : IntUartPollRead
469
470   Description : This reads a character from the internal uart. It returns
471   to the caller without blocking if not character is waiting.
472 ***************************************************************************/
473static int IntUartPollRead(int minor)
474{
475  if ((MCF_UART_USR(minor) & MCF_UART_USR_RXRDY) == 0)
476    return (-1);
477
478  return (MCF_UART_URB(minor));
479}
480
481/***************************************************************************
482   Function : IntUartPollWrite
483
484   Description : This writes out each character in the buffer to the
485   appropriate internal uart channel waiting till each one is sucessfully
486   transmitted.
487 ***************************************************************************/
488static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len)
489{
490  size_t retval = len;
491  /* loop over buffer */
492  while (len--) {
493    /* block until we can transmit */
494    while ((MCF_UART_USR(minor) & MCF_UART_USR_TXRDY) == 0)
495      continue;
496    /* transmit data byte */
497    MCF_UART_UTB(minor) = *buf++;
498  }
499  return retval;
500}
501
502/***************************************************************************
503   Function : console_initialize
504
505   Description : This initialises termios, both sets of uart hardware before
506   registering /dev/tty devices for each channel and the system /dev/console.
507 ***************************************************************************/
508rtems_device_driver console_initialize(rtems_device_major_number major,
509                                       rtems_device_minor_number minor,
510                                       void *arg)
511{
512  rtems_status_code status;
513
514  /* Set up TERMIOS */
515  rtems_termios_initialize();
516
517  /* set io modes for the different channels and initialize device */
518  IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN;
519  IntUartInitialize();
520
521  /* Register the console port */
522  status = rtems_io_register_name("/dev/console", major, CONSOLE_PORT);
523  if (status != RTEMS_SUCCESSFUL) {
524    rtems_fatal_error_occurred(status);
525  }
526
527  /* Register the other port */
528  if (CONSOLE_PORT != 0) {
529    status = rtems_io_register_name("/dev/tty00", major, 0);
530    if (status != RTEMS_SUCCESSFUL) {
531      rtems_fatal_error_occurred(status);
532    }
533  }
534  if (CONSOLE_PORT != 1) {
535    status = rtems_io_register_name("/dev/tty01", major, 1);
536    if (status != RTEMS_SUCCESSFUL) {
537      rtems_fatal_error_occurred(status);
538    }
539  }
540
541  return (RTEMS_SUCCESSFUL);
542}
543
544/***************************************************************************
545   Function : console_open
546
547   Description : This actually opens the device depending on the minor
548   number set during initialisation. The device specific access routines are
549   passed to termios when the devices is opened depending on whether it is
550   polled or not.
551 ***************************************************************************/
552rtems_device_driver console_open(rtems_device_major_number major,
553                                 rtems_device_minor_number minor, void *arg)
554{
555  rtems_status_code status = RTEMS_INVALID_NUMBER;
556  rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *) arg;
557  struct IntUartInfoStruct *info;
558
559  static const rtems_termios_callbacks IntUartPollCallbacks = {
560    NULL,                                         /* firstOpen */
561    NULL,                                         /* lastClose */
562    IntUartPollRead,                              /* pollRead */
563    IntUartPollWrite,                             /* write */
564    IntUartSetAttributes,                         /* setAttributes */
565    NULL,                                         /* stopRemoteTx */
566    NULL,                                         /* startRemoteTx */
567    TERMIOS_POLLED                                /* mode */
568  };
569  static const rtems_termios_callbacks IntUartIntrCallbacks = {
570    IntUartInterruptOpen,                         /* firstOpen */
571    IntUartInterruptClose,                        /* lastClose */
572    NULL,                                         /* pollRead */
573    IntUartInterruptWrite,                        /* write */
574    IntUartSetAttributes,                         /* setAttributes */
575    NULL,                                         /* stopRemoteTx */
576    NULL,                                         /* startRemoteTx */
577    TERMIOS_IRQ_DRIVEN                            /* mode */
578  };
579
580  static const rtems_termios_callbacks IntUartTaskCallbacks = {
581    IntUartInterruptOpen,                         /* firstOpen */
582    IntUartInterruptClose,                        /* lastClose */
583    IntUartTaskRead,                              /* pollRead */
584    IntUartInterruptWrite,                        /* write */
585    IntUartSetAttributes,                         /* setAttributes */
586    NULL,                                         /* stopRemoteTx */
587    NULL,                                         /* startRemoteTx */
588    TERMIOS_TASK_DRIVEN                           /* mode */
589  };
590
591  /* open the port depending on the minor device number */
592  if ((minor >= 0) && (minor < MAX_UART_INFO)) {
593    info = &IntUartInfo[minor];
594    switch (info->iomode) {
595      case TERMIOS_POLLED:
596        status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
597        break;
598      case TERMIOS_IRQ_DRIVEN:
599        status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
600        info->ttyp = args->iop->data1;
601        break;
602      case TERMIOS_TASK_DRIVEN:
603        status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
604        info->ttyp = args->iop->data1;
605        break;
606    }
607  }
608
609  if (status == RTEMS_SUCCESSFUL) {
610    /*
611     * Reset the default baudrate.
612     */
613    struct termios term;
614
615    if (tcgetattr(STDIN_FILENO, &term) >= 0) {
616      term.c_cflag &= ~(CBAUD | CSIZE);
617      term.c_cflag |= CS8 | B19200;
618      tcsetattr(STDIN_FILENO, TCSANOW, &term);
619    }
620  }
621
622  return (status);
623}
624
625/***************************************************************************
626   Function : console_close
627
628   Description : This closes the device via termios
629 ***************************************************************************/
630rtems_device_driver console_close(rtems_device_major_number major,
631                                  rtems_device_minor_number minor, void *arg)
632{
633  return (rtems_termios_close(arg));
634}
635
636/***************************************************************************
637   Function : console_read
638
639   Description : Read from the device via termios
640 ***************************************************************************/
641rtems_device_driver console_read(rtems_device_major_number major,
642                                 rtems_device_minor_number minor, void *arg)
643{
644  return (rtems_termios_read(arg));
645}
646
647/***************************************************************************
648   Function : console_write
649
650   Description : Write to the device via termios
651 ***************************************************************************/
652rtems_device_driver console_write(rtems_device_major_number major,
653                                  rtems_device_minor_number minor, void *arg)
654{
655  return (rtems_termios_write(arg));
656}
657
658/***************************************************************************
659   Function : console_ioctl
660
661   Description : Pass the IOCtl call to termios
662 ***************************************************************************/
663rtems_device_driver console_control(rtems_device_major_number major,
664                                    rtems_device_minor_number minor,
665                                    void *arg)
666{
667  return (rtems_termios_ioctl(arg));
668}
Note: See TracBrowser for help on using the repository browser.