summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/usb/class
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/drivers/usb/class
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-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/Kconfig52
-rw-r--r--ANDROID_3.4.5/drivers/usb/class/Makefile9
-rw-r--r--ANDROID_3.4.5/drivers/usb/class/cdc-acm.c1752
-rw-r--r--ANDROID_3.4.5/drivers/usb/class/cdc-acm.h130
-rw-r--r--ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c1048
-rw-r--r--ANDROID_3.4.5/drivers/usb/class/usblp.c1421
-rw-r--r--ANDROID_3.4.5/drivers/usb/class/usbtmc.c1121
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(&current_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 = &current_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");