source: rtems/c/src/lib/libbsp/powerpc/shared/console/uart.c @ 9ca6799

4.115
Last change on this file since 9ca6799 was 9ca6799, checked in by Joel Sherrill <joel.sherrill@…>, on 10/12/14 at 15:07:07

powerpc/shared/console: Fix warnings

  • Property mode set to 100644
File size: 15.2 KB
Line 
1/*
2 * This software is Copyright (C) 1998 by T.sqware - all rights limited
3 * It is provided in to the public domain "as is", can be freely modified
4 * as far as this copyight notice is kept unchanged, but does not imply
5 * an endorsement by T.sqware of the product in which it is included.
6 */
7
8#include <stdio.h>
9#include <bsp.h>
10#include <bsp/irq.h>
11#include <bsp/uart.h>
12#include <rtems/libio.h>
13#include <rtems/bspIo.h>
14#include <rtems/termiostypes.h>
15#include <termios.h>
16#include <assert.h>
17
18/*
19 * Basic 16552 driver
20 */
21
22struct uart_data
23{
24  unsigned long       ioBase;
25  int                 irq;
26  int                 hwFlow;
27  int                 baud;
28  BSP_UartBreakCbRec  breakCallback;
29  int                 ioMode;
30};
31
32/*
33 * Initialization of BSP specific data.
34 * The constants are pulled in from a BSP
35 * specific file, whereas all of the code
36 * in this file is generic and makes no
37 * assumptions about addresses, irq vectors
38 * etc...
39 */
40
41#define UART_UNSUPP ((unsigned long)(-1))
42
43static struct uart_data uart_data[2] = {
44        {
45#ifdef  BSP_UART_IOBASE_COM1
46                BSP_UART_IOBASE_COM1,
47                BSP_UART_COM1_IRQ,
48#else
49                UART_UNSUPP,
50                -1,
51#endif
52        },
53        {
54#ifdef  BSP_UART_IOBASE_COM2
55                BSP_UART_IOBASE_COM2,
56                BSP_UART_COM2_IRQ,
57#else
58                UART_UNSUPP,
59                -1,
60#endif
61        },
62};
63
64#define MAX_UARTS (sizeof(uart_data)/sizeof(uart_data[0]))
65#define SANITY_CHECK(uart) \
66  assert( MAX_UARTS > (unsigned)(uart) && uart_data[(uart)].ioBase != UART_UNSUPP )
67/*
68 * Macros to read/write register of uart, if configuration is
69 * different just rewrite these macros
70 */
71
72static inline unsigned char
73uread(int uart, unsigned int reg)
74{
75        return in_8((unsigned char*)(uart_data[uart].ioBase + reg));
76}
77
78static inline void
79uwrite(int uart, int reg, unsigned int val)
80{
81        out_8((unsigned char*)(uart_data[uart].ioBase + reg), val);
82}
83
84
85static void
86uartError(int uart, void *termiosPrivate)
87{
88  unsigned char uartStatus, dummy;
89  BSP_UartBreakCbProc           h;
90
91  uartStatus = uread(uart, LSR);
92  dummy = uread(uart, RBR);
93
94#ifdef UARTDEBUG
95  if (uartStatus & OE)
96    printk("********* Over run Error **********\n");
97  if (uartStatus & PE)
98    printk("********* Parity Error   **********\n");
99  if (uartStatus & FE)
100    printk("********* Framing Error  **********\n");
101  if (uartStatus & BI) {
102    printk("********* BREAK INTERRUPT *********\n");
103#endif
104   if ((h=uart_data[uart].breakCallback.handler)) {
105     h(uart,
106       (dummy<<8)|uartStatus,
107       termiosPrivate,
108       uart_data[uart].breakCallback.private);
109  }
110#ifdef UARTDEBUG
111  if (uartStatus & ERFIFO)
112    printk("********* Error receive Fifo **********\n");
113#endif
114}
115
116/*
117 * Uart initialization, it is hardcoded to 8 bit, no parity,
118 * one stop bit, FIFO, things to be changed
119 * are baud rate and nad hw flow control,
120 * and longest rx fifo setting
121 */
122void
123BSP_uart_init(int uart, int baud, int hwFlow)
124{
125  unsigned char tmp;
126
127  /* Sanity check */
128  SANITY_CHECK(uart);
129
130  /* Make sure any printk activity drains before
131   * re-initializing.
132   */
133  while ( ! (uread(uart, LSR) & TEMT) )
134        ;
135
136  switch(baud)
137    {
138    case 50:
139    case 75:
140    case 110:
141    case 134:
142    case 300:
143    case 600:
144    case 1200:
145    case 2400:
146    case 9600:
147    case 19200:
148    case 38400:
149    case 57600:
150    case 115200:
151      break;
152    default:
153      assert(0);
154      return;
155    }
156
157  /* Set DLAB bit to 1 */
158  uwrite(uart, LCR, DLAB);
159
160  if ( (int)BSPBaseBaud <= 0 ) {
161        /* Use current divisor assuming BSPBaseBaud gives us the current speed */
162        BSPBaseBaud  = BSPBaseBaud ? -BSPBaseBaud : 9600;
163        BSPBaseBaud *= ((uread(uart, DLM) << 8) | uread(uart, DLL));
164  }
165
166  /* Set baud rate */
167  uwrite(uart, DLL,  (BSPBaseBaud/baud) & 0xff);
168  uwrite(uart, DLM,  ((BSPBaseBaud/baud) >> 8) & 0xff);
169
170  /* 8-bit, no parity , 1 stop */
171  uwrite(uart, LCR, CHR_8_BITS);
172
173  /* Set DTR, RTS and OUT2 high */
174  uwrite(uart, MCR, DTR | RTS | OUT_2);
175
176  /* Enable FIFO */
177  uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12);
178
179  /* Disable Interrupts */
180  uwrite(uart, IER, 0);
181
182  /* Read status to clear them */
183  tmp = uread(uart, LSR);
184  tmp = uread(uart, RBR);
185  tmp = uread(uart, MSR);
186  (void) tmp; /* avoid set but not used warning */
187
188  /* Remember state */
189  uart_data[uart].hwFlow     = hwFlow;
190  uart_data[uart].baud       = baud;
191  return;
192}
193
194/*
195 * Set baud
196 */
197void
198BSP_uart_set_baud(int uart, int baud)
199{
200  unsigned char mcr, ier;
201
202  /* Sanity check */
203  SANITY_CHECK(uart);
204
205  /*
206   * This function may be called whenever TERMIOS parameters
207   * are changed, so we have to make sure that baud change is
208   * indeed required.
209   */
210
211  if(baud == uart_data[uart].baud)
212    {
213      return;
214    }
215
216  mcr = uread(uart, MCR);
217  ier = uread(uart, IER);
218
219  BSP_uart_init(uart, baud, uart_data[uart].hwFlow);
220
221  uwrite(uart, MCR, mcr);
222  uwrite(uart, IER, ier);
223
224  return;
225}
226
227/*
228 * Enable/disable interrupts
229 */
230void
231BSP_uart_intr_ctrl(int uart, int cmd)
232{
233
234  SANITY_CHECK(uart);
235
236  switch(cmd)
237    {
238    case BSP_UART_INTR_CTRL_DISABLE:
239      uwrite(uart, IER, INTERRUPT_DISABLE);
240      break;
241    case BSP_UART_INTR_CTRL_ENABLE:
242      if(uart_data[uart].hwFlow)
243        {
244          uwrite(uart, IER,
245                 (RECEIVE_ENABLE  |
246                  TRANSMIT_ENABLE |
247                  RECEIVER_LINE_ST_ENABLE |
248                  MODEM_ENABLE
249                 )
250                );
251        }
252      else
253        {
254          uwrite(uart, IER,
255                 (RECEIVE_ENABLE  |
256                  TRANSMIT_ENABLE |
257                  RECEIVER_LINE_ST_ENABLE
258                 )
259                );
260        }
261      break;
262    case BSP_UART_INTR_CTRL_TERMIOS:
263      if(uart_data[uart].hwFlow)
264        {
265          uwrite(uart, IER,
266                 (RECEIVE_ENABLE  |
267                  RECEIVER_LINE_ST_ENABLE |
268                  MODEM_ENABLE
269                 )
270                );
271        }
272      else
273        {
274          uwrite(uart, IER,
275                 (RECEIVE_ENABLE  |
276                  RECEIVER_LINE_ST_ENABLE
277                 )
278                );
279        }
280      break;
281    case BSP_UART_INTR_CTRL_GDB:
282      uwrite(uart, IER, RECEIVE_ENABLE);
283      break;
284    default:
285      assert(0);
286      break;
287    }
288
289  return;
290}
291
292void
293BSP_uart_throttle(int uart)
294{
295  unsigned int mcr;
296
297  SANITY_CHECK(uart);
298
299  if(!uart_data[uart].hwFlow)
300    {
301      /* Should not happen */
302      assert(0);
303      return;
304    }
305  mcr = uread (uart, MCR);
306  /* RTS down */
307  mcr &= ~RTS;
308  uwrite(uart, MCR, mcr);
309
310  return;
311}
312
313void
314BSP_uart_unthrottle(int uart)
315{
316  unsigned int mcr;
317
318  SANITY_CHECK(uart);
319
320  if(!uart_data[uart].hwFlow)
321    {
322      /* Should not happen */
323      assert(0);
324      return;
325    }
326  mcr = uread (uart, MCR);
327  /* RTS up */
328  mcr |= RTS;
329  uwrite(uart, MCR, mcr);
330
331  return;
332}
333
334/*
335 * Status function, -1 if error
336 * detected, 0 if no received chars available,
337 * 1 if received char available, 2 if break
338 * is detected, it will eat break and error
339 * chars. It ignores overruns - we cannot do
340 * anything about - it execpt count statistics
341 * and we are not counting it.
342 */
343int
344BSP_uart_polled_status(int uart)
345{
346  unsigned char val;
347
348  SANITY_CHECK(uart);
349
350  val = uread(uart, LSR);
351
352  if(val & BI)
353    {
354      /* BREAK found, eat character */
355      uread(uart, RBR);
356      return BSP_UART_STATUS_BREAK;
357    }
358
359  if((val & (DR | OE | FE)) ==  1)
360    {
361      /* No error, character present */
362      return BSP_UART_STATUS_CHAR;
363    }
364
365  if((val & (DR | OE | FE)) == 0)
366    {
367      /* Nothing */
368      return BSP_UART_STATUS_NOCHAR;
369    }
370
371  /*
372   * Framing or parity error
373   * eat character
374   */
375  uread(uart, RBR);
376
377  return BSP_UART_STATUS_ERROR;
378}
379
380/*
381 * Polled mode write function
382 */
383void
384BSP_uart_polled_write(int uart, int val)
385{
386  unsigned char val1;
387
388  /* Sanity check */
389  SANITY_CHECK(uart);
390
391  for(;;)
392    {
393      if((val1=uread(uart, LSR)) & THRE)
394        {
395          break;
396        }
397    }
398
399  if(uart_data[uart].hwFlow)
400    {
401      for(;;)
402        {
403          if(uread(uart, MSR) & CTS)
404            {
405              break;
406            }
407        }
408    }
409
410  uwrite(uart, THR, val & 0xff);
411
412  return;
413}
414
415void
416BSP_output_char_via_serial(const char val)
417{
418  BSP_uart_polled_write(BSPConsolePort, val);
419  if (val == '\n') BSP_uart_polled_write(BSPConsolePort,'\r');
420}
421
422/*
423 * Polled mode read function
424 */
425int
426BSP_uart_polled_read(int uart)
427{
428  unsigned char val;
429
430  SANITY_CHECK(uart);
431
432  for(;;)
433    {
434      if(uread(uart, LSR) & DR)
435        {
436          break;
437        }
438    }
439
440  val = uread(uart, RBR);
441
442  return (int)(val & 0xff);
443}
444
445unsigned
446BSP_poll_char_via_serial()
447{
448        return BSP_uart_polled_read(BSPConsolePort);
449}
450
451static void
452uart_noop(const rtems_irq_connect_data *unused)
453{
454  return;
455}
456
457/* note that the IRQ names contain _ISA_ for legacy
458 * reasons. They can be any interrupt, depending
459 * on the particular BSP...
460 */
461
462static int
463uart_isr_is_on(const rtems_irq_connect_data *irq)
464{
465  int uart;
466
467  uart = (irq->name == BSP_UART_COM1_IRQ) ?
468                        BSP_UART_COM1 : BSP_UART_COM2;
469
470  return uread(uart,IER);
471}
472
473static int
474doit(int uart, rtems_irq_hdl handler, int (*p)(const rtems_irq_connect_data*))
475{
476        rtems_irq_connect_data d={0};
477        d.name = uart_data[uart].irq;
478        d.off  = d.on = uart_noop;
479        d.isOn = uart_isr_is_on;
480        d.hdl  = handler;
481        return p(&d);
482}
483
484int
485BSP_uart_install_isr(int uart, rtems_irq_hdl handler)
486{
487/* Using shared interrupts by default might break things.. the
488 * shared IRQ installer uses malloc() and if a BSP had called this
489 * during early init it might not work...
490 */
491#ifdef BSP_UART_USE_SHARED_IRQS
492        return doit(uart, handler, BSP_install_rtems_shared_irq_handler);
493#else
494        return doit(uart, handler, BSP_install_rtems_irq_handler);
495#endif
496}
497
498int
499BSP_uart_remove_isr(int uart, rtems_irq_hdl handler)
500{
501        return doit(uart, handler, BSP_remove_rtems_irq_handler);
502}
503
504/* ================ Termios support  =================*/
505
506static volatile int  termios_stopped_com[2]        = {0,0};
507static volatile int  termios_tx_active_com[2]      = {0,0};
508static void*         termios_ttyp_com[2]           = {NULL,NULL};
509static char          termios_tx_hold_com[2]        = {0,0};
510static volatile char termios_tx_hold_valid_com[2]  = {0,0};
511
512/*
513 * Set channel parameters
514 */
515void
516BSP_uart_termios_set(int uart, void *p)
517{
518  struct rtems_termios_tty *ttyp = p;
519  unsigned char val;
520  SANITY_CHECK(uart);
521
522  if(uart_data[uart].hwFlow)
523    {
524      val = uread(uart, MSR);
525
526      termios_stopped_com[uart]    = (val & CTS) ? 0 : 1;
527    }
528  else
529  {
530      termios_stopped_com[uart] = 0;
531  }
532  termios_tx_active_com[uart]      = 0;
533  termios_ttyp_com[uart]           = ttyp;
534  termios_tx_hold_com[uart]        = 0;
535  termios_tx_hold_valid_com[uart]  = 0;
536
537  uart_data[uart].ioMode           = ttyp->device.outputUsesInterrupts;
538
539  return;
540}
541
542ssize_t
543BSP_uart_termios_write_polled(int minor, const char *buf, size_t len)
544{
545  int uart=minor;       /* could differ, theoretically */
546  int nwrite;
547  const char *b = buf;
548
549  for (nwrite=0 ; nwrite < len ; nwrite++) {
550    BSP_uart_polled_write(uart, *b++);
551  }
552  return nwrite;
553}
554
555ssize_t
556BSP_uart_termios_write_com(int minor, const char *buf, size_t len)
557{
558  int uart=minor;       /* could differ, theoretically */
559
560  if(len <= 0)
561    {
562      return 0;
563    }
564
565  /* If the TX buffer is busy - something is royally screwed up */
566  /*   assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */
567
568  if(termios_stopped_com[uart])
569    {
570      /* CTS low */
571      termios_tx_hold_com[uart]       = *buf;
572      termios_tx_hold_valid_com[uart] = 1;
573      return 0;
574    }
575
576  /* Write character */
577  uwrite(uart, THR, *buf & 0xff);
578
579  /* Enable interrupts if necessary */
580  if(!termios_tx_active_com[uart] && uart_data[uart].hwFlow)
581    {
582      termios_tx_active_com[uart] = 1;
583      uwrite(uart, IER,
584             (RECEIVE_ENABLE  |
585              TRANSMIT_ENABLE |
586              RECEIVER_LINE_ST_ENABLE |
587              MODEM_ENABLE
588             )
589            );
590    }
591  else if(!termios_tx_active_com[uart])
592    {
593      termios_tx_active_com[uart] = 1;
594      uwrite(uart, IER,
595             (RECEIVE_ENABLE  |
596              TRANSMIT_ENABLE |
597              RECEIVER_LINE_ST_ENABLE
598             )
599            );
600    }
601
602  return 0;
603}
604
605int
606BSP_uart_termios_read_com(int uart)
607{
608  int     off = (int)0;
609  char    buf[40];
610  rtems_interrupt_level l;
611
612  /* read bytes */
613  while (( off < sizeof(buf) ) && ( uread(uart, LSR) & DR )) {
614    buf[off++] = uread(uart, RBR);
615  }
616
617  /* write out data */
618  if ( off > 0 ) {
619    rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart], buf, off);
620  }
621
622  /* enable receive interrupts */
623  rtems_interrupt_disable(l);
624  uwrite(uart, IER, uread(uart, IER) | (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE));
625  rtems_interrupt_enable(l);
626
627  return ( EOF );
628}
629
630static void
631BSP_uart_termios_isr_com(int uart)
632{
633  unsigned char buf[40];
634  unsigned char val, ier;
635  int      off, ret, vect;
636
637  off = 0;
638
639  for(;;)
640    {
641      vect = uread(uart, IIR) & 0xf;
642
643      switch(vect)
644        {
645        case MODEM_STATUS :
646          val = uread(uart, MSR);
647          if(uart_data[uart].hwFlow)
648            {
649              if(val & CTS)
650                {
651                  /* CTS high */
652                  termios_stopped_com[uart] = 0;
653                  if(termios_tx_hold_valid_com[uart])
654                    {
655                      termios_tx_hold_valid_com[uart] = 0;
656                      BSP_uart_termios_write_com(uart, &termios_tx_hold_com[uart],
657                                                    1);
658                    }
659                }
660              else
661                {
662                  /* CTS low */
663                  termios_stopped_com[uart] = 1;
664                }
665            }
666          break;
667        case NO_MORE_INTR :
668          /* No more interrupts */
669          if(off != 0)
670            {
671              /* Update rx buffer */
672              rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart],
673                                                   (char *)buf,
674                                                   off);
675            }
676          return;
677        case TRANSMITTER_HODING_REGISTER_EMPTY :
678          /*
679           * TX holding empty: we have to disable these interrupts
680           * if there is nothing more to send.
681           */
682
683          ret = rtems_termios_dequeue_characters(termios_ttyp_com[uart], 1);
684
685          /* If nothing else to send disable interrupts */
686          if(ret == 0 && uart_data[uart].hwFlow)
687            {
688              uwrite(uart, IER,
689                     (RECEIVE_ENABLE  |
690                      RECEIVER_LINE_ST_ENABLE |
691                      MODEM_ENABLE
692                     )
693                    );
694              termios_tx_active_com[uart] = 0;
695            }
696          else if(ret == 0)
697            {
698              uwrite(uart, IER,
699                     (RECEIVE_ENABLE  |
700                      RECEIVER_LINE_ST_ENABLE
701                     )
702                    );
703              termios_tx_active_com[uart] = 0;
704            }
705          break;
706        case RECEIVER_DATA_AVAIL :
707        case CHARACTER_TIMEOUT_INDICATION:
708          if ( uart_data[uart].ioMode == TERMIOS_TASK_DRIVEN )
709            {
710              /* ensure interrupts are enabled */
711              if ( (ier = uread(uart,IER)) & RECEIVE_ENABLE )
712                {
713                   /* disable interrupts and notify termios */
714                   ier &= ~(RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
715                   uwrite(uart, IER, ier);
716                   rtems_termios_rxirq_occured(termios_ttyp_com[uart]);
717                }
718            }
719          else
720            {
721              /* RX data ready */
722              assert(off < sizeof(buf));
723              while ( off < sizeof(buf) && ( DR & uread(uart, LSR) ) )
724                buf[off++] = uread(uart, RBR);
725            }
726          break;
727        case RECEIVER_ERROR:
728          /* RX error: eat character */
729           uartError(uart, termios_ttyp_com[uart]);
730          break;
731        default:
732          /* Should not happen */
733          assert(0);
734          return;
735        }
736    }
737}
738
739/*
740 * XXX - Note that this can now be one isr with the uart
741 *       passed as the parameter.
742 */
743void
744BSP_uart_termios_isr_com1(void *unused)
745{
746        BSP_uart_termios_isr_com(BSP_UART_COM1);
747}
748
749void
750BSP_uart_termios_isr_com2(void *unused)
751{
752        BSP_uart_termios_isr_com(BSP_UART_COM2);
753}
754
755/* retrieve 'break' handler info */
756int
757BSP_uart_get_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
758{
759BSP_UartBreakCb cb=arg->buffer;
760unsigned long flags;
761        SANITY_CHECK(uart);
762        rtems_interrupt_disable(flags);
763                *cb = uart_data[uart].breakCallback;
764        rtems_interrupt_enable(flags);
765        arg->ioctl_return=0;
766        return RTEMS_SUCCESSFUL;
767}
768
769/* install 'break' handler */
770int
771BSP_uart_set_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
772{
773BSP_UartBreakCb cb=arg->buffer;
774unsigned long flags;
775        SANITY_CHECK(uart);
776        rtems_interrupt_disable(flags);
777                uart_data[uart].breakCallback = *cb;
778        rtems_interrupt_enable(flags);
779        arg->ioctl_return=0;
780        return RTEMS_SUCCESSFUL;
781}
Note: See TracBrowser for help on using the repository browser.