gonzui


Format: Advanced Search

tkernel_2/driver/tef_em1d/console/src/ns16450.cbare sourcepermlink (0.08 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T-Kernel 2.0 Software Package
    4:  *
    5:  *    Copyright 2011 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17.
   10:  *    Modified by T-Engine Forum at 2014/09/10.
   11:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   12:  *
   13:  *----------------------------------------------------------------------
   14:  */
   15: 
   16: /*
   17:  *      ns16450.c    Console/Low-level serial I/O driver
   18:  *
   19:  *      Serial line low-level driver (for NS16450)
   20:  */
   21: 
   22: #include "line_drv.h"
   23: #include <sys/sysinfo.h>
   24: 
   25: /*
   26:  *      Define the serial controller operation function groups
   27:  */
   28: LOCAL ER        ns16450_in(LINE_INFO *li, UB *buf, W len, W *alen, W tmout);
   29: LOCAL ER        ns16450_out(LINE_INFO *li, UB *buf, W len, W *alen, W tmout);
   30: LOCAL ER        ns16450_ctl(LINE_INFO *li, W kind, UW *arg);
   31: LOCAL void      ns16450_up(LINE_INFO *li);
   32: LOCAL void      ns16450_down(LINE_INFO *li);
   33: 
   34: EXPORT  SC_FUNC  ScFuncNS16450 = {
   35:         ns16450_in, ns16450_out, ns16450_ctl, ns16450_up, ns16450_down,
   36: };
   37: 
   38: /*
   39:  *      Define the serial controller ("NS16450" and "NS16550")
   40:  */
   41: #include "ns16450.h"            /* Common definition */
   42: #include "ns16450sys.h"         /* System-dependent definition */
   43: 
   44: /* Clock */
   45: #define _CLOCK          UART_CLK
   46: 
   47: /* I/O port address */
   48: #define _IOADR(n)       (scdefs->c.iobase + (n) * scdefs->c.iostep)
   49: 
   50: /*
   51:  *      Bit-unit access to serial controller register
   52:  */
   53: Inline void clr_screg( W port, UB m )
   54: {
   55:         OutB(port, InB(port) & ~m);
   56: }
   57: Inline void set_screg( W port, UB m )
   58: {
   59:         OutB(port, InB(port) | m);
   60: }
   61: Inline void set_screg2( W port, UB m, UB v )
   62: {
   63:         OutB(port, (InB(port) & ~m) | v);
   64: }
   65: 
   66: /*
   67:  *      "RTS" and "Break" signal operations
   68:  */
   69: #define ON_RTS          set_screg(SC_MCTL, MC_RTS|MC_OUT2)   /* Turn on RTS */
   70: #define OFF_RTS         set_screg2(SC_MCTL, MC_RTS, MC_OUT2) /* Turn off RTS */
   71: #define ON_BREAK        set_screg(SC_LCTL, LC_SBRK)    /* Break send */
   72: #define OFF_BREAK       clr_screg(SC_LCTL, LC_SBRK)   /* Break end */
   73: 
   74: /*
   75:  *      Send/Receive interrupt control
   76:  */
   77: 
   78: #define ENB_RXINT(li)   OutB(SC_INTE, (li->enbint == 0) ? \
   79:                                         0x00 : (IM_LSTS|IM_RCV|IM_MSTS))
   80: #define ENB_TXRXINT(li) OutB(SC_INTE, (li->enbint == 0) ? \
   81:                                         0x00 : (IM_LSTS|IM_SND|IM_RCV|IM_MSTS))
   82: #define DIS_TXRXINT(li) OutB(SC_INTE, 0x00)
   83: 
   84: /*
   85:  *      Forcible setting of the control line
   86:  */
   87: LOCAL   ER        line_ctl( LINE_INFO *li, UW cmd )
   88: {
   89:         SC_DEFS        *scdefs = &li->scdefs;
   90:         UW     line;
   91:         ER     err = E_OK;
   92: 
   93:         line = cmd & (MC_RTS|MC_DTR);
   94: 
   95:         switch ( cmd & 0xfffffffc ) {
   96:           case RSCTL_ON:
   97:                 set_screg(SC_MCTL, line | MC_OUT2);
   98:                 break;
   99:           case RSCTL_OFF:
  100:                 set_screg2(SC_MCTL, line, MC_OUT2);
  101:                 break;
  102:           case RSCTL_SET:
  103:                 set_screg2(SC_MCTL, MC_RTS|MC_DTR, line | MC_OUT2);
  104:                 break;
  105:           default:
  106:                 err = E_PAR;
  107:         }
  108:         return err;
  109: }
  110: 
  111: /*
  112:  *      Initialize the serial controller (mode setting)
  113:  */
  114: LOCAL   ER        init_sio( LINE_INFO *li, RsMode mode )
  115: {
  116:         SC_DEFS        *scdefs = &li->scdefs;
  117:         UH     divcnt;
  118:         UB     lctl, fctl, mctl;
  119:         W      i;
  120:         ER     err = E_OK;
  121: 
  122:         /* Parameter check */
  123:         if ( mode.parity == 3
  124:           || mode.stopbits == 3
  125:           || mode.baud < 50 || mode.baud > SC_LINE_SPEED(1) ) return E_PAR;
  126: 
  127:         /* Communication speed setting value */
  128:         divcnt = SC_LINE_SPEED(mode.baud);
  129: 
  130:         /* Line mode */
  131:         lctl = 0x00;
  132:         if ( mode.datalen == 0 ) {
  133:                 /* 5 data bits */
  134:                 if ( mode.stopbits == 2 ) return E_NOSPT;   /* 2 stop bits */
  135:                 if ( mode.stopbits == 1 ) lctl |= LC_STOP;  /* 1.5 stop bits */
  136:         } else {
  137:                 /* 6,7,8 data bits */
  138:                 if ( mode.stopbits == 1 ) return E_NOSPT;   /* 1.5 stop bits */
  139:                 if ( mode.stopbits == 2 ) lctl |= LC_STOP;  /* 2 stop bits */
  140:                 lctl |= mode.datalen;
  141:         }
  142:         switch ( mode.parity ) {
  143:           case 1: lctl |= LC_OddParity;  break;        /* Odd parity */
  144:           case 2: lctl |= LC_EvenParity; break;        /* Even parity */
  145:         }
  146: 
  147:         /* FIFO mode*/
  148:         fctl = FC_FIFO;
  149:         fctl |= ( mode.baud < 9600 )? FC_TL01: FC_TL08;
  150: 
  151:         /* Modem mode*/
  152:         mctl = ( li->suspend == 0 )? MC_RTS|MC_DTR|MC_OUT2: MC_OUT2;
  153: 
  154:         /* Disable the interrupt */
  155:         li->enbint = 0;
  156:         DIS_TXRXINT(li);
  157: 
  158:         /* Wait for the send buffer to become empty for confirmation */
  159:         for ( i = 0; i < FIFO_SIZE; ++i ) {
  160:                 if ( (InB(SC_LSTS) & LS_TSRE) != 0 ) break;
  161:                 tk_dly_tsk(100);
  162:         }
  163: 
  164:         /* Clear the pending interrupt */
  165:         OutB(SC_LCTL, 0x00);
  166:         InB(SC_LSTS);          /* Clear the "IS_LSTS" */
  167:         InB(SC_INTS);          /* Clear the "IS_SND" */
  168:         InB(SC_MSTS);          /* Clear the "IS_MSTS" */
  169: 
  170:         /* Read and discard the data remaining in the receive-buffer */
  171:         for ( i = 0; i < FIFO_SIZE; ++i ) {
  172:                 InB(SC_DATA); /* Clear "IS_RCV IS_CTMO" */
  173:         }
  174: 
  175:         if ( fctl != 0 ) {
  176:                 /* Check the presence and absence of FIFO */
  177:                 OutB(SC_FCTL, fctl);
  178:                 if ( (InB(SC_INTS) & IS_FIFO) == 0 ) {
  179:                         fctl = 0;  /* There is no FIFO */
  180:                 }
  181:         }
  182:         scdefs->fctl = fctl;
  183: 
  184:         /* Communication speed over 19200 bps is disabled without FIFO */
  185:         if ( fctl == 0 && mode.baud > 19200 ) err = E_NOSPT;
  186: 
  187:         /* Return to RS flow status */
  188:         if ( li->flowsts.rsoff ) mctl &= ~MC_RTS;  /* RTS OFF */
  189: 
  190:         /* Initialize the serial controller */
  191:         OutB(SC_LCTL, LC_DLAB);
  192:         OutB(SC_DIVH, divcnt >> 8);    /* Communication speed */
  193:         OutB(SC_DIVL, divcnt & 0xff);
  194:         OutB(SC_LCTL, lctl);           /* Line mode */
  195:         OutB(SC_FCTL, (fctl == 0) ? 0 : (fctl|FC_TXCLR|FC_RXCLR));
  196:                                         /* Set/Disable the FIFO mode */
  197:         li->msts = InB(SC_MSTS);       /* Initilize the modem status */
  198: 
  199:         OutB(SC_MCTL, mctl);           /* Modem mode */
  200: 
  201:         if ( err == E_OK && li->suspend == 0 ) {
  202:                 li->enbint = 1;
  203:                 ENB_RXINT(li);                /* Enable the rcv interrupt only */
  204:         }
  205: 
  206:         return err;
  207: }
  208: 
  209: /*
  210:  *      Interrupt handler
  211:  */
  212: EXPORT  void     sio_inthdr( UINT dintno )
  213: {
  214:         LINE_INFO      *li;
  215:         SC_DEFS                *scdefs;
  216:         UB             lsts, fctl, c;
  217:         UW             ptr, nptr;
  218:         W              i, n, cnt;
  219: 
  220:         /* Search the port informartion */
  221:         for (li = &LineInfo[0], i = nPorts; ; li++) {
  222:                 if (--i < 0) return;
  223:                 if (li->scdefs.c.intvec == dintno) {
  224:                         if (li->scdefs.fn != &ScFuncNS16450) return;
  225:                         break;
  226:                 }
  227:         }
  228:         scdefs = &li->scdefs;
  229:         fctl = scdefs->fctl;           /* FIFO configuration information */
  230: 
  231:    /* Execute the processing while the interrupt cause exists */
  232: 
  233:    while( (InB(SC_INTS) & IS_PEND) == 0 ) {
  234: 
  235:         /* Receive processing : repeat until there is no receive data :
  236:                 Limit the maximum number to prevent the infinite loop
  237:                 when card is pulled out */
  238: 
  239:         for ( cnt = 0; cnt < FIFO_SIZE; cnt++ ) {
  240:                 lsts = InB(SC_LSTS);
  241: 
  242:                 if ( (lsts & LS_RxERR) != 0 ) {
  243:                         UB   s;
  244: 
  245:                         /* Receive error*/
  246:                         s = lsts & LS_RxERR;
  247:                         li->lsts |= s;               /* Record the error status */
  248:                         li->lstshist |= s;
  249: 
  250:                         /* Generate event when the receive-buffer is empty */
  251:                         if ( li->in_wptr == li->in_rptr ) {
  252:                                 tk_set_flg(li->flg, FLG_IN_NORM);
  253:                         }
  254: 
  255:                         if ( fctl != 0 && (lsts & LS_OERR) != 0 ) {
  256:                                 /* If overrun error occurs when using FIFO,
  257:                                    the all receive FIFO shall be cleared. */
  258:                                 OutB(SC_FCTL, fctl|FC_RXCLR);
  259:                         }
  260: 
  261:                         /* Read and discard the receive data */
  262:                         InB(SC_DATA);
  263:                         continue;
  264:                 }
  265: 
  266:                 if ( (lsts & LS_DRDY) == 0 ) break;
  267:                                 /* There is no receive data */
  268: 
  269:                 /* Fetch the receive data */
  270:                 c = InB(SC_DATA);
  271: 
  272:                 /* Call the external function */
  273:                 if ( li->extfn != NULL ) {
  274:                         if ( (*li->extfn)(li->extpar, c) ) continue;
  275:                 }
  276: 
  277:                 /* Send "XON/XOFF" flow control  */
  278:                 if ( li->flow.sxflow ) {
  279:                         if ( c == XOFF ) {
  280:                                 li->flow.rcvxoff = 1;
  281:                                 continue;
  282:                         }
  283:                         if ( c == XON
  284:                           || (li->flow.rcvxoff && li->flow.xonany) ) {
  285:                                 li->flow.rcvxoff = 0;
  286:                                 continue;
  287:                         }
  288:                 }
  289: 
  290:                 /* Record and discard the error status
  291:                                         when the receive buffer is full  */
  292:                 ptr = li->in_wptr;
  293:                 nptr = PTRMASK(li, ptr + 1);
  294:                 if ( nptr == li->in_rptr ) {
  295:                         li->lsts |= LS_RXOV; /* Record the error status */
  296:                         li->lstshist |= LS_RXOV;
  297:                         continue;
  298:                 }
  299: 
  300:                 /* Store the receive data to the receive-buffer */
  301:                 li->in_buf[ptr] = c;
  302:                 li->in_wptr = nptr;
  303: 
  304:                 /* Generate the event when a receive-buffer is empty */
  305:                 if ( ptr == li->in_rptr ) tk_set_flg(li->flg, FLG_IN_NORM);
  306: 
  307:                 /* Receive error control */
  308:                 if ( (li->flow.rsflow || li->flow.rxflow)
  309:                   && IN_BUF_REMAIN(li) < XOFF_MARGIN ) {
  310:                         /* RS flow control */
  311:                         if ( li->flow.rsflow && li->flowsts.rsoff == 0 ) {
  312:                                 li->flowsts.rsoff = 1;
  313:                                 OFF_RTS;
  314:                         }
  315:                         /* "XON/XOFF" flow control */
  316:                         if ( li->flow.rxflow && li->flowsts.sndxoff == 0 ) {
  317:                                 li->flowsts.sndxoff = 1;
  318:                                 li->flowsts.reqchar = XOFF;
  319:                         }
  320:                 }
  321:         }
  322: 
  323:         /* Send processing*/
  324:         li->msts = InB(SC_MSTS);
  325: 
  326:         if ( (lsts & LS_THRE) != 0                             /* Tx Ready */
  327:           && li->flow.rcvxoff == 0                             /* XOFF */
  328:           && (li->flow.csflow == 0 || (li->msts & MS_CS) != 0) /* CS ON */
  329:         ) {
  330:                 cnt = n = li->ou_wptr - li->ou_rptr;
  331:                                 /* The number of characters to send */
  332:                 if ( li->flowsts.reqchar != 0 ) n++; /* Send the "XON/XOFF" */
  333:                 if ( fctl != 0 ) {
  334:                         if ( n > FIFO_SIZE ) n = FIFO_SIZE;
  335:                                 /* Limit to the FIFO buffer size */
  336:                 } else {
  337:                         if ( n >  1 ) n = 1; /* There is no FIFO */
  338:                 }
  339: 
  340:                 if ( n > 0 ) {                        /* There is the send data */
  341:                         if ( li->flowsts.reqchar != 0 ) {
  342:                                 /* Send the "XON / XOFF" */
  343:                                 OutB(SC_DATA, li->flowsts.reqchar);
  344:                                 li->flowsts.reqchar = 0;
  345:                                 n--;
  346:                         }
  347:                         cnt -= n;    /* Remainig number of chars to send */
  348: 
  349:                         ENB_TXRXINT(li); /* Enable the snd/rcv interrupts */
  350: 
  351:                         /* Send the data */
  352:                         while ( --n >= 0 ) {
  353:                                 OutB(SC_DATA, li->ou_buf[
  354:                                         OU_PTRMASK(li, li->ou_rptr++)]);
  355:                         }
  356:                 } else {
  357:                         /* Completion of sending or No sending */
  358:                         ENB_RXINT(li);       /* Enable the rcv interrupt only */
  359:                 }
  360:                 /* Send (completion)-notification event occurs */
  361:                 if (cnt < li->ou_cnt) {
  362:                         tk_set_flg(li->flg, FLG_OU_NORM);
  363:                         li->ou_cnt = 0;
  364:                 }
  365:         } else {
  366:                 /* Disable the snd interrupt
  367:                         when the send is unavailable in "Tx Ready" status */
  368:                 if ((lsts & LS_THRE) != 0) ENB_RXINT(li);
  369:         }
  370:     }
  371: 
  372:         /* Interrupt post-processing */
  373:         end_inthdr(scdefs);
  374: }
  375: 
  376: /*
  377:  *      Set the hardware configuration
  378:  */
  379: LOCAL   ER        setHwConf( LINE_INFO *li, RsHwConf_16450 *conf,
  380:                                                 RsMode mode, BOOL startup )
  381: {
  382:         SC_DEFS        *scdefs = &li->scdefs;
  383:         ER     err;
  384: 
  385:         /* Cancel the current setting when it is already set */
  386:         if ( scdefs->c.iostep > 0 ) {
  387:                 /* Disable the interrupt to the target port */
  388:                 li->enbint = 0;
  389:                 DIS_TXRXINT(li);
  390: 
  391:                 /* Release the interrupt handler */
  392:                 delete_inthdr(scdefs, sio_inthdr);
  393:         }
  394: 
  395:         /* Save the new configuration */
  396:         scdefs->c = *conf;
  397:         li->mode = mode;
  398: 
  399:         if ( scdefs->c.iostep > 0 ) {
  400: 
  401:                 /* Disable the interrupt to the target port */
  402:                 li->enbint = 0;
  403:                 DIS_TXRXINT(li);
  404: 
  405:                 /* Register the interrupt handler */
  406:                 err = regist_inthdr(scdefs, sio_inthdr);
  407:                 if (err < E_OK) return err;
  408: 
  409:                 /* Initialize the line by the specified communication mode */
  410:                 err = init_sio(li, mode);
  411:                 if ( err < E_OK ) {
  412:                         /* Initialize by the default mode when error occurs */
  413:                         li->mode = scdefs->mode;
  414:                         err = init_sio(li, li->mode);
  415:                         if ( err < E_OK ) return err;
  416:                 }
  417:                 /* Interrupt is enabled by the init_sio (when "suspend = 0") */
  418:         }
  419: 
  420:         return E_OK;
  421: }
  422: 
  423: /*
  424:  *      Set the line status
  425:  */
  426: LOCAL   RsStat    make_line_stat( LINE_INFO *li, UB lsts )
  427: {
  428:         RsStat stat;
  429: static  RsStat   stat0 = {0};
  430: 
  431:         stat = stat0;
  432:         if ( (lsts & LS_RXOV) != 0 )   stat.BE = 1;
  433:         if ( (lsts & LS_FERR) != 0 )   stat.FE = 1;
  434:         if ( (lsts & LS_OERR) != 0 )   stat.OE = 1;
  435:         if ( (lsts & LS_PERR) != 0 )   stat.PE = 1;
  436:         stat.XF = li->flow.rcvxoff;
  437:         if ( (lsts & LS_BINT) != 0 )   stat.BD = 1;
  438:         if ( (li->msts & MS_DR) != 0 ) stat.DR = 1;
  439:         if ( (li->msts & MS_CD) != 0 ) stat.CD = 1;
  440:         if ( (li->msts & MS_CS) != 0 ) stat.CS = 1;
  441:         if ( (li->msts & MS_RI) != 0 ) stat.CI = 1;
  442:         return stat;
  443: }
  444: 
  445: /*
  446:  *      Send the initial one character.
  447:  *      It shall be called in the interrupt-disabled status."True" shall be
  448:  *      returned when it can be sent.
  449:  *      It shall be sent from the send buffer when "c < 0".
  450:  *      In addition, it shall be sent to FIFO buffer size when using FIFO.
  451:  */
  452: LOCAL   BOOL      send_1st_char( LINE_INFO *li, W c )
  453: {
  454:         SC_DEFS                *scdefs = &li->scdefs;
  455:         UB             lsts, s;
  456:         W              n;
  457: 
  458:         /* Unable to send during a "XOFF" */
  459:         if ( li->flow.rcvxoff != 0 ) return FALSE;
  460: 
  461:         /* Get the line status and the modem status */
  462:         lsts = InB(SC_LSTS);
  463:         li->msts = InB(SC_MSTS);
  464: 
  465:         /* Record the line error */
  466:         if ( (s = lsts & LS_RxERR) != 0 ) {
  467:                 li->lsts |= s;
  468:                 li->lstshist |= s;
  469:         }
  470: 
  471:         /* Unable to send when "Tx Not Ready" status or "CS OFF" status */
  472:         if ( (lsts & LS_THRE) == 0
  473:           || (li->flow.csflow != 0 && (li->msts & MS_CS) == 0) ) return FALSE;
  474: 
  475:         if ( c < 0 ) {
  476:                 n = li->ou_wptr - li->ou_rptr;        /* Number of chars to send */
  477:                 if ( n <= 0 ) return FALSE;   /* There is no data to send */
  478:                 if ( scdefs->fctl != 0 ) {
  479:                         /* When FIFO is used */
  480:                         if ( n > FIFO_SIZE ) n = FIFO_SIZE;
  481:                                                 /* Limit to FIFO buffer size */
  482:                 } else {
  483:                         n = 1;       /* There is no FIFO */
  484:                 }
  485:                 c = li->ou_buf[OU_PTRMASK(li, li->ou_rptr++)];
  486:         } else {
  487:                 n = 1;
  488:         }
  489: 
  490:         /* Send */
  491:         ENB_TXRXINT(li);               /* Enable the snd/rcv interrupts */
  492:         OutB(SC_DATA, c);
  493:         while ( --n > 0 )
  494:                 OutB(SC_DATA, li->ou_buf[OU_PTRMASK(li, li->ou_rptr++)]);
  495:         return TRUE;
  496: }
  497: 
  498: /*
  499:  *      One character input
  500:  */
  501: LOCAL   WRTN      recv_one_char( LINE_INFO *li, W tmout )
  502: {
  503:         SC_DEFS        *scdefs = &li->scdefs;
  504:         UB     c;
  505:         UINT   flgptn;
  506:         UW     imask;
  507:         ER     er;
  508: 
  509:         /* Wait for receiving while the receive buffer is empty */
  510:         while ( li->in_wptr == li->in_rptr ) {
  511: 
  512:                 if ( tmout == 0 ) return RTN_NONE; /* There is no wait */
  513: 
  514:                 /* Wait for receiving or line status change */
  515:                 er = tk_wai_flg(li->flg, FLG_IN_WAIPTN,
  516:                                 TWF_ORW | TWF_BITCLR, &flgptn, tmout);
  517:                 if ( er == E_TMOUT ) return RTN_TMOUT;
  518:                 if ( er < E_OK || (flgptn & FLG_IN_ABORT) ) return RTN_ABORT;
  519:                 if ( li->lsts != 0 ) return RTN_ERR; /* Receive error*/
  520:         }
  521: 
  522:         /* Fetch the receive data */
  523:         c = li->in_buf[li->in_rptr];
  524:         li->in_rptr = PTRMASK(li, li->in_rptr + 1);
  525: 
  526:         /* Receive flow control */
  527:         if ( (li->flowsts.rsoff || li->flowsts.sndxoff)
  528:            && IN_BUF_REMAIN(li) > XON_MARGIN ) {
  529:                 /* It is a receive-stop status.
  530:                         However, the receive-buffer has some empty space */
  531:                 if ( li->flowsts.rsoff ) {
  532:                         /* "RS" flow control */
  533:                         DI(imask);
  534:                         ON_RTS;
  535:                         li->flowsts.rsoff = 0;
  536:                         EI(imask);
  537:                 }
  538:                 if ( li->flowsts.sndxoff ) {
  539:                         /* "XOFF" flow control */
  540:                         DI(imask);
  541:                         if ( !send_1st_char(li, XON) ) {
  542:                                 li->flowsts.reqchar = XON; 
  543:                                         /* "XON" reservation for sending */
  544:                         }
  545:                         li->flowsts.sndxoff = 0;
  546:                         EI(imask);
  547:                 }
  548:         }
  549: 
  550:         return c;
  551: }
  552: 
  553: /*
  554:  *      Input from serial port
  555:  */
  556: LOCAL   ER        ns16450_in( LINE_INFO *li, UB *buf, W len, W *alen, W tmout )
  557: {
  558:         SC_DEFS                *scdefs = &li->scdefs;
  559:         W              c;
  560:         UW             rsz = 0;
  561:         RsErr          err;
  562: 
  563:         if ( scdefs->c.iostep <= 0 ) return E_NOMDA; 
  564:                                 /* Hardware configuration is not set yet */
  565: 
  566:         /* Execute the special processing
  567:                         to avoid deadlock at the time of polling */
  568:         if (tmout == 0 && li->in_wptr == li->in_rptr) {
  569:                 err.w = E_BUSY;
  570:                 goto EEXIT;
  571:         }
  572: 
  573:         /* Console input processing lock */
  574:         if ( consMLock(&li->lock, IN_LOCK) < E_OK ) {
  575:                 err.s = make_line_stat(li, 0);
  576:                 err.c.ErrorClass = MERCD(E_IO);
  577:                 err.c.Aborted = 1;
  578:                 goto EEXIT;
  579:         }
  580: 
  581:         err.w = E_OK;
  582: 
  583:         if ( len <= 0 ) {
  584:                 /* Check the number of the received bytes */
  585:                 rsz = IN_BUF_SIZE(li);
  586:         } else {
  587:                 li->lsts = 0;  /* Clear the error status */
  588: 
  589:                 /* Receive the data */
  590:                 for ( rsz = 0; rsz < len; rsz++ ) {
  591: 
  592:                         c = recv_one_char(li, tmout);
  593:                         if ( c < RTN_OK ) {
  594:                                 if ( c == RTN_NONE ) {
  595:                                         err.w = ( rsz > 0 )? E_OK: E_BUSY;
  596:                                 } else {
  597:                                         err.s = make_line_stat(li, li->lsts);
  598:                                         err.c.ErrorClass = MERCD(E_IO);
  599:                                         if ( c == RTN_TMOUT ) err.c.Timout = 1;
  600:                                         if ( c == RTN_ABORT ) err.c.Aborted= 1;
  601:                                 }
  602:                                 break;
  603:                         }
  604:                         buf[rsz] = c;
  605:                 }
  606:         }
  607: 
  608:         /* Clear the "ABORT" flag */
  609:         tk_clr_flg(li->flg, ~(FLG_IN_ABORT | FLG_OU_ABORT));
  610: 
  611:         /* Release the lock */
  612:         consMUnlock(&li->lock, IN_LOCK);
  613: 
  614: EEXIT:
  615: 
  616:         *alen = rsz;  /* The number of the actually received bytes */
  617:         return err.w;
  618: }
  619: 
  620: /*
  621:  *      Output to the serial port
  622:  */
  623: LOCAL   ER        ns16450_out( LINE_INFO *li, UB *buf, W len, W *alen, W tmout )
  624: {
  625:         SC_DEFS                *scdefs = &li->scdefs;
  626:         RsErr          err;
  627:         W              sz, n;
  628:         RTN            r;
  629:         UW             wptr, ptr, imask;
  630:         UINT           flgptn;
  631:         ER             er;
  632: 
  633:         if ( scdefs->c.iostep <= 0 ) return E_NOMDA;
  634:                                 /* Hardware configuration is not set yet */
  635: 
  636:         *alen = 0;
  637: 
  638:         /* Console output processing lock */
  639:         if ( consMLock(&li->lock, OU_LOCK) < E_OK ) {
  640:                 err.s = make_line_stat(li, 0);
  641:                 err.c.ErrorClass = MERCD(E_IO);
  642:                 err.c.Aborted = 1;
  643:                 goto EEXIT;
  644:         }
  645: 
  646:         err.w = E_OK;
  647: 
  648:         /*
  649:          * An output handler is read by the interrupt handler, so the page-out
  650:          * shall not be executed.
  651:          * Therefore, the resident memory shall be used as the output buffer
  652:          * instead of using the user-specified buffer "buffer", and the output
  653:          * data shall be copied.
  654:          */
  655: 
  656:         for (wptr = li->ou_wptr; len > 0; ) {
  657: 
  658:                 /* Copy the send data to the output buffer */
  659:                 sz = li->ou_rptr + OUBUFSZ - li->ou_wptr;
  660:                 if (sz > len) sz = len;
  661:                 n = OUBUFSZ - (ptr = OU_PTRMASK(li, li->ou_wptr));
  662:                 if (n > sz) n = sz;
  663:                 if (n > 0)  MEMCPY(&li->ou_buf[ptr], buf, n);
  664:                 if (sz > n) MEMCPY(&li->ou_buf[0], &buf[n], sz - n);
  665:                 buf += sz;
  666:                 len -= sz;
  667: 
  668:                 DI(imask);
  669:                 if (len <= 0) {
  670:                         /* All the send data is copied to the output buffer.
  671:                                 Therefore, notification shall be received
  672:                                 when it is completed */
  673:                         n = 1;
  674:                         if (tmout == 0) n = 0;
  675:                                 /* Do not wait for the completion of sending */
  676: 
  677:                 } else {
  678:                         /* The all send-data can not be copied to the output
  679:                                 buffer, so notification shall be received when
  680:                                 an empty space is available */
  681:                         if ((n = OUBUFSZ - len) < 20) n = 20;
  682:                 }
  683:                 li->ou_cnt = n;
  684:                 li->ou_wptr += sz;
  685: 
  686:                 /* While no sending is executed, the one character shall be
  687:                         first sent to cause the send interrupt  */
  688:                 if ((InB(SC_INTE) & IM_SND) == 0) send_1st_char(li, -1);
  689: 
  690:                 EI(imask);
  691: 
  692:                 /* Wait-for-completion of sending */
  693:                 for (r = RTN_OK; li->ou_cnt != 0; ) {
  694:                         ptr = li->ou_rptr;
  695:                         er = tk_wai_flg(li->flg, FLG_OU_WAIPTN,
  696:                                         TWF_ORW | TWF_BITCLR, &flgptn, tmout);
  697:                         if ( er == E_TMOUT ) {
  698:                                 /* Time-out error shall occur only when even
  699:                                         one character has not been sent from
  700:                                         the previous time. */
  701:                                 if ( ptr == li->ou_rptr ) {
  702:                                         r = RTN_TMOUT;
  703:                                         break;
  704:                                 }
  705:                         } else if ( er < E_OK || (flgptn & FLG_OU_ABORT) ) {
  706:                                 r = RTN_ABORT;
  707:                                 break;
  708:                         }
  709:                 }
  710:                 if ( r < RTN_OK ) {
  711:                         err.s = make_line_stat(li, 0);
  712:                         err.c.ErrorClass = MERCD(E_IO);
  713:                         if ( r == RTN_TMOUT ) err.c.Timout  = 1;
  714:                         if ( r == RTN_ABORT ) err.c.Aborted = 1;
  715:                         DI(imask);
  716:                         li->ou_wptr = li->ou_rptr;   /* Stop sending */
  717:                         EI(imask);
  718:                         break;
  719:                 }
  720:         }
  721: 
  722:         *alen = li->ou_wptr - wptr;    /* Actual already sent byte */
  723:         li->ou_cnt = 0;
  724: 
  725:         /* Clear the "ABORT" flag */
  726:         tk_clr_flg(li->flg, ~(FLG_IN_ABORT | FLG_OU_ABORT));
  727: 
  728:         /* Release the lock */
  729:         consMUnlock(&li->lock, OU_LOCK);
  730: 
  731: EEXIT:
  732: 
  733:         return err.w;
  734: }
  735: 
  736: /*
  737:  *      Control the serial port
  738:  */
  739: LOCAL   ER        ns16450_ctl( LINE_INFO *li, W kind, UW *arg )
  740: {
  741:         SC_DEFS                *scdefs = &li->scdefs;
  742:         ER             err = E_OK;
  743:         UW             imask;
  744:         W              n;
  745: 
  746:         if ( !(kind == DN_RS16450 || kind == -DN_RS16450)
  747:                 && scdefs->c.iostep <= 0 ) return E_NOMDA;
  748:                                 /* Hardware configuration is not set yet */
  749: 
  750:         /* Lock is unnecessary */
  751: 
  752:         switch ( kind ) {
  753:           case RS_ABORT:       /* Abort (release wait) */
  754:                 tk_set_flg(li->flg, FLG_IN_ABORT | FLG_OU_ABORT); /* Release */
  755:                 break;
  756: 
  757:           case RS_SUSPEND:     /* Transit to the suspend status  */
  758:           case RS_RESUME:      /* Return from the suspend status */
  759:                 /* Debug port shall not transit to the "suspend"
  760:                                                 status in debug mode */
  761:                 if ( !(isDebugPort(li) && _isDebugMode()) ) {
  762:                         if (kind == RS_RESUME) sio_susres(li, 1);
  763: 
  764:                         /* Reset controller */
  765:                         li->suspend = (kind == RS_SUSPEND) ? 1 : 0;
  766:                         err = setHwConf(li, &li->scdefs.c, li->mode, FALSE);
  767: 
  768:                         if (kind == RS_SUSPEND) sio_susres(li, 0);
  769:                 }
  770:                 break;
  771: 
  772:           case DN_RSMODE:      /* Set the communication mode */
  773:                 err = init_sio(li, *(RsMode*)arg);
  774:                 if ( err == E_OK ) {
  775:                         /* Initialize the serial line management information */
  776:                         DI(imask);
  777:                         li->in_rptr = li->in_wptr = 0;
  778:                         li->ou_rptr = li->ou_wptr = 0;
  779:                         li->ou_cnt = li->ou_len = 0;
  780:                         li->flow = li->scdefs.flow;
  781:                         li->flowsts = li->scdefs.flowsts;
  782:                         li->lsts = li->lstshist = 0;
  783:                         li->mode = *(RsMode*)arg;
  784:                         EI(imask);
  785:                 }
  786:                 break;
  787: 
  788:           case -DN_RSMODE:     /* Get the communication mode */
  789:                 *(RsMode*)arg = li->mode;
  790:                 break;
  791: 
  792:           case DN_RSFLOW:      /* Set the flow control */
  793:                 li->flow = *(RsFlow*)arg;
  794:                 break;
  795: 
  796:           case -DN_RSFLOW:     /* Set and get the flow control */
  797:                 *(RsFlow*)arg = li->flow;
  798:                 break;
  799: 
  800:           case -DN_RSSTAT:     /* Get the line status */
  801:                 *(RsStat*)arg = make_line_stat(li, li->lstshist);
  802:                 li->lstshist = 0;
  803:                 break;
  804: 
  805:           case DN_RSBREAK:     /* Send break signal */
  806:                 if ( (n = *arg) > 0 ) {
  807:                         DI(imask);  ON_BREAK;  EI(imask);
  808:                         tk_dly_tsk(n);       /* Wait */
  809:                         DI(imask);  OFF_BREAK; EI(imask);
  810:                 }
  811:                 break;
  812: 
  813:           case RS_RCVBUFSZ:    /* Set the receive-buffer */
  814:                 if ( (n = *arg) < MIN_INBUFSZ ) {
  815:                         err = E_PAR;
  816:                         break;
  817:                 }
  818:                 if ( n != li->in_bufsz ) {
  819:                         UB *new, *old;
  820:                         new = Malloc(n);
  821:                         if ( new != NULL ) {
  822:                                 DI(imask);
  823:                                 old = li->in_buf;
  824:                                 li->in_buf = new;
  825:                                 li->in_rptr = li->in_wptr = 0;
  826:                                 li->in_bufsz = n;
  827:                                 EI(imask);
  828:                                 Free(old);
  829:                         } else {
  830:                                 err = E_NOMEM;
  831:                         }
  832:                 }
  833:                 break;
  834: 
  835:           case -RS_RCVBUFSZ:   /* Get the receive-buffer size */
  836:                 *arg = li->in_bufsz;
  837:                 break;
  838: 
  839:           case RS_LINECTL:     /* Set the "ON/OFF" of control line */
  840:                 err = line_ctl(li, *arg);
  841:                 break;
  842: 
  843:           case RS_EXTFUNC:     /* Set the external processing function */
  844:                 if ( li->extfn != NULL && (FUNCP)arg[0] != NULL ) {
  845:                         err = E_OBJ;  /* Already set */
  846:                 } else {
  847:                         DI(imask);
  848:                         li->extfn  = (FUNCP)arg[0];
  849:                         li->extpar = arg[1];
  850:                         EI(imask);
  851:                 }
  852:                 break;
  853: 
  854:           case DN_RS16450:     /* Set the hardware configuration(for 16450) */
  855:                 err = setHwConf(li, (RsHwConf_16450*)arg, li->mode, FALSE);
  856:                 break;
  857: 
  858:           case -DN_RS16450:    /* Get the hardware configuration(for 16450) */
  859:                 *(RsHwConf_16450*)arg = scdefs->c;
  860:                 break;
  861: 
  862:           default:
  863:                 err = E_PAR;
  864:         }
  865: 
  866:         return err;
  867: }
  868: 
  869: /*
  870:  *      Exit the serial port
  871:  */
  872: LOCAL   void      ns16450_down( LINE_INFO *li )
  873: {
  874:         SC_DEFS                *scdefs = &li->scdefs;
  875: 
  876:         if ( scdefs->c.iostep > 0 ) {
  877:                 li->enbint = 0;
  878:                 DIS_TXRXINT(li);
  879:                 OutB(SC_MCTL, 0x00);
  880:         }
  881: }
  882: 
  883: /*
  884:  *      Start up the serial port
  885:  */
  886: LOCAL   void      ns16450_up( LINE_INFO *li )
  887: {
  888:         li->suspend = 0;
  889:         li->flow = li->scdefs.flow;
  890:         setHwConf(li, &li->scdefs.c, li->scdefs.mode, TRUE);
  891: }