source: rtems/c/src/lib/libbsp/powerpc/shared/console/uart.c @ 4f3e4f33

4.104.114.84.95
Last change on this file since 4f3e4f33 was 4f3e4f33, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 20, 2003 at 9:32:07 PM

2003-02-20 Till Straumann <strauman@…>

PR 349/bsps

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