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

4.104.115
Last change on this file since b96f338 was b96f338, checked in by Ralf Corsepius <ralf.corsepius@…>, on 09/30/09 at 03:53:40

2009-09-30 Ralf Corsépius <ralf.corsepius@…>

  • console/console.c: Reflect termios_baud_to_number having been renamed to rtems_termios_baud_to_number.
  • Property mode set to 100644
File size: 21.0 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 int IntUartPollWrite(int minor, const char *buf, int len);
26static int IntUartInterruptWrite(int minor, const char *buf, int 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;
44
45#define MAX_UART_INFO     3
46#define RX_BUFFER_SIZE    512
47
48struct IntUartInfoStruct
49{
50  int iomode;
51  volatile int uimr;
52  int baud;
53  int databits;
54  int parity;
55  int stopbits;
56  int hwflow;
57  int rx_in;
58  int rx_out;
59  char rx_buffer[RX_BUFFER_SIZE];
60  void *ttyp;
61};
62
63struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
64
65/***************************************************************************
66   Function : IntUartSet
67
68   Description : This updates the hardware UART settings.
69 ***************************************************************************/
70static void
71IntUartSet(int minor, int baud, int databits, int parity, int stopbits,
72           int hwflow)
73{
74  int divisor;
75  uint32_t clock_speed;
76  uint8_t umr1 = 0;
77  uint8_t umr2 = 0;
78  struct IntUartInfoStruct *info = &IntUartInfo[minor];
79  int level;
80
81  rtems_interrupt_disable(level);
82
83  /* disable interrupts, clear RTS line, and disable the UARTS */
84  MCF_UART_UIMR(minor) = 0;
85  MCF_UART_UOP0(minor) = 1;
86  MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
87
88  /* save the current values */
89  info->uimr = 0;
90  info->baud = baud;
91  info->databits = databits;
92  info->parity = parity;
93  info->stopbits = stopbits;
94  info->hwflow = hwflow;
95
96  clock_speed = bsp_get_BUS_clock_speed();
97  /* determine the baud divisor value */
98  divisor = ((clock_speed) / (32 * baud));
99  if (divisor < 2)
100    divisor = 2;
101
102  /* check to see if doing hardware flow control */
103  if (hwflow) {
104    /* set hardware flow options */
105    umr1 |= MCF_UART_UMR_RXRTS;
106    umr2 |= MCF_UART_UMR_TXCTS;
107  }
108
109  /* determine the new umr values */
110  umr1 |= (parity | databits);
111  umr2 |= (stopbits);
112
113  /* reset the uart */
114  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_ERROR;
115  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_RX;
116  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_TX;
117
118  /* reset the uart mode register and update values */
119  MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_MR;
120  MCF_UART_UMR(minor) = umr1;
121  MCF_UART_UMR(minor) = umr2;
122
123  /* set the baud rate values */
124  MCF_UART_UCSR(minor) =
125    (MCF_UART_UCSR_RCS_SYS_CLK | MCF_UART_UCSR_TCS_SYS_CLK);
126  MCF_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
127  MCF_UART_UBG2(minor) = (divisor & 0x00ff);
128
129  /* enable the uart */
130  MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
131
132  /* check to see if interrupts need to be enabled */
133  if (info->iomode != TERMIOS_POLLED) {
134    /* enable rx interrupts */
135    info->uimr |= MCF_UART_UIMR_RXRDY_FU;
136    MCF_UART_UIMR(minor) = info->uimr;
137  }
138
139  /* check to see if doing hardware flow control */
140  if (hwflow) {
141    /* assert the RTS line */
142    MCF_UART_UOP1(minor) = 1;
143  }
144
145  rtems_interrupt_enable(level);
146
147}
148
149/***************************************************************************
150   Function : IntUartSetAttributes
151
152   Description : This provides the hardware-dependent portion of tcsetattr().
153   value and sets it. At the moment this just sets the baud rate.
154
155   Note: The highest baudrate is 115200 as this stays within
156   an error of +/- 5% at 25MHz processor clock
157 ***************************************************************************/
158static int IntUartSetAttributes(int minor, const struct termios *t)
159{
160  /* set default index values */
161  int baud = (int) 19200;
162  int databits = (int) MCF_UART_UMR_BC_8;
163  int parity = (int) MCF_UART_UMR_PM_NONE;
164  int stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_1;
165  int hwflow = (int) 0;
166  struct IntUartInfoStruct *info = &IntUartInfo[minor];
167
168  /* check to see if input is valid */
169  if (t != (const struct termios *) 0) {
170    /* determine baud rate index */
171    baud = rtems_termios_baud_to_number(t->c_cflag & CBAUD);
172
173    /* determine data bits */
174    switch (t->c_cflag & CSIZE) {
175      case CS5:
176        databits = (int) MCF_UART_UMR_BC_5;
177        break;
178      case CS6:
179        databits = (int) MCF_UART_UMR_BC_6;
180        break;
181      case CS7:
182        databits = (int) MCF_UART_UMR_BC_7;
183        break;
184      case CS8:
185        databits = (int) MCF_UART_UMR_BC_8;
186        break;
187    }
188
189    /* determine if parity is enabled */
190    if (t->c_cflag & PARENB) {
191      if (t->c_cflag & PARODD) {
192        /* odd parity */
193        parity = (int) MCF_UART_UMR_PM_ODD;
194      } else {
195        /* even parity */
196        parity = (int) MCF_UART_UMR_PM_EVEN;
197      }
198    }
199
200    /* determine stop bits */
201    if (t->c_cflag & CSTOPB) {
202      /* two stop bits */
203      stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_2;
204    }
205
206    /* check to see if hardware flow control */
207    if (t->c_cflag & CRTSCTS) {
208      hwflow = 1;
209    }
210  }
211
212  /* check to see if values have changed */
213  if ((baud != info->baud) ||
214      (databits != info->databits) ||
215      (parity != info->parity) ||
216      (stopbits != info->stopbits) || (hwflow != info->hwflow)) {
217
218    /* call function to set values */
219    IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
220  }
221
222  return (RTEMS_SUCCESSFUL);
223
224}
225
226/***************************************************************************
227   Function : IntUartInterruptHandler
228
229   Description : This is the interrupt handler for the internal uart. It
230   determines which channel caused the interrupt before queueing any received
231   chars and dequeueing chars waiting for transmission.
232 ***************************************************************************/
233static rtems_isr IntUartInterruptHandler(rtems_vector_number v)
234{
235  unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
236  struct IntUartInfoStruct *info = &IntUartInfo[chan];
237
238  /* check to see if received data */
239  if (MCF_UART_UISR(chan) & MCF_UART_UISR_RXRDY_FU) {
240    /* read data and put into the receive buffer */
241    while (MCF_UART_USR(chan) & MCF_UART_USR_RXRDY) {
242
243      if (MCF_UART_USR(chan) & MCF_UART_USR_ERROR) {
244        /* clear the error */
245        MCF_UART_UCR(chan) = MCF_UART_UCR_RESET_ERROR;
246      }
247      /* put data in rx buffer and check for errors */
248      info->rx_buffer[info->rx_in] = MCF_UART_URB(chan);
249
250      /* update buffer values */
251      info->rx_in++;
252
253      if (info->rx_in >= RX_BUFFER_SIZE) {
254        info->rx_in = 0;
255      }
256    }
257    /* Make sure the port has been opened */
258    if (info->ttyp) {
259
260      /* check to see if task driven */
261      if (info->iomode == TERMIOS_TASK_DRIVEN) {
262        /* notify rx task that rx buffer has data */
263        rtems_termios_rxirq_occured(info->ttyp);
264      } else {
265        /* Push up the received data */
266        rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer,
267                                             info->rx_in);
268        info->rx_in = 0;
269      }
270    }
271  }
272
273  /* check to see if data needs to be transmitted */
274  if ((info->uimr & MCF_UART_UIMR_TXRDY) &&
275      (MCF_UART_UISR(chan) & MCF_UART_UISR_TXRDY)) {
276
277    /* disable tx interrupts */
278    info->uimr &= ~MCF_UART_UIMR_TXRDY;
279    MCF_UART_UIMR(chan) = info->uimr;
280
281    /* tell upper level that character has been sent */
282    if (info->ttyp)
283      rtems_termios_dequeue_characters(info->ttyp, 1);
284  }
285}
286
287/***************************************************************************
288   Function : IntUartInitialize
289
290   Description : This initialises the internal uart hardware for all
291   internal uarts. If the internal uart is to be interrupt driven then the
292   interrupt vectors are hooked.
293 ***************************************************************************/
294static void IntUartInitialize(void)
295{
296  unsigned int chan;
297  struct IntUartInfoStruct *info;
298  rtems_isr_entry old_handler;
299  int level;
300
301  for (chan = 0; chan < MAX_UART_INFO; chan++) {
302    info = &IntUartInfo[chan];
303
304    info->ttyp = NULL;
305    info->rx_in = 0;
306    info->rx_out = 0;
307    info->baud = -1;
308    info->databits = -1;
309    info->parity = -1;
310    info->stopbits = -1;
311    info->hwflow = -1;
312    info->iomode = TERMIOS_POLLED;                /*polled console io */
313
314    MCF_UART_UACR(chan) = 0;
315    MCF_UART_UIMR(chan) = 0;
316    if (info->iomode != TERMIOS_POLLED) {
317      rtems_interrupt_catch(IntUartInterruptHandler,
318                            UART_INTC0_IRQ_VECTOR(chan), &old_handler);
319    }
320
321    /* set uart default values */
322    IntUartSetAttributes(chan, NULL);
323
324    /* unmask interrupt */
325    rtems_interrupt_disable(level);
326    switch (chan) {
327      case 0:
328        MCF_INTC0_ICR26 = MCF_INTC_ICR_IL(UART0_IRQ_LEVEL);
329        MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK26);
330        break;
331
332      case 1:
333        MCF_INTC0_ICR27 = MCF_INTC_ICR_IL(UART1_IRQ_LEVEL);
334        MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK27);
335        break;
336
337      case 2:
338        MCF_INTC0_ICR28 = MCF_INTC_ICR_IL(UART2_IRQ_LEVEL);
339        MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK28);
340        break;
341    }
342    rtems_interrupt_enable(level);
343
344  }                                               /* of chan loop */
345
346}                                                 /* IntUartInitialise */
347
348/***************************************************************************
349   Function : IntUartInterruptWrite
350
351   Description : This writes a single character to the appropriate uart
352   channel. This is either called during an interrupt or in the user's task
353   to initiate a transmit sequence. Calling this routine enables Tx
354   interrupts.
355 ***************************************************************************/
356static int IntUartInterruptWrite(int minor, const char *buf, int len)
357{
358  int level;
359
360  rtems_interrupt_disable(level);
361
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  rtems_interrupt_enable(level);
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 int IntUartPollWrite(int minor, const char *buf, int len)
490{
491  /* loop over buffer */
492  while (len--) {
493    /* block until we can transmit */
494    while ((MCF_UART_USR(minor) & MCF_UART_USR_TXRDY) == 0)
495      continue;
496    /* transmit data byte */
497    MCF_UART_UTB(minor) = *buf++;
498  }
499  return (0);
500}
501
502/***************************************************************************
503   Function : console_initialize
504
505   Description : This initialises termios, both sets of uart hardware before
506   registering /dev/tty devices for each channel and the system /dev/console.
507 ***************************************************************************/
508rtems_device_driver console_initialize(rtems_device_major_number major,
509                                       rtems_device_minor_number minor,
510                                       void *arg)
511{
512  rtems_status_code status;
513
514  /* Set up TERMIOS */
515  rtems_termios_initialize();
516
517  /* set io modes for the different channels and initialize device */
518  IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN;
519  IntUartInitialize();
520
521  /* Register the console port */
522  status = rtems_io_register_name("/dev/console", major, CONSOLE_PORT);
523  if (status != RTEMS_SUCCESSFUL) {
524    rtems_fatal_error_occurred(status);
525  }
526
527  /* Register the other port */
528  if (CONSOLE_PORT != 0) {
529    status = rtems_io_register_name("/dev/tty00", major, 0);
530    if (status != RTEMS_SUCCESSFUL) {
531      rtems_fatal_error_occurred(status);
532    }
533  }
534  if (CONSOLE_PORT != 1) {
535    status = rtems_io_register_name("/dev/tty01", major, 1);
536    if (status != RTEMS_SUCCESSFUL) {
537      rtems_fatal_error_occurred(status);
538    }
539  }
540
541  return (RTEMS_SUCCESSFUL);
542}
543
544/***************************************************************************
545   Function : console_open
546
547   Description : This actually opens the device depending on the minor
548   number set during initialisation. The device specific access routines are
549   passed to termios when the devices is opened depending on whether it is
550   polled or not.
551 ***************************************************************************/
552rtems_device_driver console_open(rtems_device_major_number major,
553                                 rtems_device_minor_number minor, void *arg)
554{
555  rtems_status_code status = RTEMS_INVALID_NUMBER;
556  rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *) arg;
557  struct IntUartInfoStruct *info;
558
559  static const rtems_termios_callbacks IntUartPollCallbacks = {
560    NULL,                                         /* firstOpen */
561    NULL,                                         /* lastClose */
562    IntUartPollRead,                              /* pollRead */
563    IntUartPollWrite,                             /* write */
564    IntUartSetAttributes,                         /* setAttributes */
565    NULL,                                         /* stopRemoteTx */
566    NULL,                                         /* startRemoteTx */
567    TERMIOS_POLLED                                /* mode */
568  };
569  static const rtems_termios_callbacks IntUartIntrCallbacks = {
570    IntUartInterruptOpen,                         /* firstOpen */
571    IntUartInterruptClose,                        /* lastClose */
572    NULL,                                         /* pollRead */
573    IntUartInterruptWrite,                        /* write */
574    IntUartSetAttributes,                         /* setAttributes */
575    NULL,                                         /* stopRemoteTx */
576    NULL,                                         /* startRemoteTx */
577    TERMIOS_IRQ_DRIVEN                            /* mode */
578  };
579
580  static const rtems_termios_callbacks IntUartTaskCallbacks = {
581    IntUartInterruptOpen,                         /* firstOpen */
582    IntUartInterruptClose,                        /* lastClose */
583    IntUartTaskRead,                              /* pollRead */
584    IntUartInterruptWrite,                        /* write */
585    IntUartSetAttributes,                         /* setAttributes */
586    NULL,                                         /* stopRemoteTx */
587    NULL,                                         /* startRemoteTx */
588    TERMIOS_TASK_DRIVEN                           /* mode */
589  };
590
591  /* open the port depending on the minor device number */
592  if ((minor >= 0) && (minor < MAX_UART_INFO)) {
593    info = &IntUartInfo[minor];
594    switch (info->iomode) {
595      case TERMIOS_POLLED:
596        status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
597        break;
598      case TERMIOS_IRQ_DRIVEN:
599        status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
600        info->ttyp = args->iop->data1;
601        break;
602      case TERMIOS_TASK_DRIVEN:
603        status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
604        info->ttyp = args->iop->data1;
605        break;
606    }
607  }
608
609  if (status == RTEMS_SUCCESSFUL) {
610    /*
611     * Reset the default baudrate.
612     */
613    struct termios term;
614
615    if (tcgetattr(STDIN_FILENO, &term) >= 0) {
616      term.c_cflag &= ~(CBAUD | CSIZE);
617      term.c_cflag |= CS8 | B19200;
618      tcsetattr(STDIN_FILENO, TCSANOW, &term);
619    }
620  }
621
622  return (status);
623}
624
625/***************************************************************************
626   Function : console_close
627
628   Description : This closes the device via termios
629 ***************************************************************************/
630rtems_device_driver console_close(rtems_device_major_number major,
631                                  rtems_device_minor_number minor, void *arg)
632{
633  return (rtems_termios_close(arg));
634}
635
636/******************
637*********************************************************
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}
670int DEBUG_OUTCHAR(int c)
671{
672  if (c == '\n')
673    DEBUG_OUTCHAR('\r');
674  _BSP_null_char(c);
675  return c;
676}
677void DEBUG_OUTSTR(const char *msg)
678{
679  while (*msg)
680    DEBUG_OUTCHAR(*msg++);
681}
682void DEBUG_OUTNUM(int i)
683{
684  int n;
685  static const char map[] = "0123456789ABCDEF";
686
687  DEBUG_OUTCHAR(' ');
688  for (n = 28; n >= 0; n -= 4)
689    DEBUG_OUTCHAR(map[(i >> n) & 0xF]);
690}
Note: See TracBrowser for help on using the repository browser.