aboutsummaryrefslogtreecommitdiff
path: root/drivers/hid/usbhid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r--drivers/hid/usbhid/Kconfig10
-rw-r--r--drivers/hid/usbhid/Makefile6
-rw-r--r--drivers/hid/usbhid/hid-core.c935
-rw-r--r--drivers/hid/usbhid/hid-pidff.c244
-rw-r--r--drivers/hid/usbhid/hid-quirks.c72
-rw-r--r--drivers/hid/usbhid/hiddev.c380
-rw-r--r--drivers/hid/usbhid/usbhid.h14
-rw-r--r--drivers/hid/usbhid/usbkbd.c124
-rw-r--r--drivers/hid/usbhid/usbmouse.c30
9 files changed, 1173 insertions, 642 deletions
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 4edb3bef94a..0108c5991a0 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -1,13 +1,13 @@
-comment "USB Input Devices"
+menu "USB HID support"
depends on USB
config USB_HID
- tristate "USB Human Interface Device (full HID) support"
+ tristate "USB HID transport layer"
default y
depends on USB && INPUT
select HID
---help---
- Say Y here if you want full HID support to connect USB keyboards,
+ Say Y here if you want to connect USB keyboards,
mice, joysticks, graphic tablets, or any other HID based devices
to your computer via USB, as well as Uninterruptible Power Supply
(UPS) and monitor control devices.
@@ -45,7 +45,7 @@ config USB_HIDDEV
If unsure, say Y.
menu "USB HID Boot Protocol drivers"
- depends on USB!=n && USB_HID!=y && EMBEDDED
+ depends on USB!=n && USB_HID!=y && EXPERT
config USB_KBD
tristate "USB HIDBP Keyboard (simple Boot) support"
@@ -81,4 +81,4 @@ config USB_MOUSE
endmenu
-
+endmenu
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
index 1329ecb37a1..db3cf31c6fa 100644
--- a/drivers/hid/usbhid/Makefile
+++ b/drivers/hid/usbhid/Makefile
@@ -3,15 +3,15 @@
#
# Multipart objects.
-usbhid-objs := hid-core.o hid-quirks.o
+usbhid-y := hid-core.o hid-quirks.o
# Optional parts of multipart objects.
ifeq ($(CONFIG_USB_HIDDEV),y)
- usbhid-objs += hiddev.o
+ usbhid-y += hiddev.o
endif
ifeq ($(CONFIG_HID_PID),y)
- usbhid-objs += hid-pidff.o
+ usbhid-y += hid-pidff.o
endif
obj-$(CONFIG_USB_HID) += usbhid.o
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index f0a0f72238a..7b88f4cb990 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -4,7 +4,8 @@
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- * Copyright (c) 2006-2008 Jiri Kosina
+ * Copyright (c) 2007-2008 Oliver Neukum
+ * Copyright (c) 2006-2010 Jiri Kosina
*/
/*
@@ -21,12 +22,13 @@
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/mutex.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include <linux/input.h>
#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
#include <linux/usb.h>
@@ -40,8 +42,6 @@
* Version Information
*/
-#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
@@ -53,6 +53,10 @@ static unsigned int hid_mousepoll_interval;
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
+static unsigned int ignoreled;
+module_param_named(ignoreled, ignoreled, uint, 0644);
+MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
+
/* Quirks specified at module load time */
static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
module_param_array_named(quirks, quirks_param, charp, NULL, 0444);
@@ -63,8 +67,12 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
/*
* Input submission and I/O error handler.
*/
+static DEFINE_MUTEX(hid_open_mut);
static void hid_io_error(struct hid_device *hid);
+static int hid_submit_out(struct hid_device *hid);
+static int hid_submit_ctrl(struct hid_device *hid);
+static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid);
/* Start up the input URB */
static int hid_start_in(struct hid_device *hid)
@@ -73,15 +81,21 @@ static int hid_start_in(struct hid_device *hid)
int rc = 0;
struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irqsave(&usbhid->inlock, flags);
- if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+ spin_lock_irqsave(&usbhid->lock, flags);
+ if (hid->open > 0 &&
!test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
+ !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
- if (rc != 0)
+ if (rc != 0) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ if (rc == -ENOSPC)
+ set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+ } else {
+ clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+ }
}
- spin_unlock_irqrestore(&usbhid->inlock, flags);
+ spin_unlock_irqrestore(&usbhid->lock, flags);
return rc;
}
@@ -127,10 +141,10 @@ static void hid_reset(struct work_struct *work)
hid_io_error(hid);
break;
default:
- err_hid("can't reset device, %s-%s/input%d, status %d",
- hid_to_usb_dev(hid)->bus->bus_name,
- hid_to_usb_dev(hid)->devpath,
- usbhid->ifnum, rc);
+ hid_err(hid, "can't reset device, %s-%s/input%d, status %d\n",
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, rc);
/* FALLTHROUGH */
case -EHOSTUNREACH:
case -ENODEV:
@@ -145,7 +159,7 @@ static void hid_io_error(struct hid_device *hid)
unsigned long flags;
struct usbhid_device *usbhid = hid->driver_data;
- spin_lock_irqsave(&usbhid->inlock, flags);
+ spin_lock_irqsave(&usbhid->lock, flags);
/* Stop when disconnected */
if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
@@ -165,8 +179,10 @@ static void hid_io_error(struct hid_device *hid)
if (time_after(jiffies, usbhid->stop_retry)) {
- /* Retries failed, so do a port reset */
- if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+ /* Retries failed, so do a port reset unless we lack bandwidth*/
+ if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
+ && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+
schedule_work(&usbhid->reset_work);
goto done;
}
@@ -175,7 +191,91 @@ static void hid_io_error(struct hid_device *hid)
mod_timer(&usbhid->io_retry,
jiffies + msecs_to_jiffies(usbhid->retry_delay));
done:
- spin_unlock_irqrestore(&usbhid->inlock, flags);
+ spin_unlock_irqrestore(&usbhid->lock, flags);
+}
+
+static void usbhid_mark_busy(struct usbhid_device *usbhid)
+{
+ struct usb_interface *intf = usbhid->intf;
+
+ usb_mark_last_busy(interface_to_usbdev(intf));
+}
+
+static int usbhid_restart_out_queue(struct usbhid_device *usbhid)
+{
+ struct hid_device *hid = usb_get_intfdata(usbhid->intf);
+ int kicked;
+ int r;
+
+ if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) ||
+ test_bit(HID_SUSPENDED, &usbhid->iofl))
+ return 0;
+
+ if ((kicked = (usbhid->outhead != usbhid->outtail))) {
+ hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
+
+ /* Try to wake up from autosuspend... */
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return r;
+
+ /*
+ * If still suspended, don't submit. Submission will
+ * occur if/when resume drains the queue.
+ */
+ if (test_bit(HID_SUSPENDED, &usbhid->iofl)) {
+ usb_autopm_put_interface_no_suspend(usbhid->intf);
+ return r;
+ }
+
+ /* Asynchronously flush queue. */
+ set_bit(HID_OUT_RUNNING, &usbhid->iofl);
+ if (hid_submit_out(hid)) {
+ clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+ usb_autopm_put_interface_async(usbhid->intf);
+ }
+ wake_up(&usbhid->wait);
+ }
+ return kicked;
+}
+
+static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)
+{
+ struct hid_device *hid = usb_get_intfdata(usbhid->intf);
+ int kicked;
+ int r;
+
+ WARN_ON(hid == NULL);
+ if (!hid || test_bit(HID_RESET_PENDING, &usbhid->iofl) ||
+ test_bit(HID_SUSPENDED, &usbhid->iofl))
+ return 0;
+
+ if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
+ hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
+
+ /* Try to wake up from autosuspend... */
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return r;
+
+ /*
+ * If still suspended, don't submit. Submission will
+ * occur if/when resume drains the queue.
+ */
+ if (test_bit(HID_SUSPENDED, &usbhid->iofl)) {
+ usb_autopm_put_interface_no_suspend(usbhid->intf);
+ return r;
+ }
+
+ /* Asynchronously flush queue. */
+ set_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ if (hid_submit_ctrl(hid)) {
+ clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ usb_autopm_put_interface_async(usbhid->intf);
+ }
+ wake_up(&usbhid->wait);
+ }
+ return kicked;
}
/*
@@ -190,12 +290,23 @@ static void hid_irq_in(struct urb *urb)
switch (urb->status) {
case 0: /* success */
+ usbhid_mark_busy(usbhid);
usbhid->retry_delay = 0;
hid_input_report(urb->context, HID_INPUT_REPORT,
urb->transfer_buffer,
urb->actual_length, 1);
+ /*
+ * autosuspend refused while keys are pressed
+ * because most keyboards don't wake up when
+ * a key is released
+ */
+ if (hid_check_keys_pressed(hid))
+ set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
+ else
+ clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
break;
case -EPIPE: /* stall */
+ usbhid_mark_busy(usbhid);
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
set_bit(HID_CLEAR_HALT, &usbhid->iofl);
schedule_work(&usbhid->reset_work);
@@ -209,22 +320,23 @@ static void hid_irq_in(struct urb *urb)
case -EPROTO: /* protocol error or unplug */
case -ETIME: /* protocol error or unplug */
case -ETIMEDOUT: /* Should never happen, but... */
+ usbhid_mark_busy(usbhid);
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
hid_io_error(hid);
return;
default: /* error */
- dev_warn(&urb->dev->dev, "input irq status %d "
- "received\n", urb->status);
+ hid_warn(urb->dev, "input irq status %d received\n",
+ urb->status);
}
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
if (status != -EPERM) {
- err_hid("can't resubmit intr, %s-%s/input%d, status %d",
- hid_to_usb_dev(hid)->bus->bus_name,
- hid_to_usb_dev(hid)->devpath,
- usbhid->ifnum, status);
+ hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, status);
hid_io_error(hid);
}
}
@@ -235,22 +347,29 @@ static int hid_submit_out(struct hid_device *hid)
struct hid_report *report;
char *raw_report;
struct usbhid_device *usbhid = hid->driver_data;
+ int r;
report = usbhid->out[usbhid->outtail].report;
raw_report = usbhid->out[usbhid->outtail].raw_report;
- usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
+ usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) +
+ 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid);
- memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length);
- kfree(raw_report);
+ if (raw_report) {
+ memcpy(usbhid->outbuf, raw_report,
+ usbhid->urbout->transfer_buffer_length);
+ kfree(raw_report);
+ usbhid->out[usbhid->outtail].raw_report = NULL;
+ }
dbg_hid("submitting out urb\n");
- if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
- err_hid("usb_submit_urb(out) failed");
- return -1;
+ r = usb_submit_urb(usbhid->urbout, GFP_ATOMIC);
+ if (r < 0) {
+ hid_err(hid, "usb_submit_urb(out) failed: %d\n", r);
+ return r;
}
-
+ usbhid->last_out = jiffies;
return 0;
}
@@ -259,7 +378,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
struct hid_report *report;
unsigned char dir;
char *raw_report;
- int len;
+ int len, r;
struct usbhid_device *usbhid = hid->driver_data;
report = usbhid->ctrl[usbhid->ctrltail].report;
@@ -270,13 +389,17 @@ static int hid_submit_ctrl(struct hid_device *hid)
if (dir == USB_DIR_OUT) {
usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
usbhid->urbctrl->transfer_buffer_length = len;
- memcpy(usbhid->ctrlbuf, raw_report, len);
- kfree(raw_report);
+ if (raw_report) {
+ memcpy(usbhid->ctrlbuf, raw_report, len);
+ kfree(raw_report);
+ usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
+ }
} else {
int maxpacket, padlen;
usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
- maxpacket = usb_maxpacket(hid_to_usb_dev(hid), usbhid->urbctrl->pipe, 0);
+ maxpacket = usb_maxpacket(hid_to_usb_dev(hid),
+ usbhid->urbctrl->pipe, 0);
if (maxpacket > 0) {
padlen = DIV_ROUND_UP(len, maxpacket);
padlen *= maxpacket;
@@ -289,20 +412,24 @@ static int hid_submit_ctrl(struct hid_device *hid)
usbhid->urbctrl->dev = hid_to_usb_dev(hid);
usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
- usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT;
- usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
+ usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT :
+ HID_REQ_GET_REPORT;
+ usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) |
+ report->id);
usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum);
usbhid->cr->wLength = cpu_to_le16(len);
dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n",
- usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report",
+ usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" :
+ "Get_Report",
usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
- if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
- err_hid("usb_submit_urb(ctrl) failed");
- return -1;
+ r = usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC);
+ if (r < 0) {
+ hid_err(hid, "usb_submit_urb(ctrl) failed: %d\n", r);
+ return r;
}
-
+ usbhid->last_ctrl = jiffies;
return 0;
}
@@ -328,28 +455,28 @@ static void hid_irq_out(struct urb *urb)
case -ENOENT:
break;
default: /* error */
- dev_warn(&urb->dev->dev, "output irq status %d "
- "received\n", urb->status);
+ hid_warn(urb->dev, "output irq status %d received\n",
+ urb->status);
}
- spin_lock_irqsave(&usbhid->outlock, flags);
+ spin_lock_irqsave(&usbhid->lock, flags);
- if (unplug)
+ if (unplug) {
usbhid->outtail = usbhid->outhead;
- else
+ } else {
usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
- if (usbhid->outhead != usbhid->outtail) {
- if (hid_submit_out(hid)) {
- clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
- wake_up(&usbhid->wait);
+ if (usbhid->outhead != usbhid->outtail &&
+ hid_submit_out(hid) == 0) {
+ /* Successfully submitted next urb in queue */
+ spin_unlock_irqrestore(&usbhid->lock, flags);
+ return;
}
- spin_unlock_irqrestore(&usbhid->outlock, flags);
- return;
}
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
- spin_unlock_irqrestore(&usbhid->outlock, flags);
+ spin_unlock_irqrestore(&usbhid->lock, flags);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
@@ -361,12 +488,11 @@ static void hid_ctrl(struct urb *urb)
{
struct hid_device *hid = urb->context;
struct usbhid_device *usbhid = hid->driver_data;
- unsigned long flags;
- int unplug = 0;
+ int unplug = 0, status = urb->status;
- spin_lock_irqsave(&usbhid->ctrllock, flags);
+ spin_lock(&usbhid->lock);
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
hid_input_report(urb->context,
@@ -382,80 +508,95 @@ static void hid_ctrl(struct urb *urb)
case -EPIPE: /* report not available */
break;
default: /* error */
- dev_warn(&urb->dev->dev, "ctrl urb status %d "
- "received\n", urb->status);
+ hid_warn(urb->dev, "ctrl urb status %d received\n", status);
}
- if (unplug)
+ if (unplug) {
usbhid->ctrltail = usbhid->ctrlhead;
- else
+ } else {
usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
- if (usbhid->ctrlhead != usbhid->ctrltail) {
- if (hid_submit_ctrl(hid)) {
- clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
- wake_up(&usbhid->wait);
+ if (usbhid->ctrlhead != usbhid->ctrltail &&
+ hid_submit_ctrl(hid) == 0) {
+ /* Successfully submitted next urb in queue */
+ spin_unlock(&usbhid->lock);
+ return;
}
- spin_unlock_irqrestore(&usbhid->ctrllock, flags);
- return;
}
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
- spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+ spin_unlock(&usbhid->lock);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *report,
+ unsigned char dir)
{
int head;
- unsigned long flags;
struct usbhid_device *usbhid = hid->driver_data;
- int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
return;
if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
-
- spin_lock_irqsave(&usbhid->outlock, flags);
-
if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
- spin_unlock_irqrestore(&usbhid->outlock, flags);
- dev_warn(&hid->dev, "output queue full\n");
+ hid_warn(hid, "output queue full\n");
return;
}
- usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
+ usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!usbhid->out[usbhid->outhead].raw_report) {
- spin_unlock_irqrestore(&usbhid->outlock, flags);
- dev_warn(&hid->dev, "output queueing failed\n");
+ hid_warn(hid, "output queueing failed\n");
return;
}
hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
usbhid->out[usbhid->outhead].report = report;
usbhid->outhead = head;
- if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
- if (hid_submit_out(hid))
- clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+ /* If the queue isn't running, restart it */
+ if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl)) {
+ usbhid_restart_out_queue(usbhid);
+
+ /* Otherwise see if an earlier request has timed out */
+ } else if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
+
+ /* Prevent autosuspend following the unlink */
+ usb_autopm_get_interface_no_resume(usbhid->intf);
+
+ /*
+ * Prevent resubmission in case the URB completes
+ * before we can unlink it. We don't want to cancel
+ * the wrong transfer!
+ */
+ usb_block_urb(usbhid->urbout);
- spin_unlock_irqrestore(&usbhid->outlock, flags);
+ /* Drop lock to avoid deadlock if the callback runs */
+ spin_unlock(&usbhid->lock);
+
+ usb_unlink_urb(usbhid->urbout);
+ spin_lock(&usbhid->lock);
+ usb_unblock_urb(usbhid->urbout);
+
+ /* Unlink might have stopped the queue */
+ if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+ usbhid_restart_out_queue(usbhid);
+
+ /* Now we can allow autosuspend again */
+ usb_autopm_put_interface_async(usbhid->intf);
+ }
return;
}
- spin_lock_irqsave(&usbhid->ctrllock, flags);
-
if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
- spin_unlock_irqrestore(&usbhid->ctrllock, flags);
- dev_warn(&hid->dev, "control queue full\n");
+ hid_warn(hid, "control queue full\n");
return;
}
if (dir == USB_DIR_OUT) {
- usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
+ usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
- spin_unlock_irqrestore(&usbhid->ctrllock, flags);
- dev_warn(&hid->dev, "control queueing failed\n");
+ hid_warn(hid, "control queueing failed\n");
return;
}
hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
@@ -464,38 +605,50 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
usbhid->ctrl[usbhid->ctrlhead].dir = dir;
usbhid->ctrlhead = head;
- if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
- if (hid_submit_ctrl(hid))
- clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ /* If the queue isn't running, restart it */
+ if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) {
+ usbhid_restart_ctrl_queue(usbhid);
- spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-}
-EXPORT_SYMBOL_GPL(usbhid_submit_report);
+ /* Otherwise see if an earlier request has timed out */
+ } else if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
-static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- struct hid_device *hid = input_get_drvdata(dev);
- struct hid_field *field;
- int offset;
+ /* Prevent autosuspend following the unlink */
+ usb_autopm_get_interface_no_resume(usbhid->intf);
- if (type == EV_FF)
- return input_ff_event(dev, type, code, value);
+ /*
+ * Prevent resubmission in case the URB completes
+ * before we can unlink it. We don't want to cancel
+ * the wrong transfer!
+ */
+ usb_block_urb(usbhid->urbctrl);
- if (type != EV_LED)
- return -1;
+ /* Drop lock to avoid deadlock if the callback runs */
+ spin_unlock(&usbhid->lock);
- if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
- dev_warn(&dev->dev, "event field not found\n");
- return -1;
+ usb_unlink_urb(usbhid->urbctrl);
+ spin_lock(&usbhid->lock);
+ usb_unblock_urb(usbhid->urbctrl);
+
+ /* Unlink might have stopped the queue */
+ if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+ usbhid_restart_ctrl_queue(usbhid);
+
+ /* Now we can allow autosuspend again */
+ usb_autopm_put_interface_async(usbhid->intf);
}
+}
- hid_set_field(field, offset, value);
- usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+static void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ unsigned long flags;
- return 0;
+ spin_lock_irqsave(&usbhid->lock, flags);
+ __usbhid_submit_report(hid, report, dir);
+ spin_unlock_irqrestore(&usbhid->lock, flags);
}
-int usbhid_wait_io(struct hid_device *hid)
+static int usbhid_wait_io(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@@ -536,28 +689,57 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
int usbhid_open(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- int res;
+ int res = 0;
+ mutex_lock(&hid_open_mut);
if (!hid->open++) {
res = usb_autopm_get_interface(usbhid->intf);
+ /* the device must be awake to reliably request remote wakeup */
if (res < 0) {
hid->open--;
- return -EIO;
+ res = -EIO;
+ goto done;
+ }
+ usbhid->intf->needs_remote_wakeup = 1;
+ res = hid_start_in(hid);
+ if (res) {
+ if (res != -ENOSPC) {
+ hid_io_error(hid);
+ res = 0;
+ } else {
+ /* no use opening if resources are insufficient */
+ hid->open--;
+ res = -EBUSY;
+ usbhid->intf->needs_remote_wakeup = 0;
+ }
}
+ usb_autopm_put_interface(usbhid->intf);
}
- if (hid_start_in(hid))
- hid_io_error(hid);
- return 0;
+done:
+ mutex_unlock(&hid_open_mut);
+ return res;
}
void usbhid_close(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
+ mutex_lock(&hid_open_mut);
+
+ /* protecting hid->open to make sure we don't restart
+ * data acquistion due to a resumption we no longer
+ * care about
+ */
+ spin_lock_irq(&usbhid->lock);
if (!--hid->open) {
+ spin_unlock_irq(&usbhid->lock);
+ hid_cancel_delayed_stuff(usbhid);
usb_kill_urb(usbhid->urbin);
- usb_autopm_put_interface(usbhid->intf);
+ usbhid->intf->needs_remote_wakeup = 0;
+ } else {
+ spin_unlock_irq(&usbhid->lock);
}
+ mutex_unlock(&hid_open_mut);
}
/*
@@ -568,12 +750,17 @@ void usbhid_init_reports(struct hid_device *hid)
{
struct hid_report *report;
struct usbhid_device *usbhid = hid->driver_data;
+ struct hid_report_enum *report_enum;
int err, ret;
- list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
- usbhid_submit_report(hid, report, USB_DIR_IN);
+ if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
+ report_enum = &hid->report_enum[HID_INPUT_REPORT];
+ list_for_each_entry(report, &report_enum->report_list, list)
+ usbhid_submit_report(hid, report, USB_DIR_IN);
+ }
- list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
+ report_enum = &hid->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(report, &report_enum->report_list, list)
usbhid_submit_report(hid, report, USB_DIR_IN);
err = 0;
@@ -588,7 +775,7 @@ void usbhid_init_reports(struct hid_device *hid)
}
if (err)
- dev_warn(&hid->dev, "timeout initializing reports\n");
+ hid_warn(hid, "timeout initializing reports\n");
}
/*
@@ -618,7 +805,7 @@ static int hid_find_field_early(struct hid_device *hid, unsigned int page,
return -1;
}
-void usbhid_set_leds(struct hid_device *hid)
+static void usbhid_set_leds(struct hid_device *hid)
{
struct hid_field *field;
int offset;
@@ -628,7 +815,6 @@ void usbhid_set_leds(struct hid_device *hid)
usbhid_submit_report(hid, field->report, USB_DIR_OUT);
}
}
-EXPORT_SYMBOL_GPL(usbhid_set_leds);
/*
* Traverse the supplied list of reports and find the longest
@@ -650,13 +836,12 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+ usbhid->inbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
&usbhid->inbuf_dma);
- usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+ usbhid->outbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
&usbhid->outbuf_dma);
- usbhid->cr = usb_buffer_alloc(dev, sizeof(*usbhid->cr), GFP_KERNEL,
- &usbhid->cr_dma);
- usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+ usbhid->cr = kmalloc(sizeof(*usbhid->cr), GFP_KERNEL);
+ usbhid->ctrlbuf = usb_alloc_coherent(dev, usbhid->bufsize, GFP_KERNEL,
&usbhid->ctrlbuf_dma);
if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr ||
!usbhid->ctrlbuf)
@@ -665,36 +850,122 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
return 0;
}
-static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
+static int usbhid_get_raw_report(struct hid_device *hid,
+ unsigned char report_number, __u8 *buf, size_t count,
+ unsigned char report_type)
{
struct usbhid_device *usbhid = hid->driver_data;
struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = usbhid->intf;
struct usb_host_interface *interface = intf->cur_altsetting;
+ int skipped_report_id = 0;
int ret;
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- HID_REQ_SET_REPORT,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ((HID_OUTPUT_REPORT + 1) << 8) | *buf,
- interface->desc.bInterfaceNumber, buf + 1, count - 1,
+ /* Byte 0 is the report number. Report data starts at byte 1.*/
+ buf[0] = report_number;
+ if (report_number == 0x0) {
+ /* Offset the return buffer by 1, so that the report ID
+ will remain in byte 0. */
+ buf++;
+ count--;
+ skipped_report_id = 1;
+ }
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ((report_type + 1) << 8) | report_number,
+ interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT);
/* count also the report id */
- if (ret > 0)
+ if (ret > 0 && skipped_report_id)
ret++;
return ret;
}
+static int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
+ __u8 *buf, size_t count, unsigned char rtype)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usb_interface *intf = usbhid->intf;
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int ret, skipped_report_id = 0;
+
+ /* Byte 0 is the report number. Report data starts at byte 1.*/
+ if ((rtype == HID_OUTPUT_REPORT) &&
+ (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORT_ID))
+ buf[0] = 0;
+ else
+ buf[0] = reportnum;
+
+ if (buf[0] == 0x0) {
+ /* Don't send the Report ID */
+ buf++;
+ count--;
+ skipped_report_id = 1;
+ }
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ HID_REQ_SET_REPORT,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ((rtype + 1) << 8) | reportnum,
+ interface->desc.bInterfaceNumber, buf, count,
+ USB_CTRL_SET_TIMEOUT);
+ /* count also the report id, if this was a numbered report. */
+ if (ret > 0 && skipped_report_id)
+ ret++;
+
+ return ret;
+}
+
+static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ int actual_length, skipped_report_id = 0, ret;
+
+ if (!usbhid->urbout)
+ return -ENOSYS;
+
+ if (buf[0] == 0x0) {
+ /* Don't send the Report ID */
+ buf++;
+ count--;
+ skipped_report_id = 1;
+ }
+
+ ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
+ buf, count, &actual_length,
+ USB_CTRL_SET_TIMEOUT);
+ /* return the number of bytes transferred */
+ if (ret == 0) {
+ ret = actual_length;
+ /* count also the report id */
+ if (skipped_report_id)
+ ret++;
+ }
+
+ return ret;
+}
+
+static void usbhid_restart_queues(struct usbhid_device *usbhid)
+{
+ if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+ usbhid_restart_out_queue(usbhid);
+ if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+ usbhid_restart_ctrl_queue(usbhid);
+}
+
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
- usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
- usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
- usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+ usb_free_coherent(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+ usb_free_coherent(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+ kfree(usbhid->cr);
+ usb_free_coherent(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}
static int usbhid_parse(struct hid_device *hid)
@@ -711,6 +982,9 @@ static int usbhid_parse(struct hid_device *hid)
quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
+ if (quirks & HID_QUIRK_IGNORE)
+ return -ENODEV;
+
/* Many keyboards and mice don't like to be polled for reports,
* so we will always set the HID_QUIRK_NOGET flag for them. */
if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) {
@@ -753,11 +1027,6 @@ static int usbhid_parse(struct hid_device *hid)
goto err;
}
- dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
- for (n = 0; n < rsize; n++)
- dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
- dbg_hid_line("\n");
-
ret = hid_parse_report(hid, rdesc, rsize);
kfree(rdesc);
if (ret) {
@@ -765,7 +1034,7 @@ static int usbhid_parse(struct hid_device *hid)
goto err;
}
- hid->quirks = quirks;
+ hid->quirks |= quirks;
return 0;
err:
@@ -848,17 +1117,6 @@ static int usbhid_start(struct hid_device *hid)
}
}
- init_waitqueue_head(&usbhid->wait);
- INIT_WORK(&usbhid->reset_work, hid_reset);
- setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
-
- spin_lock_init(&usbhid->inlock);
- spin_lock_init(&usbhid->outlock);
- spin_lock_init(&usbhid->ctrllock);
-
- usbhid->intf = intf;
- usbhid->ifnum = interface->desc.bInterfaceNumber;
-
usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
if (!usbhid->urbctrl) {
ret = -ENOMEM;
@@ -867,24 +1125,26 @@ static int usbhid_start(struct hid_device *hid)
usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
usbhid->ctrlbuf, 1, hid_ctrl, hid);
- usbhid->urbctrl->setup_dma = usbhid->cr_dma;
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
- usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+ usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- usbhid_init_reports(hid);
- hid_dump_device(hid);
+ if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
+ usbhid_init_reports(hid);
set_bit(HID_STARTED, &usbhid->iofl);
/* Some keyboards don't work until their LEDs have been set.
* Since BIOSes do set the LEDs, it must be safe for any device
* that supports the keyboard boot protocol.
+ * In addition, enable remote wakeup by default for all keyboard
+ * devices supporting the boot protocol.
*/
if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
interface->desc.bInterfaceProtocol ==
- USB_INTERFACE_PROTOCOL_KEYBOARD)
+ USB_INTERFACE_PROTOCOL_KEYBOARD) {
usbhid_set_leds(hid);
-
+ device_set_wakeup_enable(&dev->dev, 1);
+ }
return 0;
fail:
@@ -906,22 +1166,14 @@ static void usbhid_stop(struct hid_device *hid)
return;
clear_bit(HID_STARTED, &usbhid->iofl);
- spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
+ spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */
set_bit(HID_DISCONNECTED, &usbhid->iofl);
- spin_unlock_irq(&usbhid->inlock);
+ spin_unlock_irq(&usbhid->lock);
usb_kill_urb(usbhid->urbin);
usb_kill_urb(usbhid->urbout);
usb_kill_urb(usbhid->urbctrl);
- del_timer_sync(&usbhid->io_retry);
- cancel_work_sync(&usbhid->reset_work);
-
- if (hid->claimed & HID_CLAIMED_INPUT)
- hidinput_disconnect(hid);
- if (hid->claimed & HID_CLAIMED_HIDDEV)
- hiddev_disconnect(hid);
- if (hid->claimed & HID_CLAIMED_HIDRAW)
- hidraw_disconnect(hid);
+ hid_cancel_delayed_stuff(usbhid);
hid->claimed = 0;
@@ -935,16 +1187,76 @@ static void usbhid_stop(struct hid_device *hid)
hid_free_buffers(hid_to_usb_dev(hid), hid);
}
+static int usbhid_power(struct hid_device *hid, int lvl)
+{
+ int r = 0;
+
+ switch (lvl) {
+ case PM_HINT_FULLON:
+ r = usbhid_get_power(hid);
+ break;
+ case PM_HINT_NORMAL:
+ usbhid_put_power(hid);
+ break;
+ }
+ return r;
+}
+
+static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ usbhid_submit_report(hid, rep, USB_DIR_IN);
+ break;
+ case HID_REQ_SET_REPORT:
+ usbhid_submit_report(hid, rep, USB_DIR_OUT);
+ break;
+ }
+}
+
+static int usbhid_raw_request(struct hid_device *hid, unsigned char reportnum,
+ __u8 *buf, size_t len, unsigned char rtype,
+ int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ return usbhid_get_raw_report(hid, reportnum, buf, len, rtype);
+ case HID_REQ_SET_REPORT:
+ return usbhid_set_raw_report(hid, reportnum, buf, len, rtype);
+ default:
+ return -EIO;
+ }
+}
+
+static int usbhid_idle(struct hid_device *hid, int report, int idle,
+ int reqtype)
+{
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usb_interface *intf = to_usb_interface(hid->dev.parent);
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int ifnum = interface->desc.bInterfaceNumber;
+
+ if (reqtype != HID_REQ_SET_IDLE)
+ return -EINVAL;
+
+ return hid_set_idle(dev, ifnum, report, idle);
+}
+
static struct hid_ll_driver usb_hid_driver = {
.parse = usbhid_parse,
.start = usbhid_start,
.stop = usbhid_stop,
.open = usbhid_open,
.close = usbhid_close,
- .hidinput_input_event = usb_hidinput_input_event,
+ .power = usbhid_power,
+ .request = usbhid_request,
+ .wait = usbhid_wait_io,
+ .raw_request = usbhid_raw_request,
+ .output_report = usbhid_output_report,
+ .idle = usbhid_idle,
};
-static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_device *dev = interface_to_usbdev(intf);
@@ -961,8 +1273,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
has_in++;
if (!has_in) {
- dev_err(&intf->dev, "couldn't find an input interrupt "
- "endpoint\n");
+ hid_err(intf, "couldn't find an input interrupt endpoint\n");
return -ENODEV;
}
@@ -972,10 +1283,10 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver;
- hid->hid_output_raw_report = usbhid_output_raw_report;
hid->ff_init = hid_pidff_init;
#ifdef CONFIG_USB_HIDDEV
hid->hiddev_connect = hiddev_connect;
+ hid->hiddev_disconnect = hiddev_disconnect;
hid->hiddev_hid_event = hiddev_hid_event;
hid->hiddev_report_event = hiddev_report_event;
#endif
@@ -984,9 +1295,12 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
hid->product = le16_to_cpu(dev->descriptor.idProduct);
hid->name[0] = 0;
+ hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product);
if (intf->cur_altsetting->desc.bInterfaceProtocol ==
USB_INTERFACE_PROTOCOL_MOUSE)
hid->type = HID_TYPE_USBMOUSE;
+ else if (intf->cur_altsetting->desc.bInterfaceProtocol == 0)
+ hid->type = HID_TYPE_USBNONE;
if (dev->manufacturer)
strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
@@ -1020,11 +1334,18 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
hid->driver_data = usbhid;
usbhid->hid = hid;
+ usbhid->intf = intf;
+ usbhid->ifnum = interface->desc.bInterfaceNumber;
+
+ init_waitqueue_head(&usbhid->wait);
+ INIT_WORK(&usbhid->reset_work, hid_reset);
+ setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
+ spin_lock_init(&usbhid->lock);
ret = hid_add_device(hid);
if (ret) {
if (ret != -ENODEV)
- dev_err(&intf->dev, "can't add hid device: %d\n", ret);
+ hid_err(intf, "can't add hid device: %d\n", ret);
goto err_free;
}
@@ -1036,7 +1357,7 @@ err:
return ret;
}
-static void hid_disconnect(struct usb_interface *intf)
+static void usbhid_disconnect(struct usb_interface *intf)
{
struct hid_device *hid = usb_get_intfdata(intf);
struct usbhid_device *usbhid;
@@ -1049,59 +1370,216 @@ static void hid_disconnect(struct usb_interface *intf)
kfree(usbhid);
}
-static int hid_suspend(struct usb_interface *intf, pm_message_t message)
+static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
{
- struct hid_device *hid = usb_get_intfdata (intf);
- struct usbhid_device *usbhid = hid->driver_data;
-
- if (!test_bit(HID_STARTED, &usbhid->iofl))
- return 0;
+ del_timer_sync(&usbhid->io_retry);
+ cancel_work_sync(&usbhid->reset_work);
+}
- spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
- set_bit(HID_SUSPENDED, &usbhid->iofl);
- spin_unlock_irq(&usbhid->inlock);
+static void hid_cease_io(struct usbhid_device *usbhid)
+{
del_timer_sync(&usbhid->io_retry);
usb_kill_urb(usbhid->urbin);
- dev_dbg(&intf->dev, "suspend\n");
+ usb_kill_urb(usbhid->urbctrl);
+ usb_kill_urb(usbhid->urbout);
+}
+
+/* Treat USB reset pretty much the same as suspend/resume */
+static int hid_pre_reset(struct usb_interface *intf)
+{
+ struct hid_device *hid = usb_get_intfdata(intf);
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ spin_lock_irq(&usbhid->lock);
+ set_bit(HID_RESET_PENDING, &usbhid->iofl);
+ spin_unlock_irq(&usbhid->lock);
+ hid_cease_io(usbhid);
+
return 0;
}
-static int hid_resume(struct usb_interface *intf)
+/* Same routine used for post_reset and reset_resume */
+static int hid_post_reset(struct usb_interface *intf)
{
- struct hid_device *hid = usb_get_intfdata (intf);
+ struct usb_device *dev = interface_to_usbdev (intf);
+ struct hid_device *hid = usb_get_intfdata(intf);
struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_host_interface *interface = intf->cur_altsetting;
int status;
+ char *rdesc;
- if (!test_bit(HID_STARTED, &usbhid->iofl))
- return 0;
+ /* Fetch and examine the HID report descriptor. If this
+ * has changed, then rebind. Since usbcore's check of the
+ * configuration descriptors passed, we already know that
+ * the size of the HID report descriptor has not changed.
+ */
+ rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
+ if (!rdesc) {
+ dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
+ return 1;
+ }
+ status = hid_get_class_descriptor(dev,
+ interface->desc.bInterfaceNumber,
+ HID_DT_REPORT, rdesc, hid->dev_rsize);
+ if (status < 0) {
+ dbg_hid("reading report descriptor failed (post_reset)\n");
+ kfree(rdesc);
+ return 1;
+ }
+ status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize);
+ kfree(rdesc);
+ if (status != 0) {
+ dbg_hid("report descriptor changed\n");
+ return 1;
+ }
+ spin_lock_irq(&usbhid->lock);
+ clear_bit(HID_RESET_PENDING, &usbhid->iofl);
+ spin_unlock_irq(&usbhid->lock);
+ hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
+ status = hid_start_in(hid);
+ if (status < 0)
+ hid_io_error(hid);
+ usbhid_restart_queues(usbhid);
+
+ return 0;
+}
+
+int usbhid_get_power(struct hid_device *hid)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ return usb_autopm_get_interface(usbhid->intf);
+}
+
+void usbhid_put_power(struct hid_device *hid)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ usb_autopm_put_interface(usbhid->intf);
+}
+
+
+#ifdef CONFIG_PM
+static int hid_resume_common(struct hid_device *hid, bool driver_suspended)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ int status;
+
+ spin_lock_irq(&usbhid->lock);
clear_bit(HID_SUSPENDED, &usbhid->iofl);
+ usbhid_mark_busy(usbhid);
+
+ if (test_bit(HID_CLEAR_HALT, &usbhid->iofl) ||
+ test_bit(HID_RESET_PENDING, &usbhid->iofl))
+ schedule_work(&usbhid->reset_work);
usbhid->retry_delay = 0;
+
+ usbhid_restart_queues(usbhid);
+ spin_unlock_irq(&usbhid->lock);
+
status = hid_start_in(hid);
- dev_dbg(&intf->dev, "resume status %d\n", status);
+ if (status < 0)
+ hid_io_error(hid);
+
+ if (driver_suspended && hid->driver && hid->driver->resume)
+ status = hid->driver->resume(hid);
return status;
}
-/* Treat USB reset pretty much the same as suspend/resume */
-static int hid_pre_reset(struct usb_interface *intf)
+static int hid_suspend(struct usb_interface *intf, pm_message_t message)
{
- /* FIXME: What if the interface is already suspended? */
- hid_suspend(intf, PMSG_ON);
- return 0;
+ struct hid_device *hid = usb_get_intfdata(intf);
+ struct usbhid_device *usbhid = hid->driver_data;
+ int status = 0;
+ bool driver_suspended = false;
+ unsigned int ledcount;
+
+ if (PMSG_IS_AUTO(message)) {
+ ledcount = hidinput_count_leds(hid);
+ spin_lock_irq(&usbhid->lock); /* Sync with error handler */
+ if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
+ && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
+ && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
+ && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
+ && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
+ && (!ledcount || ignoreled))
+ {
+ set_bit(HID_SUSPENDED, &usbhid->iofl);
+ spin_unlock_irq(&usbhid->lock);
+ if (hid->driver && hid->driver->suspend) {
+ status = hid->driver->suspend(hid, message);
+ if (status < 0)
+ goto failed;
+ }
+ driver_suspended = true;
+ } else {
+ usbhid_mark_busy(usbhid);
+ spin_unlock_irq(&usbhid->lock);
+ return -EBUSY;
+ }
+
+ } else {
+ /* TODO: resume() might need to handle suspend failure */
+ if (hid->driver && hid->driver->suspend)
+ status = hid->driver->suspend(hid, message);
+ driver_suspended = true;
+ spin_lock_irq(&usbhid->lock);
+ set_bit(HID_SUSPENDED, &usbhid->iofl);
+ spin_unlock_irq(&usbhid->lock);
+ if (usbhid_wait_io(hid) < 0)
+ status = -EIO;
+ }
+
+ hid_cancel_delayed_stuff(usbhid);
+ hid_cease_io(usbhid);
+
+ if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
+ /* lost race against keypresses */
+ status = -EBUSY;
+ goto failed;
+ }
+ dev_dbg(&intf->dev, "suspend\n");
+ return status;
+
+ failed:
+ hid_resume_common(hid, driver_suspended);
+ return status;
}
-/* Same routine used for post_reset and reset_resume */
-static int hid_post_reset(struct usb_interface *intf)
+static int hid_resume(struct usb_interface *intf)
{
- struct usb_device *dev = interface_to_usbdev (intf);
+ struct hid_device *hid = usb_get_intfdata (intf);
+ struct usbhid_device *usbhid = hid->driver_data;
+ int status;
- hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
- /* FIXME: Any more reinitialization needed? */
+ if (!test_bit(HID_STARTED, &usbhid->iofl))
+ return 0;
- return hid_resume(intf);
+ status = hid_resume_common(hid, true);
+ dev_dbg(&intf->dev, "resume status %d\n", status);
+ return 0;
}
-static struct usb_device_id hid_usb_ids [] = {
+static int hid_reset_resume(struct usb_interface *intf)
+{
+ struct hid_device *hid = usb_get_intfdata(intf);
+ struct usbhid_device *usbhid = hid->driver_data;
+ int status;
+
+ clear_bit(HID_SUSPENDED, &usbhid->iofl);
+ status = hid_post_reset(intf);
+ if (status >= 0 && hid->driver && hid->driver->reset_resume) {
+ int ret = hid->driver->reset_resume(hid);
+ if (ret < 0)
+ status = ret;
+ }
+ return status;
+}
+
+#endif /* CONFIG_PM */
+
+static const struct usb_device_id hid_usb_ids[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
.bInterfaceClass = USB_INTERFACE_CLASS_HID },
{ } /* Terminating entry */
@@ -1111,67 +1589,54 @@ MODULE_DEVICE_TABLE (usb, hid_usb_ids);
static struct usb_driver hid_driver = {
.name = "usbhid",
- .probe = hid_probe,
- .disconnect = hid_disconnect,
+ .probe = usbhid_probe,
+ .disconnect = usbhid_disconnect,
+#ifdef CONFIG_PM
.suspend = hid_suspend,
.resume = hid_resume,
- .reset_resume = hid_post_reset,
+ .reset_resume = hid_reset_resume,
+#endif
.pre_reset = hid_pre_reset,
.post_reset = hid_post_reset,
.id_table = hid_usb_ids,
.supports_autosuspend = 1,
};
-static const struct hid_device_id hid_usb_table[] = {
- { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
- { }
-};
-
-static struct hid_driver hid_usb_driver = {
- .name = "generic-usb",
- .id_table = hid_usb_table,
-};
+struct usb_interface *usbhid_find_interface(int minor)
+{
+ return usb_find_interface(&hid_driver, minor);
+}
static int __init hid_init(void)
{
- int retval;
- retval = hid_register_driver(&hid_usb_driver);
- if (retval)
- goto hid_register_fail;
+ int retval = -ENOMEM;
+
retval = usbhid_quirks_init(quirks_param);
if (retval)
goto usbhid_quirks_init_fail;
- retval = hiddev_init();
- if (retval)
- goto hiddev_init_fail;
retval = usb_register(&hid_driver);
if (retval)
goto usb_register_fail;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0;
usb_register_fail:
- hiddev_exit();
-hiddev_init_fail:
usbhid_quirks_exit();
usbhid_quirks_init_fail:
- hid_unregister_driver(&hid_usb_driver);
-hid_register_fail:
return retval;
}
static void __exit hid_exit(void)
{
usb_deregister(&hid_driver);
- hiddev_exit();
usbhid_quirks_exit();
- hid_unregister_driver(&hid_usb_driver);
}
module_init(hid_init);
module_exit(hid_exit);
-MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_AUTHOR("Andreas Gal");
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_AUTHOR("Jiri Kosina");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 484e3eec2f8..10b61670278 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -22,9 +22,10 @@
/* #define DEBUG */
-#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/input.h>
+#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h>
@@ -219,7 +220,7 @@ static int pidff_rescale_signed(int i, struct hid_field *field)
static void pidff_set(struct pidff_usage *usage, u16 value)
{
usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
- debug("calculated from %d to %d", value, usage->value[0]);
+ pr_debug("calculated from %d to %d\n", value, usage->value[0]);
}
static void pidff_set_signed(struct pidff_usage *usage, s16 value)
@@ -234,7 +235,7 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value)
usage->value[0] =
pidff_rescale(value, 0x7fff, usage->field);
}
- debug("calculated from %d to %d", value, usage->value[0]);
+ pr_debug("calculated from %d to %d\n", value, usage->value[0]);
}
/*
@@ -258,11 +259,12 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
- debug("attack %u => %d", envelope->attack_level,
- pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
+ hid_dbg(pidff->hid, "attack %u => %d\n",
+ envelope->attack_level,
+ pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
+ HID_REQ_SET_REPORT);
}
/*
@@ -288,8 +290,8 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff,
pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
effect->u.constant.level);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONSTANT],
+ HID_REQ_SET_REPORT);
}
/*
@@ -323,8 +325,8 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->effect_direction);
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ HID_REQ_SET_REPORT);
}
/*
@@ -355,8 +357,8 @@ static void pidff_set_periodic_report(struct pidff_device *pidff,
pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
+ HID_REQ_SET_REPORT);
}
@@ -397,8 +399,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
effect->u.condition[i].left_saturation);
pidff_set(&pidff->set_condition[PID_DEAD_BAND],
effect->u.condition[i].deadband);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION],
+ HID_REQ_SET_REPORT);
}
}
@@ -438,8 +440,8 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff,
effect->u.ramp.start_level);
pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
effect->u.ramp.end_level);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_RAMP],
+ HID_REQ_SET_REPORT);
}
/*
@@ -463,35 +465,35 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
int j;
pidff->create_new_effect_type->value[0] = efnum;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
- USB_DIR_OUT);
- debug("create_new_effect sent, type: %d", efnum);
+ hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
+ HID_REQ_SET_REPORT);
+ hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum);
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
pidff->block_load_status->value[0] = 0;
- usbhid_wait_io(pidff->hid);
+ hid_hw_wait(pidff->hid);
for (j = 0; j < 60; j++) {
- debug("pid_block_load requested");
- usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
- USB_DIR_IN);
- usbhid_wait_io(pidff->hid);
+ hid_dbg(pidff->hid, "pid_block_load requested\n");
+ hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
+ HID_REQ_GET_REPORT);
+ hid_hw_wait(pidff->hid);
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
- debug("device reported free memory: %d bytes",
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+ hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
return 0;
}
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_FULL]) {
- debug("not enough memory free: %d bytes",
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ hid_dbg(pidff->hid, "not enough memory free: %d bytes\n",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
return -ENOSPC;
}
}
- printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
+ hid_err(pidff->hid, "pid_block_load failed 60 times\n");
return -EIO;
}
@@ -511,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
}
- usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
+ HID_REQ_SET_REPORT);
}
/**
@@ -533,8 +535,8 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value)
static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
{
pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE],
+ HID_REQ_SET_REPORT);
}
/*
@@ -545,10 +547,11 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
struct pidff_device *pidff = dev->ff->private;
int pid_id = pidff->pid_id[effect_id];
- debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+ hid_dbg(pidff->hid, "starting to erase %d/%d\n",
+ effect_id, pidff->pid_id[effect_id]);
/* Wait for the queue to clear. We do not want a full fifo to
prevent the effect removal. */
- usbhid_wait_io(pidff->hid);
+ hid_hw_wait(pidff->hid);
pidff_playback_pid(pidff, pid_id, 0);
pidff_erase_pid(pidff, pid_id);
@@ -603,8 +606,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
type_id = PID_SAW_DOWN;
break;
default:
- printk(KERN_ERR
- "hid-pidff: invalid waveform\n");
+ hid_err(pidff->hid, "invalid waveform\n");
return -EINVAL;
}
@@ -695,7 +697,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
break;
default:
- printk(KERN_ERR "hid-pidff: invalid type\n");
+ hid_err(pidff->hid, "invalid type\n");
return -EINVAL;
}
@@ -703,7 +705,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff->pid_id[effect->id] =
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
- debug("uploaded");
+ hid_dbg(pidff->hid, "uploaded\n");
return 0;
}
@@ -716,8 +718,8 @@ static void pidff_set_gain(struct input_dev *dev, u16 gain)
struct pidff_device *pidff = dev->ff->private;
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+ HID_REQ_SET_REPORT);
}
static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
@@ -742,8 +744,8 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
pidff->set_effect[PID_START_DELAY].value[0] = 0;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ HID_REQ_SET_REPORT);
}
/*
@@ -769,14 +771,14 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
for (i = 0; i < report->maxfield; i++) {
if (report->field[i]->maxusage !=
report->field[i]->report_count) {
- debug("maxusage and report_count do not match, "
- "skipping");
+ pr_debug("maxusage and report_count do not match, skipping\n");
continue;
}
for (j = 0; j < report->field[i]->maxusage; j++) {
if (report->field[i]->usage[j].hid ==
(HID_UP_PID | table[k])) {
- debug("found %d at %d->%d", k, i, j);
+ pr_debug("found %d at %d->%d\n",
+ k, i, j);
usage[k].field = report->field[i];
usage[k].value =
&report->field[i]->value[j];
@@ -788,7 +790,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
break;
}
if (!found && strict) {
- debug("failed to locate %d", k);
+ pr_debug("failed to locate %d\n", k);
return -1;
}
}
@@ -825,8 +827,8 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
continue;
ret = pidff_check_usage(report->field[0]->logical);
if (ret != -1) {
- debug("found usage 0x%02x from field->logical",
- pidff_reports[ret]);
+ hid_dbg(hid, "found usage 0x%02x from field->logical\n",
+ pidff_reports[ret]);
pidff->reports[ret] = report;
continue;
}
@@ -844,8 +846,9 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
continue;
ret = pidff_check_usage(hid->collection[i - 1].usage);
if (ret != -1 && !pidff->reports[ret]) {
- debug("found usage 0x%02x from collection array",
- pidff_reports[ret]);
+ hid_dbg(hid,
+ "found usage 0x%02x from collection array\n",
+ pidff_reports[ret]);
pidff->reports[ret] = report;
}
}
@@ -860,7 +863,7 @@ static int pidff_reports_ok(struct pidff_device *pidff)
for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
if (!pidff->reports[i]) {
- debug("%d missing", i);
+ hid_dbg(pidff->hid, "%d missing\n", i);
return 0;
}
}
@@ -883,8 +886,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
report->field[i]->logical_minimum == 1)
return report->field[i];
else {
- printk(KERN_ERR "hid-pidff: logical_minimum "
- "is not 1 as it should be\n");
+ pr_err("logical_minimum is not 1 as it should be\n");
return NULL;
}
}
@@ -923,7 +925,7 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld,
*/
static int pidff_find_special_fields(struct pidff_device *pidff)
{
- debug("finding special fields");
+ hid_dbg(pidff->hid, "finding special fields\n");
pidff->create_new_effect_type =
pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
@@ -944,32 +946,30 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
0x78, 1);
- debug("search done");
+ hid_dbg(pidff->hid, "search done\n");
if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
- printk(KERN_ERR "hid-pidff: effect lists not found\n");
+ hid_err(pidff->hid, "effect lists not found\n");
return -1;
}
if (!pidff->effect_direction) {
- printk(KERN_ERR "hid-pidff: direction field not found\n");
+ hid_err(pidff->hid, "direction field not found\n");
return -1;
}
if (!pidff->device_control) {
- printk(KERN_ERR "hid-pidff: device control field not found\n");
+ hid_err(pidff->hid, "device control field not found\n");
return -1;
}
if (!pidff->block_load_status) {
- printk(KERN_ERR
- "hid-pidff: block load status field not found\n");
+ hid_err(pidff->hid, "block load status field not found\n");
return -1;
}
if (!pidff->effect_operation_status) {
- printk(KERN_ERR
- "hid-pidff: effect operation field not found\n");
+ hid_err(pidff->hid, "effect operation field not found\n");
return -1;
}
@@ -981,23 +981,22 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
effect_types)) {
- printk(KERN_ERR "hid-pidff: no effect types found\n");
+ hid_err(pidff->hid, "no effect types found\n");
return -1;
}
if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
block_load_status) !=
sizeof(pidff_block_load_status)) {
- printk(KERN_ERR
- "hidpidff: block load status identifiers not found\n");
+ hid_err(pidff->hid,
+ "block load status identifiers not found\n");
return -1;
}
if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
effect_operation_status) !=
sizeof(pidff_effect_operation_status)) {
- printk(KERN_ERR
- "hidpidff: effect operation identifiers not found\n");
+ hid_err(pidff->hid, "effect operation identifiers not found\n");
return -1;
}
@@ -1016,8 +1015,8 @@ static int pidff_find_effects(struct pidff_device *pidff,
int pidff_type = pidff->type_id[i];
if (pidff->set_effect_type->usage[pidff_type].hid !=
pidff->create_new_effect_type->usage[pidff_type].hid) {
- printk(KERN_ERR "hid-pidff: "
- "effect type number %d is invalid\n", i);
+ hid_err(pidff->hid,
+ "effect type number %d is invalid\n", i);
return -1;
}
}
@@ -1072,27 +1071,23 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
int envelope_ok = 0;
if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown set_effect report layout\n");
+ hid_err(pidff->hid, "unknown set_effect report layout\n");
return -ENODEV;
}
PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
- printk(KERN_ERR
- "hid-pidff: unknown pid_block_load report layout\n");
+ hid_err(pidff->hid, "unknown pid_block_load report layout\n");
return -ENODEV;
}
if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown effect_operation report layout\n");
+ hid_err(pidff->hid, "unknown effect_operation report layout\n");
return -ENODEV;
}
if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown pid_block_free report layout\n");
+ hid_err(pidff->hid, "unknown pid_block_free report layout\n");
return -ENODEV;
}
@@ -1104,27 +1099,26 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
if (!envelope_ok) {
if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has constant effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has constant effect but no envelope\n");
if (test_and_clear_bit(FF_RAMP, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has ramp effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has ramp effect but no envelope\n");
if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has periodic effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has periodic effect but no envelope\n");
}
if (test_bit(FF_CONSTANT, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown constant effect layout\n");
+ hid_warn(pidff->hid, "unknown constant effect layout\n");
clear_bit(FF_CONSTANT, dev->ffbit);
}
if (test_bit(FF_RAMP, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
- printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
+ hid_warn(pidff->hid, "unknown ramp effect layout\n");
clear_bit(FF_RAMP, dev->ffbit);
}
@@ -1133,8 +1127,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
test_bit(FF_FRICTION, dev->ffbit) ||
test_bit(FF_INERTIA, dev->ffbit)) &&
PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown condition effect layout\n");
+ hid_warn(pidff->hid, "unknown condition effect layout\n");
clear_bit(FF_SPRING, dev->ffbit);
clear_bit(FF_DAMPER, dev->ffbit);
clear_bit(FF_FRICTION, dev->ffbit);
@@ -1143,8 +1136,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
if (test_bit(FF_PERIODIC, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown periodic effect layout\n");
+ hid_warn(pidff->hid, "unknown periodic effect layout\n");
clear_bit(FF_PERIODIC, dev->ffbit);
}
@@ -1166,33 +1158,32 @@ static void pidff_reset(struct pidff_device *pidff)
pidff->device_control->value[0] = pidff->control_id[PID_RESET];
/* We reset twice as sometimes hid_wait_io isn't waiting long enough */
- usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- usbhid_wait_io(hid);
- usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
pidff->device_control->value[0] =
pidff->control_id[PID_ENABLE_ACTUATORS];
- usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
/* pool report is sometimes messed up, refetch it */
- usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT);
+ hid_hw_wait(hid);
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
- int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
- while (sim_effects < 2) {
+ while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
if (i++ > 20) {
- printk(KERN_WARNING "hid-pidff: device reports "
- "%d simultaneous effects\n",
- sim_effects);
+ hid_warn(pidff->hid,
+ "device reports %d simultaneous effects\n",
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
break;
}
- debug("pid_pool requested again");
- usbhid_submit_report(hid, pidff->reports[PID_POOL],
- USB_DIR_IN);
- usbhid_wait_io(hid);
+ hid_dbg(pidff->hid, "pid_pool requested again\n");
+ hid_hw_request(hid, pidff->reports[PID_POOL],
+ HID_REQ_GET_REPORT);
+ hid_hw_wait(hid);
}
}
}
@@ -1215,7 +1206,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
error = pidff_request_effect_upload(pidff, 1);
if (error) {
- printk(KERN_ERR "hid-pidff: upload request failed\n");
+ hid_err(pidff->hid, "upload request failed\n");
return error;
}
@@ -1224,8 +1215,8 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
pidff_autocenter(pidff, 0xffff);
set_bit(FF_AUTOCENTER, dev->ffbit);
} else {
- printk(KERN_NOTICE "hid-pidff: "
- "device has unknown autocenter control method\n");
+ hid_notice(pidff->hid,
+ "device has unknown autocenter control method\n");
}
pidff_erase_pid(pidff,
@@ -1248,10 +1239,10 @@ int hid_pidff_init(struct hid_device *hid)
int max_effects;
int error;
- debug("starting pid init");
+ hid_dbg(hid, "starting pid init\n");
if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
- debug("not a PID device, no output report");
+ hid_dbg(hid, "not a PID device, no output report\n");
return -ENODEV;
}
@@ -1265,7 +1256,7 @@ int hid_pidff_init(struct hid_device *hid)
pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
if (!pidff_reports_ok(pidff)) {
- debug("reports not ok, aborting");
+ hid_dbg(hid, "reports not ok, aborting\n");
error = -ENODEV;
goto fail;
}
@@ -1278,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid)
if (test_bit(FF_GAIN, dev->ffbit)) {
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
- USB_DIR_OUT);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN],
+ HID_REQ_SET_REPORT);
}
error = pidff_check_autocenter(pidff, dev);
@@ -1290,23 +1281,23 @@ int hid_pidff_init(struct hid_device *hid)
pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
1;
- debug("max effects is %d", max_effects);
+ hid_dbg(hid, "max effects is %d\n", max_effects);
if (max_effects > PID_EFFECTS_MAX)
max_effects = PID_EFFECTS_MAX;
if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
- debug("max simultaneous effects is %d",
- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+ hid_dbg(hid, "max simultaneous effects is %d\n",
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
if (pidff->pool[PID_RAM_POOL_SIZE].value)
- debug("device memory size is %d bytes",
- pidff->pool[PID_RAM_POOL_SIZE].value[0]);
+ hid_dbg(hid, "device memory size is %d bytes\n",
+ pidff->pool[PID_RAM_POOL_SIZE].value[0]);
if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
- printk(KERN_NOTICE "hid-pidff: "
- "device does not support device managed pool\n");
+ hid_notice(hid,
+ "device does not support device managed pool\n");
goto fail;
}
@@ -1322,8 +1313,7 @@ int hid_pidff_init(struct hid_device *hid)
ff->set_autocenter = pidff_set_autocenter;
ff->playback = pidff_playback;
- printk(KERN_INFO "Force feedback for USB HID PID devices by "
- "Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 4391717d251..31e6727cd00 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -16,6 +16,8 @@
*/
#include <linux/hid.h>
+#include <linux/export.h>
+#include <linux/slab.h>
#include "../hid-ids.h"
@@ -32,35 +34,97 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN, HID_QUIRK_MULTI_INPUT},
{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
+ { USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH_2968, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
+
+ { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS },
+
{ 0, 0 }
};
@@ -198,7 +262,7 @@ int usbhid_quirks_init(char **quirks_param)
u32 quirks;
int n = 0, m;
- for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {
+ for (; n < MAX_USBHID_BOOT_QUIRKS && quirks_param[n]; n++) {
m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
&idVendor, &idProduct, &quirks);
@@ -277,7 +341,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
if (idVendor == USB_VENDOR_ID_NCR &&
idProduct >= USB_DEVICE_ID_NCR_FIRST &&
idProduct <= USB_DEVICE_ID_NCR_LAST)
- return HID_QUIRK_NOGET;
+ return HID_QUIRK_NO_INIT_REPORTS;
down_read(&dquirks_rwsem);
bl_entry = usbhid_exists_dquirk(idVendor, idProduct);
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 1f5b5d4c3c3..2f1ddca6f2e 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -29,12 +29,12 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/compat.h>
+#include <linux/vmalloc.h>
#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -44,7 +44,7 @@
#define HIDDEV_MINOR_BASE 96
#define HIDDEV_MINORS 16
#endif
-#define HIDDEV_BUFFER_SIZE 64
+#define HIDDEV_BUFFER_SIZE 2048
struct hiddev {
int exist;
@@ -67,8 +67,6 @@ struct hiddev_list {
struct mutex thread_lock;
};
-static struct hiddev *hiddev_table[HIDDEV_MINORS];
-
/*
* Find a report, given the report's type and ID. The ID can be specified
* indirectly by REPORT_ID_FIRST (which returns the first report of the given
@@ -227,12 +225,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
*/
static int hiddev_fasync(int fd, struct file *file, int on)
{
- int retval;
struct hiddev_list *list = file->private_data;
- retval = fasync_helper(fd, file, on, &list->fasync);
-
- return retval < 0 ? retval : 0;
+ return fasync_helper(fd, file, on, &list->fasync);
}
@@ -248,14 +243,21 @@ static int hiddev_release(struct inode * inode, struct file * file)
list_del(&list->node);
spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
+ mutex_lock(&list->hiddev->existancelock);
if (!--list->hiddev->open) {
- if (list->hiddev->exist)
+ if (list->hiddev->exist) {
usbhid_close(list->hiddev->hid);
- else
+ usbhid_put_power(list->hiddev->hid);
+ } else {
+ mutex_unlock(&list->hiddev->existancelock);
kfree(list->hiddev);
+ vfree(list);
+ return 0;
+ }
}
- kfree(list);
+ mutex_unlock(&list->hiddev->existancelock);
+ vfree(list);
return 0;
}
@@ -266,20 +268,21 @@ static int hiddev_release(struct inode * inode, struct file * file)
static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list;
+ struct usb_interface *intf;
+ struct hid_device *hid;
+ struct hiddev *hiddev;
int res;
- int i = iminor(inode) - HIDDEV_MINOR_BASE;
-
- if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
+ intf = usbhid_find_interface(iminor(inode));
+ if (!intf)
return -ENODEV;
+ hid = usb_get_intfdata(intf);
+ hiddev = hid->hiddev;
- if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+ if (!(list = vzalloc(sizeof(struct hiddev_list))))
return -ENOMEM;
mutex_init(&list->thread_lock);
-
- list->hiddev = hiddev_table[i];
-
-
+ list->hiddev = hiddev;
file->private_data = list;
/*
@@ -288,7 +291,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
*/
if (list->hiddev->exist) {
if (!list->hiddev->open++) {
- res = usbhid_open(hiddev_table[i]->hid);
+ res = usbhid_open(hiddev->hid);
if (res < 0) {
res = -EIO;
goto bail;
@@ -300,13 +303,27 @@ static int hiddev_open(struct inode *inode, struct file *file)
}
spin_lock_irq(&list->hiddev->list_lock);
- list_add_tail(&list->node, &hiddev_table[i]->list);
+ list_add_tail(&list->node, &hiddev->list);
spin_unlock_irq(&list->hiddev->list_lock);
+ mutex_lock(&hiddev->existancelock);
+ if (!list->hiddev->open++)
+ if (list->hiddev->exist) {
+ struct hid_device *hid = hiddev->hid;
+ res = usbhid_get_power(hid);
+ if (res < 0) {
+ res = -EIO;
+ goto bail_unlock;
+ }
+ usbhid_open(hid);
+ }
+ mutex_unlock(&hiddev->existancelock);
return 0;
+bail_unlock:
+ mutex_unlock(&hiddev->existancelock);
bail:
file->private_data = NULL;
- kfree(list);
+ vfree(list);
return res;
}
@@ -344,10 +361,6 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
prepare_to_wait(&list->hiddev->wait, &wait, TASK_INTERRUPTIBLE);
while (list->head == list->tail) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
@@ -356,12 +369,18 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
retval = -EIO;
break;
}
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
/* let O_NONBLOCK tasks run */
mutex_unlock(&list->thread_lock);
schedule();
- if (mutex_lock_interruptible(&list->thread_lock))
+ if (mutex_lock_interruptible(&list->thread_lock)) {
+ finish_wait(&list->hiddev->wait, &wait);
return -EINTR;
+ }
set_current_state(TASK_INTERRUPTIBLE);
}
finish_wait(&list->hiddev->wait, &wait);
@@ -440,7 +459,6 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
if (!uref_multi)
return -ENOMEM;
- lock_kernel();
uref = &uref_multi->uref;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
if (copy_from_user(uref_multi, user_arg,
@@ -503,7 +521,7 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
(uref_multi->num_values > HID_MAX_MULTI_USAGES ||
uref->usage_index + uref_multi->num_values > field->report_count))
goto inval;
- }
+ }
switch (cmd) {
case HIDIOCGUSAGE:
@@ -517,8 +535,9 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
goto goodreturn;
case HIDIOCGCOLLECTIONINDEX:
+ i = field->usage[uref->usage_index].collection_index;
kfree(uref_multi);
- return field->usage[uref->usage_index].collection_index;
+ return i;
case HIDIOCGUSAGES:
for (i = 0; i < uref_multi->num_values; i++)
uref_multi->values[i] =
@@ -535,15 +554,12 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
}
goodreturn:
- unlock_kernel();
kfree(uref_multi);
return 0;
fault:
- unlock_kernel();
kfree(uref_multi);
return -EFAULT;
inval:
- unlock_kernel();
kfree(uref_multi);
return -EINVAL;
}
@@ -581,161 +597,170 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct hiddev_list *list = file->private_data;
struct hiddev *hiddev = list->hiddev;
- struct hid_device *hid = hiddev->hid;
- struct usb_device *dev = hid_to_usb_dev(hid);
+ struct hid_device *hid;
struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo;
struct hiddev_field_info finfo;
struct hiddev_devinfo dinfo;
struct hid_report *report;
struct hid_field *field;
- struct usbhid_device *usbhid = hid->driver_data;
void __user *user_arg = (void __user *)arg;
- int i, r;
-
+ int i, r = -EINVAL;
+
/* Called without BKL by compat methods so no BKL taken */
- /* FIXME: Who or what stop this racing with a disconnect ?? */
- if (!hiddev->exist)
- return -EIO;
+ mutex_lock(&hiddev->existancelock);
+ if (!hiddev->exist) {
+ r = -ENODEV;
+ goto ret_unlock;
+ }
+
+ hid = hiddev->hid;
switch (cmd) {
case HIDIOCGVERSION:
- return put_user(HID_VERSION, (int __user *)arg);
+ r = put_user(HID_VERSION, (int __user *)arg) ?
+ -EFAULT : 0;
+ break;
case HIDIOCAPPLICATION:
- if (arg < 0 || arg >= hid->maxapplication)
- return -EINVAL;
+ if (arg >= hid->maxapplication)
+ break;
for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type ==
HID_COLLECTION_APPLICATION && arg-- == 0)
break;
- if (i == hid->maxcollection)
- return -EINVAL;
-
- return hid->collection[i].usage;
+ if (i < hid->maxcollection)
+ r = hid->collection[i].usage;
+ break;
case HIDIOCGDEVINFO:
- dinfo.bustype = BUS_USB;
- dinfo.busnum = dev->bus->busnum;
- dinfo.devnum = dev->devnum;
- dinfo.ifnum = usbhid->ifnum;
- dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
- dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
- dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
- dinfo.num_applications = hid->maxapplication;
- if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
- return -EFAULT;
-
- return 0;
+ {
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ memset(&dinfo, 0, sizeof(dinfo));
+
+ dinfo.bustype = BUS_USB;
+ dinfo.busnum = dev->bus->busnum;
+ dinfo.devnum = dev->devnum;
+ dinfo.ifnum = usbhid->ifnum;
+ dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
+ dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
+ dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
+ dinfo.num_applications = hid->maxapplication;
+
+ r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ?
+ -EFAULT : 0;
+ break;
+ }
case HIDIOCGFLAG:
- if (put_user(list->flags, (int __user *)arg))
- return -EFAULT;
-
- return 0;
+ r = put_user(list->flags, (int __user *)arg) ?
+ -EFAULT : 0;
+ break;
case HIDIOCSFLAG:
{
int newflags;
- if (get_user(newflags, (int __user *)arg))
- return -EFAULT;
+
+ if (get_user(newflags, (int __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
if ((newflags & ~HIDDEV_FLAGS) != 0 ||
((newflags & HIDDEV_FLAG_REPORT) != 0 &&
(newflags & HIDDEV_FLAG_UREF) == 0))
- return -EINVAL;
+ break;
list->flags = newflags;
- return 0;
+ r = 0;
+ break;
}
case HIDIOCGSTRING:
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist)
- r = hiddev_ioctl_string(hiddev, cmd, user_arg);
- else
- r = -ENODEV;
- mutex_unlock(&hiddev->existancelock);
- return r;
+ r = hiddev_ioctl_string(hiddev, cmd, user_arg);
+ break;
case HIDIOCINITREPORT:
- mutex_lock(&hiddev->existancelock);
- if (!hiddev->exist) {
- mutex_unlock(&hiddev->existancelock);
- return -ENODEV;
- }
usbhid_init_reports(hid);
- mutex_unlock(&hiddev->existancelock);
-
- return 0;
+ r = 0;
+ break;
case HIDIOCGREPORT:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
- return -EINVAL;
+ break;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist) {
- usbhid_submit_report(hid, report, USB_DIR_IN);
- usbhid_wait_io(hid);
- }
- mutex_unlock(&hiddev->existancelock);
+ hid_hw_request(hid, report, HID_REQ_GET_REPORT);
+ hid_hw_wait(hid);
- return 0;
+ r = 0;
+ break;
case HIDIOCSREPORT:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
- return -EINVAL;
+ break;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist) {
- usbhid_submit_report(hid, report, USB_DIR_OUT);
- usbhid_wait_io(hid);
- }
- mutex_unlock(&hiddev->existancelock);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
- return 0;
+ r = 0;
+ break;
case HIDIOCGREPORTINFO:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
rinfo.num_fields = report->maxfield;
- if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
- return -EFAULT;
-
- return 0;
+ r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ?
+ -EFAULT : 0;
+ break;
case HIDIOCGFIELDINFO:
- if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
- return -EFAULT;
+ if (copy_from_user(&finfo, user_arg, sizeof(finfo))) {
+ r = -EFAULT;
+ break;
+ }
+
rinfo.report_type = finfo.report_type;
rinfo.report_id = finfo.report_id;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
if (finfo.field_index >= report->maxfield)
- return -EINVAL;
+ break;
field = report->field[finfo.field_index];
memset(&finfo, 0, sizeof(finfo));
@@ -754,10 +779,9 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
finfo.unit_exponent = field->unit_exponent;
finfo.unit = field->unit;
- if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
- return -EFAULT;
-
- return 0;
+ r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ?
+ -EFAULT : 0;
+ break;
case HIDIOCGUCODE:
/* fall through */
@@ -766,57 +790,52 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case HIDIOCGUSAGES:
case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX:
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist)
- r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
- else
- r = -ENODEV;
- mutex_unlock(&hiddev->existancelock);
- return r;
+ r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
+ break;
case HIDIOCGCOLLECTIONINFO:
- if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
- return -EFAULT;
+ if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (cinfo.index >= hid->maxcollection)
- return -EINVAL;
+ break;
cinfo.type = hid->collection[cinfo.index].type;
cinfo.usage = hid->collection[cinfo.index].usage;
cinfo.level = hid->collection[cinfo.index].level;
- if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
+ r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ?
+ -EFAULT : 0;
+ break;
default:
-
if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
- return -EINVAL;
+ break;
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
- int len;
- if (!hid->name)
- return 0;
- len = strlen(hid->name) + 1;
+ int len = strlen(hid->name) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
- return copy_to_user(user_arg, hid->name, len) ?
+ r = copy_to_user(user_arg, hid->name, len) ?
-EFAULT : len;
+ break;
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
- int len;
- if (!hid->phys)
- return 0;
- len = strlen(hid->phys) + 1;
+ int len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
- return copy_to_user(user_arg, hid->phys, len) ?
+ r = copy_to_user(user_arg, hid->phys, len) ?
-EFAULT : len;
+ break;
}
}
- return -EINVAL;
+
+ret_unlock:
+ mutex_unlock(&hiddev->existancelock);
+ return r;
}
#ifdef CONFIG_COMPAT
@@ -838,10 +857,17 @@ static const struct file_operations hiddev_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = hiddev_compat_ioctl,
#endif
+ .llseek = noop_llseek,
};
+static char *hiddev_devnode(struct device *dev, umode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
static struct usb_class_driver hiddev_class = {
.name = "hiddev%d",
+ .devnode = hiddev_devnode,
.fops = &hiddev_fops,
.minor_base = HIDDEV_MINOR_BASE,
};
@@ -877,18 +903,13 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
hid->hiddev = hiddev;
hiddev->hid = hid;
hiddev->exist = 1;
-
retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) {
- err_hid("Not able to get a minor for this device.");
+ hid_err(hid, "Not able to get a minor for this device\n");
hid->hiddev = NULL;
kfree(hiddev);
return -1;
- } else {
- hid->minor = usbhid->intf->minor;
- hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
}
-
return 0;
}
@@ -902,56 +923,17 @@ void hiddev_disconnect(struct hid_device *hid)
struct hiddev *hiddev = hid->hiddev;
struct usbhid_device *usbhid = hid->driver_data;
+ usb_deregister_dev(usbhid->intf, &hiddev_class);
+
mutex_lock(&hiddev->existancelock);
hiddev->exist = 0;
- mutex_unlock(&hiddev->existancelock);
-
- hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
- usb_deregister_dev(usbhid->intf, &hiddev_class);
if (hiddev->open) {
+ mutex_unlock(&hiddev->existancelock);
usbhid_close(hiddev->hid);
wake_up_interruptible(&hiddev->wait);
} else {
+ mutex_unlock(&hiddev->existancelock);
kfree(hiddev);
}
}
-
-/* Currently this driver is a USB driver. It's not a conventional one in
- * the sense that it doesn't probe at the USB level. Instead it waits to
- * be connected by HID through the hiddev_connect / hiddev_disconnect
- * routines. The reason to register as a USB device is to gain part of the
- * minor number space from the USB major.
- *
- * In theory, should the HID code be generalized to more than one physical
- * medium (say, IEEE 1384), this driver will probably need to register its
- * own major number, and in doing so, no longer need to register with USB.
- * At that point the probe routine and hiddev_driver struct below will no
- * longer be useful.
- */
-
-
-/* We never attach in this manner, and rely on HID to connect us. This
- * is why there is no disconnect routine defined in the usb_driver either.
- */
-static int hiddev_usbd_probe(struct usb_interface *intf,
- const struct usb_device_id *hiddev_info)
-{
- return -ENODEV;
-}
-
-
-static /* const */ struct usb_driver hiddev_driver = {
- .name = "hiddev",
- .probe = hiddev_usbd_probe,
-};
-
-int __init hiddev_init(void)
-{
- return usb_register(&hiddev_driver);
-}
-
-void hiddev_exit(void)
-{
- usb_deregister(&hiddev_driver);
-}
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 9eb30564be9..f633c24ce28 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -34,11 +34,12 @@
#include <linux/input.h>
/* API provided by hid-core.c for USB HID drivers */
-int usbhid_wait_io(struct hid_device* hid);
void usbhid_close(struct hid_device *hid);
int usbhid_open(struct hid_device *hid);
void usbhid_init_reports(struct hid_device *hid);
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+int usbhid_get_power(struct hid_device *hid);
+void usbhid_put_power(struct hid_device *hid);
+struct usb_interface *usbhid_find_interface(int minor);
/* iofl flags */
#define HID_CTRL_RUNNING 1
@@ -49,6 +50,8 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
#define HID_CLEAR_HALT 6
#define HID_DISCONNECTED 7
#define HID_STARTED 8
+#define HID_KEYS_PRESSED 10
+#define HID_NO_BANDWIDTH 11
/*
* USB-specific HID struct, to be pointed to
@@ -66,24 +69,23 @@ struct usbhid_device {
struct urb *urbin; /* Input URB */
char *inbuf; /* Input buffer */
dma_addr_t inbuf_dma; /* Input buffer dma */
- spinlock_t inlock; /* Input fifo spinlock */
struct urb *urbctrl; /* Control URB */
struct usb_ctrlrequest *cr; /* Control request struct */
- dma_addr_t cr_dma; /* Control request struct dma */
struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */
unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */
char *ctrlbuf; /* Control buffer */
dma_addr_t ctrlbuf_dma; /* Control buffer dma */
- spinlock_t ctrllock; /* Control fifo spinlock */
+ unsigned long last_ctrl; /* record of last output for timeouts */
struct urb *urbout; /* Output URB */
struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
unsigned char outhead, outtail; /* Output pipe fifo head & tail */
char *outbuf; /* Output buffer */
dma_addr_t outbuf_dma; /* Output buffer dma */
- spinlock_t outlock; /* Output fifo spinlock */
+ unsigned long last_out; /* record of last output for timeouts */
+ spinlock_t lock; /* fifo spinlock */
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
struct timer_list io_retry; /* Retry timer */
unsigned long stop_retry; /* Time to give up, in jiffies */
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index b342926dd7f..9a332e683db 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -24,6 +24,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -62,6 +64,32 @@ static const unsigned char usb_kbd_keycode[256] = {
150,158,159,128,136,177,178,176,142,152,173,140
};
+
+/**
+ * struct usb_kbd - state of each attached keyboard
+ * @dev: input device associated with this keyboard
+ * @usbdev: usb device associated with this keyboard
+ * @old: data received in the past from the @irq URB representing which
+ * keys were pressed. By comparing with the current list of keys
+ * that are pressed, we are able to see key releases.
+ * @irq: URB for receiving a list of keys that are pressed when a
+ * new key is pressed or a key that was pressed is released.
+ * @led: URB for sending LEDs (e.g. numlock, ...)
+ * @newleds: data that will be sent with the @led URB representing which LEDs
+ should be on
+ * @name: Name of the keyboard. @dev's name field points to this buffer
+ * @phys: Physical path of the keyboard. @dev's phys field points to this
+ * buffer
+ * @new: Buffer for the @irq URB
+ * @cr: Control request for @led URB
+ * @leds: Buffer for the @led URB
+ * @new_dma: DMA address for @irq URB
+ * @leds_dma: DMA address for @led URB
+ * @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted
+ * @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
+ * submitted and its completion handler has not returned yet
+ * without resubmitting @led
+ */
struct usb_kbd {
struct input_dev *dev;
struct usb_device *usbdev;
@@ -74,9 +102,12 @@ struct usb_kbd {
unsigned char *new;
struct usb_ctrlrequest *cr;
unsigned char *leds;
- dma_addr_t cr_dma;
dma_addr_t new_dma;
dma_addr_t leds_dma;
+
+ spinlock_t leds_lock;
+ bool led_urb_submitted;
+
};
static void usb_kbd_irq(struct urb *urb)
@@ -105,16 +136,18 @@ static void usb_kbd_irq(struct urb *urb)
if (usb_kbd_keycode[kbd->old[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
else
- dev_info(&urb->dev->dev,
- "Unknown key (scancode %#x) released.\n", kbd->old[i]);
+ hid_info(urb->dev,
+ "Unknown key (scancode %#x) released.\n",
+ kbd->old[i]);
}
if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
if (usb_kbd_keycode[kbd->new[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
else
- dev_info(&urb->dev->dev,
- "Unknown key (scancode %#x) released.\n", kbd->new[i]);
+ hid_info(urb->dev,
+ "Unknown key (scancode %#x) pressed.\n",
+ kbd->new[i]);
}
}
@@ -125,52 +158,74 @@ static void usb_kbd_irq(struct urb *urb)
resubmit:
i = usb_submit_urb (urb, GFP_ATOMIC);
if (i)
- err_hid ("can't resubmit intr, %s-%s/input0, status %d",
- kbd->usbdev->bus->bus_name,
- kbd->usbdev->devpath, i);
+ hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
+ kbd->usbdev->bus->bus_name,
+ kbd->usbdev->devpath, i);
}
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
+ unsigned long flags;
struct usb_kbd *kbd = input_get_drvdata(dev);
if (type != EV_LED)
return -1;
+ spin_lock_irqsave(&kbd->leds_lock, flags);
kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
- if (kbd->led->status == -EINPROGRESS)
+ if (kbd->led_urb_submitted){
+ spin_unlock_irqrestore(&kbd->leds_lock, flags);
return 0;
+ }
- if (*(kbd->leds) == kbd->newleds)
+ if (*(kbd->leds) == kbd->newleds){
+ spin_unlock_irqrestore(&kbd->leds_lock, flags);
return 0;
+ }
*(kbd->leds) = kbd->newleds;
+
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
- err_hid("usb_submit_urb(leds) failed");
-
+ pr_err("usb_submit_urb(leds) failed\n");
+ else
+ kbd->led_urb_submitted = true;
+
+ spin_unlock_irqrestore(&kbd->leds_lock, flags);
+
return 0;
}
static void usb_kbd_led(struct urb *urb)
{
+ unsigned long flags;
struct usb_kbd *kbd = urb->context;
if (urb->status)
- dev_warn(&urb->dev->dev, "led urb status %d received\n",
+ hid_warn(urb->dev, "led urb status %d received\n",
urb->status);
- if (*(kbd->leds) == kbd->newleds)
+ spin_lock_irqsave(&kbd->leds_lock, flags);
+
+ if (*(kbd->leds) == kbd->newleds){
+ kbd->led_urb_submitted = false;
+ spin_unlock_irqrestore(&kbd->leds_lock, flags);
return;
+ }
*(kbd->leds) = kbd->newleds;
+
kbd->led->dev = kbd->usbdev;
- if (usb_submit_urb(kbd->led, GFP_ATOMIC))
- err_hid("usb_submit_urb(leds) failed");
+ if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
+ hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
+ kbd->led_urb_submitted = false;
+ }
+ spin_unlock_irqrestore(&kbd->leds_lock, flags);
+
}
static int usb_kbd_open(struct input_dev *dev)
@@ -197,11 +252,11 @@ static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
return -1;
if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
return -1;
- if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
+ if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
return -1;
- if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
+ if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
return -1;
- if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
+ if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
return -1;
return 0;
@@ -211,9 +266,9 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
{
usb_free_urb(kbd->irq);
usb_free_urb(kbd->led);
- usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
- usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
- usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
+ usb_free_coherent(dev, 8, kbd->new, kbd->new_dma);
+ kfree(kbd->cr);
+ usb_free_coherent(dev, 1, kbd->leds, kbd->leds_dma);
}
static int usb_kbd_probe(struct usb_interface *iface,
@@ -249,6 +304,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
kbd->usbdev = dev;
kbd->dev = input_dev;
+ spin_lock_init(&kbd->leds_lock);
if (dev->manufacturer)
strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
@@ -266,7 +322,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
le16_to_cpu(dev->descriptor.idProduct));
usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
- strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
+ strlcat(kbd->phys, "/input0", sizeof(kbd->phys));
input_dev->name = kbd->name;
input_dev->phys = kbd->phys;
@@ -304,15 +360,15 @@ static int usb_kbd_probe(struct usb_interface *iface,
usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
(void *) kbd->cr, kbd->leds, 1,
usb_kbd_led, kbd);
- kbd->led->setup_dma = kbd->cr_dma;
kbd->led->transfer_dma = kbd->leds_dma;
- kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
+ kbd->led->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
error = input_register_device(kbd->dev);
if (error)
goto fail2;
usb_set_intfdata(iface, kbd);
+ device_set_wakeup_enable(&dev->dev, 1);
return 0;
fail2:
@@ -331,6 +387,7 @@ static void usb_kbd_disconnect(struct usb_interface *intf)
if (kbd) {
usb_kill_urb(kbd->irq);
input_unregister_device(kbd->dev);
+ usb_kill_urb(kbd->led);
usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
kfree(kbd);
}
@@ -351,19 +408,4 @@ static struct usb_driver usb_kbd_driver = {
.id_table = usb_kbd_id_table,
};
-static int __init usb_kbd_init(void)
-{
- int result = usb_register(&usb_kbd_driver);
- if (result == 0)
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return result;
-}
-
-static void __exit usb_kbd_exit(void)
-{
- usb_deregister(&usb_kbd_driver);
-}
-
-module_init(usb_kbd_init);
-module_exit(usb_kbd_exit);
+module_usb_driver(usb_kbd_driver);
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 72ab4b26809..bf16d72dc37 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -92,9 +92,10 @@ static void usb_mouse_irq(struct urb *urb)
resubmit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
- err ("can't resubmit intr, %s-%s/input0, status %d",
- mouse->usbdev->bus->bus_name,
- mouse->usbdev->devpath, status);
+ dev_err(&mouse->usbdev->dev,
+ "can't resubmit intr, %s-%s/input0, status %d\n",
+ mouse->usbdev->bus->bus_name,
+ mouse->usbdev->devpath, status);
}
static int usb_mouse_open(struct input_dev *dev)
@@ -142,7 +143,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
if (!mouse || !input_dev)
goto fail1;
- mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
+ mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
if (!mouse->data)
goto fail1;
@@ -205,7 +206,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
fail3:
usb_free_urb(mouse->irq);
fail2:
- usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
+ usb_free_coherent(dev, 8, mouse->data, mouse->data_dma);
fail1:
input_free_device(input_dev);
kfree(mouse);
@@ -221,7 +222,7 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
usb_kill_urb(mouse->irq);
input_unregister_device(mouse->dev);
usb_free_urb(mouse->irq);
- usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
+ usb_free_coherent(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
kfree(mouse);
}
}
@@ -241,19 +242,4 @@ static struct usb_driver usb_mouse_driver = {
.id_table = usb_mouse_id_table,
};
-static int __init usb_mouse_init(void)
-{
- int retval = usb_register(&usb_mouse_driver);
- if (retval == 0)
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return retval;
-}
-
-static void __exit usb_mouse_exit(void)
-{
- usb_deregister(&usb_mouse_driver);
-}
-
-module_init(usb_mouse_init);
-module_exit(usb_mouse_exit);
+module_usb_driver(usb_mouse_driver);