📄 p3544sio.c
字号:
* If polled mode is desired the device interrupts are disabled. ** RETURNS:* Returns a status of OK if the mode was set else ERROR.*/LOCAL STATUS p3544ModeSet ( p3544_CHAN * pChan, /* pointer to channel */ UINT newMode /* mode requested */ ) { FAST int oldlevel; /* current interrupt level mask */ char ier, mask; if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT)) return (ERROR); oldlevel = intLock(); if (newMode == SIO_MODE_POLL) ier = 0x00; else { if (pChan->options & CLOCAL) { ier = UART_IER_RDI; } else { mask = (PCI_IN_BYTE (pChan->msr)) & UART_MSR_CTS; /* if the CTS is asserted enable Tx interrupt */ if (mask & UART_MSR_CTS) { ier = (UART_IER_THRI | UART_IER_MSI); } else { ier = (UART_IER_MSI); } } } PCI_OUT_BYTE (pChan->ier, ier); pChan->channelMode = newMode; intUnlock(oldlevel); return (OK); }/********************************************************************************* p3544OptsSet ()- set the serial options** Set the channel operating mode to that specified. All sioLib options* are supported: CLOCAL, HUPCL, CREAD, CSIZE, PARENB, and PARODD.** RETURNS:* Returns OK to indicate success, otherwise ERROR is returned*/LOCAL STATUS p3544OptsSet ( p3544_CHAN * pChan, /* pointer to channel */ UINT options /* new hardware options */ ) { FAST int oldlevel; /* current interrupt level mask */ char lcr = 0; char mcr = UART_MCR_OUT2; char ier; char mask; ier = PCI_IN_BYTE (pChan->ier); if (pChan == NULL || options & 0xffffff00) return ERROR; switch (options & CSIZE) { case CS5: lcr = UART_LCR_WLEN5; break; case CS6: lcr = UART_LCR_WLEN6; break; case CS7: lcr = UART_LCR_WLEN7; break; default: case CS8: lcr = UART_LCR_WLEN8; break; } if (options & STOPB) lcr |= UART_LCR_STOP; else lcr |= 0; switch (options & (PARENB | PARODD)) { case PARENB|PARODD: lcr |= UART_LCR_PARITY; break; case PARENB: lcr |= (UART_LCR_PARITY | UART_LCR_EPAR); break; default: case 0: lcr |= 0; break; } PCI_OUT_BYTE (pChan->ier, 0x00); if (!(options & CLOCAL)) { /* !clocal enables hardware flow control(DTR/DSR) */ mcr |= (UART_MCR_DTR | UART_MCR_RTS); ier |= UART_IER_MSI; /* enable modem status interrupt */ mask = (PCI_IN_BYTE (pChan->msr)) & UART_MSR_CTS; /* if the CTS is asserted enable Tx interrupt */ if (mask & UART_MSR_CTS) ier |= UART_IER_THRI; else ier &= (~UART_IER_THRI); } else ier &= ~UART_IER_MSI; /* disable modem status interrupt */ oldlevel = intLock (); PCI_OUT_BYTE (pChan->lcr, lcr| UART_LCR_DLAB); PCI_OUT_BYTE (pChan->mcr, mcr); /* now clear the port */ PCI_IN_BYTE (pChan->data); if (options & CREAD) ier |= UART_IER_RDI; if (pChan->channelMode == SIO_MODE_INT) { PCI_OUT_BYTE (pChan->ier, ier); } intUnlock (oldlevel); pChan->options = options; return OK; }/********************************************************************************* p3544Ioctl ( ) - 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 commands SIO_HUP and SIO_OPEN are implemented to provide the * HUPCL( hang up on last close) function.** RETURNS: OK on success, EIO on device error, ENOSYS on unsupported* request.*/static int p3544Ioctl ( p3544_CHAN * pChan, /* device to control */ int request, /* request code */ int arg /* some argument */ ) { int ix; int baudH; int baudL; int oldlevel; UINT8 lcr; int status = OK; switch (request) { case SIO_BAUD_SET: status = (p3544BaudSet(pChan, arg) == OK) ? OK : EIO; break; case SIO_BAUD_GET: oldlevel = intLock(); status = EIO; lcr = PCI_IN_BYTE (pChan->lcr); PCI_OUT_BYTE (pChan->lcr, (char)(UART_LCR_DLAB | lcr)); baudH = PCI_IN_BYTE(pChan->dlm); baudL = PCI_IN_BYTE(pChan->dll); PCI_OUT_BYTE (pChan->lcr, lcr); for (ix = 0; ix < NELEMENTS (p3544baudTable); ix++) { if ( baudH == MSB (p3544baudTable[ix].preset) && baudL == LSB (p3544baudTable[ix].preset) ) { *(int *)arg = p3544baudTable[ix].rate; status = OK; } } intUnlock(oldlevel); break; case SIO_MODE_SET: status = (p3544ModeSet (pChan, arg) == OK) ? OK : EIO; break; case SIO_MODE_GET: *(int *)arg = pChan->channelMode; return (OK); case SIO_AVAIL_MODES_GET: *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL; return (OK); case SIO_HW_OPTS_SET: status = (p3544OptsSet (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 = p3544Hup (pChan); break; case SIO_OPEN: /* check if hupcl option is enabled */ if (pChan->options & HUPCL) status = p3544Open (pChan); break; default: status = ENOSYS; break; } return (status); }/********************************************************************************/void st1655xIntRd ( p3544_CHAN * pChan /* ptr to struct describing channel */ ) { char inchar; UINT32 status=0; do { if (pChan->putRcvChar != NULL) { unsigned char temp = PCI_IN_BYTE (pChan->data); (*pChan->putRcvChar)(pChan->putRcvArg, temp); } else PCI_IN_BYTE (pChan->data); status = PCI_IN_BYTE ( pChan->lsr ); } while (status & 0x01) ; return; }/********************************************************************************* p3544Int () - handle a receiver/transmitter interrupt** This routine handles four sources of interrupts from the UART. If there is* another character to be transmitted, the character is sent. When a modem* status interrupt occurs, the transmit interrupt is enabled if the CTS signal* is TRUE.** INTERNAL* The UART interrupts are prioritized in the following order by the Interrupt* Identification Register:** Bit 2 bit 1 bit 0 Priority Interrupt ID* -------------------------------------------------------* 0 0 1 none none* 1 1 0 0 serialization error or BREAK* 1 0 0 1 received data* 0 1 0 2 transmitter buffer empty* 0 0 0 3 RS-232 input** In the table, priority level 0 is the highest priority. These priorities* are not typically configurable via software. The interrupt is expressed as* a two-bit integer. Bit 0, the pending bit, is negative logic - a value 0* means that an interrupt is pending.** When nested interrupts occur, the second interrupt is identified in the* Interrupt Identification Register(IIR) as soon as the first interrupt is* cleared. Therefore, the interrupt service routine must continue to read IIR* until bit-0 is 1.** When the 3544 generates an interrupt, all interrupts with an equal or* lower priority are locked out until the current interrupt has been cleared.* The operation required to clear an interrupt varies according to the source.* The actions typically required to clear an interrupt are as follows:** Source of interrupt Response required to reset* ---------------------------------------------------------------------* receiver error or BREAK read serialization status register* received data read data from receiver register* transmit buffer empty write to the transmitter or read* the interrupt ID register* RS-232 input read the RS-232 status register** In response to an empty transmit buffer (TBE), the interrupt can be* cleared by writing a byte to the transmitter buffer register. It can* also be cleared by reading the interrupt identification register.** Failure to clear all interrupts before returning will leave an interrupt* pending and prevent the UART from generating further interrupt requests* to the CPU.** RETURNS: N/A*/void p3544Int ( p3544_CHAN * pChan ) { char outChar; /* store a byte for transmission */ char interruptID; /* store contents of interrupt ID register */ char lineStatus; /* store contents of line status register */ char ier; /* store contents of interrupt enable register */ int ix = 0; /* allows us to return just in case IP never clears */ int i; for (i = 0; i < 4; i++) { ier = PCI_IN_BYTE(pChan->ier); /* service UART interrupts until IP bit set or read counter expires */ FOREVER { interruptID = PCI_IN_BYTE(pChan->iir); if ((interruptID == UART_IIR_NO_INT) || (++ix > p3544_IIR_READ_MAX)) { break; /* interrupt cleared or loop counter expired */ } /* filter possible anomalous interrupt ID from PC87307VUL (SPR 26117) */ interruptID &= UART_IIR_ID; /* clear odd-bit to find interrupt ID */ if (interruptID == UART_IIR_RLSI) { lineStatus = PCI_IN_BYTE (pChan->lsr); } else if (interruptID == UART_IIR_RDI) { st1655xIntRd (pChan); /* at least one RxChar available */#if 0 if (pChan->putRcvChar != NULL) (*pChan->putRcvChar)(pChan->putRcvArg, PCI_IN_BYTE (pChan->data)); else PCI_IN_BYTE (pChan->data);#endif } else if (interruptID == UART_IIR_THRI) { if ((pChan->getTxChar != NULL) && (*pChan->getTxChar) (pChan->getTxArg, &outChar) == OK ) { PCI_OUT_BYTE(pChan->data, outChar); } /* There are no bytes available for transmission. Reading * the IIR at the top of this loop will clear the interrupt. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -