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

Last change on this file since aea1fc5 was 121971d, checked in by Joel Sherrill <joel@…>, on Mar 29, 2016 at 6:10:51 PM

m68k/mcf5329: Remove include of <rtems/console.h> from <bsp.h> and fix warnings

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