📄 usbtarglib.c
字号:
/***************************************************************************** usbTargPipeCreate - Creates a pipe for communication on an endpoint** This function creates a pipe attached to a specific target endpoint.* <endpointId> is the TCD-assigned ID of the target endpoint to be used* for this pipe and <endpointNum> is the device endpoint number to which* the endpoint will respond. Some TCDs allow the flexible assignment of* endpoints to specific endpoint numbers while others do not. The* endpointNumMask field in the USB_TARG_ENDPOINT_INFO structure is a bit* mask that reveals which endpoint numbers are supported by a given* endpoint. (e.g., If bit 0 is '1', then the corresponding endpoint can* be assigned to endpoint #0, and so forth).** By convention, each of the endpoints exposed by the TCD is unidirectional.* Control pipes are bidirectional, and therefore logically occupy two* endpoints, one IN endpoint and one OUT endpoint, both with the same* endpointNum. When creating a control pipe, the caller must specify the* second endpoint Id in <endpointId2>. In this case, <endpointId> must* specify the OUT endpoint, and <endpointId2> must specify the IN endpoint.* <endpointId2> should be 0 for other types of pipes.** <configuration> and <interface> specify the device configuration and* interface with which the endpoint (and pipe) is associated. The * usbTargLib uses these values to reset pipes as appropriate when* USB "configuration events" are detected. (In response to a USB* configuration event, the data toggle for a given endpoint is always* reset to DATA0.)** <transferType> specifies the type of transfers to be performed as* USB_XFRTYPE_xxxx. <direction> specifies the direction of the pipe as* USB_DIR_xxxx. Control pipes specify direction as USB_DIR_INOUT.** The caller must be aware that not all endpoints are capable of all types* of transfers. Prior to assigning an endpoint for a particular purpose,* the caller should interrogate the USB_TARG_ENDPOINT_INFO structure for* the endpoint to ensure that it supports the indicated type of transfer.** RETURNS: OK, or ERROR if unable to create pipe** ERRNO:* S_usbTargLib_BAD_PARAM* S_usbTargLib_ENDPOINT_IN_USE* S_usbTargLib_OUT_OF_MEMORY* S_usbTargLib_OUT_OF_RESOURCES* S_usbTargLib_TCD_FAULT*/STATUS usbTargPipeCreate (USB_TARG_CHANNEL targChannel, /* target channel */ UINT16 endpointId, /* endpoint ID to use for pipe */ UINT16 endpointId2, /* needed for control pipes only */ UINT16 endpointNum, /* endpoint number to assign */ UINT16 configuration, /* associated configuration */ UINT16 interface, /* associated interface */ UINT16 transferType, /* USB_XFRTYPE_xxxx */ UINT16 direction, /* USB_DIR_xxxx */ 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -