usb: gadget: factor out two helper functions from composite_bind()
This patch factors out two helper functions from composite_bind()
that is composite_dev_prepare() and its counterpart
composite_dev_cleanup().
This will be used by the configfs which requries a slightly different
bind/setup code because part of its configurations (i.e. config
descripts, cdev, …) are setup in advance and VID/PID and so one should
not be overwritten. Also the setup of ep0 endpoint can be delayed until
the UDC is assigned.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 366facc..9083ec9 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1394,11 +1394,8 @@
if (cdev->driver->unbind && unbind_driver)
cdev->driver->unbind(cdev);
- if (cdev->req) {
- kfree(cdev->req->buf);
- usb_ep_free_request(gadget->ep0, cdev->req);
- }
- device_remove_file(&gadget->dev, &dev_attr_suspended);
+ composite_dev_cleanup(cdev);
+
kfree(cdev->def_manufacturer);
kfree(cdev);
set_gadget_data(gadget, NULL);
@@ -1447,9 +1444,59 @@
new->iProduct = iProduct;
}
-static struct usb_composite_driver *to_cdriver(struct usb_gadget_driver *gdrv)
+int composite_dev_prepare(struct usb_composite_driver *composite,
+ struct usb_composite_dev *cdev)
{
- return container_of(gdrv, struct usb_composite_driver, gadget_driver);
+ struct usb_gadget *gadget = cdev->gadget;
+ int ret = -ENOMEM;
+
+ /* preallocate control response and buffer */
+ cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+ if (!cdev->req)
+ return -ENOMEM;
+
+ cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
+ if (!cdev->req->buf)
+ goto fail;
+
+ ret = device_create_file(&gadget->dev, &dev_attr_suspended);
+ if (ret)
+ goto fail_dev;
+
+ cdev->req->complete = composite_setup_complete;
+ gadget->ep0->driver_data = cdev;
+
+ cdev->driver = composite;
+
+ /*
+ * As per USB compliance update, a device that is actively drawing
+ * more than 100mA from USB must report itself as bus-powered in
+ * the GetStatus(DEVICE) call.
+ */
+ if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
+ usb_gadget_set_selfpowered(gadget);
+
+ /* interface and string IDs start at zero via kzalloc.
+ * we force endpoints to start unassigned; few controller
+ * drivers will zero ep->driver_data.
+ */
+ usb_ep_autoconfig_reset(gadget);
+ return 0;
+fail_dev:
+ kfree(cdev->req->buf);
+fail:
+ usb_ep_free_request(gadget->ep0, cdev->req);
+ cdev->req = NULL;
+ return ret;
+}
+
+void composite_dev_cleanup(struct usb_composite_dev *cdev)
+{
+ if (cdev->req) {
+ kfree(cdev->req->buf);
+ usb_ep_free_request(cdev->gadget->ep0, cdev->req);
+ }
+ device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
}
static int composite_bind(struct usb_gadget *gadget,
@@ -1468,31 +1515,9 @@
set_gadget_data(gadget, cdev);
INIT_LIST_HEAD(&cdev->configs);
- /* preallocate control response and buffer */
- cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
- if (!cdev->req)
+ status = composite_dev_prepare(composite, cdev);
+ if (status)
goto fail;
- cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
- if (!cdev->req->buf)
- goto fail;
- cdev->req->complete = composite_setup_complete;
- gadget->ep0->driver_data = cdev;
-
- cdev->driver = composite;
-
- /*
- * As per USB compliance update, a device that is actively drawing
- * more than 100mA from USB must report itself as bus-powered in
- * the GetStatus(DEVICE) call.
- */
- if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
- usb_gadget_set_selfpowered(gadget);
-
- /* interface and string IDs start at zero via kzalloc.
- * we force endpoints to start unassigned; few controller
- * drivers will zero ep->driver_data.
- */
- usb_ep_autoconfig_reset(cdev->gadget);
/* composite gadget needs to assign strings for whole device (like
* serial number), register function drivers, potentially update
@@ -1508,11 +1533,6 @@
if (composite->needs_serial && !cdev->desc.iSerialNumber)
WARNING(cdev, "userspace failed to provide iSerialNumber\n");
- /* finish up */
- status = device_create_file(&gadget->dev, &dev_attr_suspended);
- if (status)
- goto fail;
-
INFO(cdev, "%s ready\n", composite->name);
return 0;
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 771de7a..bd6d857 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -323,7 +323,15 @@
extern int usb_composite_probe(struct usb_composite_driver *driver);
extern void usb_composite_unregister(struct usb_composite_driver *driver);
extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
+extern int composite_dev_prepare(struct usb_composite_driver *composite,
+ struct usb_composite_dev *cdev);
+void composite_dev_cleanup(struct usb_composite_dev *cdev);
+static inline struct usb_composite_driver *to_cdriver(
+ struct usb_gadget_driver *gdrv)
+{
+ return container_of(gdrv, struct usb_composite_driver, gadget_driver);
+}
/**
* struct usb_composite_device - represents one composite usb gadget