source: rtems/c/src/lib/libbsp/m68k/mcf52235/console/console.c @ 1c6926c1

Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on Mar 21, 2017 at 7:39:48 PM

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

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