source: rtems/c/src/lib/libbsp/m68k/av5282/console/console.c @ 00e8c344

Last change on this file since 00e8c344 was 00e8c344, checked in by Joel Sherrill <joel@…>, on Mar 29, 2016 at 7:05:33 PM

m68k/av5282/console/console.c: Remove unneeded include of <rtems/mw_uid.h>

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