[PATCH v4 30/43] usb: gadget: f_printer: conversion to new API

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux