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
RevLine 
[6b56ec3]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
[121971d]12#include <rtems/libio.h>
13#include <rtems/termiostypes.h>
14#include <rtems/console.h>
[6b56ec3]15#include <rtems/bspIo.h>
16
[121971d]17#include <bsp.h>
18
[6b56ec3]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
[39a9f8e]26static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
27static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len);
[6b56ec3]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
[989938f1]44BSP_output_char_function_type     BSP_output_char = _BSP_null_char;
45BSP_polling_getchar_function_type BSP_poll_char = NULL;
[6b56ec3]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
[d4b4664b]157   Note: The highest baudrate is 115200 as this stays within
[6b56ec3]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 */
[b96f338]173    baud = rtems_termios_baud_to_number(t->c_cflag & CBAUD);
[6b56ec3]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
[d4b4664b]353   Description : This writes a single character to the appropriate uart
[6b56ec3]354   channel. This is either called during an interrupt or in the user's task
[d4b4664b]355   to initiate a transmit sequence. Calling this routine enables Tx
[6b56ec3]356   interrupts.
357 ***************************************************************************/
[39a9f8e]358static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len)
[6b56ec3]359{
[e18db9f]360  if (len > 0) {
361    /* write out character */
362    MCF_UART_UTB(minor) = *buf;
[6b56ec3]363
[e18db9f]364    /* enable tx interrupt */
365    IntUartInfo[minor].uimr |= MCF_UART_UIMR_TXRDY;
366    MCF_UART_UIMR(minor) = IntUartInfo[minor].uimr;
367  }
[6b56ec3]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
[d4b4664b]470   Description : This reads a character from the internal uart. It returns
[6b56ec3]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
[d4b4664b]484   Description : This writes out each character in the buffer to the
485   appropriate internal uart channel waiting till each one is sucessfully
[6b56ec3]486   transmitted.
487 ***************************************************************************/
[39a9f8e]488static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len)
[6b56ec3]489{
[39a9f8e]490  size_t retval = len;
[6b56ec3]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  }
[39a9f8e]499  return retval;
[6b56ec3]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
[d4b4664b]547   Description : This actually opens the device depending on the minor
[6b56ec3]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
[d3d29749]636/***************************************************************************
[6b56ec3]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.