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

5
Last change on this file since fb31ec0b was d5e533d, checked in by Joel Sherrill <joel.sherrill@…>, on 10/12/14 at 13:53:46

m68k/mcf5329/console/console.c: Eliminate unused debug methods

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