source: rtems/c/src/lib/libcpu/powerpc/ppc403/tty_drv/tty_drv.c @ 73b5bd5d

4.104.114.84.95
Last change on this file since 73b5bd5d was 73b5bd5d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/15/04 at 13:33:58

Remove stray white spaces.

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