usbTargLib.c
资源名称:ixp425BSP.rar [点击查看]
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:68k
源码类别:
VxWorks
开发平台:
C/C++
- /* usbTargLib.c - USB Target Library */
- /* Copyright 2000 Wind River Systems, Inc. */
- /*
- Modification history
- --------------------
- 01d,12apr00,wef Fixed uninitialized variable warning: direction2 in usbTargPipeCreate
- 01c,23nov99,rcb Change #include ../xxx references to lower case.
- 01b,24sep99,rcb Change packet count calculation in usbTargErpCallback()
- to handle case where a single 0-length packet is transferred.
- 01a,05aug99,rcb First.
- */
- /*
- DESCRIPTION
- This module implements the hardware-independent USB target API.
- usbTargLib can manage one or more USB TCDs (Target Controller Drivers).
- usbTargLib provides hardware-independent target services and management
- while the USB TCDs provide the hardware-dependent USB interface.
- usbTargLib must be initialized by calling usbTargInitialize(). Before
- operation can begin, at least one TCD must be attached to usbTargLib
- by calling usbTargTcdAttach(). In response to a successful TCD
- attachment, usbTargLib returns a USB_TARG_CHANNEL handle to the caller.
- This handle must be used in all subsequent calls to usbTargLib to
- identify a given target channel.
- USB devices (targets) almost never initiate activity on the USB (the
- exception being RESUME signalling). So, as part of the call to
- usbTargTcdAttach(), the caller must provide a pointer to a
- USB_TARG_CALLBACK_TABLE structure. This table contains a collection of
- callback function pointers initialized by the caller prior to invoking
- the usbTargTcdAttach() function. Through these callbacks, usbTargLib
- notifies the calling application of various USB events and requests from
- the host. The calling application is not required to provide callback
- functions for all possible events. The callback pointers for which
- the calling application has no interest should be NULL.
- usbTargLib automatically establishes the default control pipe for
- each attached target channel and monitors all control pipe requests.
- If the calling application provides a non-NULL callback for the
- corresponding request, usbTargLib invokes the function. If the callback
- function chooses to handle the control pipe request itself, then it
- returns OK, and usbTargLib generally performs no further automatic
- processing. If the callback instead returns FALSE, then usbTargLib
- handles the control pipe request automatically using a default behavior.
- Generally, requests through the control pipe will result in the need for
- the target to establish one or more additional pipes to the host. Each
- pipe is assigned to a particular endpoint on the device. The calling
- application then submits USB_ERPs (endpoint request packets) which cause
- data transfers to be performed on specific pipes.
- */
- /* includes */
- #include "usb/usbPlatform.h" /* platform defintions */
- #include "string.h"
- #include "usb/ossLib.h" /* o/s services */
- #include "usb/usb.h" /* general USB definitions */
- #include "usb/usbListLib.h" /* linked list functions */
- #include "usb/usbHandleLib.h" /* handle functions */
- #include "usb/target/usbTcdLib.h" /* interface to USB TCD */
- #include "usb/target/usbTargLib.h" /* our API */
- /* defines */
- #define TARG_VERSION 0x0001 /* TARG version in BCD */
- #define TARG_MFG "Wind River Systems, Inc." /* TARG Mfg */
- #define TARG_TCD_SIG ((UINT32) 0xaaaa00cd)
- #define TARG_PIPE_SIG ((UINT32) 0xaaaa000e)
- /* Constants used by resetDataToggle(). */
- #define ANY_CONFIGURATION 0xffff
- #define ANY_INTERFACE 0xffff
- #define ANY_ENDPOINT 0xffff
- #define NO_CONFIGURATION 0xfffe
- #define NO_INTERFACE 0xfffe
- #define NO_ENDPOINT 0xfffe
- /* typedefs */
- /* TARG_TCD */
- typedef struct targ_tcd
- {
- LINK tcdLink; /* linked list of TCDs */
- USB_TARG_CHANNEL targChannel; /* handle allocated for channel */
- UINT16 deviceAddress; /* current device address */
- pUSB_TARG_CALLBACK_TABLE pCallbacks;/* table of application callbacks */
- pVOID callbackParam; /* caller-defined callback param */
- TCD_NEXUS tcdNexus; /* our TCD "nexus" */
- UINT16 speed; /* target speed: USB_SPEED_xxxx */
- UINT16 numEndpoints; /* number of endpoints */
- pUSB_TARG_ENDPOINT_INFO pEndpoints; /* ptr to array of endpoints */
- LIST_HEAD pipes; /* list of pipes on this target */
- USB_TARG_PIPE controlPipe; /* Pipe opened for control channel */
- USB_ERP setupErp; /* ERP to receive control pipe setup */
- UINT8 setupBfr [sizeof (USB_SETUP)]; /* bfr for control SETUP packet */
- BOOL setupErpPending; /* TRUE when ERP is pending */
- USB_ERP dataErp; /* ERP to send/receive control data */
- UINT8 dataBfr [USB_MAX_DESCR_LEN]; /* bfr for control IN/OUT packet */
- BOOL dataErpPending; /* TRUE when ERP is pending */
- USB_ERP statusErp; /* ERP to manage status phase packet */
- BOOL statusErpPending; /* TRUE when ERP is pending */
- } TARG_TCD, *pTARG_TCD;
- /* TARG_PIPE */
- typedef struct targ_pipe
- {
- LINK pipeLink; /* linked list of pipes */
- USB_TARG_PIPE pipeHandle; /* handle allocated for pipe */
- pTARG_TCD pTcd; /* TCD for this pipe */
- UINT16 configuration; /* configuration associated with pipe */
- UINT16 interface; /* interface associated with pipe */
- pUSB_TARG_ENDPOINT_INFO pEndpoint; /* ptr to TCD endpoint info */
- pUSB_TARG_ENDPOINT_INFO pEndpoint2; /* 2nd endpoint for ctrl pipes */
- UINT16 dataToggle; /* current DATA0/DATA1 state */
- LIST_HEAD erps; /* list of outstanding ERPs */
- pUSB_ERP erpBeingDeleted; /* ptr to ERP with cancel pending */
- BOOL erpDeleted; /* TRUE when ERP canceled */
- } TARG_PIPE, *pTARG_PIPE;
- /* locals */
- LOCAL UINT16 initCount = 0; /* init count nesting */
- LOCAL BOOL ossInitialized; /* TRUE when ossLib initialized */
- LOCAL BOOL handleInitialized; /* TRUE when usbHandleLib initialized */
- LOCAL MUTEX_HANDLE targMutex; /* guards data structures */
- LOCAL LIST_HEAD tcdList; /* list of attached TCDs */
- /* forward declarations */
- LOCAL VOID setupErpCallback (pVOID p);
- LOCAL VOID responseErpCallback (pVOID p);
- LOCAL VOID statusErpCallback (pVOID p);
- /* functions */
- /***************************************************************************
- *
- * cancelErp - Cancel an IRP and wait for the ERP callback
- *
- * RETURNS: OK or S_usbTargLib_xxxx if couldn't cancel ERP
- */
- LOCAL int cancelErp
- (
- pTARG_PIPE pPipe,
- pUSB_ERP pErp
- )
- {
- /* Mark ERP being canceled */
- pPipe->erpBeingDeleted = pErp;
- pPipe->erpDeleted = FALSE;
- /* Try to cancel ERP */
- if (usbTcdErpCancel (&pPipe->pTcd->tcdNexus, pErp) != OK)
- return S_usbTargLib_CANNOT_CANCEL;
- while (!pPipe->erpDeleted)
- OSS_THREAD_SLEEP (1);
- return OK;
- }
- /***************************************************************************
- *
- * mngmtFunc - Invokes target applications mngmtFunc callback.
- *
- * If there is no mngmtFunc, returns OK.
- *
- * RETURNS: return code (OK, ERROR) from mngmtFunc.
- */
- LOCAL STATUS mngmtFunc
- (
- pTARG_TCD pTcd,
- UINT16 mngmtCode
- )
- {
- if (pTcd->pCallbacks->mngmtFunc == NULL)
- return OK;
- return (*pTcd->pCallbacks->mngmtFunc)
- (pTcd->callbackParam, pTcd->targChannel, mngmtCode);
- }
- /***************************************************************************
- *
- * destroyPipe - Shuts down a pipe and releases its resources
- *
- * RETURNS: N/A
- */
- LOCAL VOID destroyPipe
- (
- pTARG_PIPE pPipe
- )
- {
- pUSB_ERP pErp;
- if (pPipe != NULL)
- {
- /* Unlink the pipe */
- usbListUnlink (&pPipe->pipeLink);
- /* Cancel outstanding ERPs */
- while ((pErp = usbListFirst (&pPipe->erps)) != NULL)
- cancelErp (pPipe, pErp);
- /* Release endpoint(s) assigned to pipe. */
- if (pPipe->pEndpoint != NULL)
- usbTcdEndpointRelease (&pPipe->pTcd->tcdNexus,
- pPipe->pEndpoint->endpointId);
- if (pPipe->pEndpoint2 != NULL)
- usbTcdEndpointRelease (&pPipe->pTcd->tcdNexus,
- pPipe->pEndpoint2->endpointId);
- /* release handle */
- usbHandleDestroy (pPipe->pipeHandle);
- OSS_FREE (pPipe);
- }
- }
- /***************************************************************************
- *
- * destroyTcd - Shuts down a target channel and releases its resources
- *
- * RETURNS: N/A
- */
- LOCAL VOID destroyTcd
- (
- pTARG_TCD pTcd
- )
- {
- pTARG_PIPE pPipe;
- if (pTcd != NULL)
- {
- /* Unlink TCD */
- usbListUnlink (&pTcd->tcdLink);
- /* Notify target application that the channel is going down. */
- mngmtFunc (pTcd, TCD_MNGMT_DETACH);
- /* Destroy outstanding pipes */
- while ((pPipe = usbListFirst (&pTcd->pipes)) != NULL)
- destroyPipe (pPipe);
- /* Detach TCD */
- usbTcdDetach (&pTcd->tcdNexus);
- /* release handle */
- if (pTcd->targChannel != NULL)
- usbHandleDestroy (pTcd->targChannel);
- ossFree (pTcd);
- }
- }
- /***************************************************************************
- *
- * validateTarg - validate a target channel and the state of usbTargLib
- *
- * If <ppTcd> is not NULL, then validate the <targChannel> parameter.
- * Also checks to make sure usbTargLib has been properly initialized.
- *
- * RETURNS: OK or ERROR if unable to validate target channel
- *
- * ERRNO:
- * S_usbTargLib_NOT_INITIALIZED
- * S_usbTargLib_BAD_HANDLE
- */
- LOCAL int validateTarg
- (
- USB_TARG_CHANNEL targChannel,
- pTARG_TCD *ppTcd
- )
- {
- if (initCount == 0)
- return ossStatus (S_usbTargLib_NOT_INITIALIZED);
- if (ppTcd != NULL)
- {
- if (usbHandleValidate (targChannel, TARG_TCD_SIG, (pVOID *) ppTcd) != OK)
- return ossStatus (S_usbTargLib_BAD_HANDLE);
- }
- return OK;
- }
- /***************************************************************************
- *
- * validatePipe - validates a pipe handle
- *
- * RETURNS: OK or ERROR if unable to validate pipe handle
- *
- * ERRNO:
- * S_usbTargLib_BAD_HANDLE
- */
- LOCAL STATUS validatePipe
- (
- USB_TARG_PIPE pipeHandle,
- pTARG_PIPE *ppPipe
- )
- {
- if (usbHandleValidate (pipeHandle, TARG_PIPE_SIG, (pVOID *) ppPipe) != OK)
- return ossStatus (S_usbTargLib_BAD_HANDLE);
- return OK;
- }
- /***************************************************************************
- *
- * findEndpointById - Return pUSB_TARG_ENDPOINT_INFO for endpointId
- *
- * RETURNS: pointer to USB_TARG_ENDPOINT_INFO or NULL if invalid endpointId
- */
- LOCAL pUSB_TARG_ENDPOINT_INFO findEndpointById
- (
- pTARG_TCD pTcd,
- UINT16 endpointId
- )
- {
- pUSB_TARG_ENDPOINT_INFO pEndpoint;
- UINT16 i;
- for (i = 0; i < pTcd->numEndpoints; i++)
- if ((pEndpoint = &pTcd->pEndpoints [i])->endpointId == endpointId)
- return pEndpoint;
- return NULL;
- }
- /***************************************************************************
- *
- * validateEndpoint - checks if an endpointId can be used as requested
- *
- * Checks if <endpointId> is a valid endpoint ID and if the endpoint it
- * indicates supports the <transferType> and <direction>. If the endpoint
- * is valid and supports the requested transfer type/direction, then
- * returns a pointer to the USB_TARG_ENDPOINT_INFO structure for the
- * endpoint.
- *
- * RETURNS: OK, or ERROR if unable to validate endpoint
- *
- * ERRNO:
- * S_usbTargLib_BAD_PARAM
- * S_usbTargLib_ENDPOINT_IN_USE
- */
- LOCAL STATUS validateEndpoint
- (
- pTARG_TCD pTcd,
- UINT16 endpointId,
- UINT16 transferType,
- UINT16 direction,
- pUSB_TARG_ENDPOINT_INFO *ppEndpoint
- )
- {
- pUSB_TARG_ENDPOINT_INFO pEndpoint;
- /* Check if endpoint number is valid */
- if ((pEndpoint = findEndpointById (pTcd, endpointId)) == NULL)
- return ossStatus (S_usbTargLib_BAD_PARAM);
- /* See if the endpointId is in use. */
- if ((pEndpoint->flags & TCD_ENDPOINT_IN_USE) != 0)
- return ossStatus (S_usbTargLib_ENDPOINT_IN_USE);
- /* See if the endpoint supports the direction */
- if (direction == USB_DIR_IN)
- {
- if ((pEndpoint->flags & TCD_ENDPOINT_IN_OK) == 0)
- return ossStatus (S_usbTargLib_BAD_PARAM);
- }
- else if (direction == USB_DIR_OUT)
- {
- if ((pEndpoint->flags & TCD_ENDPOINT_OUT_OK) == 0)
- return ossStatus (S_usbTargLib_BAD_PARAM);
- }
- else
- return ossStatus (S_usbTargLib_BAD_PARAM);
- /* See if the endpoint supports the request transfer type */
- if (transferType == USB_XFRTYPE_CONTROL)
- {
- if ((pEndpoint->flags & TCD_ENDPOINT_CTRL_OK) == 0)
- return ossStatus (S_usbTargLib_BAD_PARAM);
- }
- else if (transferType == USB_XFRTYPE_BULK)
- {
- if ((pEndpoint->flags & TCD_ENDPOINT_BULK_OK) == 0)
- return ossStatus (S_usbTargLib_BAD_PARAM);
- }
- else if (transferType == USB_XFRTYPE_INTERRUPT)
- {
- if ((pEndpoint->flags & TCD_ENDPOINT_INT_OK) == 0)
- return ossStatus (S_usbTargLib_BAD_PARAM);
- }
- else if (transferType == USB_XFRTYPE_ISOCH)
- {
- if ((pEndpoint->flags & TCD_ENDPOINT_ISOCH_OK) == 0)
- return ossStatus (S_usbTargLib_BAD_PARAM);
- }
- else
- return ossStatus (S_usbTargLib_BAD_PARAM);
- *ppEndpoint = pEndpoint;
- return OK;
- }
- /***************************************************************************
- *
- * resetDataToggle - reset data toggle on affected pipes
- *
- * This function is called when a "configuration event" is detected
- * for a given node. This function searches all pipes associated with
- * the node for any that might be affected by the configuration event
- * and resets their data toggles to DATA0.
- *
- * RETURNS: N/A
- */
- LOCAL VOID resetDataToggle
- (
- pTARG_TCD pTcd,
- UINT16 configuration,
- UINT16 interface,
- UINT16 endpoint
- )
- {
- pTARG_PIPE pPipe;
- pPipe = usbListFirst (&pTcd->pipes);
- while (pPipe != NULL)
- {
- if (configuration == ANY_CONFIGURATION ||
- configuration == pPipe->configuration)
- {
- if (interface == ANY_INTERFACE ||
- interface == pPipe->interface)
- {
- if (endpoint == ANY_ENDPOINT ||
- endpoint == pPipe->pEndpoint->endpointNum)
- {
- /* Reset our DATA0/DATA1 indicator. */
- pPipe->dataToggle = USB_DATA0;
- /* Notify the TCD to reset any TCD/hardware indicators */
- usbTcdEndpointStateSet (&pTcd->tcdNexus,
- pPipe->pEndpoint->endpointId, TCD_ENDPOINT_DATA0);
- if (pPipe->pEndpoint2 != NULL)
- usbTcdEndpointStateSet (&pTcd->tcdNexus,
- pPipe->pEndpoint2->endpointId, TCD_ENDPOINT_DATA0);
- }
- }
- }
- pPipe = usbListNext (&pPipe->pipeLink);
- }
- }
- /***************************************************************************
- *
- * initErp - initializes ERP based on arguments passed by caller, then submits it
- *
- * RETURNS: OK, or ERROR if unable to initialize/submit ERP
- */
- LOCAL STATUS initErp
- (
- pTARG_TCD pTcd,
- pBOOL erpInUse,
- pUSB_ERP pErp,
- ERP_CALLBACK callback,
- UINT16 dataToggle,
- UINT8 pid,
- pUINT8 pBfr,
- UINT16 bfrLen
- )
- {
- /* Check if the ERP is already in use. */
- if (*erpInUse)
- return ERROR;
- *erpInUse = TRUE;
- /* Initialize ERP */
- memset (pErp, 0, sizeof (*pErp));
- pErp->userPtr = pTcd;
- pErp->erpLen = sizeof (*pErp);
- pErp->userCallback = callback;
- pErp->dataToggle = dataToggle;
- pErp->bfrCount = 1;
- pErp->bfrList [0].pid = pid;
- pErp->bfrList [0].pBfr = pBfr;
- pErp->bfrList [0].bfrLen = bfrLen;
- /* Submit the ERP. */
- return usbTargTransfer (pTcd->controlPipe, pErp);
- }
- /***************************************************************************
- *
- * initSetupErp - Initialize ERP to listen for control pipe requests
- *
- * RETURNS: OK, or ERROR if unable to initialize control ERP.
- */
- LOCAL STATUS initSetupErp
- (
- pTARG_TCD pTcd
- )
- {
- /* Initialize the Setup phase ERP */
- return initErp (pTcd, &pTcd->setupErpPending, &pTcd->setupErp,
- setupErpCallback, USB_DATA0, USB_PID_SETUP,
- pTcd->setupBfr, sizeof (pTcd->setupBfr));
- }
- /***************************************************************************
- *
- * initDataErpForResponse - Initialize ERP to send a control pipe response
- *
- * TARGET.dataBfr must already contain the data to be send to the host of
- * length <bfrLen>.
- *
- * RETURNS: OK, or ERROR if unable to initialize/submit ERP
- */
- LOCAL STATUS initDataErpForResponse
- (
- pTARG_TCD pTcd,
- UINT16 bfrLen
- )
- {
- /* Initialize the Data phase ERP */
- return initErp (pTcd, &pTcd->dataErpPending, &pTcd->dataErp,
- responseErpCallback, USB_DATA1, USB_PID_IN, pTcd->dataBfr, bfrLen);
- }
- /***************************************************************************
- *
- * initStatusErp - Initialize ERP to send/rcv status phase packet
- *
- * <pid> must specify the direction of the status phase packet as USB_PID_IN
- * (from the device to the host) or USB_PID_OUT (from host to device).
- *
- * RETURNS: OK, or ERROR if unable to initialize/submit ERP
- */
- LOCAL STATUS initStatusErp
- (
- pTARG_TCD pTcd,
- UINT8 pid
- )
- {
- /* Initialize the Status phase ERP */
- return initErp (pTcd, &pTcd->statusErpPending, &pTcd->statusErp,
- statusErpCallback, USB_DATA1, pid, NULL, 0);
- }
- /***************************************************************************
- *
- * requestClearFeature - processes a CLEAR_FEATURE setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestClearFeature
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT16 feature = FROM_LITTLEW (pSetup->value);
- UINT16 index = FROM_LITTLEW (pSetup->index);
- /* A CLEAR_FEATURE request may be configuration event. Therefore, we
- * need to set the data toggle to DATA0 for any pipes which reference
- * this interface.
- */
- if (pSetup->requestType == (USB_RT_STANDARD | USB_RT_ENDPOINT) &&
- feature == USB_FSEL_DEV_ENDPOINT_HALT)
- {
- resetDataToggle (pTcd, ANY_CONFIGURATION, ANY_ENDPOINT, index);
- }
- /* The request itself isn't supported unless the target application
- * has provided a featureSet handler.
- */
- if (pTcd->pCallbacks->featureClear == NULL)
- return ERROR;
- if ((*pTcd->pCallbacks->featureClear)
- (pTcd->callbackParam, pTcd->targChannel,
- pSetup->requestType, feature, index) != OK)
- return ERROR;
- /* Request terminates with status phase. */
- return initStatusErp (pTcd, USB_PID_IN);
- }
- /***************************************************************************
- *
- * requestSetFeature - processes a SET_FEATURE setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestSetFeature
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT16 feature = FROM_LITTLEW (pSetup->value);
- UINT16 index = FROM_LITTLEW (pSetup->index);
- /* This request isn't supported unless the target application
- * has provided a featureSet handler.
- */
- if (pTcd->pCallbacks->featureSet == NULL)
- return ERROR;
- if ((*pTcd->pCallbacks->featureSet)
- (pTcd->callbackParam, pTcd->targChannel,
- pSetup->requestType, feature, index) != OK)
- return ERROR;
- /* Request terminates with status phase. */
- return initStatusErp (pTcd, USB_PID_IN);
- }
- /***************************************************************************
- *
- * requestGetConfiguration - processes a GET_CONFIGURATION setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestGetConfiguration
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- /* This request isn't supported unless the target application has
- * provided a configurationGet handler.
- */
- if (pTcd->pCallbacks->configurationGet == NULL)
- return ERROR;
- /* Get the interface setting from the target application. */
- if ((*pTcd->pCallbacks->configurationGet)
- (pTcd->callbackParam, pTcd->targChannel,
- (pUINT8) pTcd->dataBfr) != OK)
- return ERROR;
- /* Transmit the interface setting back to the host */
- return initDataErpForResponse (pTcd, sizeof (UINT8));
- }
- /***************************************************************************
- *
- * requestSetConfiguration - processes a SET_CONFIGURATION setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestSetConfiguration
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT8 configuration = LSB (FROM_LITTLEW (pSetup->value));
- /* A SET_CONFIGURATION request is a configuration event. Therefore, we
- * need to set the data toggle to DATA0 for any pipes which reference
- * this interface.
- */
- resetDataToggle (pTcd, configuration, ANY_INTERFACE, ANY_ENDPOINT);
- /* The request itself isn't supported unless the target application
- * has provided an interfaceSet handler.
- */
- if (pTcd->pCallbacks->configurationSet == NULL)
- return ERROR;
- if ((*pTcd->pCallbacks->configurationSet)
- (pTcd->callbackParam, pTcd->targChannel, configuration) != OK)
- return ERROR;
- /* Request terminates with status phase. */
- return initStatusErp (pTcd, USB_PID_IN);
- }
- /***************************************************************************
- *
- * requestGetDescriptor - processes a GET_DESCRIPTOR setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestGetDescriptor
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT8 descriptorType = MSB (FROM_LITTLEW (pSetup->value));
- UINT8 descriptorIndex = LSB (FROM_LITTLEW (pSetup->value));
- UINT16 languageId = FROM_LITTLEW (pSetup->index);
- UINT16 length = FROM_LITTLEW (pSetup->length);
- UINT16 actLen;
- /* This request isn't supported unless the target application has
- * provided a descriptorGet handler.
- */
- if (pTcd->pCallbacks->descriptorGet == NULL)
- return ERROR;
- /* Get the descriptor from the target application. */
- if ((*pTcd->pCallbacks->descriptorGet)
- (pTcd->callbackParam, pTcd->targChannel,
- pSetup->requestType, descriptorType, descriptorIndex,
- languageId, min (length, sizeof (pTcd->dataBfr)), pTcd->dataBfr,
- &actLen) != OK)
- {
- return ERROR;
- }
- /* Transmit the descriptor back to the host */
- return initDataErpForResponse (pTcd, actLen);
- }
- /***************************************************************************
- *
- * requestSetDescriptor - processes a SET_DESCRIPTOR setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestSetDescriptor
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT8 descriptorType = MSB (FROM_LITTLEW (pSetup->value));
- UINT8 descriptorIndex = LSB (FROM_LITTLEW (pSetup->value));
- UINT16 languageId = FROM_LITTLEW (pSetup->index);
- UINT16 length = FROM_LITTLEW (pSetup->length);
- /* This request isn't supported unless the target application has
- * provided a descriptorSet handler.
- */
- if (pTcd->pCallbacks->descriptorSet == NULL)
- return ERROR;
- /* Let the target application process the SET_DESCRIPTOR request. */
- return (*pTcd->pCallbacks->descriptorSet)
- (pTcd->callbackParam, pTcd->targChannel,
- pSetup->requestType, descriptorType, descriptorIndex,
- languageId, length);
- }
- /***************************************************************************
- *
- * requestGetInterface - processes a GET_INTERFACE setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestGetInterface
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT16 interface = FROM_LITTLEW (pSetup->index);
- /* This request isn't supported unless the target application has
- * provided an interfaceGet handler.
- */
- if (pTcd->pCallbacks->interfaceGet == NULL)
- return ERROR;
- /* Get the interface setting from the target application. */
- if ((*pTcd->pCallbacks->interfaceGet)
- (pTcd->callbackParam, pTcd->targChannel,
- interface, (pUINT8) pTcd->dataBfr) != OK)
- return ERROR;
- /* Transmit the interface setting back to the host */
- return initDataErpForResponse (pTcd, sizeof (UINT8));
- }
- /***************************************************************************
- *
- * requestSetInterface - processes a SET_INTERFACE setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestSetInterface
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT16 interfaceIndex = FROM_LITTLEW (pSetup->index);
- UINT8 alternateSetting = LSB (FROM_LITTLEW (pSetup->value));
- /* A SET_INTERFACE request is a configuration event. Therefore, we
- * need to set the data toggle to DATA0 for any pipes which reference
- * this interface.
- */
- resetDataToggle (pTcd, ANY_CONFIGURATION, interfaceIndex, ANY_ENDPOINT);
- /* The request itself isn't supported unless the target application
- * has provided an interfaceSet handler.
- */
- if (pTcd->pCallbacks->interfaceSet == NULL)
- return ERROR;
- if ((*pTcd->pCallbacks->interfaceSet)
- (pTcd->callbackParam, pTcd->targChannel,
- interfaceIndex, alternateSetting) != OK)
- return ERROR;
- /* Request terminates with status phase. */
- return initStatusErp (pTcd, USB_PID_IN);
- }
- /***************************************************************************
- *
- * requestGetStatus - processes a GET_STATUS setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestGetStatus
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT16 index = FROM_LITTLEW (pSetup->index);
- UINT16 length = FROM_LITTLEW (pSetup->length);
- UINT16 actLen;
- /* This request isn't supported unless the target application has
- * provided a statusGet handler.
- */
- if (pTcd->pCallbacks->statusGet == NULL)
- return ERROR;
- if ((*pTcd->pCallbacks->statusGet)
- (pTcd->callbackParam, pTcd->targChannel,
- pSetup->requestType, index,
- min (length, sizeof (pTcd->dataBfr)), pTcd->dataBfr,
- &actLen) != OK)
- {
- return ERROR;
- }
- /* Transmit the descriptor back to the host */
- return initDataErpForResponse (pTcd, actLen);
- }
- /***************************************************************************
- *
- * requestSetAddress - processes a SET_ADDRESS setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestSetAddress
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT16 deviceAddress = FROM_LITTLEW (pSetup->value);
- /* If the target application has provided a SetAddress callback,
- * then invoke it now.
- */
- if (pTcd->pCallbacks->addressSet != NULL)
- (*pTcd->pCallbacks->addressSet)
- (pTcd->callbackParam, pTcd->targChannel, deviceAddress);
- /* The new address goes into effect after the Status phase, if any. */
- pTcd->deviceAddress = deviceAddress;
- usbTcdAddressSet (&pTcd->tcdNexus, pTcd->deviceAddress);
- return initStatusErp (pTcd, USB_PID_IN);
- }
- /***************************************************************************
- *
- * requestGetSynchFrame - processes a GET_SYNCH_FRAME setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestGetSynchFrame
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- UINT16 endpoint = FROM_LITTLEW (pSetup->index);
- /* This request isn't supported unless the target application has
- * provided a synchFrameGet handler.
- */
- if (pTcd->pCallbacks->synchFrameGet == NULL)
- return ERROR;
- /* Get the synch frame from the target application. */
- if ((*pTcd->pCallbacks->synchFrameGet)
- (pTcd->callbackParam, pTcd->targChannel,
- endpoint, (pUINT16) pTcd->dataBfr) != OK)
- return ERROR;
- /* Transmit the synch frame back to the host */
- return initDataErpForResponse (pTcd, sizeof (UINT16));
- }
- /***************************************************************************
- *
- * requestVendorSpecific - processes a "vendor specific" setup packet
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS requestVendorSpecific
- (
- pTARG_TCD pTcd,
- pUSB_SETUP pSetup
- )
- {
- /* This request isn't supported unless the target application has
- * provided a vendorSpecific handler.
- */
- if (pTcd->pCallbacks->vendorSpecific == NULL)
- return ERROR;
- return (*pTcd->pCallbacks->vendorSpecific)
- (pTcd->callbackParam, pTcd->targChannel,
- pSetup->requestType, pSetup->request, FROM_LITTLEW (pSetup->value),
- FROM_LITTLEW (pSetup->index), FROM_LITTLEW (pSetup->length));
- }
- /***************************************************************************
- *
- * parseSetupPacket - parse/execute a control pipe request
- *
- * The TARGET.setupBfr should contain a setup packet. Validate it. If
- * valid, parse and execute it.
- *
- * RETURNS: OK if setup packet valid, else ERROR if invalid
- */
- LOCAL STATUS parseSetupPacket
- (
- pTARG_TCD pTcd
- )
- {
- pUSB_SETUP pSetup;
- /* Validate the setup packet */
- if (pTcd->setupErp.bfrList [0].actLen != sizeof (USB_SETUP))
- return ERROR;
- pSetup = (pUSB_SETUP) pTcd->setupBfr;
- /* Execute based on the type of request. */
- if ((pSetup->requestType & USB_RT_CATEGORY_MASK) == USB_RT_STANDARD)
- {
- switch (pSetup->request)
- {
- case USB_REQ_CLEAR_FEATURE:
- return requestClearFeature (pTcd, pSetup);
- case USB_REQ_SET_FEATURE:
- return requestSetFeature (pTcd, pSetup);
- case USB_REQ_GET_CONFIGURATION:
- return requestGetConfiguration (pTcd, pSetup);
- case USB_REQ_SET_CONFIGURATION:
- return requestSetConfiguration (pTcd, pSetup);
- case USB_REQ_GET_DESCRIPTOR:
- return requestGetDescriptor (pTcd, pSetup);
- case USB_REQ_SET_DESCRIPTOR:
- return requestSetDescriptor (pTcd, pSetup);
- case USB_REQ_GET_INTERFACE:
- return requestGetInterface (pTcd, pSetup);
- case USB_REQ_SET_INTERFACE:
- return requestSetInterface (pTcd, pSetup);
- case USB_REQ_GET_STATUS:
- return requestGetStatus (pTcd, pSetup);
- case USB_REQ_SET_ADDRESS:
- return requestSetAddress (pTcd, pSetup);
- case USB_REQ_GET_SYNCH_FRAME:
- return requestGetSynchFrame (pTcd, pSetup);
- default:
- break;
- }
- }
- return requestVendorSpecific (pTcd, pSetup);
- }
- /***************************************************************************
- *
- * setupErpCallback - invoked when Setup ERP completes
- *
- * This function receives control when a Setup ERP completes. Examines the
- * reason for completion, possibly invoking additional control request
- * handling.
- *
- * RETURNS: N/A
- */
- LOCAL VOID setupErpCallback
- (
- pVOID p /* ptr to ERP */
- )
- {
- pUSB_ERP pErp = (pUSB_ERP) p;
- pTARG_TCD pTcd = (pTARG_TCD) pErp->userPtr;
- pTcd->setupErpPending = FALSE;
- /* Completion of a setup ERP, whether successful or not, implies that
- * any previous control pipe request must be terminated. */
- if (pTcd->dataErpPending)
- cancelErp ((pTARG_PIPE) pTcd->dataErp.targPtr, &pTcd->dataErp);
- if (pTcd->statusErpPending)
- cancelErp ((pTARG_PIPE) pTcd->dataErp.targPtr, &pTcd->statusErp);
- /* Was the ERP successful? */
- if (pErp->result == OK)
- {
- /* The ERP was successful. Parse the setup packet. */
- if (parseSetupPacket (pTcd) == OK)
- {
- /* The packet can be parsed successfully. Other code will
- * take care of resubmitting the Setup ERP, so we do nothing.
- */
- return;
- }
- else
- {
- /* We cannot process the indicated command. Stall the
- * control pipe.
- */
- usbTargPipeStatusSet (pTcd->targChannel, pTcd->controlPipe,
- TCD_ENDPOINT_STALL);
- }
- }
- /* Re-submit the ERP unless it was canceled - which indicates that
- * the pipe is probably being torn down.
- */
- if (pErp->result != S_usbTcdLib_ERP_CANCELED)
- initSetupErp (pTcd);
- }
- /***************************************************************************
- *
- * responseErpCallback - invoked when control pipe response ERP completes
- *
- * This function receives control after the data IN phase of a control pipe
- * request has completed.
- *
- * RETURNS: N/A
- */
- LOCAL VOID responseErpCallback
- (
- pVOID p /* ptr to ERP */
- )
- {
- pUSB_ERP pErp = (pUSB_ERP) p;
- pTARG_TCD pTcd = (pTARG_TCD) pErp->userPtr;
- pTcd->dataErpPending = FALSE;
- /* If the ERP was successful, then we prepare the status phase. The
- * status phase is always in the oppposite direction to the data phase.
- * Since this callback handles only "responses" (from device to host),
- * then the status phase will always be an OUT (from host to device).
- *
- * If the data phase failed for some reason other than being canceled,
- * then we resubmit the Setup phase ERP to ensure that the target
- * continues to be responsive on the control pipe.
- */
- if (pErp->result == OK)
- {
- initStatusErp (pTcd, USB_PID_OUT);
- return;
- }
- if (pErp->result != S_usbTcdLib_ERP_CANCELED)
- initSetupErp (pTcd);
- }
- /***************************************************************************
- *
- * statusErpCallback - invoked when control pipe status packet completes
- *
- * This function receives control after the status phase of a control pipe
- * request has completed.
- *
- * RETURNS: N/A
- */
- LOCAL VOID statusErpCallback
- (
- pVOID p /* ptr to ERP */
- )
- {
- pUSB_ERP pErp = (pUSB_ERP) p;
- pTARG_TCD pTcd = (pTARG_TCD) pErp->userPtr;
- pTcd->statusErpPending = FALSE;
- /* Re-submit the Setup ERP. */
- if (pErp->result != S_usbTcdLib_ERP_CANCELED)
- initSetupErp (pTcd);
- }
- /***************************************************************************
- *
- * usbTargManagementCallback - invoked when TCD detects management event
- *
- * This function is invoked by a TCD when the TCD detects a "management"
- * event on a target channel. Examples of management events include
- * bus resets, detection of a new or lost connection, etc.
- *
- * RETURNS: N/A
- */
- LOCAL VOID usbTargManagementCallback
- (
- pVOID mngmtCallbackParam, /* caller-defined param */
- TCD_HANDLE handle, /* channel */
- UINT16 mngmtCode /* management code */
- )
- {
- pTARG_TCD pTcd = (pTARG_TCD) mngmtCallbackParam;
- switch (mngmtCode)
- {
- case TCD_MNGMT_VBUS_LOST:
- case TCD_MNGMT_BUS_RESET:
- /* Reset the device configuration to the power-on state. */
- pTcd->deviceAddress = 0;
- /* code falls through into following case */
- case TCD_MNGMT_VBUS_DETECT:
- case TCD_MNGMT_SUSPEND:
- case TCD_MNGMT_RESUME:
- /* reflect the management event to the target application */
- mngmtFunc (pTcd, mngmtCode);
- break;
- }
- }
- /***************************************************************************
- *
- * usbTargErpCallback - invoked when ERP completes
- *
- * The TCD invokes this callback when an ERP completes. This gives us the
- * opportunity to monitor ERP execution. We reflect the callback to the
- * calling application after we finish our processing.
- *
- * NOTE: By convention, the targPtr field of the ERP has been initialized
- * to point to the TARG_PIPE for this ERP.
- *
- * RETURNS: N/A
- */
- LOCAL VOID usbTargErpCallback
- (
- pVOID p /* ptr to ERP */
- )
- {
- pUSB_ERP pErp = (pUSB_ERP) p;
- pTARG_PIPE pPipe = (pTARG_PIPE) pErp->targPtr;
- UINT16 packets;
- UINT16 i;
- OSS_MUTEX_TAKE (targMutex, OSS_BLOCK);
- /* Unlink the ERP */
- usbListUnlink (&pErp->targLink);
- /* Check if this ERP is being deleted. If so, let the foreground
- * thread know the callback has been invoked.
- */
- if (pErp == pPipe->erpBeingDeleted)
- pPipe->erpDeleted = TRUE;
- /* Update data toggle for pipe. Control and isochronous transfers
- * always begin with DATA0, which is set at pipe initialization -
- * so we don't change it here. Bulk and interrupt pipes alternate
- * between DATA0 and DATA1, and we need to keep a running track of
- * the state across ERPs.
- */
- if (pErp->transferType == USB_XFRTYPE_INTERRUPT ||
- pErp->transferType == USB_XFRTYPE_BULK)
- {
- /* Calculate the number of packets exchanged to determine the
- * next data toggle value. If the count of packets is odd, then
- * the data toggle needs to switch.
- *
- * NOTE: If the ERP is successful, then at least one packet MUST
- * have been transferred. However, it may have been a 0-length
- * packet. This case is handled after the following "for" loop.
- */
- packets = 0;
- for (i = 0; i < pErp->bfrCount; i++)
- {
- packets +=
- (pErp->bfrList [i].actLen + pPipe->pEndpoint->maxPacketSize - 1) /
- pPipe->pEndpoint->maxPacketSize;
- }
- if (pErp->result == OK)
- packets = max (packets, 1);
- if ((packets & 1) != 0)
- pPipe->dataToggle = (pPipe->dataToggle == USB_DATA0) ?
- USB_DATA1 : USB_DATA0;
- }
- /* Invoke the user's callback routine */
- if (pErp->userCallback != NULL)
- (*pErp->userCallback) (pErp);
- OSS_MUTEX_RELEASE (targMutex);
- }
- /***************************************************************************
- *
- * usbTargVersionGet - Retrieve usbTargLib version
- *
- * This function returns the usbTargLib version. If <pVersion> is not NULL, the
- * usbTargLib returns its version in BCD in <pVersion>. For example, version
- * "1.02" would be coded as 01h in the high byte and 02h in the low byte.
- *
- * If <pMfg> is not NULL it must point to a buffer of at least USBT_NAME_LEN
- * bytes in length in which the USBD will store the NULL terminated name of
- * the usbTargLib manufacturer (e.g., "Wind River Systems" +