📄 usbtcdpdiusbd12evallib.c
字号:
/* usbTcdPdiusbd12EvalLib.c - USB target controller driver for Philips PDIUSBD12 *//* Copyright 2000 Wind River Systems, Inc. *//*Modification history--------------------01e,12apr00wef Fixed uninitialized variable warning: pTarget in usbTcdPdiusbd12EvalExec() 01d,17mar00,rcb Add code to block re-entrant processing of the ERP queue...formerly, a fast host could cause the interrupt thread to decend endlessly down the stack if the target application re-submits an ERP on the ERP completion callback. Change order in which endpoint interrupt causes are evaluated to make sure a Setup transaction received just after another transaction doesn't get processed out of order. Add code in destroyTarget() to cancel outstanding ERPs.01c,23nov99,rcb Change #include ../xxx references to lower case.01b,12nov99,rcb Short path names...affects "#include" directives.01a,09aug99,rcb First.*//*DESCRIPTIONThis module implements the USB TCD (Target Controller Driver) for the Philips PDIUSBD12 used in conjuction with the PDIUSBD12 ISA evaluation kit from Philips.This module exports a single entry point, usbTcdPdiusbd12EvalExec(). This is theUSB_TCD_EXEC_FUNC for this TCD. The caller passes requests to the TCD by constructing TRBs, or Target Request Blocks, and passing them to this entry point.The USB TCD works in conjuction with the usbTargLib module. In order to simplifythe creation of a TCD for a given USB target controller, the usbTargLib handlesmost parameter and logical validation of requests. The TCD, therefore, is largelyfree to execute requests without extensive validation, knowing that usbTargLibwill have validated the requests beforehand.TCDs are initialized by invoking the TCD_FNC_ATTACH function. In response to thisfunction, the TCD returns information about the target controller, including itsUSB speed, the number of endpoints it supports, and information about eachendpoint. Endpoint information is maintained in an array of USB_TARG_ENDPOINT_INFOstructures. These structures are allocated and owned by the TCD. The usbTargLiband the callers of the usbTargLib are allowed to examine this array, but are notallowed to modify it. All modification of the array is performed generally byinvoking the TCDs TCD_FNC_ENDPOINT_ASSIGN and TCD_FNC_ENDPOINT_RELEASE functions.These functions are invoked upon the creation and deletion of USB pipes,respectively.By convention, each endpoint exposed in the array of USB_TARG_ENDPOINT_INFO structures is unidirectional, ie., either and OUT or IN endpoint. The TCD isrequired to present the endpoints in this way, even if the underlying hardwarepresents the endpoints as bi-directional. In this way, the calling applicationcan choose to assign endpoints to pipes as it sees fit. Also, by convention, thefirst two endpoints in the array MUST be the OUT and IN endpoints which are mostappropriate for use as the default control pipe (endpoint #0).Once pipes have been created, the TCD is instructed to wait for data transfersinitiated by the host USB controller. The TCD callers pass ERPs (EndpointRequest Blocks) to the TCD to request and manage data transfers. It is importantto remember that all USB data transfers are actually initiated by the host, so no data transfers will actually be performed by the TCD and target controllerhardware unless the USB host controller is polling the target.It is also important to note a convention regarding the direction of datatransfers. The transfer of data is always viewed from the host's perspective.Therefore, an OUT transfer is a transfer from the host to the device (target) andan IN transfer is a transfer from the device to the host. Therefore,USB_DIR_OUT, USB_PID_SETUP, and USB_PID_OUT refer to host->device transfers while USB_DIR_IN and USB_PID_IN refer to device->host transfers.During TCD_FNC_ATTACH processing, the TCD creates a task to handle targetcontroller interrupts. Interrupts are first received by a normal interrupthandler, and this interrupt handler immediately reflects the interrupt to theinterrupt task. All TCD callbacks to the usbTargLib are made either from thecaller's task or from the interrupt task. No callbacks are made from theinterrupt context itself.Conditional code:The use of DMA (PC XT/AT style 8237 slave-mode DMA) is enabled by definingthe constant D12_USE_DMA. Leaving this undefined causes the driver to runexclusively in "programmed-I/O" mode.In testing the Philips PDIUSBD12 has appeared to set the "data success" bitincorrectly, causing software to declare a failure. The use of this bitcan be enabled or disabled by definining the constant D12_CHECK_DATA_SUCCESS_BIT.Leaving this constant undefined disables error checking.*//* includes */#include "usb/usbPlatform.h" /* platform definitions */#include "string.h"#include "usb/ossLib.h" /* OS services */#include "usb/usbListLib.h" /* linked list functions */#include "usb/usb.h" /* USB definitions */#include "usb/target/usbIsaLib.h" /* ISA bus functions */#include "drv/usb/target/usbTcd.h" /* generic TCD interface */#include "drv/usb/target/usbPdiusbd12.h" /* Philips PDIUSBD12 defn */#include "drv/usb/target/usbPdiusbd12Eval.h" /* eval board definitions */#include "drv/usb/target/usbTcdPdiusbd12EvalLib.h" /* our API *//* defines *//* BUILD OPTIONS */#define D12_USE_DMA /* Allow use of DMA */#define INT_THREAD_NAME "tD12Int" /* name of int handler thread */#define INT_THREAD_EXIT_TIMEOUT 5000 /* 5 seconds *//* macros used to read/write PDIUSBD12 registers */#define OUT_D12_CMD(b) \ USB_ISA_BYTE_OUT (pTarget->ioBase + D12EVAL_D12REG + D12_CMD_REG, (b))#define OUT_D12_DATA(b) \ USB_ISA_BYTE_OUT (pTarget->ioBase + D12EVAL_D12REG + D12_DATA_REG, (b))#define IN_D12_DATA() \ USB_ISA_BYTE_IN (pTarget->ioBase + D12EVAL_D12REG + D12_DATA_REG)/* macros used to read/write PDIUSBD12 eval general IN/OUT registers */#define OUT_EVAL_GOUT(b) \ USB_ISA_BYTE_OUT (pTarget->ioBase + D12EVAL_GOUT_REG, (b))#define IN_EVAL_GIN() \ USB_ISA_BYTE_IN (pTarget->ioBase + D12EVAL_GIN_REG)/* macro to invoke caller's management callback */#define MNGMT_CALLBACK(pTarget, mngmtCode) \ (*(pTarget)->mngmtCallback) ((pTarget)->mngmtCallbackParam, \ (TCD_HANDLE) (pTarget), (mngmtCode))/* Parameters to certain PDIUSBD12 functions */#define ENABLE TRUE#define DISABLE FALSE/* LEDs on PDIUSBD12 evaluation board used for debugging. */#define ATTACH_LED D12EVAL_GOUT_LED_D2#define ENABLE_LED D12EVAL_GOUT_LED_D3#define INT_THREAD_LED D12EVAL_GOUT_LED_D4/* typedefs *//* ERP_WORKSPACE * * An ERP_WORKSPACE structure is allocated for each ERP as it is enqueued. The * workspace provides storage for TCD-specific data needed to manage the ERP. */typedef struct erp_workspace { UINT16 curBfr; /* Current bfrList[] entry being processed */ UINT16 curBfrOffset; /* Offset into current bfrList[] entry */ BOOL inStatusPending; /* TRUE for ERP on "IN" pipe when waiting */ /* for packet status from hardware */ BOOL dmaInUse; /* TRUE if DMA in use for ERP/endpoint */ UINT16 dmaXfrLen; /* length of DMA transfer */ } ERP_WORKSPACE, *pERP_WORKSPACE;/* TARGET * * TARGET is the primary data structure created to manage an individual target * controller. */typedef struct target { MUTEX_HANDLE tcdMutex; /* guards TARGET data structure */ BOOL shutdown; /* TRUE when target is being shut down */ UINT32 ioBase; /* I/O base address */ UINT16 irq; /* IRQ channel */ UINT16 dma; /* DMA channel */ pUSB_TARG_ENDPOINT_INFO pEndpoints; /* ptr to array of endpoints */ USB_TCD_MNGMT_CALLBACK mngmtCallback; /* caller's management callback */ pVOID mngmtCallbackParam; /* param to mngmt callback */ THREAD_HANDLE intThread; /* Thread used to handle interrupts */ SEM_HANDLE intPending; /* semaphore indicates int pending */ BOOL intThreadExitRequest; /* TRUE when intThread should terminate */ SEM_HANDLE intThreadExit; /* signalled when int thread exits */ UINT32 intCount; /* number of interrupts processed */ BOOL intInstalled; /* TRUE when h/w int handler installed */ UINT16 deviceAddress; /* current address of target */ BOOL enableFlag; /* TRUE if device enabled */ LIST_HEAD erps [D12_NUM_ENDPOINTS]; /* queued ERPs */ ERP_WORKSPACE workspace [D12_NUM_ENDPOINTS]; /* workspace */ UINT8 goutByte; /* bits set for eval GOUT reg */ UINT8 configByte; /* bits set for config mode byte */ UINT8 clkDivByte; /* bits set for clkdiv mode byte */ UINT8 dmaByte; /* bits set for DMA config register */ UINT16 epMainCount; /* count of times endpt #2 enabled */ UINT16 epOneAndTwoCount; /* count of times endpts #1 & #2 enabled */ BOOL transPending [D12_NUM_ENDPOINTS]; /* TRUE if transStatus valid */ UINT8 transStatus [D12_NUM_ENDPOINTS]; /* last trans status for endpoints */ BOOL dmaInUse; /* TRUE if DMA in use */ UINT16 dmaEndpointId; /* endpoint using DMA */ pUSB_ERP pDmaErp; /* pointer to ERP currently using DMA */ BOOL dmaEot; /* TRUE when EOT interrupt signalled */ BOOL endpointNeedsService [D12_NUM_ENDPOINTS]; } TARGET, *pTARGET;/* forward declarations */LOCAL VOID processErpQueue ( pTARGET pTarget, UINT16 endpointId );/* globals *//* The following IMPORTed variables define the location and size of a * low-memory buffer used by the floppy diskette driver. This buffer * is guaranteed to be reachable by the i8237 DMAC (24-bit address * range). In order to demonstrate the proper operation of the Philips * PDIUSBD12 with DMA, we use these buffers for DMA transfers. */IMPORT UINT sysFdBuf; /* physical address of DMA bfr */IMPORT UINT sysFdBufSize; /* size of DMA buffer *//* functions *//***************************************************************************** d12SetAddress - Issues Set Address/Enable command to PDIUSBD12** RETURNS: N/A*/LOCAL VOID d12SetAddress ( pTARGET pTarget ) { UINT8 byte; byte = pTarget->deviceAddress & D12_CMD_SA_ADRS_MASK; byte |= (pTarget->enableFlag) ? D12_CMD_SA_ENABLE : 0; OUT_D12_CMD (D12_CMD_SET_ADDRESS); OUT_D12_DATA (byte); }/***************************************************************************** d12SetEndpointEnable - Issues Set Endpoint Enable command to PDIUSBD12** RETURNS: N/A*/LOCAL VOID d12SetEndpointEnable ( pTARGET pTarget, BOOL enable ) { OUT_D12_CMD (D12_CMD_SET_ENDPOINT_ENABLE); OUT_D12_DATA ((enable) ? D12_CMD_SEE_ENABLE : 0); }/***************************************************************************** d12SetMode - Issues Set Mode command to PDIUSBD12** RETURNS: N/A*/LOCAL VOID d12SetMode ( pTARGET pTarget ) { OUT_D12_CMD (D12_CMD_SET_MODE); OUT_D12_DATA (pTarget->configByte); OUT_D12_DATA (pTarget->clkDivByte); }/***************************************************************************** d12SetDma - Issues Set DMA command to PDIUSBD12** RETURNS: N/A*/LOCAL VOID d12SetDma ( pTARGET pTarget ) { OUT_D12_CMD (D12_CMD_SET_DMA); OUT_D12_DATA (pTarget->dmaByte); }/***************************************************************************** d12ReadIntReg - Issues Read Interrupt Register commadn to PDIUSBD12** RETURNS: UINT16 value with first byte in LSB and second byte in MSB*/LOCAL UINT16 d12ReadIntReg ( pTARGET pTarget ) { UINT8 firstByte; OUT_D12_CMD (D12_CMD_READ_INTERRUPT_REG); firstByte = IN_D12_DATA (); return firstByte | (IN_D12_DATA () << 8); }/***************************************************************************** d12SelectEndpoint - Issues Select Endpoint command to PDIUSBD12** <endpoint> parameter must be D12_ENDPOINT_xxxx.** RETURNS: UINT8 value read after issuing select endpoint command*/LOCAL UINT8 d12SelectEndpoint ( pTARGET pTarget, UINT16 endpoint ) { OUT_D12_CMD (D12_CMD_SELECT_ENDPOINT | endpoint); return IN_D12_DATA (); }/***************************************************************************** d12ReadLastTransStatus - Issues Read Last Transaction Status command** <endpoint> parameter must be D12_ENDPOINT_xxxx.** RETURNS: UINT8 value read after issuing command*/LOCAL UINT8 d12ReadLastTransStatus ( pTARGET pTarget, UINT16 endpoint ) { OUT_D12_CMD (D12_CMD_READ_LAST_TRANS_STATUS | endpoint); return IN_D12_DATA (); }/***************************************************************************** d12ClearBfr - Issues Clear Buffer command to PDIUSBD12** RETURNS: N/A*/LOCAL VOID d12ClearBfr ( pTARGET pTarget ) { OUT_D12_CMD (D12_CMD_CLEAR_BUFFER); }/***************************************************************************** d12ValidateBfr - Issues Validate Buffer command to PDIUSBD12** RETURNS: N/A*/LOCAL VOID d12ValidateBfr ( pTARGET pTarget ) { OUT_D12_CMD (D12_CMD_VALIDATE_BUFFER); }/***************************************************************************** d12ReadBfr - Issues Read Buffer command and reads buffer data** Reads data from the <endpoint> into the next bfrList[] entry/entries* in the <pErp>. ** NOTE: This function automatically invokes d12ClearBfr() after reading * buffer data. In order to avoid losing bytes, the <pErp> passed by the* caller should be able to accept all data in the buffer. ** RETURNS: N/A*/LOCAL VOID d12ReadBfr ( pTARGET pTarget, pUSB_TARG_ENDPOINT_INFO pEndpoint, pUSB_ERP pErp, pERP_WORKSPACE pWork ) { pUSB_BFR_LIST pBfrList; UINT16 actLen; /* Select the endpoint */ d12SelectEndpoint (pTarget, pEndpoint->endpointId); /* Read the number of bytes in the buffer. */ OUT_D12_CMD (D12_CMD_READ_BUFFER); actLen = IN_D12_DATA (); /* throw away first byte */ actLen = IN_D12_DATA (); /* Read buffer data */ pBfrList = &pErp->bfrList [pWork->curBfr]; while (actLen > 0 && pWork->curBfrOffset < pBfrList->bfrLen) { pBfrList->pBfr [pWork->curBfrOffset] = IN_D12_DATA (); pBfrList->actLen++; --actLen; if (++pWork->curBfrOffset == pBfrList->bfrLen) { pBfrList = &pErp->bfrList [++pWork->curBfr]; pWork->curBfrOffset = 0; } if (pWork->curBfr == pErp->bfrCount)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -