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