[PATCH v3 29/36] usb: gadget: f_printer: conversion to new API
From: Robert Baldyga
Date: Fri Dec 11 2015 - 06:30:20 EST
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 0fbfb2b..f5cfea3 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-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/