diff options
Diffstat (limited to 'drivers/usb/gadget/f_fastboot.c')
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 85 |
1 files changed, 80 insertions, 5 deletions
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index d1d087e12b..950cc11949 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -46,6 +46,25 @@ struct f_fastboot { struct usb_request *in_req, *out_req; }; +static char fb_ext_prop_name[] = "DeviceInterfaceGUID"; +static char fb_ext_prop_data[] = "{4866319A-F4D6-4374-93B9-DC2DEB361BA9}"; + +static struct usb_os_desc_ext_prop fb_ext_prop = { + .type = 1, /* NUL-terminated Unicode String (REG_SZ) */ + .name = fb_ext_prop_name, + .data = fb_ext_prop_data, +}; + +/* 16 bytes of "Compatible ID" and "Subcompatible ID" */ +static char fb_cid[16] = {'W', 'I', 'N', 'U', 'S', 'B'}; +static struct usb_os_desc fb_os_desc = { + .ext_compat_id = fb_cid, +}; + +static struct usb_os_desc_table fb_os_desc_table = { + .os_desc = &fb_os_desc, +}; + static inline struct f_fastboot *func_to_fastboot(struct usb_function *f) { return container_of(f, struct f_fastboot, usb_function); @@ -109,10 +128,45 @@ static struct usb_descriptor_header *fb_hs_function[] = { NULL, }; +/* Super speed */ +static struct usb_endpoint_descriptor ss_ep_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_ep_out = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor fb_ss_bulk_comp_desc = { + .bLength = sizeof(fb_ss_bulk_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *fb_ss_function[] = { + (struct usb_descriptor_header *)&interface_desc, + (struct usb_descriptor_header *)&ss_ep_in, + (struct usb_descriptor_header *)&fb_ss_bulk_comp_desc, + (struct usb_descriptor_header *)&ss_ep_out, + (struct usb_descriptor_header *)&fb_ss_bulk_comp_desc, + NULL, +}; + static struct usb_endpoint_descriptor * fb_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs) + struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *ss) { + if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER) + return ss; + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return hs; return fs; @@ -161,6 +215,19 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) return id; interface_desc.bInterfaceNumber = id; + /* Enable OS and Extended Properties Feature Descriptor */ + c->cdev->use_os_string = 1; + f->os_desc_table = &fb_os_desc_table; + f->os_desc_n = 1; + f->os_desc_table->if_id = id; + INIT_LIST_HEAD(&fb_os_desc.ext_prop); + fb_ext_prop.name_len = strlen(fb_ext_prop.name) * 2 + 2; + fb_os_desc.ext_prop_len = 10 + fb_ext_prop.name_len; + fb_os_desc.ext_prop_count = 1; + fb_ext_prop.data_len = strlen(fb_ext_prop.data) * 2 + 2; + fb_os_desc.ext_prop_len += fb_ext_prop.data_len + 4; + list_add_tail(&fb_ext_prop.entry, &fb_os_desc.ext_prop); + id = usb_string_id(c->cdev); if (id < 0) return id; @@ -187,6 +254,12 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) f->hs_descriptors = fb_hs_function; } + if (gadget_is_superspeed(gadget)) { + ss_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress; + ss_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress; + f->ss_descriptors = fb_ss_function; + } + s = env_get("serial#"); if (s) g_dnl_set_serialnumber((char *)s); @@ -196,6 +269,8 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f) { + f->os_desc_table = NULL; + list_del(&fb_os_desc.ext_prop); memset(fastboot_func, 0, sizeof(*fastboot_func)); } @@ -249,7 +324,7 @@ static int fastboot_set_alt(struct usb_function *f, debug("%s: func: %s intf: %d alt: %d\n", __func__, f->name, interface, alt); - d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out); + d = fb_ep_desc(gadget, &fs_ep_out, &hs_ep_out, &ss_ep_out); ret = usb_ep_enable(f_fb->out_ep, d); if (ret) { puts("failed to enable out ep\n"); @@ -264,7 +339,7 @@ static int fastboot_set_alt(struct usb_function *f, } f_fb->out_req->complete = rx_handler_command; - d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in); + d = fb_ep_desc(gadget, &fs_ep_in, &hs_ep_in, &ss_ep_in); ret = usb_ep_enable(f_fb->in_ep, d); if (ret) { puts("failed to enable in ep\n"); @@ -315,7 +390,7 @@ static int fastboot_add(struct usb_configuration *c) status = usb_add_function(c, &f_fb->usb_function); if (status) { free(f_fb); - fastboot_func = f_fb; + fastboot_func = NULL; } return status; @@ -352,7 +427,7 @@ static unsigned int rx_bytes_expected(struct usb_ep *ep) { int rx_remain = fastboot_data_remaining(); unsigned int rem; - unsigned int maxpacket = ep->maxpacket; + unsigned int maxpacket = usb_endpoint_maxp(ep->desc); if (rx_remain <= 0) return 0; |