📄 i2ellis.c
字号:
/********************************************************************************* (c) 1998 by Computone Corporation************************************************************************************ PACKAGE: Linux tty Device Driver for IntelliPort family of multiport* serial I/O controllers.** DESCRIPTION: Low-level interface code for the device driver* (This is included source code, not a separate compilation* module.)********************************************************************************///---------------------------------------------// Function declarations private to this module//---------------------------------------------// Functions called only indirectly through i2eBordStr entries.static int iiWriteBuf16(i2eBordStrPtr, unsigned char *, int);static int iiWriteBuf8(i2eBordStrPtr, unsigned char *, int);static int iiReadBuf16(i2eBordStrPtr, unsigned char *, int);static int iiReadBuf8(i2eBordStrPtr, unsigned char *, int);static unsigned short iiReadWord16(i2eBordStrPtr);static unsigned short iiReadWord8(i2eBordStrPtr);static void iiWriteWord16(i2eBordStrPtr, unsigned short);static void iiWriteWord8(i2eBordStrPtr, unsigned short);static int iiWaitForTxEmptyII(i2eBordStrPtr, int);static int iiWaitForTxEmptyIIEX(i2eBordStrPtr, int);static int iiTxMailEmptyII(i2eBordStrPtr);static int iiTxMailEmptyIIEX(i2eBordStrPtr);static int iiTrySendMailII(i2eBordStrPtr, unsigned char);static int iiTrySendMailIIEX(i2eBordStrPtr, unsigned char);static unsigned short iiGetMailII(i2eBordStrPtr);static unsigned short iiGetMailIIEX(i2eBordStrPtr);static void iiEnableMailIrqII(i2eBordStrPtr);static void iiEnableMailIrqIIEX(i2eBordStrPtr);static void iiWriteMaskII(i2eBordStrPtr, unsigned char);static void iiWriteMaskIIEX(i2eBordStrPtr, unsigned char);static void ii2DelayTimer(unsigned int);static void ii2DelayWakeup(unsigned long id);static void ii2Nop(void);//***************//* Static Data *//***************static int ii2Safe; // Safe I/O address for delay routinestatic int iiDelayed; // Set when the iiResetDelay function is // called. Cleared when ANY board is reset.static struct timer_list * pDelayTimer; // Used by iiDelayTimerstatic wait_queue_head_t pDelayWait; // Used by iiDelayTimerstatic rwlock_t Dl_spinlock;//********//* Code *//********//=======================================================// Initialization Routines//// iiSetAddress// iiReset// iiResetDelay// iiInitialize//=======================================================//******************************************************************************// Function: iiEllisInit()// Parameters: None//// Returns: Nothing//// Description://// This routine performs any required initialization of the iiEllis subsystem.////******************************************************************************static voidiiEllisInit(void){ pDelayTimer = kmalloc ( sizeof (struct timer_list), GFP_KERNEL ); init_timer(pDelayTimer); init_waitqueue_head(&pDelayWait); LOCK_INIT(&Dl_spinlock);}//******************************************************************************// Function: iiEllisCleanup()// Parameters: None//// Returns: Nothing//// Description://// This routine performs any required cleanup of the iiEllis subsystem.////******************************************************************************static voidiiEllisCleanup(void){ kfree(pDelayTimer);}//******************************************************************************// Function: iiSetAddress(pB, address, delay)// Parameters: pB - pointer to the board structure// address - the purported I/O address of the board// delay - pointer to the 1-ms delay function to use// in this and any future operations to this board//// Returns: True if everything appears copacetic.// False if there is any error: the pB->i2eError field has the error//// Description://// This routine (roughly) checks for address validity, sets the i2eValid OK and// sets the state to II_STATE_COLD which means that we haven't even sent a reset// yet.////******************************************************************************static intiiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay ){ // Should any failure occur before init is finished... pB->i2eValid = I2E_INCOMPLETE; // Cannot check upper limit except extremely: Might be microchannel // Address must be on an 8-byte boundary if ((unsigned int)address <= 0x100 || (unsigned int)address >= 0xfff8 || (address & 0x7) ) { COMPLETE(pB,I2EE_BADADDR); } // Initialize accelerators pB->i2eBase = address; pB->i2eData = address + FIFO_DATA; pB->i2eStatus = address + FIFO_STATUS; pB->i2ePointer = address + FIFO_PTR; pB->i2eXMail = address + FIFO_MAIL; pB->i2eXMask = address + FIFO_MASK; // Initialize i/o address for ii2DelayIO ii2Safe = address + FIFO_NOP; // Initialize the delay routine pB->i2eDelay = ((delay != (delayFunc_t)NULL) ? delay : (delayFunc_t)ii2Nop); pB->i2eValid = I2E_MAGIC; pB->i2eState = II_STATE_COLD; COMPLETE(pB, I2EE_GOOD);}//******************************************************************************// Function: iiReset(pB)// Parameters: pB - pointer to the board structure//// Returns: True if everything appears copacetic.// False if there is any error: the pB->i2eError field has the error//// Description://// Attempts to reset the board (see also i2hw.h). Normally, we would use this to// reset a board immediately after iiSetAddress(), but it is valid to reset a// board from any state, say, in order to change or re-load loadware. (Under// such circumstances, no reason to re-run iiSetAddress(), which is why it is a// separate routine and not included in this routine.////******************************************************************************static intiiReset(i2eBordStrPtr pB){ // Magic number should be set, else even the address is suspect if (pB->i2eValid != I2E_MAGIC) { COMPLETE(pB, I2EE_BADMAGIC); } OUTB(pB->i2eBase + FIFO_RESET, 0); // Any data will do iiDelay(pB, 50); // Pause between resets OUTB(pB->i2eBase + FIFO_RESET, 0); // Second reset // We must wait before even attempting to read anything from the FIFO: the // board's P.O.S.T may actually attempt to read and write its end of the // FIFO in order to check flags, loop back (where supported), etc. On // completion of this testing it would reset the FIFO, and on completion // of all // P.O.S.T., write the message. We must not mistake data which // might have been sent for testing as part of the reset message. To // better utilize time, say, when resetting several boards, we allow the // delay to be performed externally; in this way the caller can reset // several boards, delay a single time, then call the initialization // routine for all. pB->i2eState = II_STATE_RESET; iiDelayed = 0; // i.e., the delay routine hasn't been called since the most // recent reset. // Ensure anything which would have been of use to standard loadware is // blanked out, since board has now forgotten everything!. pB->i2eUsingIrq = IRQ_UNDEFINED; // Not set up to use an interrupt yet pB->i2eWaitingForEmptyFifo = 0; pB->i2eOutMailWaiting = 0; pB->i2eChannelPtr = NULL; pB->i2eChannelCnt = 0; pB->i2eLeadoffWord[0] = 0; pB->i2eFifoInInts = 0; pB->i2eFifoOutInts = 0; pB->i2eFatalTrap = NULL; pB->i2eFatal = 0; COMPLETE(pB, I2EE_GOOD);}//******************************************************************************// Function: iiResetDelay(pB)// Parameters: pB - pointer to the board structure//// Returns: True if everything appears copacetic.// False if there is any error: the pB->i2eError field has the error//// Description://// Using the delay defined in board structure, waits two seconds (for board to// reset).////******************************************************************************static intiiResetDelay(i2eBordStrPtr pB){ if (pB->i2eValid != I2E_MAGIC) { COMPLETE(pB, I2EE_BADMAGIC); } if (pB->i2eState != II_STATE_RESET) { COMPLETE(pB, I2EE_BADSTATE); } iiDelay(pB,2000); /* Now we wait for two seconds. */ iiDelayed = 1; /* Delay has been called: ok to initialize */ COMPLETE(pB, I2EE_GOOD);}//******************************************************************************// Function: iiInitialize(pB)// Parameters: pB - pointer to the board structure//// Returns: True if everything appears copacetic.// False if there is any error: the pB->i2eError field has the error//// Description://// Attempts to read the Power-on reset message. Initializes any remaining fields// in the pB structure.//// This should be called as the third step of a process beginning with// iiReset(), then iiResetDelay(). This routine checks to see that the structure// is "valid" and in the reset state, also confirms that the delay routine has// been called since the latest reset (to any board! overly strong!).////******************************************************************************static intiiInitialize(i2eBordStrPtr pB){ int itemp; unsigned char c; unsigned short utemp; unsigned int ilimit; if (pB->i2eValid != I2E_MAGIC) { COMPLETE(pB, I2EE_BADMAGIC); } if (pB->i2eState != II_STATE_RESET || !iiDelayed) { COMPLETE(pB, I2EE_BADSTATE); } // In case there is a failure short of our completely reading the power-up // message. pB->i2eValid = I2E_INCOMPLETE; // Now attempt to read the message. for (itemp = 0; itemp < sizeof(porStr); itemp++) { // We expect the entire message is ready. if (HAS_NO_INPUT(pB)) { pB->i2ePomSize = itemp; COMPLETE(pB, I2EE_PORM_SHORT); } pB->i2ePom.c[itemp] = c = BYTE_FROM(pB); // We check the magic numbers as soon as they are supposed to be read // (rather than after) to minimize effect of reading something we // already suspect can't be "us". if ( (itemp == POR_1_INDEX && c != POR_MAGIC_1) || (itemp == POR_2_INDEX && c != POR_MAGIC_2)) { pB->i2ePomSize = itemp+1; COMPLETE(pB, I2EE_BADMAGIC); } } pB->i2ePomSize = itemp; // Ensure that this was all the data... if (HAS_INPUT(pB)) COMPLETE(pB, I2EE_PORM_LONG); // For now, we'll fail to initialize if P.O.S.T reports bad chip mapper: // Implying we will not be able to download any code either: That's ok: the // condition is pretty explicit. if (pB->i2ePom.e.porDiag1 & POR_BAD_MAPPER) { COMPLETE(pB, I2EE_POSTERR); } // Determine anything which must be done differently depending on the family // of boards! switch (pB->i2ePom.e.porID & POR_ID_FAMILY) { case POR_ID_FII: // IntelliPort-II pB->i2eFifoStyle = FIFO_II; pB->i2eFifoSize = 512; // 512 bytes, always pB->i2eDataWidth16 = NO; pB->i2eMaxIrq = 15; // Because board cannot tell us it is in an 8-bit // slot, we do allow it to be done (documentation!) pB->i2eGoodMap[1] = pB->i2eGoodMap[2] = pB->i2eGoodMap[3] = pB->i2eChannelMap[1] = pB->i2eChannelMap[2] = pB->i2eChannelMap[3] = 0; switch (pB->i2ePom.e.porID & POR_ID_SIZE) { case POR_ID_II_4: pB->i2eGoodMap[0] = pB->i2eChannelMap[0] = 0x0f; // four-port // Since porPorts1 is based on the Hardware ID register, the numbers // should always be consistent for IntelliPort-II. Ditto below... if (pB->i2ePom.e.porPorts1 != 4) { COMPLETE(pB, I2EE_INCONSIST); } break; case POR_ID_II_8: case POR_ID_II_8R: pB->i2eGoodMap[0] = pB->i2eChannelMap[0] = 0xff; // Eight port
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -