📄 usbdcorelib.c
字号:
*/ if (pClient->mngmtCallback != NULL) (*pClient->mngmtCallback) (pClient->mngmtCallbackParam, (USBD_NODE_ID) msg.lParam, msg.wParam); break; } } while (msg.msg != CALLBACK_FNC_TERMINATE); /* Mark the callback routine as having terminated. */ OSS_SEM_GIVE (pClient->callbackExit); }/***************************************************************************** doTransferAbort - Cancel an outstanding IRP** Directs the HCD to cancel the IRP and waits for the IRP callback to* be invoked signalling that the IRP has been unlinked successfully.** RETURNS: S_usbdLib_xxxx*/LOCAL int doTransferAbort ( pUSBD_PIPE pPipe, /* Pipe owning transfer */ pUSB_IRP pIrp /* IRP to be cancelled */ ) { /* The callback which indicates that an IRP has been deleted is * asynchronous. However, when deleting an IRP (such as when * destroying a pipe) we generally need to know when the IRP * callback has actually been invoked - and hence the IRP unlinked * from the list of outstanding IRPs on the pipe. */ pPipe->irpBeingDeleted = pIrp; pPipe->irpDeleted = FALSE; /* Instruct the HCD to cancel the IRP */ if (usbHcdIrpCancel (&pPipe->pNode->pBus->pHcd->nexus, pIrp) != OK) return S_usbdLib_CANNOT_CANCEL; /* Wait for the IRP callback to be invoked. */ while (!pPipe->irpDeleted) OSS_THREAD_SLEEP (1); return OK; }/***************************************************************************** destroyNotify - de-allocates a USBD_NOTIFY_REQ** RETURNS: N/A*/LOCAL VOID destroyNotify ( pUSBD_NOTIFY_REQ pNotify ) { usbListUnlink (&pNotify->reqLink); OSS_FREE (pNotify); }/***************************************************************************** destroyPipe - de-allocates a USBD_PIPE and its resources** RETURNS: N/A*/LOCAL VOID destroyPipe ( pUSBD_PIPE pPipe ) { pUSB_IRP pIrp; pUSBD_BUS pBus; if (pPipe != NULL) { pPipe->pipeDeletePending = TRUE; /* Cancel all IRPs outstanding on this pipe. * * NOTE: Since the IRP completion callbacks are on a different thread, * we need to wait until all callbacks have been completed. This * functionality is built into doTransferAbort(). */ while ((pIrp = usbListFirst (&pPipe->irps)) != NULL) doTransferAbort (pPipe, pIrp); /* Release bandwidth and notify HCD that the pipe is going away. */ pBus = pPipe->pNode->pBus; pBus->nanoseconds -= pPipe->nanoseconds; usbHcdPipeDestroy (&pBus->pHcd->nexus, pPipe->hcdHandle); /* Unlink pipe from owning client's list of pipes */ if (pPipe->pClient != NULL) usbListUnlink (&pPipe->clientPipeLink); /* Unlink pipe from owning node's list of pipes */ if (pPipe->pNode != NULL) usbListUnlink (&pPipe->nodePipeLink); /* Release pipe handle */ if (pPipe->handle != NULL) usbHandleDestroy (pPipe->handle); OSS_FREE (pPipe); } }/***************************************************************************** destroyClient - tears down a USBD_CLIENT structure** RETURNS: N/A*/LOCAL VOID destroyClient ( pUSBD_CLIENT pClient ) { pUSBD_NOTIFY_REQ pNotify; pUSBD_PIPE pPipe; pUSBD_HCD pHcd; UINT16 busNo; /* unlink client from list of clients. * * NOTE: usbListUnlink is smart and only unlinks the structure if it is * actually linked. */ usbListUnlink (&pClient->clientLink); /* destroy all notification requests outstanding for the client */ while ((pNotify = usbListFirst (&pClient->notifyReqs)) != NULL) destroyNotify (pNotify); /* destroy all pipes owned by this client */ while ((pPipe = usbListFirst (&pClient->pipes)) != NULL) destroyPipe (pPipe); /* If this client is the current SOF master for any USBs, then release * the SOF master status. */ pHcd = usbListFirst (&hcdList); while (pHcd != NULL) { for (busNo = 0; busNo < pHcd->busCount; busNo++) if (pHcd->pBuses [busNo].pSofMasterClient == pClient) pHcd->pBuses [busNo].pSofMasterClient = NULL; pHcd = usbListNext (&pHcd->hcdLink); } /* Note: callbackQueue is always created after callbackExit and * before callbackThread */ if (pClient->callbackThread != NULL) { /* Terminate the client callback thread */ usbQueuePut (pClient->callbackQueue, CALLBACK_FNC_TERMINATE, 0, 0, CALLBACK_TIMEOUT); OSS_SEM_TAKE (pClient->callbackExit, CALLBACK_TIMEOUT); OSS_THREAD_DESTROY (pClient->callbackThread); } if (pClient->callbackQueue != NULL) usbQueueDestroy (pClient->callbackQueue); if (pClient->callbackExit != NULL) OSS_SEM_DESTROY (pClient->callbackExit); if (pClient->handle != NULL) usbHandleDestroy (pClient->handle); OSS_FREE (pClient); }/***************************************************************************** fncClientReg - Register a new USBD client** RETURNS: S_usbdLib_xxxx*/LOCAL int fncClientReg ( pURB_CLIENT_REG pUrb ) { pUSBD_CLIENT pClient; int s; /* validate URB */ if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK) return s; /* Create structures/resources/etc., required by new client */ if ((pClient = OSS_CALLOC (sizeof (*pClient))) == NULL) return S_usbdLib_OUT_OF_MEMORY; memcpy (pClient->clientName, pUrb->clientName, USBD_NAME_LEN); if (usbHandleCreate (USBD_CLIENT_SIG, pClient, &pClient->handle) != OK || OSS_SEM_CREATE (1, 0, &pClient->callbackExit) != OK || usbQueueCreate (CALLBACK_Q_DEPTH, &pClient->callbackQueue) != OK || OSS_THREAD_CREATE (clientThread, pClient, OSS_PRIORITY_INHERIT, "tUsbdClnt", &pClient->callbackThread) != OK) s = S_usbdLib_OUT_OF_RESOURCES; else { /* The client was initialized successfully. Add it to the list */ usbListLink (&clientList, pClient, &pClient->clientLink, LINK_TAIL); /* return the client's USBD_CLIENT_HANDLE */ pUrb->header.handle = pClient->handle; } if (s != OK) { destroyClient (pClient); } return s; }/***************************************************************************** fncClientUnreg - Unregister a USBD client** RETURNS: S_usbdLib_xxxx*/LOCAL int fncClientUnreg ( pURB_CLIENT_UNREG pUrb ) { pUSBD_CLIENT pClient; int s; /* validate Urb */ if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK) return s; /* destroy client */ destroyClient (pClient); return s; }/***************************************************************************** fncMngmtCallbackSet - sets management callback for a client** RETURNS: S_usbdLib_xxxx*/LOCAL int fncMngmtCallbackSet ( pURB_MNGMT_CALLBACK_SET pUrb ) { pUSBD_CLIENT pClient; int s; /* validate URB */ if ((s = validateUrb (pUrb, sizeof (*pUrb), &pClient)) != OK) return s; /* Set the management callback */ pClient->mngmtCallback = pUrb->mngmtCallback; pClient->mngmtCallbackParam = pUrb->mngmtCallbackParam; return s; }/***************************************************************************** fncVersionGet - Return USBD version** RETURNS: S_usbdLib_xxxx*/LOCAL int fncVersionGet ( pURB_VERSION_GET pUrb ) { int s; /* validate urb */ if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK) return s; /* return version information */ pUrb->version = USBD_VERSION; strncpy ((char *)pUrb->mfg, USBD_MFG, USBD_NAME_LEN); return s; }/***************************************************************************** releaseAddress - release a USB device address** RETURNS: N/A*/LOCAL VOID releaseAddress ( pUSBD_NODE pNode ) { pUSBD_BUS pBus = pNode->pBus; pBus->adrsVec [pNode->busAddress / 8] &= ~(0x1 << (pNode->busAddress % 8)); }/***************************************************************************** assignAddress - assigns a unique USB address to a node** RETURNS: TRUE if successful, else FALSE*/LOCAL BOOL assignAddress ( pUSBD_NODE pNode ) { pUSBD_BUS pBus = pNode->pBus; UINT16 i; /* Find an available address */ for (i = 1; i < USB_MAX_DEVICES; i++) { if ((pBus->adrsVec [i / 8] & (0x1 << (i % 8))) == 0) { /* i is the value of an unused address. Set the device adrs. */ if (usbdAddressSet (internalClient, pNode->nodeHandle, i) == OK) { pNode->busAddress = i; pBus->adrsVec [i / 8] |= 0x1 << (i % 8); return TRUE; } else { return FALSE; } } } return FALSE; }/***************************************************************************** notifyIfMatch - Invoke attach callback if appropriate.** Compares the device class/subclass/protocol for <pClassType> and <pNotify>.* If the two match, then invokes the callback in <pNotify> with an attach* code of <attachCode>.** RETURNS: N/A*/LOCAL VOID notifyIfMatch ( pUSBD_NODE pNode, pUSBD_NODE_CLASS pClassType, pUSBD_CLIENT pClient, pUSBD_NOTIFY_REQ pNotify, UINT16 attachCode ) { pNOTIFICATION pNotification; /* Do the pClassType and pNotify structures contain matching class * descriptions? */ if (pNotify->deviceClass == USBD_NOTIFY_ALL || pClassType->deviceClass == pNotify->deviceClass) { if (pNotify->deviceSubClass == USBD_NOTIFY_ALL || pClassType->deviceSubClass == pNotify->deviceSubClass) { if (pNotify->deviceProtocol == USBD_NOTIFY_ALL || pClassType->deviceProtocol == pNotify->deviceProtocol) { /* We have a match. Schedule the client attach callback. * * NOTE: The pNotification structure is created here and * released when consumed in the client callback thread. * * NOTE: In a very large USB topology (at least several * dozen nodes) there is a chance that we could overrun * a client's callback queue depending on the type of * notification requests the client has made. If this happens, * the following call to usbQueuePut() may block. If *that* * happens, there is a chance of a deadlock if the client's * callback code - invoked from the clientThread() reenters * the USBD. A simple solution, if that situation is observed, * is to increase the depth of the callback queue. */ if ((pNotification = OSS_CALLOC (sizeof (*pNotification))) != NULL) { pNotification->callback = pNotify->callback; pNotification->nodeId = pNode->nodeHandle; pNotification->attachCode = attachCode; pNotification->configuration = pClassType->configuration; pNotification->interface = pClassType->interface; pNotification->deviceClass = pClassType->deviceClass; pNotification->deviceSubClass = pClassType->deviceSubClass; pNotification->deviceProtocol = pClassType->deviceProtocol; usbQueuePut (pClient->callbackQueue, CALLBACK_FNC_NOTIFY_ATTACH, 0, (UINT32) pNotification, OSS_BLOCK); } } } } }/***************************************************************************** notifyClients - notify clients of a dynamic attach/removal** Scans the clientList looking for clients who have requested dynamic* attach/removal notification for a class matching <pNode>. If any* are found, their dynamic attach callback routines will be invoked* with an attach code of <attachCode>.** RETURNS: N/A*/LOCAL VOID notifyClients ( pUSBD_NODE pNode, UINT16 attachCode ) { pUSBD_CLIENT pClient; pUSBD_NOTIFY_REQ pNotify; pUSBD_NODE_CLASS pClassType; /* Scan for clients which have requested dynamic attach notification. */ pClient = usbListFirst (&clientList); while (pClient != NULL) { /* Walk through the list of notification requests for this client */ pNotify = usbListFirst (&pClient->notifyReqs); while (pNotify != NULL) { /* Walk through the class types for this node, looking for one * which matches the current client notification request. */ pClassType = usbListFirst (&pNode->classTypes); while (pClassType != NULL) { notifyIfMatch (pNode, pClassType, pClient, pNotify, attachCode); pClassType = usbListNext (&pClassType->classLink); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -