?? i82550sio.c
字號:
* TODO - Typically, acknowledge the interrupt as soon as possible. * Usually before passing data or error conditions upstream. */ I82550_SIO_WRITE8(pChan, I82550_CSR_ID, I82550_RESET_INT); /* ack interrupt*/ if (status == ERROR) { /* send error notification upstream */ (*pChan->errorRtn) (pChan->errorArg, SIO_ERROR_UNKNWN, NULL, 0); } else { /* send data character upstream */ (*pChan->putRcvChar) (pChan->putRcvArg, inChar); } }/******************************************************************************** i82550SioIntTx - handle a channels transmitter-ready interrupt** RETURNS: N/A*/ LOCAL void i82550SioIntTx ( I82550_CHAN * pChan /* channel generating the interrupt */ ) { char outChar; char crData = 0; BOOL txReady = TRUE; int errorCode = SIO_ERROR_NONE; /* * TODO - Check the Tx status * * For PCI devices, do an immediate return if device is not asserting * an interrupt. */ I82550_PIPE_FLUSH(pChan); I82550_SIO_READ8(pChan, I82550_CSR_ID, &crData); /* TODO - Check for error conditions */ if (crData & I82550_CR_TX_ERROR) { /* * TODO - Typically you should determine the precise error condition * and perform all recovery operations here. */ I82550_SIO_WRITE8 (pChan, I82550_CSR_ID, I82550_RESET_TX); errorCode = SIO_ERROR_UNKNWN; txReady = TRUE; /* set to false if xmitter is not ready now */ } /* * If transmitter is okay and ready to send, lets see if there is a * data character ready to be sent. * * If there's a character to transmit then write it out, else reset (idle) * the transmitter. For chips with output FIFO's it is more efficient * to fill the entire FIFO here. */ if (txReady) { if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR) { /* TODO - Output data to device. */ I82550_SIO_WRITE8(pChan, I82550_DATA_ID, outChar); /* * TODO - If a device error occurs at this point, then * isolate the precise error type and try to recover. */ } else { /* * TODO - There is no more data to send. * * Put XMTR in an idle state. Higher layer * will call TxStartup entry to resume xmit operations. */ I82550_SIO_WRITE8(pChan, I82550_CSR_ID, I82550_RESET_TX); } } /* * TODO - If needed, you should acknowledge or reset the interrupt source * as soon as possible, usually before passing any error conditions * upstream. */ I82550_SIO_WRITE8(pChan, I82550_CSR_ID, I82550_RESET_INT); /* Pass any errorCodes upstream. */ if (errorCode != SIO_ERROR_NONE) { (*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0); } }/******************************************************************************** i82550SioIntErr - handle a channels error interrupt** RETURNS: N/A*/ LOCAL void i82550SioIntErr ( I82550_CHAN * pChan /* channel generating the interrupt */ ) { int errorCode = SIO_ERROR_NONE; char controlReg; I82550_PIPE_FLUSH(pChan); I82550_SIO_READ8 (pChan, I82550_CSR_ID, &controlReg); /* * TODO - Determine the precise error condition and perform recovery * operations. * * For PCI devices, do an immediate return if device is not asserting * an interrupt. */ /* * TODO - If needed, you should acknowledge or reset the interrupt source * as soon as possible, usually before passing any error conditions * upstream. */ I82550_SIO_WRITE8(pChan, I82550_CSR_ID, I82550_RESET_INT); if (errorCode != SIO_ERROR_NONE) (*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0); }/******************************************************************************** i82550TxStartup - start the interrupt transmitter** This routine exits to inform the device to start transmitting data again.* The actual data will be obtained by calling the TxCharGet callback routine.** This routine is usually just the same as the tx interrupt routine. This* routine runs at task level context and does not have to be interrupt safe.** RETURNS: OK on success, ENOSYS if the device is polled-only, or* EIO on hardware error.*/LOCAL int i82550TxStartup ( SIO_CHAN * pSioChan /* channel to start */ ) { I82550_CHAN * pChan = (I82550_CHAN *)pSioChan; /* This routine should only be called while in interrupt mode */ if (pChan->mode == SIO_MODE_INT) { if (pChan->options & CLOCAL) { /* TODO - No modem control - start immediately */ } else { /* * TODO - Modem controls are active. * * If CTS is high, we can start immediately so just enable * the TX interrupt. * * If CTS is low, then we cannot send now. The driver * should be set up to generate a TX interrupt when the CTS * line returns to the active state. */ } /* * TODO - Enable the correct interrupts. A TX interrupt should either * occur immediately, or later when CTS becomes active. That will start * the flow of data. * * There are two usual methods here. The first is to just enable * TX interrupts, which should cause an immediate TX interrupt, which * will begin fetching and sending characters. * * The second method is to call the getTxChara callback here, put * the data to the transmitter directly, and then to enable TX * interrupts to fetch and send additional characters. */ I82550_SIO_WRITE8(pChan, I82550_CSR_ID, I82550_TX_ENABLE); } else return ENOSYS; /* Not valid for polled mode operation */ return (OK); }/******************************************************************************** i82550CallbackInstall - install ISR callbacks to get/put chars** This driver allows interrupt callbacks for transmitting characters* and receiving characters. In general, drivers may support other* types of callbacks too.** RETURNS: OK on success, or ENOSYS for an unsupported callback type.*/ LOCAL int i82550CallbackInstall ( SIO_CHAN * pSioChan, /* channel */ int callbackType, /* type of callback */ STATUS (*callback)(void *,...), /* callback */ void * callbackArg /* parameter to callback */ ) { I82550_CHAN * pChan = (I82550_CHAN *)pSioChan; switch (callbackType) { case SIO_CALLBACK_GET_TX_CHAR: pChan->getTxChar = (STATUS (*)(void *, char *))callback; pChan->getTxArg = callbackArg; return (OK); case SIO_CALLBACK_PUT_RCV_CHAR: pChan->putRcvChar = (void (*)(void *, char))callback; pChan->putRcvArg = callbackArg; return (OK); case SIO_CALLBACK_ERROR: pChan->errorRtn = (void (*)(void *, int, void *, int))callback; pChan->errorArg = callbackArg; return (OK); default: return (ENOSYS); } }/********************************************************************************* i82550PollOutput - output a character in polled mode** Polled mode operation takes place without any kernel or other OS* services available. Use extreme care to insure that this code does not* call any kernel services. Polled mode is only for WDB system mode use.* Kernel services, semaphores, tasks, etc, are not available during WDB* system mode.** RETURNS: OK if a character arrived, EIO on device error, EAGAIN* if the output buffer if full. ENOSYS if the device is* interrupt-only.*/LOCAL int i82550PollOutput ( SIO_CHAN * pSioChan, char outChar ) { I82550_CHAN * pChan = (I82550_CHAN *)pSioChan; UINT8 status; /* is the transmitter ready to accept a character? */ I82550_PIPE_FLUSH(pChan); I82550_SIO_READ8(pChan, I82550_CSR_ID, &status); /* TODO - determine if transmitter is ready */ if ((status & I82550_CR_TX_READY) == 0x00) { /* device is busy, try again later */ return (EAGAIN); } /* TODO - Check for TX errors */ if (status & I82550_CR_TX_ERROR) { /* TODO - decode specific error condition and handle it */ /* Do not make error callback, just return EIO */ return EIO; } else { /* TODO - transmit the character */ I82550_SIO_WRITE8(pChan, I82550_DATA_ID, outChar); } return (OK); }/******************************************************************************** i82550PollInput - poll the device for input** Polled mode operation takes place without any kernel or other OS* services available. Use extreme care to insure that this code does not* call any kernel services. Polled mode is only for WDB system mode use.* Kernel services, semaphores, tasks, etc, are not available during WDB* system mode.** RETURNS: OK if a character arrived, EIO on device error, EAGAIN* if the input buffer if empty, ENOSYS if the device is* interrupt-only.*/LOCAL int i82550PollInput ( SIO_CHAN * pSioChan, char * thisChar ) { I82550_CHAN * pChan = (I82550_CHAN *)pSioChan; UINT8 status; /* Read RX device status */ I82550_PIPE_FLUSH(pChan); I82550_SIO_READ8(pChan, I82550_CSR_ID, &status); /* TODO - Check if receive data is available */ if ((status & I82550_CR_RX_AVAIL) == 0x00) { return EAGAIN; /* no input available at this time */ } /* TODO - Check for receive error conditions */ if (status & I82550_CR_RX_ERROR) { /* TODO - Decode and handle the specific error condition */ /* Do NOT call the error callback routine, just return EIO */ return EIO; } /* TODO - read character, store it, and return OK */ I82550_SIO_READ8(pChan, I82550_DATA_ID, thisChar); return (OK); }/******************************************************************************** i82550ModeSet - toggle between interrupt and polled mode** RETURNS: OK on success, EIO on unsupported mode.*/LOCAL int i82550ModeSet ( I82550_CHAN * pChan, /* channel */ uint_t newMode /* new mode */ ) { UINT8 temp; if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT)) return (EIO); I82550_PIPE_FLUSH(pChan); if (pChan->mode == SIO_MODE_INT) { /* TODO - switch device to interrupt mode */ if (pChan->intConnect == FALSE) { I82550_SIO_INT_CONNECT(pChan,I82550_RXINT_ID, i82550SioIntRcv, (void *)pChan); I82550_SIO_INT_CONNECT(pChan, I82550_TXINT_ID, i82550SioIntTx, (void *)pChan); I82550_SIO_INT_CONNECT(pChan, I82550_ERRINT_ID, i82550SioIntErr, (void *)pChan); pChan->intConnect = TRUE; } I82550_SIO_READ8(pChan, I82550_CSR_ID, &temp); temp |= I82550_INT_ENABLE; I82550_SIO_WRITE8(pChan, I82550_CSR_ID, temp); } else { /* TODO - switch device to polled mode */ I82550_SIO_READ8(pChan, I82550_CSR_ID, &temp); temp &= ~I82550_INT_ENABLE; I82550_SIO_WRITE8(pChan, I82550_CSR_ID, temp); } /* activate the new mode */ pChan->mode = newMode; return (OK); }/********************************************************************************* i82550Hup - hang up the modem control lines ** Resets the RTS and DTR signals.** RETURNS: OK always.*/LOCAL STATUS i82550Hup ( I82550_CHAN * pChan /* pointer to channel */ ) { /* * TODO - Use global intLock if lockout time will be very short. If not, * use a device specific lockout that will not damage overall system * latency. */ i82550MstatSetClr (pChan,(SIO_MODEM_RTS|SIO_MODEM_DTR), FALSE); return (OK); } /********************************************************************************* i82550Open - Set the modem control lines ** Set the modem control lines(RTS, DTR) TRUE if not already set. ** RETURNS: OK*/LOCAL STATUS i82550Open ( I82550_CHAN * pChan /* pointer to channel */ ) { /* * TODO - Use global intLock if lockout time will be very short. If not, * use a device specific lockout that will not damage overall system * latency. */ i82550MstatSetClr (pChan, (SIO_MODEM_RTS|SIO_MODEM_DTR), TRUE); return (OK); }/******************************************************************************** i82550OptSet - set hardware options** This routine sets up the hardware according to the specified option* argument. If the hardware cannot support a particular option value, then* it should ignore that portion of the request.** RETURNS: OK upon success, or EIO for invalid arguments.*/LOCAL int i82550OptSet ( I82550_CHAN * pChan, /* channel */ uint_t newOpts /* new options */ ) { int dataBits = 8; int stopBits = 1; BOOL hdweFlowCtrl=TRUE; BOOL rcvrEnable = TRUE; int lvl; if (pChan == NULL || newOpts & 0xffffff00) return EIO; /* do nothing if options already set */ if (pChan->options == newOpts) return OK; /* ignore requests for unsupported options */ /* decode individual request elements */ switch (newOpts & CSIZE) { case CS5: dataBits = 5; break; case CS6: dataBits = 6; break; case CS7: dataBits = 7; break; default: case CS8: dataBits = 8; break; } if (newOpts & STOPB) stopBits = 2; else stopBits = 1; switch (newOpts & (PARENB|PARODD)) { case PARENB|PARODD: /* enable odd parity */ break;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -