[PATCH experimental 1/6] usb: cdc-wdm: split out reusable parts of probe and destroy

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

 



Preparing for the addition of a wdm_register/wdm_deregister
alternative to probe/destroy for interface-less usage.  This should
not change anything apart from minor code reordering.

Signed-off-by: Bjørn Mork <bjorn@xxxxxxx>
---
 drivers/usb/class/cdc-wdm.c |  129 ++++++++++++++++++++++++------------------
 1 files changed, 74 insertions(+), 55 deletions(-)

diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index e6001ec..e81565f 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -617,47 +617,11 @@ static void wdm_rxwork(struct work_struct *work)
 
 /* --- hotplug --- */
 
-static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static struct wdm_device *wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, u16 bufsize)
 {
-	int rv = -EINVAL;
+	int rv = -ENOMEM;
 	struct wdm_device *desc;
-	struct usb_host_interface *iface;
-	struct usb_endpoint_descriptor *ep;
-	struct usb_cdc_dmm_desc *dmhd;
-	u8 *buffer = intf->altsetting->extra;
-	int buflen = intf->altsetting->extralen;
-	u16 maxcom = WDM_DEFAULT_BUFSIZE;
 
-	if (!buffer)
-		goto out;
-
-	while (buflen > 2) {
-		if (buffer [1] != USB_DT_CS_INTERFACE) {
-			dev_err(&intf->dev, "skipping garbage\n");
-			goto next_desc;
-		}
-
-		switch (buffer [2]) {
-		case USB_CDC_HEADER_TYPE:
-			break;
-		case USB_CDC_DMM_TYPE:
-			dmhd = (struct usb_cdc_dmm_desc *)buffer;
-			maxcom = le16_to_cpu(dmhd->wMaxCommand);
-			dev_dbg(&intf->dev,
-				"Finding maximum buffer length: %d", maxcom);
-			break;
-		default:
-			dev_err(&intf->dev,
-				"Ignoring extra header, type %d, length %d\n",
-				buffer[2], buffer[0]);
-			break;
-		}
-next_desc:
-		buflen -= buffer[0];
-		buffer += buffer[0];
-	}
-
-	rv = -ENOMEM;
 	desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
 	if (!desc)
 		goto out;
@@ -665,17 +629,13 @@ next_desc:
 	mutex_init(&desc->wlock);
 	spin_lock_init(&desc->iuspin);
 	init_waitqueue_head(&desc->wait);
-	desc->wMaxCommand = maxcom;
+	desc->wMaxCommand = bufsize;
 	/* this will be expanded and needed in hardware endianness */
 	desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
 	desc->intf = intf;
 	INIT_WORK(&desc->rxwork, wdm_rxwork);
 
 	rv = -EINVAL;
-	iface = intf->cur_altsetting;
-	if (iface->desc.bNumEndpoints != 1)
-		goto err;
-	ep = &iface->endpoint[0].desc;
 	if (!ep || !usb_endpoint_is_int_in(ep))
 		goto err;
 
@@ -741,35 +701,87 @@ next_desc:
 		desc
 	);
 
+	return desc;
+
+err:
+	cleanup(desc);
+out:
+	return ERR_PTR(rv);
+}
+
+static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	int rv = -EINVAL;
+	struct wdm_device *desc;
+	struct usb_host_interface *iface;
+	struct usb_endpoint_descriptor *ep;
+	struct usb_cdc_dmm_desc *dmhd;
+	u8 *buffer = intf->altsetting->extra;
+	int buflen = intf->altsetting->extralen;
+	u16 maxcom = WDM_DEFAULT_BUFSIZE;
+
+	if (!buffer)
+		goto err;
+
+	while (buflen > 2) {
+		if (buffer [1] != USB_DT_CS_INTERFACE) {
+			dev_err(&intf->dev, "skipping garbage\n");
+			goto next_desc;
+		}
+
+		switch (buffer [2]) {
+		case USB_CDC_HEADER_TYPE:
+			break;
+		case USB_CDC_DMM_TYPE:
+			dmhd = (struct usb_cdc_dmm_desc *)buffer;
+			maxcom = le16_to_cpu(dmhd->wMaxCommand);
+			dev_dbg(&intf->dev,
+				"Finding maximum buffer length: %d", maxcom);
+			break;
+		default:
+			dev_err(&intf->dev,
+				"Ignoring extra header, type %d, length %d\n",
+				buffer[2], buffer[0]);
+			break;
+		}
+next_desc:
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	iface = intf->cur_altsetting;
+	if (iface->desc.bNumEndpoints != 1)
+		goto err;
+	ep = &iface->endpoint[0].desc;
+
+	desc = wdm_create(intf, ep, maxcom);
+	if (IS_ERR(desc)) {
+		rv = PTR_ERR(desc);
+		goto err;
+	}
+
 	usb_set_intfdata(intf, desc);
 	rv = usb_register_dev(intf, &wdm_class);
 	if (rv < 0)
 		goto err2;
 	else
 		dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
-out:
+
 	return rv;
+
 err2:
 	usb_set_intfdata(intf, NULL);
+	cleanup(desc);
 err:
-	free_urbs(desc);
-	kfree(desc->inbuf);
-	kfree(desc->sbuf);
-	kfree(desc->ubuf);
-	kfree(desc->orq);
-	kfree(desc->irq);
-	kfree(desc);
 	return rv;
 }
 
-static void wdm_disconnect(struct usb_interface *intf)
+static void wdm_destroy(struct wdm_device *desc)
 {
-	struct wdm_device *desc;
 	unsigned long flags;
 
-	usb_deregister_dev(intf, &wdm_class);
+	usb_deregister_dev(desc->intf, &wdm_class);
 	mutex_lock(&wdm_mutex);
-	desc = usb_get_intfdata(intf);
 
 	/* the spinlock makes sure no new urbs are generated in the callbacks */
 	spin_lock_irqsave(&desc->iuspin, flags);
@@ -788,6 +800,13 @@ static void wdm_disconnect(struct usb_interface *intf)
 	if (!desc->count)
 		cleanup(desc);
 	mutex_unlock(&wdm_mutex);
+
+}
+
+static void wdm_disconnect(struct usb_interface *intf)
+{
+	struct wdm_device *desc = usb_get_intfdata(intf);
+	wdm_destroy(desc);
 }
 
 #ifdef CONFIG_PM
-- 
1.7.8.3

--
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