?? i82550sio.c
字號:
/* i82550Sio.c - i82550 serial driver *//* Copyright 1984-2002 Wind River Systems, Inc. *//*TODO - Remove the i82550 modification history and begin a new historystarting with version 01a and growing the history upward witheach revision.modification history--------------------01o,30may02,dat mismatch argument warning from diab01n,05apr02,dat Poll mode cannot make any callbacks01m,08dec01,dat compiler warnings01l,24sep01,dat Update for new IOCTL codes/callbacks, new adaptor type macros01k,07mar01,dat 36080, new driver components, renamed I82550_REG_READ/WRITE to be I82550_READ/WRITE01j,11may98,dat change Open/Hup handling slightly. SPR 2119801i,23sep97,dat added I82550_REG_READ, I82550_REG_WRITE01h,10sep97,dat added opt declarations for SIO_HUP, SIO_OPEN01g,10aug97,dat fixed bugs in ver 01f01f,01jul97,db added ioctl commands used in modem control(SPR 7637,1037).01e,16apr97,dat fixed baud rate calc for SIO_BAUD_GET, SPR 8405.01d,06mar97,dat doc cleanup01c,16dec96,dat added i82550OptSet() hardware options i8255001b,16oct96,dat added i82550DevInit2(), and i82550IntrMode variable.01a,01aug95,ms written.*//*.SH TODO - Replace the documentation for this i82550 driver with documentationfor the driver being written. - Begin with an overview of the complete device. Indicate if the new driveronly implements a sub-section of the whole device or not. - Describe all of the operating modes of the device, and indicate whichones this driver implements. - Document the device initialization steps to be used in the BSP to createand initialize the device. Document all the macros thatcan be used to customize the driver to a particular hardware environment. - Document anything that will help the user to understand how this deviceworks and interacts with this driver..SH I82550 OVERVIEWThis is a i82550 serial driver. It can be used as a starting pointwhen writing new drivers for VxWorks version 5.4 or later.These drivers support new functionality not found in the older styleserial drivers. First, they provide an interface for setting hardwareoptions; e.g., the number of stop bits, data bits, parity, etc.Second, they provide an interface for polled communication whichcan be used to provided external mode debugging (i.e., ROM monitorstyle debugging) over a serial line. Currently only asynchronous modedrivers are supported.Throughout this file the word "i82550" is used in place of a realdevice name, which by convention uses the first letter of themanufacturers name followed by the part number. For example, theZilog 8530 serial device would have a data structure called aZ8530_CHAN, rather than I82550_CHAN..SH CALLBACKSServicing a "transmitter ready" interrupt involves making a callback to ahigher level library in order to get a character to transmit.By default, this driver installs dummy callback routines which donothing. A higher layer library that wants to use this driver (e.g., ttyDrv)will install its own callback routines using the SIO_INSTALL_CALLBACKioctl command. (See below).The prototype for the transmit data callback SIO_CALLBACK_GET_TX_CHAR is:.CS int sioTxCharGet ( void * arg, /@ callback argument @/ char * pChar /@ ptr to data location @/ ).CEThis callback routine should fetch the next character to send and store itin the location pointed to by pChar. It returns OK to indicate that acharacter is ready and should be sent. It returns ERROR to indicate thatno character was available and the transmitter can be placed in an idle state.Likewise, a receiver interrupt handler makes a callback to pass thecharacter to the higher layer library. It will be called by the driverfor each character received. This routine should capture the data and passit along to other layers and eventually to the user.The prototype for the receive data callback SIO_CALLBACK_PUT_RCV_CHAR is:.CS void sioRxCharPut ( void * arg, /@ callback argument @/ char data /@ data byte @/ ).CEA new error handling callback has been added SIO_CALLBACK_ERROR. This drivershould use this callback to inform the higher layer about error conditions.The prototype for this callback is:.CS void sioErrorRtn ( void * arg, /@ callback argument @/ int code, /@ error code @/ void * pData, /@ opt dev specific data @/ int dataSize /@ opt size of data in bytes @/ ).CEThe available error codes for this callback are:.CS SIO_ERROR_FRAMING /@ (1) Framing error @/ SIO_ERROR_PARITY /@ (2) Parity error @/ SIO_ERROR_OFLOW /@ (3) data overflow @/ SIO_ERROR_UFLOW /@ (4) data underflow @/ SIO_ERROR_CONNECT /@ (5) connection made @/ SIO_ERROR_DISCONNECT /@ (6) connection lost @/ SIO_ERROR_NO_CLK /@ (7) clock lost @/ SIO_ERROR_UNKNWN /@ (8) other errors @/.CEFor engineering purposes, the driver may return device specific data inthe form of a data buffer. The argument pData is the location of the bufferand dataSize is its size, in bytes. The data is not guaranteed to be staticso it should be copied to a static buffer for safekeeping..SH MODESIdeally the driver should support both polled and interrupt modes, and becapable of switching modes dynamically. However this is not required.VxWorks will be able to support a tty device on this driver even ifthe driver only supports interrupt mode.Polled mode is provided solely for WDB system mode usage. Users can usethe polled mode interface directly, but there is no clear reason for doing so.Normal access to SIO devices through ttyDrv only uses interrupt mode.For dynamically switchable drivers, be aware that the driver may beasked to switch modes in the middle of its input ISR. A driver's input ISRwill look something like this: inChar = *pDev->dr; /@ read a char from data register @/ *pDev->cr = GOT_IT; /@ acknowledge the interrupt @/ pDev->putRcvChar (...); /@ give the character to the higher layer @/If this channel is used as a communication path to an external modedebug agent, and if the character received is a special "end of packet"character, then the agent's callback will lock interrupts, switchthe device to polled mode, and use the device in polled mode for awhile.Later on the agent will unlock interrupts, switch the device back tointerrupt mode, and return to the ISR.In particular, the callback can cause two mode switches, first to polled modeand then back to interrupt mode, before it returns.This may require careful ordering of the callback within the interrupthandler. For example, you may need to acknowledge the interrupt beforeinvoking the callback..SH USAGEThe driver is typically called only by the BSP. The directly callableroutines in this module are i82550SioCreate(), i82550SioDestroy()..SH BSPBy convention all the BSP-specific serial initialization is performed ina file called sysSerial.c, which is #include'ed by sysLib.c.This driver can be customized by redefining the macros SYS_SIO_READ8 andSYS_SIO_WRITE8. These two macros are used for all accesses to theactual chip. If not defined, the source code will assume a simple memorymapped device using byte read/write access to all registers.The macros SYS_SIO_INT_CONNECT, SYS_SIO_INT_DISCONNECT, SYS_SIO_INT_ENABLE,and SYS_SIO_PROBE can be redefined by the BSP to perform basic low levelroutines with the same calling sequence as intConnect(), intConnect(),intEnable(), and vxMemProbe()..SH TESTINGThe interrupt driven interface can be tested in the usual way; VxWorksprints to the serial console when it comes up, so seeing the usual VxWorksoutput on power-up shows that the driver is basically working.The VxWorks portkit test can be used to perform a more strenuous test.The polled interface should be easy enough to verify - you should be ableto call the channels SIO_MODE_SET ioctl to put it in polled mode. Notethat the usual print tools won't work with a serial channel in polled mode.Some agent has to perform a polling loop to handle input/output on acharacter by character basis. It is not automatic. The WDB agentperforms its own polling loop when it switches the WDB serial line intopolled mode. The dynamic mode switching can be verified using the tornado tools.Reconfigure the agent to use the WDB_COMM_UDLP_SLIP communication path (seethe Configuration section in the VxWorks run-time Guide for details).Start VxWorks, and connect the tgtsvr to the agent using the wdbserialbackend (see the Tornado Users Guide for details).Start the wtxtcl shell as follows: % wtxtclFrom the tcl prompt, attach to the target server: wtxtcl.ex> wtxToolAttach <tgtsvr name>Tell the agent to switch to external mode, and verify the reply is OK (0). wtxtcl.ex>wtxAgentModeSet 2 0Ask the agent to suspend the system (the request will reach the agent ininterrupt mode, but the reply will be sent in polled mode): wtxtcl.ex>wtxContextSuspend 0 0 0At this point the target will be suspended. The console should apprearfrozen (if the board has a console device), and you will not be able to"ping" the target's network interface.Resume the target: wtxtcl.ex>wtxContextResume 0 0 0The target should now be running again, so you should be able to type intothe console (if the board has a console device) and ping the targets networkinterface from the host..SH INCLUDE FILES:drv/sio/i82550Sio.h sioLib.h*/#include "vxWorks.h"#include "intLib.h"#include "errnoLib.h"#include "iosLib.h" /* For S_iosLib_DEVICE_NOT_FOUND */#include "cacheLib.h"#include "stdlib.h" /* malloc/free */#include "stdio.h" /* for printf */#include "vxLib.h" /* for vxMemProbe */#include "i82550Sio.h"/* device and channel structures *//* TODO - Define a driver specific extended SIO_CHAN structure */typedef struct { /* SIO_CHAN *MUST* be first */ SIO_CHAN sio; /* standard SIO_CHAN element */ UINT32 ioBase; UINT32 vecBase; UINT32 intLevel; /* callbacks */ STATUS (*getTxChar) (void *, char *); void (*putRcvChar) (void *, char); void (*errorRtn) (void *, int, void *, int); void * getTxArg; void * putRcvArg; void * errorArg; /* misc */ int intConnect; /* intConnect done flag */ int baudFreq; /* current baud rate */ int mode; /* current mode (interrupt or poll) */ int clkFreq; /* input clock frequency */ uint_t options; /* Hardware options */ int scanMode; /* keyboard mapping mode */ } I82550_CHAN;/* channel control register (write) definitions *//* TODO - These are just made up bit defines for a mythical device! */#define I82550_RESET_CHIP 0x07 /* reset all */#define I82550_RESET_TX 0x01 /* reset the transmitter */#define I82550_RESET_ERR 0x02 /* reset error condition */#define I82550_RESET_INT 0x04 /* acknoledge the interrupt */#define I82550_INT_ENABLE 0x08 /* enable interrupts */#define I82550_TX_ENABLE 0x10 /* enable interrupts */#define I82550_RX_ENABLE 0x20 /* enable interrupts *//* channel status register (read) definitions */#define I82550_CR_OKAY 0x00 /* no error conditions */#define I82550_CR_TX_READY 0x01 /* txmitter ready for another char */#define I82550_CR_TX_ERROR 0x04 /* txmitter int enable */#define I82550_CR_RX_AVAIL 0x10 /* character has arrived */#define I82550_CR_RX_ERROR 0x40 /* receiver error *//* channel modem status register definitions */#define I82550_MSR_RTS 0x1 /* RTS signal asserted */#define I82550_MSR_DTR 0x2 /* DTR signal asserted */#define I82550_MSR_DSR 0x4 /* DSR signal asserted */#define I82550_MSR_CTS 0x8 /* CTS signal asserted */#define I82550_MSR_CD 0x10 /* CD signal asserted *//* input and output signals */#define I82550_ISIG_MASK (SIO_MODEM_CTS|SIO_MODEM_DSR|SIO_MODEM_CD)#define I82550_OSIG_MASK (SIO_MODEM_RTS|SIO_MODEM_DTR)/* channel modem control register definitions */#define I82550_MC_RTS 0x1 /* enable RTS */#define I82550_MC_DTR 0x2 /* enable DTR */#define I82550_BAUD_MIN 75#define I82550_BAUD_MAX 38400/* Hardware abstraction macros *//* Macros from BSP */#define SYS_SIO_READ8(addr, pData) \ (*pData = *(UINT8 *)(addr))#define SYS_SIO_WRITE8(addr, data) \ (*(UINT8 *)addr = data)#define SYS_SIO_INT_CONNECT(vec, rtn, arg) \ intConnect ((VOIDFUNCPTR *)vec, (VOIDFUNCPTR)rtn, (int)arg)#define SYS_SIO_INT_DISCONNECT(vec, rtn, arg) \ intConnect ((VOIDFUNCPTR *)vec, NULL, 0)#define SYS_SIO_INT_ENABLE(level) \ intEnable (level)#define SYS_SIO_PROBE(addr, mode, size, pData) \ vxMemProbe (addr, mode, size, pData)/* #define CACHE_PIPE_FLUSH() *//* Local driver abstractions, following bus/adaptor model */#define I82550_SIO_READ8(pChan, reg, result) \ SYS_SIO_READ8(((pChan->ioBase) + reg),result)#define I82550_SIO_WRITE8(pChan, reg, data) \ SYS_SIO_WRITE8(((pChan->ioBase) + reg),data)#define I82550_SIO_INT_CONNECT(pChan, vec, rtn, arg) \ do { \ SYS_SIO_INT_CONNECT((pChan->vecBase) + vec, rtn, arg); \ SYS_SIO_INT_ENABLE(pChan->intLevel); \ } while (0)#define I82550_INT_DISCONNECT(pChan, vec, rtn, arg) \ SYS_SIO_INT_DISCONNECT(((pChan)->vecBase + vec), rtn, arg) /* Do NOT disable interrupt level for disconnect */#define I82550_PROBE(pChan, offset, dir, size, ptr) \ SYS_SIO_PROBE((char *)((pChan)->ioBase + offset), dir, size, ptr)#define I82550_PIPE_FLUSH(pChan) \ CACHE_PIPE_FLUSH()/* forward static declarations */LOCAL int i82550TxStartup (SIO_CHAN * pSioChan);LOCAL int i82550CallbackInstall (SIO_CHAN *pSioChan, int callbackType, STATUS (*callback)(void *,...), void *callbackArg);LOCAL int i82550PollOutput (SIO_CHAN *pSioChan, char outChar);LOCAL int i82550PollInput (SIO_CHAN *pSioChan, char *thisChar);LOCAL int i82550Ioctl (SIO_CHAN *pSioChan, int request, void *arg);LOCAL STATUS dummyTxCallback (void *, char *);LOCAL void dummyRxCallback (void *, char);LOCAL void dummyErrCallback (void *, int, void *, int);LOCAL void i82550SioIntTx (I82550_CHAN * pChan);LOCAL void i82550SioIntRcv (I82550_CHAN * pChan);LOCAL void i82550SioIntErr (I82550_CHAN * pChan);LOCAL STATUS i82550Probe (I82550_CHAN *);LOCAL STATUS i82550Verify (I82550_CHAN *);LOCAL int i82550MstatGet (I82550_CHAN *);LOCAL int i82550MstatSetClr (I82550_CHAN *, UINT bits, BOOL setFlag);/* local variables */LOCAL SIO_DRV_FUNCS i82550SioDrvFuncs = { i82550Ioctl, i82550TxStartup, i82550CallbackInstall, i82550PollInput, i82550PollOutput };/* local variable */int i82550DrvNum=0;/******************************************************************************** i82550SioCreate - create a I82550_CHAN instance** This routine initializes the driver* function pointers and then resets the chip to a quiescent state.** RETURNS: N/A*/SIO_CHAN * i82550SioCreate ( UINT32 ioBase, UINT32 vecBase, UINT32 level, UINT32 clkFreq ) { I82550_CHAN * pChan; pChan = (I82550_CHAN *) malloc (sizeof (I82550_CHAN)); if (pChan != NULL) { pChan->sio.pDrvFuncs = &i82550SioDrvFuncs; pChan->ioBase = ioBase; pChan->vecBase = vecBase; pChan->intLevel = level; pChan->clkFreq = clkFreq; /* install dummy driver callbacks */ pChan->getTxChar = dummyTxCallback; pChan->putRcvChar = dummyRxCallback; pChan->errorRtn = dummyErrCallback; pChan->intConnect = FALSE; /* int's not connected yet */ if (i82550Probe (pChan) == OK) { I82550_SIO_WRITE8(pChan, I82550_CSR_ID, I82550_RESET_CHIP); /* setting polled mode is one way to make the device quiet */ i82550Ioctl (&pChan->sio, SIO_MODE_SET, (void *)SIO_MODE_POLL); } else { /* Whoops, device is not there! */ free ((char *)pChan); errnoSet (S_iosLib_DEVICE_NOT_FOUND); return NULL; } } return &pChan->sio; }/******************************************************************************** i82550SioDestroy - destroy a I82550_CHAN instance** This function is used to destroy an instance of a I82550_CHAN object.** RETURNS: OK upon success, or ERROR on failure or if the object is not a* valid I82550_CHAN object.*/STATUS i82550SioDestroy ( SIO_CHAN * pSioChan ) { I82550_CHAN * pChan = (I82550_CHAN *)pSioChan; /* * Verify that it is a valid I82550_CHAN device, before doing * anything. */ if (i82550Verify(pChan) == OK) { if (pChan->intConnect == TRUE) { I82550_INT_DISCONNECT(pChan,I82550_RXINT_ID, i82550SioIntRcv, (void *)pChan); I82550_INT_DISCONNECT(pChan, I82550_TXINT_ID, i82550SioIntTx, (void *)pChan); I82550_INT_DISCONNECT(pChan, I82550_ERRINT_ID, i82550SioIntErr, (void *)pChan); } free (pChan); return OK; } return ERROR; }/******************************************************************************** i82550SioIntRcv - handle a channel's receive-character interrupt** RETURNS: N/A*/ LOCAL void i82550SioIntRcv ( I82550_CHAN * pChan /* channel generating the interrupt */ ) { char inChar; /* rcvr data */ char crData = 0; /* rcvr status */ STATUS status = OK; /* * TODO - * * Get status and data from the device. Determine if valid data is ready * or not. * * For PCI devices, do an immediate return if device is not asserting * an interrupt. */ I82550_SIO_READ8(pChan, I82550_CSR_ID, &crData); /* Check for error conditions */ if (crData & I82550_CR_OKAY) { I82550_SIO_READ8(pChan, I82550_DATA_ID, &inChar);#if 0 /* Keyboard emulation code */ /* * TODO - For a keyboard type device we would map the raw scan code * to ASCII, or other mapping. Do that here. */ if (pChan->scanMode == SIO_KYBD_MODE_ASCII) inChar = i82550AsciiTbl[(UINT8)inChar];#endif } else { /* * TODO - Determine precise error condition and perform * recovery actions. */ status = ERROR; } /*
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -