diff --git a/drivers/usb/gadget/function/f_ccid.c b/drivers/usb/gadget/function/f_ccid.c index 1a281833eadd..9523d67dfb15 100644 --- a/drivers/usb/gadget/function/f_ccid.c +++ b/drivers/usb/gadget/function/f_ccid.c @@ -206,6 +206,71 @@ static struct usb_descriptor_header *ccid_hs_descs[] = { NULL, }; +/* Super speed support: */ +static struct usb_endpoint_descriptor ccid_ss_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(CCID_NOTIFY_MAXPACKET), + .bInterval = CCID_NOTIFY_INTERVAL + 4, +}; + +static struct usb_ss_ep_comp_descriptor ccid_ss_notify_comp_desc = { + .bLength = sizeof(ccid_ss_notify_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_endpoint_descriptor ccid_ss_in_desc = { + .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_ss_ep_comp_descriptor ccid_ss_in_comp_desc = { + .bLength = sizeof(ccid_ss_in_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_endpoint_descriptor ccid_ss_out_desc = { + .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 ccid_ss_out_comp_desc = { + .bLength = sizeof(ccid_ss_out_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *ccid_ss_descs[] = { + (struct usb_descriptor_header *) &ccid_interface_desc, + (struct usb_descriptor_header *) &ccid_class_desc, + (struct usb_descriptor_header *) &ccid_ss_notify_desc, + (struct usb_descriptor_header *) &ccid_ss_notify_comp_desc, + (struct usb_descriptor_header *) &ccid_ss_in_desc, + (struct usb_descriptor_header *) &ccid_ss_in_comp_desc, + (struct usb_descriptor_header *) &ccid_ss_out_desc, + (struct usb_descriptor_header *) &ccid_ss_out_comp_desc, + NULL, +}; + static inline struct f_ccid *func_to_ccid(struct usb_function *f) { return container_of(f, struct f_ccid, function); @@ -503,10 +568,7 @@ free_notify: static void ccid_function_unbind(struct usb_configuration *c, struct usb_function *f) { - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->fs_descriptors); - + usb_free_all_descriptors(f); } static int ccid_function_bind(struct usb_configuration *c, @@ -551,24 +613,27 @@ static int ccid_function_bind(struct usb_configuration *c, ccid_dev->out = ep; ep->driver_data = cdev; - f->fs_descriptors = usb_copy_descriptors(ccid_fs_descs); - if (!f->fs_descriptors) + /* + * support all relevant hardware speeds... we expect that when + * hardware is dual speed, all bulk-capable endpoints work at + * both speeds + */ + ccid_hs_in_desc.bEndpointAddress = ccid_fs_in_desc.bEndpointAddress; + ccid_hs_out_desc.bEndpointAddress = ccid_fs_out_desc.bEndpointAddress; + ccid_hs_notify_desc.bEndpointAddress = + ccid_fs_notify_desc.bEndpointAddress; + + + ccid_ss_in_desc.bEndpointAddress = ccid_fs_in_desc.bEndpointAddress; + ccid_ss_out_desc.bEndpointAddress = ccid_fs_out_desc.bEndpointAddress; + ccid_ss_notify_desc.bEndpointAddress = + ccid_fs_notify_desc.bEndpointAddress; + + ret = usb_assign_descriptors(f, ccid_fs_descs, ccid_hs_descs, + ccid_ss_descs); + if (ret) goto ep_auto_out_fail; - if (gadget_is_dualspeed(cdev->gadget)) { - ccid_hs_in_desc.bEndpointAddress = - ccid_fs_in_desc.bEndpointAddress; - ccid_hs_out_desc.bEndpointAddress = - ccid_fs_out_desc.bEndpointAddress; - ccid_hs_notify_desc.bEndpointAddress = - ccid_fs_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(ccid_hs_descs); - if (!f->hs_descriptors) - goto ep_auto_out_fail; - } - pr_debug("%s: CCID %s Speed, IN:%s OUT:%s\n", __func__, gadget_is_dualspeed(cdev->gadget) ? "dual" : "full", ccid_dev->in->name, ccid_dev->out->name); @@ -972,6 +1037,7 @@ static int ccid_bind_config(struct f_ccid *ccid_dev) ccid_dev->function.name = FUNCTION_NAME; ccid_dev->function.fs_descriptors = ccid_fs_descs; ccid_dev->function.hs_descriptors = ccid_hs_descs; + ccid_dev->function.ss_descriptors = ccid_ss_descs; ccid_dev->function.bind = ccid_function_bind; ccid_dev->function.unbind = ccid_function_unbind; ccid_dev->function.set_alt = ccid_function_set_alt;