Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * RTEMS generic mcf548x BSP
0005  *
0006  * The file contains the console driver code of generic MCF548x BSP.
0007  *
0008  * Parts of the code has been derived from the "dBUG source code"
0009  * package Freescale is providing for M548X EVBs. The usage of
0010  * the modified or unmodified code and it's integration into the
0011  * generic mcf548x BSP has been done according to the Freescale
0012  * license terms.
0013  *
0014  * The Freescale license terms can be reviewed in the file
0015  *
0016  *    LICENSE.Freescale
0017  *
0018  * The generic mcf548x BSP has been developed on the basic
0019  * structures and modules of the av5282 BSP.
0020  */
0021 
0022 /*
0023  * Copyright (c) 2007 embedded brains GmbH & Co. KG
0024  *
0025  * Redistribution and use in source and binary forms, with or without
0026  * modification, are permitted provided that the following conditions
0027  * are met:
0028  * 1. Redistributions of source code must retain the above copyright
0029  *    notice, this list of conditions and the following disclaimer.
0030  * 2. Redistributions in binary form must reproduce the above copyright
0031  *    notice, this list of conditions and the following disclaimer in the
0032  *    documentation and/or other materials provided with the distribution.
0033  *
0034  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0035  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0036  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0037  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0038  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0039  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0040  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0041  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0042  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0043  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0044  * POSSIBILITY OF SUCH DAMAGE.
0045  */
0046 
0047  /*
0048   *  Multi UART console serial I/O.
0049   *
0050   * TO DO: Add DMA input/output
0051   */
0052 
0053 #include <stdio.h>
0054 #include <fcntl.h>
0055 #include <termios.h>
0056 #include <malloc.h>
0057 
0058 #include <bsp.h>
0059 #include <bsp/irq-generic.h>
0060 #include <rtems/libio.h>
0061 #include <rtems/termiostypes.h>
0062 #include <rtems/console.h>
0063 #include <rtems/bspIo.h>
0064 
0065 #define UART_INTC0_IRQ_VECTOR(x) (64+35-(x))
0066 
0067 #define MCF548X_PSC_SR_ERROR ( MCF548X_PSC_SR_RB_NEOF   | \
0068                            MCF548X_PSC_SR_FE_PHYERR | \
0069                            MCF548X_PSC_SR_PE_CRCERR | \
0070                            MCF548X_PSC_SR_OE )
0071 
0072 static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
0073 static int IntUartPollRead (int minor);
0074 static int IntUartSetAttributes(int minor, const struct termios *t);
0075 
0076 static void
0077 psc_output_char( char c )
0078 {
0079     rtems_interrupt_level level;
0080 
0081     rtems_interrupt_disable(level);
0082     while (!((MCF548X_PSC_SR(CONSOLE_PORT) & MCF548X_PSC_SR_TXRDY)))
0083         continue;
0084     *((uint8_t *) &MCF548X_PSC_TB(CONSOLE_PORT)) = c;
0085     while (!((MCF548X_PSC_SR(CONSOLE_PORT) & MCF548X_PSC_SR_TXRDY)))
0086         continue;
0087     rtems_interrupt_enable(level);
0088 }
0089 
0090 static void
0091 psc_output_char_init(char c)
0092 {
0093     IntUartSetAttributes(CONSOLE_PORT, NULL);
0094     BSP_output_char = psc_output_char;
0095     psc_output_char(c);
0096 }
0097 
0098 BSP_output_char_function_type     BSP_output_char = psc_output_char_init;
0099 
0100 BSP_polling_getchar_function_type BSP_poll_char = NULL;
0101 
0102 #define MAX_UART_INFO     4
0103 #define RX_BUFFER_SIZE    248
0104 
0105 struct IntUartInfoStruct
0106 {
0107     int                    iomode;
0108     volatile int           imr;
0109     int                    baud;
0110     int                    databits;
0111     int                    parity;
0112     int                    stopbits;
0113     int                    hwflow;
0114     int                    rx_in;
0115     int                    rx_out;
0116     char                   rx_buffer[RX_BUFFER_SIZE];
0117     void                  *ttyp;
0118 };
0119 
0120 struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
0121 
0122 static int GetBaud( int baudHandle )
0123 {
0124     int baud = BSP_CONSOLE_BAUD;
0125     switch(baudHandle)
0126     {
0127         case B0:
0128             baud = (int)0;
0129             break;
0130         case B1200:
0131             baud = (int)1200;
0132             break;
0133         case B2400:
0134             baud = (int)2400;
0135             break;
0136         case B4800:
0137             baud = (int)4800;
0138             break;
0139         case B9600:
0140             baud = (int)9600;
0141             break;
0142         case B19200:
0143             baud = (int)19200;
0144             break;
0145         case B38400:
0146             baud = (int)38400;
0147             break;
0148         case B57600:
0149             baud = (int)57600;
0150             break;
0151         case B115200:
0152             baud = (int)115200;
0153             break;
0154     }
0155     return baud;
0156 }
0157 
0158 /***************************************************************************
0159    Function : IntUartSet
0160 
0161    Description : This updates the hardware UART settings.
0162  ***************************************************************************/
0163 static void
0164 IntUartSet(int minor, int baud, int databits, int parity, int stopbits, int hwflow)
0165 {
0166     uint8_t                    psc_mode_1 = 0, psc_mode_2 = 0;
0167     uint16_t                   divider;
0168     int                        level;
0169     struct IntUartInfoStruct   *info = &IntUartInfo[minor];
0170 
0171     rtems_interrupt_disable(level);
0172 
0173     /* disable interrupts, clear RTS line, and disable the UARTS */
0174     /* Mask all psc interrupts */
0175     MCF548X_PSC_IMR(minor) = 0x0000;
0176 
0177     /* Clear RTS to send */
0178     MCF548X_PSC_OPSET(minor) &= ~(MCF548X_PSC_OPSET_RTS);
0179 
0180     /* Disable receiver and transmitter */
0181     MCF548X_PSC_CR(minor) &= ~(MCF548X_PSC_CR_RX_ENABLED | MCF548X_PSC_CR_TX_ENABLED);
0182 
0183     /* provide gpio settings */
0184     switch (minor)
0185       {
0186       case 0:
0187         MCF548X_GPIO_PAR_PSC0    = (0 | MCF548X_GPIO_PAR_PSC0_PAR_TXD0 | MCF548X_GPIO_PAR_PSC0_PAR_RXD0);
0188 
0189         if(hwflow)
0190           {
0191           MCF548X_GPIO_PAR_PSC0 |= (0 | MCF548X_GPIO_PAR_PSC0_PAR_CTS0_CTS | MCF548X_GPIO_PAR_PSC0_PAR_RTS0_RTS);
0192           }
0193         break;
0194       case 1:
0195         MCF548X_GPIO_PAR_PSC1    = (0 | MCF548X_GPIO_PAR_PSC1_PAR_TXD1 | MCF548X_GPIO_PAR_PSC1_PAR_RXD1);
0196 
0197         if(hwflow)
0198           {
0199           MCF548X_GPIO_PAR_PSC1 |= (0 | MCF548X_GPIO_PAR_PSC1_PAR_CTS1_CTS | MCF548X_GPIO_PAR_PSC1_PAR_RTS1_RTS);
0200           }
0201         break;
0202       case 2:
0203         MCF548X_GPIO_PAR_PSC2    = (0 | MCF548X_GPIO_PAR_PSC2_PAR_TXD2 | MCF548X_GPIO_PAR_PSC2_PAR_RXD2);
0204 
0205         if(hwflow)
0206           {
0207           MCF548X_GPIO_PAR_PSC2 |= (0 | MCF548X_GPIO_PAR_PSC2_PAR_CTS2_CTS | MCF548X_GPIO_PAR_PSC2_PAR_RTS2_RTS);
0208           }
0209         break;
0210       case 3:
0211         MCF548X_GPIO_PAR_PSC3    = (0 | MCF548X_GPIO_PAR_PSC3_PAR_TXD3 | MCF548X_GPIO_PAR_PSC3_PAR_RXD3);
0212 
0213         if(hwflow)
0214           {
0215           MCF548X_GPIO_PAR_PSC3 |= (0 | MCF548X_GPIO_PAR_PSC3_PAR_CTS3_CTS | MCF548X_GPIO_PAR_PSC3_PAR_RTS3_RTS);
0216           }
0217         break;
0218       default:
0219         break;
0220     }
0221 
0222     /* save the current values */
0223     info->imr      = 0;
0224     info->baud     = baud;
0225     info->databits = databits;
0226     info->parity   = parity;
0227     info->stopbits = stopbits;
0228     info->hwflow   = hwflow;
0229 
0230     /* Put PSC in UART mode */
0231     MCF548X_PSC_SICR(minor) = MCF548X_PSC_SICR_SIM_UART;
0232 
0233     /* set the baud rate values */
0234     MCF548X_PSC_CSR(minor) = (0 | MCF548X_PSC_CSR_RCSEL_SYS_CLK | MCF548X_PSC_CSR_TCSEL_SYS_CLK);
0235 
0236     /* Calculate baud settings */
0237     divider = (uint16_t)((get_CPU_clock_speed())/(baud * 32));
0238     MCF548X_PSC_CTUR(minor) =  (uint8_t) ((divider >> 8) & 0xFF);
0239     MCF548X_PSC_CTLR(minor) =  (uint8_t) (divider & 0xFF);
0240 
0241     /* Reset transmitter, receiver, mode register, and error conditions */
0242     MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_RX;
0243     MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_TX;
0244     MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_ERROR;
0245     MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_BKCHGINT;
0246     MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_MR;
0247 
0248     /* check to see if doing hardware flow control */
0249     if ( hwflow )
0250     {
0251         /* set hardware flow options */
0252         psc_mode_1 = MCF548X_PSC_MR_RXRTS;
0253         psc_mode_2 = MCF548X_PSC_MR_TXCTS;
0254     }
0255 
0256     /* set mode registers */
0257     psc_mode_1 |= (uint8_t)(parity | databits);
0258     psc_mode_2 |= (uint8_t)(stopbits);
0259 
0260     /* set mode registers */
0261     MCF548X_PSC_MR(minor) = psc_mode_1;
0262     MCF548X_PSC_MR(minor) = psc_mode_2;
0263 
0264     /* Setup FIFO Alarms */
0265     MCF548X_PSC_RFAR(minor) = MCF548X_PSC_RFAR_ALARM(248);
0266     MCF548X_PSC_TFAR(minor) = MCF548X_PSC_TFAR_ALARM(248);
0267 
0268     /* check to see if interrupts need to be enabled */
0269     if ( info->iomode != TERMIOS_POLLED )
0270     {
0271         /* enable rx interrupts */
0272         info->imr |= MCF548X_PSC_IMR_RXRDY_FU;
0273         MCF548X_PSC_IMR(minor) = info->imr;
0274     }
0275 
0276     /* check to see if doing hardware flow control */
0277     if ( hwflow )
0278     {
0279         /* assert the RTS line */
0280         MCF548X_PSC_OPSET(minor) = MCF548X_PSC_OPSET_RTS;
0281     }
0282 
0283     rtems_interrupt_enable(level);
0284 
0285     /* Enable receiver and transmitter */
0286     MCF548X_PSC_CR(minor) =(0 | MCF548X_PSC_CR_RX_ENABLED | MCF548X_PSC_CR_TX_ENABLED);
0287 
0288 
0289 }
0290 
0291 /***************************************************************************
0292    Function : IntUartSetAttributes
0293 
0294    Description : This provides the hardware-dependent portion of tcsetattr().
0295    value and sets it. At the moment this just sets the baud rate.
0296 
0297    Note: The highest baudrate is 115200 as this stays within
0298    an error of +/- 5% at 25MHz processor clock
0299  ***************************************************************************/
0300 static int
0301 IntUartSetAttributes(int minor, const struct termios *t)
0302 {
0303 /* set default index values */
0304 #ifdef HAS_DBUG
0305     int                         baud     = DBUG_SETTINGS.console_baudrate;
0306 #else
0307     int                         baud     = (int)BSP_CONSOLE_BAUD;
0308 #endif
0309     int                         databits = (int)MCF548X_PSC_MR_BC_8;
0310     int                         parity   = (int)MCF548X_PSC_MR_PM_NONE;
0311     int                         stopbits = (int)MCF548X_PSC_MR_SB_STOP_BITS_1;
0312     int                         hwflow   = (int)1;
0313     struct IntUartInfoStruct   *info     = &IntUartInfo[minor];
0314 
0315     /* check to see if input is valid */
0316     if ( t != (const struct termios *)0 )
0317     {
0318         /* determine baud rate index */
0319     baud = GetBaud( t->c_ospeed );
0320 
0321         /* determine data bits */
0322         switch ( t->c_cflag & CSIZE )
0323         {
0324             case CS5:
0325                 databits = (int)MCF548X_PSC_MR_BC_5;
0326                 break;
0327             case CS6:
0328                 databits = (int)MCF548X_PSC_MR_BC_6;
0329                 break;
0330             case CS7:
0331                 databits = (int)MCF548X_PSC_MR_BC_7;
0332                 break;
0333             case CS8:
0334                 databits = (int)MCF548X_PSC_MR_BC_8;
0335                 break;
0336         }
0337 
0338         /* determine if parity is enabled */
0339         if ( t->c_cflag & PARENB )
0340         {
0341             if ( t->c_cflag & PARODD )
0342             {
0343                 /* odd parity */
0344                 parity = (int)MCF548X_PSC_MR_PM_ODD;
0345             }
0346             else
0347             {
0348                 /* even parity */
0349                 parity = (int)MCF548X_PSC_MR_PM_EVEN;
0350             }
0351         }
0352 
0353         /* determine stop bits */
0354         if ( t->c_cflag & CSTOPB )
0355         {
0356             /* two stop bits */
0357             stopbits = (int)MCF548X_PSC_MR_SB_STOP_BITS_2;
0358         }
0359 
0360         /* check to see if hardware flow control */
0361         if ( t->c_cflag & CRTSCTS )
0362         {
0363             hwflow = 1;
0364         }
0365     }
0366 
0367     /* check to see if values have changed */
0368     if ( ( baud     != info->baud     ) ||
0369          ( databits != info->databits ) ||
0370          ( parity   != info->parity   ) ||
0371          ( stopbits != info->stopbits ) ||
0372          ( hwflow   != info->hwflow   ) )
0373     {
0374 
0375         /* call function to set values */
0376         IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
0377     }
0378 
0379 return RTEMS_SUCCESSFUL;
0380 
0381 }
0382 
0383 /***************************************************************************
0384    Function : IntUartInterruptHandler
0385 
0386    Description : This is the interrupt handler for the internal uart. It
0387    determines which channel caused the interrupt before queueing any received
0388    chars and dequeueing chars waiting for transmission.
0389  ***************************************************************************/
0390 static rtems_isr
0391 IntUartInterruptHandler(rtems_vector_number v)
0392 {
0393     unsigned int                chan = v - UART_INTC0_IRQ_VECTOR(0);
0394     struct IntUartInfoStruct   *info = &IntUartInfo[chan];
0395 
0396     /* check to see if received data */
0397     if ( MCF548X_PSC_ISR(chan) & MCF548X_PSC_ISR_RXRDY_FU )
0398     {
0399         /* read data and put into the receive buffer */
0400         while ( MCF548X_PSC_SR(chan) & MCF548X_PSC_SR_RXRDY )
0401         {
0402 
0403            /* put data in rx buffer */
0404             info->rx_buffer[info->rx_in] = *((volatile uint8_t *)&MCF548X_PSC_RB(chan));
0405 
0406            /* check for errors */
0407            if ( MCF548X_PSC_SR(chan) & MCF548X_PSC_SR_ERROR )
0408             {
0409                 /* clear the error */
0410                 MCF548X_PSC_CR(chan) = MCF548X_PSC_CR_RESET_ERROR;
0411             }
0412 
0413             /* update buffer values */
0414             info->rx_in++;
0415 
0416             if ( info->rx_in >= RX_BUFFER_SIZE )
0417             {
0418                 info->rx_in = 0;
0419             }
0420         }
0421         /* Make sure the port has been opened */
0422         if ( info->ttyp )
0423         {
0424 
0425             /* check to see if task driven */
0426             if ( info->iomode == TERMIOS_TASK_DRIVEN )
0427             {
0428                 /* notify rx task that rx buffer has data */
0429                 rtems_termios_rxirq_occured(info->ttyp);
0430             }
0431             else
0432             {
0433                 /* Push up the received data */
0434                 rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer, info->rx_in);
0435                 info->rx_in    = 0;
0436             }
0437         }
0438     }
0439 
0440     /* check to see if data needs to be transmitted */
0441     if ( ( info->imr & MCF548X_PSC_IMR_TXRDY ) &&
0442          ( MCF548X_PSC_ISR(chan) & MCF548X_PSC_ISR_TXRDY ) )
0443     {
0444 
0445         /* disable tx interrupts */
0446         info->imr &= ~MCF548X_PSC_IMR_TXRDY;
0447         MCF548X_PSC_IMR(chan) = info->imr;
0448 
0449         /* tell upper level that character has been sent */
0450         if ( info->ttyp )
0451             rtems_termios_dequeue_characters(info->ttyp, 1);
0452     }
0453 
0454 }
0455 
0456 /***************************************************************************
0457    Function : IntUartInitialize
0458 
0459    Description : This initialises the internal uart hardware for all
0460    internal uarts. If the internal uart is to be interrupt driven then the
0461    interrupt vectors are hooked.
0462  ***************************************************************************/
0463 static void
0464 IntUartInitialize(void)
0465 {
0466     unsigned int        chan;
0467     struct IntUartInfoStruct   *info;
0468     rtems_isr_entry old_handler;
0469 
0470     for ( chan = 0; chan < MAX_UART_INFO; chan++ )
0471     {
0472         info = &IntUartInfo[chan];
0473 
0474         info->ttyp     = NULL;
0475         info->rx_in    = 0;
0476         info->rx_out   = 0;
0477         info->baud     = -1;
0478         info->databits = -1;
0479         info->parity   = -1;
0480         info->stopbits = -1;
0481         info->hwflow   = -1;
0482 
0483         MCF548X_PSC_ACR(chan) = 0;
0484         MCF548X_PSC_IMR(chan) = 0;
0485         if ( info->iomode != TERMIOS_POLLED )
0486         {
0487             rtems_interrupt_catch (IntUartInterruptHandler,
0488                                    UART_INTC0_IRQ_VECTOR(chan),
0489                                    &old_handler);
0490         }
0491 
0492         /* set uart default values */
0493         IntUartSetAttributes(chan, NULL);
0494 
0495         /* unmask interrupt */
0496         bsp_interrupt_vector_enable(MCF548X_IRQ_PSC(chan));
0497     } /* of chan loop */
0498 
0499     BSP_output_char = psc_output_char;
0500 } /* IntUartInitialise */
0501 
0502 /***************************************************************************
0503    Function : IntUartInterruptWrite
0504 
0505    Description : This writes a single character to the appropriate uart
0506    channel. This is either called during an interrupt or in the user's task
0507    to initiate a transmit sequence. Calling this routine enables Tx
0508    interrupts.
0509  ***************************************************************************/
0510 static ssize_t
0511 IntUartInterruptWrite (int minor, const char *buf, size_t len)
0512 {
0513     if (len > 0) {
0514         /* write out character */
0515         *(volatile uint8_t *)(&MCF548X_PSC_TB(minor)) = *buf;
0516 
0517         /* enable tx interrupt */
0518         IntUartInfo[minor].imr |= MCF548X_PSC_IMR_TXRDY;
0519         MCF548X_PSC_IMR(minor) = IntUartInfo[minor].imr;
0520     }
0521 
0522     return 0;
0523 }
0524 
0525 /***************************************************************************
0526    Function : IntUartInterruptOpen
0527 
0528    Description : This enables interrupts when the tty is opened.
0529  ***************************************************************************/
0530 static int
0531 IntUartInterruptOpen(int major, int minor, void *arg)
0532 {
0533     struct IntUartInfoStruct   *info = &IntUartInfo[minor];
0534 
0535     /* enable the uart */
0536     MCF548X_PSC_CR(minor) = (MCF548X_PSC_CR_TX_ENABLED | MCF548X_PSC_CR_RX_ENABLED);
0537 
0538     /* check to see if interrupts need to be enabled */
0539     if ( info->iomode != TERMIOS_POLLED )
0540     {
0541         /* enable rx interrupts */
0542         info->imr |= MCF548X_PSC_IMR_RXRDY_FU;
0543         MCF548X_PSC_IMR(minor) = info->imr;
0544     }
0545 
0546     /* check to see if doing hardware flow control */
0547     if ( info->hwflow )
0548     {
0549         /* assert the RTS line */
0550         MCF548X_PSC_OPSET(minor) = MCF548X_PSC_OPSET_RTS;
0551     }
0552 
0553     return 0;
0554 }
0555 
0556 
0557 /***************************************************************************
0558    Function : IntUartInterruptClose
0559 
0560    Description : This disables interrupts when the tty is closed.
0561  ***************************************************************************/
0562 static int
0563 IntUartInterruptClose(int major, int minor, void *arg)
0564 {
0565     struct IntUartInfoStruct   *info = &IntUartInfo[minor];
0566 
0567     /* disable the interrupts and the uart */
0568     MCF548X_PSC_IMR(minor) = 0;
0569     MCF548X_PSC_CR(minor) = (MCF548X_PSC_CR_TX_ENABLED | MCF548X_PSC_CR_RX_ENABLED);
0570 
0571     /* reset values */
0572     info->ttyp     = NULL;
0573     info->imr       = 0;
0574     info->rx_in    = 0;
0575     info->rx_out   = 0;
0576 
0577     return 0;
0578 }
0579 
0580 /***************************************************************************
0581    Function : IntUartTaskRead
0582 
0583    Description : This reads all available characters from the internal uart
0584    and places them into the termios buffer.  The rx interrupts will be
0585    re-enabled after all data has been read.
0586  ***************************************************************************/
0587 static int
0588 IntUartTaskRead(int minor)
0589 {
0590     char                        buffer[RX_BUFFER_SIZE];
0591     int                         count;
0592     int                         rx_in;
0593     int                         index = 0;
0594     struct IntUartInfoStruct   *info  = &IntUartInfo[minor];
0595 
0596     /* determine number of values to copy out */
0597     rx_in = info->rx_in;
0598     if ( info->rx_out <= rx_in )
0599     {
0600         count = rx_in - info->rx_out;
0601     }
0602     else
0603     {
0604         count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
0605     }
0606 
0607     /* copy data into local buffer from rx buffer */
0608     while ( ( index < count ) && ( index < RX_BUFFER_SIZE ) )
0609     {
0610         /* copy data byte */
0611         buffer[index] = info->rx_buffer[info->rx_out];
0612         index++;
0613 
0614         /* increment rx buffer values */
0615         info->rx_out++;
0616         if ( info->rx_out >= RX_BUFFER_SIZE )
0617         {
0618             info->rx_out = 0;
0619         }
0620     }
0621 
0622     /* check to see if buffer is not empty */
0623     if ( count > 0 )
0624     {
0625         /* set characters into termios buffer  */
0626         rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
0627     }
0628 
0629     return EOF;
0630 }
0631 
0632 
0633 /***************************************************************************
0634    Function : IntUartPollRead
0635 
0636    Description : This reads a character from the internal uart. It returns
0637    to the caller without blocking if not character is waiting.
0638  ***************************************************************************/
0639 static int
0640 IntUartPollRead (int minor)
0641 {
0642 if (!((MCF548X_PSC_SR(minor) & MCF548X_PSC_SR_RXRDY)))
0643         return(-1);
0644 
0645     return *((uint8_t *)&MCF548X_PSC_RB(minor));
0646 }
0647 
0648 
0649 /***************************************************************************
0650    Function : IntUartPollWrite
0651 
0652    Description : This writes out each character in the buffer to the
0653    appropriate internal uart channel waiting till each one is sucessfully
0654    transmitted.
0655  ***************************************************************************/
0656 static ssize_t
0657 IntUartPollWrite (int minor, const char *buf, size_t len)
0658 {
0659     size_t retval = len;
0660 /* loop over buffer */
0661     while ( len-- )
0662     {
0663         /* block until we can transmit */
0664         while (!((MCF548X_PSC_SR(minor) & MCF548X_PSC_SR_TXRDY)))
0665             continue;
0666         /* transmit data byte */
0667         *((uint8_t *)&MCF548X_PSC_TB(minor)) = *buf++;
0668     }
0669     return retval;
0670 }
0671 
0672 /***************************************************************************
0673    Function : console_initialize
0674 
0675    Description : This initialises termios, both sets of uart hardware before
0676    registering /dev/tty devices for each channel and the system /dev/console.
0677  ***************************************************************************/
0678 rtems_device_driver console_initialize(
0679     rtems_device_major_number  major,
0680     rtems_device_minor_number  minor,
0681     void  *arg )
0682 {
0683     rtems_status_code status;
0684 
0685 
0686     /* Set up TERMIOS */
0687     rtems_termios_initialize ();
0688 
0689     /* set io modes for the different channels and initialize device */
0690     IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN; //TERMIOS_POLLED;
0691     IntUartInitialize();
0692 
0693     /* Register the console port */
0694     status = rtems_io_register_name ("/dev/console", major, CONSOLE_PORT);
0695     if ( status != RTEMS_SUCCESSFUL )
0696     {
0697         rtems_fatal_error_occurred (status);
0698     }
0699 
0700     /* Register the other port */
0701     if ( CONSOLE_PORT != 0 )
0702     {
0703         status = rtems_io_register_name ("/dev/tty00", major, 0);
0704         if ( status != RTEMS_SUCCESSFUL )
0705         {
0706             rtems_fatal_error_occurred (status);
0707         }
0708     }
0709     if ( CONSOLE_PORT != 1 )
0710     {
0711         status = rtems_io_register_name ("/dev/tty01", major, 1);
0712         if ( status != RTEMS_SUCCESSFUL )
0713         {
0714             rtems_fatal_error_occurred (status);
0715         }
0716     }
0717 
0718     return(RTEMS_SUCCESSFUL);
0719 }
0720 
0721 /***************************************************************************
0722    Function : console_open
0723 
0724    Description : This actually opens the device depending on the minor
0725    number set during initialisation. The device specific access routines are
0726    passed to termios when the devices is opened depending on whether it is
0727    polled or not.
0728  ***************************************************************************/
0729 rtems_device_driver console_open(
0730     rtems_device_major_number major,
0731     rtems_device_minor_number minor,
0732     void  * arg)
0733 {
0734     rtems_status_code                status = RTEMS_INVALID_NUMBER;
0735     rtems_libio_open_close_args_t   *args   = (rtems_libio_open_close_args_t *)arg;
0736     struct IntUartInfoStruct        *info;
0737 
0738     static const rtems_termios_callbacks IntUartPollCallbacks = {
0739         NULL,                 /* firstOpen */
0740         NULL,                 /* lastClose */
0741         IntUartPollRead,      /* pollRead */
0742         IntUartPollWrite,     /* write */
0743         IntUartSetAttributes, /* setAttributes */
0744         NULL,                 /* stopRemoteTx */
0745         NULL,                 /* startRemoteTx */
0746         TERMIOS_POLLED        /* mode */
0747     };
0748     static const rtems_termios_callbacks IntUartIntrCallbacks = {
0749         IntUartInterruptOpen,  /* firstOpen */
0750         IntUartInterruptClose, /* lastClose */
0751         NULL,                  /* pollRead */
0752         IntUartInterruptWrite, /* write */
0753         IntUartSetAttributes,  /* setAttributes */
0754         NULL,                  /* stopRemoteTx */
0755         NULL,                  /* startRemoteTx */
0756         TERMIOS_IRQ_DRIVEN     /* mode */
0757     };
0758 
0759     static const rtems_termios_callbacks IntUartTaskCallbacks = {
0760         IntUartInterruptOpen,  /* firstOpen */
0761         IntUartInterruptClose, /* lastClose */
0762         IntUartTaskRead,       /* pollRead */
0763         IntUartInterruptWrite, /* write */
0764         IntUartSetAttributes,  /* setAttributes */
0765         NULL,                  /* stopRemoteTx */
0766         NULL,                  /* startRemoteTx */
0767         TERMIOS_TASK_DRIVEN    /* mode */
0768     };
0769 
0770     /* open the port depending on the minor device number */
0771     if ( ( minor >= 0 ) && ( minor < MAX_UART_INFO ) )
0772     {
0773         info = &IntUartInfo[minor];
0774         switch ( info->iomode )
0775         {
0776             case TERMIOS_POLLED:
0777                 status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
0778                 break;
0779             case TERMIOS_IRQ_DRIVEN:
0780                 status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
0781                 info->ttyp = args->iop->data1;
0782                 break;
0783             case TERMIOS_TASK_DRIVEN:
0784                 status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
0785                 info->ttyp = args->iop->data1;
0786                 break;
0787         }
0788     }
0789 
0790     return( status );
0791 }
0792 
0793 /***************************************************************************
0794    Function : console_close
0795 
0796    Description : This closes the device via termios
0797  ***************************************************************************/
0798 rtems_device_driver console_close(
0799     rtems_device_major_number major,
0800     rtems_device_minor_number minor,
0801     void   * arg)
0802 {
0803     return(rtems_termios_close (arg));
0804 }
0805 
0806 /***************************************************************************
0807    Function : console_read
0808 
0809    Description : Read from the device via termios
0810  ***************************************************************************/
0811 rtems_device_driver console_read(
0812     rtems_device_major_number major,
0813     rtems_device_minor_number minor,
0814     void  * arg)
0815 {
0816     return(rtems_termios_read (arg));
0817 }
0818 
0819 /***************************************************************************
0820    Function : console_write
0821 
0822    Description : Write to the device via termios
0823  ***************************************************************************/
0824 rtems_device_driver console_write(
0825     rtems_device_major_number major,
0826     rtems_device_minor_number minor,
0827     void  * arg)
0828 {
0829     return(rtems_termios_write (arg));
0830 }
0831 
0832 /***************************************************************************
0833    Function : console_ioctl
0834 
0835    Description : Pass the IOCtl call to termios
0836  ***************************************************************************/
0837 rtems_device_driver console_control(
0838     rtems_device_major_number major,
0839     rtems_device_minor_number minor,
0840     void  * arg)
0841 {
0842     return( rtems_termios_ioctl (arg) );
0843 }