📄 usbdcorelib.c
字号:
!= OK || actLen < USB_HUB_DESCR_LEN) { OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return FALSE; } /* We now have all important descriptors for this hub. Pick out * important information and configure hub. */ /* Record hub power capability */ pNode->pwrGoodDelay = pHubDescrBuf->pwrOn2PwrGood * 2; /* 2 msec per unit */ pNode->hubContrCurrent = pHubDescrBuf->hubContrCurrent; if ((pCfgDescr->attributes & USB_ATTR_SELF_POWERED) != 0) { pNode->selfPowered = TRUE; pNode->maxPowerPerPort = USB_POWER_SELF_POWERED; } else { pNode->selfPowered = FALSE; pNode->maxPowerPerPort = USB_POWER_BUS_POWERED; } pNode->numPorts = pHubDescrBuf->nbrPorts; /* If this hub is not already at the maximum USB topology depth, then * create a pipe to monitor it's status and enable each of its ports. */ if (pNode->topologyDepth < USB_MAX_TOPOLOGY_DEPTH) { /* Set the hub's configuration. */ if (usbdConfigurationSet (internalClient, pNode->nodeHandle, pCfgDescr->configurationValue, pNode->hubContrCurrent) != OK) { OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return FALSE; } /* Create a pipe for interrupt transfers from this device. */ if (usbdPipeCreate (internalClient, pNode->nodeHandle, pEpDescr->endpointAddress, pCfgDescr->configurationValue, 0, USB_XFRTYPE_INTERRUPT, USB_DIR_IN, FROM_LITTLEW (pEpDescr->maxPacketSize), HUB_STATUS_LEN (pNode), pEpDescr->interval, &pNode->hubStatusPipe) != OK) { OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return FALSE; } /* Allocate structures for downstream nodes. */ if ((pNode->pPorts = OSS_CALLOC (pNode->numPorts * sizeof (USBD_PORT))) == NULL) { OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return FALSE; } /* Initialize each hub port */ for (port = 0; port < pNode->numPorts; port++) { /* Enable power to the port */ usbdFeatureSet (internalClient, pNode->nodeHandle, USB_RT_CLASS | USB_RT_OTHER, USB_HUB_FSEL_PORT_POWER, port + 1); } OSS_THREAD_SLEEP (pNode->pwrGoodDelay); /* let power stabilize */ /* Initialize an IRP to listen for status changes on the hub */ if (!initHubIrp (pNode)) { OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return FALSE; } } OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return TRUE; }/***************************************************************************** createNode - Creates and initializes new USBD_NODE** If the node is a hub, then automatically initializes hub.** RETURNS: pointer to newly created USBD_NODE, or* NULL if not successful*/LOCAL void reset_upll(void){ CLKCON &= ~0x00000040; UPLLCON = 0x00078023; CLKCON |= 0x00000040; taskDelay(1);}LOCAL pUSBD_NODE createNode ( pUSBD_BUS pBus, /* node's parent bus */ USBD_NODE_ID rootId, /* root id */ USBD_NODE_ID parentHubId, /* parent hub id */ UINT16 parentHubPort, /* parent hub port no */ UINT16 nodeSpeed, /* node speed */ UINT16 topologyDepth /* this node's depth in topology */ ) { pUSBD_NODE pNode; pUSBD_PIPE pPipe; UINT16 actLen, i; /* Allocate/initialize USBD_NODE */ if ((pNode = OSS_CALLOC (sizeof (*pNode))) == NULL) return NULL; /* * The hub status buffer gets touched by hardware. Ensure that * it does not span a cache line */ if ((pNode->pHubStatus = OSS_CALLOC (MAX_HUB_STATUS_LEN)) == NULL) { OSS_FREE (pNode); return NULL; } if (usbHandleCreate (USBD_NODE_SIG, pNode, &pNode->nodeHandle) != OK || OSS_SEM_CREATE (1, 1, &pNode->controlSem) != OK) { destroyNode (pNode); return NULL; } pNode->pBus = pBus; pNode->nodeInfo.nodeSpeed = nodeSpeed; pNode->nodeInfo.parentHubId = parentHubId; pNode->nodeInfo.parentHubPort = parentHubPort; pNode->nodeInfo.rootId = (rootId == 0) ? pNode->nodeHandle : rootId; pNode->topologyDepth = topologyDepth; /* Create a pipe for control transfers to this device. */ if (usbdPipeCreate (internalClient, pNode->nodeHandle, USB_ENDPOINT_CONTROL, 0, 0, USB_XFRTYPE_CONTROL, USB_DIR_INOUT, USB_MIN_CTRL_PACKET_SIZE, 0, 0, &pNode->controlPipe) != OK) { destroyNode (pNode); return NULL; } /* Read the device descriptor to get the maximum payload size and to * determine if this is a hub or not. * * NOTE: We read only the first 8 bytes of the device descriptor (which * takes us through the maxPacketSize field) as suggested by the USB * spec. */ for(i=0; i<8; i++){ if (usbdDescriptorGet (internalClient, pNode->nodeHandle, USB_RT_STANDARD | USB_RT_DEVICE, USB_DESCR_DEVICE, 0, 0, USB_MIN_CTRL_PACKET_SIZE, (pUINT8) &pNode->devDescr, &actLen) != OK || actLen < USB_MIN_CTRL_PACKET_SIZE){ /*printf("usbDescGet(%d) faile!\n", i);*/ reset_upll(); }else{ break; } } if(i==8){ destroyNode (pNode); return NULL; } /* Now that we've read the device descriptor, we know the actual * packet size supported by the control pipe. Update the pipe * accordingly. */ validatePipe (pNode->controlPipe, &pPipe); pPipe->maxPacketSize = pNode->devDescr.maxPacketSize0; /* field is byte wide */ /* Set a unique address for this device. */ if (!assignAddress (pNode)) { destroyNode (pNode); return NULL; } /* Notify the HCD of the change in device address and max packet size */ usbHcdPipeModify (&pBus->pHcd->nexus, pPipe->hcdHandle, pNode->busAddress, pPipe->maxPacketSize); /* If this is a hub node, it requires additional initialization. Otherwise, * we're done unless and until a client performs additional I/O to this * device. */ if (pNode->devDescr.deviceClass == USB_CLASS_HUB) { pNode->nodeInfo.nodeType = USB_NODETYPE_HUB; if (!initHubNode (pNode)) { destroyNode (pNode); return NULL; } } else { pNode->nodeInfo.nodeType = USB_NODETYPE_DEVICE; } /* Read the device class type(s) from the device and notify interested * clients of the device's insertion. */ interrogateDeviceClass (pNode, pNode->devDescr.deviceClass, pNode->devDescr.deviceSubClass, pNode->devDescr.deviceProtocol); notifyClients (pNode, USBD_DYNA_ATTACH); return pNode; }/***************************************************************************** checkHubStatus - checks hub status and updates hub as necessary** Note: We take a Node ID as our parameter (instead of, say, a pointer* to a USBD_NODE structure) so that we can validate the node upon entry.* There are cases where this routine may be called when the underlying* node has already disappeared.** RETURNS: N/A*/LOCAL VOID checkHubStatus ( USBD_NODE_ID nodeId ) { pUSBD_NODE pNode; pUSB_IRP pIrp; UINT16 port; UINT8 portMask; UINT8 statusIndex; /* Is the node still valid? */ if (!validateNode (nodeId, &pNode)) return; pIrp = &pNode->hubIrp; /* Determine what status is available. * * The hubStatus vector contains one bit for the hub itself and * then one bit for each port. */ if (pIrp->result == OK) { port = 0; statusIndex = 0; portMask = USB_HUB_ENDPOINT_STS_PORT0; while (port < pNode->numPorts && statusIndex < pIrp->bfrList [0].actLen) { if ((*(pNode->pHubStatus + statusIndex) & portMask) != 0) { /* This port appears to have status to report */ updateHubPort (pNode, port); } port++; portMask <<= 1; if (portMask == 0) { portMask = 0x01; /* next byte starts with bit 0 */ statusIndex++; } } } /* resubmit the IRP */ if (pIrp->result != S_usbHcdLib_IRP_CANCELED) initHubIrp (pNode); }/***************************************************************************** busThread - bus monitor thread** A separate busThread() thread is spawned for each bus currently* attached to the USBD. This thread is responsible for monitoring and* responding to bus events, like the attachment and removal of devices.* Using a separate thread for each bus helps to ensure that one bus's * behavior won't affect the throughput of other buses.** By convention, the <param> is a pointer to the USBD_BUS structure* for the associated bus. This thread waits on the bus queue* in the bus structure. At the time this thread is first created,* the USBD_BUS structure is only guaranteed to have an initialized* queue...other fields may not yet be initialized.** RETURNS: N/A*/LOCAL VOID busThread ( pVOID param /* thread parameter */ ) { pUSBD_BUS pBus = (pUSBD_BUS) param; USB_MESSAGE msg; /* Execute messages from the busQueue until a BUS_FNC_TERMINATE message is received. */ do { if (usbQueueGet (pBus->busQueue, &msg, OSS_BLOCK) != OK) break; switch (msg.msg) { case BUS_FNC_UPDATE_HUB: OSS_MUTEX_TAKE (structMutex, OSS_BLOCK); checkHubStatus ((USBD_NODE_ID) msg.lParam); OSS_MUTEX_RELEASE (structMutex); break; } } while (msg.msg != BUS_FNC_TERMINATE); /* Mark the callback routine as having terminated. */ OSS_SEM_GIVE (pBus->busExit); }/***************************************************************************** hcdMngmtCallback - invoked when HCD detects managment event** RETURNS: N/A*/LOCAL VOID hcdMngmtCallback ( pVOID mngmtCallbackParam, /* caller-defined param */ HCD_CLIENT_HANDLE handle, /* handle to host controller */ UINT16 busNo, /* bus number */ UINT16 mngmtCode /* management code */ ) { pUSBD_HCD pHcd = (pUSBD_HCD) mngmtCallbackParam; pUSBD_BUS pBus; pUSBD_CLIENT pClient; /* In an unusual case, this routine could be invoked by the HCD * before we have completely initialized our structures. In that * case, just ignore the event. */ if (pHcd->pBuses == NULL) return; pBus = &pHcd->pBuses [busNo]; if (pBus->busThread == NULL || pBus->busQueue == NULL || pBus->pRoot == NULL || pBus->pRoot->nodeHandle == NULL) return; /* Reflect the management event to interested clients */ OSS_MUTEX_TAKE (structMutex, OSS_BLOCK); pClient = usbListFirst (&clientList); while (pClient != NULL) { if (pClient->mngmtCallback != NULL) usbQueuePut (pClient->callbackQueue, CALLBACK_FNC_MNGMT_EVENT, mngmtCode, (UINT32) pBus->pRoot->nodeHandle, OSS_BLOCK); pClient = usbListNext (&pClient->clientLink); } OSS_MUTEX_RELEASE (structMutex); }/***************************************************************************** initHcdBus - Initialize USBD_BUS element of USBD_HCD structure** <pHcd> points to the USBD_HCD being initialized. <busNo> is the index* of the HCD bus to be initialized.** RETURNS: S_usbdLib_xxxx*/LOCAL int initHcdBus ( pUSBD_HCD pHcd, /* USBD_HCD being initialized */ UINT16 busNo /* Bus number to initialize */ ) { pUSBD_BUS pBus = &pHcd->pBuses [busNo]; int s = OK; /* Allocate resources for this bus. */ pBus->pHcd = pHcd; pBus->busNo = busNo; if (OSS_SEM_CREATE (1, 0, &pBus->busExit) != OK || usbQueueCreate (BUS_Q_DEPTH, &pBus->busQueue) != OK || OSS_THREAD_CREATE (busThread, pBus, OSS_PRIORITY_HIGH, "tUsbdBus", &pBus->busThread) != OK || (pBus->pRoot = createNode (pBus, 0, 0, 0, USB_SPEED_FULL, 0)) == NULL) { /* NOTE: If we fail here, destroyHcd() will clean up partially * allocate structures/resources/etc. */ return S_usbdLib_OUT_OF_RESOURCES; } return s; }/***************************************************************************** destroyHcd - tears down a USBD_HCD structure** Detaches the indicated HCD and tears down the HCD structures.** RETURNS: N/A*/LOCAL VOID destroyHcd ( pUSBD_HCD pHcd ) { pUSBD_BUS pBus; UINT16 busNo; /* Unlink the HCD */ usbListUnlink (&pHcd->hcdLink); /* Begin by de-allocating resources related to each bus */ for (busNo = 0; pHcd->pBuses != NULL && busNo < pHcd->busCount; busNo++) { pBus = &pHcd->pBuses [busNo]; /* Destroy all nodes associated with this bus */ destroyAllNodes (pBus->pRoot); /* NOTE: The busQueue is always allocated before the busThread. */ if (pBus->busThread != NULL) { /* Issue a terminate request to the bus thread */ usbQueuePut (pBus->busQueue, BUS_FNC_TERMINATE, 0, 0, BUS_TIMEOUT); OSS_SEM_TAKE (pBus->busExit, BUS_TIMEOUT); OSS_THREAD_DESTROY (pBus->busThread); } if (pBus->busQueue != NULL) usbQueueDestroy (pBus->busQueue); if (pBus->busExit != NULL) OSS_SEM_DESTROY (pBus->busQueue); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -