Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:05

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  This file contains the termios TTY driver for the Motorola MC68681.
0005  *
0006  *  This part is available from a number of secondary sources.
0007  *  In particular, we know about the following:
0008  *
0009  *     + Exar 88c681 and 68c681
0010  *
0011  *  COPYRIGHT (c) 1989-1999.
0012  *  On-Line Applications Research Corporation (OAR).
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <rtems.h>
0037 #include <rtems/libio.h>
0038 #include <rtems/score/sysstate.h>
0039 #include <stdlib.h>
0040 
0041 #include <libchip/serial.h>
0042 #include <libchip/mc68681.h>
0043 #include <libchip/sersupp.h>
0044 #include "mc68681_p.h"
0045 
0046 /*
0047  * Flow control is only supported when using interrupts
0048  */
0049 
0050 const console_fns mc68681_fns =
0051 {
0052   libchip_serial_default_probe,   /* deviceProbe */
0053   mc68681_open,                   /* deviceFirstOpen */
0054   NULL,                           /* deviceLastClose */
0055   NULL,                           /* deviceRead */
0056   mc68681_write_support_int,      /* deviceWrite */
0057   mc68681_initialize_interrupts,  /* deviceInitialize */
0058   mc68681_write_polled,           /* deviceWritePolled */
0059   mc68681_set_attributes,         /* deviceSetAttributes */
0060   true                            /* deviceOutputUsesInterrupts */
0061 };
0062 
0063 const console_fns mc68681_fns_polled =
0064 {
0065   libchip_serial_default_probe,        /* deviceProbe */
0066   mc68681_open,                        /* deviceFirstOpen */
0067   mc68681_close,                       /* deviceLastClose */
0068   mc68681_inbyte_nonblocking_polled,   /* deviceRead */
0069   mc68681_write_support_polled,        /* deviceWrite */
0070   mc68681_init,                        /* deviceInitialize */
0071   mc68681_write_polled,                /* deviceWritePolled */
0072   mc68681_set_attributes,              /* deviceSetAttributes */
0073   false,                               /* deviceOutputUsesInterrupts */
0074 };
0075 
0076 
0077 #if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
0078   extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
0079 #endif
0080 
0081 /*
0082  *  Console Device Driver Entry Points
0083  */
0084 
0085 /*
0086  *  mc68681_baud_rate
0087  *
0088  *  This routine returns the proper ACR bit and baud rate field values
0089  *  based on the requested baud rate.  The baud rate set to be used
0090  *  must be configured by the user.
0091  */
0092 
0093 MC68681_STATIC int mc68681_baud_rate(
0094   int           minor,
0095   int           baud,
0096   unsigned int *baud_mask_p,
0097   unsigned int *acr_bit_p,
0098   unsigned int *command
0099 );
0100 
0101 /*
0102  *  mc68681_set_attributes
0103  *
0104  *  This function sets the DUART channel to reflect the requested termios
0105  *  port settings.
0106  */
0107 
0108 MC68681_STATIC int mc68681_set_attributes(
0109   int minor,
0110   const struct termios *t
0111 )
0112 {
0113   uint32_t               pMC68681_port;
0114   uint32_t               pMC68681;
0115   unsigned int           mode1;
0116   unsigned int           mode2;
0117   unsigned int           baud_mask;
0118   unsigned int           acr_bit;
0119   unsigned int           cmd = 0;
0120   setRegister_f          setReg;
0121   rtems_interrupt_level  Irql;
0122 
0123   pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
0124   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0125   setReg        = Console_Port_Tbl[minor]->setRegister;
0126 
0127   /*
0128    *  Set the baud rate
0129    */
0130 
0131   if (mc68681_baud_rate( minor, t->c_cflag, &baud_mask, &acr_bit, &cmd ) == -1)
0132     return -1;
0133 
0134   baud_mask |=  baud_mask << 4;
0135   acr_bit   <<= 7;
0136 
0137   /*
0138    *  Parity
0139    */
0140 
0141   mode1 = 0;
0142   mode2 = 0;
0143 
0144   if (t->c_cflag & PARENB) {
0145     if (t->c_cflag & PARODD)
0146       mode1 |= 0x04;
0147     /* else
0148         mode1 |= 0x04; */
0149   } else {
0150    mode1 |= 0x10;
0151   }
0152 
0153   /*
0154    *  Character Size
0155    */
0156 
0157   if (t->c_cflag & CSIZE) {
0158     switch (t->c_cflag & CSIZE) {
0159       case CS5:  break;
0160       case CS6:  mode1 |= 0x01;  break;
0161       case CS7:  mode1 |= 0x02;  break;
0162       case CS8:  mode1 |= 0x03;  break;
0163     }
0164   } else {
0165     mode1 |= 0x03;       /* default to 9600,8,N,1 */
0166   }
0167 
0168   /*
0169    *  Stop Bits
0170    */
0171 
0172   if (t->c_cflag & CSTOPB) {
0173     mode2 |= 0x0F;                      /* 2 stop bits */
0174   } else {
0175     if ((t->c_cflag & CSIZE) == CS5)    /* CS5 and 1 stop bits not supported */
0176       return -1;
0177     mode2 |= 0x07;                      /* 1 stop bit */
0178   }
0179 
0180  /*
0181   *   Hardware Flow Control
0182   */
0183 
0184   if(t->c_cflag & CRTSCTS) {
0185       mode1 |= 0x80; /* Enable Rx RTS Control */
0186       mode2 |= 0x10; /* Enable CTS Enable Tx */
0187   }
0188 
0189 
0190   rtems_interrupt_disable(Irql);
0191     (*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr_bit );
0192     (*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud_mask );
0193     if ( cmd ) {
0194       (*setReg)( pMC68681_port, MC68681_COMMAND, cmd );         /* RX */
0195       (*setReg)( pMC68681_port, MC68681_COMMAND, cmd | 0x20 );  /* TX */
0196     }
0197     (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
0198     (*setReg)( pMC68681_port, MC68681_MODE, mode1 );
0199     (*setReg)( pMC68681_port, MC68681_MODE, mode2 );
0200   rtems_interrupt_enable(Irql);
0201   return 0;
0202 }
0203 
0204 /*
0205  *  mc68681_initialize_context
0206  *
0207  *  This function sets the default values of the per port context structure.
0208  */
0209 
0210 MC68681_STATIC void mc68681_initialize_context(
0211   int               minor,
0212   mc68681_context  *pmc68681Context
0213 )
0214 {
0215   int          port;
0216   unsigned int pMC68681;
0217   unsigned int pMC68681_port;
0218 
0219   pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
0220   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0221 
0222   pmc68681Context->mate = -1;
0223 
0224   for (port=0 ; port<Console_Port_Count ; port++ ) {
0225     if ( Console_Port_Tbl[port]->ulCtrlPort1 == pMC68681 &&
0226          Console_Port_Tbl[port]->ulCtrlPort2 != pMC68681_port ) {
0227       pmc68681Context->mate = port;
0228       pmc68681Context->imr  = 0;
0229       break;
0230     }
0231   }
0232 
0233 }
0234 
0235 /*
0236  *  mc68681_init
0237  *
0238  *  This function initializes the DUART to a quiecsent state.
0239  */
0240 
0241 MC68681_STATIC void mc68681_init(int minor)
0242 {
0243   uint32_t                pMC68681_port;
0244   mc68681_context        *pmc68681Context;
0245   setRegister_f           setReg;
0246 
0247   pmc68681Context = (mc68681_context *) malloc(sizeof(mc68681_context));
0248 
0249   Console_Port_Data[minor].pDeviceContext = (void *)pmc68681Context;
0250 
0251   mc68681_initialize_context( minor, pmc68681Context );
0252 
0253   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0254   setReg        = Console_Port_Tbl[minor]->setRegister;
0255 
0256   /*
0257    *  Reset everything and leave this port disabled.
0258    */
0259 
0260   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_RX );
0261   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_TX );
0262   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
0263   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_BREAK );
0264   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_STOP_BREAK );
0265   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
0266   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
0267 
0268 
0269   (*setReg)( pMC68681_port, MC68681_MODE_REG_1A, 0x00 );
0270   (*setReg)( pMC68681_port, MC68681_MODE_REG_2A, 0x02 );
0271 
0272   /*
0273    *  Disable interrupts on RX and TX for this port
0274    */
0275 
0276   mc68681_enable_interrupts( minor, MC68681_IMR_DISABLE_ALL );
0277 }
0278 
0279 /*
0280  *  mc68681_open
0281  *
0282  *  This function opens a port for communication.
0283  *
0284  *  Default state is 9600 baud, 8 bits, No parity, and 1 stop bit.
0285  */
0286 
0287 MC68681_STATIC int mc68681_open(
0288   int      major,
0289   int      minor,
0290   void    *arg
0291 )
0292 {
0293   uint32_t               pMC68681;
0294   uint32_t               pMC68681_port;
0295   unsigned int           baud;
0296   unsigned int           acr_bit;
0297   unsigned int           vector;
0298   unsigned int           command = 0;
0299   rtems_interrupt_level  Irql;
0300   setRegister_f          setReg;
0301   int            status;
0302 
0303 
0304   pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
0305   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0306   setReg        = Console_Port_Tbl[minor]->setRegister;
0307   vector        = Console_Port_Tbl[minor]->ulIntVector;
0308 
0309   /* XXX default baud rate should be from configuration table */
0310 
0311   status = mc68681_baud_rate( minor, B9600, &baud, &acr_bit, &command );
0312   if (status < 0) rtems_fatal_error_occurred (RTEMS_NOT_DEFINED);
0313 
0314   /*
0315    *  Set the DUART channel to a default useable state
0316    */
0317 
0318   rtems_interrupt_disable(Irql);
0319     (*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr_bit << 7 );
0320     (*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud );
0321     if ( command ) {
0322       (*setReg)( pMC68681_port, MC68681_COMMAND, command );         /* RX */
0323       (*setReg)( pMC68681_port, MC68681_COMMAND, command | 0x20 );  /* TX */
0324     }
0325     (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
0326     (*setReg)( pMC68681_port, MC68681_MODE, 0x13 );
0327     (*setReg)( pMC68681_port, MC68681_MODE, 0x07 );
0328   rtems_interrupt_enable(Irql);
0329 
0330   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_TX );
0331   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_RX );
0332 
0333   (*setReg)( pMC68681, MC68681_INTERRUPT_VECTOR_REG, vector );
0334 
0335   return RTEMS_SUCCESSFUL;
0336 }
0337 
0338 /*
0339  *  mc68681_close
0340  *
0341  *  This function shuts down the requested port.
0342  */
0343 
0344 MC68681_STATIC int mc68681_close(
0345   int      major,
0346   int      minor,
0347   void    *arg
0348 )
0349 {
0350   uint32_t        pMC68681_port;
0351   setRegister_f   setReg;
0352 
0353   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0354   setReg        = Console_Port_Tbl[minor]->setRegister;
0355 
0356   /*
0357    *  Disable interrupts from this channel and then disable it totally.
0358    */
0359   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
0360   (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
0361 
0362   return(RTEMS_SUCCESSFUL);
0363 }
0364 
0365 /*
0366  *  mc68681_write_polled
0367  *
0368  *  This routine polls out the requested character.
0369  */
0370 
0371 MC68681_STATIC void mc68681_write_polled(
0372   int   minor,
0373   char  cChar
0374 )
0375 {
0376   uint32_t                pMC68681_port;
0377   unsigned char           ucLineStatus;
0378   int                     iTimeout;
0379   getRegister_f           getReg;
0380   setRegister_f           setReg;
0381 
0382   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0383   getReg        = Console_Port_Tbl[minor]->getRegister;
0384   setReg        = Console_Port_Tbl[minor]->setRegister;
0385 
0386   /*
0387    * wait for transmitter holding register to be empty
0388    */
0389   iTimeout = 1000;
0390   ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
0391   while ((ucLineStatus & (MC68681_TX_READY|MC68681_TX_EMPTY)) == 0) {
0392 
0393     if ((ucLineStatus & 0xF0))
0394       (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
0395 
0396     /*
0397      * Yield while we wait
0398      */
0399 
0400 #if 0
0401      if(_System_state_Is_up(_System_state_Get())) {
0402        rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
0403      }
0404 #endif
0405      ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
0406      if(!--iTimeout) {
0407        break;
0408      }
0409   }
0410 
0411   /*
0412    * transmit character
0413    */
0414 
0415   (*setReg)(pMC68681_port, MC68681_TX_BUFFER, cChar);
0416 }
0417 
0418 /*
0419  *  mc68681_isr
0420  *
0421  *  This is the single interrupt entry point which parcels interrupts
0422  *  out to the various ports.
0423  */
0424 
0425 MC68681_STATIC rtems_isr mc68681_isr(
0426   rtems_vector_number vector
0427 )
0428 {
0429   int     minor;
0430 
0431   for(minor=0 ; minor<Console_Port_Count ; minor++) {
0432     if(Console_Port_Tbl[minor]->ulIntVector == vector &&
0433        Console_Port_Tbl[minor]->deviceType == SERIAL_MC68681 ) {
0434       mc68681_process(minor);
0435     }
0436   }
0437 }
0438 
0439 /*
0440  *  mc68681_initialize_interrupts
0441  *
0442  *  This routine initializes the console's receive and transmit
0443  *  ring buffers and loads the appropriate vectors to handle the interrupts.
0444  */
0445 
0446 MC68681_STATIC void mc68681_initialize_interrupts(int minor)
0447 {
0448   mc68681_init(minor);
0449 
0450   Console_Port_Data[minor].bActive = FALSE;
0451 
0452 #if (CPU_SIMPLE_VECTORED_INTERRUPTS == TRUE)
0453   set_vector(mc68681_isr, Console_Port_Tbl[minor]->ulIntVector, 1);
0454 #endif
0455 
0456   mc68681_enable_interrupts(minor,MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
0457 }
0458 
0459 /*
0460  *  mc68681_write_support_int
0461  *
0462  *  Console Termios output entry point when using interrupt driven output.
0463  */
0464 
0465 MC68681_STATIC ssize_t mc68681_write_support_int(
0466   int         minor,
0467   const char *buf,
0468   size_t      len
0469 )
0470 {
0471   uint32_t        Irql;
0472   uint32_t        pMC68681_port;
0473   setRegister_f   setReg;
0474 
0475   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0476   setReg        = Console_Port_Tbl[minor]->setRegister;
0477 
0478   /*
0479    *  We are using interrupt driven output and termios only sends us
0480    *  one character at a time.
0481    */
0482 
0483   if ( !len )
0484     return 0;
0485 
0486   /*
0487    *  Put the character out and enable interrupts if necessary.
0488    */
0489 
0490   rtems_interrupt_disable(Irql);
0491     if ( Console_Port_Data[minor].bActive == FALSE ) {
0492       Console_Port_Data[minor].bActive = TRUE;
0493       mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL);
0494     }
0495     (*setReg)(pMC68681_port, MC68681_TX_BUFFER, *buf);
0496   rtems_interrupt_enable(Irql);
0497 
0498   return 0;
0499 }
0500 
0501 /*
0502  *  mc68681_write_support_polled
0503  *
0504  *  Console Termios output entry point when using polled output.
0505  *
0506  */
0507 
0508 MC68681_STATIC ssize_t mc68681_write_support_polled(
0509   int         minor,
0510   const char *buf,
0511   size_t      len
0512 )
0513 {
0514   int nwrite = 0;
0515 
0516   /*
0517    * poll each byte in the string out of the port.
0518    */
0519   while (nwrite < len) {
0520     /*
0521      * transmit character
0522      */
0523     mc68681_write_polled(minor, *buf++);
0524     nwrite++;
0525   }
0526 
0527   /*
0528    * return the number of bytes written.
0529    */
0530   return nwrite;
0531 }
0532 
0533 /*
0534  *  mc68681_inbyte_nonblocking_polled
0535  *
0536  *  Console Termios polling input entry point.
0537  */
0538 
0539 MC68681_STATIC int mc68681_inbyte_nonblocking_polled(
0540   int minor
0541 )
0542 {
0543   uint32_t             pMC68681_port;
0544   unsigned char        ucLineStatus;
0545   unsigned char        cChar;
0546   getRegister_f        getReg;
0547 
0548   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0549   getReg        = Console_Port_Tbl[minor]->getRegister;
0550 
0551   ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
0552   if(ucLineStatus & MC68681_RX_READY) {
0553     cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
0554     return (int)cChar;
0555   } else {
0556     return -1;
0557   }
0558 }
0559 
0560 /*
0561  *  mc68681_baud_rate
0562  */
0563 
0564 MC68681_STATIC int mc68681_baud_rate(
0565   int           minor,
0566   int           baud,
0567   unsigned int *baud_mask_p,
0568   unsigned int *acr_bit_p,
0569   unsigned int *command
0570 )
0571 {
0572   unsigned int           baud_mask;
0573   unsigned int           acr_bit;
0574   int                    status;
0575   int                    is_extended;
0576   int                    baud_requested;
0577   mc68681_baud_table_t  *baud_tbl;
0578 
0579   baud_mask = 0;
0580   acr_bit = 0;
0581   status = 0;
0582 
0583   if (Console_Port_Tbl[minor]->ulDataPort & MC68681_DATA_BAUD_RATE_SET_2)
0584   {
0585     acr_bit = 1;
0586   }
0587 
0588   is_extended = 0;
0589 
0590   switch (Console_Port_Tbl[minor]->ulDataPort & MC68681_XBRG_MASK) {
0591     case MC68681_XBRG_IGNORED:
0592       *command = 0x00;
0593       break;
0594     case MC68681_XBRG_ENABLED:
0595       *command = 0x80;
0596       is_extended = 1;
0597       break;
0598     case MC68681_XBRG_DISABLED:
0599       *command = 0x90;
0600       break;
0601   }
0602 
0603   baud_requested = baud;
0604   if (!baud_requested)
0605     baud_requested = B9600;              /* default to 9600 baud */
0606 
0607   baud_requested = rtems_termios_baud_to_index( baud_requested );
0608   if (baud_requested == -1)
0609     return -1;
0610 
0611   baud_tbl = (mc68681_baud_table_t *)
0612      ((uintptr_t)Console_Port_Tbl[minor]->ulClock);
0613   if (!baud_tbl)
0614     rtems_fatal_error_occurred(RTEMS_INVALID_ADDRESS);
0615 
0616   if ( is_extended )
0617     baud_mask = (unsigned int)baud_tbl[ acr_bit + 2 ][ baud_requested ];
0618   else
0619     baud_mask = baud_tbl[ acr_bit ][ baud_requested ];
0620 
0621   if ( baud_mask == MC68681_BAUD_NOT_VALID )
0622     status = -1;
0623 
0624   /*
0625    *  upper nibble is receiver and lower nibble is transmitter
0626    */
0627 
0628   *baud_mask_p = (baud_mask << 4) | baud_mask;
0629   *acr_bit_p   = acr_bit;
0630   return status;
0631 }
0632 
0633 /*
0634  *  mc68681_process
0635  *
0636  *  This routine is the per port console interrupt handler.
0637  */
0638 
0639 MC68681_STATIC void mc68681_process(
0640   int  minor
0641 )
0642 {
0643   uint32_t                pMC68681;
0644   uint32_t                pMC68681_port;
0645   volatile uint8_t        ucLineStatus;
0646   volatile uint8_t        ucISRStatus;
0647   char                    cChar;
0648   getRegister_f           getReg;
0649 
0650   pMC68681      = Console_Port_Tbl[minor]->ulCtrlPort1;
0651   pMC68681_port = Console_Port_Tbl[minor]->ulCtrlPort2;
0652   getReg        = Console_Port_Tbl[minor]->getRegister;
0653 
0654   /* Get ISR at the beginning of the IT routine */
0655   ucISRStatus = (*getReg)(pMC68681, MC68681_INTERRUPT_STATUS_REG);
0656 
0657   /* Get good ISR a or b channel */
0658   if (pMC68681 != pMC68681_port){
0659     ucISRStatus >>= 4;
0660   }
0661 
0662   /* See if is usefull to call rtems_termios_dequeue */
0663   if(Console_Port_Data[minor].bActive == FALSE) {
0664         ucISRStatus = ucISRStatus & ~MC68681_IR_TX_READY;
0665   }
0666 
0667   /*
0668    * Deal with any received characters
0669    */
0670   while(true) {
0671     ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
0672     if(!(ucLineStatus & MC68681_RX_READY)) {
0673       break;
0674     }
0675     /*
0676      *  If there is a RX error, then dump all the data.
0677      */
0678     if ( ucLineStatus & MC68681_RX_ERRORS ) {
0679       do {
0680         cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
0681         ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
0682       } while ( ucLineStatus & MC68681_RX_READY );
0683       continue;
0684     }
0685     cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
0686     rtems_termios_enqueue_raw_characters(
0687       Console_Port_Data[minor].termios_data,
0688       &cChar,
0689       1
0690     );
0691   }
0692 
0693   /*
0694    *  Deal with the transmitter
0695    */
0696 
0697   if (ucISRStatus & MC68681_IR_TX_READY) {
0698     if (!rtems_termios_dequeue_characters(
0699           Console_Port_Data[minor].termios_data, 1)) {
0700       /* If no more char to send, disable TX interrupt */
0701       Console_Port_Data[minor].bActive = FALSE;
0702       mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
0703     }
0704   }
0705 }
0706 
0707 /*
0708  *  mc68681_build_imr
0709  *
0710  *  This function returns the value for the interrupt mask register for this
0711  *  DUART.  Since this is a shared register, we must look at the other port
0712  *  on this chip to determine whether or not it is using interrupts.
0713  */
0714 
0715 MC68681_STATIC unsigned int mc68681_build_imr(
0716   int  minor,
0717   int  enable_flag
0718 )
0719 {
0720   int              mate;
0721   int              is_a;
0722   unsigned int     mask;
0723   unsigned int     mate_mask;
0724   unsigned int     pMC68681;
0725   unsigned int     pMC68681_port;
0726   mc68681_context *pmc68681Context;
0727   mc68681_context *mateContext;
0728 
0729   pMC68681        = Console_Port_Tbl[minor]->ulCtrlPort1;
0730   pMC68681_port   = Console_Port_Tbl[minor]->ulCtrlPort2;
0731   pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
0732   mate            = pmc68681Context->mate;
0733 
0734   mask = 0;
0735   mate_mask = 0;
0736 
0737   is_a = (pMC68681 == pMC68681_port);
0738 
0739   /*
0740    *  If there is a mate for this port, get its IMR mask.
0741    */
0742 
0743   if ( mate != -1 ) {
0744     mateContext = Console_Port_Data[mate].pDeviceContext;
0745 
0746     if (mateContext)
0747       mate_mask = mateContext->imr;
0748   }
0749 
0750   /*
0751    *  Calculate this port's IMR mask and save it in the context area.
0752    */
0753 
0754   if ( Console_Port_Tbl[minor]->pDeviceFns->deviceOutputUsesInterrupts )
0755     mask = enable_flag;
0756 
0757   pmc68681Context->imr = mask;
0758 
0759   /*
0760    *  Now return the full IMR value
0761    */
0762 
0763   if (is_a)
0764     return (mate_mask << 4) | mask;
0765 
0766   return (mask << 4) | mate_mask;
0767 }
0768 
0769 /*
0770  *  mc68681_enable_interrupts
0771  *
0772  *  This function enables specific interrupt sources on the DUART.
0773  */
0774 
0775 MC68681_STATIC void mc68681_enable_interrupts(
0776   int minor,
0777   int imr_mask
0778 )
0779 {
0780   uint32_t              pMC68681;
0781   setRegister_f         setReg;
0782 
0783   pMC68681 = Console_Port_Tbl[minor]->ulCtrlPort1;
0784   setReg   = Console_Port_Tbl[minor]->setRegister;
0785 
0786   /*
0787    *  Enable interrupts on RX and TX -- not break
0788    */
0789 
0790   (*setReg)(
0791      pMC68681,
0792      MC68681_INTERRUPT_MASK_REG,
0793      mc68681_build_imr(minor, imr_mask)
0794   );
0795 }