source: rtems/c/src/lib/libbsp/m68k/av5282/console/console.c @ 6ac64302

5
Last change on this file since 6ac64302 was 8307bebe, checked in by Joel Sherrill <joel@…>, on 03/29/16 at 18:10:51

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

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