/** * USB CDC class request handler. * This is an internal function. */ static void USB_VirtualCOM_HandleClassRequest() { USB_SetupPacket_t setupPacket; USBD_GetSetupPacket((uint8_t *) &setupPacket); if(setupPacket.bmRequestType & 0x80) { // Transfer direction: device to host switch(setupPacket.bRequest) { case USB_VCOM_REQ_GET_LINE_CODE: if(setupPacket.wIndex == USB_VCOM_INDEX) { // Copy line coding data to USB buffer USBD_MemCopy((uint8_t *) (USBD_BUF_BASE + USB_VCOM_CTRL_IN_BUF_BASE), (uint8_t *) &USB_VirtualCOM_lineCoding, USB_VirtualCOM_LineCoding_t_SIZE); } // Data stage USBD_SET_DATA1(USB_VCOM_CTRL_IN_EP); USBD_SET_PAYLOAD_LEN(USB_VCOM_CTRL_IN_EP, USB_VirtualCOM_LineCoding_t_SIZE); // Status stage USBD_PrepareCtrlOut(NULL, 0); break; default: // Setup error, stall the device USBD_SetStall(USB_VCOM_CTRL_IN_EP); USBD_SetStall(USB_VCOM_CTRL_OUT_EP); break; } } else { // Transfer direction: host to device switch(setupPacket.bRequest) { case USB_VCOM_REQ_SET_CONTROL_LINE_STATE: // Control signals are ignored // Status stage USBD_SET_DATA1(USB_VCOM_CTRL_IN_EP); USBD_SET_PAYLOAD_LEN(USB_VCOM_CTRL_IN_EP, 0); break; case USB_VCOM_REQ_SET_LINE_CODE: if(setupPacket.wIndex == USB_VCOM_INDEX) { // Prepare for line coding copy USBD_PrepareCtrlOut((uint8_t *) &USB_VirtualCOM_lineCoding, USB_VirtualCOM_LineCoding_t_SIZE); } // Status stage USBD_SET_DATA1(USB_VCOM_CTRL_IN_EP); USBD_SET_PAYLOAD_LEN(USB_VCOM_CTRL_IN_EP, 0); break; default: // Setup error, stall the device USBD_SetStall(USB_VCOM_CTRL_IN_EP); USBD_SetStall(USB_VCOM_CTRL_OUT_EP); break; } } }
void CCID_ClassRequest(void) { uint8_t buf[8]; USBD_GetSetupPacket(buf); if (buf[0] & 0x80) /* request data transfer direction */ { // Device to host switch (buf[1]) { case CCID_GET_CLOCK_FREQUENCIES: case CCID_GET_DATA_RATES: { uint8_t pData[1] = {0}; USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)), pData, sizeof(pData)); /* Data stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, sizeof(pData)); /* Status stage */ USBD_PrepareCtrlOut(0,0); break; } default: { /* Setup error, stall the device */ USBD_SetStall(0); break; } } } else { // Host to device switch (buf[1]) { case CCID_ABORT: { /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); break; } default: { // Stall /* Setup error, stall the device */ USBD_SetStall(0); break; } } } }
void PTR_ClassRequest(void) { uint8_t buf[8]; USBD_GetSetupPacket(buf); if (buf[0] & 0x80) { /* request data transfer direction */ // Device to host switch (buf[1]) { case GET_PORT_STATUS: { /* Data stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); /* Status stage */ USBD_PrepareCtrlOut(0,0); break; } default: { /* Setup error, stall the device */ USBD_SetStall(0); break; } } } else { // Host to device switch (buf[1]) { case SET_REPORT: { if (buf[3] == 3) { /* Request Type = Feature */ USBD_SET_DATA1(EP1); USBD_SET_PAYLOAD_LEN(EP1, 0); } break; } case SET_IDLE: { /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); break; } case SET_PROTOCOL: // { // break; // } default: { // Stall /* Setup error, stall the device */ USBD_SetStall(0); break; } } } }
/** * @brief Repeat Control IN pipe * * @param None * * @return None * * @details This function processes the remained data of Control IN transfer. * */ void USBD_CtrlIn(void) { static uint8_t u8ZeroFlag = 0; if(g_usbd_CtrlInSize) { // Process remained data if(g_usbd_CtrlInSize > g_usbd_CtrlMaxPktSize) { // Data size > MXPLD USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlMaxPktSize); USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlMaxPktSize); g_usbd_CtrlInPointer += g_usbd_CtrlMaxPktSize; g_usbd_CtrlInSize -= g_usbd_CtrlMaxPktSize; } else { // Data size <= MXPLD USBD_MemCopy((uint8_t *)USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0), (uint8_t *)g_usbd_CtrlInPointer, g_usbd_CtrlInSize); USBD_SET_PAYLOAD_LEN(EP0, g_usbd_CtrlInSize); if(g_usbd_CtrlInSize == g_usbd_CtrlMaxPktSize) u8ZeroFlag = 1; g_usbd_CtrlInPointer = 0; g_usbd_CtrlInSize = 0; } } else { // In ACK for Set address if((g_usbd_SetupPacket[0] == 0) && (g_usbd_SetupPacket[1] == 5)) { if((USBD_GET_ADDR() != g_usbd_UsbAddr) && (USBD_GET_ADDR() == 0)) { USBD_SET_ADDR(g_usbd_UsbAddr); } } // For size if n x MXPLD if(u8ZeroFlag) { USBD_SET_PAYLOAD_LEN(EP0, 0); u8ZeroFlag = 0; } // No more data for IN token USBD_PrepareCtrlOut(0, 0); DBG_PRINTF("Ctrl In Done.\n"); } }
/** * @brief Process standard request * * @param None * * @return None * * @details Parse standard request and perform the corresponding action. * */ void USBD_StandardRequest(void) { /* clear global variables for new request */ g_usbd_CtrlInPointer = 0; g_usbd_CtrlInSize = 0; if(g_usbd_SetupPacket[0] & 0x80) /* request data transfer direction */ { // Device to host switch(g_usbd_SetupPacket[1]) { case GET_CONFIGURATION: { // Return current configuration setting /* Data stage */ M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbConfig; USBD_SET_DATA1(EP1); USBD_SET_PAYLOAD_LEN(EP1, 0); USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 1); /* Status stage */ USBD_PrepareCtrlOut(0, 0); DBG_PRINTF("Get configuration\n"); break; } case GET_DESCRIPTOR: { USBD_GetDescriptor(); break; } case GET_INTERFACE: { // Return current interface setting /* Data stage */ M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = g_usbd_UsbAltInterface; USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 1); /* Status stage */ USBD_PrepareCtrlOut(0, 0); DBG_PRINTF("Get interface\n"); break; } case GET_STATUS: { // Device if(g_usbd_SetupPacket[0] == 0x80) { uint8_t u8Tmp; u8Tmp = 0; if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x40) u8Tmp |= 1; // Self-Powered/Bus-Powered. if(g_usbd_sInfo->gu8ConfigDesc[7] & 0x20) u8Tmp |= (g_usbd_RemoteWakeupEn << 1); // Remote wake up M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = u8Tmp; } // Interface else if(g_usbd_SetupPacket[0] == 0x81) M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = 0; // Endpoint else if(g_usbd_SetupPacket[0] == 0x82) { uint8_t ep = g_usbd_SetupPacket[4] & 0xF; M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = USBD_GetStall(ep) ? 1 : 0; } M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0) + 1) = 0; /* Data stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 2); /* Status stage */ USBD_PrepareCtrlOut(0, 0); DBG_PRINTF("Get status\n"); break; } default: { /* Setup error, stall the device */ USBD_SET_EP_STALL(EP0); USBD_SET_EP_STALL(EP1); DBG_PRINTF("Unknown request. stall ctrl pipe.\n"); break; } } } else { // Host to device switch(g_usbd_SetupPacket[1]) { case CLEAR_FEATURE: { if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT) { int32_t epNum, i; /* EP number stall is not allow to be clear in MSC class "Error Recovery Test". a flag: g_u32EpStallLock is added to support it */ epNum = g_usbd_SetupPacket[4] & 0xF; for(i = 0; i < USBD_MAX_EP; i++) { if(((USBD->EP[i].CFG & 0xF) == epNum) && ((g_u32EpStallLock & (1 << i)) == 0)) { USBD->EP[i].CFGP &= ~USBD_CFGP_SSTALL_Msk; DBG_PRINTF("Clr stall ep%d %x\n",i, USBD->EP[i].CFGP); } } } else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP) g_usbd_RemoteWakeupEn = 0; /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); DBG_PRINTF("Clear feature op %d\n", g_usbd_SetupPacket[2]); break; } case SET_ADDRESS: { g_usbd_UsbAddr = g_usbd_SetupPacket[2]; DBG_PRINTF("Set addr to %d\n", g_usbd_UsbAddr); // DATA IN for end of setup /* Status Stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); break; } case SET_CONFIGURATION: { g_usbd_UsbConfig = g_usbd_SetupPacket[2]; if(g_usbd_pfnSetConfigCallback) g_usbd_pfnSetConfigCallback(); // DATA IN for end of setup /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); DBG_PRINTF("Set config to %d\n", g_usbd_UsbConfig); break; } case SET_FEATURE: { if(g_usbd_SetupPacket[2] == FEATURE_ENDPOINT_HALT) { USBD_SetStall(g_usbd_SetupPacket[4] & 0xF); DBG_PRINTF("Set feature. stall ep %d\n", g_usbd_SetupPacket[4] & 0xF); } else if(g_usbd_SetupPacket[2] == FEATURE_DEVICE_REMOTE_WAKEUP) { g_usbd_RemoteWakeupEn = 1; DBG_PRINTF("Set feature. enable remote wakeup\n"); } /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); break; } case SET_INTERFACE: { g_usbd_UsbAltInterface = g_usbd_SetupPacket[2]; if(g_usbd_pfnSetInterface != NULL) g_usbd_pfnSetInterface(); /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); DBG_PRINTF("Set interface to %d\n", g_usbd_UsbAltInterface); break; } default: { /* Setup error, stall the device */ USBD_SET_EP_STALL(EP0); USBD_SET_EP_STALL(EP1); DBG_PRINTF("Unsupported request. stall ctrl pipe.\n"); break; } } } }
/** * @brief Process GetDescriptor request * * @param None * * @return None * * @details Parse GetDescriptor request and perform the corresponding action. * */ void USBD_GetDescriptor(void) { uint32_t u32Len; u32Len = 0; u32Len = g_usbd_SetupPacket[7]; u32Len <<= 8; u32Len += g_usbd_SetupPacket[6]; switch(g_usbd_SetupPacket[3]) { // Get Device Descriptor case DESC_DEVICE: { u32Len = Minimum(u32Len, LEN_DEVICE); DBG_PRINTF("Get device desc, %d\n", u32Len); USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8DevDesc, u32Len); USBD_PrepareCtrlOut(0, 0); break; } // Get Configuration Descriptor case DESC_CONFIG: { uint32_t u32TotalLen; u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[3]; u32TotalLen = g_usbd_sInfo->gu8ConfigDesc[2] + (u32TotalLen << 8); DBG_PRINTF("Get config desc len %d, acture len %d\n", u32Len, u32TotalLen); u32Len = Minimum(u32Len, u32TotalLen); DBG_PRINTF("Minimum len %d\n", u32Len); USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8ConfigDesc, u32Len); USBD_PrepareCtrlOut(0, 0); break; } // Get HID Descriptor case DESC_HID: { int32_t i32IfNum; int32_t i32TotalSize; int32_t i32Idx; uint8_t *pu8HidDesc; int32_t i32Size = 0; // Get total size of configuration descriptor i32TotalSize = g_usbd_sInfo->gu8ConfigDesc[3]; i32TotalSize = (i32TotalSize << 8) | g_usbd_sInfo->gu8ConfigDesc[2]; // Get requested HID interface i32IfNum = g_usbd_SetupPacket[4]; // Search specified HID descriptor in configuration descritpor pu8HidDesc = NULL; i32Idx = 1; do{ // Search interface first and check HID class code (0x3) and check requested interface number if((g_usbd_sInfo->gu8ConfigDesc[i32Idx] == DESC_INTERFACE) && (g_usbd_sInfo->gu8ConfigDesc[i32Idx+4] == 0x3) && (g_usbd_sInfo->gu8ConfigDesc[i32Idx+1] == i32IfNum)) { // Calculate the offset of the requested HID descriptor in configuration descriptor i32Idx = i32Idx-1+g_usbd_sInfo->gu8ConfigDesc[i32Idx-1]; pu8HidDesc = (uint8_t *)&g_usbd_sInfo->gu8ConfigDesc[i32Idx]; i32Size = pu8HidDesc[0]; DBG_PRINTF("HID desc at if=%d, offset=%d\n", i32IfNum, i32Idx); break; } else i32Idx += g_usbd_sInfo->gu8ConfigDesc[i32Idx-1]; // Seek to next descriptor }while(i32Idx < i32TotalSize); if(pu8HidDesc) { u32Len = Minimum(u32Len, i32Size); USBD_PrepareCtrlIn(pu8HidDesc, u32Len); USBD_PrepareCtrlOut(0, 0); } else { // No any HID descriptor found. Just stall. USBD_SET_EP_STALL(EP0); USBD_SET_EP_STALL(EP1); DBG_PRINTF("No HID desc found. stall ctrl pipe\n"); } break; } // Get Report Descriptor case DESC_HID_RPT: { uint32_t u32RptDescLen; uint8_t *pu8RptDesc; if(g_usbd_pfnGetHidReportCallback) pu8RptDesc = g_usbd_pfnGetHidReportCallback(g_usbd_SetupPacket[4] ,&u32RptDescLen); else { pu8RptDesc = (uint8_t *)g_usbd_sInfo->gu8HidReportDesc; u32RptDescLen = u32Len; } if(pu8RptDesc) { u32Len = Minimum(u32Len, u32RptDescLen); DBG_PRINTF("Get report desc %d\n", u32Len); USBD_PrepareCtrlIn(pu8RptDesc, u32Len); USBD_PrepareCtrlOut(0, 0); } else { USBD_SET_EP_STALL(EP0); USBD_SET_EP_STALL(EP1); DBG_PRINTF("No HID report. stall ctrl pipe\n"); } break; } // Get String Descriptor case DESC_STRING: { // Get String Descriptor if(g_usbd_SetupPacket[2] < 4) { u32Len = Minimum(u32Len, g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]][0]); DBG_PRINTF("Get string desc %d\n", u32Len); USBD_PrepareCtrlIn((uint8_t *)g_usbd_sInfo->gu8StringDesc[g_usbd_SetupPacket[2]], u32Len); USBD_PrepareCtrlOut(0, 0); break; } else { // Not support. Reply STALL. USBD_SET_EP_STALL(EP0); USBD_SET_EP_STALL(EP1); DBG_PRINTF("Unsupported string desc (%d). Stall ctrl pipe.\n", g_usbd_SetupPacket[2]); break; } } default: // Not support. Reply STALL. USBD_SET_EP_STALL(EP0); USBD_SET_EP_STALL(EP1); DBG_PRINTF("Unsupported get desc type. stall ctrl pipe\n"); break; } }
void HID_ClassRequest(void) { uint8_t buf[8]; USBD_GetSetupPacket(buf); if (buf[0] & 0x80) /* request data transfer direction */ { // Device to host switch (buf[1]) { case GET_LINE_CODE: { if (buf[4] == 0) /* VCOM-1 */ { USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)), (uint8_t *)&gLineCoding, 7); } /* Data stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 7); /* Status stage */ USBD_PrepareCtrlOut(0,0); break; } case GET_REPORT: case GET_IDLE: case GET_PROTOCOL: default: { /* Setup error, stall the device */ USBD_SetStall(0); break; } } } else { // Host to device switch (buf[1]) { case SET_CONTROL_LINE_STATE: { if (buf[4] == 0) /* VCOM-1 */ { gCtrlSignal = buf[3]; gCtrlSignal = (gCtrlSignal << 8) | buf[2]; //printf("RTS=%d DTR=%d\n", (gCtrlSignal0 >> 1) & 1, gCtrlSignal0 & 1); } /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); break; } case SET_LINE_CODE: { //g_usbd_UsbConfig = 0100; if (buf[4] == 0) /* VCOM-1 */ USBD_PrepareCtrlOut((uint8_t *)&gLineCoding, 7); /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); // /* UART setting */ // if (buf[4] == 0) /* VCOM-1 */ // VCOM_LineCoding(0); break; } case SET_REPORT: { if(buf[3] == 2) { /* Request Type = Output */ USBD_SET_DATA1(EP1); USBD_SET_PAYLOAD_LEN(EP1, buf[6]); /* Trigger for HID Int in */ USBD_SET_PAYLOAD_LEN(EP5, 0); /* Status stage */ USBD_PrepareCtrlIn(0, 0); } break; } case SET_IDLE: { /* Status stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); break; } case SET_PROTOCOL: default: { // Stall /* Setup error, stall the device */ USBD_SetStall(0); break; } } } }
void MSC_ClassRequest(void) { uint8_t buf[8]; USBD_GetSetupPacket(buf); if (buf[0] & 0x80) /* request data transfer direction */ { // Device to host switch (buf[1]) { case GET_MAX_LUN: { /* Check interface number with cfg descriptor and check wValue = 0, wLength = 1 */ if ((((buf[3]<<8)+buf[2]) == 0) && (((buf[5]<<8)+buf[4]) == 0) && (((buf[7]<<8)+buf[6]) == 1)) { M8(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(EP0)) = 0; /* Data stage */ USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 1); /* Status stage */ USBD_PrepareCtrlOut(0,0); } else /* Invalid Get MaxLun command */ { USBD_SetStall(0); } break; } default: { /* Setup error, stall the device */ USBD_SetStall(0); break; } } } else { // Host to device switch (buf[1]) { case BULK_ONLY_MASS_STORAGE_RESET: { /* Check interface number with cfg descriptor and check wValue = 0, wLength = 0 */ if ((((buf[3]<<8)+buf[2]) == 0) && (((buf[5]<<8)+buf[4]) == 0) && (((buf[7]<<8)+buf[6]) == 0)) { USBD_SET_DATA1(EP0); USBD_SET_PAYLOAD_LEN(EP0, 0); USBD_LockEpStall(0); /* Clear ready */ USBD->EP[EP2].CFG |= USBD_CFG_CLRRDY_Msk; USBD->EP[EP3].CFG |= USBD_CFG_CLRRDY_Msk; /* Prepare to receive the CBW */ g_u8EP3Ready = 0; g_u8BulkState = BULK_CBW; USBD_SET_DATA1(EP3); USBD_SET_EP_BUF_ADDR(EP3, g_u32BulkBuf0); USBD_SET_PAYLOAD_LEN(EP3, EP3_MAX_PKT_SIZE); } else /* Invalid Reset command */ { USBD_SetStall(0); } break; } default: { // Stall /* Setup error, stall the device */ USBD_SetStall(0); break; } } } }