source: rtems/c/src/lib/libcpu/powerpc/ppc403/tty_drv/tty_drv.c @ 1c6926c1

Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on Mar 21, 2017 at 7:39:48 PM

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*
2 * This file contains the PowerPC 405GP tty driver.
3 *
4 * Derived from /c/src/lib/libbsp/i386/shared/comm/tty_drv.c
5 *
6 * Modifications to PPC405GP by Dennis Ehlin
7 *
8 */
9
10#define NO_BSP_INIT
11
12#include <stdio.h>
13#include <rtems/termiostypes.h>
14#include <termios.h>
15#include <assert.h>
16#include <rtems.h>
17#include <rtems/libio.h>
18#include "../irq/ictrl.h"
19#include <stdlib.h>                                     /* for atexit() */
20#include <tty_drv.h>
21
22extern uint32_t bsp_serial_per_sec;
23extern bool bsp_serial_external_clock;
24extern bool bsp_serial_cts_rts;
25extern bool bsp_serial_xon_xoff;
26extern uint32_t bsp_serial_rate;
27
28struct ttyasync {
29/*---------------------------------------------------------------------------+
30| Data Register.
31+---------------------------------------------------------------------------*/
32  unsigned char RBR;    /* 0x00 */
33  #define THR   RBR
34/*---------------------------------------------------------------------------+
35| Interrupt registers
36+---------------------------------------------------------------------------*/
37  unsigned char IER;    /* Interrupt Enable Register 0x01 */
38  #define IER_RCV                0x01
39  #define IER_XMT                0x02
40  #define IER_LS                 0x04
41  #define IER_MS                 0x08
42
43  unsigned char ISR;    /* Interrupt Status Register 0x02 */
44  #define ISR_MS                 0x00
45  #define ISR_nIP                0x01
46  #define ISR_Tx                 0x02
47  #define ISR_Rx                 0x04
48  #define ISR_LS                 0x06
49  #define ISR_RxTO               0x0C
50  #define ISR_64BFIFO            0x20
51  #define ISR_FIFOworks          0x40
52  #define ISR_FIFOen             0x80
53
54/*---------------------------------------------------------------------------+
55| FIFO Control registers
56+---------------------------------------------------------------------------*/
57  #define FCR   ISR
58  #define FCR_FE                0x01    /* FIFO enable */
59  #define FCR_CRF               0x02    /* Clear receive FIFO */
60  #define FCR_CTF               0x04    /* Clear transmit FIFO */
61  #define FCR_DMA               0x08    /* DMA mode select */
62  #define FCR_F64               0x20    /* Enable 64 byte fifo (16750+) */
63  #define FCR_RT14              0xC0    /* Set Rx trigger at 14 */
64  #define FCR_RT8               0x80    /* Set Rx trigger at 8 */
65  #define FCR_RT4               0x40    /* Set Rx trigger at 4 */
66  #define FCR_RT1               0x00    /* Set Rx trigger at 1 */
67
68/*---------------------------------------------------------------------------+
69| Baud rate divisor registers
70+---------------------------------------------------------------------------*/
71  #define DLL   RBR
72  #define DLM   IER
73
74/*---------------------------------------------------------------------------+
75| Alternate function registers
76+---------------------------------------------------------------------------*/
77  #define AFR   ISR
78
79/*---------------------------------------------------------------------------+
80| Line control Register.
81+---------------------------------------------------------------------------*/
82  unsigned char LCR;    /* 0x03 */
83  #define LCR_WL5                0x00   /* Word length 5 */
84  #define LCR_WL6                0x01   /* Word length 6 */
85  #define LCR_WL7                0x02   /* Word length 7 */
86  #define LCR_WL8                0x03   /* Word length 8 */
87
88  #define LCR_SB1                0x00   /* 1 stop bits */
89  #define LCR_SB1_5              0x04   /* 1.5 stop bits , only valid with 5 bit words*/
90  #define LCR_SB1_5              0x04   /* 2 stop bits */
91
92  #define LCR_PN                 0x00   /* Parity NONE */
93  #define LCR_PE                 0x0C   /* Parity EVEN */
94  #define LCR_PO                 0x08   /* Parity ODD */
95  #define LCR_PM                 0x28   /* Forced "mark" parity */
96  #define LCR_PS                 0x38   /* Forced "space" parity */
97
98  #define LCR_DL                 0x80   /* Enable baudrate latch */
99
100/*---------------------------------------------------------------------------+
101| Modem control Register.
102+---------------------------------------------------------------------------*/
103  unsigned char MCR;    /* 0x04 */
104  #define MCR_DTR                0x01
105  #define MCR_RTS                0x02
106  #define MCR_INT                0x08   /* Enable interrupts */
107  #define MCR_LOOP               0x10   /* Loopback mode */
108
109/*---------------------------------------------------------------------------+
110| Line status Register.
111+---------------------------------------------------------------------------*/
112  unsigned char LSR;    /* 0x05 */
113  #define LSR_RSR                0x01
114  #define LSR_OE                 0x02
115  #define LSR_PE                 0x04
116  #define LSR_FE                 0x08
117  #define LSR_BI                 0x10
118  #define LSR_THE                0x20
119  #define LSR_TEMT               0x40
120  #define LSR_FIE                0x80
121
122/*---------------------------------------------------------------------------+
123| Modem status Register.
124+---------------------------------------------------------------------------*/
125  unsigned char MSR;    /* 0x06 */
126  #define UART_MSR_DCTS          0x01
127  #define UART_MSR_DDSR          0x02
128  #define UART_MSR_TERI          0x04
129  #define UART_MSR_DDCD          0x08
130  #define UART_MSR_CTS           0x10
131  #define UART_MSR_DSR           0x20
132  #define UART_MSR_RI            0x40
133  #define UART_MSR_CD            0x80
134
135/*---------------------------------------------------------------------------+
136| Scratch pad Register.
137+---------------------------------------------------------------------------*/
138  unsigned char SCR;    /* 0x07 */
139};
140
141
142#define TTY0_USE_UART 1 /* 0=UART0 1=UART1 */
143#define TTY0_UART_INTERNAL_CLOCK_DIVISOR 16
144#define TTY0_USE_INTERRUPT
145
146
147typedef volatile struct ttyasync *tty0pasync;
148static const tty0pasync tty0port = (tty0pasync)(0xEF600300   + (TTY0_USE_UART*0x100));  /* 0xEF600300 - port A,  0xEF600400 - port B */
149
150static void *tty0ttyp;         /* handle for termios */
151
152
153static int
154tty0_round(double x)
155{
156  return (int)((int)((x-(int)x)*1000)>500 ? x+1 : x);
157}
158
159static void
160tty0BaudSet(uint32_t baudrate)
161{
162  uint32_t   tmp;
163
164  tmp = tty0_round( (double)bsp_serial_per_sec / (baudrate * 16) );
165
166  tty0port->LCR = tty0port->LCR | LCR_DL;
167
168  tty0port->DLL = tmp & 0xff;
169  tty0port->DLM = tmp >> 8;
170
171  tty0port->LCR = tty0port->LCR & ~LCR_DL;
172}
173
174/*
175 * Hardware-dependent portion of tcsetattr().
176 */
177static int
178tty0SetAttributes (int minor, const struct termios *t)
179{
180  int baud;
181
182  /* FIXME: check c_cflag & CRTSCTS for hardware flow control */
183  /* FIXME: check and IMPLEMENT XON/XOFF                     */
184  switch (t->c_ospeed) {
185  default:      baud = -1;      break;
186  case B50:     baud = 50;      break;
187  case B75:     baud = 75;      break;
188  case B110:    baud = 110;     break;
189  case B134:    baud = 134;     break;
190  case B150:    baud = 150;     break;
191  case B200:    baud = 200;     break;
192  case B300:    baud = 300;     break;
193  case B600:    baud = 600;     break;
194  case B1200:   baud = 1200;    break;
195  case B1800:   baud = 1800;    break;
196  case B2400:   baud = 2400;    break;
197  case B4800:   baud = 4800;    break;
198  case B9600:   baud = 9600;    break;
199  case B19200:  baud = 19200;   break;
200  case B38400:  baud = 38400;   break;
201  case B57600:  baud = 57600;   break;
202  case B115200: baud = 115200;  break;
203  case B230400: baud = 230400;  break;
204  case B460800: baud = 460800;  break;
205  }
206  if (baud > 0) {
207    tty0BaudSet(baud);
208  }
209  return 0;
210}
211
212#ifndef TTY0_USE_INTERRUPT
213static int
214tty0PollRead (int minor)
215{
216
217  /* Wait for character */
218  while ((tty0port->LSR & LSR_RSR)==0);
219
220  return tty0port->RBR;
221}
222
223
224static ssize_t
225tty0PollWrite(int minor, const char *buf, size_t len)
226{
227
228  while (len-- > 0) {
229    while (!(tty0port->LSR & LSR_THE));
230    tty0port->THR = *buf++;
231  }
232  return 0;
233}
234#endif
235
236/* ================ Termios support  =================*/
237
238static ssize_t tty0InterruptWrite (int minor, const char *buf, size_t len)
239{
240
241  if(len <= 0)
242    {
243      return 0;
244    }
245
246  /* Write character */
247
248  tty0port->THR = (*buf &0xff);
249  tty0port->IER |= IER_XMT;     /* always enable tx interrupt */
250
251  return 0;
252
253}
254
255static rtems_isr tty0serial_ISR(rtems_vector_number v)
256{
257  char buf[128];
258  int      off, ret, vect;
259
260  off = 0;
261
262  for(;;)
263    {
264          vect = tty0port->ISR & 0x0f;
265          if(vect & 1)
266          {
267                  /* no more interrupts */
268          if(off > 0) {
269                  /* Update rx buffer */
270                  rtems_termios_enqueue_raw_characters(tty0ttyp, buf, off );
271
272                  tty0port->IER |= IER_RCV;     /* always enable rx interrupt */
273                 /*rtems_termios_rxirq_occured(tty0ttyp);*/
274          }
275            return;
276          }
277
278        vect = vect & 0xe; /*mask out all except interrupt pending*/
279
280    switch(vect)
281        {
282
283        case ISR_Tx :
284          /*
285           * TX holding empty: we have to disable these interrupts
286           * if there is nothing more to send.
287           */
288
289          /* If nothing else to send disable interrupts */
290          ret = rtems_termios_dequeue_characters(tty0ttyp, 1);
291
292          if ( ret == 0 ) {
293            tty0port->IER &= ~IER_XMT;
294          }
295
296          break;
297        case ISR_RxTO:
298        case ISR_Rx :
299
300              /* disable interrupts and notify termios */
301               tty0port->IER &= ~IER_RCV;
302
303              /* read all bytes in fifo*/
304               while (( off < sizeof(buf) ) && (  tty0port->LSR & LSR_RSR ))
305                          {
306                                buf[off++] = tty0port->RBR;
307                          }
308
309          break;
310        case ISR_LS:
311          /* RX error: eat character */
312          /* printk("********* Error **********\n"); */
313          break;
314        default:
315          /* Should not happen */
316          /* printk("error vect=%x",vect); */
317          return;
318        }
319    }
320
321}
322
323
324/*
325 *
326 * deinit TTY0
327 *
328 */
329static void tty0DeInit(void)
330{
331  /*
332   * disable interrupts for serial tty0port
333   * set it to state to work with polling boot monitor, if any...
334   */
335
336  /* set up baud rate to original state */
337  tty0BaudSet(bsp_serial_rate);
338
339  tty0port->IER = 0;
340
341}
342
343/*
344 *
345 * init SPI
346 *
347 */
348static rtems_status_code
349tty0Initialize(void)
350{
351  register unsigned tmp;
352  rtems_isr_entry previous_isr; /* this is a dummy */
353  unsigned char _ier;
354  unsigned char _tmp;
355
356  /*
357   * Initialise the serial tty0port
358   */
359
360  /*
361   * Select clock source and set uart internal clock divisor
362   */
363
364  __asm__ volatile ("mfdcr %0, 0x0b1" : "=r" (tmp)); /* CPC_CR0 0x0b1 */
365
366  /* UART0 bit 24 0x80, UART1 bit 25 0x40 */
367  tmp |= (bsp_serial_external_clock ?  (TTY0_USE_UART ? 0x40 : 0x80) : 0);
368
369  tmp |= (bsp_serial_external_clock ?  0: ((TTY0_UART_INTERNAL_CLOCK_DIVISOR -1) << 1));
370
371  __asm__ volatile ("mtdcr 0x0b1, %0" : "=r" (tmp) : "0" (tmp)); /* CPC_CR0 0x0b1*/
372
373  /* Disable tty0port interrupts while changing hardware */
374  _ier = tty0port->IER;
375  (void) _ier; /* avoid set but not used warning */
376  tty0port->IER = 0;
377
378  /* set up tty0port control: 8 bit,1 stop,no parity */
379  tty0port->LCR = LCR_WL8 | LCR_SB1 | LCR_PN;
380
381  /* set up baud rate */
382  tty0BaudSet(bsp_serial_rate);
383
384
385#ifdef TTY0_USE_INTERRUPT
386
387    /* add rx/tx isr to vector table */
388
389    if (TTY0_USE_UART==0)
390        ictrl_set_vector(tty0serial_ISR,PPC_IRQ_EXT_UART0,&previous_isr);
391    else
392        ictrl_set_vector(tty0serial_ISR,PPC_IRQ_EXT_UART1,&previous_isr);
393
394    /* Enable and clear FIFO */
395    tty0port->FCR = FCR_FE | FCR_CRF | FCR_CTF | FCR_RT14;
396
397    /* Read status to clear them */
398    _tmp = tty0port->LSR;
399    _tmp = tty0port->RBR;
400    _tmp = tty0port->MSR;
401    (void) _tmp; /* avoid set but not used warning */
402
403    /* Enable recive interrupts, don't enable TxInt yet */
404    tty0port->IER=IER_RCV;
405
406#else
407
408    tty0port->IER=_ier;
409
410#endif
411
412  atexit(tty0DeInit);
413
414  return RTEMS_SUCCESSFUL;
415}
416
417/*
418 ***************
419 * BOILERPLATE *
420 ***************
421 */
422
423/*  console_initialize
424 *
425 *  This routine initializes the console IO driver.
426 *
427 *  Input parameters: NONE
428 *
429 *  Output parameters:  NONE
430 *
431 *  Return values:
432 */
433
434rtems_device_driver tty0_initialize(
435  rtems_device_major_number  major,
436  rtems_device_minor_number  minor,
437  void                      *arg
438)
439{
440  rtems_status_code status;
441
442
443  /*
444   * Set up TERMIOS
445   */
446  rtems_termios_initialize ();
447
448  /*
449   * Do device-specific initialization
450   */
451
452  /*tty0Initialize ();   Moved this to open instead */
453
454  /*
455   * Register the device
456   */
457  status = rtems_io_register_name ("/dev/ttyS0", major, 0);
458  if (status != RTEMS_SUCCESSFUL)
459    rtems_fatal_error_occurred (status);
460  return RTEMS_SUCCESSFUL;
461}
462
463
464/*
465 *  Open entry point
466 */
467
468rtems_device_driver tty0_open(
469  rtems_device_major_number major,
470  rtems_device_minor_number minor,
471  void                    * arg
472)
473{
474  rtems_status_code sc;
475
476#ifdef TTY0_USE_INTERRUPT
477
478  static const rtems_termios_callbacks intrCallbacks = {
479    NULL,               /* firstOpen */
480    NULL,               /* lastClose */
481    NULL,               /* pollRead */
482    tty0InterruptWrite, /* write */
483    tty0SetAttributes,  /* setAttributes */
484    NULL,               /* stopRemoteTx */
485    NULL,               /* startRemoteTx */
486    TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */
487  };
488  rtems_libio_open_close_args_t *args = arg;
489
490    tty0Initialize ();  /* Initalize hardware */
491
492    sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
493    tty0ttyp = args->iop->data1;
494
495#else
496
497  static const rtems_termios_callbacks pollCallbacks = {
498    NULL,               /* firstOpen */
499    NULL,               /* lastClose */
500    tty0PollRead,       /* pollRead */
501    tty0PollWrite,      /* write */
502    tty0SetAttributes,  /* setAttributes */
503    NULL,               /* stopRemoteTx */
504    NULL,               /* startRemoteTx */
505    0                   /* outputUsesInterrupts */
506  };
507
508    tty0Initialize ();  /* Initalize hardware */
509
510    sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
511
512#endif
513
514    return sc;
515}
516
517/*
518 *  Close entry point
519 */
520
521rtems_device_driver tty0_close(
522  rtems_device_major_number major,
523  rtems_device_minor_number minor,
524  void                    * arg
525)
526{
527  return rtems_termios_close (arg);
528}
529
530/*
531 * read bytes from the serial port. We only have stdin.
532 */
533
534rtems_device_driver tty0_read(
535  rtems_device_major_number major,
536  rtems_device_minor_number minor,
537  void                    * arg
538)
539{
540  return rtems_termios_read (arg);
541}
542
543/*
544 * write bytes to the serial port. Stdout and stderr are the same.
545 */
546
547rtems_device_driver tty0_write(
548  rtems_device_major_number major,
549  rtems_device_minor_number minor,
550  void                    * arg
551)
552{
553  return rtems_termios_write (arg);
554}
555
556/*
557 *  IO Control entry point
558 */
559
560rtems_device_driver tty0_control(
561  rtems_device_major_number major,
562  rtems_device_minor_number minor,
563  void                    * arg
564)
565{
566  return rtems_termios_ioctl (arg);
567}
Note: See TracBrowser for help on using the repository browser.