/* ******************************************************************************* * do_usb_req_get_descriptor * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_get_descriptor(struct usb_device_request *req, uchar *buffer) { int ret = SUNXI_USB_REQ_SUCCESSED; //获取描述符 switch(req->wValue >> 8) { case USB_DT_DEVICE: //设备描述符 { struct usb_device_descriptor *dev_dscrptr; sunxi_usb_dbg("get device descriptor\n"); dev_dscrptr = (struct usb_device_descriptor *)buffer; memset((void *)dev_dscrptr, 0, sizeof(struct usb_device_descriptor)); dev_dscrptr->bLength = MIN(req->wLength, sizeof (struct usb_device_descriptor)); dev_dscrptr->bDescriptorType = USB_DT_DEVICE; #ifdef CONFIG_USB_1_1_DEVICE dev_dscrptr->bcdUSB = 0x110; #else dev_dscrptr->bcdUSB = 0x200; #endif dev_dscrptr->bDeviceClass = 0xff; //设备类:大容量存储 dev_dscrptr->bDeviceSubClass = 0xff; dev_dscrptr->bDeviceProtocol = 0xff; dev_dscrptr->bMaxPacketSize0 = 0x40; dev_dscrptr->idVendor = DEVICE_VENDOR_ID; dev_dscrptr->idProduct = DEVICE_PRODUCT_ID; dev_dscrptr->bcdDevice = DEVICE_BCD; dev_dscrptr->iManufacturer = SUNXI_FASTBOOT_DEVICE_STRING_MANUFACTURER_INDEX; dev_dscrptr->iProduct = SUNXI_FASTBOOT_DEVICE_STRING_PRODUCT_INDEX; dev_dscrptr->iSerialNumber = SUNXI_FASTBOOT_DEVICE_STRING_SERIAL_NUMBER_INDEX; dev_dscrptr->bNumConfigurations = 1; sunxi_udc_send_setup(dev_dscrptr->bLength, buffer); } break; case USB_DT_CONFIG: //配置描述符 { struct usb_configuration_descriptor *config_dscrptr; struct usb_interface_descriptor *inter_dscrptr; struct usb_endpoint_descriptor *ep_in, *ep_out; unsigned char bytes_remaining = req->wLength; unsigned char bytes_total = 0; sunxi_usb_dbg("get config descriptor\n"); bytes_total = sizeof (struct usb_configuration_descriptor) + \ sizeof (struct usb_interface_descriptor) + \ sizeof (struct usb_endpoint_descriptor) + \ sizeof (struct usb_endpoint_descriptor); memset(buffer, 0, bytes_total); config_dscrptr = (struct usb_configuration_descriptor *)(buffer + 0); inter_dscrptr = (struct usb_interface_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor)); ep_in = (struct usb_endpoint_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor) + \ sizeof(struct usb_interface_descriptor)); ep_out = (struct usb_endpoint_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor) + \ sizeof(struct usb_interface_descriptor) + \ sizeof(struct usb_endpoint_descriptor)); /* configuration */ config_dscrptr->bLength = MIN(bytes_remaining, sizeof (struct usb_configuration_descriptor)); config_dscrptr->bDescriptorType = USB_DT_CONFIG; config_dscrptr->wTotalLength = bytes_total; config_dscrptr->bNumInterfaces = 1; config_dscrptr->bConfigurationValue = 1; config_dscrptr->iConfiguration = SUNXI_FASTBOOT_DEVICE_STRING_CONFIG_INDEX; config_dscrptr->bmAttributes = 0xC0; config_dscrptr->bMaxPower = 0xFA; //最大电流500ms(0xfa * 2) bytes_remaining -= config_dscrptr->bLength; /* interface */ inter_dscrptr->bLength = MIN (bytes_remaining, sizeof(struct usb_interface_descriptor)); inter_dscrptr->bDescriptorType = USB_DT_INTERFACE; inter_dscrptr->bInterfaceNumber = 0x00; inter_dscrptr->bAlternateSetting = 0x00; inter_dscrptr->bNumEndpoints = 0x02; inter_dscrptr->bInterfaceClass = 0xff; //fastboot storage inter_dscrptr->bInterfaceSubClass = FASTBOOT_INTERFACE_SUB_CLASS; inter_dscrptr->bInterfaceProtocol = FASTBOOT_INTERFACE_PROTOCOL; inter_dscrptr->iInterface = SUNXI_FASTBOOT_DEVICE_STRING_INTERFACE_INDEX; bytes_remaining -= inter_dscrptr->bLength; /* ep_in */ ep_in->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor)); ep_in->bDescriptorType = USB_DT_ENDPOINT; ep_in->bEndpointAddress = sunxi_udc_get_ep_in_type(); /* IN */ ep_in->bmAttributes = USB_ENDPOINT_XFER_BULK; ep_in->wMaxPacketSize = sunxi_udc_get_ep_max(); ep_in->bInterval = 0x00; bytes_remaining -= ep_in->bLength; /* ep_out */ ep_out->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor)); ep_out->bDescriptorType = USB_DT_ENDPOINT; ep_out->bEndpointAddress = sunxi_udc_get_ep_out_type(); /* OUT */ ep_out->bmAttributes = USB_ENDPOINT_XFER_BULK; ep_out->wMaxPacketSize = sunxi_udc_get_ep_max(); ep_out->bInterval = 0x00; bytes_remaining -= ep_out->bLength; sunxi_udc_send_setup(MIN(req->wLength, bytes_total), buffer); } break; case USB_DT_STRING: { unsigned char bLength = 0; unsigned char string_index = req->wValue & 0xff; sunxi_usb_dbg("get string descriptor\n"); /* Language ID */ if(string_index == 0) { bLength = MIN(4, req->wLength); sunxi_udc_send_setup(bLength, (void *)sunxi_usb_fastboot_dev[0]); } else if(string_index < SUNXI_USB_FASTBOOT_DEV_MAX) { /* Size of string in chars */ unsigned char i = 0; unsigned char str_length = strlen ((const char *)sunxi_usb_fastboot_dev[string_index]); unsigned char bLength = 2 + (2 * str_length); buffer[0] = bLength; /* length */ buffer[1] = USB_DT_STRING; /* descriptor = string */ /* Copy device string to fifo, expand to simple unicode */ for(i = 0; i < str_length; i++) { buffer[2+ 2*i + 0] = sunxi_usb_fastboot_dev[string_index][i]; buffer[2+ 2*i + 1] = 0; } bLength = MIN(bLength, req->wLength); sunxi_udc_send_setup(bLength, buffer); } else { printf("sunxi usb err: string line %d is not supported\n", string_index); } } break; case USB_DT_DEVICE_QUALIFIER: { #ifdef CONFIG_USB_1_1_DEVICE /* This is an invalid request for usb 1.1, nak it */ USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); #else struct usb_qualifier_descriptor *qua_dscrpt; sunxi_usb_dbg("get qualifier descriptor\n"); qua_dscrpt = (struct usb_qualifier_descriptor *)buffer; memset(&buffer, 0, sizeof(struct usb_qualifier_descriptor)); qua_dscrpt->bLength = MIN(req->wLength, sizeof(sizeof(struct usb_qualifier_descriptor))); qua_dscrpt->bDescriptorType = USB_DT_DEVICE_QUALIFIER; qua_dscrpt->bcdUSB = 0x200; qua_dscrpt->bDeviceClass = 0xff; qua_dscrpt->bDeviceSubClass = 0xff; qua_dscrpt->bDeviceProtocol = 0xff; qua_dscrpt->bMaxPacketSize0 = 0x40; qua_dscrpt->bNumConfigurations = 1; qua_dscrpt->bRESERVED = 0; sunxi_udc_send_setup(qua_dscrpt->bLength, buffer); #endif } break; default: printf("err: unkown wValue(%d)\n", req->wValue); ret = SUNXI_USB_REQ_OP_ERR; } return ret; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int ep0_recv_op(void) { u32 old_ep_index = 0; int ret = 0; static uint ep0_stage = 0; if(!ep0_stage) { memset(&sunxi_udc_source.standard_reg, 0, sizeof(struct usb_device_request)); } old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_CTRL_EP_INDEX); //clear stall status if(USBC_Dev_IsEpStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0)) { printf("ERR: handle_ep0: ep0 stall\n"); USBC_Dev_EpClearStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); ret = -1; goto __ep0_recv_op_err; } //clear setup end if (USBC_Dev_Ctrl_IsSetupEnd(sunxi_udc_source.usbc_hd)) { USBC_Dev_Ctrl_ClearSetupEnd(sunxi_udc_source.usbc_hd); } //检查读ep0数据是否完成 if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0)) { uint status; if(!ep0_stage) { status = __usb_read_ep0_data(&sunxi_udc_source.standard_reg, ep0_stage); } else { status = __usb_read_ep0_data(sunxi_usb_ep0_buffer, ep0_stage); } if(status!= 0) { printf("sunxi usb err: read_request failed\n"); ret = -1; goto __ep0_recv_op_err; } } else //此情况通常由于ep0发送空包引起,可以不处理 { sunxi_usb_dbg("sunxi usb msg: ep0 rx data is not ready\n"); goto __ep0_recv_op_err; } /* Check data */ if(USB_REQ_TYPE_STANDARD == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_TYPE_MASK)) { ret = SUNXI_USB_REQ_UNMATCHED_COMMAND; /* standard */ switch(sunxi_udc_source.standard_reg.bRequest) { case USB_REQ_GET_STATUS: // 0x00 { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_STATUS, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } break; } case USB_REQ_CLEAR_FEATURE: // 0x01 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_CLEAR_FEATURE, &sunxi_udc_source.standard_reg, NULL); } break; } case USB_REQ_SET_FEATURE: // 0x03 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_FEATURE, &sunxi_udc_source.standard_reg, NULL); } break; } case USB_REQ_SET_ADDRESS: // 0x05 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { /* receiver is device */ ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_ADDRESS, &sunxi_udc_source.standard_reg, NULL); } } break; } case USB_REQ_GET_DESCRIPTOR: // 0x06 { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_DESCRIPTOR, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_SET_DESCRIPTOR: // 0x07 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { //there is some problem ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_DESCRIPTOR, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_GET_CONFIGURATION: // 0x08 { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_CONFIGURATION, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_SET_CONFIGURATION: // 0x09 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_CONFIGURATION, &sunxi_udc_source.standard_reg, NULL); } } break; } case USB_REQ_GET_INTERFACE: // 0x0a { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_INTERFACE, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_SET_INTERFACE: // 0x0b { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_INTERFACE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_INTERFACE, &sunxi_udc_source.standard_reg, NULL); } } break; } case USB_REQ_SYNCH_FRAME: // 0x0b { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_INTERFACE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { //there is some problem if(!ep0_stage) { ep0_stage = 1; } else { ret = sunxi_udev_active->standard_req_op(USB_REQ_SYNCH_FRAME, &sunxi_udc_source.standard_reg, NULL); ep0_stage = 0; } } } break; } default: { printf("sunxi usb err: unknown usb out request to device\n"); USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED; ep0_stage = 0; break; } } } else { /* Non-Standard Req */ printf("non standard req\n"); ret = sunxi_udev_active->nonstandard_req_op(USB_REQ_GET_STATUS, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer, ep0_stage); if(ret == SUNXI_USB_REQ_DATA_HUNGRY) { ep0_stage = 1; } else if(ret == SUNXI_USB_REQ_SUCCESSED) { ep0_stage = 0; } else if(ret < 0) { ep0_stage = 0; printf("err: unkown bmRequestType(%d)\n", sunxi_udc_source.standard_reg.bmRequestType); USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); } } __ep0_recv_op_err: USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index); return ret; }
/* ******************************************************************************* * do_usb_req_get_descriptor * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_get_descriptor(struct usb_device_request *req, uchar *buffer) { int ret = SUNXI_USB_REQ_SUCCESSED; //获取描述符 switch(req->wValue >> 8) { case USB_DT_DEVICE: //设备描述符 { struct usb_device_descriptor *dev_dscrptr; sunxi_usb_dbg("get device descriptor\n"); dev_dscrptr = (struct usb_device_descriptor *)buffer; memset((void *)dev_dscrptr, 0, sizeof(struct usb_device_descriptor)); dev_dscrptr->bLength = MIN(req->wLength, sizeof (struct usb_device_descriptor)); dev_dscrptr->bDescriptorType = USB_DT_DEVICE; #ifdef CONFIG_USB_1_1_DEVICE dev_dscrptr->bcdUSB = 0x110; #else dev_dscrptr->bcdUSB = 0x200; #endif dev_dscrptr->bDeviceClass = 0; dev_dscrptr->bDeviceSubClass = 0; dev_dscrptr->bDeviceProtocol = 0; dev_dscrptr->bMaxPacketSize0 = 0x40; dev_dscrptr->idVendor = DRIVER_VENDOR_ID; dev_dscrptr->idProduct = DRIVER_PRODUCT_ID; dev_dscrptr->bcdDevice = 0xffff; //ignored //dev_dscrptr->iManufacturer = SUNXI_USB_STRING_IMANUFACTURER; //dev_dscrptr->iProduct = SUNXI_USB_STRING_IPRODUCT; //dev_dscrptr->iSerialNumber = SUNXI_USB_STRING_ISERIALNUMBER; dev_dscrptr->iManufacturer = 0; dev_dscrptr->iProduct = 0; dev_dscrptr->iSerialNumber = 0; dev_dscrptr->bNumConfigurations = 1; sunxi_udc_send_setup(dev_dscrptr->bLength, buffer); } break; case USB_DT_CONFIG: //配置描述符 { struct usb_configuration_descriptor *config_dscrptr; struct usb_interface_descriptor *inter_dscrptr; struct usb_endpoint_descriptor *ep_in, *ep_out; unsigned char bytes_remaining = req->wLength; unsigned char bytes_total = 0; sunxi_usb_dbg("get config descriptor\n"); bytes_total = sizeof (struct usb_configuration_descriptor) + \ sizeof (struct usb_interface_descriptor) + \ sizeof (struct usb_endpoint_descriptor) + \ sizeof (struct usb_endpoint_descriptor); memset(buffer, 0, bytes_total); config_dscrptr = (struct usb_configuration_descriptor *)(buffer + 0); inter_dscrptr = (struct usb_interface_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor)); ep_in = (struct usb_endpoint_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor) + \ sizeof(struct usb_interface_descriptor)); ep_out = (struct usb_endpoint_descriptor *)(buffer + \ sizeof(struct usb_configuration_descriptor) + \ sizeof(struct usb_interface_descriptor) + \ sizeof(struct usb_endpoint_descriptor)); /* configuration */ config_dscrptr->bLength = MIN(bytes_remaining, sizeof (struct usb_configuration_descriptor)); config_dscrptr->bDescriptorType = USB_DT_CONFIG; config_dscrptr->wTotalLength = bytes_total; config_dscrptr->bNumInterfaces = 1; config_dscrptr->bConfigurationValue = 1; config_dscrptr->iConfiguration = 0; config_dscrptr->bmAttributes = 0x80; //not self powered config_dscrptr->bMaxPower = 0xFA; //最大电流500ms(0xfa * 2) bytes_remaining -= config_dscrptr->bLength; /* interface */ inter_dscrptr->bLength = MIN (bytes_remaining, sizeof(struct usb_interface_descriptor)); inter_dscrptr->bDescriptorType = USB_DT_INTERFACE; inter_dscrptr->bInterfaceNumber = 0x00; inter_dscrptr->bAlternateSetting = 0x00; inter_dscrptr->bNumEndpoints = 0x02; inter_dscrptr->bInterfaceClass = 0xff; inter_dscrptr->bInterfaceSubClass = 0xff; inter_dscrptr->bInterfaceProtocol = 0xff; inter_dscrptr->iInterface = 0; bytes_remaining -= inter_dscrptr->bLength; /* ep_in */ ep_in->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor)); ep_in->bDescriptorType = USB_DT_ENDPOINT; ep_in->bEndpointAddress = sunxi_udc_get_ep_in_type(); /* IN */ ep_in->bmAttributes = USB_ENDPOINT_XFER_BULK; ep_in->wMaxPacketSize = sunxi_udc_get_ep_max(); ep_in->bInterval = 0x00; bytes_remaining -= ep_in->bLength; /* ep_out */ ep_out->bLength = MIN (bytes_remaining, sizeof (struct usb_endpoint_descriptor)); ep_out->bDescriptorType = USB_DT_ENDPOINT; ep_out->bEndpointAddress = sunxi_udc_get_ep_out_type(); /* OUT */ ep_out->bmAttributes = USB_ENDPOINT_XFER_BULK; ep_out->wMaxPacketSize = sunxi_udc_get_ep_max(); ep_out->bInterval = 0x00; bytes_remaining -= ep_out->bLength; sunxi_udc_send_setup(MIN(req->wLength, bytes_total), buffer); } break; case USB_DT_STRING: { unsigned char bLength = 0; unsigned char string_index = req->wValue & 0xff; sunxi_usb_dbg("get string descriptor\n"); /* Language ID */ if(string_index == 0) { bLength = MIN(4, req->wLength); buffer[0] = bLength; buffer[1] = USB_DT_STRING; buffer[2] = 9; buffer[3] = 4; sunxi_udc_send_setup(bLength, (void *)buffer); } else { printf("sunxi usb err: string line %d is not supported\n", string_index); } } break; case USB_DT_DEVICE_QUALIFIER: { #ifdef CONFIG_USB_1_1_DEVICE /* This is an invalid request for usb 1.1, nak it */ USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); #else struct usb_qualifier_descriptor *qua_dscrpt; sunxi_usb_dbg("get qualifier descriptor\n"); qua_dscrpt = (struct usb_qualifier_descriptor *)buffer; memset(&buffer, 0, sizeof(struct usb_qualifier_descriptor)); qua_dscrpt->bLength = MIN(req->wLength, sizeof(sizeof(struct usb_qualifier_descriptor))); qua_dscrpt->bDescriptorType = USB_DT_DEVICE_QUALIFIER; qua_dscrpt->bcdUSB = 0x200; qua_dscrpt->bDeviceClass = 0xff; qua_dscrpt->bDeviceSubClass = 0xff; qua_dscrpt->bDeviceProtocol = 0xff; qua_dscrpt->bMaxPacketSize0 = 0x40; qua_dscrpt->bNumConfigurations = 1; qua_dscrpt->breserved = 0; sunxi_udc_send_setup(qua_dscrpt->bLength, buffer); #endif } break; default: printf("err: unkown wValue(%d)\n", req->wValue); ret = SUNXI_USB_REQ_OP_ERR; } return ret; }