Merge branch 'upstream' into for-linus
Conflicts: drivers/hid/hid-core.c
This commit is contained in:
Коммит
56ccd186f1
|
@ -104,6 +104,12 @@ config HID_APPLE
|
|||
Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
|
||||
MacBooks, MacBook Pros and Apple Aluminum.
|
||||
|
||||
config HID_AUREAL
|
||||
tristate "Aureal"
|
||||
depends on USB_HID
|
||||
---help---
|
||||
Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
|
||||
|
||||
config HID_BELKIN
|
||||
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
|
||||
depends on USB_HID
|
||||
|
|
|
@ -38,6 +38,7 @@ endif
|
|||
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
|
||||
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
|
||||
obj-$(CONFIG_HID_APPLE) += hid-apple.o
|
||||
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
|
||||
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
|
||||
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
|
||||
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
|
||||
|
|
|
@ -234,7 +234,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
|||
}
|
||||
}
|
||||
|
||||
if (iso_layout) {
|
||||
if (iso_layout) {
|
||||
if (asc->quirks & APPLE_ISO_KEYBOARD) {
|
||||
trans = apple_find_translation(apple_iso_keyboard, usage->code);
|
||||
if (trans) {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* HID driver for Aureal Cy se W-01RN USB_V3.1 devices
|
||||
*
|
||||
* Copyright (c) 2010 Franco Catrin <fcatrin@gmail.com>
|
||||
* Copyright (c) 2010 Ben Cropley <bcropley@internode.on.net>
|
||||
*
|
||||
* Based on HID sunplus driver by
|
||||
* 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-2007 Jiri Kosina
|
||||
* Copyright (c) 2007 Paul Walmsley
|
||||
* Copyright (c) 2008 Jiri Slaby
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
|
||||
dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
|
||||
rdesc[53] = 0x65;
|
||||
} return rdesc;
|
||||
}
|
||||
|
||||
static const struct hid_device_id aureal_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, aureal_devices);
|
||||
|
||||
static struct hid_driver aureal_driver = {
|
||||
.name = "aureal",
|
||||
.id_table = aureal_devices,
|
||||
.report_fixup = aureal_report_fixup,
|
||||
};
|
||||
|
||||
static int __init aureal_init(void)
|
||||
{
|
||||
return hid_register_driver(&aureal_driver);
|
||||
}
|
||||
|
||||
static void __exit aureal_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&aureal_driver);
|
||||
}
|
||||
|
||||
module_init(aureal_init);
|
||||
module_exit(aureal_exit);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -230,9 +230,16 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (parser->global.logical_maximum < parser->global.logical_minimum) {
|
||||
hid_err(parser->device, "logical range invalid %d %d\n",
|
||||
parser->global.logical_minimum, parser->global.logical_maximum);
|
||||
/* Handle both signed and unsigned cases properly */
|
||||
if ((parser->global.logical_minimum < 0 &&
|
||||
parser->global.logical_maximum <
|
||||
parser->global.logical_minimum) ||
|
||||
(parser->global.logical_minimum >= 0 &&
|
||||
(__u32)parser->global.logical_maximum <
|
||||
(__u32)parser->global.logical_minimum)) {
|
||||
dbg_hid("logical range invalid 0x%x 0x%x\n",
|
||||
parser->global.logical_minimum,
|
||||
parser->global.logical_maximum);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1149,7 +1156,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
|
|||
return report;
|
||||
}
|
||||
|
||||
void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||||
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||||
int interrupt)
|
||||
{
|
||||
struct hid_report_enum *report_enum = hid->report_enum + type;
|
||||
|
@ -1157,10 +1164,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
|||
unsigned int a;
|
||||
int rsize, csize = size;
|
||||
u8 *cdata = data;
|
||||
int ret = 0;
|
||||
|
||||
report = hid_get_report(report_enum, data);
|
||||
if (!report)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
if (report_enum->numbered) {
|
||||
cdata++;
|
||||
|
@ -1180,14 +1188,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
|||
|
||||
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
|
||||
hid->hiddev_report_event(hid, report);
|
||||
if (hid->claimed & HID_CLAIMED_HIDRAW)
|
||||
hidraw_report_event(hid, data, size);
|
||||
if (hid->claimed & HID_CLAIMED_HIDRAW) {
|
||||
ret = hidraw_report_event(hid, data, size);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (a = 0; a < report->maxfield; a++)
|
||||
hid_input_field(hid, report->field[a], cdata, interrupt);
|
||||
|
||||
if (hid->claimed & HID_CLAIMED_INPUT)
|
||||
hidinput_report_event(hid, report);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_report_raw_event);
|
||||
|
||||
|
@ -1264,7 +1277,7 @@ nomem:
|
|||
}
|
||||
}
|
||||
|
||||
hid_report_raw_event(hid, type, data, size, interrupt);
|
||||
ret = hid_report_raw_event(hid, type, data, size, interrupt);
|
||||
|
||||
unlock:
|
||||
up(&hid->driver_lock);
|
||||
|
@ -1496,6 +1509,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2), },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
|
||||
|
@ -1631,6 +1645,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
|
||||
|
|
|
@ -154,6 +154,9 @@
|
|||
#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
|
||||
#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118
|
||||
|
||||
#define USB_VENDOR_ID_AUREAL 0x0755
|
||||
#define USB_DEVICE_ID_AUREAL_W01RN 0x2626
|
||||
|
||||
#define USB_VENDOR_ID_AVERMEDIA 0x07ca
|
||||
#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
|
||||
|
||||
|
@ -729,6 +732,7 @@
|
|||
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
|
||||
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
|
||||
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
|
||||
#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
|
||||
|
||||
#define USB_VENDOR_ID_UNITEC 0x227d
|
||||
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
|
@ -352,9 +353,125 @@ static __u8 pf1209_rdesc_fixed[] = {
|
|||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
/*
|
||||
* See TWHL850 description, device and HID report descriptors at
|
||||
* http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
|
||||
*/
|
||||
|
||||
/* Size of the original descriptors of TWHL850 tablet */
|
||||
#define TWHL850_RDESC_ORIG_SIZE0 182
|
||||
#define TWHL850_RDESC_ORIG_SIZE1 161
|
||||
#define TWHL850_RDESC_ORIG_SIZE2 92
|
||||
|
||||
/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
|
||||
static __u8 twhl850_rdesc_fixed0[] = {
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x09, 0x02, /* Usage (Pen), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x09, /* Report ID (9), */
|
||||
0x09, 0x20, /* Usage (Stylus), */
|
||||
0xA0, /* Collection (Physical), */
|
||||
0x14, /* Logical Minimum (0), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x09, 0x42, /* Usage (Tip Switch), */
|
||||
0x09, 0x44, /* Usage (Barrel Switch), */
|
||||
0x09, 0x46, /* Usage (Tablet Pick), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x09, 0x32, /* Usage (In Range), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0xA4, /* Push, */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x65, 0x13, /* Unit (Inch), */
|
||||
0x55, 0xFD, /* Unit Exponent (-3), */
|
||||
0x34, /* Physical Minimum (0), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
|
||||
0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x46, 0x88, 0x13, /* Physical Maximum (5000), */
|
||||
0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xB4, /* Pop, */
|
||||
0x09, 0x30, /* Usage (Tip Pressure), */
|
||||
0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
|
||||
static __u8 twhl850_rdesc_fixed1[] = {
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x09, 0x02, /* Usage (Mouse), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x01, /* Report ID (1), */
|
||||
0x09, 0x01, /* Usage (Pointer), */
|
||||
0xA0, /* Collection (Physical), */
|
||||
0x05, 0x09, /* Usage Page (Button), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x19, 0x01, /* Usage Minimum (01h), */
|
||||
0x29, 0x03, /* Usage Maximum (03h), */
|
||||
0x14, /* Logical Minimum (0), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x05, /* Report Count (5), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x16, 0x00, 0x80, /* Logical Minimum (-32768), */
|
||||
0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x81, 0x06, /* Input (Variable, Relative), */
|
||||
0x09, 0x38, /* Usage (Wheel), */
|
||||
0x15, 0xFF, /* Logical Minimum (-1), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x81, 0x06, /* Input (Variable, Relative), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
|
||||
static __u8 twhl850_rdesc_fixed2[] = {
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x09, 0x06, /* Usage (Keyboard), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x03, /* Report ID (3), */
|
||||
0x05, 0x07, /* Usage Page (Keyboard), */
|
||||
0x14, /* Logical Minimum (0), */
|
||||
0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
|
||||
0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x08, /* Report Count (8), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x18, /* Usage Minimum (None), */
|
||||
0x29, 0xFF, /* Usage Maximum (FFh), */
|
||||
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x95, 0x06, /* Report Count (6), */
|
||||
0x80, /* Input, */
|
||||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
|
||||
__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
|
||||
|
||||
switch (hdev->product) {
|
||||
case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
|
||||
if (*rsize == PF1209_RDESC_ORIG_SIZE) {
|
||||
|
@ -386,6 +503,28 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||
*rsize = sizeof(wp1062_rdesc_fixed);
|
||||
}
|
||||
break;
|
||||
case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
|
||||
switch (iface_num) {
|
||||
case 0:
|
||||
if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
|
||||
rdesc = twhl850_rdesc_fixed0;
|
||||
*rsize = sizeof(twhl850_rdesc_fixed0);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
|
||||
rdesc = twhl850_rdesc_fixed1;
|
||||
*rsize = sizeof(twhl850_rdesc_fixed1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
|
||||
rdesc = twhl850_rdesc_fixed2;
|
||||
*rsize = sizeof(twhl850_rdesc_fixed2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return rdesc;
|
||||
|
@ -402,6 +541,8 @@ static const struct hid_device_id uclogic_devices[] = {
|
|||
USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
|
||||
USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
|
||||
USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, uclogic_devices);
|
||||
|
|
|
@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
|
|||
len = list->buffer[list->tail].len > count ?
|
||||
count : list->buffer[list->tail].len;
|
||||
|
||||
if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
if (list->buffer[list->tail].value) {
|
||||
if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
ret = len;
|
||||
}
|
||||
ret = len;
|
||||
|
||||
kfree(list->buffer[list->tail].value);
|
||||
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
|
||||
|
@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = {
|
|||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
|
||||
int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
|
||||
{
|
||||
struct hidraw *dev = hid->hidraw;
|
||||
struct hidraw_list *list;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each_entry(list, &dev->list, node) {
|
||||
list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
|
||||
if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
list->buffer[list->head].len = len;
|
||||
list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
wake_up_interruptible(&dev->wait);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hidraw_report_event);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
|
@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid)
|
|||
!test_bit(HID_REPORTED_IDLE, &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->lock, flags);
|
||||
return rc;
|
||||
|
@ -173,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;
|
||||
}
|
||||
|
@ -700,7 +708,7 @@ 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++) {
|
||||
|
@ -708,17 +716,27 @@ int usbhid_open(struct hid_device *hid)
|
|||
/* the device must be awake to reliably request remote wakeup */
|
||||
if (res < 0) {
|
||||
hid->open--;
|
||||
mutex_unlock(&hid_open_mut);
|
||||
return -EIO;
|
||||
res = -EIO;
|
||||
goto done;
|
||||
}
|
||||
usbhid->intf->needs_remote_wakeup = 1;
|
||||
if (hid_start_in(hid))
|
||||
hid_io_error(hid);
|
||||
|
||||
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);
|
||||
}
|
||||
done:
|
||||
mutex_unlock(&hid_open_mut);
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
void usbhid_close(struct hid_device *hid)
|
||||
|
@ -1347,7 +1365,34 @@ static int hid_post_reset(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;
|
||||
struct usb_host_interface *interface = intf->cur_altsetting;
|
||||
int status;
|
||||
char *rdesc;
|
||||
|
||||
/* 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->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->rsize);
|
||||
if (status < 0) {
|
||||
dbg_hid("reading report descriptor failed (post_reset)\n");
|
||||
kfree(rdesc);
|
||||
return 1;
|
||||
}
|
||||
status = memcmp(rdesc, hid->rdesc, hid->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);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/hiddev.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include "usbhid.h"
|
||||
|
||||
#ifdef CONFIG_USB_DYNAMIC_MINORS
|
||||
|
@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file)
|
|||
} else {
|
||||
mutex_unlock(&list->hiddev->existancelock);
|
||||
kfree(list->hiddev);
|
||||
kfree(list);
|
||||
vfree(list);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&list->hiddev->existancelock);
|
||||
kfree(list);
|
||||
vfree(list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
|
|||
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;
|
||||
|
@ -322,7 +323,7 @@ bail_unlock:
|
|||
mutex_unlock(&hiddev->existancelock);
|
||||
bail:
|
||||
file->private_data = NULL;
|
||||
kfree(list);
|
||||
vfree(list);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor);
|
|||
#define HID_STARTED 8
|
||||
#define HID_REPORTED_IDLE 9
|
||||
#define HID_KEYS_PRESSED 10
|
||||
#define HID_NO_BANDWIDTH 11
|
||||
|
||||
/*
|
||||
* USB-specific HID struct, to be pointed to
|
||||
|
|
|
@ -896,7 +896,7 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
|
|||
return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
|
||||
}
|
||||
|
||||
void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||||
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||||
int interrupt);
|
||||
|
||||
extern int hid_generic_init(void);
|
||||
|
|
|
@ -76,13 +76,13 @@ struct hidraw_list {
|
|||
#ifdef CONFIG_HIDRAW
|
||||
int hidraw_init(void);
|
||||
void hidraw_exit(void);
|
||||
void hidraw_report_event(struct hid_device *, u8 *, int);
|
||||
int hidraw_report_event(struct hid_device *, u8 *, int);
|
||||
int hidraw_connect(struct hid_device *);
|
||||
void hidraw_disconnect(struct hid_device *);
|
||||
#else
|
||||
static inline int hidraw_init(void) { return 0; }
|
||||
static inline void hidraw_exit(void) { }
|
||||
static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
|
||||
static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; }
|
||||
static inline int hidraw_connect(struct hid_device *hid) { return -1; }
|
||||
static inline void hidraw_disconnect(struct hid_device *hid) { }
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче