📄 ns16550sio_x86.c
字号:
#endif /* if the CTS is asserted enable Tx interrupt */ if (mask & MSR_CTS) pChan->ier |= TxFIFO_BIT; /* enable Tx interrupt */ else pChan->ier &= (~TxFIFO_BIT); /* disable Tx interrupt */#if X86_16550 X86_REG_OUT(IER,pChan,pChan->ier);#else REG(IER, pChan) = pChan->ier; #endif } } else/*==SIO_MODE_POLL*/ { /* disable all ns16550 interrupts */ #if X86_16550 X86_REG_OUT(IER,pChan,0);#else REG(IER, pChan) = 0; #endif } pChan->channelMode = newMode; intUnlock (oldlevel); return (OK); }/********************************************************************************* ns16550Ioctl - special device control** Includes commands to get/set baud rate, mode(INT,POLL), hardware options(* parity, number of data bits), and modem control(RTS/CTS and DTR/DSR).* The ioctl command SIO_HUP is sent by ttyDrv when the last close() function * call is made. Likewise SIO_OPEN is sent when the first open() function call* is made.** RETURNS: OK on success, EIO on device error, ENOSYS on unsupported* request.*/LOCAL STATUS ns16550Ioctl ( NS16550_CHAN * pChan, /* pointer to channel */ int request, /* request code */ int arg /* some argument */ ) { FAST STATUS status; status = OK; switch (request) { case SIO_BAUD_SET: if (arg < NS16550_MIN_RATE || arg > NS16550_MAX_RATE) status = EIO; /* baud rate out of range */ else status = ns16550BaudSet (pChan, arg); break; case SIO_BAUD_GET: *(int *)arg = pChan->baudRate; break; case SIO_MODE_SET: status = (ns16550ModeSet (pChan, arg) == OK) ? OK : EIO; break; case SIO_MODE_GET: *(int *)arg = pChan->channelMode; break; case SIO_AVAIL_MODES_GET: *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL; break; case SIO_HW_OPTS_SET: status = (ns16550OptsSet (pChan, arg) == OK) ? OK : EIO; break; case SIO_HW_OPTS_GET: *(int *)arg = pChan->options; break; case SIO_HUP: /* check if hupcl option is enabled */ if (pChan->options & HUPCL) status = ns16550Hup (pChan); break; case SIO_OPEN: /* check if hupcl option is enabled */ if (pChan->options & HUPCL) status = ns16550Open (pChan); break; default: status = ENOSYS; } return (status); }/********************************************************************************* ns16550IntWr - handle a transmitter interrupt ** This routine handles write interrupts from the UART. It reads a character* and puts it in the transmit holding register of the device for transfer.** If there are no more characters to transmit, transmission is disabled by * clearing the transmit interrupt enable bit in the IER(int enable register).** RETURNS: N/A**/void ns16550IntWr ( NS16550_CHAN * pChan /* pointer to channel */ ) { char outChar; if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)#if X86_16550 X86_REG_OUT(THR,pChan,outChar);#else REG(THR,pChan) = outChar; /* write char to Transmit Holding Reg */#endif else { pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */#if X86_16550 X86_REG_OUT(IER,pChan,pChan->ier);#else REG(IER, pChan) = pChan->ier;#endif } }/********************************************************************************* ns16550IntRd - handle a receiver interrupt ** This routine handles read interrupts from the UART.** RETURNS: N/A**/void ns16550IntRd ( NS16550_CHAN * pChan /* pointer to channel */ ) { char inchar; /* read character from Receive Holding Reg. */#if X86_16550 inchar = X86_REG_IN(RBR,pChan);#else inchar = REG(RBR, pChan);#endif (*pChan->putRcvChar) (pChan->putRcvArg, inchar); }/********************************************************************************* ns16550IntEx - miscellaneous interrupt processing** This routine handles miscellaneous interrupts on the UART.* Not implemented yet.** RETURNS: N/A**/void ns16550IntEx ( NS16550_CHAN *pChan /* pointer to channel */ ) { /* Nothing for now... */ }/********************************************************************************** ns16550Int - interrupt level processing** This routine handles four sources of interrupts from the UART. They are* prioritized in the following order by the Interrupt Identification Register:* Receiver Line Status, Received Data Ready, Transmit Holding Register Empty* and Modem Status.** When a modem status interrupt occurs, the transmit interrupt is enabled if* the CTS signal is TRUE.** RETURNS: N/A**/void ns16550Int ( NS16550_CHAN * pChan /* pointer to channel */ ) { FAST volatile char intStatus; /* read the Interrrupt Status Register (Int. Ident.) */#if X86_16550 intStatus = (X86_REG_IN(IIR,pChan)) & 0x0f; X86_REG_OUT(IER,pChan,0);#else intStatus = (REG(IIR, pChan)) & 0x0f; /* * This UART chip always produces level active interrupts, and the IIR * only indicates the highest priority interrupt. * In the case that receive and transmit interrupts happened at * the same time, we must clear both interrupt pending to prevent * edge-triggered interrupt(output from interrupt controller) from locking * up. One way doing it is to disable all the interrupts at the beginning * of the ISR and enable at the end. */ REG(IER,pChan) = 0; /* disable interrupt */#endif switch (intStatus) { case IIR_RLS: /* overrun,parity error and break interrupt */#if X86_16550 intStatus = X86_REG_IN(LSR,pChan);#else intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */#endif break; case IIR_RDA: /* received data available */ case IIR_TIMEOUT: /* * receiver FIFO interrupt. In some case, IIR_RDA will * not be indicated in IIR register when there is more * than one character in FIFO. */ ns16550IntRd (pChan); /* RxChar Avail */ break; case IIR_THRE: /* transmitter holding register ready */ { char outChar; if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)#if X86_16550 X86_REG_OUT(THR,pChan,outChar);#else REG(THR, pChan) = outChar; /* char to Transmit Holding Reg */#endif else pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */ } break; case IIR_MSTAT: /* modem status register */ { char msr;#if X86_16550 msr = X86_REG_IN(MSR,pChan);#else msr = REG(MSR, pChan);#endif /* if CTS is asserted by modem, enable tx interrupt */ if ((msr & MSR_CTS) && (msr & MSR_DCTS)) pChan->ier |= TxFIFO_BIT; else pChan->ier &= (~TxFIFO_BIT); } break; default: break; }#if X86_16550 X86_REG_OUT(IER,pChan,pChan->ier);#else REG(IER, pChan) = pChan->ier; /* enable interrupts accordingly */#endif }/********************************************************************************* ns16550TxStartup - transmitter startup routine** Call interrupt level character output routine and enable interrupt if it is* in interrupt mode with no hardware flow control.* If the option for hardware flow control is enabled and CTS is set TRUE,* then the Tx interrupt is enabled.* * RETURNS: N/A*/LOCAL void ns16550TxStartup ( NS16550_CHAN * pChan /* pointer to channel */ ) { char mask; if (pChan->channelMode == SIO_MODE_INT) { if (pChan->options & CLOCAL) { /* No modem control */ pChan->ier |= TxFIFO_BIT;#if X86_16550 X86_REG_OUT(IER,pChan,pChan->ier);#else REG(IER,pChan) = pChan->ier; #endif } else {#if X86_16550 mask = X86_REG_IN(MSR, pChan) & MSR_CTS;#else mask = REG(MSR, pChan) & MSR_CTS;#endif /* if the CTS is asserted enable Tx interrupt */ if (mask & MSR_CTS) pChan->ier |= TxFIFO_BIT; /* enable Tx interrupt */ else pChan->ier &= (~TxFIFO_BIT); /* disable Tx interrupt */#if X86_16550 X86_REG_OUT(IER,pChan,pChan->ier);#else REG(IER, pChan) = pChan->ier; #endif } } }/******************************************************************************** ns16550PollOutput - output a character in polled mode.** RETURNS: OK if a character arrived, EIO on device error, EAGAIN* if the output buffer if full.*/LOCAL int ns16550PollOutput ( NS16550_CHAN * pChan, /* pointer to channel */ char outChar /* char to send */ ) {#if X86_16550 char pollStatus = X86_REG_IN(LSR,pChan); char msr = X86_REG_IN(MSR,pChan);#else char pollStatus = REG(LSR, pChan); char msr = REG(MSR, pChan);#endif /* is the transmitter ready to accept a character? */ if ((pollStatus & LSR_THRE) == 0x00) return (EAGAIN); if (!(pChan->options & CLOCAL)) /* modem flow control ? */ { if (msr & MSR_CTS)#if X86_16550 X86_REG_OUT(THR,pChan,outChar);#else REG(THR, pChan) = outChar;#endif else return (EAGAIN); } else#if X86_16550 X86_REG_OUT(THR,pChan,outChar);#else REG(THR, pChan) = outChar; /* transmit character */#endif return (OK); }/******************************************************************************** ns16550PollInput - poll the device for input.** RETURNS: OK if a character arrived, EIO on device error, EAGAIN* if the input buffer if empty.*/LOCAL int ns16550PollInput ( NS16550_CHAN * pChan, /* pointer to channel */ char * pChar /* pointer to char */ ) {#if X86_16550 char pollStatus = X86_REG_IN(LSR,pChan);#else char pollStatus = REG(LSR, pChan);#endif if ((pollStatus & LSR_DR) == 0x00) return (EAGAIN); /* got a character */#if X86_16550 *pChar = X86_REG_IN(RBR,pChan);#else *pChar = REG(RBR, pChan);#endif return (OK); }/******************************************************************************** ns16550CallbackInstall - install ISR callbacks to get/put chars.** This routine installs the callback functions for the driver** RETURNS: OK on success or ENOSYS on unsupported callback type.*/LOCAL int ns16550CallbackInstall ( SIO_CHAN * pSioChan, /* pointer to device to control */ int callbackType, /* callback type(tx or receive) */ STATUS (*callback)(), /* pointer to callback function */ void * callbackArg /* callback function argument */ ) { NS16550_CHAN * pChan = (NS16550_CHAN *)pSioChan; switch (callbackType) { case SIO_CALLBACK_GET_TX_CHAR: pChan->getTxChar = callback; pChan->getTxArg = callbackArg; return (OK); case SIO_CALLBACK_PUT_RCV_CHAR: pChan->putRcvChar = callback; pChan->putRcvArg = callbackArg; return (OK); default: return (ENOSYS); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -