📄 usbdcorelib.c
字号:
/***************************************************************************** initHubIrp - initialize IRP used to listen for hub status** RETURNS: TRUE if successful, else FALSE*/LOCAL BOOL initHubIrp (pUSBD_NODE pNode){ pUSB_IRP pIrp = &pNode->hubIrp; /* initialize IRP */ memset (pIrp, 0, sizeof (*pIrp)); pIrp->userPtr = pNode; pIrp->irpLen = sizeof (USB_IRP); pIrp->userCallback = hubIrpCallback; pIrp->flags = USB_FLAG_SHORT_OK; pIrp->timeout = USB_TIMEOUT_NONE; pIrp->transferLen = HUB_STATUS_LEN (pNode); pIrp->bfrCount = 1; pIrp->bfrList[0].pid = USB_PID_IN; pIrp->bfrList[0].pBfr = (pUINT8) pNode->pHubStatus; pIrp->bfrList[0].bfrLen = pIrp->transferLen; memset (pNode->pHubStatus, 0, MAX_HUB_STATUS_LEN); /* submit the IRP. */ if (usbdTransfer (internalClient, pNode->hubStatusPipe, pIrp) != OK) return FALSE; return TRUE;}/***************************************************************************** initHubNode - initialize a hub** RETURNS: TRUE if successful, else FALSE*/LOCAL BOOL initHubNode (pUSBD_NODE pNode){ pUSB_CONFIG_DESCR pCfgDescr; pUSB_INTERFACE_DESCR pIfDescr; pUSB_ENDPOINT_DESCR pEpDescr; pUSB_HUB_DESCR pHubDescrBuf; UINT8 *pConfDescrBfr; UINT16 actLen; UINT16 port; pConfDescrBfr = OSS_MALLOC (USB_MAX_DESCR_LEN); pHubDescrBuf = OSS_MALLOC (sizeof (USB_HUB_DESCR)); /* Read the hub's descriptors. */ if (usbdDescriptorGet (internalClient, pNode->nodeHandle, USB_RT_STANDARD | USB_RT_DEVICE, USB_DESCR_CONFIGURATION, 0, 0, USB_MAX_DESCR_LEN, pConfDescrBfr, &actLen) != OK) { OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return FALSE; } if ((pCfgDescr = usbDescrParse (pConfDescrBfr, actLen, USB_DESCR_CONFIGURATION)) == NULL || (pIfDescr = usbDescrParse (pConfDescrBfr, actLen, USB_DESCR_INTERFACE)) == NULL || (pEpDescr = usbDescrParse (pConfDescrBfr, actLen, USB_DESCR_ENDPOINT)) == NULL) { OSS_FREE (pConfDescrBfr); OSS_FREE (pHubDescrBuf); return FALSE; } if (usbdDescriptorGet (internalClient, pNode->nodeHandle, USB_RT_CLASS | USB_RT_DEVICE, USB_DESCR_HUB, 0, 0, sizeof (USB_HUB_DESCR), (UINT8 *) pHubDescrBuf, &actLen) != 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 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; /* 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. */ 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) { 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -