Generate descriptors in new format and attach them to USB function in prep_descs(). Implement prep_vendor_descs() to supply class specific descriptors. Change set_alt() implementation and implement clear_alt() operation. Remove boilerplate code. Signed-off-by: Robert Baldyga <r.baldyga@xxxxxxxxxxx> --- drivers/usb/gadget/function/f_printer.c | 300 ++++++++++---------------------- 1 file changed, 88 insertions(+), 212 deletions(-) diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 26ccad5..70bad43 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -135,13 +135,6 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK }; -static struct usb_descriptor_header *fs_printer_function[] = { - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &fs_ep_in_desc, - (struct usb_descriptor_header *) &fs_ep_out_desc, - NULL -}; - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -169,13 +162,6 @@ static struct usb_qualifier_descriptor dev_qualifier = { .bNumConfigurations = 1 }; -static struct usb_descriptor_header *hs_printer_function[] = { - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &hs_ep_in_desc, - (struct usb_descriptor_header *) &hs_ep_out_desc, - NULL -}; - /* * Added endpoint descriptors for 3.0 devices */ @@ -204,14 +190,16 @@ static struct usb_ss_ep_comp_descriptor ss_ep_out_comp_desc = { .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, }; -static struct usb_descriptor_header *ss_printer_function[] = { - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &ss_ep_in_desc, - (struct usb_descriptor_header *) &ss_ep_in_comp_desc, - (struct usb_descriptor_header *) &ss_ep_out_desc, - (struct usb_descriptor_header *) &ss_ep_out_comp_desc, - NULL -}; +USB_COMPOSITE_ENDPOINT(ep_in, &fs_ep_in_desc, &hs_ep_in_desc, + &ss_ep_in_desc, &ss_ep_in_comp_desc); +USB_COMPOSITE_ENDPOINT(ep_out, &fs_ep_out_desc, &hs_ep_out_desc, + &ss_ep_out_desc, &ss_ep_out_comp_desc); + +USB_COMPOSITE_ALTSETTING(intf0alt0, &intf_desc, &ep_in, &ep_out); + +USB_COMPOSITE_INTERFACE(intf0, &intf0alt0); + +USB_COMPOSITE_DESCRIPTORS(printer_descs, &intf0); /* maxpacket and other transfer characteristics vary by speed. */ static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget, @@ -764,86 +752,6 @@ static const struct file_operations printer_io_operations = { /*-------------------------------------------------------------------------*/ -static int -set_printer_interface(struct printer_dev *dev) -{ - int result = 0; - - dev->in_ep->desc = ep_desc(dev->gadget, &fs_ep_in_desc, &hs_ep_in_desc, - &ss_ep_in_desc); - dev->in_ep->driver_data = dev; - - dev->out_ep->desc = ep_desc(dev->gadget, &fs_ep_out_desc, - &hs_ep_out_desc, &ss_ep_out_desc); - dev->out_ep->driver_data = dev; - - result = usb_ep_enable(dev->in_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); - goto done; - } - - result = usb_ep_enable(dev->out_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); - goto done; - } - -done: - /* on error, disable any endpoints */ - if (result != 0) { - (void) usb_ep_disable(dev->in_ep); - (void) usb_ep_disable(dev->out_ep); - dev->in_ep->desc = NULL; - dev->out_ep->desc = NULL; - } - - /* caller is responsible for cleanup on error */ - return result; -} - -static void printer_reset_interface(struct printer_dev *dev) -{ - unsigned long flags; - - if (dev->interface < 0) - return; - - DBG(dev, "%s\n", __func__); - - if (dev->in_ep->desc) - usb_ep_disable(dev->in_ep); - - if (dev->out_ep->desc) - usb_ep_disable(dev->out_ep); - - spin_lock_irqsave(&dev->lock, flags); - dev->in_ep->desc = NULL; - dev->out_ep->desc = NULL; - dev->interface = -1; - spin_unlock_irqrestore(&dev->lock, flags); -} - -/* Change our operational Interface. */ -static int set_interface(struct printer_dev *dev, unsigned number) -{ - int result = 0; - - /* Free the current interface */ - printer_reset_interface(dev); - - result = set_printer_interface(dev); - if (result) - printer_reset_interface(dev); - else - dev->interface = number; - - if (!result) - INFO(dev, "Using interface %x\n", number); - - return result; -} - static void printer_soft_reset(struct printer_dev *dev) { struct usb_request *req; @@ -1008,55 +916,64 @@ unknown: return value; } -static int printer_func_bind(struct usb_configuration *c, - struct usb_function *f) +static int printer_func_prep_descs(struct usb_function *f) +{ + return usb_function_set_descs(f, &printer_descs); +} + +static int printer_func_prep_vendor_descs(struct usb_function *f) { - struct usb_gadget *gadget = c->cdev->gadget; struct printer_dev *dev = func_to_printer(f); struct device *pdev; - struct usb_composite_dev *cdev = c->cdev; - struct usb_ep *in_ep; - struct usb_ep *out_ep = NULL; - struct usb_request *req; dev_t devt; - int id; int ret; - u32 i; - id = usb_interface_id(c, f); - if (id < 0) - return id; - intf_desc.bInterfaceNumber = id; + dev->interface = usb_get_interface_id(f, 0); - /* finish hookup to lower layer ... */ - dev->gadget = gadget; - - /* all we really need is bulk IN/OUT */ - in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc); - if (!in_ep) { -autoconf_fail: - dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n", - cdev->gadget->name); - return -ENODEV; + /* Setup the sysfs files for the printer gadget. */ + devt = MKDEV(major, dev->minor); + pdev = device_create(usb_gadget_class, NULL, devt, + NULL, "g_printer%d", dev->minor); + if (IS_ERR(pdev)) { + ERROR(dev, "Failed to create device: g_printer\n"); + return PTR_ERR(pdev); + } + + /* + * Register a character device as an interface to a user mode + * program that handles the printer specific functionality. + */ + cdev_init(&dev->printer_cdev, &printer_io_operations); + dev->printer_cdev.owner = THIS_MODULE; + ret = cdev_add(&dev->printer_cdev, devt, 1); + if (ret) { + ERROR(dev, "Failed to open char device\n"); + device_destroy(usb_gadget_class, devt); } - out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc); - if (!out_ep) - goto autoconf_fail; + return ret; +} - /* assumes that all endpoints are dual-speed */ - hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; - hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; - ss_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; - ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; +static int printer_func_set_alt(struct usb_function *f, + unsigned intf, unsigned alt) +{ + struct printer_dev *dev = func_to_printer(f); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req; + int i, ret = -ENOTSUPP; - ret = usb_assign_descriptors(f, fs_printer_function, - hs_printer_function, ss_printer_function); - if (ret) - return ret; + /* finish hookup to lower layer ... */ + dev->gadget = cdev->gadget; + + dev->in_ep = usb_function_get_ep(f, intf, 0); + if (!dev->in_ep) + return -ENODEV; + dev->out_ep = usb_function_get_ep(f, intf, 1); + if (!dev->out_ep) + return -ENODEV; - dev->in_ep = in_ep; - dev->out_ep = out_ep; + dev->in_ep->driver_data = dev; + dev->out_ep->driver_data = dev; ret = -ENOMEM; for (i = 0; i < dev->q_len; i++) { @@ -1073,33 +990,8 @@ autoconf_fail: list_add(&req->list, &dev->rx_reqs); } - /* Setup the sysfs files for the printer gadget. */ - devt = MKDEV(major, dev->minor); - pdev = device_create(usb_gadget_class, NULL, devt, - NULL, "g_printer%d", dev->minor); - if (IS_ERR(pdev)) { - ERROR(dev, "Failed to create device: g_printer\n"); - ret = PTR_ERR(pdev); - goto fail_rx_reqs; - } - - /* - * Register a character device as an interface to a user mode - * program that handles the printer specific functionality. - */ - cdev_init(&dev->printer_cdev, &printer_io_operations); - dev->printer_cdev.owner = THIS_MODULE; - ret = cdev_add(&dev->printer_cdev, devt, 1); - if (ret) { - ERROR(dev, "Failed to open char device\n"); - goto fail_cdev_add; - } - return 0; -fail_cdev_add: - device_destroy(usb_gadget_class, devt); - fail_rx_reqs: while (!list_empty(&dev->rx_reqs)) { req = container_of(dev->rx_reqs.next, struct usb_request, list); @@ -1115,28 +1007,44 @@ fail_tx_reqs: } return ret; - } -static int printer_func_set_alt(struct usb_function *f, +static void printer_func_clear_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct printer_dev *dev = func_to_printer(f); - int ret = -ENOTSUPP; + struct usb_request *req; + + DBG(dev, "%s\n", __func__); - if (!alt) - ret = set_interface(dev, intf); + /* we must already have been disconnected ... no i/o may be active */ + WARN_ON(!list_empty(&dev->tx_reqs_active)); + WARN_ON(!list_empty(&dev->rx_reqs_active)); - return ret; -} + /* Free all memory for this driver. */ + while (!list_empty(&dev->tx_reqs)) { + req = container_of(dev->tx_reqs.next, struct usb_request, + list); + list_del(&req->list); + printer_req_free(dev->in_ep, req); + } -static void printer_func_disable(struct usb_function *f) -{ - struct printer_dev *dev = func_to_printer(f); + if (dev->current_rx_req != NULL) + printer_req_free(dev->out_ep, dev->current_rx_req); - DBG(dev, "%s\n", __func__); + while (!list_empty(&dev->rx_reqs)) { + req = container_of(dev->rx_reqs.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } - printer_reset_interface(dev); + while (!list_empty(&dev->rx_buffers)) { + req = container_of(dev->rx_buffers.next, + struct usb_request, list); + list_del(&req->list); + printer_req_free(dev->out_ep, req); + } } static inline struct f_printer_opts @@ -1333,45 +1241,12 @@ static void gprinter_free(struct usb_function *f) static void printer_func_unbind(struct usb_configuration *c, struct usb_function *f) { - struct printer_dev *dev; - struct usb_request *req; - - dev = func_to_printer(f); + struct printer_dev *dev = func_to_printer(f); device_destroy(usb_gadget_class, MKDEV(major, dev->minor)); /* Remove Character Device */ cdev_del(&dev->printer_cdev); - - /* we must already have been disconnected ... no i/o may be active */ - WARN_ON(!list_empty(&dev->tx_reqs_active)); - WARN_ON(!list_empty(&dev->rx_reqs_active)); - - /* Free all memory for this driver. */ - while (!list_empty(&dev->tx_reqs)) { - req = container_of(dev->tx_reqs.next, struct usb_request, - list); - list_del(&req->list); - printer_req_free(dev->in_ep, req); - } - - if (dev->current_rx_req != NULL) - printer_req_free(dev->out_ep, dev->current_rx_req); - - while (!list_empty(&dev->rx_reqs)) { - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } - - while (!list_empty(&dev->rx_buffers)) { - req = container_of(dev->rx_buffers.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } - usb_free_all_descriptors(f); } static struct usb_function *gprinter_alloc(struct usb_function_instance *fi) @@ -1400,11 +1275,12 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi) mutex_unlock(&opts->lock); dev->function.name = "printer"; - dev->function.bind = printer_func_bind; + dev->function.prep_descs = printer_func_prep_descs; + dev->function.prep_vendor_descs = printer_func_prep_vendor_descs; dev->function.setup = printer_func_setup; dev->function.unbind = printer_func_unbind; dev->function.set_alt = printer_func_set_alt; - dev->function.disable = printer_func_disable; + dev->function.clear_alt = printer_func_clear_alt; dev->function.req_match = gprinter_req_match; dev->function.free_func = gprinter_free; -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html