diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/drivers/usb/class | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'ANDROID_3.4.5/drivers/usb/class')
-rw-r--r-- | ANDROID_3.4.5/drivers/usb/class/Kconfig | 52 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/usb/class/Makefile | 9 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/usb/class/cdc-acm.c | 1752 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/usb/class/cdc-acm.h | 130 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c | 1048 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/usb/class/usblp.c | 1421 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/usb/class/usbtmc.c | 1121 |
7 files changed, 0 insertions, 5533 deletions
diff --git a/ANDROID_3.4.5/drivers/usb/class/Kconfig b/ANDROID_3.4.5/drivers/usb/class/Kconfig deleted file mode 100644 index 2519e320..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -# -# USB Class driver configuration -# -comment "USB Device Class drivers" - depends on USB - -config USB_ACM - tristate "USB Modem (CDC ACM) support" - depends on USB - ---help--- - This driver supports USB modems and ISDN adapters which support the - Communication Device Class Abstract Control Model interface. - Please read <file:Documentation/usb/acm.txt> for details. - - If your modem only reports "Cls=ff(vend.)" in the descriptors in - /proc/bus/usb/devices, then your modem will not work with this - driver. - - To compile this driver as a module, choose M here: the - module will be called cdc-acm. - -config USB_PRINTER - tristate "USB Printer support" - depends on USB - help - Say Y here if you want to connect a USB printer to your computer's - USB port. - - To compile this driver as a module, choose M here: the - module will be called usblp. - -config USB_WDM - tristate "USB Wireless Device Management support" - depends on USB - ---help--- - This driver supports the WMC Device Management functionality - of cell phones compliant to the CDC WMC specification. You can use - AT commands over this device. - - To compile this driver as a module, choose M here: the - module will be called cdc-wdm. - -config USB_TMC - tristate "USB Test and Measurement Class support" - depends on USB - help - Say Y here if you want to connect a USB device that follows - the USB.org specification for USB Test and Measurement devices - to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called usbtmc. diff --git a/ANDROID_3.4.5/drivers/usb/class/Makefile b/ANDROID_3.4.5/drivers/usb/class/Makefile deleted file mode 100644 index 32e85277..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for USB Class drivers -# (one step up from the misc category) -# - -obj-$(CONFIG_USB_ACM) += cdc-acm.o -obj-$(CONFIG_USB_PRINTER) += usblp.o -obj-$(CONFIG_USB_WDM) += cdc-wdm.o -obj-$(CONFIG_USB_TMC) += usbtmc.o diff --git a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.c b/ANDROID_3.4.5/drivers/usb/class/cdc-acm.c deleted file mode 100644 index 640cf798..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.c +++ /dev/null @@ -1,1752 +0,0 @@ -/* - * cdc-acm.c - * - * Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de> - * Copyright (c) 1999 Pavel Machek <pavel@ucw.cz> - * Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com> - * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> - * Copyright (c) 2004 Oliver Neukum <oliver@neukum.name> - * Copyright (c) 2005 David Kubicek <dave@awk.cz> - * Copyright (c) 2011 Johan Hovold <jhovold@gmail.com> - * - * USB Abstract Control Model driver for USB modems and ISDN adapters - * - * Sponsored by SuSE - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#undef DEBUG -#undef VERBOSE_DEBUG - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/serial.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <asm/byteorder.h> -#include <asm/unaligned.h> -#include <linux/list.h> - -#include "cdc-acm.h" - - -#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold" -#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" - -static struct usb_driver acm_driver; -static struct tty_driver *acm_tty_driver; -static struct acm *acm_table[ACM_TTY_MINORS]; - -static DEFINE_MUTEX(acm_table_lock); - -/* - * acm_table accessors - */ - -/* - * Look up an ACM structure by index. If found and not disconnected, increment - * its refcount and return it with its mutex held. - */ -static struct acm *acm_get_by_index(unsigned index) -{ - struct acm *acm; - - mutex_lock(&acm_table_lock); - acm = acm_table[index]; - if (acm) { - mutex_lock(&acm->mutex); - if (acm->disconnected) { - mutex_unlock(&acm->mutex); - acm = NULL; - } else { - tty_port_get(&acm->port); - mutex_unlock(&acm->mutex); - } - } - mutex_unlock(&acm_table_lock); - return acm; -} - -/* - * Try to find an available minor number and if found, associate it with 'acm'. - */ -static int acm_alloc_minor(struct acm *acm) -{ - int minor; - - mutex_lock(&acm_table_lock); - for (minor = 0; minor < ACM_TTY_MINORS; minor++) { - if (!acm_table[minor]) { - acm_table[minor] = acm; - break; - } - } - mutex_unlock(&acm_table_lock); - - return minor; -} - -/* Release the minor number associated with 'acm'. */ -static void acm_release_minor(struct acm *acm) -{ - mutex_lock(&acm_table_lock); - acm_table[acm->minor] = NULL; - mutex_unlock(&acm_table_lock); -} - -/* - * Functions for ACM control messages. - */ - -static int acm_ctrl_msg(struct acm *acm, int request, int value, - void *buf, int len) -{ - int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), - request, USB_RT_ACM, value, - acm->control->altsetting[0].desc.bInterfaceNumber, - buf, len, 5000); - dev_dbg(&acm->control->dev, - "%s - rq 0x%02x, val %#x, len %#x, result %d\n", - __func__, request, value, len, retval); - return retval < 0 ? retval : 0; -} - -/* devices aren't required to support these requests. - * the cdc acm descriptor tells whether they do... - */ -#define acm_set_control(acm, control) \ - acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0) -#define acm_set_line(acm, line) \ - acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line)) -#define acm_send_break(acm, ms) \ - acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) - -/* - * Write buffer management. - * All of these assume proper locks taken by the caller. - */ - -static int acm_wb_alloc(struct acm *acm) -{ - int i, wbn; - struct acm_wb *wb; - - wbn = 0; - i = 0; - for (;;) { - wb = &acm->wb[wbn]; - if (!wb->use) { - wb->use = 1; - return wbn; - } - wbn = (wbn + 1) % ACM_NW; - if (++i >= ACM_NW) - return -1; - } -} - -static int acm_wb_is_avail(struct acm *acm) -{ - int i, n; - unsigned long flags; - - n = ACM_NW; - spin_lock_irqsave(&acm->write_lock, flags); - for (i = 0; i < ACM_NW; i++) - n -= acm->wb[i].use; - spin_unlock_irqrestore(&acm->write_lock, flags); - return n; -} - -/* - * Finish write. Caller must hold acm->write_lock - */ -static void acm_write_done(struct acm *acm, struct acm_wb *wb) -{ - wb->use = 0; - acm->transmitting--; - usb_autopm_put_interface_async(acm->control); -} - -/* - * Poke write. - * - * the caller is responsible for locking - */ - -static int acm_start_wb(struct acm *acm, struct acm_wb *wb) -{ - int rc; - - acm->transmitting++; - - wb->urb->transfer_buffer = wb->buf; - wb->urb->transfer_dma = wb->dmah; - wb->urb->transfer_buffer_length = wb->len; - wb->urb->dev = acm->dev; - - rc = usb_submit_urb(wb->urb, GFP_ATOMIC); - if (rc < 0) { - dev_err(&acm->data->dev, - "%s - usb_submit_urb(write bulk) failed: %d\n", - __func__, rc); - acm_write_done(acm, wb); - } - return rc; -} - -static int acm_write_start(struct acm *acm, int wbn) -{ - unsigned long flags; - struct acm_wb *wb = &acm->wb[wbn]; - int rc; - - spin_lock_irqsave(&acm->write_lock, flags); - if (!acm->dev) { - wb->use = 0; - spin_unlock_irqrestore(&acm->write_lock, flags); - return -ENODEV; - } - - dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__, - acm->susp_count); - usb_autopm_get_interface_async(acm->control); - if (acm->susp_count) { - if (!acm->delayed_wb) - acm->delayed_wb = wb; - else - usb_autopm_put_interface_async(acm->control); - spin_unlock_irqrestore(&acm->write_lock, flags); - return 0; /* A white lie */ - } - usb_mark_last_busy(acm->dev); - - rc = acm_start_wb(acm, wb); - spin_unlock_irqrestore(&acm->write_lock, flags); - - return rc; - -} -/* - * attributes exported through sysfs - */ -static ssize_t show_caps -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - return sprintf(buf, "%d", acm->ctrl_caps); -} -static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); - -static ssize_t show_country_codes -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - memcpy(buf, acm->country_codes, acm->country_code_size); - return acm->country_code_size; -} - -static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); - -static ssize_t show_country_rel_date -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - return sprintf(buf, "%d", acm->country_rel_date); -} - -static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); -/* - * Interrupt handlers for various ACM device responses - */ - -/* control interface reports status changes with "interrupt" transfers */ -static void acm_ctrl_irq(struct urb *urb) -{ - struct acm *acm = urb->context; - struct usb_cdc_notification *dr = urb->transfer_buffer; - struct tty_struct *tty; - unsigned char *data; - int newctrl; - int retval; - int status = urb->status; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dev_dbg(&acm->control->dev, - "%s - urb shutting down with status: %d\n", - __func__, status); - return; - default: - dev_dbg(&acm->control->dev, - "%s - nonzero urb status received: %d\n", - __func__, status); - goto exit; - } - - usb_mark_last_busy(acm->dev); - - data = (unsigned char *)(dr + 1); - switch (dr->bNotificationType) { - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - dev_dbg(&acm->control->dev, "%s - network connection: %d\n", - __func__, dr->wValue); - break; - - case USB_CDC_NOTIFY_SERIAL_STATE: - tty = tty_port_tty_get(&acm->port); - newctrl = get_unaligned_le16(data); - - if (tty) { - if (!acm->clocal && - (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { - dev_dbg(&acm->control->dev, - "%s - calling hangup\n", __func__); - tty_hangup(tty); - } - tty_kref_put(tty); - } - - acm->ctrlin = newctrl; - - dev_dbg(&acm->control->dev, - "%s - input control lines: dcd%c dsr%c break%c " - "ring%c framing%c parity%c overrun%c\n", - __func__, - acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', - acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', - acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', - acm->ctrlin & ACM_CTRL_RI ? '+' : '-', - acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', - acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', - acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); - break; - - default: - dev_dbg(&acm->control->dev, - "%s - unknown notification %d received: index %d " - "len %d data0 %d data1 %d\n", - __func__, - dr->bNotificationType, dr->wIndex, - dr->wLength, data[0], data[1]); - break; - } -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n", - __func__, retval); -} - -static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) -{ - int res; - - if (!test_and_clear_bit(index, &acm->read_urbs_free)) - return 0; - - dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index); - - res = usb_submit_urb(acm->read_urbs[index], mem_flags); - if (res) { - if (res != -EPERM) { - dev_err(&acm->data->dev, - "%s - usb_submit_urb failed: %d\n", - __func__, res); - } - set_bit(index, &acm->read_urbs_free); - return res; - } - - return 0; -} - -static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags) -{ - int res; - int i; - - for (i = 0; i < acm->rx_buflimit; ++i) { - res = acm_submit_read_urb(acm, i, mem_flags); - if (res) - return res; - } - - return 0; -} - -static void acm_process_read_urb(struct acm *acm, struct urb *urb) -{ - struct tty_struct *tty; - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&acm->port); - if (!tty) - return; - - tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); - tty_flip_buffer_push(tty); - - tty_kref_put(tty); -} - -static void acm_read_bulk_callback(struct urb *urb) -{ - struct acm_rb *rb = urb->context; - struct acm *acm = rb->instance; - unsigned long flags; - - dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__, - rb->index, urb->actual_length); - set_bit(rb->index, &acm->read_urbs_free); - - if (!acm->dev) { - dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); - return; - } - usb_mark_last_busy(acm->dev); - - if (urb->status) { - dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", - __func__, urb->status); - return; - } - acm_process_read_urb(acm, urb); - - /* throttle device if requested by tty */ - spin_lock_irqsave(&acm->read_lock, flags); - acm->throttled = acm->throttle_req; - if (!acm->throttled && !acm->susp_count) { - spin_unlock_irqrestore(&acm->read_lock, flags); - acm_submit_read_urb(acm, rb->index, GFP_ATOMIC); - } else { - spin_unlock_irqrestore(&acm->read_lock, flags); - } -} - -/* data interface wrote those outgoing bytes */ -static void acm_write_bulk(struct urb *urb) -{ - struct acm_wb *wb = urb->context; - struct acm *acm = wb->instance; - unsigned long flags; - - if (urb->status || (urb->actual_length != urb->transfer_buffer_length)) - dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n", - __func__, - urb->actual_length, - urb->transfer_buffer_length, - urb->status); - - spin_lock_irqsave(&acm->write_lock, flags); - acm_write_done(acm, wb); - spin_unlock_irqrestore(&acm->write_lock, flags); - schedule_work(&acm->work); -} - -static void acm_softint(struct work_struct *work) -{ - struct acm *acm = container_of(work, struct acm, work); - struct tty_struct *tty; - - dev_vdbg(&acm->data->dev, "%s\n", __func__); - - tty = tty_port_tty_get(&acm->port); - if (!tty) - return; - tty_wakeup(tty); - tty_kref_put(tty); -} - -/* - * TTY handlers - */ - -static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - struct acm *acm; - int retval; - - dev_dbg(tty->dev, "%s\n", __func__); - - acm = acm_get_by_index(tty->index); - if (!acm) - return -ENODEV; - - retval = tty_standard_install(driver, tty); - if (retval) - goto error_init_termios; - - tty->driver_data = acm; - - return 0; - -error_init_termios: - tty_port_put(&acm->port); - return retval; -} - -static int acm_tty_open(struct tty_struct *tty, struct file *filp) -{ - struct acm *acm = tty->driver_data; - - dev_dbg(tty->dev, "%s\n", __func__); - - return tty_port_open(&acm->port, tty, filp); -} - -static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct acm *acm = container_of(port, struct acm, port); - int retval = -ENODEV; - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - mutex_lock(&acm->mutex); - if (acm->disconnected) - goto disconnected; - - retval = usb_autopm_get_interface(acm->control); - if (retval) - goto error_get_interface; - - /* - * FIXME: Why do we need this? Allocating 64K of physically contiguous - * memory is really nasty... - */ - set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); - acm->control->needs_remote_wakeup = 1; - - acm->ctrlurb->dev = acm->dev; - if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { - dev_err(&acm->control->dev, - "%s - usb_submit_urb(ctrl irq) failed\n", __func__); - goto error_submit_urb; - } - - acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; - if (acm_set_control(acm, acm->ctrlout) < 0 && - (acm->ctrl_caps & USB_CDC_CAP_LINE)) - goto error_set_control; - - usb_autopm_put_interface(acm->control); - - /* - * Unthrottle device in case the TTY was closed while throttled. - */ - spin_lock_irq(&acm->read_lock); - acm->throttled = 0; - acm->throttle_req = 0; - spin_unlock_irq(&acm->read_lock); - - if (acm_submit_read_urbs(acm, GFP_KERNEL)) - goto error_submit_read_urbs; - - mutex_unlock(&acm->mutex); - - return 0; - -error_submit_read_urbs: - acm->ctrlout = 0; - acm_set_control(acm, acm->ctrlout); -error_set_control: - usb_kill_urb(acm->ctrlurb); -error_submit_urb: - usb_autopm_put_interface(acm->control); -error_get_interface: -disconnected: - mutex_unlock(&acm->mutex); - return retval; -} - -static void acm_port_destruct(struct tty_port *port) -{ - struct acm *acm = container_of(port, struct acm, port); - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - tty_unregister_device(acm_tty_driver, acm->minor); - acm_release_minor(acm); - usb_put_intf(acm->control); - kfree(acm->country_codes); - kfree(acm); -} - -static void acm_port_shutdown(struct tty_port *port) -{ - struct acm *acm = container_of(port, struct acm, port); - int i; - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - mutex_lock(&acm->mutex); - if (!acm->disconnected) { - usb_autopm_get_interface(acm->control); - acm_set_control(acm, acm->ctrlout = 0); - usb_kill_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_kill_urb(acm->wb[i].urb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->read_urbs[i]); - acm->control->needs_remote_wakeup = 0; - usb_autopm_put_interface(acm->control); - } - mutex_unlock(&acm->mutex); -} - -static void acm_tty_cleanup(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); - tty_port_put(&acm->port); -} - -static void acm_tty_hangup(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); - tty_port_hangup(&acm->port); -} - -static void acm_tty_close(struct tty_struct *tty, struct file *filp) -{ - struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); - tty_port_close(&acm->port, tty, filp); -} - -static int acm_tty_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct acm *acm = tty->driver_data; - int stat; - unsigned long flags; - int wbn; - struct acm_wb *wb; - - if (!count) - return 0; - - dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count); - - spin_lock_irqsave(&acm->write_lock, flags); - wbn = acm_wb_alloc(acm); - if (wbn < 0) { - spin_unlock_irqrestore(&acm->write_lock, flags); - return 0; - } - wb = &acm->wb[wbn]; - - count = (count > acm->writesize) ? acm->writesize : count; - dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count); - memcpy(wb->buf, buf, count); - wb->len = count; - spin_unlock_irqrestore(&acm->write_lock, flags); - - stat = acm_write_start(acm, wbn); - if (stat < 0) - return stat; - return count; -} - -static int acm_tty_write_room(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - /* - * Do not let the line discipline to know that we have a reserve, - * or it might get too enthusiastic. - */ - return acm_wb_is_avail(acm) ? acm->writesize : 0; -} - -static int acm_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - /* - * if the device was unplugged then any remaining characters fell out - * of the connector ;) - */ - if (acm->disconnected) - return 0; - /* - * This is inaccurate (overcounts), but it works. - */ - return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; -} - -static void acm_tty_throttle(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - - spin_lock_irq(&acm->read_lock); - acm->throttle_req = 1; - spin_unlock_irq(&acm->read_lock); -} - -static void acm_tty_unthrottle(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - unsigned int was_throttled; - - spin_lock_irq(&acm->read_lock); - was_throttled = acm->throttled; - acm->throttled = 0; - acm->throttle_req = 0; - spin_unlock_irq(&acm->read_lock); - - if (was_throttled) - acm_submit_read_urbs(acm, GFP_KERNEL); -} - -static int acm_tty_break_ctl(struct tty_struct *tty, int state) -{ - struct acm *acm = tty->driver_data; - int retval; - - retval = acm_send_break(acm, state ? 0xffff : 0); - if (retval < 0) - dev_dbg(&acm->control->dev, "%s - send break failed\n", - __func__); - return retval; -} - -static int acm_tty_tiocmget(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - - return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | - (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | - (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | - (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) | - (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) | - TIOCM_CTS; -} - -static int acm_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct acm *acm = tty->driver_data; - unsigned int newctrl; - - newctrl = acm->ctrlout; - set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | - (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); - clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | - (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); - - newctrl = (newctrl & ~clear) | set; - - if (acm->ctrlout == newctrl) - return 0; - return acm_set_control(acm, acm->ctrlout = newctrl); -} - -static int get_serial_info(struct acm *acm, struct serial_struct __user *info) -{ - struct serial_struct tmp; - - if (!info) - return -EINVAL; - - memset(&tmp, 0, sizeof(tmp)); - tmp.flags = ASYNC_LOW_LATENCY; - tmp.xmit_fifo_size = acm->writesize; - tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); - - if (copy_to_user(info, &tmp, sizeof(tmp))) - return -EFAULT; - else - return 0; -} - -static int acm_tty_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct acm *acm = tty->driver_data; - int rv = -ENOIOCTLCMD; - - switch (cmd) { - case TIOCGSERIAL: /* gets serial port data */ - rv = get_serial_info(acm, (struct serial_struct __user *) arg); - break; - } - - return rv; -} - -static const __u32 acm_tty_speed[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, - 1200, 1800, 2400, 4800, 9600, 19200, 38400, - 57600, 115200, 230400, 460800, 500000, 576000, - 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 -}; - -static const __u8 acm_tty_size[] = { - 5, 6, 7, 8 -}; - -static void acm_tty_set_termios(struct tty_struct *tty, - struct ktermios *termios_old) -{ - struct acm *acm = tty->driver_data; - struct ktermios *termios = tty->termios; - struct usb_cdc_line_coding newline; - int newctrl = acm->ctrlout; - - newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); - newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; - newline.bParityType = termios->c_cflag & PARENB ? - (termios->c_cflag & PARODD ? 1 : 2) + - (termios->c_cflag & CMSPAR ? 2 : 0) : 0; - newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; - /* FIXME: Needs to clear unsupported bits in the termios */ - acm->clocal = ((termios->c_cflag & CLOCAL) != 0); - - if (!newline.dwDTERate) { - newline.dwDTERate = acm->line.dwDTERate; - newctrl &= ~ACM_CTRL_DTR; - } else - newctrl |= ACM_CTRL_DTR; - - if (newctrl != acm->ctrlout) - acm_set_control(acm, acm->ctrlout = newctrl); - - if (memcmp(&acm->line, &newline, sizeof newline)) { - memcpy(&acm->line, &newline, sizeof newline); - dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n", - __func__, - le32_to_cpu(newline.dwDTERate), - newline.bCharFormat, newline.bParityType, - newline.bDataBits); - acm_set_line(acm, &acm->line); - } -} - -static const struct tty_port_operations acm_port_ops = { - .shutdown = acm_port_shutdown, - .activate = acm_port_activate, - .destruct = acm_port_destruct, -}; - -/* - * USB probe and disconnect routines. - */ - -/* Little helpers: write/read buffers free */ -static void acm_write_buffers_free(struct acm *acm) -{ - int i; - struct acm_wb *wb; - struct usb_device *usb_dev = interface_to_usbdev(acm->control); - - for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) - usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah); -} - -static void acm_read_buffers_free(struct acm *acm) -{ - struct usb_device *usb_dev = interface_to_usbdev(acm->control); - int i; - - for (i = 0; i < acm->rx_buflimit; i++) - usb_free_coherent(usb_dev, acm->readsize, - acm->read_buffers[i].base, acm->read_buffers[i].dma); -} - -/* Little helper: write buffers allocate */ -static int acm_write_buffers_alloc(struct acm *acm) -{ - int i; - struct acm_wb *wb; - - for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { - wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL, - &wb->dmah); - if (!wb->buf) { - while (i != 0) { - --i; - --wb; - usb_free_coherent(acm->dev, acm->writesize, - wb->buf, wb->dmah); - } - return -ENOMEM; - } - } - return 0; -} - -static int acm_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_cdc_union_desc *union_header = NULL; - struct usb_cdc_country_functional_desc *cfd = NULL; - unsigned char *buffer = intf->altsetting->extra; - int buflen = intf->altsetting->extralen; - struct usb_interface *control_interface; - struct usb_interface *data_interface; - struct usb_endpoint_descriptor *epctrl = NULL; - struct usb_endpoint_descriptor *epread = NULL; - struct usb_endpoint_descriptor *epwrite = NULL; - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct acm *acm; - int minor; - int ctrlsize, readsize; - u8 *buf; - u8 ac_management_function = 0; - u8 call_management_function = 0; - int call_interface_num = -1; - int data_interface_num = -1; - unsigned long quirks; - int num_rx_buf; - int i; - int combined_interfaces = 0; - - /* normal quirks */ - quirks = (unsigned long)id->driver_info; - num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; - - /* handle quirks deadly to normal probing*/ - if (quirks == NO_UNION_NORMAL) { - data_interface = usb_ifnum_to_if(usb_dev, 1); - control_interface = usb_ifnum_to_if(usb_dev, 0); - goto skip_normal_probe; - } - - /* normal probing*/ - if (!buffer) { - dev_err(&intf->dev, "Weird descriptor references\n"); - return -EINVAL; - } - - if (!buflen) { - if (intf->cur_altsetting->endpoint && - intf->cur_altsetting->endpoint->extralen && - intf->cur_altsetting->endpoint->extra) { - dev_dbg(&intf->dev, - "Seeking extra descriptors on endpoint\n"); - buflen = intf->cur_altsetting->endpoint->extralen; - buffer = intf->cur_altsetting->endpoint->extra; - } else { - dev_err(&intf->dev, - "Zero length descriptor references\n"); - return -EINVAL; - } - } - - while (buflen > 0) { - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - - switch (buffer[2]) { - case USB_CDC_UNION_TYPE: /* we've found it */ - if (union_header) { - dev_err(&intf->dev, "More than one " - "union descriptor, skipping ...\n"); - goto next_desc; - } - union_header = (struct usb_cdc_union_desc *)buffer; - break; - case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ - cfd = (struct usb_cdc_country_functional_desc *)buffer; - break; - case USB_CDC_HEADER_TYPE: /* maybe check version */ - break; /* for now we ignore it */ - case USB_CDC_ACM_TYPE: - ac_management_function = buffer[3]; - break; - case USB_CDC_CALL_MANAGEMENT_TYPE: - call_management_function = buffer[3]; - call_interface_num = buffer[4]; - if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) - dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); - break; - default: - /* there are LOTS more CDC descriptors that - * could legitimately be found here. - */ - dev_dbg(&intf->dev, "Ignoring descriptor: " - "type %02x, length %d\n", - buffer[2], buffer[0]); - break; - } -next_desc: - buflen -= buffer[0]; - buffer += buffer[0]; - } - - if (!union_header) { - if (call_interface_num > 0) { - dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); - /* quirks for Droids MuIn LCD */ - if (quirks & NO_DATA_INTERFACE) - data_interface = usb_ifnum_to_if(usb_dev, 0); - else - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); - control_interface = intf; - } else { - if (intf->cur_altsetting->desc.bNumEndpoints != 3) { - dev_dbg(&intf->dev,"No union descriptor, giving up\n"); - return -ENODEV; - } else { - dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n"); - combined_interfaces = 1; - control_interface = data_interface = intf; - goto look_for_collapsed_interface; - } - } - } else { - control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); - if (!control_interface || !data_interface) { - dev_dbg(&intf->dev, "no interfaces\n"); - return -ENODEV; - } - } - - if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); - - if (control_interface == data_interface) { - /* some broken devices designed for windows work this way */ - dev_warn(&intf->dev,"Control and data interfaces are not separated!\n"); - combined_interfaces = 1; - /* a popular other OS doesn't use it */ - quirks |= NO_CAP_LINE; - if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) { - dev_err(&intf->dev, "This needs exactly 3 endpoints\n"); - return -EINVAL; - } -look_for_collapsed_interface: - for (i = 0; i < 3; i++) { - struct usb_endpoint_descriptor *ep; - ep = &data_interface->cur_altsetting->endpoint[i].desc; - - if (usb_endpoint_is_int_in(ep)) - epctrl = ep; - else if (usb_endpoint_is_bulk_out(ep)) - epwrite = ep; - else if (usb_endpoint_is_bulk_in(ep)) - epread = ep; - else - return -EINVAL; - } - if (!epctrl || !epread || !epwrite) - return -ENODEV; - else - goto made_compressed_probe; - } - -skip_normal_probe: - - /*workaround for switched interfaces */ - if (data_interface->cur_altsetting->desc.bInterfaceClass - != CDC_DATA_INTERFACE_TYPE) { - if (control_interface->cur_altsetting->desc.bInterfaceClass - == CDC_DATA_INTERFACE_TYPE) { - struct usb_interface *t; - dev_dbg(&intf->dev, - "Your device has switched interfaces.\n"); - t = control_interface; - control_interface = data_interface; - data_interface = t; - } else { - return -EINVAL; - } - } - - /* Accept probe requests only for the control interface */ - if (!combined_interfaces && intf != control_interface) - return -ENODEV; - - if (!combined_interfaces && usb_interface_claimed(data_interface)) { - /* valid in this context */ - dev_dbg(&intf->dev, "The data interface isn't available\n"); - return -EBUSY; - } - - - if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) - return -EINVAL; - - epctrl = &control_interface->cur_altsetting->endpoint[0].desc; - epread = &data_interface->cur_altsetting->endpoint[0].desc; - epwrite = &data_interface->cur_altsetting->endpoint[1].desc; - - - /* workaround for switched endpoints */ - if (!usb_endpoint_dir_in(epread)) { - /* descriptors are swapped */ - struct usb_endpoint_descriptor *t; - dev_dbg(&intf->dev, - "The data interface has switched endpoints\n"); - t = epread; - epread = epwrite; - epwrite = t; - } -made_compressed_probe: - dev_dbg(&intf->dev, "interfaces are valid\n"); - - acm = kzalloc(sizeof(struct acm), GFP_KERNEL); - if (acm == NULL) { - dev_err(&intf->dev, "out of memory (acm kzalloc)\n"); - goto alloc_fail; - } - - minor = acm_alloc_minor(acm); - if (minor == ACM_TTY_MINORS) { - dev_err(&intf->dev, "no more free acm devices\n"); - kfree(acm); - return -ENODEV; - } - - ctrlsize = usb_endpoint_maxp(epctrl); - readsize = usb_endpoint_maxp(epread) * - (quirks == SINGLE_RX_URB ? 1 : 2); - acm->combined_interfaces = combined_interfaces; - acm->writesize = usb_endpoint_maxp(epwrite) * 20; - acm->control = control_interface; - acm->data = data_interface; - acm->minor = minor; - acm->dev = usb_dev; - acm->ctrl_caps = ac_management_function; - if (quirks & NO_CAP_LINE) - acm->ctrl_caps &= ~USB_CDC_CAP_LINE; - acm->ctrlsize = ctrlsize; - acm->readsize = readsize; - acm->rx_buflimit = num_rx_buf; - INIT_WORK(&acm->work, acm_softint); - spin_lock_init(&acm->write_lock); - spin_lock_init(&acm->read_lock); - mutex_init(&acm->mutex); - acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); - acm->is_int_ep = usb_endpoint_xfer_int(epread); - if (acm->is_int_ep) - acm->bInterval = epread->bInterval; - tty_port_init(&acm->port); - acm->port.ops = &acm_port_ops; - - buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); - if (!buf) { - dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n"); - goto alloc_fail2; - } - acm->ctrl_buffer = buf; - - if (acm_write_buffers_alloc(acm) < 0) { - dev_err(&intf->dev, "out of memory (write buffer alloc)\n"); - goto alloc_fail4; - } - - acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->ctrlurb) { - dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); - goto alloc_fail5; - } - for (i = 0; i < num_rx_buf; i++) { - struct acm_rb *rb = &(acm->read_buffers[i]); - struct urb *urb; - - rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, - &rb->dma); - if (!rb->base) { - dev_err(&intf->dev, "out of memory " - "(read bufs usb_alloc_coherent)\n"); - goto alloc_fail6; - } - rb->index = i; - rb->instance = acm; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&intf->dev, - "out of memory (read urbs usb_alloc_urb)\n"); - goto alloc_fail6; - } - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - urb->transfer_dma = rb->dma; - if (acm->is_int_ep) { - usb_fill_int_urb(urb, acm->dev, - acm->rx_endpoint, - rb->base, - acm->readsize, - acm_read_bulk_callback, rb, - acm->bInterval); - } else { - usb_fill_bulk_urb(urb, acm->dev, - acm->rx_endpoint, - rb->base, - acm->readsize, - acm_read_bulk_callback, rb); - } - - acm->read_urbs[i] = urb; - __set_bit(i, &acm->read_urbs_free); - } - for (i = 0; i < ACM_NW; i++) { - struct acm_wb *snd = &(acm->wb[i]); - - snd->urb = usb_alloc_urb(0, GFP_KERNEL); - if (snd->urb == NULL) { - dev_err(&intf->dev, - "out of memory (write urbs usb_alloc_urb)\n"); - goto alloc_fail7; - } - - if (usb_endpoint_xfer_int(epwrite)) - usb_fill_int_urb(snd->urb, usb_dev, - usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); - else - usb_fill_bulk_urb(snd->urb, usb_dev, - usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - NULL, acm->writesize, acm_write_bulk, snd); - snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - snd->instance = acm; - } - - usb_set_intfdata(intf, acm); - - i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); - if (i < 0) - goto alloc_fail7; - - if (cfd) { /* export the country data */ - acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); - if (!acm->country_codes) - goto skip_countries; - acm->country_code_size = cfd->bLength - 4; - memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, - cfd->bLength - 4); - acm->country_rel_date = cfd->iCountryCodeRelDate; - - i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); - if (i < 0) { - kfree(acm->country_codes); - acm->country_codes = NULL; - acm->country_code_size = 0; - goto skip_countries; - } - - i = device_create_file(&intf->dev, - &dev_attr_iCountryCodeRelDate); - if (i < 0) { - device_remove_file(&intf->dev, &dev_attr_wCountryCodes); - kfree(acm->country_codes); - acm->country_codes = NULL; - acm->country_code_size = 0; - goto skip_countries; - } - } - -skip_countries: - usb_fill_int_urb(acm->ctrlurb, usb_dev, - usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), - acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, - /* works around buggy devices */ - epctrl->bInterval ? epctrl->bInterval : 0xff); - acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - acm->ctrlurb->transfer_dma = acm->ctrl_dma; - - dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); - - acm_set_control(acm, acm->ctrlout); - - acm->line.dwDTERate = cpu_to_le32(9600); - acm->line.bDataBits = 8; - acm_set_line(acm, &acm->line); - - usb_driver_claim_interface(&acm_driver, data_interface, acm); - usb_set_intfdata(data_interface, acm); - - usb_get_intf(control_interface); - tty_register_device(acm_tty_driver, minor, &control_interface->dev); - - return 0; -alloc_fail7: - for (i = 0; i < ACM_NW; i++) - usb_free_urb(acm->wb[i].urb); -alloc_fail6: - for (i = 0; i < num_rx_buf; i++) - usb_free_urb(acm->read_urbs[i]); - acm_read_buffers_free(acm); - usb_free_urb(acm->ctrlurb); -alloc_fail5: - acm_write_buffers_free(acm); -alloc_fail4: - usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); -alloc_fail2: - acm_release_minor(acm); - kfree(acm); -alloc_fail: - return -ENOMEM; -} - -static void stop_data_traffic(struct acm *acm) -{ - int i; - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - usb_kill_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_kill_urb(acm->wb[i].urb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->read_urbs[i]); - - cancel_work_sync(&acm->work); -} - -static void acm_disconnect(struct usb_interface *intf) -{ - struct acm *acm = usb_get_intfdata(intf); - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct tty_struct *tty; - int i; - - dev_dbg(&intf->dev, "%s\n", __func__); - - /* sibling interface is already cleaning up */ - if (!acm) - return; - - mutex_lock(&acm->mutex); - acm->disconnected = true; - if (acm->country_codes) { - device_remove_file(&acm->control->dev, - &dev_attr_wCountryCodes); - device_remove_file(&acm->control->dev, - &dev_attr_iCountryCodeRelDate); - } - device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); - usb_set_intfdata(acm->control, NULL); - usb_set_intfdata(acm->data, NULL); - mutex_unlock(&acm->mutex); - - tty = tty_port_tty_get(&acm->port); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } - - stop_data_traffic(acm); - - usb_free_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_free_urb(acm->wb[i].urb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_free_urb(acm->read_urbs[i]); - acm_write_buffers_free(acm); - usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); - acm_read_buffers_free(acm); - - if (!acm->combined_interfaces) - usb_driver_release_interface(&acm_driver, intf == acm->control ? - acm->data : acm->control); - - tty_port_put(&acm->port); -} - -#ifdef CONFIG_PM -static int acm_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct acm *acm = usb_get_intfdata(intf); - int cnt; - - if (PMSG_IS_AUTO(message)) { - int b; - - spin_lock_irq(&acm->write_lock); - b = acm->transmitting; - spin_unlock_irq(&acm->write_lock); - if (b) - return -EBUSY; - } - - spin_lock_irq(&acm->read_lock); - spin_lock(&acm->write_lock); - cnt = acm->susp_count++; - spin_unlock(&acm->write_lock); - spin_unlock_irq(&acm->read_lock); - - if (cnt) - return 0; - - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) - stop_data_traffic(acm); - - return 0; -} - -static int acm_resume(struct usb_interface *intf) -{ - struct acm *acm = usb_get_intfdata(intf); - struct acm_wb *wb; - int rv = 0; - int cnt; - - spin_lock_irq(&acm->read_lock); - acm->susp_count -= 1; - cnt = acm->susp_count; - spin_unlock_irq(&acm->read_lock); - - if (cnt) - return 0; - - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { - rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); - - spin_lock_irq(&acm->write_lock); - if (acm->delayed_wb) { - wb = acm->delayed_wb; - acm->delayed_wb = NULL; - spin_unlock_irq(&acm->write_lock); - acm_start_wb(acm, wb); - } else { - spin_unlock_irq(&acm->write_lock); - } - - /* - * delayed error checking because we must - * do the write path at all cost - */ - if (rv < 0) - goto err_out; - - rv = acm_submit_read_urbs(acm, GFP_NOIO); - } - -err_out: - return rv; -} - -static int acm_reset_resume(struct usb_interface *intf) -{ - struct acm *acm = usb_get_intfdata(intf); - struct tty_struct *tty; - - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { - tty = tty_port_tty_get(&acm->port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } - } - - return acm_resume(intf); -} - -#endif /* CONFIG_PM */ - -#define NOKIA_PCSUITE_ACM_INFO(x) \ - USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \ - USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ - USB_CDC_ACM_PROTO_VENDOR) - -#define SAMSUNG_PCSUITE_ACM_INFO(x) \ - USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \ - USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ - USB_CDC_ACM_PROTO_VENDOR) - -/* - * USB driver structure. - */ - -static const struct usb_device_id acm_ids[] = { - /* quirky and broken devices */ - { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */ - .driver_info = SINGLE_RX_URB, - }, - { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ - .driver_info = SINGLE_RX_URB, /* firmware bug */ - }, - { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ - .driver_info = SINGLE_RX_URB, /* firmware bug */ - }, - { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ - }, - /* Motorola H24 HSPA module: */ - { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ - { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ - { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ - { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ - { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ - { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ - { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ - { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ - - { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ - .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on - data interface instead of - communications interface. - Maybe we should define a new - quirk for this. */ - }, - { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ - .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ - }, - { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ - .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ - }, - - /* Nokia S60 phones expose two ACM channels. The first is - * a modem and is picked up by the standard AT-command - * information below. The second is 'vendor-specific' but - * is treated as a serial device at the S60 end, so we want - * to expose it on Linux too. */ - { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */ - { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */ - { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */ - { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */ - { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */ - { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */ - { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */ - { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */ - { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */ - { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */ - { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */ - { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */ - { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */ - { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */ - { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */ - { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */ - { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */ - { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */ - { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */ - { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */ - { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */ - { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */ - { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */ - { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */ - { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */ - { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */ - { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */ - { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */ - { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */ - { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */ - { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */ - { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */ - { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */ - { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */ - { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */ - { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */ - { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */ - { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */ - { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ - { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ - { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */ - { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */ - { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */ - { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */ - { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */ - { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */ - { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */ - { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */ - { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */ - { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */ - { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */ - { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */ - { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ - { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ - - /* Support for Owen devices */ - { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */ - - /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ - - /* Support Lego NXT using pbLua firmware */ - { USB_DEVICE(0x0694, 0xff00), - .driver_info = NOT_A_MODEM, - }, - - /* Support for Droids MuIn LCD */ - { USB_DEVICE(0x04d8, 0x000b), - .driver_info = NO_DATA_INTERFACE, - }, - - /* control interfaces without any protocol set */ - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_PROTO_NONE) }, - - /* control interfaces with various AT-command sets */ - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_V25TER) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_PCCA101) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_GSM) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_3G) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_CDMA) }, - - { } -}; - -MODULE_DEVICE_TABLE(usb, acm_ids); - -static struct usb_driver acm_driver = { - .name = "cdc_acm", - .probe = acm_probe, - .disconnect = acm_disconnect, -#ifdef CONFIG_PM - .suspend = acm_suspend, - .resume = acm_resume, - .reset_resume = acm_reset_resume, -#endif - .id_table = acm_ids, -#ifdef CONFIG_PM - .supports_autosuspend = 1, -#endif -}; - -/* - * TTY driver structures. - */ - -static const struct tty_operations acm_ops = { - .install = acm_tty_install, - .open = acm_tty_open, - .close = acm_tty_close, - .cleanup = acm_tty_cleanup, - .hangup = acm_tty_hangup, - .write = acm_tty_write, - .write_room = acm_tty_write_room, - .ioctl = acm_tty_ioctl, - .throttle = acm_tty_throttle, - .unthrottle = acm_tty_unthrottle, - .chars_in_buffer = acm_tty_chars_in_buffer, - .break_ctl = acm_tty_break_ctl, - .set_termios = acm_tty_set_termios, - .tiocmget = acm_tty_tiocmget, - .tiocmset = acm_tty_tiocmset, -}; - -/* - * Init / exit. - */ - -static int __init acm_init(void) -{ - int retval; - acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); - if (!acm_tty_driver) - return -ENOMEM; - acm_tty_driver->driver_name = "acm", - acm_tty_driver->name = "ttyACM", - acm_tty_driver->major = ACM_TTY_MAJOR, - acm_tty_driver->minor_start = 0, - acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, - acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, - acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - acm_tty_driver->init_termios = tty_std_termios; - acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | - HUPCL | CLOCAL; - tty_set_operations(acm_tty_driver, &acm_ops); - - retval = tty_register_driver(acm_tty_driver); - if (retval) { - put_tty_driver(acm_tty_driver); - return retval; - } - - retval = usb_register(&acm_driver); - if (retval) { - tty_unregister_driver(acm_tty_driver); - put_tty_driver(acm_tty_driver); - return retval; - } - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - - return 0; -} - -static void __exit acm_exit(void) -{ - usb_deregister(&acm_driver); - tty_unregister_driver(acm_tty_driver); - put_tty_driver(acm_tty_driver); -} - -module_init(acm_init); -module_exit(acm_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR); diff --git a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.h b/ANDROID_3.4.5/drivers/usb/class/cdc-acm.h deleted file mode 100644 index 35ef887b..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * Includes for cdc-acm.c - * - * Mainly take from usbnet's cdc-ether part - * - */ - -/* - * CMSPAR, some architectures can't have space and mark parity. - */ - -#ifndef CMSPAR -#define CMSPAR 0 -#endif - -/* - * Major and minor numbers. - */ - -#define ACM_TTY_MAJOR 166 -#define ACM_TTY_MINORS 32 - -/* - * Requests. - */ - -#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) - -/* - * Output control lines. - */ - -#define ACM_CTRL_DTR 0x01 -#define ACM_CTRL_RTS 0x02 - -/* - * Input control lines and line errors. - */ - -#define ACM_CTRL_DCD 0x01 -#define ACM_CTRL_DSR 0x02 -#define ACM_CTRL_BRK 0x04 -#define ACM_CTRL_RI 0x08 - -#define ACM_CTRL_FRAMING 0x10 -#define ACM_CTRL_PARITY 0x20 -#define ACM_CTRL_OVERRUN 0x40 - -/* - * Internal driver structures. - */ - -/* - * The only reason to have several buffers is to accommodate assumptions - * in line disciplines. They ask for empty space amount, receive our URB size, - * and proceed to issue several 1-character writes, assuming they will fit. - * The very first write takes a complete URB. Fortunately, this only happens - * when processing onlcr, so we only need 2 buffers. These values must be - * powers of 2. - */ -#define ACM_NW 16 -#define ACM_NR 16 - -struct acm_wb { - unsigned char *buf; - dma_addr_t dmah; - int len; - int use; - struct urb *urb; - struct acm *instance; -}; - -struct acm_rb { - int size; - unsigned char *base; - dma_addr_t dma; - int index; - struct acm *instance; -}; - -struct acm { - struct usb_device *dev; /* the corresponding usb device */ - struct usb_interface *control; /* control interface */ - struct usb_interface *data; /* data interface */ - struct tty_port port; /* our tty port data */ - struct urb *ctrlurb; /* urbs */ - u8 *ctrl_buffer; /* buffers of urbs */ - dma_addr_t ctrl_dma; /* dma handles of buffers */ - u8 *country_codes; /* country codes from device */ - unsigned int country_code_size; /* size of this buffer */ - unsigned int country_rel_date; /* release date of version */ - struct acm_wb wb[ACM_NW]; - unsigned long read_urbs_free; - struct urb *read_urbs[ACM_NR]; - struct acm_rb read_buffers[ACM_NR]; - int rx_buflimit; - int rx_endpoint; - spinlock_t read_lock; - int write_used; /* number of non-empty write buffers */ - int transmitting; - spinlock_t write_lock; - struct mutex mutex; - bool disconnected; - struct usb_cdc_line_coding line; /* bits, stop, parity */ - struct work_struct work; /* work queue entry for line discipline waking up */ - unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ - unsigned int ctrlout; /* output control lines (DTR, RTS) */ - unsigned int writesize; /* max packet size for the output bulk endpoint */ - unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ - unsigned int minor; /* acm minor number */ - unsigned char clocal; /* termios CLOCAL */ - unsigned int ctrl_caps; /* control capabilities from the class specific header */ - unsigned int susp_count; /* number of suspended interfaces */ - unsigned int combined_interfaces:1; /* control and data collapsed */ - unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */ - unsigned int throttled:1; /* actually throttled */ - unsigned int throttle_req:1; /* throttle requested */ - u8 bInterval; - struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ -}; - -#define CDC_DATA_INTERFACE_TYPE 0x0a - -/* constants describing various quirks and errors */ -#define NO_UNION_NORMAL 1 -#define SINGLE_RX_URB 2 -#define NO_CAP_LINE 4 -#define NOT_A_MODEM 8 -#define NO_DATA_INTERFACE 16 diff --git a/ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c b/ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c deleted file mode 100644 index 01d247e8..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * cdc-wdm.c - * - * This driver supports USB CDC WCM Device Management. - * - * Copyright (c) 2007-2009 Oliver Neukum - * - * Some code taken from cdc-acm.c - * - * Released under the GPLv2. - * - * Many thanks to Carl Nordbeck - */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <linux/bitops.h> -#include <linux/poll.h> -#include <linux/usb.h> -#include <linux/usb/cdc.h> -#include <asm/byteorder.h> -#include <asm/unaligned.h> -#include <linux/usb/cdc-wdm.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.03" -#define DRIVER_AUTHOR "Oliver Neukum" -#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" - -#define HUAWEI_VENDOR_ID 0x12D1 - -static const struct usb_device_id wdm_ids[] = { - { - .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM - }, - { - /* - * Huawei E392, E398 and possibly other Qualcomm based modems - * embed the Qualcomm QMI protocol inside CDC on CDC ECM like - * control interfaces. Userspace access to this is required - * to configure the accompanying data interface - */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = HUAWEI_VENDOR_ID, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */ - }, - { - /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = HUAWEI_VENDOR_ID, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 57, /* NOTE: CDC ECM control interface! */ - }, - { } -}; - -MODULE_DEVICE_TABLE (usb, wdm_ids); - -#define WDM_MINOR_BASE 176 - - -#define WDM_IN_USE 1 -#define WDM_DISCONNECTING 2 -#define WDM_RESULT 3 -#define WDM_READ 4 -#define WDM_INT_STALL 5 -#define WDM_POLL_RUNNING 6 -#define WDM_RESPONDING 7 -#define WDM_SUSPENDING 8 -#define WDM_RESETTING 9 - -#define WDM_MAX 16 - -/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */ -#define WDM_DEFAULT_BUFSIZE 256 - -static DEFINE_MUTEX(wdm_mutex); -static DEFINE_SPINLOCK(wdm_device_list_lock); -static LIST_HEAD(wdm_device_list); - -/* --- method tables --- */ - -struct wdm_device { - u8 *inbuf; /* buffer for response */ - u8 *outbuf; /* buffer for command */ - u8 *sbuf; /* buffer for status */ - u8 *ubuf; /* buffer for copy to user space */ - - struct urb *command; - struct urb *response; - struct urb *validity; - struct usb_interface *intf; - struct usb_ctrlrequest *orq; - struct usb_ctrlrequest *irq; - spinlock_t iuspin; - - unsigned long flags; - u16 bufsize; - u16 wMaxCommand; - u16 wMaxPacketSize; - __le16 inum; - int reslength; - int length; - int read; - int count; - dma_addr_t shandle; - dma_addr_t ihandle; - struct mutex wlock; - struct mutex rlock; - wait_queue_head_t wait; - struct work_struct rxwork; - int werr; - int rerr; - - struct list_head device_list; - int (*manage_power)(struct usb_interface *, int); -}; - -static struct usb_driver wdm_driver; - -/* return intfdata if we own the interface, else look up intf in the list */ -static struct wdm_device *wdm_find_device(struct usb_interface *intf) -{ - struct wdm_device *desc = NULL; - - spin_lock(&wdm_device_list_lock); - list_for_each_entry(desc, &wdm_device_list, device_list) - if (desc->intf == intf) - break; - spin_unlock(&wdm_device_list_lock); - - return desc; -} - -static struct wdm_device *wdm_find_device_by_minor(int minor) -{ - struct wdm_device *desc = NULL; - - spin_lock(&wdm_device_list_lock); - list_for_each_entry(desc, &wdm_device_list, device_list) - if (desc->intf->minor == minor) - break; - spin_unlock(&wdm_device_list_lock); - - return desc; -} - -/* --- callbacks --- */ -static void wdm_out_callback(struct urb *urb) -{ - struct wdm_device *desc; - desc = urb->context; - spin_lock(&desc->iuspin); - desc->werr = urb->status; - spin_unlock(&desc->iuspin); - kfree(desc->outbuf); - desc->outbuf = NULL; - clear_bit(WDM_IN_USE, &desc->flags); - wake_up(&desc->wait); -} - -static void wdm_in_callback(struct urb *urb) -{ - struct wdm_device *desc = urb->context; - int status = urb->status; - - spin_lock(&desc->iuspin); - clear_bit(WDM_RESPONDING, &desc->flags); - - if (status) { - switch (status) { - case -ENOENT: - dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ENOENT"); - goto skip_error; - case -ECONNRESET: - dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ECONNRESET"); - goto skip_error; - case -ESHUTDOWN: - dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ESHUTDOWN"); - goto skip_error; - case -EPIPE: - dev_err(&desc->intf->dev, - "nonzero urb status received: -EPIPE\n"); - break; - default: - dev_err(&desc->intf->dev, - "Unexpected error %d\n", status); - break; - } - } - - desc->rerr = status; - desc->reslength = urb->actual_length; - memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); - desc->length += desc->reslength; -skip_error: - wake_up(&desc->wait); - - set_bit(WDM_READ, &desc->flags); - spin_unlock(&desc->iuspin); -} - -static void wdm_int_callback(struct urb *urb) -{ - int rv = 0; - int status = urb->status; - struct wdm_device *desc; - struct usb_cdc_notification *dr; - - desc = urb->context; - dr = (struct usb_cdc_notification *)desc->sbuf; - - if (status) { - switch (status) { - case -ESHUTDOWN: - case -ENOENT: - case -ECONNRESET: - return; /* unplug */ - case -EPIPE: - set_bit(WDM_INT_STALL, &desc->flags); - dev_err(&desc->intf->dev, "Stall on int endpoint\n"); - goto sw; /* halt is cleared in work */ - default: - dev_err(&desc->intf->dev, - "nonzero urb status received: %d\n", status); - break; - } - } - - if (urb->actual_length < sizeof(struct usb_cdc_notification)) { - dev_err(&desc->intf->dev, "wdm_int_callback - %d bytes\n", - urb->actual_length); - goto exit; - } - - switch (dr->bNotificationType) { - case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: - dev_dbg(&desc->intf->dev, - "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d", - dr->wIndex, dr->wLength); - break; - - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - - dev_dbg(&desc->intf->dev, - "NOTIFY_NETWORK_CONNECTION %s network", - dr->wValue ? "connected to" : "disconnected from"); - goto exit; - default: - clear_bit(WDM_POLL_RUNNING, &desc->flags); - dev_err(&desc->intf->dev, - "unknown notification %d received: index %d len %d\n", - dr->bNotificationType, dr->wIndex, dr->wLength); - goto exit; - } - - spin_lock(&desc->iuspin); - clear_bit(WDM_READ, &desc->flags); - set_bit(WDM_RESPONDING, &desc->flags); - if (!test_bit(WDM_DISCONNECTING, &desc->flags) - && !test_bit(WDM_SUSPENDING, &desc->flags)) { - rv = usb_submit_urb(desc->response, GFP_ATOMIC); - dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", - __func__, rv); - } - spin_unlock(&desc->iuspin); - if (rv < 0) { - clear_bit(WDM_RESPONDING, &desc->flags); - if (rv == -EPERM) - return; - if (rv == -ENOMEM) { -sw: - rv = schedule_work(&desc->rxwork); - if (rv) - dev_err(&desc->intf->dev, - "Cannot schedule work\n"); - } - } -exit: - rv = usb_submit_urb(urb, GFP_ATOMIC); - if (rv) - dev_err(&desc->intf->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, rv); - -} - -static void kill_urbs(struct wdm_device *desc) -{ - /* the order here is essential */ - usb_kill_urb(desc->command); - usb_kill_urb(desc->validity); - usb_kill_urb(desc->response); -} - -static void free_urbs(struct wdm_device *desc) -{ - usb_free_urb(desc->validity); - usb_free_urb(desc->response); - usb_free_urb(desc->command); -} - -static void cleanup(struct wdm_device *desc) -{ - kfree(desc->sbuf); - kfree(desc->inbuf); - kfree(desc->orq); - kfree(desc->irq); - kfree(desc->ubuf); - free_urbs(desc); - kfree(desc); -} - -static ssize_t wdm_write -(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - u8 *buf; - int rv = -EMSGSIZE, r, we; - struct wdm_device *desc = file->private_data; - struct usb_ctrlrequest *req; - - if (count > desc->wMaxCommand) - count = desc->wMaxCommand; - - spin_lock_irq(&desc->iuspin); - we = desc->werr; - desc->werr = 0; - spin_unlock_irq(&desc->iuspin); - if (we < 0) - return -EIO; - - buf = kmalloc(count, GFP_KERNEL); - if (!buf) { - rv = -ENOMEM; - goto outnl; - } - - r = copy_from_user(buf, buffer, count); - if (r > 0) { - kfree(buf); - rv = -EFAULT; - goto outnl; - } - - /* concurrent writes and disconnect */ - r = mutex_lock_interruptible(&desc->wlock); - rv = -ERESTARTSYS; - if (r) { - kfree(buf); - goto outnl; - } - - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - kfree(buf); - rv = -ENODEV; - goto outnp; - } - - r = usb_autopm_get_interface(desc->intf); - if (r < 0) { - kfree(buf); - goto outnp; - } - - if (!(file->f_flags & O_NONBLOCK)) - r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, - &desc->flags)); - else - if (test_bit(WDM_IN_USE, &desc->flags)) - r = -EAGAIN; - - if (test_bit(WDM_RESETTING, &desc->flags)) - r = -EIO; - - if (r < 0) { - kfree(buf); - goto out; - } - - req = desc->orq; - usb_fill_control_urb( - desc->command, - interface_to_usbdev(desc->intf), - /* using common endpoint 0 */ - usb_sndctrlpipe(interface_to_usbdev(desc->intf), 0), - (unsigned char *)req, - buf, - count, - wdm_out_callback, - desc - ); - - req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | - USB_RECIP_INTERFACE); - req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; - req->wValue = 0; - req->wIndex = desc->inum; - req->wLength = cpu_to_le16(count); - set_bit(WDM_IN_USE, &desc->flags); - desc->outbuf = buf; - - rv = usb_submit_urb(desc->command, GFP_KERNEL); - if (rv < 0) { - kfree(buf); - desc->outbuf = NULL; - clear_bit(WDM_IN_USE, &desc->flags); - dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); - } else { - dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", - req->wIndex); - } -out: - usb_autopm_put_interface(desc->intf); -outnp: - mutex_unlock(&desc->wlock); -outnl: - return rv < 0 ? rv : count; -} - -static ssize_t wdm_read -(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - int rv, cntr; - int i = 0; - struct wdm_device *desc = file->private_data; - - - rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ - if (rv < 0) - return -ERESTARTSYS; - - cntr = ACCESS_ONCE(desc->length); - if (cntr == 0) { - desc->read = 0; -retry: - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - rv = -ENODEV; - goto err; - } - i++; - if (file->f_flags & O_NONBLOCK) { - if (!test_bit(WDM_READ, &desc->flags)) { - rv = cntr ? cntr : -EAGAIN; - goto err; - } - rv = 0; - } else { - rv = wait_event_interruptible(desc->wait, - test_bit(WDM_READ, &desc->flags)); - } - - /* may have happened while we slept */ - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - rv = -ENODEV; - goto err; - } - if (test_bit(WDM_RESETTING, &desc->flags)) { - rv = -EIO; - goto err; - } - usb_mark_last_busy(interface_to_usbdev(desc->intf)); - if (rv < 0) { - rv = -ERESTARTSYS; - goto err; - } - - spin_lock_irq(&desc->iuspin); - - if (desc->rerr) { /* read completed, error happened */ - desc->rerr = 0; - spin_unlock_irq(&desc->iuspin); - rv = -EIO; - goto err; - } - /* - * recheck whether we've lost the race - * against the completion handler - */ - if (!test_bit(WDM_READ, &desc->flags)) { /* lost race */ - spin_unlock_irq(&desc->iuspin); - goto retry; - } - if (!desc->reslength) { /* zero length read */ - dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); - clear_bit(WDM_READ, &desc->flags); - spin_unlock_irq(&desc->iuspin); - goto retry; - } - cntr = desc->length; - spin_unlock_irq(&desc->iuspin); - } - - if (cntr > count) - cntr = count; - rv = copy_to_user(buffer, desc->ubuf, cntr); - if (rv > 0) { - rv = -EFAULT; - goto err; - } - - spin_lock_irq(&desc->iuspin); - - for (i = 0; i < desc->length - cntr; i++) - desc->ubuf[i] = desc->ubuf[i + cntr]; - - desc->length -= cntr; - /* in case we had outstanding data */ - if (!desc->length) - clear_bit(WDM_READ, &desc->flags); - - spin_unlock_irq(&desc->iuspin); - - rv = cntr; - -err: - mutex_unlock(&desc->rlock); - return rv; -} - -static int wdm_flush(struct file *file, fl_owner_t id) -{ - struct wdm_device *desc = file->private_data; - - wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); - - /* cannot dereference desc->intf if WDM_DISCONNECTING */ - if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags)) - dev_err(&desc->intf->dev, "Error in flush path: %d\n", - desc->werr); - - return usb_translate_errors(desc->werr); -} - -static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) -{ - struct wdm_device *desc = file->private_data; - unsigned long flags; - unsigned int mask = 0; - - spin_lock_irqsave(&desc->iuspin, flags); - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - mask = POLLHUP | POLLERR; - spin_unlock_irqrestore(&desc->iuspin, flags); - goto desc_out; - } - if (test_bit(WDM_READ, &desc->flags)) - mask = POLLIN | POLLRDNORM; - if (desc->rerr || desc->werr) - mask |= POLLERR; - if (!test_bit(WDM_IN_USE, &desc->flags)) - mask |= POLLOUT | POLLWRNORM; - spin_unlock_irqrestore(&desc->iuspin, flags); - - poll_wait(file, &desc->wait, wait); - -desc_out: - return mask; -} - -static int wdm_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - int rv = -ENODEV; - struct usb_interface *intf; - struct wdm_device *desc; - - mutex_lock(&wdm_mutex); - desc = wdm_find_device_by_minor(minor); - if (!desc) - goto out; - - intf = desc->intf; - if (test_bit(WDM_DISCONNECTING, &desc->flags)) - goto out; - file->private_data = desc; - - rv = usb_autopm_get_interface(desc->intf); - if (rv < 0) { - dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); - goto out; - } - - /* using write lock to protect desc->count */ - mutex_lock(&desc->wlock); - if (!desc->count++) { - desc->werr = 0; - desc->rerr = 0; - rv = usb_submit_urb(desc->validity, GFP_KERNEL); - if (rv < 0) { - desc->count--; - dev_err(&desc->intf->dev, - "Error submitting int urb - %d\n", rv); - } - } else { - rv = 0; - } - mutex_unlock(&desc->wlock); - if (desc->count == 1) - desc->manage_power(intf, 1); - usb_autopm_put_interface(desc->intf); -out: - mutex_unlock(&wdm_mutex); - return rv; -} - -static int wdm_release(struct inode *inode, struct file *file) -{ - struct wdm_device *desc = file->private_data; - - mutex_lock(&wdm_mutex); - - /* using write lock to protect desc->count */ - mutex_lock(&desc->wlock); - desc->count--; - mutex_unlock(&desc->wlock); - - if (!desc->count) { - if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { - dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); - kill_urbs(desc); - desc->manage_power(desc->intf, 0); - } else { - /* must avoid dev_printk here as desc->intf is invalid */ - pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__); - cleanup(desc); - } - } - mutex_unlock(&wdm_mutex); - return 0; -} - -static const struct file_operations wdm_fops = { - .owner = THIS_MODULE, - .read = wdm_read, - .write = wdm_write, - .open = wdm_open, - .flush = wdm_flush, - .release = wdm_release, - .poll = wdm_poll, - .llseek = noop_llseek, -}; - -static struct usb_class_driver wdm_class = { - .name = "cdc-wdm%d", - .fops = &wdm_fops, - .minor_base = WDM_MINOR_BASE, -}; - -/* --- error handling --- */ -static void wdm_rxwork(struct work_struct *work) -{ - struct wdm_device *desc = container_of(work, struct wdm_device, rxwork); - unsigned long flags; - int rv; - - spin_lock_irqsave(&desc->iuspin, flags); - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - spin_unlock_irqrestore(&desc->iuspin, flags); - } else { - spin_unlock_irqrestore(&desc->iuspin, flags); - rv = usb_submit_urb(desc->response, GFP_KERNEL); - if (rv < 0 && rv != -EPERM) { - spin_lock_irqsave(&desc->iuspin, flags); - if (!test_bit(WDM_DISCONNECTING, &desc->flags)) - schedule_work(&desc->rxwork); - spin_unlock_irqrestore(&desc->iuspin, flags); - } - } -} - -/* --- hotplug --- */ - -static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, - u16 bufsize, int (*manage_power)(struct usb_interface *, int)) -{ - int rv = -ENOMEM; - struct wdm_device *desc; - - desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); - if (!desc) - goto out; - INIT_LIST_HEAD(&desc->device_list); - mutex_init(&desc->rlock); - mutex_init(&desc->wlock); - spin_lock_init(&desc->iuspin); - init_waitqueue_head(&desc->wait); - desc->wMaxCommand = bufsize; - /* this will be expanded and needed in hardware endianness */ - desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); - desc->intf = intf; - INIT_WORK(&desc->rxwork, wdm_rxwork); - - rv = -EINVAL; - if (!usb_endpoint_is_int_in(ep)) - goto err; - - desc->wMaxPacketSize = usb_endpoint_maxp(ep); - - desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!desc->orq) - goto err; - desc->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!desc->irq) - goto err; - - desc->validity = usb_alloc_urb(0, GFP_KERNEL); - if (!desc->validity) - goto err; - - desc->response = usb_alloc_urb(0, GFP_KERNEL); - if (!desc->response) - goto err; - - desc->command = usb_alloc_urb(0, GFP_KERNEL); - if (!desc->command) - goto err; - - desc->ubuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); - if (!desc->ubuf) - goto err; - - desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL); - if (!desc->sbuf) - goto err; - - desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); - if (!desc->inbuf) - goto err; - - usb_fill_int_urb( - desc->validity, - interface_to_usbdev(intf), - usb_rcvintpipe(interface_to_usbdev(intf), ep->bEndpointAddress), - desc->sbuf, - desc->wMaxPacketSize, - wdm_int_callback, - desc, - ep->bInterval - ); - - desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); - desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; - desc->irq->wValue = 0; - desc->irq->wIndex = desc->inum; - desc->irq->wLength = cpu_to_le16(desc->wMaxCommand); - - usb_fill_control_urb( - desc->response, - interface_to_usbdev(intf), - /* using common endpoint 0 */ - usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), - (unsigned char *)desc->irq, - desc->inbuf, - desc->wMaxCommand, - wdm_in_callback, - desc - ); - - desc->manage_power = manage_power; - - spin_lock(&wdm_device_list_lock); - list_add(&desc->device_list, &wdm_device_list); - spin_unlock(&wdm_device_list_lock); - - rv = usb_register_dev(intf, &wdm_class); - if (rv < 0) - goto err; - else - dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev)); -out: - return rv; -err: - spin_lock(&wdm_device_list_lock); - list_del(&desc->device_list); - spin_unlock(&wdm_device_list_lock); - cleanup(desc); - return rv; -} - -static int wdm_manage_power(struct usb_interface *intf, int on) -{ - /* need autopm_get/put here to ensure the usbcore sees the new value */ - int rv = usb_autopm_get_interface(intf); - if (rv < 0) - goto err; - - intf->needs_remote_wakeup = on; - usb_autopm_put_interface(intf); -err: - return rv; -} - -static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - int rv = -EINVAL; - struct usb_host_interface *iface; - struct usb_endpoint_descriptor *ep; - struct usb_cdc_dmm_desc *dmhd; - u8 *buffer = intf->altsetting->extra; - int buflen = intf->altsetting->extralen; - u16 maxcom = WDM_DEFAULT_BUFSIZE; - - if (!buffer) - goto err; - while (buflen > 2) { - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - - switch (buffer[2]) { - case USB_CDC_HEADER_TYPE: - break; - case USB_CDC_DMM_TYPE: - dmhd = (struct usb_cdc_dmm_desc *)buffer; - maxcom = le16_to_cpu(dmhd->wMaxCommand); - dev_dbg(&intf->dev, - "Finding maximum buffer length: %d", maxcom); - break; - default: - dev_err(&intf->dev, - "Ignoring extra header, type %d, length %d\n", - buffer[2], buffer[0]); - break; - } -next_desc: - buflen -= buffer[0]; - buffer += buffer[0]; - } - - iface = intf->cur_altsetting; - if (iface->desc.bNumEndpoints != 1) - goto err; - ep = &iface->endpoint[0].desc; - - rv = wdm_create(intf, ep, maxcom, &wdm_manage_power); - -err: - return rv; -} - -/** - * usb_cdc_wdm_register - register a WDM subdriver - * @intf: usb interface the subdriver will associate with - * @ep: interrupt endpoint to monitor for notifications - * @bufsize: maximum message size to support for read/write - * - * Create WDM usb class character device and associate it with intf - * without binding, allowing another driver to manage the interface. - * - * The subdriver will manage the given interrupt endpoint exclusively - * and will issue control requests referring to the given intf. It - * will otherwise avoid interferring, and in particular not do - * usb_set_intfdata/usb_get_intfdata on intf. - * - * The return value is a pointer to the subdriver's struct usb_driver. - * The registering driver is responsible for calling this subdriver's - * disconnect, suspend, resume, pre_reset and post_reset methods from - * its own. - */ -struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf, - struct usb_endpoint_descriptor *ep, - int bufsize, - int (*manage_power)(struct usb_interface *, int)) -{ - int rv = -EINVAL; - - rv = wdm_create(intf, ep, bufsize, manage_power); - if (rv < 0) - goto err; - - return &wdm_driver; -err: - return ERR_PTR(rv); -} -EXPORT_SYMBOL(usb_cdc_wdm_register); - -static void wdm_disconnect(struct usb_interface *intf) -{ - struct wdm_device *desc; - unsigned long flags; - - usb_deregister_dev(intf, &wdm_class); - desc = wdm_find_device(intf); - mutex_lock(&wdm_mutex); - - /* the spinlock makes sure no new urbs are generated in the callbacks */ - spin_lock_irqsave(&desc->iuspin, flags); - set_bit(WDM_DISCONNECTING, &desc->flags); - set_bit(WDM_READ, &desc->flags); - /* to terminate pending flushes */ - clear_bit(WDM_IN_USE, &desc->flags); - spin_unlock_irqrestore(&desc->iuspin, flags); - wake_up_all(&desc->wait); - mutex_lock(&desc->rlock); - mutex_lock(&desc->wlock); - kill_urbs(desc); - cancel_work_sync(&desc->rxwork); - mutex_unlock(&desc->wlock); - mutex_unlock(&desc->rlock); - - /* the desc->intf pointer used as list key is now invalid */ - spin_lock(&wdm_device_list_lock); - list_del(&desc->device_list); - spin_unlock(&wdm_device_list_lock); - - if (!desc->count) - cleanup(desc); - mutex_unlock(&wdm_mutex); -} - -#ifdef CONFIG_PM -static int wdm_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct wdm_device *desc = wdm_find_device(intf); - int rv = 0; - - dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); - - /* if this is an autosuspend the caller does the locking */ - if (!PMSG_IS_AUTO(message)) { - mutex_lock(&desc->rlock); - mutex_lock(&desc->wlock); - } - spin_lock_irq(&desc->iuspin); - - if (PMSG_IS_AUTO(message) && - (test_bit(WDM_IN_USE, &desc->flags) - || test_bit(WDM_RESPONDING, &desc->flags))) { - spin_unlock_irq(&desc->iuspin); - rv = -EBUSY; - } else { - - set_bit(WDM_SUSPENDING, &desc->flags); - spin_unlock_irq(&desc->iuspin); - /* callback submits work - order is essential */ - kill_urbs(desc); - cancel_work_sync(&desc->rxwork); - } - if (!PMSG_IS_AUTO(message)) { - mutex_unlock(&desc->wlock); - mutex_unlock(&desc->rlock); - } - - return rv; -} -#endif - -static int recover_from_urb_loss(struct wdm_device *desc) -{ - int rv = 0; - - if (desc->count) { - rv = usb_submit_urb(desc->validity, GFP_NOIO); - if (rv < 0) - dev_err(&desc->intf->dev, - "Error resume submitting int urb - %d\n", rv); - } - return rv; -} - -#ifdef CONFIG_PM -static int wdm_resume(struct usb_interface *intf) -{ - struct wdm_device *desc = wdm_find_device(intf); - int rv; - - dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); - - clear_bit(WDM_SUSPENDING, &desc->flags); - rv = recover_from_urb_loss(desc); - - return rv; -} -#endif - -static int wdm_pre_reset(struct usb_interface *intf) -{ - struct wdm_device *desc = wdm_find_device(intf); - - /* - * we notify everybody using poll of - * an exceptional situation - * must be done before recovery lest a spontaneous - * message from the device is lost - */ - spin_lock_irq(&desc->iuspin); - set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */ - set_bit(WDM_READ, &desc->flags); /* unblock read */ - clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */ - desc->rerr = -EINTR; - spin_unlock_irq(&desc->iuspin); - wake_up_all(&desc->wait); - mutex_lock(&desc->rlock); - mutex_lock(&desc->wlock); - kill_urbs(desc); - cancel_work_sync(&desc->rxwork); - return 0; -} - -static int wdm_post_reset(struct usb_interface *intf) -{ - struct wdm_device *desc = wdm_find_device(intf); - int rv; - - clear_bit(WDM_RESETTING, &desc->flags); - rv = recover_from_urb_loss(desc); - mutex_unlock(&desc->wlock); - mutex_unlock(&desc->rlock); - return 0; -} - -static struct usb_driver wdm_driver = { - .name = "cdc_wdm", - .probe = wdm_probe, - .disconnect = wdm_disconnect, -#ifdef CONFIG_PM - .suspend = wdm_suspend, - .resume = wdm_resume, - .reset_resume = wdm_resume, -#endif - .pre_reset = wdm_pre_reset, - .post_reset = wdm_post_reset, - .id_table = wdm_ids, - .supports_autosuspend = 1, -}; - -module_usb_driver(wdm_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/class/usblp.c b/ANDROID_3.4.5/drivers/usb/class/usblp.c deleted file mode 100644 index a68c1a63..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/usblp.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * usblp.c - * - * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com> - * Copyright (c) 1999 Pavel Machek <pavel@ucw.cz> - * Copyright (c) 2000 Randy Dunlap <rdunlap@xenotime.net> - * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> - # Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com> - # Copyright (c) 2001 David Paschal <paschal@rcsis.com> - * Copyright (c) 2006 Oliver Neukum <oliver@neukum.name> - * - * USB Printer Device Class driver for USB printers and printer cables - * - * Sponsored by SuSE - * - * ChangeLog: - * v0.1 - thorough cleaning, URBification, almost a rewrite - * v0.2 - some more cleanups - * v0.3 - cleaner again, waitqueue fixes - * v0.4 - fixes in unidirectional mode - * v0.5 - add DEVICE_ID string support - * v0.6 - never time out - * v0.7 - fixed bulk-IN read and poll (David Paschal) - * v0.8 - add devfs support - * v0.9 - fix unplug-while-open paths - * v0.10- remove sleep_on, fix error on oom (oliver@neukum.org) - * v0.11 - add proto_bias option (Pete Zaitcev) - * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) - * v0.13 - alloc space for statusbuf (<status> not on stack); - * use usb_alloc_coherent() for read buf & write buf; - * none - Maintained in Linux kernel after v0.13 - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/lp.h> -#include <linux/mutex.h> -#undef DEBUG -#include <linux/usb.h> -#include <linux/ratelimit.h> - -/* - * Version Information - */ -#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" -#define DRIVER_DESC "USB Printer Device Class driver" - -#define USBLP_BUF_SIZE 8192 -#define USBLP_BUF_SIZE_IN 1024 -#define USBLP_DEVICE_ID_SIZE 1024 - -/* ioctls: */ -#define IOCNR_GET_DEVICE_ID 1 -#define IOCNR_GET_PROTOCOLS 2 -#define IOCNR_SET_PROTOCOL 3 -#define IOCNR_HP_SET_CHANNEL 4 -#define IOCNR_GET_BUS_ADDRESS 5 -#define IOCNR_GET_VID_PID 6 -#define IOCNR_SOFT_RESET 7 -/* Get device_id string: */ -#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) -/* The following ioctls were added for http://hpoj.sourceforge.net: */ -/* Get two-int array: - * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), - * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ -#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) -/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ -#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) -/* Set channel number (HP Vendor-specific command): */ -#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) -/* Get two-int array: [0]=bus number, [1]=device address: */ -#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len) -/* Get two-int array: [0]=vendor ID, [1]=product ID: */ -#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) -/* Perform class specific soft reset */ -#define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0); - -/* - * A DEVICE_ID string may include the printer's serial number. - * It should end with a semi-colon (';'). - * An example from an HP 970C DeskJet printer is (this is one long string, - * with the serial number changed): -MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ: ; - */ - -/* - * USB Printer Requests - */ - -#define USBLP_REQ_GET_ID 0x00 -#define USBLP_REQ_GET_STATUS 0x01 -#define USBLP_REQ_RESET 0x02 -#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */ - -#define USBLP_MINORS 16 -#define USBLP_MINOR_BASE 0 - -#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */ - -#define USBLP_FIRST_PROTOCOL 1 -#define USBLP_LAST_PROTOCOL 3 -#define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1) - -/* - * some arbitrary status buffer size; - * need a status buffer that is allocated via kmalloc(), not on stack - */ -#define STATUS_BUF_SIZE 8 - -/* - * Locks down the locking order: - * ->wmut locks wstatus. - * ->mut locks the whole usblp, except [rw]complete, and thus, by indirection, - * [rw]status. We only touch status when we know the side idle. - * ->lock locks what interrupt accesses. - */ -struct usblp { - struct usb_device *dev; /* USB device */ - struct mutex wmut; - struct mutex mut; - spinlock_t lock; /* locks rcomplete, wcomplete */ - char *readbuf; /* read transfer_buffer */ - char *statusbuf; /* status transfer_buffer */ - struct usb_anchor urbs; - wait_queue_head_t rwait, wwait; - int readcount; /* Counter for reads */ - int ifnum; /* Interface number */ - struct usb_interface *intf; /* The interface */ - /* Alternate-setting numbers and endpoints for each protocol - * (7/1/{index=1,2,3}) that the device supports: */ - struct { - int alt_setting; - struct usb_endpoint_descriptor *epwrite; - struct usb_endpoint_descriptor *epread; - } protocol[USBLP_MAX_PROTOCOLS]; - int current_protocol; - int minor; /* minor number of device */ - int wcomplete, rcomplete; - int wstatus; /* bytes written or error */ - int rstatus; /* bytes ready or error */ - unsigned int quirks; /* quirks flags */ - unsigned int flags; /* mode flags */ - unsigned char used; /* True if open */ - unsigned char present; /* True if not disconnected */ - unsigned char bidir; /* interface is bidirectional */ - unsigned char no_paper; /* Paper Out happened */ - unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ - /* first 2 bytes are (big-endian) length */ -}; - -#ifdef DEBUG -static void usblp_dump(struct usblp *usblp) -{ - int p; - - dbg("usblp=0x%p", usblp); - dbg("dev=0x%p", usblp->dev); - dbg("present=%d", usblp->present); - dbg("readbuf=0x%p", usblp->readbuf); - dbg("readcount=%d", usblp->readcount); - dbg("ifnum=%d", usblp->ifnum); - for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { - dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); - dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); - dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); - } - dbg("current_protocol=%d", usblp->current_protocol); - dbg("minor=%d", usblp->minor); - dbg("wstatus=%d", usblp->wstatus); - dbg("rstatus=%d", usblp->rstatus); - dbg("quirks=%d", usblp->quirks); - dbg("used=%d", usblp->used); - dbg("bidir=%d", usblp->bidir); - dbg("device_id_string=\"%s\"", - usblp->device_id_string ? - usblp->device_id_string + 2 : - (unsigned char *)"(null)"); -} -#endif - -/* Quirks: various printer quirks are handled by this table & its flags. */ - -struct quirk_printer_struct { - __u16 vendorId; - __u16 productId; - unsigned int quirks; -}; - -#define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ -#define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ -#define USBLP_QUIRK_BAD_CLASS 0x4 /* descriptor uses vendor-specific Class or SubClass */ - -static const struct quirk_printer_struct quirk_printers[] = { - { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ - { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */ - { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ - { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ - { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ - { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */ - { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */ - { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */ - { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */ - { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ - { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ - { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ - { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ - { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut <kernel@zut.de> */ - { 0x04f9, 0x000d, USBLP_QUIRK_BIDIR }, /* Brother Industries, Ltd HL-1440 Laser Printer */ - { 0x04b8, 0x0202, USBLP_QUIRK_BAD_CLASS }, /* Seiko Epson Receipt Printer M129C */ - { 0, 0 } -}; - -static int usblp_wwait(struct usblp *usblp, int nonblock); -static int usblp_wtest(struct usblp *usblp, int nonblock); -static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock); -static int usblp_rtest(struct usblp *usblp, int nonblock); -static int usblp_submit_read(struct usblp *usblp); -static int usblp_select_alts(struct usblp *usblp); -static int usblp_set_protocol(struct usblp *usblp, int protocol); -static int usblp_cache_device_id_string(struct usblp *usblp); - -/* forward reference to make our lives easier */ -static struct usb_driver usblp_driver; -static DEFINE_MUTEX(usblp_mutex); /* locks the existence of usblp's */ - -/* - * Functions for usblp control messages. - */ - -static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) -{ - int retval; - int index = usblp->ifnum; - - /* High byte has the interface index. - Low byte has the alternate setting. - */ - if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) - index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting; - - retval = usb_control_msg(usblp->dev, - dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); - dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", - request, !!dir, recip, value, index, len, retval); - return retval < 0 ? retval : 0; -} - -#define usblp_read_status(usblp, status)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) -#define usblp_get_id(usblp, config, id, maxlen)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) -#define usblp_reset(usblp)\ - usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) - -#define usblp_hp_channel_change_request(usblp, channel, buffer) \ - usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) - -/* - * See the description for usblp_select_alts() below for the usage - * explanation. Look into your /proc/bus/usb/devices and dmesg in - * case of any trouble. - */ -static int proto_bias = -1; - -/* - * URB callback. - */ - -static void usblp_bulk_read(struct urb *urb) -{ - struct usblp *usblp = urb->context; - int status = urb->status; - - if (usblp->present && usblp->used) { - if (status) - printk(KERN_WARNING "usblp%d: " - "nonzero read bulk status received: %d\n", - usblp->minor, status); - } - spin_lock(&usblp->lock); - if (status < 0) - usblp->rstatus = status; - else - usblp->rstatus = urb->actual_length; - usblp->rcomplete = 1; - wake_up(&usblp->rwait); - spin_unlock(&usblp->lock); - - usb_free_urb(urb); -} - -static void usblp_bulk_write(struct urb *urb) -{ - struct usblp *usblp = urb->context; - int status = urb->status; - - if (usblp->present && usblp->used) { - if (status) - printk(KERN_WARNING "usblp%d: " - "nonzero write bulk status received: %d\n", - usblp->minor, status); - } - spin_lock(&usblp->lock); - if (status < 0) - usblp->wstatus = status; - else - usblp->wstatus = urb->actual_length; - usblp->no_paper = 0; - usblp->wcomplete = 1; - wake_up(&usblp->wwait); - spin_unlock(&usblp->lock); - - usb_free_urb(urb); -} - -/* - * Get and print printer errors. - */ - -static const char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; - -static int usblp_check_status(struct usblp *usblp, int err) -{ - unsigned char status, newerr = 0; - int error; - - mutex_lock(&usblp->mut); - if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { - mutex_unlock(&usblp->mut); - printk_ratelimited(KERN_ERR - "usblp%d: error %d reading printer status\n", - usblp->minor, error); - return 0; - } - status = *usblp->statusbuf; - mutex_unlock(&usblp->mut); - - if (~status & LP_PERRORP) - newerr = 3; - if (status & LP_POUTPA) - newerr = 1; - if (~status & LP_PSELECD) - newerr = 2; - - if (newerr != err) { - printk(KERN_INFO "usblp%d: %s\n", - usblp->minor, usblp_messages[newerr]); - } - - return newerr; -} - -static int handle_bidir(struct usblp *usblp) -{ - if (usblp->bidir && usblp->used) { - if (usblp_submit_read(usblp) < 0) - return -EIO; - } - return 0; -} - -/* - * File op functions. - */ - -static int usblp_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct usblp *usblp; - struct usb_interface *intf; - int retval; - - if (minor < 0) - return -ENODEV; - - mutex_lock(&usblp_mutex); - - retval = -ENODEV; - intf = usb_find_interface(&usblp_driver, minor); - if (!intf) - goto out; - usblp = usb_get_intfdata(intf); - if (!usblp || !usblp->dev || !usblp->present) - goto out; - - retval = -EBUSY; - if (usblp->used) - goto out; - - /* - * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: - * - We do not want persistent state which close(2) does not clear - * - It is not used anyway, according to CUPS people - */ - - retval = usb_autopm_get_interface(intf); - if (retval < 0) - goto out; - usblp->used = 1; - file->private_data = usblp; - - usblp->wcomplete = 1; /* we begin writeable */ - usblp->wstatus = 0; - usblp->rcomplete = 0; - - if (handle_bidir(usblp) < 0) { - usb_autopm_put_interface(intf); - usblp->used = 0; - file->private_data = NULL; - retval = -EIO; - } -out: - mutex_unlock(&usblp_mutex); - return retval; -} - -static void usblp_cleanup(struct usblp *usblp) -{ - printk(KERN_INFO "usblp%d: removed\n", usblp->minor); - - kfree(usblp->readbuf); - kfree(usblp->device_id_string); - kfree(usblp->statusbuf); - kfree(usblp); -} - -static void usblp_unlink_urbs(struct usblp *usblp) -{ - usb_kill_anchored_urbs(&usblp->urbs); -} - -static int usblp_release(struct inode *inode, struct file *file) -{ - struct usblp *usblp = file->private_data; - - usblp->flags &= ~LP_ABORT; - - mutex_lock(&usblp_mutex); - usblp->used = 0; - if (usblp->present) { - usblp_unlink_urbs(usblp); - usb_autopm_put_interface(usblp->intf); - } else /* finish cleanup from disconnect */ - usblp_cleanup(usblp); - mutex_unlock(&usblp_mutex); - return 0; -} - -/* No kernel lock - fine */ -static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait) -{ - int ret; - unsigned long flags; - - struct usblp *usblp = file->private_data; - /* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */ - poll_wait(file, &usblp->rwait, wait); - poll_wait(file, &usblp->wwait, wait); - spin_lock_irqsave(&usblp->lock, flags); - ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | - ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); - spin_unlock_irqrestore(&usblp->lock, flags); - return ret; -} - -static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usblp *usblp = file->private_data; - int length, err, i; - unsigned char newChannel; - int status; - int twoints[2]; - int retval = 0; - - mutex_lock(&usblp->mut); - if (!usblp->present) { - retval = -ENODEV; - goto done; - } - - dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), - _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd)); - - if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ - - switch (_IOC_NR(cmd)) { - - case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ - if (_IOC_DIR(cmd) != _IOC_READ) { - retval = -EINVAL; - goto done; - } - - length = usblp_cache_device_id_string(usblp); - if (length < 0) { - retval = length; - goto done; - } - if (length > _IOC_SIZE(cmd)) - length = _IOC_SIZE(cmd); /* truncate */ - - if (copy_to_user((void __user *) arg, - usblp->device_id_string, - (unsigned long) length)) { - retval = -EFAULT; - goto done; - } - - break; - - case IOCNR_GET_PROTOCOLS: - if (_IOC_DIR(cmd) != _IOC_READ || - _IOC_SIZE(cmd) < sizeof(twoints)) { - retval = -EINVAL; - goto done; - } - - twoints[0] = usblp->current_protocol; - twoints[1] = 0; - for (i = USBLP_FIRST_PROTOCOL; - i <= USBLP_LAST_PROTOCOL; i++) { - if (usblp->protocol[i].alt_setting >= 0) - twoints[1] |= (1<<i); - } - - if (copy_to_user((void __user *)arg, - (unsigned char *)twoints, - sizeof(twoints))) { - retval = -EFAULT; - goto done; - } - - break; - - case IOCNR_SET_PROTOCOL: - if (_IOC_DIR(cmd) != _IOC_WRITE) { - retval = -EINVAL; - goto done; - } - -#ifdef DEBUG - if (arg == -10) { - usblp_dump(usblp); - break; - } -#endif - - usblp_unlink_urbs(usblp); - retval = usblp_set_protocol(usblp, arg); - if (retval < 0) { - usblp_set_protocol(usblp, - usblp->current_protocol); - } - break; - - case IOCNR_HP_SET_CHANNEL: - if (_IOC_DIR(cmd) != _IOC_WRITE || - le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 || - usblp->quirks & USBLP_QUIRK_BIDIR) { - retval = -EINVAL; - goto done; - } - - err = usblp_hp_channel_change_request(usblp, - arg, &newChannel); - if (err < 0) { - dev_err(&usblp->dev->dev, - "usblp%d: error = %d setting " - "HP channel\n", - usblp->minor, err); - retval = -EIO; - goto done; - } - - dbg("usblp%d requested/got HP channel %ld/%d", - usblp->minor, arg, newChannel); - break; - - case IOCNR_GET_BUS_ADDRESS: - if (_IOC_DIR(cmd) != _IOC_READ || - _IOC_SIZE(cmd) < sizeof(twoints)) { - retval = -EINVAL; - goto done; - } - - twoints[0] = usblp->dev->bus->busnum; - twoints[1] = usblp->dev->devnum; - if (copy_to_user((void __user *)arg, - (unsigned char *)twoints, - sizeof(twoints))) { - retval = -EFAULT; - goto done; - } - - dbg("usblp%d is bus=%d, device=%d", - usblp->minor, twoints[0], twoints[1]); - break; - - case IOCNR_GET_VID_PID: - if (_IOC_DIR(cmd) != _IOC_READ || - _IOC_SIZE(cmd) < sizeof(twoints)) { - retval = -EINVAL; - goto done; - } - - twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor); - twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct); - if (copy_to_user((void __user *)arg, - (unsigned char *)twoints, - sizeof(twoints))) { - retval = -EFAULT; - goto done; - } - - dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", - usblp->minor, twoints[0], twoints[1]); - break; - - case IOCNR_SOFT_RESET: - if (_IOC_DIR(cmd) != _IOC_NONE) { - retval = -EINVAL; - goto done; - } - retval = usblp_reset(usblp); - break; - default: - retval = -ENOTTY; - } - else /* old-style ioctl value */ - switch (cmd) { - - case LPGETSTATUS: - if ((retval = usblp_read_status(usblp, usblp->statusbuf))) { - printk_ratelimited(KERN_ERR "usblp%d:" - "failed reading printer status (%d)\n", - usblp->minor, retval); - retval = -EIO; - goto done; - } - status = *usblp->statusbuf; - if (copy_to_user((void __user *)arg, &status, sizeof(int))) - retval = -EFAULT; - break; - - case LPABORT: - if (arg) - usblp->flags |= LP_ABORT; - else - usblp->flags &= ~LP_ABORT; - break; - - default: - retval = -ENOTTY; - } - -done: - mutex_unlock(&usblp->mut); - return retval; -} - -static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) -{ - struct urb *urb; - char *writebuf; - - if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) - return NULL; - if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { - kfree(writebuf); - return NULL; - } - - usb_fill_bulk_urb(urb, usblp->dev, - usb_sndbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), - writebuf, transfer_length, usblp_bulk_write, usblp); - urb->transfer_flags |= URB_FREE_BUFFER; - - return urb; -} - -static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct usblp *usblp = file->private_data; - struct urb *writeurb; - int rv; - int transfer_length; - ssize_t writecount = 0; - - if (mutex_lock_interruptible(&usblp->wmut)) { - rv = -EINTR; - goto raise_biglock; - } - if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0) - goto raise_wait; - - while (writecount < count) { - /* - * Step 1: Submit next block. - */ - if ((transfer_length = count - writecount) > USBLP_BUF_SIZE) - transfer_length = USBLP_BUF_SIZE; - - rv = -ENOMEM; - if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) - goto raise_urb; - usb_anchor_urb(writeurb, &usblp->urbs); - - if (copy_from_user(writeurb->transfer_buffer, - buffer + writecount, transfer_length)) { - rv = -EFAULT; - goto raise_badaddr; - } - - spin_lock_irq(&usblp->lock); - usblp->wcomplete = 0; - spin_unlock_irq(&usblp->lock); - if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { - usblp->wstatus = 0; - spin_lock_irq(&usblp->lock); - usblp->no_paper = 0; - usblp->wcomplete = 1; - wake_up(&usblp->wwait); - spin_unlock_irq(&usblp->lock); - if (rv != -ENOMEM) - rv = -EIO; - goto raise_submit; - } - - /* - * Step 2: Wait for transfer to end, collect results. - */ - rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK)); - if (rv < 0) { - if (rv == -EAGAIN) { - /* Presume that it's going to complete well. */ - writecount += transfer_length; - } - if (rv == -ENOSPC) { - spin_lock_irq(&usblp->lock); - usblp->no_paper = 1; /* Mark for poll(2) */ - spin_unlock_irq(&usblp->lock); - writecount += transfer_length; - } - /* Leave URB dangling, to be cleaned on close. */ - goto collect_error; - } - - if (usblp->wstatus < 0) { - rv = -EIO; - goto collect_error; - } - /* - * This is critical: it must be our URB, not other writer's. - * The wmut exists mainly to cover us here. - */ - writecount += usblp->wstatus; - } - - mutex_unlock(&usblp->wmut); - return writecount; - -raise_submit: -raise_badaddr: - usb_unanchor_urb(writeurb); - usb_free_urb(writeurb); -raise_urb: -raise_wait: -collect_error: /* Out of raise sequence */ - mutex_unlock(&usblp->wmut); -raise_biglock: - return writecount ? writecount : rv; -} - -/* - * Notice that we fail to restart in a few cases: on EFAULT, on restart - * error, etc. This is the historical behaviour. In all such cases we return - * EIO, and applications loop in order to get the new read going. - */ -static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos) -{ - struct usblp *usblp = file->private_data; - ssize_t count; - ssize_t avail; - int rv; - - if (!usblp->bidir) - return -EINVAL; - - rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK)); - if (rv < 0) - return rv; - - if ((avail = usblp->rstatus) < 0) { - printk(KERN_ERR "usblp%d: error %d reading from printer\n", - usblp->minor, (int)avail); - usblp_submit_read(usblp); - count = -EIO; - goto done; - } - - count = len < avail - usblp->readcount ? len : avail - usblp->readcount; - if (count != 0 && - copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) { - count = -EFAULT; - goto done; - } - - if ((usblp->readcount += count) == avail) { - if (usblp_submit_read(usblp) < 0) { - /* We don't want to leak USB return codes into errno. */ - if (count == 0) - count = -EIO; - goto done; - } - } - -done: - mutex_unlock(&usblp->mut); - return count; -} - -/* - * Wait for the write path to come idle. - * This is called under the ->wmut, so the idle path stays idle. - * - * Our write path has a peculiar property: it does not buffer like a tty, - * but waits for the write to succeed. This allows our ->release to bug out - * without waiting for writes to drain. But it obviously does not work - * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use - * select(2) or poll(2) to wait for the buffer to drain before closing. - * Alternatively, set blocking mode with fcntl and issue a zero-size write. - */ -static int usblp_wwait(struct usblp *usblp, int nonblock) -{ - DECLARE_WAITQUEUE(waita, current); - int rc; - int err = 0; - - add_wait_queue(&usblp->wwait, &waita); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (mutex_lock_interruptible(&usblp->mut)) { - rc = -EINTR; - break; - } - rc = usblp_wtest(usblp, nonblock); - mutex_unlock(&usblp->mut); - if (rc <= 0) - break; - - if (schedule_timeout(msecs_to_jiffies(1500)) == 0) { - if (usblp->flags & LP_ABORT) { - err = usblp_check_status(usblp, err); - if (err == 1) { /* Paper out */ - rc = -ENOSPC; - break; - } - } else { - /* Prod the printer, Gentoo#251237. */ - mutex_lock(&usblp->mut); - usblp_read_status(usblp, usblp->statusbuf); - mutex_unlock(&usblp->mut); - } - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&usblp->wwait, &waita); - return rc; -} - -static int usblp_wtest(struct usblp *usblp, int nonblock) -{ - unsigned long flags; - - if (!usblp->present) - return -ENODEV; - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&usblp->lock, flags); - if (usblp->wcomplete) { - spin_unlock_irqrestore(&usblp->lock, flags); - return 0; - } - spin_unlock_irqrestore(&usblp->lock, flags); - if (nonblock) - return -EAGAIN; - return 1; -} - -/* - * Wait for read bytes to become available. This probably should have been - * called usblp_r_lock_and_wait(), because we lock first. But it's a traditional - * name for functions which lock and return. - * - * We do not use wait_event_interruptible because it makes locking iffy. - */ -static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock) -{ - DECLARE_WAITQUEUE(waita, current); - int rc; - - add_wait_queue(&usblp->rwait, &waita); - for (;;) { - if (mutex_lock_interruptible(&usblp->mut)) { - rc = -EINTR; - break; - } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_rtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } - if (rc == 0) /* Keep it locked */ - break; - mutex_unlock(&usblp->mut); - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&usblp->rwait, &waita); - return rc; -} - -static int usblp_rtest(struct usblp *usblp, int nonblock) -{ - unsigned long flags; - - if (!usblp->present) - return -ENODEV; - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&usblp->lock, flags); - if (usblp->rcomplete) { - spin_unlock_irqrestore(&usblp->lock, flags); - return 0; - } - spin_unlock_irqrestore(&usblp->lock, flags); - if (nonblock) - return -EAGAIN; - return 1; -} - -/* - * Please check ->bidir and other such things outside for now. - */ -static int usblp_submit_read(struct usblp *usblp) -{ - struct urb *urb; - unsigned long flags; - int rc; - - rc = -ENOMEM; - if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) - goto raise_urb; - - usb_fill_bulk_urb(urb, usblp->dev, - usb_rcvbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epread->bEndpointAddress), - usblp->readbuf, USBLP_BUF_SIZE_IN, - usblp_bulk_read, usblp); - usb_anchor_urb(urb, &usblp->urbs); - - spin_lock_irqsave(&usblp->lock, flags); - usblp->readcount = 0; /* XXX Why here? */ - usblp->rcomplete = 0; - spin_unlock_irqrestore(&usblp->lock, flags); - if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) { - dbg("error submitting urb (%d)", rc); - spin_lock_irqsave(&usblp->lock, flags); - usblp->rstatus = rc; - usblp->rcomplete = 1; - spin_unlock_irqrestore(&usblp->lock, flags); - goto raise_submit; - } - - return 0; - -raise_submit: - usb_unanchor_urb(urb); - usb_free_urb(urb); -raise_urb: - return rc; -} - -/* - * Checks for printers that have quirks, such as requiring unidirectional - * communication but reporting bidirectional; currently some HP printers - * have this flaw (HP 810, 880, 895, etc.), or needing an init string - * sent at each open (like some Epsons). - * Returns 1 if found, 0 if not found. - * - * HP recommended that we use the bidirectional interface but - * don't attempt any bulk IN transfers from the IN endpoint. - * Here's some more detail on the problem: - * The problem is not that it isn't bidirectional though. The problem - * is that if you request a device ID, or status information, while - * the buffers are full, the return data will end up in the print data - * buffer. For example if you make sure you never request the device ID - * while you are sending print data, and you don't try to query the - * printer status every couple of milliseconds, you will probably be OK. - */ -static unsigned int usblp_quirks(__u16 vendor, __u16 product) -{ - int i; - - for (i = 0; quirk_printers[i].vendorId; i++) { - if (vendor == quirk_printers[i].vendorId && - product == quirk_printers[i].productId) - return quirk_printers[i].quirks; - } - return 0; -} - -static const struct file_operations usblp_fops = { - .owner = THIS_MODULE, - .read = usblp_read, - .write = usblp_write, - .poll = usblp_poll, - .unlocked_ioctl = usblp_ioctl, - .compat_ioctl = usblp_ioctl, - .open = usblp_open, - .release = usblp_release, - .llseek = noop_llseek, -}; - -static char *usblp_devnode(struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); -} - -static struct usb_class_driver usblp_class = { - .name = "lp%d", - .devnode = usblp_devnode, - .fops = &usblp_fops, - .minor_base = USBLP_MINOR_BASE, -}; - -static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usblp *usblp = usb_get_intfdata(intf); - - if (usblp->device_id_string[0] == 0 && - usblp->device_id_string[1] == 0) - return 0; - - return sprintf(buf, "%s", usblp->device_id_string+2); -} - -static DEVICE_ATTR(ieee1284_id, S_IRUGO, usblp_show_ieee1284_id, NULL); - -static int usblp_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usblp *usblp; - int protocol; - int retval; - - /* Malloc and start initializing usblp structure so we can use it - * directly. */ - usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL); - if (!usblp) { - retval = -ENOMEM; - goto abort_ret; - } - usblp->dev = dev; - mutex_init(&usblp->wmut); - mutex_init(&usblp->mut); - spin_lock_init(&usblp->lock); - init_waitqueue_head(&usblp->rwait); - init_waitqueue_head(&usblp->wwait); - init_usb_anchor(&usblp->urbs); - usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - usblp->intf = intf; - - /* Malloc device ID string buffer to the largest expected length, - * since we can re-query it on an ioctl and a dynamic string - * could change in length. */ - if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) { - retval = -ENOMEM; - goto abort; - } - - /* - * Allocate read buffer. We somewhat wastefully - * malloc both regardless of bidirectionality, because the - * alternate setting can be changed later via an ioctl. - */ - if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) { - retval = -ENOMEM; - goto abort; - } - - /* Allocate buffer for printer status */ - usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL); - if (!usblp->statusbuf) { - retval = -ENOMEM; - goto abort; - } - - /* Lookup quirks for this printer. */ - usblp->quirks = usblp_quirks( - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - /* Analyze and pick initial alternate settings and endpoints. */ - protocol = usblp_select_alts(usblp); - if (protocol < 0) { - dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - retval = -ENODEV; - goto abort; - } - - /* Setup the selected alternate setting and endpoints. */ - if (usblp_set_protocol(usblp, protocol) < 0) { - retval = -ENODEV; /* ->probe isn't ->ioctl */ - goto abort; - } - - /* Retrieve and store the device ID string. */ - usblp_cache_device_id_string(usblp); - retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id); - if (retval) - goto abort_intfdata; - -#ifdef DEBUG - usblp_check_status(usblp, 0); -#endif - - usb_set_intfdata(intf, usblp); - - usblp->present = 1; - - retval = usb_register_dev(intf, &usblp_class); - if (retval) { - printk(KERN_ERR "usblp: Not able to get a minor" - " (base %u, slice default): %d\n", - USBLP_MINOR_BASE, retval); - goto abort_intfdata; - } - usblp->minor = intf->minor; - printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d " - "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n", - usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, - usblp->ifnum, - usblp->protocol[usblp->current_protocol].alt_setting, - usblp->current_protocol, - le16_to_cpu(usblp->dev->descriptor.idVendor), - le16_to_cpu(usblp->dev->descriptor.idProduct)); - - return 0; - -abort_intfdata: - usb_set_intfdata(intf, NULL); - device_remove_file(&intf->dev, &dev_attr_ieee1284_id); -abort: - kfree(usblp->readbuf); - kfree(usblp->statusbuf); - kfree(usblp->device_id_string); - kfree(usblp); -abort_ret: - return retval; -} - -/* - * We are a "new" style driver with usb_device_id table, - * but our requirements are too intricate for simple match to handle. - * - * The "proto_bias" option may be used to specify the preferred protocol - * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device - * supports the preferred protocol, then we bind to it. - * - * The best interface for us is 7/1/2, because it is compatible - * with a stream of characters. If we find it, we bind to it. - * - * Note that the people from hpoj.sourceforge.net need to be able to - * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. - * - * Failing 7/1/2, we look for 7/1/3, even though it's probably not - * stream-compatible, because this matches the behaviour of the old code. - * - * If nothing else, we bind to 7/1/1 - the unidirectional interface. - */ -static int usblp_select_alts(struct usblp *usblp) -{ - struct usb_interface *if_alt; - struct usb_host_interface *ifd; - struct usb_endpoint_descriptor *epd, *epwrite, *epread; - int p, i, e; - - if_alt = usblp->intf; - - for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) - usblp->protocol[p].alt_setting = -1; - - /* Find out what we have. */ - for (i = 0; i < if_alt->num_altsetting; i++) { - ifd = &if_alt->altsetting[i]; - - if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) - if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS)) - continue; - - if (ifd->desc.bInterfaceProtocol < USBLP_FIRST_PROTOCOL || - ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL) - continue; - - /* Look for bulk OUT and IN endpoints. */ - epwrite = epread = NULL; - for (e = 0; e < ifd->desc.bNumEndpoints; e++) { - epd = &ifd->endpoint[e].desc; - - if (usb_endpoint_is_bulk_out(epd)) - if (!epwrite) - epwrite = epd; - - if (usb_endpoint_is_bulk_in(epd)) - if (!epread) - epread = epd; - } - - /* Ignore buggy hardware without the right endpoints. */ - if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread)) - continue; - - /* Turn off reads for 7/1/1 (unidirectional) interfaces - * and buggy bidirectional printers. */ - if (ifd->desc.bInterfaceProtocol == 1) { - epread = NULL; - } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { - printk(KERN_INFO "usblp%d: Disabling reads from " - "problematic bidirectional printer\n", - usblp->minor); - epread = NULL; - } - - usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = - ifd->desc.bAlternateSetting; - usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite; - usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread; - } - - /* If our requested protocol is supported, then use it. */ - if (proto_bias >= USBLP_FIRST_PROTOCOL && - proto_bias <= USBLP_LAST_PROTOCOL && - usblp->protocol[proto_bias].alt_setting != -1) - return proto_bias; - - /* Ordering is important here. */ - if (usblp->protocol[2].alt_setting != -1) - return 2; - if (usblp->protocol[1].alt_setting != -1) - return 1; - if (usblp->protocol[3].alt_setting != -1) - return 3; - - /* If nothing is available, then don't bind to this device. */ - return -1; -} - -static int usblp_set_protocol(struct usblp *usblp, int protocol) -{ - int r, alts; - - if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) - return -EINVAL; - - alts = usblp->protocol[protocol].alt_setting; - if (alts < 0) - return -EINVAL; - r = usb_set_interface(usblp->dev, usblp->ifnum, alts); - if (r < 0) { - printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", - alts, usblp->ifnum); - return r; - } - - usblp->bidir = (usblp->protocol[protocol].epread != NULL); - usblp->current_protocol = protocol; - dbg("usblp%d set protocol %d", usblp->minor, protocol); - return 0; -} - -/* Retrieves and caches device ID string. - * Returns length, including length bytes but not null terminator. - * On error, returns a negative errno value. */ -static int usblp_cache_device_id_string(struct usblp *usblp) -{ - int err, length; - - err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1); - if (err < 0) { - dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", - usblp->minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; - return -EIO; - } - - /* First two bytes are length in big-endian. - * They count themselves, and we copy them into - * the user's buffer. */ - length = be16_to_cpu(*((__be16 *)usblp->device_id_string)); - if (length < 2) - length = 2; - else if (length >= USBLP_DEVICE_ID_SIZE) - length = USBLP_DEVICE_ID_SIZE - 1; - usblp->device_id_string[length] = '\0'; - - dbg("usblp%d Device ID string [len=%d]=\"%s\"", - usblp->minor, length, &usblp->device_id_string[2]); - - return length; -} - -static void usblp_disconnect(struct usb_interface *intf) -{ - struct usblp *usblp = usb_get_intfdata(intf); - - usb_deregister_dev(intf, &usblp_class); - - if (!usblp || !usblp->dev) { - dev_err(&intf->dev, "bogus disconnect\n"); - BUG(); - } - - device_remove_file(&intf->dev, &dev_attr_ieee1284_id); - - mutex_lock(&usblp_mutex); - mutex_lock(&usblp->mut); - usblp->present = 0; - wake_up(&usblp->wwait); - wake_up(&usblp->rwait); - usb_set_intfdata(intf, NULL); - - usblp_unlink_urbs(usblp); - mutex_unlock(&usblp->mut); - - if (!usblp->used) - usblp_cleanup(usblp); - mutex_unlock(&usblp_mutex); -} - -static int usblp_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usblp *usblp = usb_get_intfdata(intf); - - usblp_unlink_urbs(usblp); -#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */ - /* not strictly necessary, but just in case */ - wake_up(&usblp->wwait); - wake_up(&usblp->rwait); -#endif - - return 0; -} - -static int usblp_resume(struct usb_interface *intf) -{ - struct usblp *usblp = usb_get_intfdata(intf); - int r; - - r = handle_bidir(usblp); - - return r; -} - -static const struct usb_device_id usblp_ids[] = { - { USB_DEVICE_INFO(7, 1, 1) }, - { USB_DEVICE_INFO(7, 1, 2) }, - { USB_DEVICE_INFO(7, 1, 3) }, - { USB_INTERFACE_INFO(7, 1, 1) }, - { USB_INTERFACE_INFO(7, 1, 2) }, - { USB_INTERFACE_INFO(7, 1, 3) }, - { USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, usblp_ids); - -static struct usb_driver usblp_driver = { - .name = "usblp", - .probe = usblp_probe, - .disconnect = usblp_disconnect, - .suspend = usblp_suspend, - .resume = usblp_resume, - .id_table = usblp_ids, - .supports_autosuspend = 1, -}; - -module_usb_driver(usblp_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -module_param(proto_bias, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/class/usbtmc.c b/ANDROID_3.4.5/drivers/usb/class/usbtmc.c deleted file mode 100644 index 70d69d06..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/usbtmc.c +++ /dev/null @@ -1,1121 +0,0 @@ -/** - * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver - * - * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * The GNU General Public License is available at - * http://www.gnu.org/copyleft/gpl.html. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/kref.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <linux/usb.h> -#include <linux/usb/tmc.h> - - -#define USBTMC_MINOR_BASE 176 - -/* - * Size of driver internal IO buffer. Must be multiple of 4 and at least as - * large as wMaxPacketSize (which is usually 512 bytes). - */ -#define USBTMC_SIZE_IOBUFFER 2048 - -/* Default USB timeout (in milliseconds) */ -#define USBTMC_TIMEOUT 5000 - -/* - * Maximum number of read cycles to empty bulk in endpoint during CLEAR and - * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short - * packet is never read. - */ -#define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100 - -static const struct usb_device_id usbtmc_devices[] = { - { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), }, - { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), }, - { 0, } /* terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, usbtmc_devices); - -/* - * This structure is the capabilities for the device - * See section 4.2.1.8 of the USBTMC specification, - * and section 4.2.2 of the USBTMC usb488 subclass - * specification for details. - */ -struct usbtmc_dev_capabilities { - __u8 interface_capabilities; - __u8 device_capabilities; - __u8 usb488_interface_capabilities; - __u8 usb488_device_capabilities; -}; - -/* This structure holds private data for each USBTMC device. One copy is - * allocated for each USBTMC device in the driver's probe function. - */ -struct usbtmc_device_data { - const struct usb_device_id *id; - struct usb_device *usb_dev; - struct usb_interface *intf; - - unsigned int bulk_in; - unsigned int bulk_out; - - u8 bTag; - u8 bTag_last_write; /* needed for abort */ - u8 bTag_last_read; /* needed for abort */ - - /* attributes from the USB TMC spec for this device */ - u8 TermChar; - bool TermCharEnabled; - bool auto_abort; - - bool zombie; /* fd of disconnected device */ - - struct usbtmc_dev_capabilities capabilities; - struct kref kref; - struct mutex io_mutex; /* only one i/o function running at a time */ -}; -#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref) - -/* Forward declarations */ -static struct usb_driver usbtmc_driver; - -static void usbtmc_delete(struct kref *kref) -{ - struct usbtmc_device_data *data = to_usbtmc_data(kref); - - usb_put_dev(data->usb_dev); - kfree(data); -} - -static int usbtmc_open(struct inode *inode, struct file *filp) -{ - struct usb_interface *intf; - struct usbtmc_device_data *data; - int retval = 0; - - intf = usb_find_interface(&usbtmc_driver, iminor(inode)); - if (!intf) { - printk(KERN_ERR KBUILD_MODNAME - ": can not find device for minor %d", iminor(inode)); - retval = -ENODEV; - goto exit; - } - - data = usb_get_intfdata(intf); - kref_get(&data->kref); - - /* Store pointer in file structure's private data field */ - filp->private_data = data; - -exit: - return retval; -} - -static int usbtmc_release(struct inode *inode, struct file *file) -{ - struct usbtmc_device_data *data = file->private_data; - - kref_put(&data->kref, usbtmc_delete); - return 0; -} - -static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) -{ - u8 *buffer; - struct device *dev; - int rv; - int n; - int actual; - struct usb_host_interface *current_setting; - int max_size; - - dev = &data->intf->dev; - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - data->bTag_last_read, data->bulk_in, - buffer, 2, USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_FAILED) { - rv = 0; - goto exit; - } - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", - buffer[0]); - rv = -EPERM; - goto exit; - } - - max_size = 0; - current_setting = data->intf->cur_altsetting; - for (n = 0; n < current_setting->desc.bNumEndpoints; n++) - if (current_setting->endpoint[n].desc.bEndpointAddress == - data->bulk_in) - max_size = usb_endpoint_maxp(¤t_setting->endpoint[n].desc); - - if (max_size == 0) { - dev_err(dev, "Couldn't get wMaxPacketSize\n"); - rv = -EPERM; - goto exit; - } - - dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size); - - n = 0; - - do { - dev_dbg(dev, "Reading from bulk in EP\n"); - - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); - - n++; - - if (rv < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", rv); - goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); - - if (actual == max_size) { - dev_err(dev, "Couldn't clear device buffer within %d cycles\n", - USBTMC_MAX_READS_TO_CLEAR_BULK_IN); - rv = -EPERM; - goto exit; - } - - n = 0; - -usbtmc_abort_bulk_in_status: - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - 0, data->bulk_in, buffer, 0x08, - USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_SUCCESS) { - rv = 0; - goto exit; - } - - if (buffer[0] != USBTMC_STATUS_PENDING) { - dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - - if (buffer[1] == 1) - do { - dev_dbg(dev, "Reading from bulk in EP\n"); - - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); - - n++; - - if (rv < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", rv); - goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); - - if (actual == max_size) { - dev_err(dev, "Couldn't clear device buffer within %d cycles\n", - USBTMC_MAX_READS_TO_CLEAR_BULK_IN); - rv = -EPERM; - goto exit; - } - - goto usbtmc_abort_bulk_in_status; - -exit: - kfree(buffer); - return rv; - -} - -static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) -{ - struct device *dev; - u8 *buffer; - int rv; - int n; - - dev = &data->intf->dev; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - data->bTag_last_write, data->bulk_out, - buffer, 2, USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]); - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", - buffer[0]); - rv = -EPERM; - goto exit; - } - - n = 0; - -usbtmc_abort_bulk_out_check_status: - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - 0, data->bulk_out, buffer, 0x08, - USBTMC_TIMEOUT); - n++; - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_SUCCESS) - goto usbtmc_abort_bulk_out_clear_halt; - - if ((buffer[0] == USBTMC_STATUS_PENDING) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)) - goto usbtmc_abort_bulk_out_check_status; - - rv = -EPERM; - goto exit; - -usbtmc_abort_bulk_out_clear_halt: - rv = usb_clear_halt(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, data->bulk_out)); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static ssize_t usbtmc_read(struct file *filp, char __user *buf, - size_t count, loff_t *f_pos) -{ - struct usbtmc_device_data *data; - struct device *dev; - u32 n_characters; - u8 *buffer; - int actual; - size_t done; - size_t remaining; - int retval; - size_t this_part; - - /* Get pointer to private data structure */ - data = filp->private_data; - dev = &data->intf->dev; - - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - mutex_lock(&data->io_mutex); - if (data->zombie) { - retval = -ENODEV; - goto exit; - } - - remaining = count; - done = 0; - - while (remaining > 0) { - if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3) - this_part = USBTMC_SIZE_IOBUFFER - 12 - 3; - else - this_part = remaining; - - /* Setup IO buffer for DEV_DEP_MSG_IN message - * Refer to class specs for details - */ - buffer[0] = 2; - buffer[1] = data->bTag; - buffer[2] = ~(data->bTag); - buffer[3] = 0; /* Reserved */ - buffer[4] = (this_part) & 255; - buffer[5] = ((this_part) >> 8) & 255; - buffer[6] = ((this_part) >> 16) & 255; - buffer[7] = ((this_part) >> 24) & 255; - buffer[8] = data->TermCharEnabled * 2; - /* Use term character? */ - buffer[9] = data->TermChar; - buffer[10] = 0; /* Reserved */ - buffer[11] = 0; /* Reserved */ - - /* Send bulk URB */ - retval = usb_bulk_msg(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, - data->bulk_out), - buffer, 12, &actual, USBTMC_TIMEOUT); - - /* Store bTag (in case we need to abort) */ - data->bTag_last_write = data->bTag; - - /* Increment bTag -- and increment again if zero */ - data->bTag++; - if (!data->bTag) - (data->bTag)++; - - if (retval < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", retval); - if (data->auto_abort) - usbtmc_ioctl_abort_bulk_out(data); - goto exit; - } - - /* Send bulk URB */ - retval = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, &actual, - USBTMC_TIMEOUT); - - /* Store bTag (in case we need to abort) */ - data->bTag_last_read = data->bTag; - - if (retval < 0) { - dev_err(dev, "Unable to read data, error %d\n", retval); - if (data->auto_abort) - usbtmc_ioctl_abort_bulk_in(data); - goto exit; - } - - /* How many characters did the instrument send? */ - n_characters = buffer[4] + - (buffer[5] << 8) + - (buffer[6] << 16) + - (buffer[7] << 24); - - /* Ensure the instrument doesn't lie about it */ - if(n_characters > actual - 12) { - dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12); - n_characters = actual - 12; - } - - /* Ensure the instrument doesn't send more back than requested */ - if(n_characters > this_part) { - dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part); - n_characters = this_part; - } - - /* Bound amount of data received by amount of data requested */ - if (n_characters > this_part) - n_characters = this_part; - - /* Copy buffer to user space */ - if (copy_to_user(buf + done, &buffer[12], n_characters)) { - /* There must have been an addressing problem */ - retval = -EFAULT; - goto exit; - } - - done += n_characters; - /* Terminate if end-of-message bit received from device */ - if ((buffer[8] & 0x01) && (actual >= n_characters + 12)) - remaining = 0; - else - remaining -= n_characters; - } - - /* Update file position value */ - *f_pos = *f_pos + done; - retval = done; - -exit: - mutex_unlock(&data->io_mutex); - kfree(buffer); - return retval; -} - -static ssize_t usbtmc_write(struct file *filp, const char __user *buf, - size_t count, loff_t *f_pos) -{ - struct usbtmc_device_data *data; - u8 *buffer; - int retval; - int actual; - unsigned long int n_bytes; - int remaining; - int done; - int this_part; - - data = filp->private_data; - - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - mutex_lock(&data->io_mutex); - if (data->zombie) { - retval = -ENODEV; - goto exit; - } - - remaining = count; - done = 0; - - while (remaining > 0) { - if (remaining > USBTMC_SIZE_IOBUFFER - 12) { - this_part = USBTMC_SIZE_IOBUFFER - 12; - buffer[8] = 0; - } else { - this_part = remaining; - buffer[8] = 1; - } - - /* Setup IO buffer for DEV_DEP_MSG_OUT message */ - buffer[0] = 1; - buffer[1] = data->bTag; - buffer[2] = ~(data->bTag); - buffer[3] = 0; /* Reserved */ - buffer[4] = this_part & 255; - buffer[5] = (this_part >> 8) & 255; - buffer[6] = (this_part >> 16) & 255; - buffer[7] = (this_part >> 24) & 255; - /* buffer[8] is set above... */ - buffer[9] = 0; /* Reserved */ - buffer[10] = 0; /* Reserved */ - buffer[11] = 0; /* Reserved */ - - if (copy_from_user(&buffer[12], buf + done, this_part)) { - retval = -EFAULT; - goto exit; - } - - n_bytes = roundup(12 + this_part, 4); - memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part)); - - do { - retval = usb_bulk_msg(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, - data->bulk_out), - buffer, n_bytes, - &actual, USBTMC_TIMEOUT); - if (retval != 0) - break; - n_bytes -= actual; - } while (n_bytes); - - data->bTag_last_write = data->bTag; - data->bTag++; - - if (!data->bTag) - data->bTag++; - - if (retval < 0) { - dev_err(&data->intf->dev, - "Unable to send data, error %d\n", retval); - if (data->auto_abort) - usbtmc_ioctl_abort_bulk_out(data); - goto exit; - } - - remaining -= this_part; - done += this_part; - } - - retval = count; -exit: - mutex_unlock(&data->io_mutex); - kfree(buffer); - return retval; -} - -static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) -{ - struct usb_host_interface *current_setting; - struct usb_endpoint_descriptor *desc; - struct device *dev; - u8 *buffer; - int rv; - int n; - int actual; - int max_size; - - dev = &data->intf->dev; - - dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); - - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INITIATE_CLEAR, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 1, USBTMC_TIMEOUT); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - - max_size = 0; - current_setting = data->intf->cur_altsetting; - for (n = 0; n < current_setting->desc.bNumEndpoints; n++) { - desc = ¤t_setting->endpoint[n].desc; - if (desc->bEndpointAddress == data->bulk_in) - max_size = usb_endpoint_maxp(desc); - } - - if (max_size == 0) { - dev_err(dev, "Couldn't get wMaxPacketSize\n"); - rv = -EPERM; - goto exit; - } - - dev_dbg(dev, "wMaxPacketSize is %d\n", max_size); - - n = 0; - -usbtmc_clear_check_status: - - dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n"); - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_CHECK_CLEAR_STATUS, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 2, USBTMC_TIMEOUT); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_SUCCESS) - goto usbtmc_clear_bulk_out_halt; - - if (buffer[0] != USBTMC_STATUS_PENDING) { - dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - - if (buffer[1] == 1) - do { - dev_dbg(dev, "Reading from bulk in EP\n"); - - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); - n++; - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", - rv); - goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); - - if (actual == max_size) { - dev_err(dev, "Couldn't clear device buffer within %d cycles\n", - USBTMC_MAX_READS_TO_CLEAR_BULK_IN); - rv = -EPERM; - goto exit; - } - - goto usbtmc_clear_check_status; - -usbtmc_clear_bulk_out_halt: - - rv = usb_clear_halt(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, data->bulk_out)); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) -{ - u8 *buffer; - int rv; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_clear_halt(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, data->bulk_out)); - - if (rv < 0) { - dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", - rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) -{ - u8 *buffer; - int rv; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_clear_halt(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); - - if (rv < 0) { - dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", - rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static int get_capabilities(struct usbtmc_device_data *data) -{ - struct device *dev = &data->usb_dev->dev; - char *buffer; - int rv = 0; - - buffer = kmalloc(0x18, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_GET_CAPABILITIES, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 0x18, USBTMC_TIMEOUT); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto err_out; - } - - dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); - rv = -EPERM; - goto err_out; - } - dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); - dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); - dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); - dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); - - data->capabilities.interface_capabilities = buffer[4]; - data->capabilities.device_capabilities = buffer[5]; - data->capabilities.usb488_interface_capabilities = buffer[14]; - data->capabilities.usb488_device_capabilities = buffer[15]; - rv = 0; - -err_out: - kfree(buffer); - return rv; -} - -#define capability_attribute(name) \ -static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - \ - return sprintf(buf, "%d\n", data->capabilities.name); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) - -capability_attribute(interface_capabilities); -capability_attribute(device_capabilities); -capability_attribute(usb488_interface_capabilities); -capability_attribute(usb488_device_capabilities); - -static struct attribute *capability_attrs[] = { - &dev_attr_interface_capabilities.attr, - &dev_attr_device_capabilities.attr, - &dev_attr_usb488_interface_capabilities.attr, - &dev_attr_usb488_device_capabilities.attr, - NULL, -}; - -static struct attribute_group capability_attr_grp = { - .attrs = capability_attrs, -}; - -static ssize_t show_TermChar(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbtmc_device_data *data = usb_get_intfdata(intf); - - return sprintf(buf, "%c\n", data->TermChar); -} - -static ssize_t store_TermChar(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbtmc_device_data *data = usb_get_intfdata(intf); - - if (count < 1) - return -EINVAL; - data->TermChar = buf[0]; - return count; -} -static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar); - -#define data_attribute(name) \ -static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - \ - return sprintf(buf, "%d\n", data->name); \ -} \ -static ssize_t store_##name(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - ssize_t result; \ - unsigned val; \ - \ - result = sscanf(buf, "%u\n", &val); \ - if (result != 1) \ - result = -EINVAL; \ - data->name = val; \ - if (result < 0) \ - return result; \ - else \ - return count; \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name) - -data_attribute(TermCharEnabled); -data_attribute(auto_abort); - -static struct attribute *data_attrs[] = { - &dev_attr_TermChar.attr, - &dev_attr_TermCharEnabled.attr, - &dev_attr_auto_abort.attr, - NULL, -}; - -static struct attribute_group data_attr_grp = { - .attrs = data_attrs, -}; - -static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) -{ - struct device *dev; - u8 *buffer; - int rv; - - dev = &data->intf->dev; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INDICATOR_PULSE, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 0x01, USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usbtmc_device_data *data; - int retval = -EBADRQC; - - data = file->private_data; - mutex_lock(&data->io_mutex); - if (data->zombie) { - retval = -ENODEV; - goto skip_io_on_zombie; - } - - switch (cmd) { - case USBTMC_IOCTL_CLEAR_OUT_HALT: - retval = usbtmc_ioctl_clear_out_halt(data); - break; - - case USBTMC_IOCTL_CLEAR_IN_HALT: - retval = usbtmc_ioctl_clear_in_halt(data); - break; - - case USBTMC_IOCTL_INDICATOR_PULSE: - retval = usbtmc_ioctl_indicator_pulse(data); - break; - - case USBTMC_IOCTL_CLEAR: - retval = usbtmc_ioctl_clear(data); - break; - - case USBTMC_IOCTL_ABORT_BULK_OUT: - retval = usbtmc_ioctl_abort_bulk_out(data); - break; - - case USBTMC_IOCTL_ABORT_BULK_IN: - retval = usbtmc_ioctl_abort_bulk_in(data); - break; - } - -skip_io_on_zombie: - mutex_unlock(&data->io_mutex); - return retval; -} - -static const struct file_operations fops = { - .owner = THIS_MODULE, - .read = usbtmc_read, - .write = usbtmc_write, - .open = usbtmc_open, - .release = usbtmc_release, - .unlocked_ioctl = usbtmc_ioctl, - .llseek = default_llseek, -}; - -static struct usb_class_driver usbtmc_class = { - .name = "usbtmc%d", - .fops = &fops, - .minor_base = USBTMC_MINOR_BASE, -}; - - -static int usbtmc_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usbtmc_device_data *data; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int n; - int retcode; - - dev_dbg(&intf->dev, "%s called\n", __func__); - - data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL); - if (!data) { - dev_err(&intf->dev, "Unable to allocate kernel memory\n"); - return -ENOMEM; - } - - data->intf = intf; - data->id = id; - data->usb_dev = usb_get_dev(interface_to_usbdev(intf)); - usb_set_intfdata(intf, data); - kref_init(&data->kref); - mutex_init(&data->io_mutex); - data->zombie = 0; - - /* Initialize USBTMC bTag and other fields */ - data->bTag = 1; - data->TermCharEnabled = 0; - data->TermChar = '\n'; - - /* USBTMC devices have only one setting, so use that */ - iface_desc = data->intf->cur_altsetting; - - /* Find bulk in endpoint */ - for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { - endpoint = &iface_desc->endpoint[n].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - data->bulk_in = endpoint->bEndpointAddress; - dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", - data->bulk_in); - break; - } - } - - /* Find bulk out endpoint */ - for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { - endpoint = &iface_desc->endpoint[n].desc; - - if (usb_endpoint_is_bulk_out(endpoint)) { - data->bulk_out = endpoint->bEndpointAddress; - dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", - data->bulk_out); - break; - } - } - - retcode = get_capabilities(data); - if (retcode) - dev_err(&intf->dev, "can't read capabilities\n"); - else - retcode = sysfs_create_group(&intf->dev.kobj, - &capability_attr_grp); - - retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); - - retcode = usb_register_dev(intf, &usbtmc_class); - if (retcode) { - dev_err(&intf->dev, "Not able to get a minor" - " (base %u, slice default): %d\n", USBTMC_MINOR_BASE, - retcode); - goto error_register; - } - dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor); - - return 0; - -error_register: - sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); - sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); - kref_put(&data->kref, usbtmc_delete); - return retcode; -} - -static void usbtmc_disconnect(struct usb_interface *intf) -{ - struct usbtmc_device_data *data; - - dev_dbg(&intf->dev, "usbtmc_disconnect called\n"); - - data = usb_get_intfdata(intf); - usb_deregister_dev(intf, &usbtmc_class); - sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); - sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); - mutex_lock(&data->io_mutex); - data->zombie = 1; - mutex_unlock(&data->io_mutex); - kref_put(&data->kref, usbtmc_delete); -} - -static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) -{ - /* this driver does not have pending URBs */ - return 0; -} - -static int usbtmc_resume(struct usb_interface *intf) -{ - return 0; -} - -static struct usb_driver usbtmc_driver = { - .name = "usbtmc", - .id_table = usbtmc_devices, - .probe = usbtmc_probe, - .disconnect = usbtmc_disconnect, - .suspend = usbtmc_suspend, - .resume = usbtmc_resume, -}; - -module_usb_driver(usbtmc_driver); - -MODULE_LICENSE("GPL"); |