Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:52

0001 /*
0002  * RTEMS generic MPC5200 BSP
0003  *
0004  * This file contains the console driver functions.
0005  *
0006  * The PSCs of mpc5200 are assigned as follows
0007  *
0008  *    Channel     Device      Minor   Note
0009  *      PSC1      /dev/tty0      0
0010  *      PSC2      /dev/tty1      1
0011  *      PSC3      /dev/tty2      2
0012  */
0013 
0014 /*
0015  * Author: Jay Monkman (jmonkman@frasca.com)
0016  * Copyright (C) 1998 by Frasca International, Inc.
0017  *
0018  * Derived from c/src/lib/libbsp/m68k/gen360/console/console.c
0019  * Author: W. Eric Norum <eric@norum.ca>
0020  *
0021  * COPYRIGHT (c) 1989, 2008.
0022  * On-Line Applications Research Corporation (OAR).
0023  *
0024  * Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
0025  * and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
0026  * Copyright (c) 1999, National Research Council of Canada
0027  *
0028  * Modifications by Andy Dachs <a.dachs@sstl.co.uk> to add MPC8260 support.
0029  * Copyright (c) 2001, Surrey Satellite Technology Ltd
0030  *
0031  * Copyright (c) 2003, IPR Engineering
0032  *
0033  * Copyright (c) 2005 embedded brains GmbH & Co. KG
0034  *
0035  * The license and distribution terms for this file may be
0036  * found in the file LICENSE in this distribution or at
0037  * http://www.rtems.org/license/LICENSE.
0038  */
0039 
0040 #include <assert.h>
0041 #include <string.h>
0042 
0043 #include <rtems.h>
0044 #include <bsp/mpc5200.h>
0045 #include <bsp.h>
0046 #include <bsp/irq.h>
0047 
0048 #include <rtems/console.h>
0049 #include <rtems/bspIo.h>
0050 #include <rtems/libio.h>
0051 #include <rtems/termiostypes.h>
0052 
0053 
0054 #define NUM_PORTS       MPC5200_PSC_NO
0055 
0056 #define PSC1_MINOR      0
0057 #define PSC2_MINOR      1
0058 #define PSC3_MINOR      2
0059 #define PSC4_MINOR      3
0060 #define PSC5_MINOR      4
0061 #define PSC6_MINOR      5
0062 
0063 uint32_t mpc5200_uart_avail_mask = BSP_UART_AVAIL_MASK;
0064 
0065 #if defined(UARTS_USE_TERMIOS_INT)
0066   uint8_t psc_minor_to_irqname[NUM_PORTS] = {
0067      BSP_SIU_IRQ_PSC1,
0068      BSP_SIU_IRQ_PSC2,
0069      BSP_SIU_IRQ_PSC3,
0070      BSP_SIU_IRQ_PSC4,
0071      BSP_SIU_IRQ_PSC5,
0072      BSP_SIU_IRQ_PSC6
0073   };
0074 
0075   static int mpc5200_psc_irqname_to_minor(int name) {
0076     int      minor;
0077     uint8_t *chrptr;
0078 
0079     chrptr = memchr(psc_minor_to_irqname, name, sizeof(psc_minor_to_irqname));
0080     if (chrptr != NULL) {
0081       minor = chrptr - psc_minor_to_irqname;
0082     } else {
0083       minor = -1;
0084     }
0085     return minor;
0086   }
0087 #endif
0088 
0089 static void A_BSP_output_char(char c);
0090 static int A_BSP_get_char(void);
0091 BSP_output_char_function_type BSP_output_char = A_BSP_output_char;
0092 
0093 BSP_polling_getchar_function_type BSP_poll_char = A_BSP_get_char;
0094 
0095 /* Used to handle premature outputs of printk */
0096 bool console_initialized = false;
0097 
0098 /* per channel info structure */
0099 struct per_channel_info {
0100   uint16_t shadow_imr;
0101   uint8_t shadow_mode1;
0102   uint8_t shadow_mode2;
0103   int cur_tx_len;
0104   int rx_interrupts;
0105   int tx_interrupts;
0106   int rx_characters;
0107   int tx_characters;
0108   int breaks_detected;
0109   int framing_errors;
0110   int parity_errors;
0111   int overrun_errors;
0112 };
0113 
0114 /* Used to handle more than one channel */
0115 struct per_channel_info channel_info[NUM_PORTS];
0116 
0117 /*
0118  * XXX: there are only 6 PSCs, but PSC6 has an extra register gap
0119  *      from PSC5, therefore we instantiate seven(!) PSC register sets
0120  */
0121 uint8_t psc_minor_to_regset[MPC5200_PSC_NO] = {0,1,2,3,4,6};
0122 
0123 /* Used to track termios private data for callbacks */
0124 struct rtems_termios_tty *ttyp[NUM_PORTS];
0125 
0126 static int mpc5200_psc_setAttributes(
0127   int                   minor,
0128   const struct termios *t
0129 )
0130 {
0131   int baud;
0132   uint8_t csize=0, cstopb, parenb, parodd;
0133   struct mpc5200_psc *psc =
0134     (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0135 
0136   /* Baud rate */
0137   baud = rtems_termios_baud_to_number(t->c_ospeed);
0138   if (baud > 0) {
0139    /*
0140     * Calculate baud rate
0141     * round divider to nearest!
0142     */
0143     baud = (IPB_CLOCK + baud *16) / (baud * 32);
0144   }
0145 
0146   /* Number of data bits */
0147   switch ( t->c_cflag & CSIZE ) {
0148     case CS5:     csize = 0x00;  break;
0149     case CS6:     csize = 0x01;  break;
0150     case CS7:     csize = 0x02;  break;
0151     case CS8:     csize = 0x03;  break;
0152   }
0153 
0154   /* Stop bits */
0155   if(csize == 0) {
0156     if(t->c_cflag & CSTOPB)
0157       cstopb = 0x0F;           /* Two stop bits */
0158     else
0159       cstopb = 0x00;           /* One stop bit */
0160   } else {
0161     if(t->c_cflag & CSTOPB)
0162       cstopb = 0x0F;           /* Two stop bits */
0163     else
0164       cstopb = 0x07;           /* One stop bit */
0165   }
0166 
0167   /* Parity */
0168   if (t->c_cflag & PARENB)
0169     parenb = 0x00;             /* Parity enabled on Tx and Rx */
0170   else
0171     parenb = 0x10;             /* No parity on Tx and Rx */
0172 
0173   if (t->c_cflag & PARODD)
0174     parodd = 0x04;             /* Odd parity */
0175   else
0176     parodd = 0x00;
0177 
0178  /*
0179   * Set upper timer counter
0180   */
0181   psc->ctur = (uint8_t) (baud >> 8);
0182 
0183  /*
0184   * Set lower timer counter
0185   */
0186   psc->ctlr = (uint8_t) baud;
0187 
0188  /*
0189   * Reset mode pointer
0190   */
0191   psc->cr = ((1 << 4) << 8);
0192 
0193  /*
0194   * Set mode1 register
0195   */
0196   channel_info[minor].shadow_mode1 &= ~(0x1F);
0197   psc->mr = channel_info[minor].shadow_mode1 | (csize | parenb | parodd);
0198 
0199  /*
0200   * Set mode2 register
0201   */
0202   channel_info[minor].shadow_mode2 &= ~(0x0F);
0203   psc->mr = channel_info[minor].shadow_mode2 | cstopb;
0204 
0205   return 0;
0206 
0207 }
0208 
0209 
0210 static int mpc5200_uart_setAttributes(int minor, const struct termios *t)
0211 {
0212   /*
0213    * Check that port number is valid
0214    */
0215   if( (minor < PSC1_MINOR) || (minor > NUM_PORTS-1) )
0216     return 0;
0217 
0218   return mpc5200_psc_setAttributes(minor, t);
0219 
0220 }
0221 
0222 #ifdef UARTS_USE_TERMIOS_INT
0223 /*
0224  * Interrupt handlers
0225  */
0226 static void mpc5200_psc_interrupt_handler(rtems_irq_hdl_param handle)
0227 {
0228   unsigned char c;
0229   uint16_t isr;
0230   int minor = (int)handle;
0231   struct mpc5200_psc *psc =
0232     (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0233 
0234   /*
0235    * get content of psc interrupt status
0236    */
0237   isr = psc->isr_imr;
0238 
0239   /*
0240    * Character received?
0241    */
0242   if (isr & ISR_RX_RDY_FULL) {
0243 
0244     channel_info[minor].rx_interrupts++;
0245 
0246 
0247 #ifndef SINGLE_CHAR_MODE
0248     while(psc->rfnum) {
0249 #endif
0250       /*
0251        * get the character
0252        */
0253        c = (psc->rb_tb >> 24);
0254 
0255       if (ttyp[minor] != NULL) {
0256         rtems_termios_enqueue_raw_characters(
0257            (void *)ttyp[minor], (char *)&c, (int)1);
0258         channel_info[minor].rx_characters++;
0259       }
0260 
0261 #ifndef SINGLE_CHAR_MODE
0262     }
0263 #endif
0264 
0265   }
0266 
0267   /*
0268    * Character transmitted ?
0269    */
0270   if (isr & ISR_TX_RDY & channel_info[minor].shadow_imr) {
0271     channel_info[minor].tx_interrupts++;
0272 
0273     if (ttyp[minor] != NULL) {
0274       #ifndef SINGLE_CHAR_MODE
0275         rtems_termios_dequeue_characters(
0276            (void *)ttyp[minor], channel_info[minor].cur_tx_len);
0277         channel_info[minor].tx_characters += channel_info[minor].cur_tx_len;
0278       #else
0279         rtems_termios_dequeue_characters((void *)ttyp[minor], (int)1);
0280         channel_info[minor].tx_characters++;
0281       #endif
0282     }
0283   }
0284 
0285   if(isr & ISR_ERROR) {
0286     if(isr & ISR_RB)
0287       channel_info[minor].breaks_detected++;
0288     if(isr & ISR_FE)
0289       channel_info[minor].framing_errors++;
0290     if(isr & ISR_PE)
0291       channel_info[minor].parity_errors++;
0292     if(isr & ISR_OE)
0293       channel_info[minor].overrun_errors++;
0294 
0295     /*
0296      *  Reset error status
0297      */
0298     psc->cr = ((4 << 4) << 8);
0299   }
0300 }
0301 
0302 static void mpc5200_psc_enable(
0303   const rtems_irq_connect_data* ptr
0304 )
0305 {
0306   struct mpc5200_psc *psc;
0307   int minor =  mpc5200_psc_irqname_to_minor(ptr->name);
0308 
0309   if (minor >= 0) {
0310     psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0311     psc->isr_imr = channel_info[minor].shadow_imr |=
0312       (IMR_RX_RDY_FULL | IMR_TX_RDY);
0313   }
0314 }
0315 
0316 
0317 static void mpc5200_psc_disable(
0318   const rtems_irq_connect_data* ptr
0319 )
0320 {
0321   struct mpc5200_psc *psc;
0322   int minor =  mpc5200_psc_irqname_to_minor(ptr->name);
0323 
0324   if (minor >= 0) {
0325     psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0326     psc->isr_imr = channel_info[minor].shadow_imr &=
0327       ~(IMR_RX_RDY_FULL | IMR_TX_RDY);
0328   }
0329 }
0330 
0331 static int mpc5200_psc_isOn(
0332   const rtems_irq_connect_data* ptr
0333 )
0334 {
0335   struct mpc5200_psc *psc;
0336   int minor =  mpc5200_psc_irqname_to_minor(ptr->name);
0337 
0338   if (minor >= 0) {
0339     psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0340     return ((psc->isr_imr & IMR_RX_RDY_FULL) & (psc->isr_imr & IMR_TX_RDY));
0341   }
0342   return false;
0343 }
0344 
0345 
0346 static rtems_irq_connect_data consoleIrqData;
0347 #endif
0348 
0349 static void mpc5200_uart_psc_initialize(
0350   int minor
0351 )
0352 {
0353   uint32_t baud_divider;
0354   struct mpc5200_psc *psc =
0355     (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0356 
0357   /*
0358    * Check that minor number is valid
0359    */
0360   if ((minor < PSC1_MINOR) || (minor >= (PSC1_MINOR + NUM_PORTS)))
0361     return;
0362 
0363   /*
0364    * Clear per channel info
0365    */
0366   memset((void *)&channel_info[minor], 0, sizeof(struct per_channel_info));
0367 
0368   /*
0369    * Reset receiver and transmitter
0370    */
0371   psc->cr = ((2 << 4) << 8);
0372   psc->cr = ((3 << 4) << 8);
0373 
0374   /*
0375    * Reset mode pointer
0376    */
0377   psc->cr = ((1 << 4) << 8);
0378 
0379   /*
0380    * Set clock select register
0381    */
0382   psc->sr_csr = 0;
0383 
0384   /*
0385    * Set mode1 register
0386    */
0387   psc->mr = channel_info[minor].shadow_mode1 = 0x33; /* 8Bit / no parity */
0388 
0389   /*
0390    * Set mode2 register
0391    */
0392   psc->mr = channel_info[minor].shadow_mode2 = 7; /* 1 stop bit */
0393 
0394   /*
0395    * Set rx FIFO alarm
0396    */
0397   psc->rfalarm = RX_FIFO_SIZE - 1;
0398 
0399   /*
0400    * Set tx FIFO alarm
0401    */
0402   psc->tfalarm = 1;
0403 
0404   baud_divider =
0405     (IPB_CLOCK + GEN5200_CONSOLE_BAUD *16) / (GEN5200_CONSOLE_BAUD * 32);
0406 
0407   /*
0408    * Set upper timer counter
0409    */
0410   psc->ctur = baud_divider >> 16;
0411 
0412   /*
0413    * Set lower timer counter
0414    */
0415 
0416   psc->ctlr = baud_divider & 0x0000ffff;
0417 
0418   /*
0419    * Disable Frame mode / set granularity 0
0420    */
0421   psc->tfcntl = 0;
0422 
0423 #ifdef UARTS_USE_TERMIOS_INT
0424   /*
0425    * Tie interrupt dependent routines
0426    */
0427   consoleIrqData.on     = mpc5200_psc_enable;
0428   consoleIrqData.off    = mpc5200_psc_disable;
0429   consoleIrqData.isOn   = mpc5200_psc_isOn;
0430   consoleIrqData.handle = (rtems_irq_hdl_param)minor;
0431   consoleIrqData.hdl    = (rtems_irq_hdl)mpc5200_psc_interrupt_handler;
0432 
0433   /*
0434    * Tie interrupt handler
0435    */
0436   consoleIrqData.name = psc_minor_to_irqname[minor];
0437 
0438   /*
0439    * Install rtems irq handler
0440    */
0441   assert(BSP_install_rtems_irq_handler(&consoleIrqData) == 1);
0442 #endif
0443 
0444   /*
0445    * Reset rx fifo errors Error/UF/OF
0446    */
0447   psc->rfstat |= 0x70;
0448 
0449   /*
0450    * Reset tx fifo errors Error/UF/OF
0451    */
0452   psc->tfstat |= 0x70;
0453 
0454 #ifdef UARTS_USE_TERMIOS_INT
0455   /*
0456    * Unmask receive interrupt
0457    */
0458   psc->isr_imr = channel_info[minor].shadow_imr = IMR_RX_RDY_FULL;
0459 #endif
0460 
0461   /*
0462    * Enable receiver
0463    */
0464   psc->cr = ((1 << 0) << 8);
0465 
0466   /*
0467    * Enable transmitter
0468    */
0469   psc->cr = ((1 << 2) << 8);
0470 }
0471 
0472 
0473 static int mpc5200_uart_pollRead(
0474   int minor
0475 )
0476 {
0477   unsigned char c;
0478   struct mpc5200_psc *psc =
0479     (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0480 
0481   if (psc->sr_csr & (1 << 8))
0482      c = (psc->rb_tb >> 24);
0483   else
0484      return -1;
0485 
0486   return c;
0487 }
0488 
0489 
0490 static ssize_t mpc5200_uart_pollWrite(
0491   int minor,
0492   const char *buf,
0493   size_t len
0494 )
0495 {
0496   size_t retval = len;
0497   const char *tmp_buf = buf;
0498   struct mpc5200_psc *psc =
0499     (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0500 
0501   while(len--) {
0502     while(!(psc->sr_csr & (1 << 11)))
0503       continue;
0504 
0505     /*rtems_cache_flush_multiple_data_lines( (void *)buf, 1);*/
0506 
0507     psc->rb_tb = (*tmp_buf << 24);
0508 
0509     tmp_buf++;
0510 
0511   }
0512   return retval;
0513 
0514 }
0515 
0516 static ssize_t mpc5200_uart_write(
0517   int         minor,
0518   const char *buf,
0519   size_t len
0520 )
0521 {
0522   struct mpc5200_psc *psc =
0523     (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
0524 
0525   if (len > 0) {
0526     int frame_len = len;
0527     const char *frame_buf = buf;
0528 
0529    /*
0530     * Check tx fifo space
0531     */
0532     if(len > (TX_FIFO_SIZE - psc->tfnum))
0533       frame_len = TX_FIFO_SIZE - psc->tfnum;
0534 
0535 #ifndef SINGLE_CHAR_MODE
0536     channel_info[minor].cur_tx_len = frame_len;
0537 #else
0538     frame_len = 1;
0539 #endif
0540 
0541    /*rtems_cache_flush_multiple_data_lines( (void *)frame_buf, frame_len);*/
0542 
0543     while (frame_len--)
0544       /* perform byte write to avoid extra NUL characters */
0545       (* (volatile char *)&(psc->rb_tb)) = *frame_buf++;
0546 
0547    /*
0548     * unmask interrupt
0549     */
0550     psc->isr_imr = channel_info[minor].shadow_imr |= IMR_TX_RDY;
0551   } else {
0552     /*
0553      * mask interrupt
0554      */
0555     psc->isr_imr = channel_info[minor].shadow_imr &= ~(IMR_TX_RDY);
0556   }
0557 
0558   return 0;
0559 }
0560 
0561 /*
0562  *  Print functions prototyped in bspIo.h
0563  */
0564 static void A_BSP_output_char(
0565   char c
0566 )
0567 {
0568   /*
0569    *  If we are using U-Boot, then the console is already initialized
0570    *  and we can just poll bytes out at any time.
0571    */
0572   #if !defined(HAS_UBOOT)
0573     if (console_initialized == false)
0574      return;
0575   #endif
0576 
0577 #define PRINTK_WRITE mpc5200_uart_pollWrite
0578 
0579     PRINTK_WRITE(PRINTK_MINOR, &c, 1 );
0580 }
0581 
0582 static int A_BSP_get_char(void)
0583 {
0584   /*
0585    *  If we are using U-Boot, then the console is already initialized
0586    *  and we can just poll bytes in at any time.
0587    */
0588   #if !defined(HAS_UBOOT)
0589     if (console_initialized == false)
0590      return -1;
0591   #endif
0592 
0593   return mpc5200_uart_pollRead(0);
0594 }
0595 
0596 /*
0597  ***************
0598  * BOILERPLATE *
0599  ***************
0600  *
0601  *  All these functions are prototyped in rtems/c/src/lib/include/console.h.
0602  */
0603 
0604 /*
0605  * Initialize and register the device
0606  */
0607 rtems_device_driver console_initialize(
0608   rtems_device_major_number major,
0609   rtems_device_minor_number minor,
0610   void *arg
0611 )
0612 {
0613   rtems_status_code status;
0614   rtems_device_minor_number console_minor;
0615   char dev_name[] = "/dev/ttyx";
0616   uint32_t tty_num = 0;
0617   bool first = true;
0618 
0619   /*
0620    * Always use and set up TERMIOS
0621    */
0622   console_minor = PSC1_MINOR;
0623   rtems_termios_initialize();
0624 
0625   for (console_minor = PSC1_MINOR;
0626        console_minor < PSC1_MINOR + NUM_PORTS;
0627        console_minor++) {
0628      /*
0629       * check, whether UART is available for this board
0630       */
0631     if (0 != ((1 << console_minor) & (mpc5200_uart_avail_mask))) {
0632       /*
0633        * Do device-specific initialization and registration for Motorola IceCube
0634        */
0635       mpc5200_uart_psc_initialize(console_minor); /* /dev/tty0 */
0636       dev_name[8] = '0' + tty_num;
0637       status = rtems_io_register_name (dev_name, major, console_minor);
0638       assert(status == RTEMS_SUCCESSFUL);
0639 
0640       #ifdef MPC5200_PSC_INDEX_FOR_GPS_MODULE
0641         if (console_minor == MPC5200_PSC_INDEX_FOR_GPS_MODULE) {
0642           status = rtems_io_register_name("/dev/gps", major, console_minor);
0643           assert(status == RTEMS_SUCCESSFUL);
0644         }
0645       #endif
0646 
0647       if (first) {
0648         first = false;
0649 
0650         /* Now register the RTEMS console */
0651         status = rtems_io_register_name ("/dev/console", major, console_minor);
0652         assert(status == RTEMS_SUCCESSFUL);
0653       }
0654 
0655       tty_num++;
0656     }
0657   }
0658 
0659   console_initialized = true;
0660   return RTEMS_SUCCESSFUL;
0661 }
0662 
0663 /*
0664  * Open the device
0665  */
0666 rtems_device_driver console_open(
0667   rtems_device_major_number  major,
0668   rtems_device_minor_number  minor,
0669   void                      *arg
0670 )
0671 {
0672   rtems_libio_open_close_args_t *args = arg;
0673   rtems_status_code sc;
0674 
0675 #ifdef UARTS_USE_TERMIOS_INT
0676   static const rtems_termios_callbacks intrCallbacks = {
0677     NULL,                           /* firstOpen */
0678     NULL,                           /* lastClose */
0679     NULL,                           /* pollRead */
0680     mpc5200_uart_write,             /* write */
0681     mpc5200_uart_setAttributes,     /* setAttributes */
0682     NULL,
0683     NULL,
0684     TERMIOS_IRQ_DRIVEN              /* outputUsesInterrupts */
0685   };
0686 #else
0687   static const rtems_termios_callbacks pollCallbacks = {
0688     NULL,                           /* firstOpen */
0689     NULL,                           /* lastClose */
0690     mpc5200_uart_pollRead,          /* pollRead */
0691     mpc5200_uart_pollWrite,         /* write */
0692     mpc5200_uart_setAttributes,     /* setAttributes */
0693     NULL,
0694     NULL,
0695     TERMIOS_POLLED                  /* output don't use Interrupts */
0696   };
0697 #endif
0698 
0699   if(minor > NUM_PORTS - 1)
0700     return RTEMS_INVALID_NUMBER;
0701 
0702 #ifdef UARTS_USE_TERMIOS_INT
0703   sc = rtems_termios_open( major, minor, arg, &intrCallbacks );
0704 #else                               /* RTEMS polled I/O with termios */
0705   sc = rtems_termios_open( major, minor, arg, &pollCallbacks );
0706 #endif
0707 
0708   ttyp[minor] = args->iop->data1;   /* Keep cookie returned by termios_open */
0709 
0710   if ( !sc )
0711     rtems_termios_set_initial_baud( ttyp[minor], GEN5200_CONSOLE_BAUD );
0712 
0713   return sc;
0714 }
0715 
0716 
0717 /*
0718  * Close the device
0719  */
0720 rtems_device_driver console_close(
0721   rtems_device_major_number  major,
0722   rtems_device_minor_number  minor,
0723   void                      *arg
0724 )
0725 {
0726   if ( minor > NUM_PORTS-1 )
0727     return RTEMS_INVALID_NUMBER;
0728 
0729   ttyp[minor] = NULL; /* mark for int handler: tty no longer open */
0730 
0731   return rtems_termios_close( arg );
0732 }
0733 
0734 
0735 /*
0736  * Read from the device
0737  */
0738 rtems_device_driver console_read(
0739   rtems_device_major_number  major,
0740   rtems_device_minor_number  minor,
0741   void                      *arg
0742 )
0743 {
0744   if(minor > NUM_PORTS-1)
0745     return RTEMS_INVALID_NUMBER;
0746 
0747   return rtems_termios_read(arg);
0748 }
0749 
0750 /*
0751  * Write to the device
0752  */
0753 rtems_device_driver console_write(
0754   rtems_device_major_number  major,
0755   rtems_device_minor_number  minor,
0756   void                      *arg
0757 )
0758 {
0759   if ( minor > NUM_PORTS-1 )
0760     return RTEMS_INVALID_NUMBER;
0761   return rtems_termios_write(arg);
0762 }
0763 
0764 /*
0765  * Handle ioctl request.
0766  */
0767 rtems_device_driver console_control(
0768   rtems_device_major_number  major,
0769   rtems_device_minor_number  minor,
0770   void                      *arg
0771 )
0772 {
0773   if ( minor > NUM_PORTS-1 )
0774     return RTEMS_INVALID_NUMBER;
0775 
0776   return rtems_termios_ioctl(arg);
0777 }