📄 ns16550sio.c
字号:
if (pChan->options & CLOCAL) { REG(IER, pChan) = pChan->ier | RxFIFO_BIT; } else { mask = REG(MSR, pChan) & MSR_CTS; /* 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 */ REG(IER, pChan) = pChan->ier; } } else { /* disable all ns16550 interrupts */ REG(IER, pChan) = 0; } 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; UINT8 intStatus; if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR) REG(THR,pChan) = outChar; /* write char to Transmit Holding Reg */ else { pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */ REG(IER, pChan) = pChan->ier; } intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */ }/********************************************************************************* 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. */ inchar = REG(RBR, pChan); (*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.) */ intStatus = (REG(IIR, pChan)) & 0x0f; if(intStatus & IIR_IP) return ; intStatus = REG(LSR, pChan); if(intStatus & LSR_DR) ns16550IntRd (pChan); /* RxChar Avail */ if(intStatus & LSR_THRE) ns16550IntWr (pChan); /* RxChar Avail */ /*pxa_serial_write1(intStatus); */#if 0 /* * 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) &= ~(0x3); */ /* disable interrupt */ REG(IER,pChan) = 0; switch (intStatus) { case IIR_RLS: /* overrun,parity error and break interrupt */ intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */ 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) REG(THR, pChan) = outChar; /* char to Transmit Holding Reg */ else pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */ } intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */ break; case IIR_MSTAT: /* modem status register */ { char msr; msr = REG(MSR, pChan); /* 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; } REG(IER, pChan) = pChan->ier; /* enable interrupts accordingly */ #endif /* REG(IER, pChan) |= 0x3; */ }/********************************************************************************* 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: OK, or ENOSYS if in polled mode.*/LOCAL int ns16550TxStartup ( NS16550_CHAN * pChan /* pointer to channel */ ) { char mask; char outChar; if (pChan->channelMode == SIO_MODE_INT) { if (pChan->options & CLOCAL) { pChan->ier |= TxFIFO_BIT; REG(IER,pChan) = pChan->ier; /* No modem control */ } else { mask = REG(MSR, pChan) & MSR_CTS; /* 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 */ REG(IER, pChan) = pChan->ier; } return (OK); } else { if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR) ns16550PollOutput(pChan, outChar); /* return (ENOSYS); */ return (OK); } }/******************************************************************************** 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 */ ) { char pollStatus = REG(LSR, pChan); char msr = REG(MSR, pChan); /* 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) REG(THR, pChan) = outChar; else return (EAGAIN); } else REG(THR, pChan) = outChar; /* transmit character */ 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 */ ) { char pollStatus = REG(LSR, pChan); if ((pollStatus & LSR_DR) == 0x00) return (EAGAIN); /* got a character */ *pChar = REG(RBR, pChan); 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 + -