📄 usbtarglib.c
字号:
pUSB_TARG_PIPE pPipeHandle /* returned pipe handle */ ) { pTARG_TCD pTcd; pUSB_TARG_ENDPOINT_INFO pEndpoint = NULL; pUSB_TARG_ENDPOINT_INFO pEndpoint2 = NULL; pTARG_PIPE pPipe = NULL; UINT16 direction2 = NULL; STATUS status; UINT16 i; OSS_MUTEX_TAKE (targMutex, OSS_BLOCK); /* Validate parameters */ if (pPipeHandle == NULL) status = S_usbTargLib_BAD_PARAM; else status = validateTarg (targChannel, &pTcd); if (transferType == USB_XFRTYPE_CONTROL) { /* Must validate both endpoints. pEndpointId must be OUT endpoint * and pEndpointId2 must be IN endpoint. */ direction = USB_DIR_OUT; direction2 = USB_DIR_IN; if ((status = validateEndpoint (pTcd, endpointId, USB_XFRTYPE_CONTROL, direction, &pEndpoint)) == OK) { status = validateEndpoint (pTcd, endpointId2, USB_XFRTYPE_CONTROL, direction2, &pEndpoint2); } } else { /* Validate only the first endpointId. */ status = validateEndpoint (pTcd, endpointId, transferType, direction, &pEndpoint); } if (status == OK) { /* See if the requested endpoint number is valid */ if (endpointNum > USB_MAX_ENDPOINT_NUM) status = S_usbTargLib_BAD_PARAM; } if (status == OK) { /* See if the endpointNum is in use (for the same direction) */ for (i = 0; i < pTcd->numEndpoints; i++) { if ((pTcd->pEndpoints [i].flags & TCD_ENDPOINT_IN_USE) != 0 && pTcd->pEndpoints [i].direction == direction && pTcd->pEndpoints [i].endpointNum == endpointNum) { status = S_usbTargLib_ENDPOINT_IN_USE; break; } } } if (status == OK) { /* All of the parameters check out OK. Create a pipe to manage * this endpoint. */ if ((pPipe = OSS_CALLOC (sizeof (*pPipe))) == NULL) status = S_usbTargLib_OUT_OF_MEMORY; else { /* Initialize pipe */ pPipe->pTcd = pTcd; pPipe->configuration = configuration; pPipe->interface = interface; pPipe->dataToggle = USB_DATA0; if (usbHandleCreate (TARG_PIPE_SIG, pPipe, &pPipe->pipeHandle) != OK) status = S_usbTargLib_OUT_OF_RESOURCES; } } if (status == OK) { /* Ask the TCD to assign endpointId to the pipe. */ if (usbTcdEndpointAssign (&pTcd->tcdNexus, endpointId, endpointNum, configuration, interface, transferType, direction) != OK) status = S_usbTargLib_TCD_FAULT; else pPipe->pEndpoint = pEndpoint; } if (status == OK && pEndpoint2 != NULL) { /* Ask the TCD to assign endpointId2 to the pipe. */ if (usbTcdEndpointAssign (&pTcd->tcdNexus, endpointId2, endpointNum, configuration, interface, transferType, direction2) != OK) status = S_usbTargLib_TCD_FAULT; else pPipe->pEndpoint2 = pEndpoint2; } /* If we failed to create the pipe, release any partially created pipe. * Otherwise, link the pipe to the list of pipes on this target channel. */ if (status != OK) destroyPipe (pPipe); else { usbListLink (&pTcd->pipes, pPipe, &pPipe->pipeLink, LINK_TAIL); *pPipeHandle = pPipe->pipeHandle; } OSS_MUTEX_RELEASE (targMutex); return ossStatus (status); }/***************************************************************************** usbTargPipeDestroy - Destroys an endpoint pipe** This function tears down a pipe previously created by calling* usbTargPipeCreate(). Any pending transfers on the pipe are canceled* and all resources allocated to the pipe are released.** RETURNS: OK, or ERROR if unable to destroy pipe.*/STATUS usbTargPipeDestroy ( USB_TARG_PIPE pipeHandle /* pipe to be destroyed */ ) { pTARG_PIPE pPipe; STATUS status; OSS_MUTEX_TAKE (targMutex, OSS_BLOCK); /* Validate parameters */ if ((status = validatePipe (pipeHandle, &pPipe)) == OK) { /* Destroy pipe */ destroyPipe (pPipe); } OSS_MUTEX_RELEASE (targMutex); return status; }/***************************************************************************** usbTargTransfer - Submits a USB_ERP for transfer through a pipe** A client uses this function to initiate an transfer on the pipe indicated * by <pipeHandle>. The transfer is described by an ERP, or endpoint request * packet, which must be allocated and initialized by the caller prior to * invoking usbdTargTransfer().** The USB_ERP structure is defined in usb.h as:** .CS* typedef struct usb_bfr_list* {* UINT16 pid;* pUINT8 pBfr;* UINT32 bfrLen;* UINT32 actLen;* } USB_BFR_LIST;** typedef struct usb_erp* {* LINK targLink; // used by usbTargLib* pVOID targPtr; // used by usbTargLib* LINK tcdLink; // used by TCD* pVOID tcdPtr; // used by TCD* pVOID userPtr; * UINT16 erpLen; * int result; // returned by usbTargLib/TCD* ERP_CALLBACK targCallback; // used by usbTargLib* ERP_CALLBACK userCallback;* UINT16 endpointId; // filled in by usbTargLib* UINT16 transferType; // filled in by usbTargLib* UINT16 dataToggle; // filled in by usbTargLib* UINT16 bfrCount; * USB_BFR_LIST bfrList [1];* } USB_ERP, *pUSB_ERP;* .CE** The length of the USB_ERP structure must be stored in <erpLen> and varies * depending on the number of <bfrList> elements allocated at the end of the * structure. By default, the default structure contains a single <bfrList>* element, but clients may allocate a longer structure to accommodate a larger * number of <bfrList> elements. ** <endpointId> and <transferType> are filled in automatically * by the usbTargLib using values recorded when the pipe was created. ** <dataToggle> is filled in automatically except for control pipes. For these* pipes, the caller is required to store the next data toggle as USB_DATA0* or USB_DATA1. The Setup packet is always a DATA0. The first packet of the* data phase is always DATA1, with data packets alternating thereafter, and * the Status phase packet is always DATA1. When using the functions* usbTargLibResponseSend() and usbTargLibPayloadRcv(), usbTargLib handles the* <dataToggle> value automatically.** <bfrList> is an array of buffer descriptors which describe data buffers to * be associated with this ERP. If more than the one <bfrList> element is * required then the caller must allocate the ERP by calculating the size as ** .CS* erpLen = sizeof (USB_ERP) + (sizeof (USB_BFR_DESCR) * (bfrCount - 1))* .CE** <pid> specifies the packet type to use for the indicated buffer and is* specified as USB_PID_xxxx. Note that packet types are specified from the* perspective of the host. For example, USB_PID_IN indicates a transfer from* the device (target) to the host.** The ERP <userCallback> routine must point to a client-supplied ERP_CALLBACK* routine. The usbdTargTransfer() function returns as soon as the ERP has been* successfully enqueued. If there is a failure in delivering the ERP to the* TCD, then usbdTargTransfer() returns an error. The actual result of the ERP* should be checked after the <userCallback> routine has been invoked.** RETURNS: OK, or ERROR if unable to submit USB_ERP for execution** ERRNO:* S_usbTargLib_BAD_PARAM* S_usbTargLib_TCD_FAULT*/STATUS usbTargTransfer ( USB_TARG_PIPE pipeHandle, /* pipe for transfer */ pUSB_ERP pErp /* ERP describing transfer */ ) { pTARG_PIPE pPipe; STATUS status; OSS_MUTEX_TAKE (targMutex, OSS_BLOCK); /* Validate parameters */ if (pErp == NULL) status = S_usbTargLib_BAD_PARAM; else if ((status = validatePipe (pipeHandle, &pPipe)) == OK) { /* Fill in fields in ERP. */ pErp->targPtr = pPipe; pErp->targCallback = usbTargErpCallback; pErp->transferType = pPipe->pEndpoint->transferType; /* If this is a control pipe and with a direction of USB_PID_IN, * then use the second endpoint for the pipe. */ if (pErp->transferType == USB_XFRTYPE_CONTROL && pErp->bfrList [0].pid == USB_PID_IN) pErp->endpointId = pPipe->pEndpoint2->endpointId; else pErp->endpointId = pPipe->pEndpoint->endpointId; /* The caller must specify DATA0/DATA1 for control pipes */ if (pErp->transferType != USB_XFRTYPE_CONTROL) pErp->dataToggle = pPipe->dataToggle; usbListLink (&pPipe->erps, pErp, &pErp->targLink, LINK_HEAD); /* Submit ERP to TCD */ if (usbTcdErpSubmit (&pPipe->pTcd->tcdNexus, pErp) != OK) { status = S_usbTargLib_TCD_FAULT; usbListUnlink (&pErp->targLink); } } OSS_MUTEX_RELEASE (targMutex); return ossStatus (status); }/***************************************************************************** usbTargTransferAbort - Cancels a previously submitted USB_ERP** This function aborts an ERP which was previously submitted through* a call to usbdTargTransfer(). ** RETURNS: OK, or ERROR if unable to cancel USB_ERP** ERRNO:* S_usbTargLib_BAD_PARAM*/STATUS usbTargTransferAbort ( USB_TARG_PIPE pipeHandle, /* pipe for transfer to abort */ pUSB_ERP pErp /* ERP to be aborted */ ) { pTARG_PIPE pPipe; STATUS status; OSS_MUTEX_TAKE (targMutex, OSS_BLOCK); /* Validate parameters */ if (pErp == NULL) status = S_usbTargLib_BAD_PARAM; else if ((status = validatePipe (pipeHandle, &pPipe)) == OK) { /* cancel the ERP */ status = cancelErp (pPipe, pErp); } OSS_MUTEX_RELEASE (targMutex); return ossStatus (status); }/***************************************************************************** usbTargControlResponseSend - Sends a response on the control pipe** usbTargLib automatically creates a pipe to manage communication on the* default control endpoint (#0) defined by the USB. Certain application* callbacks (e.g., the USB_TARG_VENDOR_SPECIFIC callback) may need to* formulate a response and send it to the host. This function allows a* caller to respond to a host control pipe request.** There are two kinds of responses, those that involve a data phase and* those that do not. This function may be used to handle both types. If* a data phase is required, the caller passes a non-NULL <pBfr> for the * usbTargTransfer() function. The usbTargControlResponseSend() function* sends the data described by the USB_ERP and then automatically* accepts the "status phase" transfer sent the by the host to acknowledge* the transfer. If there is no data phase, the <pBfr> parameter should be* NULL, in which case usbTargLib generates just the Status phase* automatically.** The contents of the <pBfr> passed by the caller are copied into a * private usbTargLib buffer. <bfrLen> must not exceed USB_MAX_DESCR_LEN.** This function returns as soon as the transfer is enqueued. ** RETURNS: OK, or ERROR if unable to submit response to host.** ERRNO:* S_usbTargLib_GENERAL_FAULT* S_usbTargLib_BAD_PARAM*/STATUS usbTargControlResponseSend ( USB_TARG_CHANNEL targChannel, /* target channel */ UINT16 bfrLen, /* length of response, or 0 */ pUINT8 pBfr /* ptr to bfr or NULL */ ) { pTARG_TCD pTcd; STATUS status; OSS_MUTEX_TAKE (targMutex, OSS_BLOCK); /* Validate parameters */ if ((status = validateTarg (targChannel, &pTcd)) == OK) { /* If <pErp> is NULL, then just do a Status packet. Otherwise, * submit the caller's ERP. */ if (pBfr == NULL) { if (initStatusErp (pTcd, USB_PID_IN) != OK) status = S_usbTargLib_GENERAL_FAULT; } else { /* Transfer the caller's data. */ if (bfrLen > sizeof (pTcd->dataBfr)) status = S_usbTargLib_BAD_PARAM; else { memcpy (pTcd->dataBfr, pBfr, bfrLen); if (initDataErpForResponse (pTcd, bfrLen) != OK) status = S_usbTargLib_GENERAL_FAULT; } } } OSS_MUTEX_RELEASE (targMutex); return ossStatus (status); }/***************************************************************************** usbTargControlPayloadRcv - Receives data on the default control pipe** usbTargLib automatically creates a pipe to manage communication on the* default control pipe (#0) defined by the USB. Certain application* callbacks (e.g., USB_TARG_VENDOR_SPECIFIC or USB_TARG_DESCRIPTOR_SET)* may need to receive additional data on the control OUT endpoint in order* to complete processing of the control pipe request. This function allows* a caller to receive data on a control pipe.** The <pErp> parameter must point to an ERP which will receive the* additional data. ** This function returns as soon as the USB_ERP is enqueued. Completion of* the USB_ERP is indicated when the ERP's callback is invoked. After the* ERP completes, the application should terminate the USB request by* invoking the usbTargControlResponseSend() function with a NULL <pBfr>* parameter. This will direct usbTargLib to generate a Status IN phase,* signalling the end of the transaction.** NOTE: The caller must ensure that the ERP remains valid until the ERP* userCallback has been invoked - signalling completion of the ERP.** RETURNS: OK, or ERROR if unable to submit ERP to receive additional data*/STATUS usbTargControlPayloadRcv ( USB_TARG_CHANNEL targChannel, pUSB_ERP pErp ) { pTARG_TCD pTcd; STATUS status; OSS_MUTEX_TAKE (targMutex, OSS_BLOCK); /* Validate parameters */ if ((status = validateTarg (targChannel, &pTcd)) == OK) { status = usbTargTransfer (pTcd->controlPipe, pErp); } OSS_MUTEX_RELEASE (targMutex); return ossStatus (status); }/***************************************************************************** usbTargPipeStatusSet - sets pipe stalled/unstalled status** If the target application detects an error while servicing a pipe,* including the default control pipe, it may choose to stall the endpoint(s)* associated with that pipe. This function allows the caller to set the* state of a p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -