1afba937eSOliver Neukum /* 2afba937eSOliver Neukum * cdc-wdm.c 3afba937eSOliver Neukum * 4afba937eSOliver Neukum * This driver supports USB CDC WCM Device Management. 5afba937eSOliver Neukum * 6afba937eSOliver Neukum * Copyright (c) 2007-2008 Oliver Neukum 7afba937eSOliver Neukum * 8afba937eSOliver Neukum * Some code taken from cdc-acm.c 9afba937eSOliver Neukum * 10afba937eSOliver Neukum * Released under the GPLv2. 11afba937eSOliver Neukum * 12afba937eSOliver Neukum * Many thanks to Carl Nordbeck 13afba937eSOliver Neukum */ 14afba937eSOliver Neukum #include <linux/kernel.h> 15afba937eSOliver Neukum #include <linux/errno.h> 16afba937eSOliver Neukum #include <linux/slab.h> 17afba937eSOliver Neukum #include <linux/module.h> 18afba937eSOliver Neukum #include <linux/smp_lock.h> 19afba937eSOliver Neukum #include <linux/mutex.h> 20afba937eSOliver Neukum #include <linux/uaccess.h> 21afba937eSOliver Neukum #include <linux/bitops.h> 22afba937eSOliver Neukum #include <linux/poll.h> 23afba937eSOliver Neukum #include <linux/usb.h> 24afba937eSOliver Neukum #include <linux/usb/cdc.h> 25afba937eSOliver Neukum #include <asm/byteorder.h> 26afba937eSOliver Neukum #include <asm/unaligned.h> 27afba937eSOliver Neukum 28afba937eSOliver Neukum /* 29afba937eSOliver Neukum * Version Information 30afba937eSOliver Neukum */ 3187d65e54SOliver Neukum #define DRIVER_VERSION "v0.03" 32afba937eSOliver Neukum #define DRIVER_AUTHOR "Oliver Neukum" 3387d65e54SOliver Neukum #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" 34afba937eSOliver Neukum 35afba937eSOliver Neukum static struct usb_device_id wdm_ids[] = { 36afba937eSOliver Neukum { 37afba937eSOliver Neukum .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | 38afba937eSOliver Neukum USB_DEVICE_ID_MATCH_INT_SUBCLASS, 39afba937eSOliver Neukum .bInterfaceClass = USB_CLASS_COMM, 40afba937eSOliver Neukum .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM 41afba937eSOliver Neukum }, 42afba937eSOliver Neukum { } 43afba937eSOliver Neukum }; 44afba937eSOliver Neukum 45aa5380b9SOliver Neukum MODULE_DEVICE_TABLE (usb, wdm_ids); 46aa5380b9SOliver Neukum 47afba937eSOliver Neukum #define WDM_MINOR_BASE 176 48afba937eSOliver Neukum 49afba937eSOliver Neukum 50afba937eSOliver Neukum #define WDM_IN_USE 1 51afba937eSOliver Neukum #define WDM_DISCONNECTING 2 52afba937eSOliver Neukum #define WDM_RESULT 3 53afba937eSOliver Neukum #define WDM_READ 4 54afba937eSOliver Neukum #define WDM_INT_STALL 5 55afba937eSOliver Neukum #define WDM_POLL_RUNNING 6 56afba937eSOliver Neukum 57afba937eSOliver Neukum 58afba937eSOliver Neukum #define WDM_MAX 16 59afba937eSOliver Neukum 60afba937eSOliver Neukum 61afba937eSOliver Neukum static DEFINE_MUTEX(wdm_mutex); 62afba937eSOliver Neukum 63afba937eSOliver Neukum /* --- method tables --- */ 64afba937eSOliver Neukum 65afba937eSOliver Neukum struct wdm_device { 66afba937eSOliver Neukum u8 *inbuf; /* buffer for response */ 67afba937eSOliver Neukum u8 *outbuf; /* buffer for command */ 68afba937eSOliver Neukum u8 *sbuf; /* buffer for status */ 69afba937eSOliver Neukum u8 *ubuf; /* buffer for copy to user space */ 70afba937eSOliver Neukum 71afba937eSOliver Neukum struct urb *command; 72afba937eSOliver Neukum struct urb *response; 73afba937eSOliver Neukum struct urb *validity; 74afba937eSOliver Neukum struct usb_interface *intf; 75afba937eSOliver Neukum struct usb_ctrlrequest *orq; 76afba937eSOliver Neukum struct usb_ctrlrequest *irq; 77afba937eSOliver Neukum spinlock_t iuspin; 78afba937eSOliver Neukum 79afba937eSOliver Neukum unsigned long flags; 80afba937eSOliver Neukum u16 bufsize; 81afba937eSOliver Neukum u16 wMaxCommand; 82afba937eSOliver Neukum u16 wMaxPacketSize; 83afba937eSOliver Neukum u16 bMaxPacketSize0; 84afba937eSOliver Neukum __le16 inum; 85afba937eSOliver Neukum int reslength; 86afba937eSOliver Neukum int length; 87afba937eSOliver Neukum int read; 88afba937eSOliver Neukum int count; 89afba937eSOliver Neukum dma_addr_t shandle; 90afba937eSOliver Neukum dma_addr_t ihandle; 91afba937eSOliver Neukum struct mutex wlock; 92afba937eSOliver Neukum struct mutex rlock; 9317d80d56SOliver Neukum struct mutex plock; 94afba937eSOliver Neukum wait_queue_head_t wait; 95afba937eSOliver Neukum struct work_struct rxwork; 96afba937eSOliver Neukum int werr; 97afba937eSOliver Neukum int rerr; 98afba937eSOliver Neukum }; 99afba937eSOliver Neukum 100afba937eSOliver Neukum static struct usb_driver wdm_driver; 101afba937eSOliver Neukum 102afba937eSOliver Neukum /* --- callbacks --- */ 103afba937eSOliver Neukum static void wdm_out_callback(struct urb *urb) 104afba937eSOliver Neukum { 105afba937eSOliver Neukum struct wdm_device *desc; 106afba937eSOliver Neukum desc = urb->context; 107afba937eSOliver Neukum spin_lock(&desc->iuspin); 108afba937eSOliver Neukum desc->werr = urb->status; 109afba937eSOliver Neukum spin_unlock(&desc->iuspin); 110afba937eSOliver Neukum clear_bit(WDM_IN_USE, &desc->flags); 111afba937eSOliver Neukum kfree(desc->outbuf); 112afba937eSOliver Neukum wake_up(&desc->wait); 113afba937eSOliver Neukum } 114afba937eSOliver Neukum 115afba937eSOliver Neukum static void wdm_in_callback(struct urb *urb) 116afba937eSOliver Neukum { 117afba937eSOliver Neukum struct wdm_device *desc = urb->context; 118afba937eSOliver Neukum int status = urb->status; 119afba937eSOliver Neukum 120afba937eSOliver Neukum spin_lock(&desc->iuspin); 121afba937eSOliver Neukum 122afba937eSOliver Neukum if (status) { 123afba937eSOliver Neukum switch (status) { 124afba937eSOliver Neukum case -ENOENT: 125afba937eSOliver Neukum dev_dbg(&desc->intf->dev, 126afba937eSOliver Neukum "nonzero urb status received: -ENOENT"); 127afba937eSOliver Neukum break; 128afba937eSOliver Neukum case -ECONNRESET: 129afba937eSOliver Neukum dev_dbg(&desc->intf->dev, 130afba937eSOliver Neukum "nonzero urb status received: -ECONNRESET"); 131afba937eSOliver Neukum break; 132afba937eSOliver Neukum case -ESHUTDOWN: 133afba937eSOliver Neukum dev_dbg(&desc->intf->dev, 134afba937eSOliver Neukum "nonzero urb status received: -ESHUTDOWN"); 135afba937eSOliver Neukum break; 136afba937eSOliver Neukum case -EPIPE: 1379908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 1389908a32eSGreg Kroah-Hartman "nonzero urb status received: -EPIPE\n"); 139afba937eSOliver Neukum break; 140afba937eSOliver Neukum default: 1419908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 1429908a32eSGreg Kroah-Hartman "Unexpected error %d\n", status); 143afba937eSOliver Neukum break; 144afba937eSOliver Neukum } 145afba937eSOliver Neukum } 146afba937eSOliver Neukum 147afba937eSOliver Neukum desc->rerr = status; 148afba937eSOliver Neukum desc->reslength = urb->actual_length; 149afba937eSOliver Neukum memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); 150afba937eSOliver Neukum desc->length += desc->reslength; 151afba937eSOliver Neukum wake_up(&desc->wait); 152afba937eSOliver Neukum 153afba937eSOliver Neukum set_bit(WDM_READ, &desc->flags); 154afba937eSOliver Neukum spin_unlock(&desc->iuspin); 155afba937eSOliver Neukum } 156afba937eSOliver Neukum 157afba937eSOliver Neukum static void wdm_int_callback(struct urb *urb) 158afba937eSOliver Neukum { 159afba937eSOliver Neukum int rv = 0; 160afba937eSOliver Neukum int status = urb->status; 161afba937eSOliver Neukum struct wdm_device *desc; 162afba937eSOliver Neukum struct usb_ctrlrequest *req; 163afba937eSOliver Neukum struct usb_cdc_notification *dr; 164afba937eSOliver Neukum 165afba937eSOliver Neukum desc = urb->context; 166afba937eSOliver Neukum req = desc->irq; 167afba937eSOliver Neukum dr = (struct usb_cdc_notification *)desc->sbuf; 168afba937eSOliver Neukum 169afba937eSOliver Neukum if (status) { 170afba937eSOliver Neukum switch (status) { 171afba937eSOliver Neukum case -ESHUTDOWN: 172afba937eSOliver Neukum case -ENOENT: 173afba937eSOliver Neukum case -ECONNRESET: 174afba937eSOliver Neukum return; /* unplug */ 175afba937eSOliver Neukum case -EPIPE: 176afba937eSOliver Neukum set_bit(WDM_INT_STALL, &desc->flags); 1779908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, "Stall on int endpoint\n"); 178afba937eSOliver Neukum goto sw; /* halt is cleared in work */ 179afba937eSOliver Neukum default: 1809908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 1819908a32eSGreg Kroah-Hartman "nonzero urb status received: %d\n", status); 182afba937eSOliver Neukum break; 183afba937eSOliver Neukum } 184afba937eSOliver Neukum } 185afba937eSOliver Neukum 186afba937eSOliver Neukum if (urb->actual_length < sizeof(struct usb_cdc_notification)) { 1879908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, "wdm_int_callback - %d bytes\n", 1889908a32eSGreg Kroah-Hartman urb->actual_length); 189afba937eSOliver Neukum goto exit; 190afba937eSOliver Neukum } 191afba937eSOliver Neukum 192afba937eSOliver Neukum switch (dr->bNotificationType) { 193afba937eSOliver Neukum case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: 194afba937eSOliver Neukum dev_dbg(&desc->intf->dev, 195afba937eSOliver Neukum "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d", 196afba937eSOliver Neukum dr->wIndex, dr->wLength); 197afba937eSOliver Neukum break; 198afba937eSOliver Neukum 199afba937eSOliver Neukum case USB_CDC_NOTIFY_NETWORK_CONNECTION: 200afba937eSOliver Neukum 201afba937eSOliver Neukum dev_dbg(&desc->intf->dev, 202afba937eSOliver Neukum "NOTIFY_NETWORK_CONNECTION %s network", 203afba937eSOliver Neukum dr->wValue ? "connected to" : "disconnected from"); 204afba937eSOliver Neukum goto exit; 205afba937eSOliver Neukum default: 206afba937eSOliver Neukum clear_bit(WDM_POLL_RUNNING, &desc->flags); 2079908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 2089908a32eSGreg Kroah-Hartman "unknown notification %d received: index %d len %d\n", 209afba937eSOliver Neukum dr->bNotificationType, dr->wIndex, dr->wLength); 210afba937eSOliver Neukum goto exit; 211afba937eSOliver Neukum } 212afba937eSOliver Neukum 213afba937eSOliver Neukum req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); 214afba937eSOliver Neukum req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; 215afba937eSOliver Neukum req->wValue = 0; 216afba937eSOliver Neukum req->wIndex = desc->inum; 21787d65e54SOliver Neukum req->wLength = cpu_to_le16(desc->wMaxCommand); 218afba937eSOliver Neukum 219afba937eSOliver Neukum usb_fill_control_urb( 220afba937eSOliver Neukum desc->response, 221afba937eSOliver Neukum interface_to_usbdev(desc->intf), 222afba937eSOliver Neukum /* using common endpoint 0 */ 223afba937eSOliver Neukum usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), 224afba937eSOliver Neukum (unsigned char *)req, 225afba937eSOliver Neukum desc->inbuf, 22687d65e54SOliver Neukum desc->wMaxCommand, 227afba937eSOliver Neukum wdm_in_callback, 228afba937eSOliver Neukum desc 229afba937eSOliver Neukum ); 230afba937eSOliver Neukum desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 231afba937eSOliver Neukum spin_lock(&desc->iuspin); 232afba937eSOliver Neukum clear_bit(WDM_READ, &desc->flags); 233afba937eSOliver Neukum if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { 234afba937eSOliver Neukum rv = usb_submit_urb(desc->response, GFP_ATOMIC); 235afba937eSOliver Neukum dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", 236afba937eSOliver Neukum __func__, rv); 237afba937eSOliver Neukum } 238afba937eSOliver Neukum spin_unlock(&desc->iuspin); 239afba937eSOliver Neukum if (rv < 0) { 240afba937eSOliver Neukum if (rv == -EPERM) 241afba937eSOliver Neukum return; 242afba937eSOliver Neukum if (rv == -ENOMEM) { 243afba937eSOliver Neukum sw: 244afba937eSOliver Neukum rv = schedule_work(&desc->rxwork); 245afba937eSOliver Neukum if (rv) 2469908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 2479908a32eSGreg Kroah-Hartman "Cannot schedule work\n"); 248afba937eSOliver Neukum } 249afba937eSOliver Neukum } 250afba937eSOliver Neukum exit: 251afba937eSOliver Neukum rv = usb_submit_urb(urb, GFP_ATOMIC); 252afba937eSOliver Neukum if (rv) 2539908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 2549908a32eSGreg Kroah-Hartman "%s - usb_submit_urb failed with result %d\n", 255afba937eSOliver Neukum __func__, rv); 256afba937eSOliver Neukum 257afba937eSOliver Neukum } 258afba937eSOliver Neukum 259afba937eSOliver Neukum static void kill_urbs(struct wdm_device *desc) 260afba937eSOliver Neukum { 26117d80d56SOliver Neukum /* the order here is essential */ 262afba937eSOliver Neukum usb_kill_urb(desc->command); 263afba937eSOliver Neukum usb_kill_urb(desc->validity); 264afba937eSOliver Neukum usb_kill_urb(desc->response); 265afba937eSOliver Neukum } 266afba937eSOliver Neukum 267afba937eSOliver Neukum static void free_urbs(struct wdm_device *desc) 268afba937eSOliver Neukum { 269afba937eSOliver Neukum usb_free_urb(desc->validity); 270afba937eSOliver Neukum usb_free_urb(desc->response); 271afba937eSOliver Neukum usb_free_urb(desc->command); 272afba937eSOliver Neukum } 273afba937eSOliver Neukum 274afba937eSOliver Neukum static void cleanup(struct wdm_device *desc) 275afba937eSOliver Neukum { 276afba937eSOliver Neukum usb_buffer_free(interface_to_usbdev(desc->intf), 277afba937eSOliver Neukum desc->wMaxPacketSize, 278afba937eSOliver Neukum desc->sbuf, 279afba937eSOliver Neukum desc->validity->transfer_dma); 280afba937eSOliver Neukum usb_buffer_free(interface_to_usbdev(desc->intf), 28187d65e54SOliver Neukum desc->wMaxCommand, 282afba937eSOliver Neukum desc->inbuf, 283afba937eSOliver Neukum desc->response->transfer_dma); 284afba937eSOliver Neukum kfree(desc->orq); 285afba937eSOliver Neukum kfree(desc->irq); 286afba937eSOliver Neukum kfree(desc->ubuf); 287afba937eSOliver Neukum free_urbs(desc); 288afba937eSOliver Neukum kfree(desc); 289afba937eSOliver Neukum } 290afba937eSOliver Neukum 291afba937eSOliver Neukum static ssize_t wdm_write 292afba937eSOliver Neukum (struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 293afba937eSOliver Neukum { 294afba937eSOliver Neukum u8 *buf; 295afba937eSOliver Neukum int rv = -EMSGSIZE, r, we; 296afba937eSOliver Neukum struct wdm_device *desc = file->private_data; 297afba937eSOliver Neukum struct usb_ctrlrequest *req; 298afba937eSOliver Neukum 299afba937eSOliver Neukum if (count > desc->wMaxCommand) 300afba937eSOliver Neukum count = desc->wMaxCommand; 301afba937eSOliver Neukum 302afba937eSOliver Neukum spin_lock_irq(&desc->iuspin); 303afba937eSOliver Neukum we = desc->werr; 304afba937eSOliver Neukum desc->werr = 0; 305afba937eSOliver Neukum spin_unlock_irq(&desc->iuspin); 306afba937eSOliver Neukum if (we < 0) 307afba937eSOliver Neukum return -EIO; 308afba937eSOliver Neukum 309afba937eSOliver Neukum r = mutex_lock_interruptible(&desc->wlock); /* concurrent writes */ 310afba937eSOliver Neukum rv = -ERESTARTSYS; 311afba937eSOliver Neukum if (r) 312afba937eSOliver Neukum goto outnl; 313afba937eSOliver Neukum 31417d80d56SOliver Neukum r = usb_autopm_get_interface(desc->intf); 31517d80d56SOliver Neukum if (r < 0) 31617d80d56SOliver Neukum goto outnp; 317afba937eSOliver Neukum r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, 318afba937eSOliver Neukum &desc->flags)); 319afba937eSOliver Neukum if (r < 0) 320afba937eSOliver Neukum goto out; 321afba937eSOliver Neukum 322afba937eSOliver Neukum if (test_bit(WDM_DISCONNECTING, &desc->flags)) { 323afba937eSOliver Neukum rv = -ENODEV; 324afba937eSOliver Neukum goto out; 325afba937eSOliver Neukum } 326afba937eSOliver Neukum 327afba937eSOliver Neukum desc->outbuf = buf = kmalloc(count, GFP_KERNEL); 328afba937eSOliver Neukum if (!buf) { 329afba937eSOliver Neukum rv = -ENOMEM; 330afba937eSOliver Neukum goto out; 331afba937eSOliver Neukum } 332afba937eSOliver Neukum 333afba937eSOliver Neukum r = copy_from_user(buf, buffer, count); 334afba937eSOliver Neukum if (r > 0) { 335afba937eSOliver Neukum kfree(buf); 336afba937eSOliver Neukum rv = -EFAULT; 337afba937eSOliver Neukum goto out; 338afba937eSOliver Neukum } 339afba937eSOliver Neukum 340afba937eSOliver Neukum req = desc->orq; 341afba937eSOliver Neukum usb_fill_control_urb( 342afba937eSOliver Neukum desc->command, 343afba937eSOliver Neukum interface_to_usbdev(desc->intf), 344afba937eSOliver Neukum /* using common endpoint 0 */ 345afba937eSOliver Neukum usb_sndctrlpipe(interface_to_usbdev(desc->intf), 0), 346afba937eSOliver Neukum (unsigned char *)req, 347afba937eSOliver Neukum buf, 348afba937eSOliver Neukum count, 349afba937eSOliver Neukum wdm_out_callback, 350afba937eSOliver Neukum desc 351afba937eSOliver Neukum ); 352afba937eSOliver Neukum 353afba937eSOliver Neukum req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | 354afba937eSOliver Neukum USB_RECIP_INTERFACE); 355afba937eSOliver Neukum req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; 356afba937eSOliver Neukum req->wValue = 0; 357afba937eSOliver Neukum req->wIndex = desc->inum; 358afba937eSOliver Neukum req->wLength = cpu_to_le16(count); 359afba937eSOliver Neukum set_bit(WDM_IN_USE, &desc->flags); 360afba937eSOliver Neukum 361afba937eSOliver Neukum rv = usb_submit_urb(desc->command, GFP_KERNEL); 362afba937eSOliver Neukum if (rv < 0) { 363afba937eSOliver Neukum kfree(buf); 364afba937eSOliver Neukum clear_bit(WDM_IN_USE, &desc->flags); 3659908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); 366afba937eSOliver Neukum } else { 367afba937eSOliver Neukum dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", 368afba937eSOliver Neukum req->wIndex); 369afba937eSOliver Neukum } 370afba937eSOliver Neukum out: 37117d80d56SOliver Neukum usb_autopm_put_interface(desc->intf); 37217d80d56SOliver Neukum outnp: 373afba937eSOliver Neukum mutex_unlock(&desc->wlock); 374afba937eSOliver Neukum outnl: 375afba937eSOliver Neukum return rv < 0 ? rv : count; 376afba937eSOliver Neukum } 377afba937eSOliver Neukum 378afba937eSOliver Neukum static ssize_t wdm_read 379afba937eSOliver Neukum (struct file *file, char __user *buffer, size_t count, loff_t *ppos) 380afba937eSOliver Neukum { 381afba937eSOliver Neukum int rv, cntr; 382afba937eSOliver Neukum int i = 0; 383afba937eSOliver Neukum struct wdm_device *desc = file->private_data; 384afba937eSOliver Neukum 385afba937eSOliver Neukum 386afba937eSOliver Neukum rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ 387afba937eSOliver Neukum if (rv < 0) 388afba937eSOliver Neukum return -ERESTARTSYS; 389afba937eSOliver Neukum 390afba937eSOliver Neukum if (desc->length == 0) { 391afba937eSOliver Neukum desc->read = 0; 392afba937eSOliver Neukum retry: 393afba937eSOliver Neukum i++; 394afba937eSOliver Neukum rv = wait_event_interruptible(desc->wait, 395afba937eSOliver Neukum test_bit(WDM_READ, &desc->flags)); 396afba937eSOliver Neukum 39717d80d56SOliver Neukum if (test_bit(WDM_DISCONNECTING, &desc->flags)) { 39817d80d56SOliver Neukum rv = -ENODEV; 39917d80d56SOliver Neukum goto err; 40017d80d56SOliver Neukum } 40117d80d56SOliver Neukum usb_mark_last_busy(interface_to_usbdev(desc->intf)); 402afba937eSOliver Neukum if (rv < 0) { 403afba937eSOliver Neukum rv = -ERESTARTSYS; 404afba937eSOliver Neukum goto err; 405afba937eSOliver Neukum } 406afba937eSOliver Neukum 407afba937eSOliver Neukum spin_lock_irq(&desc->iuspin); 408afba937eSOliver Neukum 409afba937eSOliver Neukum if (desc->rerr) { /* read completed, error happened */ 410afba937eSOliver Neukum int t = desc->rerr; 411afba937eSOliver Neukum desc->rerr = 0; 412afba937eSOliver Neukum spin_unlock_irq(&desc->iuspin); 4139908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 4149908a32eSGreg Kroah-Hartman "reading had resulted in %d\n", t); 415afba937eSOliver Neukum rv = -EIO; 416afba937eSOliver Neukum goto err; 417afba937eSOliver Neukum } 418afba937eSOliver Neukum /* 419afba937eSOliver Neukum * recheck whether we've lost the race 420afba937eSOliver Neukum * against the completion handler 421afba937eSOliver Neukum */ 422afba937eSOliver Neukum if (!test_bit(WDM_READ, &desc->flags)) { /* lost race */ 423afba937eSOliver Neukum spin_unlock_irq(&desc->iuspin); 424afba937eSOliver Neukum goto retry; 425afba937eSOliver Neukum } 426afba937eSOliver Neukum if (!desc->reslength) { /* zero length read */ 427afba937eSOliver Neukum spin_unlock_irq(&desc->iuspin); 428afba937eSOliver Neukum goto retry; 429afba937eSOliver Neukum } 430afba937eSOliver Neukum clear_bit(WDM_READ, &desc->flags); 431afba937eSOliver Neukum spin_unlock_irq(&desc->iuspin); 432afba937eSOliver Neukum } 433afba937eSOliver Neukum 434afba937eSOliver Neukum cntr = count > desc->length ? desc->length : count; 435afba937eSOliver Neukum rv = copy_to_user(buffer, desc->ubuf, cntr); 436afba937eSOliver Neukum if (rv > 0) { 437afba937eSOliver Neukum rv = -EFAULT; 438afba937eSOliver Neukum goto err; 439afba937eSOliver Neukum } 440afba937eSOliver Neukum 441afba937eSOliver Neukum for (i = 0; i < desc->length - cntr; i++) 442afba937eSOliver Neukum desc->ubuf[i] = desc->ubuf[i + cntr]; 443afba937eSOliver Neukum 444afba937eSOliver Neukum desc->length -= cntr; 44587d65e54SOliver Neukum /* in case we had outstanding data */ 44687d65e54SOliver Neukum if (!desc->length) 44787d65e54SOliver Neukum clear_bit(WDM_READ, &desc->flags); 448afba937eSOliver Neukum rv = cntr; 449afba937eSOliver Neukum 450afba937eSOliver Neukum err: 451afba937eSOliver Neukum mutex_unlock(&desc->rlock); 452afba937eSOliver Neukum if (rv < 0) 4539908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, "wdm_read: exit error\n"); 454afba937eSOliver Neukum return rv; 455afba937eSOliver Neukum } 456afba937eSOliver Neukum 457afba937eSOliver Neukum static int wdm_flush(struct file *file, fl_owner_t id) 458afba937eSOliver Neukum { 459afba937eSOliver Neukum struct wdm_device *desc = file->private_data; 460afba937eSOliver Neukum 461afba937eSOliver Neukum wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); 462afba937eSOliver Neukum if (desc->werr < 0) 4639908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, "Error in flush path: %d\n", 4649908a32eSGreg Kroah-Hartman desc->werr); 465afba937eSOliver Neukum 466afba937eSOliver Neukum return desc->werr; 467afba937eSOliver Neukum } 468afba937eSOliver Neukum 469afba937eSOliver Neukum static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) 470afba937eSOliver Neukum { 471afba937eSOliver Neukum struct wdm_device *desc = file->private_data; 472afba937eSOliver Neukum unsigned long flags; 473afba937eSOliver Neukum unsigned int mask = 0; 474afba937eSOliver Neukum 475afba937eSOliver Neukum spin_lock_irqsave(&desc->iuspin, flags); 476afba937eSOliver Neukum if (test_bit(WDM_DISCONNECTING, &desc->flags)) { 477afba937eSOliver Neukum mask = POLLERR; 478afba937eSOliver Neukum spin_unlock_irqrestore(&desc->iuspin, flags); 479afba937eSOliver Neukum goto desc_out; 480afba937eSOliver Neukum } 481afba937eSOliver Neukum if (test_bit(WDM_READ, &desc->flags)) 482afba937eSOliver Neukum mask = POLLIN | POLLRDNORM; 483afba937eSOliver Neukum if (desc->rerr || desc->werr) 484afba937eSOliver Neukum mask |= POLLERR; 485afba937eSOliver Neukum if (!test_bit(WDM_IN_USE, &desc->flags)) 486afba937eSOliver Neukum mask |= POLLOUT | POLLWRNORM; 487afba937eSOliver Neukum spin_unlock_irqrestore(&desc->iuspin, flags); 488afba937eSOliver Neukum 489afba937eSOliver Neukum poll_wait(file, &desc->wait, wait); 490afba937eSOliver Neukum 491afba937eSOliver Neukum desc_out: 492afba937eSOliver Neukum return mask; 493afba937eSOliver Neukum } 494afba937eSOliver Neukum 495afba937eSOliver Neukum static int wdm_open(struct inode *inode, struct file *file) 496afba937eSOliver Neukum { 497afba937eSOliver Neukum int minor = iminor(inode); 498afba937eSOliver Neukum int rv = -ENODEV; 499afba937eSOliver Neukum struct usb_interface *intf; 500afba937eSOliver Neukum struct wdm_device *desc; 501afba937eSOliver Neukum 502afba937eSOliver Neukum mutex_lock(&wdm_mutex); 503afba937eSOliver Neukum intf = usb_find_interface(&wdm_driver, minor); 504afba937eSOliver Neukum if (!intf) 505afba937eSOliver Neukum goto out; 506afba937eSOliver Neukum 507afba937eSOliver Neukum desc = usb_get_intfdata(intf); 508afba937eSOliver Neukum if (test_bit(WDM_DISCONNECTING, &desc->flags)) 509afba937eSOliver Neukum goto out; 510afba937eSOliver Neukum 51117d80d56SOliver Neukum ; 512afba937eSOliver Neukum file->private_data = desc; 513afba937eSOliver Neukum 51417d80d56SOliver Neukum rv = usb_autopm_get_interface(desc->intf); 51517d80d56SOliver Neukum if (rv < 0) { 5169908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); 51717d80d56SOliver Neukum goto out; 51817d80d56SOliver Neukum } 51917d80d56SOliver Neukum intf->needs_remote_wakeup = 1; 520afba937eSOliver Neukum 52117d80d56SOliver Neukum mutex_lock(&desc->plock); 52217d80d56SOliver Neukum if (!desc->count++) { 52317d80d56SOliver Neukum rv = usb_submit_urb(desc->validity, GFP_KERNEL); 524afba937eSOliver Neukum if (rv < 0) { 525afba937eSOliver Neukum desc->count--; 5269908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 5279908a32eSGreg Kroah-Hartman "Error submitting int urb - %d\n", rv); 528afba937eSOliver Neukum } 52917d80d56SOliver Neukum } else { 530afba937eSOliver Neukum rv = 0; 53117d80d56SOliver Neukum } 53217d80d56SOliver Neukum mutex_unlock(&desc->plock); 53317d80d56SOliver Neukum usb_autopm_put_interface(desc->intf); 534afba937eSOliver Neukum out: 535afba937eSOliver Neukum mutex_unlock(&wdm_mutex); 536afba937eSOliver Neukum return rv; 537afba937eSOliver Neukum } 538afba937eSOliver Neukum 539afba937eSOliver Neukum static int wdm_release(struct inode *inode, struct file *file) 540afba937eSOliver Neukum { 541afba937eSOliver Neukum struct wdm_device *desc = file->private_data; 542afba937eSOliver Neukum 543afba937eSOliver Neukum mutex_lock(&wdm_mutex); 54417d80d56SOliver Neukum mutex_lock(&desc->plock); 545afba937eSOliver Neukum desc->count--; 54617d80d56SOliver Neukum mutex_unlock(&desc->plock); 54717d80d56SOliver Neukum 548afba937eSOliver Neukum if (!desc->count) { 549afba937eSOliver Neukum dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); 550afba937eSOliver Neukum kill_urbs(desc); 55117d80d56SOliver Neukum if (!test_bit(WDM_DISCONNECTING, &desc->flags)) 55217d80d56SOliver Neukum desc->intf->needs_remote_wakeup = 0; 553afba937eSOliver Neukum } 554afba937eSOliver Neukum mutex_unlock(&wdm_mutex); 555afba937eSOliver Neukum return 0; 556afba937eSOliver Neukum } 557afba937eSOliver Neukum 558afba937eSOliver Neukum static const struct file_operations wdm_fops = { 559afba937eSOliver Neukum .owner = THIS_MODULE, 560afba937eSOliver Neukum .read = wdm_read, 561afba937eSOliver Neukum .write = wdm_write, 562afba937eSOliver Neukum .open = wdm_open, 563afba937eSOliver Neukum .flush = wdm_flush, 564afba937eSOliver Neukum .release = wdm_release, 565afba937eSOliver Neukum .poll = wdm_poll 566afba937eSOliver Neukum }; 567afba937eSOliver Neukum 568afba937eSOliver Neukum static struct usb_class_driver wdm_class = { 569afba937eSOliver Neukum .name = "cdc-wdm%d", 570afba937eSOliver Neukum .fops = &wdm_fops, 571afba937eSOliver Neukum .minor_base = WDM_MINOR_BASE, 572afba937eSOliver Neukum }; 573afba937eSOliver Neukum 574afba937eSOliver Neukum /* --- error handling --- */ 575afba937eSOliver Neukum static void wdm_rxwork(struct work_struct *work) 576afba937eSOliver Neukum { 577afba937eSOliver Neukum struct wdm_device *desc = container_of(work, struct wdm_device, rxwork); 578afba937eSOliver Neukum unsigned long flags; 579afba937eSOliver Neukum int rv; 580afba937eSOliver Neukum 581afba937eSOliver Neukum spin_lock_irqsave(&desc->iuspin, flags); 582afba937eSOliver Neukum if (test_bit(WDM_DISCONNECTING, &desc->flags)) { 583afba937eSOliver Neukum spin_unlock_irqrestore(&desc->iuspin, flags); 584afba937eSOliver Neukum } else { 585afba937eSOliver Neukum spin_unlock_irqrestore(&desc->iuspin, flags); 586afba937eSOliver Neukum rv = usb_submit_urb(desc->response, GFP_KERNEL); 587afba937eSOliver Neukum if (rv < 0 && rv != -EPERM) { 588afba937eSOliver Neukum spin_lock_irqsave(&desc->iuspin, flags); 589afba937eSOliver Neukum if (!test_bit(WDM_DISCONNECTING, &desc->flags)) 590afba937eSOliver Neukum schedule_work(&desc->rxwork); 591afba937eSOliver Neukum spin_unlock_irqrestore(&desc->iuspin, flags); 592afba937eSOliver Neukum } 593afba937eSOliver Neukum } 594afba937eSOliver Neukum } 595afba937eSOliver Neukum 596afba937eSOliver Neukum /* --- hotplug --- */ 597afba937eSOliver Neukum 598afba937eSOliver Neukum static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) 599afba937eSOliver Neukum { 600afba937eSOliver Neukum int rv = -EINVAL; 601afba937eSOliver Neukum struct usb_device *udev = interface_to_usbdev(intf); 602afba937eSOliver Neukum struct wdm_device *desc; 603afba937eSOliver Neukum struct usb_host_interface *iface; 604afba937eSOliver Neukum struct usb_endpoint_descriptor *ep; 605afba937eSOliver Neukum struct usb_cdc_dmm_desc *dmhd; 606afba937eSOliver Neukum u8 *buffer = intf->altsetting->extra; 607afba937eSOliver Neukum int buflen = intf->altsetting->extralen; 608afba937eSOliver Neukum u16 maxcom = 0; 609afba937eSOliver Neukum 610afba937eSOliver Neukum if (!buffer) 611afba937eSOliver Neukum goto out; 612afba937eSOliver Neukum 613afba937eSOliver Neukum while (buflen > 0) { 614afba937eSOliver Neukum if (buffer [1] != USB_DT_CS_INTERFACE) { 6159908a32eSGreg Kroah-Hartman dev_err(&intf->dev, "skipping garbage\n"); 616afba937eSOliver Neukum goto next_desc; 617afba937eSOliver Neukum } 618afba937eSOliver Neukum 619afba937eSOliver Neukum switch (buffer [2]) { 620afba937eSOliver Neukum case USB_CDC_HEADER_TYPE: 621afba937eSOliver Neukum break; 622afba937eSOliver Neukum case USB_CDC_DMM_TYPE: 623afba937eSOliver Neukum dmhd = (struct usb_cdc_dmm_desc *)buffer; 624afba937eSOliver Neukum maxcom = le16_to_cpu(dmhd->wMaxCommand); 625afba937eSOliver Neukum dev_dbg(&intf->dev, 626afba937eSOliver Neukum "Finding maximum buffer length: %d", maxcom); 627afba937eSOliver Neukum break; 628afba937eSOliver Neukum default: 6299908a32eSGreg Kroah-Hartman dev_err(&intf->dev, 6309908a32eSGreg Kroah-Hartman "Ignoring extra header, type %d, length %d\n", 631afba937eSOliver Neukum buffer[2], buffer[0]); 632afba937eSOliver Neukum break; 633afba937eSOliver Neukum } 634afba937eSOliver Neukum next_desc: 635afba937eSOliver Neukum buflen -= buffer[0]; 636afba937eSOliver Neukum buffer += buffer[0]; 637afba937eSOliver Neukum } 638afba937eSOliver Neukum 639afba937eSOliver Neukum rv = -ENOMEM; 640afba937eSOliver Neukum desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); 641afba937eSOliver Neukum if (!desc) 642afba937eSOliver Neukum goto out; 643afba937eSOliver Neukum mutex_init(&desc->wlock); 644afba937eSOliver Neukum mutex_init(&desc->rlock); 64517d80d56SOliver Neukum mutex_init(&desc->plock); 646afba937eSOliver Neukum spin_lock_init(&desc->iuspin); 647afba937eSOliver Neukum init_waitqueue_head(&desc->wait); 648afba937eSOliver Neukum desc->wMaxCommand = maxcom; 649afba937eSOliver Neukum desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); 650afba937eSOliver Neukum desc->intf = intf; 651afba937eSOliver Neukum INIT_WORK(&desc->rxwork, wdm_rxwork); 652afba937eSOliver Neukum 653afba937eSOliver Neukum iface = &intf->altsetting[0]; 654afba937eSOliver Neukum ep = &iface->endpoint[0].desc; 655afba937eSOliver Neukum if (!usb_endpoint_is_int_in(ep)) { 656afba937eSOliver Neukum rv = -EINVAL; 657afba937eSOliver Neukum goto err; 658afba937eSOliver Neukum } 659afba937eSOliver Neukum 660fa4144b7SAl Viro desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); 661fa4144b7SAl Viro desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0; 662afba937eSOliver Neukum 663afba937eSOliver Neukum desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); 664afba937eSOliver Neukum if (!desc->orq) 665afba937eSOliver Neukum goto err; 666afba937eSOliver Neukum desc->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); 667afba937eSOliver Neukum if (!desc->irq) 668afba937eSOliver Neukum goto err; 669afba937eSOliver Neukum 670afba937eSOliver Neukum desc->validity = usb_alloc_urb(0, GFP_KERNEL); 671afba937eSOliver Neukum if (!desc->validity) 672afba937eSOliver Neukum goto err; 673afba937eSOliver Neukum 674afba937eSOliver Neukum desc->response = usb_alloc_urb(0, GFP_KERNEL); 675afba937eSOliver Neukum if (!desc->response) 676afba937eSOliver Neukum goto err; 677afba937eSOliver Neukum 678afba937eSOliver Neukum desc->command = usb_alloc_urb(0, GFP_KERNEL); 679afba937eSOliver Neukum if (!desc->command) 680afba937eSOliver Neukum goto err; 681afba937eSOliver Neukum 682afba937eSOliver Neukum desc->ubuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); 683afba937eSOliver Neukum if (!desc->ubuf) 684afba937eSOliver Neukum goto err; 685afba937eSOliver Neukum 686afba937eSOliver Neukum desc->sbuf = usb_buffer_alloc(interface_to_usbdev(intf), 687afba937eSOliver Neukum desc->wMaxPacketSize, 688afba937eSOliver Neukum GFP_KERNEL, 689afba937eSOliver Neukum &desc->validity->transfer_dma); 690afba937eSOliver Neukum if (!desc->sbuf) 691afba937eSOliver Neukum goto err; 692afba937eSOliver Neukum 693afba937eSOliver Neukum desc->inbuf = usb_buffer_alloc(interface_to_usbdev(intf), 694afba937eSOliver Neukum desc->bMaxPacketSize0, 695afba937eSOliver Neukum GFP_KERNEL, 696afba937eSOliver Neukum &desc->response->transfer_dma); 697afba937eSOliver Neukum if (!desc->inbuf) 698afba937eSOliver Neukum goto err2; 699afba937eSOliver Neukum 700afba937eSOliver Neukum usb_fill_int_urb( 701afba937eSOliver Neukum desc->validity, 702afba937eSOliver Neukum interface_to_usbdev(intf), 703afba937eSOliver Neukum usb_rcvintpipe(interface_to_usbdev(intf), ep->bEndpointAddress), 704afba937eSOliver Neukum desc->sbuf, 705afba937eSOliver Neukum desc->wMaxPacketSize, 706afba937eSOliver Neukum wdm_int_callback, 707afba937eSOliver Neukum desc, 708afba937eSOliver Neukum ep->bInterval 709afba937eSOliver Neukum ); 710afba937eSOliver Neukum desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 711afba937eSOliver Neukum 712afba937eSOliver Neukum usb_set_intfdata(intf, desc); 713afba937eSOliver Neukum rv = usb_register_dev(intf, &wdm_class); 714afba937eSOliver Neukum dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n", 715afba937eSOliver Neukum intf->minor - WDM_MINOR_BASE); 716afba937eSOliver Neukum if (rv < 0) 717afba937eSOliver Neukum goto err; 718afba937eSOliver Neukum out: 719afba937eSOliver Neukum return rv; 720afba937eSOliver Neukum err2: 721afba937eSOliver Neukum usb_buffer_free(interface_to_usbdev(desc->intf), 722afba937eSOliver Neukum desc->wMaxPacketSize, 723afba937eSOliver Neukum desc->sbuf, 724afba937eSOliver Neukum desc->validity->transfer_dma); 725afba937eSOliver Neukum err: 726afba937eSOliver Neukum free_urbs(desc); 727afba937eSOliver Neukum kfree(desc->ubuf); 728afba937eSOliver Neukum kfree(desc->orq); 729afba937eSOliver Neukum kfree(desc->irq); 730afba937eSOliver Neukum kfree(desc); 731afba937eSOliver Neukum return rv; 732afba937eSOliver Neukum } 733afba937eSOliver Neukum 734afba937eSOliver Neukum static void wdm_disconnect(struct usb_interface *intf) 735afba937eSOliver Neukum { 736afba937eSOliver Neukum struct wdm_device *desc; 737afba937eSOliver Neukum unsigned long flags; 738afba937eSOliver Neukum 739afba937eSOliver Neukum usb_deregister_dev(intf, &wdm_class); 740afba937eSOliver Neukum mutex_lock(&wdm_mutex); 741afba937eSOliver Neukum desc = usb_get_intfdata(intf); 742afba937eSOliver Neukum 743afba937eSOliver Neukum /* the spinlock makes sure no new urbs are generated in the callbacks */ 744afba937eSOliver Neukum spin_lock_irqsave(&desc->iuspin, flags); 745afba937eSOliver Neukum set_bit(WDM_DISCONNECTING, &desc->flags); 746afba937eSOliver Neukum set_bit(WDM_READ, &desc->flags); 74717d80d56SOliver Neukum /* to terminate pending flushes */ 748afba937eSOliver Neukum clear_bit(WDM_IN_USE, &desc->flags); 749afba937eSOliver Neukum spin_unlock_irqrestore(&desc->iuspin, flags); 750afba937eSOliver Neukum cancel_work_sync(&desc->rxwork); 751afba937eSOliver Neukum kill_urbs(desc); 752afba937eSOliver Neukum wake_up_all(&desc->wait); 753afba937eSOliver Neukum if (!desc->count) 754afba937eSOliver Neukum cleanup(desc); 755afba937eSOliver Neukum mutex_unlock(&wdm_mutex); 756afba937eSOliver Neukum } 757afba937eSOliver Neukum 75817d80d56SOliver Neukum static int wdm_suspend(struct usb_interface *intf, pm_message_t message) 75917d80d56SOliver Neukum { 76017d80d56SOliver Neukum struct wdm_device *desc = usb_get_intfdata(intf); 76117d80d56SOliver Neukum int rv = 0; 76217d80d56SOliver Neukum 76317d80d56SOliver Neukum dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); 76417d80d56SOliver Neukum 76517d80d56SOliver Neukum mutex_lock(&desc->plock); 76635758589SOliver Neukum #ifdef CONFIG_PM 76765bfd296SAlan Stern if ((message.event & PM_EVENT_AUTO) && 76865bfd296SAlan Stern test_bit(WDM_IN_USE, &desc->flags)) { 76917d80d56SOliver Neukum rv = -EBUSY; 77017d80d56SOliver Neukum } else { 77135758589SOliver Neukum #endif 77217d80d56SOliver Neukum cancel_work_sync(&desc->rxwork); 77317d80d56SOliver Neukum kill_urbs(desc); 77435758589SOliver Neukum #ifdef CONFIG_PM 77517d80d56SOliver Neukum } 77635758589SOliver Neukum #endif 77717d80d56SOliver Neukum mutex_unlock(&desc->plock); 77817d80d56SOliver Neukum 77917d80d56SOliver Neukum return rv; 78017d80d56SOliver Neukum } 78117d80d56SOliver Neukum 78217d80d56SOliver Neukum static int recover_from_urb_loss(struct wdm_device *desc) 78317d80d56SOliver Neukum { 78417d80d56SOliver Neukum int rv = 0; 78517d80d56SOliver Neukum 78617d80d56SOliver Neukum if (desc->count) { 78717d80d56SOliver Neukum rv = usb_submit_urb(desc->validity, GFP_NOIO); 78817d80d56SOliver Neukum if (rv < 0) 7899908a32eSGreg Kroah-Hartman dev_err(&desc->intf->dev, 7909908a32eSGreg Kroah-Hartman "Error resume submitting int urb - %d\n", rv); 79117d80d56SOliver Neukum } 79217d80d56SOliver Neukum return rv; 79317d80d56SOliver Neukum } 79417d80d56SOliver Neukum static int wdm_resume(struct usb_interface *intf) 79517d80d56SOliver Neukum { 79617d80d56SOliver Neukum struct wdm_device *desc = usb_get_intfdata(intf); 79717d80d56SOliver Neukum int rv; 79817d80d56SOliver Neukum 79917d80d56SOliver Neukum dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); 80017d80d56SOliver Neukum mutex_lock(&desc->plock); 80117d80d56SOliver Neukum rv = recover_from_urb_loss(desc); 80217d80d56SOliver Neukum mutex_unlock(&desc->plock); 80317d80d56SOliver Neukum return rv; 80417d80d56SOliver Neukum } 80517d80d56SOliver Neukum 80617d80d56SOliver Neukum static int wdm_pre_reset(struct usb_interface *intf) 80717d80d56SOliver Neukum { 80817d80d56SOliver Neukum struct wdm_device *desc = usb_get_intfdata(intf); 80917d80d56SOliver Neukum 81017d80d56SOliver Neukum mutex_lock(&desc->plock); 81117d80d56SOliver Neukum return 0; 81217d80d56SOliver Neukum } 81317d80d56SOliver Neukum 81417d80d56SOliver Neukum static int wdm_post_reset(struct usb_interface *intf) 81517d80d56SOliver Neukum { 81617d80d56SOliver Neukum struct wdm_device *desc = usb_get_intfdata(intf); 81717d80d56SOliver Neukum int rv; 81817d80d56SOliver Neukum 81917d80d56SOliver Neukum rv = recover_from_urb_loss(desc); 82017d80d56SOliver Neukum mutex_unlock(&desc->plock); 82117d80d56SOliver Neukum return 0; 82217d80d56SOliver Neukum } 82317d80d56SOliver Neukum 824afba937eSOliver Neukum static struct usb_driver wdm_driver = { 825afba937eSOliver Neukum .name = "cdc_wdm", 826afba937eSOliver Neukum .probe = wdm_probe, 827afba937eSOliver Neukum .disconnect = wdm_disconnect, 82817d80d56SOliver Neukum .suspend = wdm_suspend, 82917d80d56SOliver Neukum .resume = wdm_resume, 83017d80d56SOliver Neukum .reset_resume = wdm_resume, 83117d80d56SOliver Neukum .pre_reset = wdm_pre_reset, 83217d80d56SOliver Neukum .post_reset = wdm_post_reset, 833afba937eSOliver Neukum .id_table = wdm_ids, 83417d80d56SOliver Neukum .supports_autosuspend = 1, 835afba937eSOliver Neukum }; 836afba937eSOliver Neukum 837afba937eSOliver Neukum /* --- low level module stuff --- */ 838afba937eSOliver Neukum 839afba937eSOliver Neukum static int __init wdm_init(void) 840afba937eSOliver Neukum { 841afba937eSOliver Neukum int rv; 842afba937eSOliver Neukum 843afba937eSOliver Neukum rv = usb_register(&wdm_driver); 844afba937eSOliver Neukum 845afba937eSOliver Neukum return rv; 846afba937eSOliver Neukum } 847afba937eSOliver Neukum 848afba937eSOliver Neukum static void __exit wdm_exit(void) 849afba937eSOliver Neukum { 850afba937eSOliver Neukum usb_deregister(&wdm_driver); 851afba937eSOliver Neukum } 852afba937eSOliver Neukum 853afba937eSOliver Neukum module_init(wdm_init); 854afba937eSOliver Neukum module_exit(wdm_exit); 855afba937eSOliver Neukum 856afba937eSOliver Neukum MODULE_AUTHOR(DRIVER_AUTHOR); 85787d65e54SOliver Neukum MODULE_DESCRIPTION(DRIVER_DESC); 858afba937eSOliver Neukum MODULE_LICENSE("GPL"); 859