/** * @brief USBH_Set_Protocol * Set protocol State. * @param pdev: Selected device * @param protocol : Set Protocol for HID : boot/report protocol * @retval USBH_Status : Response for USB Set Protocol request */ static USBH_Status USBH_Set_Protocol(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t protocol) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL; if(protocol != 0) { /* Boot Protocol */ phost->Control.setup.b.wValue.w = 0; } else { /*Report Protocol*/ phost->Control.setup.b.wValue.w = 1; } phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); }
//-------------------------------------------------------------- USBH_Status USBH_ClrFeature(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t ep_num, uint8_t hc_num) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT | USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE; phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT; phost->Control.setup.b.wIndex.w = ep_num; phost->Control.setup.b.wLength.w = 0; if ((ep_num & USB_REQ_DIR_MASK ) == USB_D2H) { /* EP Type is IN */ pdev->host.hc[hc_num].toggle_in = 0; } else {/* EP Type is OUT */ pdev->host.hc[hc_num].toggle_out = 0; } return USBH_CtlReq(pdev, phost, 0 , 0 ); }
/** * @brief USBH_MSC_GETMaxLUN * This request is used to reset the mass storage device and its * associated interface. This class-specific request shall ready the * device for the next CBW from the host. * @param pdev: Selected device * @retval USBH_Status : USB ctl xfer status */ USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev) { MSC_Setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \ USB_REQ_RECIPIENT_INTERFACE; MSC_Setup.b.bRequest = USB_REQ_GET_MAX_LUN; MSC_Setup.b.wValue.w = 0; MSC_Setup.b.wIndex.w = 0; MSC_Setup.b.wLength.w = 1; return USBH_CtlReq(pdev, &MSC_Setup, MSC_Machine.buff , 1 ); }
/** * @brief USBH_ADK_switch * Request the Android device start up in accessory mode. * @param pdev: Selected device * @param hdev: Selected device property * @retval USBH_StatusTypeDef */ static USBH_StatusTypeDef USBH_AOA_Switch(USBH_HandleTypeDef *phost) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_VENDOR | USB_REQ_RECIPIENT_DEVICE; phost->Control.setup.b.bRequest = ACCESSORY_START; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; /* Control Request */ return USBH_CtlReq(phost, 0, 0); }
/** * @brief USBH_MSC_BOT_REQ_GetMaxLUN * The function the MSC BOT GetMaxLUN request. * @param phost: Host handle * @param Maxlun: pointer to Maxlun variable * @retval USBH Status */ USBH_StatusTypeDef USBH_MSC_BOT_REQ_GetMaxLUN(USBH_HandleTypeDef *phost, uint8_t *Maxlun) { phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \ USB_REQ_RECIPIENT_INTERFACE; phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 1; return USBH_CtlReq(phost, Maxlun , 1 ); }
/** * @brief USBH_MSC_GETMaxLUN * This request is used to reset the mass storage device and its * associated interface. This class-specific request shall ready the * device for the next CBW from the host. * @param pdev: Selected device * @retval USBH_Status : USB ctl xfer status */ static USBH_Status USBH_MSC_GETMaxLUN(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost) { phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \ USB_REQ_RECIPIENT_INTERFACE; phost->Control.setup.b.bRequest = USB_REQ_GET_MAX_LUN; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 1; return USBH_CtlReq(pdev, phost, MSC_Machine.buff , 1 ); }
/** * @brief USBH_MSC_BOT_REQ_Reset * The function the MSC BOT Reset request. * @param phost: Host handle * @retval USBH Status */ USBH_StatusTypeDef USBH_MSC_BOT_REQ_Reset(USBH_HandleTypeDef *phost) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \ USB_REQ_RECIPIENT_INTERFACE; phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(phost, 0 , 0 ); }
/** * @brief USBH_MSC_BOTReset * This request is used to reset the mass storage device and its * associated interface. This class-specific request shall ready the * device for the next CBW from the host. * @param pdev: Selected device * @retval USBH_Status : Status of class request handled. */ USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev) { MSC_Setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \ USB_REQ_RECIPIENT_INTERFACE; MSC_Setup.b.bRequest = USB_REQ_BOT_RESET; MSC_Setup.b.wValue.w = 0; MSC_Setup.b.wIndex.w = 0; MSC_Setup.b.wLength.w = 0; return USBH_CtlReq(pdev, &MSC_Setup, 0 , 0 ); }
/** * @brief This request allows the host to find out the currently * configured line coding. * @param pdev: Selected device * @retval USBH_StatusTypeDef : USB ctl xfer status */ static USBH_StatusTypeDef GetLineCoding(USBH_HandleTypeDef *phost, CDC_LineCodingTypeDef *linecoding) { phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_CLASS | \ USB_REQ_RECIPIENT_INTERFACE; phost->Control.setup.b.bRequest = CDC_GET_LINE_CODING; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = LINE_CODING_STRUCTURE_SIZE; return USBH_CtlReq(phost, linecoding->Array, LINE_CODING_STRUCTURE_SIZE); }
/** * @brief USBH_ADK_getProtocol * Inquiry protocol version number from Android device. * @param pdev: Selected device * @param hdev: Selected device property * @retval USBH_StatusTypeDef */ static USBH_StatusTypeDef USBH_AOA_GetProtocol(USBH_HandleTypeDef *phost) { AOA_HandShakeDataTypeDef* p = phost->pUserData; phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_TYPE_VENDOR | USB_REQ_RECIPIENT_DEVICE; phost->Control.setup.b.bRequest = ACCESSORY_GET_PROTOCOL; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 2; /* Control Request */ return USBH_CtlReq(phost, (uint8_t*)&p->protocol, 2); }
//-------------------------------------------------------------- USBH_Status USBH_SetCfg(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint16_t cfg_idx) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION; phost->Control.setup.b.wValue.w = cfg_idx; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); }
/** * @brief USBH_MSC_BOTReset * This request is used to reset the mass storage device and its * associated interface. This class-specific request shall ready the * device for the next CBW from the host. * @param pdev: Selected device * @retval USBH_Status : Status of class request handled. */ static USBH_Status USBH_MSC_BOTReset(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_CLASS | \ USB_REQ_RECIPIENT_INTERFACE; phost->Control.setup.b.bRequest = USB_REQ_BOT_RESET; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); }
/** * @brief USBH_ClearDeviceFeature * The command sets the device features (remote wakeup feature,..) * @param pdev: Selected device * @param itf_idx * @retval Status */ USBH_Status USBH_ClearDeviceFeature(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t FeatureSelector, uint16_t wIndex) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE; phost->Control.setup.b.wValue.w = FeatureSelector; phost->Control.setup.b.wIndex.w = wIndex; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); }
/** * @brief USBH_SetInterface * The command sets the Interface value to the connected device * @param pdev: Selected device * @param itf_idx: Interface value * @retval Status */ USBH_Status USBH_SetInterface(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t ep_num, uint8_t altSetting) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE; phost->Control.setup.b.wValue.w = altSetting; phost->Control.setup.b.wIndex.w = ep_num; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); }
/** * @brief USBH_SetCfg * The command sets the configuration value to the connected device * @param phost: Host Handle * @param cfg_idx: Configuration value * @retval USBH Status */ USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost, uint16_t cfg_idx) { if(phost->RequestState == CMD_SEND) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION; phost->Control.setup.b.wValue.w = cfg_idx; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; } return USBH_CtlReq(phost, 0 , 0 ); }
//-------------------------------------------------------------- USBH_Status USBH_SetAddress(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t DeviceAddress) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS; phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); }
/** * @brief USBH_AOA_SendString * Send identifying string information to the Android device. * @param pdev: Selected device * @param hdev: Selected device property * @param index: String ID * @param buff: Identifying string * @retval USBH_StatusTypeDef */ static USBH_StatusTypeDef USBH_AOA_SendString(USBH_HandleTypeDef *phost, uint16_t index, uint8_t* buff) { uint16_t length; length = (uint16_t) strlen((char*)buff) + 1; phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_VENDOR | USB_REQ_RECIPIENT_DEVICE; phost->Control.setup.b.bRequest = ACCESSORY_SEND_STRING; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = index; phost->Control.setup.b.wLength.w = length; /* Control Request */ return USBH_CtlReq(phost, buff, length); }
/** * @brief USBH_ClrFeature * This request is used to clear or disable a specific feature. * @param phost: Host Handle * @param ep_num: endpoint number * @param hc_num: Host channel number * @retval USBH Status */ USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost, uint8_t ep_num) { if(phost->RequestState == CMD_SEND) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT | USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE; phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT; phost->Control.setup.b.wIndex.w = ep_num; phost->Control.setup.b.wLength.w = 0; } return USBH_CtlReq(phost, 0 , 0 ); }
/** * @brief USBH_SetInterface * The command sets the Interface value to the connected device * @param phost: Host Handle * @param altSetting: Interface value * @retval USBH Status */ USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost, uint8_t ep_num, uint8_t altSetting) { if(phost->RequestState == CMD_SEND) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE; phost->Control.setup.b.wValue.w = altSetting; phost->Control.setup.b.wIndex.w = ep_num; phost->Control.setup.b.wLength.w = 0; } return USBH_CtlReq(phost, 0 , 0 ); }
/** * @brief USBH_SetAddress * This command sets the address to the connected device * @param phost: Host Handle * @param DeviceAddress: Device address to assign * @retval USBH Status */ USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost, uint8_t DeviceAddress) { if(phost->RequestState == CMD_SEND) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS; phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; } return USBH_CtlReq(phost, 0 , 0 ); }
/** * @brief USBH_Set_Protocol * Set protocol State. * @param phost: Host handle * @param protocol : Set Protocol for HID : boot/report protocol * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_SetProtocol(USBH_HandleTypeDef *phost, uint8_t protocol) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL; phost->Control.setup.b.wValue.w = protocol != 0 ? 0 : 1; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(phost, 0 , 0 ); }
/** * @brief USBH_Set_Idle * Set Idle State. * @param phost: Host handle * @param duration: Duration for HID Idle request * @param reportId : Targeted report ID for Set Idle request * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_SetIdle (USBH_HandleTypeDef *phost, uint8_t duration, uint8_t reportId) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_IDLE; phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(phost, 0 , 0 ); }
/** * @brief USBH_Set_Idle * Set Idle State. * @param pdev: Selected device * @param duration: Duration for HID Idle request * @param reportID : Targetted report ID for Set Idle request * @retval USBH_Status : Response for USB Set Idle request */ static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t duration, uint8_t reportId) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_IDLE; phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); }
/** * @brief USBH_HID_GetReport * retreive Set Report * @param phost: Host handle * @param reportType : Report type to be sent * @param reportId : Targeted report ID for Set Report request * @param reportBuff : Report Buffer * @param reportLen : Length of data report to be send * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_GetReport (USBH_HandleTypeDef *phost, uint8_t reportType, uint8_t reportId, uint8_t* reportBuff, uint8_t reportLen) { phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE |\ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_GET_REPORT; phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = reportLen; return USBH_CtlReq(phost, reportBuff , reportLen ); }
USBH_Status USBH_Set_Report (USB_OTG_CORE_HANDLE *pcore, USBH_DEV *pdev, uint8_t intf, uint8_t reportType, uint8_t reportId, uint8_t reportLen, uint8_t* reportBuff) { pdev->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_CLASS; pdev->Control.setup.b.bRequest = USB_HID_SET_REPORT; pdev->Control.setup.b.wValue.w = (reportType << 8 ) | reportId; pdev->Control.setup.b.wIndex.w = intf; pdev->Control.setup.b.wLength.w = reportLen; return USBH_CtlReq(pcore, pdev, reportBuff , reportLen ); }
/** * @brief USBH_Set_Report * Issues Set Report * @param pdev: Selected device * @param reportType : Report type to be sent * @param reportID : Targetted report ID for Set Report request * @param reportLen : Length of data report to be send * @param reportBuff : Report Buffer * @retval USBH_Status : Response for USB Set Idle request */ USBH_Status USBH_Set_Report (USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t reportType, uint8_t reportId, uint8_t reportLen, uint8_t* reportBuff) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_REPORT; phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = reportLen; return USBH_CtlReq(pdev, phost, reportBuff , reportLen ); }
//-------------------------------------------------------------- USBH_Status USBH_GetDescriptor(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t req_type, uint16_t value_idx, uint8_t* buff, uint16_t length ) { phost->Control.setup.b.bmRequestType = USB_D2H | req_type; phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR; phost->Control.setup.b.wValue.w = value_idx; if ((value_idx & 0xff00) == USB_DESC_STRING) { phost->Control.setup.b.wIndex.w = 0x0409; } else { phost->Control.setup.b.wIndex.w = 0; } phost->Control.setup.b.wLength.w = length; return USBH_CtlReq(pdev, phost, buff , length ); }
/** * @brief USBH_GetDescriptor * Issues Descriptor command to the device. Once the response received, * it parses the descriptor and updates the status. * @param phost: Host Handle * @param req_type: Descriptor type * @param value_idx: wValue for the GetDescriptr request * @param buff: Buffer to store the descriptor * @param length: Length of the descriptor * @retval USBH Status */ USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost, uint8_t req_type, uint16_t value_idx, uint8_t* buff, uint16_t length ) { if(phost->RequestState == CMD_SEND) { phost->Control.setup.b.bmRequestType = USB_D2H | req_type; phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR; phost->Control.setup.b.wValue.w = value_idx; if ((value_idx & 0xff00) == USB_DESC_STRING) { phost->Control.setup.b.wIndex.w = 0x0409; } else { phost->Control.setup.b.wIndex.w = 0; } phost->Control.setup.b.wLength.w = length; } return USBH_CtlReq(phost, buff , length ); }
uint8_t USBPTD_SetupStage(USB_OTG_CORE_HANDLE* pcore, USB_SETUP_REQ* req) { // store for later use from another function memcpy(USBPT_LastSetupPacket, pcore->dev.setup_packet, 24); // print for monitoring USBPT_printf("\b\r\n USBPT:SETUP:"); for (uint8_t i = 0; i < 8; i++) { USBPT_printf(" 0x%02X", USBPT_LastSetupPacket[i]); } USBPT_printf("\r\n"); // prepare to be sent to the device memcpy(USBPT_Dev->Control.setup.d8, USBPT_LastSetupPacket, 8); // set address must be handled explicitly if ((req->bmRequest & 0x7F) == (USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD) && req->bRequest == USB_REQ_SET_ADDRESS) { // let the internal code handle it for the device interface USBD_StdDevReq(pcore, req); // pass it to the downstream device USBH_CtlReq_Blocking(&USB_OTG_Core_host, USBPT_Dev, 0, 0, 100); USBD_CtlSendStatus(pcore); // modifiy our host channel to match USBPT_Dev->device_prop.address = (uint8_t)(req->wValue) & 0x7F; USBH_Modify_Channel (&USB_OTG_Core_host, USBPT_Dev->Control.hc_num_in, USBPT_Dev->device_prop.address, 0, 0, 0); USBH_Modify_Channel (&USB_OTG_Core_host, USBPT_Dev->Control.hc_num_out, USBPT_Dev->device_prop.address, 0, 0, 0); // modify all other channels to match for (uint8_t i = 0; i < USBPTH_MAX_LISTENERS; i++) { USBPTH_HC_EP_t* pl = &USBPTH_Listeners[i]; uint8_t hc = pl->hc; if (hc != 0 && hc != HC_ERROR) // if listener is actually allocated { USBH_EpDesc_TypeDef* epDesc = pl->epDesc; uint8_t epType = 0; if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_INTR) { epType = EP_TYPE_INTR; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_BULK) { epType = EP_TYPE_BULK; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_ISOC) { epType = EP_TYPE_ISOC; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_CTRL) { epType = EP_TYPE_CTRL; } USBH_Modify_Channel( &USB_OTG_Core_host, USBPTH_Listeners[i].hc, USBPT_Dev->device_prop.address, USBPT_Dev->device_prop.speed, epType, USBPTH_Listeners[i].epDesc->wMaxPacketSize); } } // note: out direction channels are dynamically allocated only when needed // so we don't need to modify those channel addresses return USBD_OK; } // no data means we can just directly relay the data if (req->wLength == 0) { USBH_CtlReq_Blocking(&USB_OTG_Core_host, USBPT_Dev, 0, 0, 100); USBD_CtlSendStatus(pcore); return USBD_OK; } // there is extra data later USBPT_CtrlDataLen = req->wLength; if (USBPT_CtrlData != 0) free(USBPT_CtrlData); USBPT_CtrlData = malloc(USBPT_CtrlDataLen); USBH_Status status; // wait until previous req is finished delay_1ms_cnt = 100; while (delay_1ms_cnt > 0 && USBPT_Dev->Control.state != CTRL_COMPLETE && USBPT_Dev->Control.state != CTRL_IDLE && USBPT_Dev->Control.state != CTRL_ERROR && USBPT_Dev->Control.state != CTRL_STALLED); { status = USBH_HandleControl(&USB_OTG_Core_host, USBPT_Dev); } // finalize previous ctrl req if (USBPT_Dev->RequestState == CMD_WAIT) { USBH_CtlReq(&USB_OTG_Core_host, USBPT_Dev, 0 , 0 ); } // prepare new setup USBH_SubmitSetupRequest(USBPT_Dev, USBPT_CtrlData, USBPT_CtrlDataLen); USBPT_Dev->RequestState = CMD_WAIT; USBH_CtlSendSetup (&USB_OTG_Core_host, USBPT_Dev->Control.setup.d8, USBPT_Dev->Control.hc_num_out); USBPT_Dev->Control.state = CTRL_SETUP_WAIT; USBPT_Dev->Control.timer = HCD_GetCurrentFrame(pcore); USBPT_Dev->Control.timeout = 50; if ((req->bmRequest & 0x80) == 0) { // H2D // we need to obtain the data from EP0_RxReady first USBD_CtlPrepareRx (pcore, USBPT_CtrlData, USBPT_CtrlDataLen); return USBD_OK; } else { // D2H // wait for request to finish delay_1ms_cnt = 100; do { status = USBH_CtlReq(&USB_OTG_Core_host, USBPT_Dev, USBPT_CtrlData , USBPT_CtrlDataLen ); if (status == USBH_OK || status == USBH_FAIL || status == USBH_STALL || status == USBH_NOT_SUPPORTED) { break; } else { status = USBH_HandleControl(&USB_OTG_Core_host, USBPT_Dev); if (status == USBH_FAIL || status == USBH_STALL || status == USBH_NOT_SUPPORTED) { break; } } } while (delay_1ms_cnt > 0); if (delay_1ms_cnt == 0) { // timeout dbg_printf(DBGMODE_ERR, "USBPT Setup Timed Out \r\n"); USBD_CtlSendStatus(pcore); // we reply with nothing to simulate a timeout return USBH_OK; } else if (status == USBH_OK) { // all good, send back the data USBD_CtlSendData (pcore, USBPT_CtrlData, USBPT_CtrlDataLen); // handle config descriptors specially, we need to know what channels to open based on endpoints if ((req->bmRequest & 0x7F) == (USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD) && req->bRequest == USB_REQ_GET_DESCRIPTOR && req->wValue == USB_DESC_CONFIGURATION && req->wLength > USB_CONFIGURATION_DESC_SIZE) { // this is a full length configuration descriptor // we need this info to open as many D2H endpoints to channels USBH_ParseCfgDesc(&USBPT_Dev->device_prop.Cfg_Desc, USBPT_Dev->device_prop.Itf_Desc, USBPT_Dev->device_prop.Ep_Desc, USBPT_CtrlData, USBPT_CtrlDataLen); USBPTH_OutEPCnt = 0; USBPT_GeneralInDataLen = 0; for (uint8_t i = 0; i < USBPT_Dev->device_prop.Cfg_Desc.bNumInterfaces && i < USBH_MAX_NUM_INTERFACES; i++) { for (uint8_t j = 0; j < USBPT_Dev->device_prop.Itf_Desc[i].bNumEndpoints && j < USBH_MAX_NUM_ENDPOINTS; j++) { USBH_EpDesc_TypeDef* epDesc = &USBPT_Dev->device_prop.Ep_Desc[i][j]; for (uint8_t k = 0; k < USBPTH_MAX_LISTENERS; k++) { if ((epDesc->bEndpointAddress & USB_EP_DIR_MSK) == USB_D2H && USBPTH_Listeners[k].used == 0) { USBPTH_Listeners[k].epDesc = epDesc; uint8_t epType = 0; if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_INTR) { epType = EP_TYPE_INTR; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_BULK) { epType = EP_TYPE_BULK; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_ISOC) { epType = EP_TYPE_ISOC; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_CTRL) { epType = EP_TYPE_CTRL; } USBH_Open_Channel( &USB_OTG_Core_host, &(USBPTH_Listeners[k].hc), epDesc->bEndpointAddress, USBPT_Dev->device_prop.address, USBPT_Dev->device_prop.speed, epType, USBPTH_Listeners[k].epDesc->wMaxPacketSize); if (USBPTH_Listeners[k].hc >= 0) { USBPTH_Listeners[k].used = 1; DCD_EP_Open(&USB_OTG_Core_dev, epDesc->bEndpointAddress, epDesc->wMaxPacketSize, epType); if (epDesc->wMaxPacketSize > USBPT_GeneralInDataMax) { USBPT_GeneralInDataMax = epDesc->wMaxPacketSize; } } } } if ((epDesc->bEndpointAddress & 0x80) == USB_H2D) { USBPTH_OutEPCnt++; } } } if (USBPT_GeneralInData != 0) free(USBPT_GeneralInData); // release memory if previously allocated USBPT_GeneralInData = malloc(USBPT_GeneralInDataMax); // only allocate the memory we need if (USBPTH_OutEP != 0) free(USBPTH_OutEP); // release memory if previously allocated USBPTH_OutEP = malloc(sizeof(USBH_EpDesc_TypeDef*) * USBPTH_OutEPCnt); // only allocate the memory we need uint8_t ec = 0; for (uint8_t i = 0; i < USBPT_Dev->device_prop.Cfg_Desc.bNumInterfaces && i < USBH_MAX_NUM_INTERFACES; i++) { for (uint8_t j = 0; j < USBPT_Dev->device_prop.Itf_Desc[i].bNumEndpoints && j < USBH_MAX_NUM_ENDPOINTS; j++) { USBH_EpDesc_TypeDef* epDesc = &USBPT_Dev->device_prop.Ep_Desc[i][j]; if ((epDesc->bEndpointAddress & 0x80) == USB_H2D) { // only save the H2D direction endpoints USBPTH_OutEP[ec] = epDesc; ec++; } } } } return USBH_OK; } else { if (status == USBH_STALL || status == USBH_NOT_SUPPORTED) { dbg_printf(DBGMODE_ERR, "USBPT Setup Stalled \r\n"); USBD_CtlError(pcore , req); return USBH_OK; } } return USBD_OK; } dbg_printf(DBGMODE_ERR, "USBPT Setup Unhandled Error \r\n"); USBD_CtlError(pcore , req); return USBD_OK; }
uint8_t USBPTD_DataOut (void *pcore , uint8_t epnum) { USB_OTG_CORE_HANDLE* pcore_ = (USB_OTG_CORE_HANDLE*)pcore; DCD_DEV* pdev = &(pcore_->dev); uint8_t* data; uint16_t wLength; if (epnum == 0x00) { // CTRL REQ wLength = USBPT_CtrlDataLen; data = USBPT_CtrlData; } else { wLength = pdev->out_ep[epnum].xfer_count; data = pdev->out_ep[epnum].xfer_buff; } // print to monitor USBPT_printf("USBPT:OUT:EP0x%02X:", epnum); for (uint16_t i = 0; i < wLength; i++) { USBPT_printf(" 0x%02X", data[i]); } USBPT_printf("\r\n"); if (epnum == 0x00) { // CTRL REQ USBH_Status status; delay_1ms_cnt = 100; // wait for transfer complete do { status = USBH_CtlReq(&USB_OTG_Core_host, USBPT_Dev, USBPT_CtrlData , USBPT_CtrlDataLen ); if (status == USBH_OK || status == USBH_FAIL || status == USBH_STALL || status == USBH_NOT_SUPPORTED) { break; } else { status = USBH_HandleControl(&USB_OTG_Core_host, USBPT_Dev); if (status == USBH_FAIL || status == USBH_STALL || status == USBH_NOT_SUPPORTED) { break; } } } while (delay_1ms_cnt > 0); if (delay_1ms_cnt == 0) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut timed out while sending to device, status: 0x%04X \r\n", status); USBD_CtlError(pcore , 0); return USBD_FAIL; } else if (status != USBH_OK) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut failed to send to device, status: 0x%04X \r\n", status); USBD_CtlError(pcore , 0); return USBD_FAIL; } else { // everything is OK USBD_CtlSendStatus(pcore); return USBD_OK; } } else { wLength = pdev->out_ep[epnum].xfer_count; data = pdev->out_ep[epnum].xfer_buff; // allocate memory needed if (USBPT_GeneralOutData != 0) free(USBPT_GeneralOutData); USBPT_GeneralOutDataLen = wLength; USBPT_GeneralOutData = malloc(wLength); memcpy(USBPT_GeneralOutData, data, USBPT_GeneralOutDataLen); USBH_EpDesc_TypeDef* epDesc = 0; for (uint8_t i = 0; i < USBPTH_OutEPCnt; i++) { // look for appropriate EP if (USBPTH_OutEP[i]->bEndpointAddress == epnum) { epDesc = USBPTH_OutEP[i]; break; } } if (epDesc != 0) // EP found { uint8_t epType = 0; int8_t hc = -1; if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_INTR) { epType = EP_TYPE_INTR; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_BULK) { epType = EP_TYPE_BULK; } else if ((epDesc->bmAttributes & USB_EP_TYPE_INTR) == USB_EP_TYPE_ISOC) { epType = EP_TYPE_ISOC; } // dynamically allocate host channel for use if (USBH_Open_Channel( &USB_OTG_Core_host, &hc, epnum, USBPT_Dev->device_prop.address, USBPT_Dev->device_prop.speed, epType, epDesc->wMaxPacketSize) == HC_OK) { // try to only send on even frame volatile uint32_t syncTries = 0x7FFFFFFF; while (USB_OTG_IsEvenFrame(&USB_OTG_Core_host) == 0 && syncTries--) __NOP(); // send using appropriate method switch (epType) { case EP_TYPE_INTR: USBH_InterruptSendData(&USB_OTG_Core_host, USBPT_GeneralOutData, USBPT_GeneralOutDataLen, hc); break; case EP_TYPE_BULK: USBH_BulkSendData(&USB_OTG_Core_host, USBPT_GeneralOutData, USBPT_GeneralOutDataLen, hc); break; case EP_TYPE_ISOC: USBH_IsocSendData(&USB_OTG_Core_host, USBPT_GeneralOutData, USBPT_GeneralOutDataLen, hc); break; default: break; } // wait until done sending USBH_Status status; delay_1ms_cnt = 100; do { URB_STATE us = HCD_GetURB_State(&USB_OTG_Core_host, hc); if (us == URB_DONE) { break; } else if (us == URB_ERROR) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Send Error on EP 0x%02X \r\n", epnum); DCD_EP_Stall(pcore, epnum); break; } else if (us == URB_STALL) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Stalled EP 0x%02X \r\n", epnum); DCD_EP_Stall(pcore, epnum); break; } } while (delay_1ms_cnt > 0); if (delay_1ms_cnt == 0) { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Send Timed Out EP 0x%02X \r\n", epnum); } // free the channel to be used by something else later USBH_Free_Channel(&USB_OTG_Core_host, &hc); } else { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut Failed to Alloc HC for EP 0x%02X \r\n", epnum); } } else { dbg_printf(DBGMODE_ERR, "USBPTD_DataOut No Such EP 0x%02X \r\n", epnum); } return USBD_OK; } return USBD_OK; }