source: rtems/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c @ 472e949e

4.104.114.84.95
Last change on this file since 472e949e was 472e949e, checked in by Ralf Corsepius <ralf.corsepius@…>, on 05/10/05 at 13:04:28

Eliminate rtems_unsigned16.

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 *  General Serial I/O functions.
3 *
4 *  This file contains the functions for performing serial I/O.  The actual
5 *  system calls (console_*) should be in the BSP part of the source tree.
6 *  That way different BSPs can use whichever SCI they wish for /dev/console.
7 *
8 *  On-chip resources used:
9 *   resource   minor                note
10 *      SCI1      0
11 *      SCI2      1
12 *
13 *
14 *  MPC5xx port sponsored by Defence Research and Development Canada - Suffield
15 *  Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
16 *
17 *  Derived from
18 *    c/src/lib/libcpu/powerpc/mpc8xx/console_generic/console_generic.c:
19 *  Author: Jay Monkman (jmonkman@frasca.com)
20 *  Copyright (C) 1998 by Frasca International, Inc.
21 *
22 *  Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by:
23 *    W. Eric Norum
24 *    Saskatchewan Accelerator Laboratory
25 *    University of Saskatchewan
26 *    Saskatoon, Saskatchewan, CANADA
27 *    eric@skatter.usask.ca
28 *
29 *  COPYRIGHT (c) 1989-1998.
30 *  On-Line Applications Research Corporation (OAR).
31 *
32 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
33 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
34 *  Copyright (c) 1999, National Research Council of Canada
35 *
36 *  The license and distribution terms for this file may be
37 *  found in the file LICENSE in this distribution or at
38 *
39 *  http://www.rtems.com/license/LICENSE.
40 *
41 *  $Id$
42 */
43
44#include <stdlib.h>
45#include <unistd.h>
46#include <termios.h>
47#include <rtems.h>
48#include <rtems/libio.h>
49#include <rtems/bspIo.h>   /* for printk */
50#include <mpc5xx.h>
51#include <mpc5xx/console.h>
52#include <libcpu/irq.h>
53
54
55extern rtems_cpu_table Cpu_table;       /* for CPU clock speed */
56
57/*
58 * SCI port descriptor table.
59 */
60typedef struct
61{
62  volatile m5xxSCIRegisters_t *regs;    /* hardware registers */
63  struct rtems_termios_tty *ttyp;       /* termios data for this port */
64} sci_desc;
65
66static sci_desc sci_descs[] = {
67  { &imb.qsmcm.sci1, 0 },               /* SCI 1 */
68  { &imb.qsmcm.sci2, 0 },               /* SCI 2 */
69};
70
71/*
72 * Number of SCI port initialization calls made so far.  Used to avoid
73 * installing the common interrupt handler more than once.
74 */
75int init_calls = 0;
76
77/*
78 * Default configuration.
79 */
80static struct termios default_termios = {
81  0,                                    /* input mode flags */
82  0,                                    /* output mode flags */
83  CS8 | CREAD | CLOCAL | B9600,         /* control mode flags */
84  0,                                    /* local mode flags */
85  0,                                    /* line discipline */
86  { 0 }                                 /* control characters */
87};
88
89 
90/*
91 * Termios callback functions
92 */
93
94int
95m5xx_uart_firstOpen(
96  int major,
97  int minor,
98  void *arg
99)
100{
101  rtems_libio_open_close_args_t *args = arg;
102  sci_desc* desc = &sci_descs[minor];
103  struct rtems_termios_tty *tty = args->iop->data1;
104
105  desc->ttyp = tty;                             /* connect tty */
106  if ( tty->device.outputUsesInterrupts == TERMIOS_IRQ_DRIVEN)
107    desc->regs->sccr1 |= QSMCM_SCI_RIE;         /* enable rx interrupt */
108
109  return RTEMS_SUCCESSFUL;
110}
111
112int
113m5xx_uart_lastClose(
114  int major,
115  int minor,
116  void* arg
117)
118{
119  sci_desc* desc = &sci_descs[minor];
120
121  desc->regs->sccr1 &= ~(QSMCM_SCI_RIE | QSMCM_SCI_TIE);  /* disable all */
122  desc->ttyp = NULL;                                      /* disconnect tty */
123
124  return RTEMS_SUCCESSFUL;
125}
126
127int
128m5xx_uart_pollRead(
129  int minor
130)
131{
132  volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs;
133  int c = -1;
134 
135  if ( regs ) {
136    while ( (regs->scsr & QSMCM_SCI_RDRF) == 0 )
137      ;
138    c = regs->scdr;
139  }
140
141  return c;
142}
143
144int
145m5xx_uart_write(
146  int minor,
147  const char *buf,
148  int len
149)
150{
151  volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs;
152
153  regs->scdr = *buf;                    /* start transmission */
154  regs->sccr1 |= QSMCM_SCI_TIE;         /* enable interrupt */
155  return 0;
156}
157
158int
159m5xx_uart_pollWrite(
160  int minor,
161  const char *buf,
162  int len
163)
164{
165  volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs;
166
167  while ( len-- ) {
168    while ( (regs->scsr & QSMCM_SCI_TDRE) == 0 )
169      ;
170    regs->scdr = *buf++;
171  }
172  return 0;
173}
174
175void
176m5xx_uart_reserve_resources(
177  rtems_configuration_table *configuration
178)
179{
180  rtems_termios_reserve_resources (configuration, NUM_PORTS);
181}
182
183int
184m5xx_uart_setAttributes(
185  int minor,
186  const struct termios *t
187)
188{
189  uint16_t sccr0 = sci_descs[minor].regs->sccr0;
190  uint16_t sccr1 = sci_descs[minor].regs->sccr1;
191  int baud;
192 
193  /*
194   * Check that port number is valid
195   */
196  if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) )
197    return RTEMS_INVALID_NUMBER;
198
199  /* Baud rate */
200  switch (t->c_cflag & CBAUD) {
201    default:      baud = -1;      break;
202    case B50:     baud = 50;      break;
203    case B75:     baud = 75;      break;
204    case B110:    baud = 110;     break;
205    case B134:    baud = 134;     break;
206    case B150:    baud = 150;     break;
207    case B200:    baud = 200;     break;
208    case B300:    baud = 300;     break;
209    case B600:    baud = 600;     break;
210    case B1200:   baud = 1200;    break;
211    case B1800:   baud = 1800;    break;
212    case B2400:   baud = 2400;    break;
213    case B4800:   baud = 4800;    break;
214    case B9600:   baud = 9600;    break;
215    case B19200:  baud = 19200;   break;
216    case B38400:  baud = 38400;   break;
217    case B57600:  baud = 57600;   break;
218    case B115200: baud = 115200;  break;
219    case B230400: baud = 230400;  break;
220    case B460800: baud = 460800;  break;
221  }
222  if (baud > 0) {
223    sccr0 &= ~QSMCM_SCI_BAUD(-1);
224    sccr0 |=
225      QSMCM_SCI_BAUD((Cpu_table.clock_speed + (16 * baud)) / (32 * baud));
226  }
227     
228  /* Number of data bits -- not available with MPC5xx SCI */
229  switch ( t->c_cflag & CSIZE ) {
230    case CS5:     break;
231    case CS6:     break;
232    case CS7:     break;
233    case CS8:     break;
234  }
235
236  /* Stop bits -- not easily available with MPC5xx SCI */
237  if ( t->c_cflag & CSTOPB ) {
238    /* Two stop bits */
239  } else {
240    /* One stop bit */
241  }
242
243  /* Parity */
244  if ( t->c_cflag & PARENB )
245    sccr1 |= QSMCM_SCI_PE;
246  else
247    sccr1 &= ~QSMCM_SCI_PE;
248 
249  if ( t->c_cflag & PARODD )
250    sccr1 |= QSMCM_SCI_PT;
251  else
252    sccr1 &= ~QSMCM_SCI_PT;
253
254  /* Transmitter and receiver enable */
255  sccr1 |= QSMCM_SCI_TE;
256  if ( t->c_cflag & CREAD )
257    sccr1 |= QSMCM_SCI_RE;
258  else
259    sccr1 &= ~QSMCM_SCI_RE;
260   
261  /* Write hardware registers */
262  sci_descs[minor].regs->sccr0 = sccr0;
263  sci_descs[minor].regs->sccr1 = sccr1;
264 
265  return RTEMS_SUCCESSFUL;
266}
267
268
269/*
270 * Interrupt handling.
271 */
272static void
273m5xx_sci_interrupt_handler (rtems_irq_hdl_param unused)
274{
275  int minor;
276 
277  for ( minor = 0; minor < NUM_PORTS; minor++ ) {
278    sci_desc *desc = &sci_descs[minor];
279    int sccr1 = desc->regs->sccr1;
280    int scsr = desc->regs->scsr;
281       
282    /*
283     * Character received?
284     */
285    if ((sccr1 & QSMCM_SCI_RIE) && (scsr & QSMCM_SCI_RDRF)) {
286      char c = desc->regs->scdr;
287      rtems_termios_enqueue_raw_characters(desc->ttyp, &c, 1);
288    }
289    /*
290     * Transmitter empty?
291     */
292    if ((sccr1 & QSMCM_SCI_TIE) && (scsr & QSMCM_SCI_TDRE)) {
293      desc->regs->sccr1 &= ~QSMCM_SCI_TIE;
294      rtems_termios_dequeue_characters (desc->ttyp, 1);
295    }
296  }
297}
298
299void m5xx_sci_nop(const rtems_irq_connect_data* ptr)
300{
301}
302
303int m5xx_sci_isOn(const rtems_irq_connect_data* ptr)
304{
305  return 1;
306}
307
308/*
309 * Basic initialization.
310 */
311
312void
313m5xx_uart_initialize (int minor)
314{
315  /*
316   * Check that minor number is valid.
317   */
318  if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) )
319    return;
320
321  /*
322   * Configure and enable receiver and transmitter.
323   */
324  m5xx_uart_setAttributes(minor, &default_termios);
325   
326  /*
327   * Connect interrupt if not yet done.
328   */
329  if ( init_calls++ == 0 ) {
330    rtems_irq_connect_data irq_data;
331
332    irq_data.name = CPU_IRQ_SCI;
333    irq_data.hdl  = m5xx_sci_interrupt_handler;
334    irq_data.on   = m5xx_sci_nop;       /* can't enable both channels here */
335    irq_data.off  = m5xx_sci_nop;       /* can't disable both channels here */
336    irq_data.isOn = m5xx_sci_isOn;
337   
338    if (!CPU_install_rtems_irq_handler (&irq_data)) {
339      printk("Unable to connect SCI Irq handler\n");
340      rtems_fatal_error_occurred(1);
341    }
342
343    imb.qsmcm.qdsci_il =                /* set interrupt level in port */
344      QSMCM_ILDSCI(CPU_irq_level_from_symbolic_name(CPU_IRQ_SCI));
345  }
346}
Note: See TracBrowser for help on using the repository browser.