^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * cdc-wdm.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This driver supports USB CDC WCM Device Management.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2007-2009 Oliver Neukum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Some code taken from cdc-acm.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Released under the GPLv2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Many thanks to Carl Nordbeck
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/poll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/usb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/usb/cdc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/byteorder.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/usb/cdc-wdm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define DRIVER_AUTHOR "Oliver Neukum"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static const struct usb_device_id wdm_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) USB_DEVICE_ID_MATCH_INT_SUBCLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .bInterfaceClass = USB_CLASS_COMM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) MODULE_DEVICE_TABLE (usb, wdm_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define WDM_MINOR_BASE 176
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define WDM_IN_USE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define WDM_DISCONNECTING 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define WDM_RESULT 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define WDM_READ 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define WDM_INT_STALL 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define WDM_POLL_RUNNING 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define WDM_RESPONDING 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define WDM_SUSPENDING 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define WDM_RESETTING 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define WDM_OVERFLOW 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define WDM_MAX 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* we cannot wait forever at flush() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define WDM_FLUSH_TIMEOUT (30 * HZ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define WDM_DEFAULT_BUFSIZE 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static DEFINE_MUTEX(wdm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static DEFINE_SPINLOCK(wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static LIST_HEAD(wdm_device_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* --- method tables --- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct wdm_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) u8 *inbuf; /* buffer for response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) u8 *outbuf; /* buffer for command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) u8 *sbuf; /* buffer for status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) u8 *ubuf; /* buffer for copy to user space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct urb *command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct urb *response;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct urb *validity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct usb_interface *intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct usb_ctrlrequest *orq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct usb_ctrlrequest *irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) spinlock_t iuspin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u16 bufsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u16 wMaxCommand;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) u16 wMaxPacketSize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) __le16 inum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int reslength;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) int read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) int count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) dma_addr_t shandle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) dma_addr_t ihandle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct mutex wlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct mutex rlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) wait_queue_head_t wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct work_struct rxwork;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct work_struct service_outs_intr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) int werr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int rerr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int resp_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct list_head device_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int (*manage_power)(struct usb_interface *, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static struct usb_driver wdm_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* return intfdata if we own the interface, else look up intf in the list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static struct wdm_device *wdm_find_device(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) spin_lock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) list_for_each_entry(desc, &wdm_device_list, device_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (desc->intf == intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) goto found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) desc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) found:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) spin_unlock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static struct wdm_device *wdm_find_device_by_minor(int minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) spin_lock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) list_for_each_entry(desc, &wdm_device_list, device_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (desc->intf->minor == minor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) goto found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) desc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) found:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) spin_unlock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* --- callbacks --- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static void wdm_out_callback(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) desc = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) spin_lock_irqsave(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) desc->werr = urb->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) kfree(desc->outbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) desc->outbuf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) clear_bit(WDM_IN_USE, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) wake_up_all(&desc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static void wdm_in_callback(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct wdm_device *desc = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) int status = urb->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) int length = urb->actual_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) spin_lock_irqsave(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) clear_bit(WDM_RESPONDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) switch (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) case -ENOENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) dev_dbg(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) "nonzero urb status received: -ENOENT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) goto skip_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) case -ECONNRESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) dev_dbg(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) "nonzero urb status received: -ECONNRESET\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) goto skip_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) case -ESHUTDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) dev_dbg(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) "nonzero urb status received: -ESHUTDOWN\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) goto skip_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) case -EPIPE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) "nonzero urb status received: -EPIPE\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) "Unexpected error %d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * only set a new error if there is no previous error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * Errors are only cleared during read/open
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * Avoid propagating -EPIPE (stall) to userspace since it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * better handled as an empty read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (desc->rerr == 0 && status != -EPIPE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) desc->rerr = status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (length + desc->length > desc->wMaxCommand) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /* The buffer would overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) set_bit(WDM_OVERFLOW, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* we may already be in overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) memmove(desc->ubuf + desc->length, desc->inbuf, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) desc->length += length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) desc->reslength = length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) skip_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (desc->rerr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * Since there was an error, userspace may decide to not read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * any data after poll'ing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * We should respond to further attempts from the device to send
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * data, so that we can get unstuck.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) schedule_work(&desc->service_outs_intr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) set_bit(WDM_READ, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) wake_up(&desc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static void wdm_int_callback(struct urb *urb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) int responding;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) int status = urb->status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct usb_cdc_notification *dr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) desc = urb->context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) dr = (struct usb_cdc_notification *)desc->sbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) switch (status) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) case -ESHUTDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) case -ENOENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) case -ECONNRESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return; /* unplug */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case -EPIPE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) set_bit(WDM_INT_STALL, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dev_err(&desc->intf->dev, "Stall on int endpoint\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) goto sw; /* halt is cleared in work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) "nonzero urb status received: %d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (urb->actual_length < sizeof(struct usb_cdc_notification)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) dev_err(&desc->intf->dev, "wdm_int_callback - %d bytes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) urb->actual_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) switch (dr->bNotificationType) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) dev_dbg(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) le16_to_cpu(dr->wIndex), le16_to_cpu(dr->wLength));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) case USB_CDC_NOTIFY_NETWORK_CONNECTION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dev_dbg(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) "NOTIFY_NETWORK_CONNECTION %s network\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) dr->wValue ? "connected to" : "disconnected from");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) case USB_CDC_NOTIFY_SPEED_CHANGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) dev_dbg(&desc->intf->dev, "SPEED_CHANGE received (len %u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) urb->actual_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) clear_bit(WDM_POLL_RUNNING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) "unknown notification %d received: index %d len %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) dr->bNotificationType,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) le16_to_cpu(dr->wIndex),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) le16_to_cpu(dr->wLength));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) spin_lock_irqsave(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (!desc->resp_count++ && !responding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) && !test_bit(WDM_DISCONNECTING, &desc->flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) && !test_bit(WDM_SUSPENDING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) rv = usb_submit_urb(desc->response, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (rv < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) clear_bit(WDM_RESPONDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (rv == -EPERM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (rv == -ENOMEM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) sw:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) rv = schedule_work(&desc->rxwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) "Cannot schedule work\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) rv = usb_submit_urb(urb, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) "%s - usb_submit_urb failed with result %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) __func__, rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) static void poison_urbs(struct wdm_device *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /* the order here is essential */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) usb_poison_urb(desc->command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) usb_poison_urb(desc->validity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) usb_poison_urb(desc->response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) static void unpoison_urbs(struct wdm_device *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * the order here is not essential
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) * it is symmetrical just to be nice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) usb_unpoison_urb(desc->response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) usb_unpoison_urb(desc->validity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) usb_unpoison_urb(desc->command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static void free_urbs(struct wdm_device *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) usb_free_urb(desc->validity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) usb_free_urb(desc->response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) usb_free_urb(desc->command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static void cleanup(struct wdm_device *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) kfree(desc->sbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) kfree(desc->inbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) kfree(desc->orq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) kfree(desc->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) kfree(desc->ubuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) free_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) kfree(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) static ssize_t wdm_write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) (struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) u8 *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) int rv = -EMSGSIZE, r, we;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) struct wdm_device *desc = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) struct usb_ctrlrequest *req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (count > desc->wMaxCommand)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) count = desc->wMaxCommand;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) we = desc->werr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) desc->werr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (we < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) return usb_translate_errors(we);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) buf = memdup_user(buffer, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (IS_ERR(buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return PTR_ERR(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /* concurrent writes and disconnect */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) r = mutex_lock_interruptible(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) rv = -ERESTARTSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) goto out_free_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) rv = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) goto out_free_mem_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) r = usb_autopm_get_interface(desc->intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (r < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) rv = usb_translate_errors(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) goto out_free_mem_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (!(file->f_flags & O_NONBLOCK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) &desc->flags));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (test_bit(WDM_IN_USE, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) r = -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (test_bit(WDM_RESETTING, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) r = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (test_bit(WDM_DISCONNECTING, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) r = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (r < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) rv = r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) goto out_free_mem_pm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) req = desc->orq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) usb_fill_control_urb(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) desc->command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) interface_to_usbdev(desc->intf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) /* using common endpoint 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) usb_sndctrlpipe(interface_to_usbdev(desc->intf), 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) (unsigned char *)req,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) wdm_out_callback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) desc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) USB_RECIP_INTERFACE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) req->wValue = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) req->wIndex = desc->inum; /* already converted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) req->wLength = cpu_to_le16(count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) set_bit(WDM_IN_USE, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) desc->outbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) rv = usb_submit_urb(desc->command, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (rv < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) desc->outbuf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) clear_bit(WDM_IN_USE, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) wake_up_all(&desc->wait); /* for wdm_wait_for_response() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) rv = usb_translate_errors(rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) goto out_free_mem_pm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) le16_to_cpu(req->wIndex));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) usb_autopm_put_interface(desc->intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) mutex_unlock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) out_free_mem_pm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) usb_autopm_put_interface(desc->intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) out_free_mem_lock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) mutex_unlock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) out_free_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * Submit the read urb if resp_count is non-zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * Called with desc->iuspin locked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) static int service_outstanding_interrupt(struct wdm_device *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) /* submit read urb only if the device is waiting for it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (!desc->resp_count || !--desc->resp_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) rv = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (test_bit(WDM_RESETTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) rv = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) set_bit(WDM_RESPONDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) rv = usb_submit_urb(desc->response, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (rv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (!test_bit(WDM_DISCONNECTING, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) "usb_submit_urb failed with result %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) /* make sure the next notification trigger a submit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) clear_bit(WDM_RESPONDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) desc->resp_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) static ssize_t wdm_read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) (struct file *file, char __user *buffer, size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int rv, cntr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct wdm_device *desc = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) return -ERESTARTSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) cntr = READ_ONCE(desc->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (cntr == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) desc->read = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) rv = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (test_bit(WDM_OVERFLOW, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) clear_bit(WDM_OVERFLOW, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) rv = -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) if (file->f_flags & O_NONBLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) if (!test_bit(WDM_READ, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) rv = -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) rv = wait_event_interruptible(desc->wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) test_bit(WDM_READ, &desc->flags));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /* may have happened while we slept */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) rv = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (test_bit(WDM_RESETTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) rv = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) usb_mark_last_busy(interface_to_usbdev(desc->intf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (rv < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) rv = -ERESTARTSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (desc->rerr) { /* read completed, error happened */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) rv = usb_translate_errors(desc->rerr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) desc->rerr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * recheck whether we've lost the race
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * against the completion handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) if (!test_bit(WDM_READ, &desc->flags)) { /* lost race */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (!desc->reslength) { /* zero length read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) clear_bit(WDM_READ, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) rv = service_outstanding_interrupt(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) cntr = desc->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (cntr > count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) cntr = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) rv = copy_to_user(buffer, desc->ubuf, cntr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (rv > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) rv = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) for (i = 0; i < desc->length - cntr; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) desc->ubuf[i] = desc->ubuf[i + cntr];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) desc->length -= cntr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) /* in case we had outstanding data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (!desc->length) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) clear_bit(WDM_READ, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) service_outstanding_interrupt(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) rv = cntr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) mutex_unlock(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) static int wdm_wait_for_response(struct file *file, long timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) struct wdm_device *desc = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) long rv; /* Use long here because (int) MAX_SCHEDULE_TIMEOUT < 0. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) * Needs both flags. We cannot do with one because resetting it would
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * cause a race with write() yet we need to signal a disconnect.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) rv = wait_event_interruptible_timeout(desc->wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) !test_bit(WDM_IN_USE, &desc->flags) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) test_bit(WDM_DISCONNECTING, &desc->flags),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * To report the correct error. This is best effort.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * We are inevitably racing with the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (test_bit(WDM_DISCONNECTING, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) if (!rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) rv = desc->werr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) desc->werr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) return usb_translate_errors(rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * You need to send a signal when you react to malicious or defective hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * Also, don't abort when fsync() returned -EINVAL, for older kernels which do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) * not implement wdm_flush() will return -EINVAL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) static int wdm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return wdm_wait_for_response(file, MAX_SCHEDULE_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * Same with wdm_fsync(), except it uses finite timeout in order to react to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * malicious or defective hardware which ceased communication after close() was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * implicitly called due to process termination.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static int wdm_flush(struct file *file, fl_owner_t id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) return wdm_wait_for_response(file, WDM_FLUSH_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) static __poll_t wdm_poll(struct file *file, struct poll_table_struct *wait)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) struct wdm_device *desc = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) __poll_t mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) spin_lock_irqsave(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) mask = EPOLLHUP | EPOLLERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) goto desc_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (test_bit(WDM_READ, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) mask = EPOLLIN | EPOLLRDNORM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if (desc->rerr || desc->werr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) mask |= EPOLLERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (!test_bit(WDM_IN_USE, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) mask |= EPOLLOUT | EPOLLWRNORM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) poll_wait(file, &desc->wait, wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) desc_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) return mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) static int wdm_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) int minor = iminor(inode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) int rv = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) struct usb_interface *intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) mutex_lock(&wdm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) desc = wdm_find_device_by_minor(minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (!desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) intf = desc->intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (test_bit(WDM_DISCONNECTING, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) file->private_data = desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) rv = usb_autopm_get_interface(desc->intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (rv < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) /* using write lock to protect desc->count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) mutex_lock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (!desc->count++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) desc->werr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) desc->rerr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) rv = usb_submit_urb(desc->validity, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (rv < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) desc->count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) "Error submitting int urb - %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) rv = usb_translate_errors(rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) mutex_unlock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (desc->count == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) desc->manage_power(intf, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) usb_autopm_put_interface(desc->intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) mutex_unlock(&wdm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) static int wdm_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) struct wdm_device *desc = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) mutex_lock(&wdm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) /* using write lock to protect desc->count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) mutex_lock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) desc->count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) mutex_unlock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) if (!desc->count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) dev_dbg(&desc->intf->dev, "wdm_release: cleanup\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) poison_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) desc->resp_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) desc->manage_power(desc->intf, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) unpoison_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) /* must avoid dev_printk here as desc->intf is invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) cleanup(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) mutex_unlock(&wdm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) struct wdm_device *desc = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) case IOCTL_WDM_MAX_COMMAND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) rv = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) rv = -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static const struct file_operations wdm_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) .read = wdm_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) .write = wdm_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) .fsync = wdm_fsync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) .open = wdm_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) .flush = wdm_flush,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) .release = wdm_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) .poll = wdm_poll,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) .unlocked_ioctl = wdm_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) .compat_ioctl = compat_ptr_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) .llseek = noop_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) static struct usb_class_driver wdm_class = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) .name = "cdc-wdm%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) .fops = &wdm_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) .minor_base = WDM_MINOR_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) /* --- error handling --- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) static void wdm_rxwork(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) struct wdm_device *desc = container_of(work, struct wdm_device, rxwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) int responding;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) spin_lock_irqsave(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) if (!responding)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) rv = usb_submit_urb(desc->response, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) if (rv < 0 && rv != -EPERM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) spin_lock_irqsave(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) clear_bit(WDM_RESPONDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (!test_bit(WDM_DISCONNECTING, &desc->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) schedule_work(&desc->rxwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) static void service_interrupt_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) desc = container_of(work, struct wdm_device, service_outs_intr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) service_outstanding_interrupt(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) if (!desc->resp_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) set_bit(WDM_READ, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) wake_up(&desc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) /* --- hotplug --- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) u16 bufsize, int (*manage_power)(struct usb_interface *, int))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) int rv = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) if (!desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) INIT_LIST_HEAD(&desc->device_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) mutex_init(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) mutex_init(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) spin_lock_init(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) init_waitqueue_head(&desc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) desc->wMaxCommand = bufsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) /* this will be expanded and needed in hardware endianness */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) desc->intf = intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) INIT_WORK(&desc->rxwork, wdm_rxwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) INIT_WORK(&desc->service_outs_intr, service_interrupt_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) rv = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (!usb_endpoint_is_int_in(ep))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) desc->wMaxPacketSize = usb_endpoint_maxp(ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (!desc->orq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) desc->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) if (!desc->irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) desc->validity = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) if (!desc->validity)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) desc->response = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) if (!desc->response)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) desc->command = usb_alloc_urb(0, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) if (!desc->command)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) desc->ubuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) if (!desc->ubuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) if (!desc->sbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) if (!desc->inbuf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) usb_fill_int_urb(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) desc->validity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) interface_to_usbdev(intf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) usb_rcvintpipe(interface_to_usbdev(intf), ep->bEndpointAddress),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) desc->sbuf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) desc->wMaxPacketSize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) wdm_int_callback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) ep->bInterval
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) desc->irq->wValue = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) desc->irq->wIndex = desc->inum; /* already converted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) usb_fill_control_urb(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) desc->response,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) interface_to_usbdev(intf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) /* using common endpoint 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) (unsigned char *)desc->irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) desc->inbuf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) desc->wMaxCommand,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) wdm_in_callback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) desc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) desc->manage_power = manage_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) spin_lock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) list_add(&desc->device_list, &wdm_device_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) spin_unlock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) rv = usb_register_dev(intf, &wdm_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) spin_lock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) list_del(&desc->device_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) spin_unlock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) cleanup(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) static int wdm_manage_power(struct usb_interface *intf, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) /* need autopm_get/put here to ensure the usbcore sees the new value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) int rv = usb_autopm_get_interface(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) intf->needs_remote_wakeup = on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) if (!rv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) usb_autopm_put_interface(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) int rv = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) struct usb_host_interface *iface;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) struct usb_endpoint_descriptor *ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) struct usb_cdc_parsed_header hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) u8 *buffer = intf->altsetting->extra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) int buflen = intf->altsetting->extralen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) u16 maxcom = WDM_DEFAULT_BUFSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) if (!buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) cdc_parse_cdc_header(&hdr, intf, buffer, buflen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (hdr.usb_cdc_dmm_desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) maxcom = le16_to_cpu(hdr.usb_cdc_dmm_desc->wMaxCommand);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) iface = intf->cur_altsetting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) if (iface->desc.bNumEndpoints != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) ep = &iface->endpoint[0].desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) * usb_cdc_wdm_register - register a WDM subdriver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) * @intf: usb interface the subdriver will associate with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * @ep: interrupt endpoint to monitor for notifications
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * @bufsize: maximum message size to support for read/write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) * @manage_power: call-back invoked during open and release to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) * manage the device's power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) * Create WDM usb class character device and associate it with intf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) * without binding, allowing another driver to manage the interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) * The subdriver will manage the given interrupt endpoint exclusively
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) * and will issue control requests referring to the given intf. It
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) * will otherwise avoid interferring, and in particular not do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) * usb_set_intfdata/usb_get_intfdata on intf.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) * The return value is a pointer to the subdriver's struct usb_driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) * The registering driver is responsible for calling this subdriver's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) * disconnect, suspend, resume, pre_reset and post_reset methods from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) * its own.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) struct usb_endpoint_descriptor *ep,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) int bufsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) int (*manage_power)(struct usb_interface *, int))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) rv = wdm_create(intf, ep, bufsize, manage_power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) return &wdm_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) return ERR_PTR(rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) EXPORT_SYMBOL(usb_cdc_wdm_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) static void wdm_disconnect(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) struct wdm_device *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) usb_deregister_dev(intf, &wdm_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) desc = wdm_find_device(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) mutex_lock(&wdm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) /* the spinlock makes sure no new urbs are generated in the callbacks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) spin_lock_irqsave(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) set_bit(WDM_DISCONNECTING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) set_bit(WDM_READ, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) spin_unlock_irqrestore(&desc->iuspin, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) wake_up_all(&desc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) mutex_lock(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) mutex_lock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) poison_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) cancel_work_sync(&desc->rxwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) cancel_work_sync(&desc->service_outs_intr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) mutex_unlock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) mutex_unlock(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) /* the desc->intf pointer used as list key is now invalid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) spin_lock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) list_del(&desc->device_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) spin_unlock(&wdm_device_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) if (!desc->count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) cleanup(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) dev_dbg(&intf->dev, "%d open files - postponing cleanup\n", desc->count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) mutex_unlock(&wdm_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) struct wdm_device *desc = wdm_find_device(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) /* if this is an autosuspend the caller does the locking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) if (!PMSG_IS_AUTO(message)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) mutex_lock(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) mutex_lock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) if (PMSG_IS_AUTO(message) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) (test_bit(WDM_IN_USE, &desc->flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) || test_bit(WDM_RESPONDING, &desc->flags))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) rv = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) set_bit(WDM_SUSPENDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) /* callback submits work - order is essential */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) poison_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) cancel_work_sync(&desc->rxwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) cancel_work_sync(&desc->service_outs_intr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) unpoison_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) if (!PMSG_IS_AUTO(message)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) mutex_unlock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) mutex_unlock(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) static int recover_from_urb_loss(struct wdm_device *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) int rv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) if (desc->count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) rv = usb_submit_urb(desc->validity, GFP_NOIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) dev_err(&desc->intf->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) "Error resume submitting int urb - %d\n", rv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) static int wdm_resume(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) struct wdm_device *desc = wdm_find_device(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) clear_bit(WDM_SUSPENDING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) rv = recover_from_urb_loss(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) static int wdm_pre_reset(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) struct wdm_device *desc = wdm_find_device(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) * we notify everybody using poll of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) * an exceptional situation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) * must be done before recovery lest a spontaneous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) * message from the device is lost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) spin_lock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) set_bit(WDM_READ, &desc->flags); /* unblock read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) desc->rerr = -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) spin_unlock_irq(&desc->iuspin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) wake_up_all(&desc->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) mutex_lock(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) mutex_lock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) poison_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) cancel_work_sync(&desc->rxwork);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) cancel_work_sync(&desc->service_outs_intr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) static int wdm_post_reset(struct usb_interface *intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) struct wdm_device *desc = wdm_find_device(intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) int rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) unpoison_urbs(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) clear_bit(WDM_OVERFLOW, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) clear_bit(WDM_RESETTING, &desc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) rv = recover_from_urb_loss(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) mutex_unlock(&desc->wlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) mutex_unlock(&desc->rlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) static struct usb_driver wdm_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) .name = "cdc_wdm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) .probe = wdm_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) .disconnect = wdm_disconnect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) .suspend = wdm_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) .resume = wdm_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) .reset_resume = wdm_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) .pre_reset = wdm_pre_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) .post_reset = wdm_post_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) .id_table = wdm_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) .supports_autosuspend = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) .disable_hub_initiated_lpm = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) module_usb_driver(wdm_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) MODULE_AUTHOR(DRIVER_AUTHOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) MODULE_DESCRIPTION(DRIVER_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) MODULE_LICENSE("GPL");