source: rtems/c/src/lib/libbsp/powerpc/shared/console/uart.c @ 2cedc46

4.104.114.95
Last change on this file since 2cedc46 was 2cedc46, checked in by Till Straumann <strauman@…>, on 03/21/08 at 18:48:49

2008-03-21 Till Straumann <strauman@…>

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