boolean SMSC951xDeviceReadReg (TSMSC951xDevice *pThis, u32 nIndex, u32 *pValue) { assert (pThis != 0); return DWHCIDeviceControlMessage (USBDeviceGetHost (&pThis->m_USBDevice), USBDeviceGetEndpoint0 (&pThis->m_USBDevice), REQUEST_IN | REQUEST_VENDOR, READ_REGISTER, 0, nIndex, pValue, sizeof *pValue) == (int) sizeof *pValue; }
boolean SMSC951xDeviceWriteReg (TSMSC951xDevice *pThis, u32 nIndex, u32 nValue) { assert (pThis != 0); return DWHCIDeviceControlMessage (USBDeviceGetHost (&pThis->m_USBDevice), USBDeviceGetEndpoint0 (&pThis->m_USBDevice), REQUEST_OUT | REQUEST_VENDOR, WRITE_REGISTER, 0, nIndex, &nValue, sizeof nValue) >= 0; }
boolean SMSC951xDeviceReceiveFrame (TSMSC951xDevice *pThis, void *pBuffer, unsigned *pResultLength) { assert (pThis != 0); assert (pThis->m_pEndpointBulkIn != 0); assert (pBuffer != 0); TUSBRequest URB; USBRequest (&URB, pThis->m_pEndpointBulkIn, pBuffer, FRAME_BUFFER_SIZE, 0); if (!DWHCIDeviceSubmitBlockingRequest (USBDeviceGetHost (&pThis->m_USBDevice), &URB)) { _USBRequest (&URB); return FALSE; } u32 nResultLength = USBRequestGetResultLength (&URB); if (nResultLength < 4) // should not happen with HW_CFG_BIR set { _USBRequest (&URB); return FALSE; } u32 nRxStatus = *(u32 *) pBuffer; if (nRxStatus & RX_STS_ERROR) { LogWrite (FromSMSC951x, LOG_WARNING, "RX error (status 0x%X)", nRxStatus); _USBRequest (&URB); return FALSE; } u32 nFrameLength = RX_STS_FRAMELEN (nRxStatus); assert (nFrameLength == nResultLength-4); assert (nFrameLength > 4); if (nFrameLength <= 4) { _USBRequest (&URB); return FALSE; } nFrameLength -= 4; // ignore CRC //LogWrite (FromSMSC951x, LOG_DEBUG, "Frame received (status 0x%X)", nRxStatus); memcpy (pBuffer, (u8 *) pBuffer + 4, nFrameLength); // overwrite RX status assert (pResultLength != 0); *pResultLength = nFrameLength; _USBRequest (&URB); return TRUE; }
boolean USBKeyboardDeviceStartRequest (TUSBKeyboardDevice *pThis) { assert (pThis != 0); assert (pThis->m_pReportEndpoint != 0); assert (pThis->m_pReportBuffer != 0); assert (pThis->m_pURB == 0); pThis->m_pURB = malloc (sizeof (TUSBRequest)); assert (pThis->m_pURB != 0); USBRequest (pThis->m_pURB, pThis->m_pReportEndpoint, pThis->m_pReportBuffer, BOOT_REPORT_SIZE, 0); USBRequestSetCompletionRoutine (pThis->m_pURB, USBKeyboardDeviceCompletionRoutine, 0, pThis); return DWHCIDeviceSubmitAsyncRequest (USBDeviceGetHost (&pThis->m_USBDevice), pThis->m_pURB); }
boolean SMSC951xDeviceSendFrame (TSMSC951xDevice *pThis, const void *pBuffer, unsigned nLength) { assert (pThis != 0); if (nLength >= FRAME_BUFFER_SIZE-8) { return FALSE; } assert (pThis->m_pTxBuffer != 0); assert (pBuffer != 0); memcpy (pThis->m_pTxBuffer+8, pBuffer, nLength); *(u32 *) &pThis->m_pTxBuffer[0] = TX_CMD_A_FIRST_SEG | TX_CMD_A_LAST_SEG | nLength; *(u32 *) &pThis->m_pTxBuffer[4] = nLength; assert (pThis->m_pEndpointBulkOut != 0); return DWHCIDeviceTransfer (USBDeviceGetHost (&pThis->m_USBDevice), pThis->m_pEndpointBulkOut, pThis->m_pTxBuffer, nLength+8) >= 0; }
boolean USBKeyboardDeviceConfigure (TUSBDevice *pUSBDevice) { TUSBKeyboardDevice *pThis = (TUSBKeyboardDevice *) pUSBDevice; assert (pThis != 0); TUSBConfigurationDescriptor *pConfDesc = (TUSBConfigurationDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_CONFIGURATION); if ( pConfDesc == 0 || pConfDesc->bNumInterfaces < 1) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromUSBKbd); return FALSE; } TUSBInterfaceDescriptor *pInterfaceDesc; while ((pInterfaceDesc = (TUSBInterfaceDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_INTERFACE)) != 0) { if ( pInterfaceDesc->bNumEndpoints < 1 || pInterfaceDesc->bInterfaceClass != 0x03 // HID Class || pInterfaceDesc->bInterfaceSubClass != 0x01 // Boot Interface Subclass || pInterfaceDesc->bInterfaceProtocol != 0x01) // Keyboard { continue; } pThis->m_ucInterfaceNumber = pInterfaceDesc->bInterfaceNumber; pThis->m_ucAlternateSetting = pInterfaceDesc->bAlternateSetting; TUSBEndpointDescriptor *pEndpointDesc = (TUSBEndpointDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_ENDPOINT); if ( pEndpointDesc == 0 || (pEndpointDesc->bEndpointAddress & 0x80) != 0x80 // Input EP || (pEndpointDesc->bmAttributes & 0x3F) != 0x03) // Interrupt EP { continue; } assert (pThis->m_pReportEndpoint == 0); pThis->m_pReportEndpoint = malloc (sizeof (TUSBEndpoint)); assert (pThis->m_pReportEndpoint != 0); USBEndpoint2 (pThis->m_pReportEndpoint, &pThis->m_USBDevice, pEndpointDesc); break; } if (pThis->m_pReportEndpoint == 0) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromUSBKbd); return FALSE; } if (!USBDeviceConfigure (&pThis->m_USBDevice)) { LogWrite (FromUSBKbd, LOG_ERROR, "Cannot set configuration"); return FALSE; } if (pThis->m_ucAlternateSetting != 0) { if (DWHCIDeviceControlMessage (USBDeviceGetHost (&pThis->m_USBDevice), USBDeviceGetEndpoint0 (&pThis->m_USBDevice), REQUEST_OUT | REQUEST_TO_INTERFACE, SET_INTERFACE, pThis->m_ucAlternateSetting, pThis->m_ucInterfaceNumber, 0, 0) < 0) { LogWrite (FromUSBKbd, LOG_ERROR, "Cannot set interface"); return FALSE; } } if (DWHCIDeviceControlMessage (USBDeviceGetHost (&pThis->m_USBDevice), USBDeviceGetEndpoint0 (&pThis->m_USBDevice), REQUEST_OUT | REQUEST_CLASS | REQUEST_TO_INTERFACE, SET_PROTOCOL, BOOT_PROTOCOL, pThis->m_ucInterfaceNumber, 0, 0) < 0) { LogWrite (FromUSBKbd, LOG_ERROR, "Cannot set boot protocol"); return FALSE; } TString DeviceName; String (&DeviceName); StringFormat (&DeviceName, "ukbd%u", s_nDeviceNumber++); DeviceNameServiceAddDevice (DeviceNameServiceGet (), StringGet (&DeviceName), pThis, FALSE); _String (&DeviceName); return USBKeyboardDeviceStartRequest (pThis); }
boolean USBStandardHubConfigure (TUSBDevice *pUSBDevice) { TUSBStandardHub *pThis = (TUSBStandardHub *) pUSBDevice; assert (pThis != 0); const TUSBDeviceDescriptor *pDeviceDesc = USBDeviceGetDeviceDescriptor (&pThis->m_USBDevice); assert (pDeviceDesc != 0); if ( pDeviceDesc->bDeviceClass != USB_DEVICE_CLASS_HUB || pDeviceDesc->bDeviceSubClass != 0 || pDeviceDesc->bDeviceProtocol != 2 // hub with multiple TTs || pDeviceDesc->bNumConfigurations != 1) { LogWrite (FromHub, LOG_ERROR, "Unsupported hub (proto %u)", (unsigned) pDeviceDesc->bDeviceProtocol); return FALSE; } const TUSBConfigurationDescriptor *pConfigDesc = (TUSBConfigurationDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_CONFIGURATION); if ( pConfigDesc == 0 || pConfigDesc->bNumInterfaces != 1) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromHub); return FALSE; } const TUSBInterfaceDescriptor *pInterfaceDesc; while ((pInterfaceDesc = (TUSBInterfaceDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_INTERFACE)) != 0) { if ( pInterfaceDesc->bInterfaceClass != USB_DEVICE_CLASS_HUB || pInterfaceDesc->bInterfaceSubClass != 0 || pInterfaceDesc->bInterfaceProtocol != 2) { continue; } if (pInterfaceDesc->bNumEndpoints != 1) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromHub); return FALSE; } const TUSBEndpointDescriptor *pEndpointDesc = (TUSBEndpointDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_ENDPOINT); if ( pEndpointDesc == 0 || (pEndpointDesc->bEndpointAddress & 0x80) != 0x80 // input EP || (pEndpointDesc->bmAttributes & 0x3F) != 0x03) // interrupt EP { USBDeviceConfigurationError (&pThis->m_USBDevice, FromHub); return FALSE; } break; } if (pInterfaceDesc == 0) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromHub); return FALSE; } if (!USBDeviceConfigure (&pThis->m_USBDevice)) { LogWrite (FromHub, LOG_ERROR, "Cannot set configuration"); return FALSE; } TUSBHostController *pHost = USBDeviceGetHost (&pThis->m_USBDevice); assert (pHost != 0); if (pInterfaceDesc->bAlternateSetting != 0) { if (DWHCIDeviceControlMessage (pHost, USBDeviceGetEndpoint0 (&pThis->m_USBDevice), REQUEST_OUT | REQUEST_TO_INTERFACE, SET_INTERFACE, pInterfaceDesc->bAlternateSetting, pInterfaceDesc->bInterfaceNumber, 0, 0) < 0) { LogWrite (FromHub, LOG_ERROR, "Cannot set interface"); return FALSE; } } assert (pThis->m_pHubDesc == 0); pThis->m_pHubDesc = (TUSBHubDescriptor *) malloc (sizeof (TUSBHubDescriptor)); assert (pThis->m_pHubDesc != 0); if (DWHCIDeviceGetDescriptor (pHost, USBDeviceGetEndpoint0 (&pThis->m_USBDevice), DESCRIPTOR_HUB, DESCRIPTOR_INDEX_DEFAULT, pThis->m_pHubDesc, sizeof *pThis->m_pHubDesc, REQUEST_IN | REQUEST_CLASS) != (int) sizeof *pThis->m_pHubDesc) { LogWrite (FromHub, LOG_ERROR, "Cannot get hub descriptor"); free (pThis->m_pHubDesc); pThis->m_pHubDesc = 0; return FALSE; } #ifndef NDEBUG //DebugHexdump (pThis->m_pHubDesc, sizeof *pThis->m_pHubDesc, FromHub); #endif pThis->m_nPorts = pThis->m_pHubDesc->bNbrPorts; if (pThis->m_nPorts > USB_HUB_MAX_PORTS) { LogWrite (FromHub, LOG_ERROR, "Too many ports (%u)", pThis->m_nPorts); free (pThis->m_pHubDesc); pThis->m_pHubDesc = 0; return FALSE; } if (!USBStandardHubEnumeratePorts (pThis)) { LogWrite (FromHub, LOG_ERROR, "Port enumeration failed"); return FALSE; } return TRUE; }
boolean USBStandardHubEnumeratePorts (TUSBStandardHub *pThis) { assert (pThis != 0); TUSBHostController *pHost = USBDeviceGetHost (&pThis->m_USBDevice); assert (pHost != 0); TUSBEndpoint *pEndpoint0 = USBDeviceGetEndpoint0 (&pThis->m_USBDevice); assert (pEndpoint0 != 0); assert (pThis->m_nPorts > 0); // first power on all ports for (unsigned nPort = 0; nPort < pThis->m_nPorts; nPort++) { if (DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_OUT | REQUEST_CLASS | REQUEST_TO_OTHER, SET_FEATURE, PORT_POWER, nPort+1, 0, 0) < 0) { LogWrite (FromHub, LOG_ERROR, "Cannot power port %u", nPort+1); return FALSE; } } // pThis->m_pHubDesc->bPwrOn2PwrGood delay seems to be not enough // for some low speed devices, so we use the maximum here MsDelay (510); // now detect devices, reset and initialize them for (unsigned nPort = 0; nPort < pThis->m_nPorts; nPort++) { assert (pThis->m_pStatus[nPort] == 0); pThis->m_pStatus[nPort] = malloc (sizeof (TUSBPortStatus)); assert (pThis->m_pStatus[nPort] != 0); if (DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_IN | REQUEST_CLASS | REQUEST_TO_OTHER, GET_STATUS, 0, nPort+1, pThis->m_pStatus[nPort], 4) != 4) { LogWrite (FromHub, LOG_ERROR, "Cannot get status of port %u", nPort+1); continue; } assert (pThis->m_pStatus[nPort]->wPortStatus & PORT_POWER__MASK); if (!(pThis->m_pStatus[nPort]->wPortStatus & PORT_CONNECTION__MASK)) { continue; } if (DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_OUT | REQUEST_CLASS | REQUEST_TO_OTHER, SET_FEATURE, PORT_RESET, nPort+1, 0, 0) < 0) { LogWrite (FromHub, LOG_ERROR, "Cannot reset port %u", nPort+1); continue; } MsDelay (100); if (DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_IN | REQUEST_CLASS | REQUEST_TO_OTHER, GET_STATUS, 0, nPort+1, pThis->m_pStatus[nPort], 4) != 4) { return FALSE; } //LogWrite (FromHub, LOG_DEBUG, "Port %u status is 0x%04X", nPort+1, (unsigned) pThis->m_pStatus[nPort]->wPortStatus); if (!(pThis->m_pStatus[nPort]->wPortStatus & PORT_ENABLE__MASK)) { LogWrite (FromHub, LOG_ERROR, "Port %u is not enabled", nPort+1); continue; } // check for over-current if (pThis->m_pStatus[nPort]->wPortStatus & PORT_OVER_CURRENT__MASK) { DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_OUT | REQUEST_CLASS | REQUEST_TO_OTHER, CLEAR_FEATURE, PORT_POWER, nPort+1, 0, 0); LogWrite (FromHub, LOG_ERROR, "Over-current condition on port %u", nPort+1); return FALSE; } TUSBSpeed Speed = USBSpeedUnknown; if (pThis->m_pStatus[nPort]->wPortStatus & PORT_LOW_SPEED__MASK) { Speed = USBSpeedLow; } else if (pThis->m_pStatus[nPort]->wPortStatus & PORT_HIGH_SPEED__MASK) { Speed = USBSpeedHigh; } else { Speed = USBSpeedFull; } // first create default device assert (pThis->m_pDevice[nPort] == 0); pThis->m_pDevice[nPort] = malloc (sizeof (TUSBDevice)); assert (pThis->m_pDevice[nPort] != 0); USBDevice (pThis->m_pDevice[nPort], pHost, Speed, USBDeviceGetAddress (&pThis->m_USBDevice), nPort+1); if (!USBDeviceInitialize (pThis->m_pDevice[nPort])) { _USBDevice (pThis->m_pDevice[nPort]); free (pThis->m_pDevice[nPort]); pThis->m_pDevice[nPort] = 0; continue; } TString *pNames = USBStandardHubGetDeviceNames (pThis->m_pDevice[nPort]); assert (pNames != 0); LogWrite (FromHub, LOG_NOTICE, "Port %u: Device %s found", nPort+1, StringGet (pNames)); _String (pNames); free (pNames); } // now configure devices for (unsigned nPort = 0; nPort < pThis->m_nPorts; nPort++) { if (pThis->m_pDevice[nPort] == 0) { continue; } // now create specific device from default device TUSBDevice *pChild = USBDeviceFactoryGetDevice (pThis->m_pDevice[nPort]); if (pChild != 0) { _USBDevice (pThis->m_pDevice[nPort]); // delete default device free (pThis->m_pDevice[nPort]); pThis->m_pDevice[nPort] = pChild; // assign specific device if (!(*pThis->m_pDevice[nPort]->Configure) (pThis->m_pDevice[nPort])) { LogWrite (FromHub, LOG_ERROR, "Port %u: Cannot configure device", nPort+1); continue; } LogWrite (FromHub, LOG_DEBUG, "Port %u: Device configured", nPort+1); } else { LogWrite (FromHub, LOG_NOTICE, "Port %u: Device is not supported", nPort+1); _USBDevice (pThis->m_pDevice[nPort]); free (pThis->m_pDevice[nPort]); pThis->m_pDevice[nPort] = 0; } } // again check for over-current TUSBHubStatus *pHubStatus = malloc (sizeof (TUSBHubStatus)); assert (pHubStatus != 0); if (DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_IN | REQUEST_CLASS, GET_STATUS, 0, 0, pHubStatus, sizeof *pHubStatus) != (int) sizeof *pHubStatus) { LogWrite (FromHub, LOG_ERROR, "Cannot get hub status"); free (pHubStatus); return FALSE; } if (pHubStatus->wHubStatus & HUB_OVER_CURRENT__MASK) { for (unsigned nPort = 0; nPort < pThis->m_nPorts; nPort++) { DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_OUT | REQUEST_CLASS | REQUEST_TO_OTHER, CLEAR_FEATURE, PORT_POWER, nPort+1, 0, 0); } LogWrite (FromHub, LOG_ERROR, "Hub over-current condition"); free (pHubStatus); return FALSE; } free (pHubStatus); pHubStatus = 0; boolean bResult = TRUE; for (unsigned nPort = 0; nPort < pThis->m_nPorts; nPort++) { if (DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_IN | REQUEST_CLASS | REQUEST_TO_OTHER, GET_STATUS, 0, nPort+1, pThis->m_pStatus[nPort], 4) != 4) { continue; } if (pThis->m_pStatus[nPort]->wPortStatus & PORT_OVER_CURRENT__MASK) { DWHCIDeviceControlMessage (pHost, pEndpoint0, REQUEST_OUT | REQUEST_CLASS | REQUEST_TO_OTHER, CLEAR_FEATURE, PORT_POWER, nPort+1, 0, 0); LogWrite (FromHub, LOG_ERROR, "Over-current condition on port %u", nPort+1); bResult = FALSE; } } return bResult; }