source: rtems/c/src/lib/libbsp/powerpc/mbx8xx/console/console.c @ 59d4d513

4.104.114.84.95
Last change on this file since 59d4d513 was 59d4d513, checked in by Joel Sherrill <joel.sherrill@…>, on 08/10/00 at 16:22:27

2000-08-10 Charles-Antoine Gauthier <charles.gauthier@…>

  • README: Updated.
  • console/console.c: Addition of support for shared printk and no termios.
  • include/bsp.h: Addition of second parameter to rtems_enet_driver_attach. Removed prototypes for printk and BSP_output_string.
  • network/network.c(rtems_enet_driver_attach): Addition of second parameter to function.
  • Property mode set to 100644
File size: 16.5 KB
Line 
1/*
2 *  console.c
3 *
4 *  This file contains the MBX8xx termios serial I/O package.
5 *  Only asynchronous I/O is supported.
6 *
7 *  The SCCs and SMCs are assigned as follows
8 *
9 *   Channel     Device      Minor   Note
10 *    SMC1      /dev/tty0      0
11 *    SMC2      /dev/tty1      1
12 *    SCC1                     2     N/A. Hardwired as ethernet port
13 *    SCC2      /dev/tty2      3
14 *    SCC3      /dev/tty3      4
15 *    SCC4      /dev/tty4      5
16 *
17 *  All ports support termios. The use of termios is recommended for real-time
18 *  applications. Termios provides buffering and input processing. When not
19 *  using termios, processing is limited to the substitution of LF for CR on
20 *  input, and the output of a CR following the output of a LF character.
21 *  Note that the terminal should not send CR/LF pairs when the return key
22 *  is pressed, and that output lines are terminated with LF/CR, not CR/LF
23 *  (although that would be easy to change).
24 *
25 *  I/O may be interrupt-driven (recommended for real-time applications) or
26 *  polled. Polled I/O may be performed by this device driver entirely, or
27 *  in part by EPPCBug. With EPPCBug 1.1, polled I/O is limited to the
28 *  EPPCBug debug console. This is a limitation of the firmware. Later
29 *  firmware may be able to do I/O through any port. This code assumes
30 *  that the EPPCBug console is the default: SMC1. If the console and
31 *  printk ports are set to anything else with EPPCBug polled I/O, the
32 *  system will hang. Only port SMC1 is usable with EPPCBug polled I/O.
33 *
34 *  LIMITATIONS:
35 *
36 *  It is not possible to use different I/O modes on the different ports. The
37 *  exception is with printk. The printk port can use a different mode from
38 *  the other ports. If this is done, it is important not to open the printk
39 *  port from an RTEMS application.
40 *
41 *  Currently, the I/O modes are determined at build time. It would be much
42 *  better to have the mode selected at boot time based on parameters in
43 *  NVRAM.
44 *
45 *  Interrupt-driven I/O requires termios.
46 *
47 *  TESTS:
48 *
49 *  TO RUN THE TESTS, USE POLLED I/O WITHOUT TERMIOS SUPPORT. Some tests
50 *  play with the interrupt masks and turn off I/O. Those tests will hang
51 *  when interrupt-driven I/O is used. Other tests, such as cdtest, do I/O
52 *  from the static constructors before the console is open. This test
53 *  will not work with interrupt-driven I/O. Because of the buffering
54 *  performed in termios, test output may not be in sequence.The tests
55 *  should all be fixed to work with interrupt-driven I/O and to
56 *  produce output in the expected sequence. Obviously, the termios test
57 *  requires termios support in the driver.
58 * 
59 *  Set CONSOLE_MINOR to the appropriate device minor number in the
60 *  config file. This allows the RTEMS application console to be different
61 *  from the EPPBug debug console or the GDB port.
62 *
63 *  This driver handles all five available serial ports: it distinguishes
64 *  the sub-devices using minor device numbers. It is not possible to have
65 *  other protocols running on the other ports when this driver is used as
66 *  currently written.
67 * 
68 *  Based on code (alloc860.c in eth_comm port) by
69 *  Jay Monkman (jmonkman@frasca.com),
70 *  Copyright (C) 1998 by Frasca International, Inc.
71 *
72 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
73 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>.
74 *  Copyright (c) 2000, National Research Council of Canada
75 *
76 */
77#include <stdarg.h>
78#include <stdio.h>
79#include <bsp.h>                /* Must be before libio.h */
80#include <bspIo.h>
81#include <rtems/libio.h>
82#include <termios.h>
83
84#if UARTS_IO_MODE == 0
85#define BSP_WRITE m8xx_uart_pollWrite
86#define BSP_READ  m8xx_uart_pollRead
87#elif UARTS_IO_MODE == 1
88#define BSP_WRITE m8xx_uart_write
89#elif UARTS_IO_MODE == 2
90#define BSP_WRITE _EPPCBug_pollWrite
91#define BSP_READ  _EPPCBug_pollRead
92#endif
93
94static int _EPPCBug_pollRead( int minor );
95static int _EPPCBug_pollWrite( int minor, const char *buf, int len );
96static void _BSP_output_char( char c );
97
98BSP_output_char_function_type BSP_output_char = _BSP_output_char;
99
100
101/*
102 * _EPPCBug_pollRead
103 *
104 *  Read a character from the EPPCBug console, and return it. Return -1
105 *  if there is no character in the input FIFO.
106 *
107 *  Input parameters:
108 *    minor - selected channel
109 *
110 *  Output parameters:  NONE
111 *
112 *  Return value: char returned as positive signed int
113 *                -1 if no character is present in the input FIFO.
114 */
115int _EPPCBug_pollRead(
116  int minor
117)
118{
119  extern volatile m8xx_t m8xx;
120
121  char c;
122  volatile int simask;          /* We must read and write m8xx.simask */
123  int retval;
124  ISR_Level level;
125 
126  struct {
127    int clun;
128    int dlun;
129    char * inbuf;
130    int nbytes_requested;
131    int reserved;
132  } volatile input_params;
133 
134  struct {
135    int status;
136    union {
137      struct {
138        int input_char_available;
139        int output_possible;
140        int break_detected;
141        int modem_status;
142      } stat;
143      struct {
144        int nbytes_received;
145      } read;
146    } u;
147  } volatile output_params;
148
149  retval = -1;
150
151  input_params.clun = 0;
152  input_params.dlun = 0;
153 
154  switch( minor ) {
155    case SMC1_MINOR:   
156      input_params.dlun = 0;  /* Should be 4, but doesn't work with EPPCBug 1.1 */
157      break;
158    case SMC2_MINOR:   
159      input_params.dlun = 5;
160      break;
161    case SCC2_MINOR:   
162      input_params.dlun = 1;
163      break;
164#ifdef mpc860
165    case SCC3_MINOR:   
166      input_params.dlun = 2;
167      break;
168    case SCC4_MINOR:   
169      input_params.dlun = 3;
170      break;
171#endif
172    default:   
173      input_params.dlun = 0;
174      break;
175  }
176 
177  _ISR_Disable( level );
178  simask = m8xx.simask;
179
180  /* Check for a char in the input FIFO using .CIO_STAT */
181  asm volatile( "li 10,0x202
182                 mr 3, %0
183                 mr 4, %1
184                 sc"
185    :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" );
186
187  if ( (output_params.status == 0) && output_params.u.stat.input_char_available) {
188 
189    /* Read the char and return it */
190    input_params.inbuf = &c;
191    input_params.nbytes_requested = 1;
192 
193    asm volatile( "li     10,0x200     /* Code for .CIO_READ */
194                   mr    3, %0         /* Address of input_params */
195                   mr    4, %1         /* Address of output_params */
196                   sc"             /* Call EPPCBUG */
197      :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" );
198
199    if ( (output_params.status == 0) && output_params.u.read.nbytes_received)
200      retval = (int)c;
201  }
202 
203  m8xx.simask = simask;
204  _ISR_Enable( level );
205  return retval;
206}
207
208
209/*
210 * _EPPCBug_pollWrite
211 *
212 *  Output buffer through EPPCBug. Returns only once every character has been
213 *  sent (polled output).
214 *
215 *  Input parameters:
216 *    minor - selected channel
217 *    buf - output buffer
218 *    len - number of chars to output
219 *
220 *  Output parameters:  NONE
221 *
222 *  Return value: IGNORED
223 */
224int _EPPCBug_pollWrite(
225  int minor,
226  const char *buf,
227  int len
228)
229{
230  extern volatile m8xx_t m8xx;
231
232  volatile int simask;
233  int i, retval;
234  ISR_Level level;
235 
236  struct {
237    int clun;
238    int dlun;
239    const char * outbuf;
240    int nbytes_to_output;
241    int reserved;
242  } volatile input_params;
243 
244  struct {
245    int status;
246    union {
247      struct {
248        int input_char_available;
249        int output_possible;
250        int break_detected;
251        int modem_status;
252      } stat;
253      struct {
254        int nbytes_sent;
255      } write;
256    } u;
257  } volatile output_params;
258
259  retval = -1;
260
261  input_params.clun = 0;
262  input_params.reserved = 0;
263 
264  switch( minor ) {
265    case SMC1_MINOR:   
266      input_params.dlun = 0;  /* Should be 4, but doesn't work with EPPCBug 1.1 */
267      break;
268    case SMC2_MINOR:   
269      input_params.dlun = 5;
270      break;
271    case SCC2_MINOR:   
272      input_params.dlun = 1;
273      break;
274#ifdef mpc860
275    case SCC3_MINOR:   
276      input_params.dlun = 2;
277      break;
278    case SCC4_MINOR:   
279      input_params.dlun = 3;
280      break;
281#endif
282    default:   
283      input_params.dlun = 0;
284      break;
285  }
286
287  i = 0;
288
289  _ISR_Disable( level );
290  simask = m8xx.simask;
291
292  while (i < len) {
293    /* Wait for space in the output buffer */
294    do {
295      /* Check for space in the output FIFO */
296      asm volatile( "li 10,0x202        /* Code for .CIO_STAT */
297                     mr 3, %0           /* Address of input_params */
298                     mr 4, %1           /* Address of output_params */
299                     sc"            /* Call EPPCBUG */
300        :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" );
301
302      if (output_params.status)
303        goto error;
304    } while (!output_params.u.stat.output_possible);
305
306    /* Output the characters until done */
307    input_params.outbuf = &buf[i];
308    input_params.nbytes_to_output = len - i;
309 
310    asm volatile( "li 10,0x201          /* Code for .CIO_WRITE */
311                   mr 3, %0             /* Address of input_params */
312                   mr 4, %1             /* Address of output_params */
313                   sc"                  /* Call EPPCBUG */
314      :: "g" (&input_params), "g" (&output_params) : "3", "4", "10" );
315
316    if (output_params.status)
317      goto error;
318
319    i += output_params.u.write.nbytes_sent;
320  }
321 
322  /* Return something */
323  m8xx.simask = simask;
324  _ISR_Enable( level );
325  return RTEMS_SUCCESSFUL;
326
327error:
328  m8xx.simask = simask;
329  _ISR_Enable( level );
330  return -1;
331}
332
333
334/*
335 *  Print functions prototyped in bspIo.h
336 */
337
338void _BSP_output_char( char c )
339{
340  char cr = '\r';
341 
342  BSP_WRITE( PRINTK_MINOR, &c, 1 );
343  if( c == '\n' )
344    BSP_WRITE( PRINTK_MINOR, &cr, 1 );
345}
346
347
348/*
349 ***************
350 * BOILERPLATE *
351 ***************
352 *
353 *  All these functions are prototyped in rtems/c/src/lib/include/console.h.
354 */
355
356/*
357 * Initialize and register the device
358 */
359rtems_device_driver console_initialize(
360  rtems_device_major_number major,
361  rtems_device_minor_number minor,
362  void *arg
363)
364{
365  rtems_status_code status;
366 
367  /*
368   * Set up TERMIOS
369   */
370#if UARTS_USE_TERMIOS == 1
371  rtems_termios_initialize();
372#endif
373  /*
374   *  Do common initialization.
375   */
376  m8xx_uart_initialize();
377 
378  /*
379   * Do device-specific initialization
380   */
381#if !defined(EPPCBUG_SMC1) && ( PRINTK_IO_MODE != 2 || PRINTK_MINOR != SMC1_MINOR )
382  m8xx_uart_smc_initialize(SMC1_MINOR); /* /dev/tty0 */
383#endif
384
385#if PRINTK_IO_MODE != 2 || PRINTK_MINOR != SMC2_MINOR
386  m8xx_uart_smc_initialize(SMC2_MINOR); /* /dev/tty1 */                             
387#endif
388
389  #if PRINTK_IO_MODE != 2 || PRINTK_MINOR != SCC2_MINOR
390  m8xx_uart_scc_initialize(SCC2_MINOR); /* /dev/tty2    */
391   #endif
392                           
393#ifdef mpc860
394
395#if PRINTK_IO_MODE != 2 || PRINTK_MINOR != SCC3_MINOR
396  m8xx_uart_scc_initialize(SCC3_MINOR); /* /dev/tty3    */
397#endif
398
399#if PRINTK_IO_MODE != 2 || PRINTK_MINOR != SCC4_MINOR
400  m8xx_uart_scc_initialize(SCC4_MINOR); /* /dev/tty4    */
401#endif
402
403#endif /* mpc860 */
404
405  /*
406   * Set up interrupts
407   */
408   m8xx_uart_interrupts_initialize();
409
410  status = rtems_io_register_name ("/dev/tty0", major, SMC1_MINOR);
411  if (status != RTEMS_SUCCESSFUL)
412    rtems_fatal_error_occurred (status);
413   
414  status = rtems_io_register_name ("/dev/tty1", major, SMC2_MINOR);
415  if (status != RTEMS_SUCCESSFUL)
416    rtems_fatal_error_occurred (status);
417   
418  status = rtems_io_register_name ("/dev/tty2", major, SCC2_MINOR);
419  if (status != RTEMS_SUCCESSFUL)
420    rtems_fatal_error_occurred (status);
421   
422#ifdef mpc860
423  status = rtems_io_register_name ("/dev/tty3", major, SCC3_MINOR);
424  if (status != RTEMS_SUCCESSFUL)
425    rtems_fatal_error_occurred (status);
426                             
427  status = rtems_io_register_name ("/dev/tty4", major, SCC4_MINOR);
428  if (status != RTEMS_SUCCESSFUL)
429    rtems_fatal_error_occurred (status);
430   
431#endif /* mpc860 */
432   
433  /* Now register the RTEMS console */
434  status = rtems_io_register_name ("/dev/console", major, CONSOLE_MINOR);
435  if (status != RTEMS_SUCCESSFUL)
436    rtems_fatal_error_occurred (status);
437   
438  return RTEMS_SUCCESSFUL;
439}
440
441
442/*
443 * Open the device
444 */
445rtems_device_driver console_open(
446  rtems_device_major_number major,
447  rtems_device_minor_number minor,
448  void *arg
449)
450{
451  /* Used to track termios private data for callbacks */
452#if UARTS_IO_MODE == 1
453  extern struct rtems_termios_tty *ttyp[];
454  rtems_libio_open_close_args_t *args = arg;
455#endif
456
457  rtems_status_code sc;
458
459#if UARTS_USE_TERMIOS == 1
460  static const rtems_termios_callbacks sccEPPCBugCallbacks = {
461    NULL,                               /* firstOpen */
462    NULL,                               /* lastClose */
463    _EPPCBug_pollRead,                  /* pollRead */
464    _EPPCBug_pollWrite,                 /* write */
465    NULL,                               /* stopRemoteTx */
466    NULL,                               /* startRemoteTx */
467    0                                   /* outputUsesInterrupts */
468  };
469  static const rtems_termios_callbacks intrCallbacks = {
470    NULL,                               /* firstOpen */
471    NULL,                               /* lastClose */
472    NULL,                         /* pollRead */
473    m8xx_uart_write,                  /* write */
474    m8xx_uart_setAttributes,            /* setAttributes */
475    NULL,                               /* stopRemoteTx */
476    NULL,                               /* startRemoteTx */
477    1                                   /* outputUsesInterrupts */
478  };
479  static const rtems_termios_callbacks pollCallbacks = {
480    NULL,                               /* firstOpen */
481    NULL,                               /* lastClose */
482    m8xx_uart_pollRead,           /* pollRead */
483    m8xx_uart_pollWrite,          /* write */
484    m8xx_uart_setAttributes,      /* setAttributes */
485    NULL,                               /* stopRemoteTx */
486    NULL,                               /* startRemoteTx */
487    0                                   /* outputUsesInterrupts */
488  };
489#endif
490   
491  if ( minor > NUM_PORTS-1 )
492    return RTEMS_INVALID_NUMBER;
493
494#if UARTS_USE_TERMIOS == 1
495
496#if UARTS_IO_MODE == 2    /* EPPCBug polled I/O with termios */
497
498  sc = rtems_termios_open (major, minor, arg, &sccEPPCBugCallbacks);
499 
500#elif UARTS_IO_MODE == 1  /* RTEMS interrupt-driven I/O with termios */
501
502  sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
503  ttyp[minor] = args->iop->data1;        /* Keep cookie returned by termios_open */
504 
505#else                     /* RTEMS polled I/O with termios */
506
507  sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
508 
509#endif
510
511#else                     /* Nothing to do if termios is not used */
512
513  sc = RTEMS_SUCCESSFUL;
514 
515#endif
516
517  return sc;
518}
519
520
521/*
522 * Close the device
523 */
524rtems_device_driver console_close(
525  rtems_device_major_number major,
526  rtems_device_minor_number minor,
527  void *arg
528)
529{
530  if ( minor > NUM_PORTS-1 )
531    return RTEMS_INVALID_NUMBER;
532
533#if UARTS_USE_TERMIOS == 1
534  return rtems_termios_close (arg);
535#else
536  return RTEMS_SUCCESSFUL;
537#endif
538}
539
540
541/*
542 * Read from the device
543 */
544rtems_device_driver console_read(
545  rtems_device_major_number major,
546  rtems_device_minor_number minor,
547  void *arg
548)
549{
550#if UARTS_USE_TERMIOS != 1
551  rtems_libio_rw_args_t *rw_args = arg;
552  int i;
553#endif
554 
555  if ( minor > NUM_PORTS-1 )
556    return RTEMS_INVALID_NUMBER;
557
558#if UARTS_USE_TERMIOS == 1
559
560  return rtems_termios_read(arg);
561 
562#else
563
564#if UARTS_IO_MODE != 1    /* Polled I/O without termios */
565
566  for( i = 0; i < rw_args->count; i++ ) {
567    rw_args->buffer[i] = BSP_READ( minor );
568    if( rw_args->buffer[i] == '\r' )
569      rw_args->buffer[i] = '\n';
570  }
571  rw_args->bytes_moved = i;
572  return RTEMS_SUCCESSFUL;
573 
574#else                     /* RTEMS interrupt-driven I/O without termios */
575
576  #error "Interrupt-driven input without termios is not yet supported"
577 
578#endif
579
580#endif
581}
582
583
584/*
585 * Write to the device
586 */
587rtems_device_driver console_write(
588  rtems_device_major_number major,
589  rtems_device_minor_number minor,
590  void *arg
591)
592{
593#if UARTS_USE_TERMIOS != 1
594  rtems_libio_rw_args_t *rw_args = arg;
595  int i;
596  char cr = '\r';
597#endif
598
599  if ( minor > NUM_PORTS-1 )
600    return RTEMS_INVALID_NUMBER;
601
602#if UARTS_USE_TERMIOS == 1
603
604  return rtems_termios_write(arg);
605 
606#else
607
608#if UARTS_IO_MODE != 1     /* Polled I/O without termios*/
609
610  /* Must add carriage return to line feeds */
611  for( i = 0; i < rw_args->count; i++ ) {
612    BSP_WRITE( minor, &(rw_args->buffer[i]), 1 );
613    if( rw_args->buffer[i] == '\n' )
614      BSP_WRITE( minor, &cr, 1 );
615  }
616  rw_args->bytes_moved = rw_args->count;
617  return RTEMS_SUCCESSFUL;
618   
619#else                     /* RTEMS interrupt-driven I/O without termios */
620
621  #error "Interrupt-driven output without termios is not yet supported"
622 
623#endif
624
625#endif
626}
627
628
629/*
630 * Handle ioctl request.
631 */
632rtems_device_driver console_control(
633  rtems_device_major_number major,
634  rtems_device_minor_number minor,
635  void *arg
636)
637{
638  if ( minor > NUM_PORTS-1 )
639    return RTEMS_INVALID_NUMBER;
640
641#if UARTS_USE_TERMIOS == 1
642  return rtems_termios_ioctl (arg);
643#else
644  return RTEMS_SUCCESSFUL;
645#endif
646}
647
Note: See TracBrowser for help on using the repository browser.