Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: HID: Suppress hidinput for Samsung IR control HID: remove 60x GTCO devices from blacklist HID: export headers properly HID: WiseGroup 866 Dual Joypad needs output reports quirk HID: ThrustMaster FF driver is no longer experimental HID: Logitech diNovo Mini pad support HID: fix race between open() and disconnect() in usbhid HID: make hid_input_field and usbhid_modify_dquirk static HID: pass numbered reports properly to hidraw HID: fix misplaced rdesc quirk HID: force feedback driver for Logitech Rumblepad 2 HID: move wait from hid to usbhid HID: make function from dbg_hid HID: fix sparse warnings HID: only dump report traffic with debug level 2 HID: patch to add NOGET for DMI/Acomdata HID: Sunplus Wireless Desktop needs report descriptor fixup HID: quirk for MS Wireless Desktop Receiver (model 1028) HID: fixup fullspeed interval on highspeed Afatech DVB-T IR kbd HID: fix build failure in hiddev_ioctl with gcc 3.2
This commit is contained in:
Коммит
0d07a15bdb
|
@ -44,8 +44,8 @@
|
|||
|
||||
#ifdef CONFIG_HID_DEBUG
|
||||
int hid_debug = 0;
|
||||
module_param_named(debug, hid_debug, bool, 0600);
|
||||
MODULE_PARM_DESC(debug, "Turn HID debugging mode on and off");
|
||||
module_param_named(debug, hid_debug, int, 0600);
|
||||
MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)");
|
||||
EXPORT_SYMBOL_GPL(hid_debug);
|
||||
#endif
|
||||
|
||||
|
@ -97,7 +97,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
|
|||
field->index = report->maxfield++;
|
||||
report->field[field->index] = field;
|
||||
field->usage = (struct hid_usage *)(field + 1);
|
||||
field->value = (unsigned *)(field->usage + usages);
|
||||
field->value = (s32 *)(field->usage + usages);
|
||||
field->report = report;
|
||||
|
||||
return field;
|
||||
|
@ -830,7 +830,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
|
|||
* reporting to the layer).
|
||||
*/
|
||||
|
||||
void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
|
||||
static void hid_input_field(struct hid_device *hid, struct hid_field *field,
|
||||
__u8 *data, int interrupt)
|
||||
{
|
||||
unsigned n;
|
||||
unsigned count = field->report_count;
|
||||
|
@ -876,7 +877,6 @@ void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data
|
|||
exit:
|
||||
kfree(value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_input_field);
|
||||
|
||||
/*
|
||||
* Output the field into the report.
|
||||
|
@ -988,8 +988,13 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
|
|||
|
||||
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) {
|
||||
/* numbered reports need to be passed with the report num */
|
||||
if (report_enum->numbered)
|
||||
hidraw_report_event(hid, data - 1, size + 1);
|
||||
else
|
||||
hidraw_report_event(hid, data, size);
|
||||
}
|
||||
|
||||
for (n = 0; n < report->maxfield; n++)
|
||||
hid_input_field(hid, report->field[n], data, interrupt);
|
||||
|
|
|
@ -498,7 +498,7 @@ void hid_dump_device(struct hid_device *device) {
|
|||
EXPORT_SYMBOL_GPL(hid_dump_device);
|
||||
|
||||
void hid_dump_input(struct hid_usage *usage, __s32 value) {
|
||||
if (!hid_debug)
|
||||
if (hid_debug < 2)
|
||||
return;
|
||||
|
||||
printk(KERN_DEBUG "hid-debug: input ");
|
||||
|
|
|
@ -276,6 +276,21 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int quirk_sunplus_wdesktop(struct hid_usage *usage, struct input_dev *input,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
|
||||
return 0;
|
||||
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case 0x2003: map_key_clear(KEY_ZOOMIN); break;
|
||||
case 0x2103: map_key_clear(KEY_ZOOMOUT); break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define VENDOR_ID_BELKIN 0x1020
|
||||
#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006
|
||||
|
||||
|
@ -306,6 +321,9 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
|
|||
#define VENDOR_ID_PETALYNX 0x18b1
|
||||
#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
|
||||
|
||||
#define VENDOR_ID_SUNPLUS 0x04fc
|
||||
#define DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
|
||||
|
||||
static const struct hid_input_blacklist {
|
||||
__u16 idVendor;
|
||||
__u16 idProduct;
|
||||
|
@ -332,8 +350,10 @@ static const struct hid_input_blacklist {
|
|||
{ VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e },
|
||||
|
||||
{ VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
|
||||
|
||||
{ 0, 0, 0 }
|
||||
|
||||
{ VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop },
|
||||
|
||||
{ 0, 0, NULL }
|
||||
};
|
||||
|
||||
int hidinput_mapping_quirks(struct hid_usage *usage,
|
||||
|
|
|
@ -71,6 +71,14 @@ config LOGITECH_FF
|
|||
Note: if you say N here, this device will still be supported, but without
|
||||
force feedback.
|
||||
|
||||
config LOGIRUMBLEPAD2_FF
|
||||
bool "Logitech Rumblepad 2 support"
|
||||
depends on HID_FF
|
||||
select INPUT_FF_MEMLESS if USB_HID
|
||||
help
|
||||
Say Y here if you want to enable force feedback support for Logitech
|
||||
Rumblepad 2 devices.
|
||||
|
||||
config PANTHERLORD_FF
|
||||
bool "PantherLord/GreenAsia based device support"
|
||||
depends on HID_FF
|
||||
|
@ -80,8 +88,8 @@ config PANTHERLORD_FF
|
|||
or adapter and want to enable force feedback support for it.
|
||||
|
||||
config THRUSTMASTER_FF
|
||||
bool "ThrustMaster devices support (EXPERIMENTAL)"
|
||||
depends on HID_FF && EXPERIMENTAL
|
||||
bool "ThrustMaster devices support"
|
||||
depends on HID_FF
|
||||
select INPUT_FF_MEMLESS if USB_HID
|
||||
help
|
||||
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
|
||||
|
|
|
@ -16,6 +16,9 @@ endif
|
|||
ifeq ($(CONFIG_LOGITECH_FF),y)
|
||||
usbhid-objs += hid-lgff.o
|
||||
endif
|
||||
ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y)
|
||||
usbhid-objs += hid-lg2ff.o
|
||||
endif
|
||||
ifeq ($(CONFIG_PANTHERLORD_FF),y)
|
||||
usbhid-objs += hid-plff.o
|
||||
endif
|
||||
|
|
|
@ -82,6 +82,7 @@ static int hid_start_in(struct hid_device *hid)
|
|||
|
||||
spin_lock_irqsave(&usbhid->inlock, flags);
|
||||
if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
|
||||
!test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
|
||||
!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
|
||||
rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
|
||||
if (rc != 0)
|
||||
|
@ -155,7 +156,7 @@ static void hid_io_error(struct hid_device *hid)
|
|||
spin_lock_irqsave(&usbhid->inlock, flags);
|
||||
|
||||
/* Stop when disconnected */
|
||||
if (usb_get_intfdata(usbhid->intf) == NULL)
|
||||
if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
|
||||
goto done;
|
||||
|
||||
/* If it has been a while since the last error, we'll assume
|
||||
|
@ -341,7 +342,7 @@ static void hid_irq_out(struct urb *urb)
|
|||
if (usbhid->outhead != usbhid->outtail) {
|
||||
if (hid_submit_out(hid)) {
|
||||
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
||||
wake_up(&hid->wait);
|
||||
wake_up(&usbhid->wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&usbhid->outlock, flags);
|
||||
return;
|
||||
|
@ -349,7 +350,7 @@ static void hid_irq_out(struct urb *urb)
|
|||
|
||||
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
||||
spin_unlock_irqrestore(&usbhid->outlock, flags);
|
||||
wake_up(&hid->wait);
|
||||
wake_up(&usbhid->wait);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -391,7 +392,7 @@ static void hid_ctrl(struct urb *urb)
|
|||
if (usbhid->ctrlhead != usbhid->ctrltail) {
|
||||
if (hid_submit_ctrl(hid)) {
|
||||
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
||||
wake_up(&hid->wait);
|
||||
wake_up(&usbhid->wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
|
||||
return;
|
||||
|
@ -399,7 +400,7 @@ static void hid_ctrl(struct urb *urb)
|
|||
|
||||
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
||||
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
|
||||
wake_up(&hid->wait);
|
||||
wake_up(&usbhid->wait);
|
||||
}
|
||||
|
||||
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
|
||||
|
@ -478,8 +479,9 @@ int usbhid_wait_io(struct hid_device *hid)
|
|||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
|
||||
if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
|
||||
!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
|
||||
if (!wait_event_timeout(usbhid->wait,
|
||||
(!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
|
||||
!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
|
||||
10*HZ)) {
|
||||
dbg_hid("timeout waiting for ctrl or out queue to clear\n");
|
||||
return -1;
|
||||
|
@ -610,10 +612,11 @@ static void usbhid_set_leds(struct hid_device *hid)
|
|||
/*
|
||||
* Traverse the supplied list of reports and find the longest
|
||||
*/
|
||||
static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
|
||||
static void hid_find_max_report(struct hid_device *hid, unsigned int type,
|
||||
unsigned int *max)
|
||||
{
|
||||
struct hid_report *report;
|
||||
int size;
|
||||
unsigned int size;
|
||||
|
||||
list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
|
||||
size = ((report->size - 1) >> 3) + 1;
|
||||
|
@ -705,9 +708,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|||
struct hid_descriptor *hdesc;
|
||||
struct hid_device *hid;
|
||||
u32 quirks = 0;
|
||||
unsigned rsize = 0;
|
||||
unsigned int insize = 0, rsize = 0;
|
||||
char *rdesc;
|
||||
int n, len, insize = 0;
|
||||
int n, len;
|
||||
struct usbhid_device *usbhid;
|
||||
|
||||
quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
|
||||
|
@ -800,6 +803,22 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
hid->name[0] = 0;
|
||||
|
||||
if (dev->manufacturer)
|
||||
strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
|
||||
|
||||
if (dev->product) {
|
||||
if (dev->manufacturer)
|
||||
strlcat(hid->name, " ", sizeof(hid->name));
|
||||
strlcat(hid->name, dev->product, sizeof(hid->name));
|
||||
}
|
||||
|
||||
if (!strlen(hid->name))
|
||||
snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
|
||||
for (n = 0; n < interface->desc.bNumEndpoints; n++) {
|
||||
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
|
@ -812,6 +831,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|||
|
||||
interval = endpoint->bInterval;
|
||||
|
||||
/* Some vendors give fullspeed interval on highspeed devides */
|
||||
if (quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
|
||||
dev->speed == USB_SPEED_HIGH) {
|
||||
interval = fls(endpoint->bInterval*8);
|
||||
printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
|
||||
hid->name, endpoint->bInterval, interval);
|
||||
}
|
||||
|
||||
/* Change the polling interval of mice. */
|
||||
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
|
||||
interval = hid_mousepoll_interval;
|
||||
|
@ -844,8 +871,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&hid->wait);
|
||||
|
||||
init_waitqueue_head(&usbhid->wait);
|
||||
INIT_WORK(&usbhid->reset_work, hid_reset);
|
||||
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
|
||||
|
||||
|
@ -859,22 +885,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
|||
usbhid->intf = intf;
|
||||
usbhid->ifnum = interface->desc.bInterfaceNumber;
|
||||
|
||||
hid->name[0] = 0;
|
||||
|
||||
if (dev->manufacturer)
|
||||
strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
|
||||
|
||||
if (dev->product) {
|
||||
if (dev->manufacturer)
|
||||
strlcat(hid->name, " ", sizeof(hid->name));
|
||||
strlcat(hid->name, dev->product, sizeof(hid->name));
|
||||
}
|
||||
|
||||
if (!strlen(hid->name))
|
||||
snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
|
||||
le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
|
||||
hid->bus = BUS_USB;
|
||||
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
|
||||
hid->product = le16_to_cpu(dev->descriptor.idProduct);
|
||||
|
@ -932,6 +942,7 @@ static void hid_disconnect(struct usb_interface *intf)
|
|||
|
||||
spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
|
||||
usb_set_intfdata(intf, NULL);
|
||||
set_bit(HID_DISCONNECTED, &usbhid->iofl);
|
||||
spin_unlock_irq(&usbhid->inlock);
|
||||
usb_kill_urb(usbhid->urbin);
|
||||
usb_kill_urb(usbhid->urbout);
|
||||
|
|
|
@ -59,6 +59,9 @@ static struct hid_ff_initializer inits[] = {
|
|||
{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
|
||||
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
|
||||
#endif
|
||||
#ifdef CONFIG_LOGIRUMBLEPAD2_FF
|
||||
{ 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */
|
||||
#endif
|
||||
#ifdef CONFIG_PANTHERLORD_FF
|
||||
{ 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
|
||||
{ 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Force feedback support for Logitech Rumblepad 2
|
||||
*
|
||||
* Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
#include "usbhid.h"
|
||||
|
||||
struct lg2ff_device {
|
||||
struct hid_report *report;
|
||||
};
|
||||
|
||||
static int play_effect(struct input_dev *dev, void *data,
|
||||
struct ff_effect *effect)
|
||||
{
|
||||
struct hid_device *hid = input_get_drvdata(dev);
|
||||
struct lg2ff_device *lg2ff = data;
|
||||
int weak, strong;
|
||||
|
||||
strong = effect->u.rumble.strong_magnitude;
|
||||
weak = effect->u.rumble.weak_magnitude;
|
||||
|
||||
if (weak || strong) {
|
||||
weak = weak * 0xff / 0xffff;
|
||||
strong = strong * 0xff / 0xffff;
|
||||
|
||||
lg2ff->report->field[0]->value[0] = 0x51;
|
||||
lg2ff->report->field[0]->value[2] = weak;
|
||||
lg2ff->report->field[0]->value[4] = strong;
|
||||
} else {
|
||||
lg2ff->report->field[0]->value[0] = 0xf3;
|
||||
lg2ff->report->field[0]->value[2] = 0x00;
|
||||
lg2ff->report->field[0]->value[4] = 0x00;
|
||||
}
|
||||
|
||||
usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hid_lg2ff_init(struct hid_device *hid)
|
||||
{
|
||||
struct lg2ff_device *lg2ff;
|
||||
struct hid_report *report;
|
||||
struct hid_input *hidinput = list_entry(hid->inputs.next,
|
||||
struct hid_input, list);
|
||||
struct list_head *report_list =
|
||||
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct input_dev *dev = hidinput->input;
|
||||
int error;
|
||||
|
||||
if (list_empty(report_list)) {
|
||||
printk(KERN_ERR "hid-lg2ff: no output report found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
report = list_entry(report_list->next, struct hid_report, list);
|
||||
|
||||
if (report->maxfield < 1) {
|
||||
printk(KERN_ERR "hid-lg2ff: output report is empty\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (report->field[0]->report_count < 7) {
|
||||
printk(KERN_ERR "hid-lg2ff: not enough values in the field\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
|
||||
if (!lg2ff)
|
||||
return -ENOMEM;
|
||||
|
||||
set_bit(FF_RUMBLE, dev->ffbit);
|
||||
|
||||
error = input_ff_create_memless(dev, lg2ff, play_effect);
|
||||
if (error) {
|
||||
kfree(lg2ff);
|
||||
return error;
|
||||
}
|
||||
|
||||
lg2ff->report = report;
|
||||
report->field[0]->value[0] = 0xf3;
|
||||
report->field[0]->value[1] = 0x00;
|
||||
report->field[0]->value[2] = 0x00;
|
||||
report->field[0]->value[3] = 0x00;
|
||||
report->field[0]->value[4] = 0x00;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
|
||||
printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by "
|
||||
"Anssi Hannula <anssi.hannula@gmail.com>\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -32,6 +32,9 @@
|
|||
#define USB_VENDOR_ID_ADS_TECH 0x06e1
|
||||
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
|
||||
|
||||
#define USB_VENDOR_ID_AFATECH 0x15a4
|
||||
#define USB_DEVICE_ID_AFATECH_AF9016 0x9016
|
||||
|
||||
#define USB_VENDOR_ID_AIPTEK 0x08ca
|
||||
#define USB_DEVICE_ID_AIPTEK_01 0x0001
|
||||
#define USB_DEVICE_ID_AIPTEK_10 0x0010
|
||||
|
@ -124,6 +127,9 @@
|
|||
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
|
||||
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
|
||||
|
||||
#define USB_VENDOR_ID_DMI 0x0c0b
|
||||
#define USB_DEVICE_ID_DMI_ENC 0x5fab
|
||||
|
||||
#define USB_VENDOR_ID_ELO 0x04E7
|
||||
#define USB_DEVICE_ID_ELO_TS2700 0x0020
|
||||
|
||||
|
@ -199,17 +205,6 @@
|
|||
#define USB_DEVICE_ID_GTCO_502 0x0502
|
||||
#define USB_DEVICE_ID_GTCO_503 0x0503
|
||||
#define USB_DEVICE_ID_GTCO_504 0x0504
|
||||
#define USB_DEVICE_ID_GTCO_600 0x0600
|
||||
#define USB_DEVICE_ID_GTCO_601 0x0601
|
||||
#define USB_DEVICE_ID_GTCO_602 0x0602
|
||||
#define USB_DEVICE_ID_GTCO_603 0x0603
|
||||
#define USB_DEVICE_ID_GTCO_604 0x0604
|
||||
#define USB_DEVICE_ID_GTCO_605 0x0605
|
||||
#define USB_DEVICE_ID_GTCO_606 0x0606
|
||||
#define USB_DEVICE_ID_GTCO_607 0x0607
|
||||
#define USB_DEVICE_ID_GTCO_608 0x0608
|
||||
#define USB_DEVICE_ID_GTCO_609 0x0609
|
||||
#define USB_DEVICE_ID_GTCO_609 0x0609
|
||||
#define USB_DEVICE_ID_GTCO_1000 0x1000
|
||||
#define USB_DEVICE_ID_GTCO_1001 0x1001
|
||||
#define USB_DEVICE_ID_GTCO_1002 0x1002
|
||||
|
@ -320,6 +315,7 @@
|
|||
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
|
||||
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
|
||||
#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
|
||||
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
|
||||
|
||||
#define USB_VENDOR_ID_MCC 0x09db
|
||||
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
|
||||
|
@ -332,6 +328,7 @@
|
|||
#define USB_VENDOR_ID_MICROSOFT 0x045e
|
||||
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
|
||||
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
|
||||
#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9
|
||||
#define USB_DEVICE_ID_MS_NE4K 0x00db
|
||||
#define USB_DEVICE_ID_MS_LK6K 0x00f9
|
||||
|
||||
|
@ -377,6 +374,9 @@
|
|||
#define USB_VENDOR_ID_SUN 0x0430
|
||||
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
|
||||
|
||||
#define USB_VENDOR_ID_SUNPLUS 0x04fc
|
||||
#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
|
||||
|
||||
#define USB_VENDOR_ID_TOPMAX 0x0663
|
||||
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
|
||||
|
||||
|
@ -435,9 +435,13 @@ static const struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
|
||||
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI, HID_QUIRK_DUPLICATE_USAGES },
|
||||
|
||||
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
|
||||
|
||||
{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
|
||||
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
|
||||
{ USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
|
||||
|
||||
{ USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
|
||||
|
@ -518,16 +522,6 @@ static const struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_600, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_601, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_602, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_603, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_604, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_605, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_606, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_607, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_608, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_609, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
|
||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
|
||||
|
@ -601,6 +595,7 @@ static const struct hid_blacklist {
|
|||
{ 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_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
|
||||
|
@ -608,7 +603,7 @@ static const struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | 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_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 },
|
||||
|
@ -719,6 +714,7 @@ static const struct hid_rdesc_blacklist {
|
|||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 },
|
||||
|
||||
{ USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER },
|
||||
|
||||
|
@ -728,6 +724,8 @@ static const struct hid_rdesc_blacklist {
|
|||
|
||||
{ USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE },
|
||||
|
||||
{ USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP },
|
||||
|
||||
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
|
||||
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
|
||||
|
||||
|
@ -793,8 +791,8 @@ static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
|
|||
*
|
||||
* Returns: 0 OK, -error on failure.
|
||||
*/
|
||||
int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
|
||||
const u32 quirks)
|
||||
static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
|
||||
const u32 quirks)
|
||||
{
|
||||
struct quirks_list_struct *q_new, *q;
|
||||
int list_edited = 0;
|
||||
|
@ -1002,6 +1000,17 @@ static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
|
|||
}
|
||||
}
|
||||
|
||||
static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize)
|
||||
{
|
||||
if (rsize >= 107 && rdesc[104] == 0x26
|
||||
&& rdesc[105] == 0x80
|
||||
&& rdesc[106] == 0x03) {
|
||||
printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n");
|
||||
rdesc[105] = rdesc[110] = 0x03;
|
||||
rdesc[106] = rdesc[111] = 0x21;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Samsung IrDA remote controller (reports as Cypress USB Mouse).
|
||||
*
|
||||
|
@ -1089,6 +1098,28 @@ static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rs
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Microsoft Wireless Desktop Receiver (Model 1028) has several
|
||||
* 'Usage Min/Max' where it ought to have 'Physical Min/Max'
|
||||
*/
|
||||
static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize)
|
||||
{
|
||||
if (rsize == 571 && rdesc[284] == 0x19
|
||||
&& rdesc[286] == 0x2a
|
||||
&& rdesc[304] == 0x19
|
||||
&& rdesc[306] == 0x29
|
||||
&& rdesc[352] == 0x1a
|
||||
&& rdesc[355] == 0x2a
|
||||
&& rdesc[557] == 0x19
|
||||
&& rdesc[559] == 0x29) {
|
||||
printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
|
||||
rdesc[284] = rdesc[304] = rdesc[558] = 0x35;
|
||||
rdesc[352] = 0x36;
|
||||
rdesc[286] = rdesc[355] = 0x46;
|
||||
rdesc[306] = rdesc[559] = 0x45;
|
||||
}
|
||||
}
|
||||
|
||||
static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
|
||||
{
|
||||
if ((quirks & HID_QUIRK_RDESC_CYMOTION))
|
||||
|
@ -1112,6 +1143,11 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
|
|||
if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
|
||||
usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
|
||||
|
||||
if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028)
|
||||
usbhid_fixup_microsoft_descriptor(rdesc, rsize);
|
||||
|
||||
if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP)
|
||||
usbhid_fixup_sunplus_wdesktop(rdesc, rsize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1150,5 +1186,4 @@ void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct,
|
|||
else if (paramVendor == idVendor && paramProduct == idProduct)
|
||||
__usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
|
|||
/*
|
||||
* "ioctl" file op
|
||||
*/
|
||||
static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
|
||||
{
|
||||
struct hid_device *hid = hiddev->hid;
|
||||
struct hiddev_report_info rinfo;
|
||||
struct hiddev_usage_ref_multi *uref_multi = NULL;
|
||||
struct hiddev_usage_ref *uref;
|
||||
struct hid_report *report;
|
||||
struct hid_field *field;
|
||||
int i;
|
||||
|
||||
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
|
||||
if (!uref_multi)
|
||||
return -ENOMEM;
|
||||
uref = &uref_multi->uref;
|
||||
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
|
||||
if (copy_from_user(uref_multi, user_arg,
|
||||
sizeof(*uref_multi)))
|
||||
goto fault;
|
||||
} else {
|
||||
if (copy_from_user(uref, user_arg, sizeof(*uref)))
|
||||
goto fault;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case HIDIOCGUCODE:
|
||||
rinfo.report_type = uref->report_type;
|
||||
rinfo.report_id = uref->report_id;
|
||||
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
|
||||
goto inval;
|
||||
|
||||
if (uref->field_index >= report->maxfield)
|
||||
goto inval;
|
||||
|
||||
field = report->field[uref->field_index];
|
||||
if (uref->usage_index >= field->maxusage)
|
||||
goto inval;
|
||||
|
||||
uref->usage_code = field->usage[uref->usage_index].hid;
|
||||
|
||||
if (copy_to_user(user_arg, uref, sizeof(*uref)))
|
||||
goto fault;
|
||||
|
||||
kfree(uref_multi);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
if (cmd != HIDIOCGUSAGE &&
|
||||
cmd != HIDIOCGUSAGES &&
|
||||
uref->report_type == HID_REPORT_TYPE_INPUT)
|
||||
goto inval;
|
||||
|
||||
if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
|
||||
field = hiddev_lookup_usage(hid, uref);
|
||||
if (field == NULL)
|
||||
goto inval;
|
||||
} else {
|
||||
rinfo.report_type = uref->report_type;
|
||||
rinfo.report_id = uref->report_id;
|
||||
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
|
||||
goto inval;
|
||||
|
||||
if (uref->field_index >= report->maxfield)
|
||||
goto inval;
|
||||
|
||||
field = report->field[uref->field_index];
|
||||
|
||||
if (cmd == HIDIOCGCOLLECTIONINDEX) {
|
||||
if (uref->usage_index >= field->maxusage)
|
||||
goto inval;
|
||||
} else if (uref->usage_index >= field->report_count)
|
||||
goto inval;
|
||||
|
||||
else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
|
||||
(uref_multi->num_values > HID_MAX_MULTI_USAGES ||
|
||||
uref->usage_index + uref_multi->num_values > field->report_count))
|
||||
goto inval;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case HIDIOCGUSAGE:
|
||||
uref->value = field->value[uref->usage_index];
|
||||
if (copy_to_user(user_arg, uref, sizeof(*uref)))
|
||||
goto fault;
|
||||
goto goodreturn;
|
||||
|
||||
case HIDIOCSUSAGE:
|
||||
field->value[uref->usage_index] = uref->value;
|
||||
goto goodreturn;
|
||||
|
||||
case HIDIOCGCOLLECTIONINDEX:
|
||||
kfree(uref_multi);
|
||||
return field->usage[uref->usage_index].collection_index;
|
||||
case HIDIOCGUSAGES:
|
||||
for (i = 0; i < uref_multi->num_values; i++)
|
||||
uref_multi->values[i] =
|
||||
field->value[uref->usage_index + i];
|
||||
if (copy_to_user(user_arg, uref_multi,
|
||||
sizeof(*uref_multi)))
|
||||
goto fault;
|
||||
goto goodreturn;
|
||||
case HIDIOCSUSAGES:
|
||||
for (i = 0; i < uref_multi->num_values; i++)
|
||||
field->value[uref->usage_index + i] =
|
||||
uref_multi->values[i];
|
||||
goto goodreturn;
|
||||
}
|
||||
|
||||
goodreturn:
|
||||
kfree(uref_multi);
|
||||
return 0;
|
||||
fault:
|
||||
kfree(uref_multi);
|
||||
return -EFAULT;
|
||||
inval:
|
||||
kfree(uref_multi);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
|
||||
{
|
||||
struct hid_device *hid = hiddev->hid;
|
||||
struct usb_device *dev = hid_to_usb_dev(hid);
|
||||
int idx, len;
|
||||
char *buf;
|
||||
|
||||
if (get_user(idx, (int __user *)user_arg))
|
||||
return -EFAULT;
|
||||
|
||||
if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
|
||||
kfree(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
|
||||
kfree(buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct hiddev_list *list = file->private_data;
|
||||
|
@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
|
|||
struct hiddev_collection_info cinfo;
|
||||
struct hiddev_report_info rinfo;
|
||||
struct hiddev_field_info finfo;
|
||||
struct hiddev_usage_ref_multi *uref_multi = NULL;
|
||||
struct hiddev_usage_ref *uref;
|
||||
struct hiddev_devinfo dinfo;
|
||||
struct hid_report *report;
|
||||
struct hid_field *field;
|
||||
|
@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
|
|||
}
|
||||
|
||||
case HIDIOCGSTRING:
|
||||
{
|
||||
int idx, len;
|
||||
char *buf;
|
||||
|
||||
if (get_user(idx, (int __user *)arg))
|
||||
return -EFAULT;
|
||||
|
||||
if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
|
||||
kfree(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
|
||||
kfree(buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return len;
|
||||
}
|
||||
return hiddev_ioctl_string(hiddev, cmd, user_arg);
|
||||
|
||||
case HIDIOCINITREPORT:
|
||||
usbhid_init_reports(hid);
|
||||
|
@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
|
|||
return 0;
|
||||
|
||||
case HIDIOCGUCODE:
|
||||
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
|
||||
if (!uref_multi)
|
||||
return -ENOMEM;
|
||||
uref = &uref_multi->uref;
|
||||
if (copy_from_user(uref, user_arg, sizeof(*uref)))
|
||||
goto fault;
|
||||
|
||||
rinfo.report_type = uref->report_type;
|
||||
rinfo.report_id = uref->report_id;
|
||||
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
|
||||
goto inval;
|
||||
|
||||
if (uref->field_index >= report->maxfield)
|
||||
goto inval;
|
||||
|
||||
field = report->field[uref->field_index];
|
||||
if (uref->usage_index >= field->maxusage)
|
||||
goto inval;
|
||||
|
||||
uref->usage_code = field->usage[uref->usage_index].hid;
|
||||
|
||||
if (copy_to_user(user_arg, uref, sizeof(*uref)))
|
||||
goto fault;
|
||||
|
||||
kfree(uref_multi);
|
||||
return 0;
|
||||
|
||||
/* fall through */
|
||||
case HIDIOCGUSAGE:
|
||||
case HIDIOCSUSAGE:
|
||||
case HIDIOCGUSAGES:
|
||||
case HIDIOCSUSAGES:
|
||||
case HIDIOCGCOLLECTIONINDEX:
|
||||
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
|
||||
if (!uref_multi)
|
||||
return -ENOMEM;
|
||||
uref = &uref_multi->uref;
|
||||
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
|
||||
if (copy_from_user(uref_multi, user_arg,
|
||||
sizeof(*uref_multi)))
|
||||
goto fault;
|
||||
} else {
|
||||
if (copy_from_user(uref, user_arg, sizeof(*uref)))
|
||||
goto fault;
|
||||
}
|
||||
|
||||
if (cmd != HIDIOCGUSAGE &&
|
||||
cmd != HIDIOCGUSAGES &&
|
||||
uref->report_type == HID_REPORT_TYPE_INPUT)
|
||||
goto inval;
|
||||
|
||||
if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
|
||||
field = hiddev_lookup_usage(hid, uref);
|
||||
if (field == NULL)
|
||||
goto inval;
|
||||
} else {
|
||||
rinfo.report_type = uref->report_type;
|
||||
rinfo.report_id = uref->report_id;
|
||||
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
|
||||
goto inval;
|
||||
|
||||
if (uref->field_index >= report->maxfield)
|
||||
goto inval;
|
||||
|
||||
field = report->field[uref->field_index];
|
||||
|
||||
if (cmd == HIDIOCGCOLLECTIONINDEX) {
|
||||
if (uref->usage_index >= field->maxusage)
|
||||
goto inval;
|
||||
} else if (uref->usage_index >= field->report_count)
|
||||
goto inval;
|
||||
|
||||
else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
|
||||
(uref_multi->num_values > HID_MAX_MULTI_USAGES ||
|
||||
uref->usage_index + uref_multi->num_values > field->report_count))
|
||||
goto inval;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case HIDIOCGUSAGE:
|
||||
uref->value = field->value[uref->usage_index];
|
||||
if (copy_to_user(user_arg, uref, sizeof(*uref)))
|
||||
goto fault;
|
||||
goto goodreturn;
|
||||
|
||||
case HIDIOCSUSAGE:
|
||||
field->value[uref->usage_index] = uref->value;
|
||||
goto goodreturn;
|
||||
|
||||
case HIDIOCGCOLLECTIONINDEX:
|
||||
kfree(uref_multi);
|
||||
return field->usage[uref->usage_index].collection_index;
|
||||
case HIDIOCGUSAGES:
|
||||
for (i = 0; i < uref_multi->num_values; i++)
|
||||
uref_multi->values[i] =
|
||||
field->value[uref->usage_index + i];
|
||||
if (copy_to_user(user_arg, uref_multi,
|
||||
sizeof(*uref_multi)))
|
||||
goto fault;
|
||||
goto goodreturn;
|
||||
case HIDIOCSUSAGES:
|
||||
for (i = 0; i < uref_multi->num_values; i++)
|
||||
field->value[uref->usage_index + i] =
|
||||
uref_multi->values[i];
|
||||
goto goodreturn;
|
||||
}
|
||||
|
||||
goodreturn:
|
||||
kfree(uref_multi);
|
||||
return 0;
|
||||
fault:
|
||||
kfree(uref_multi);
|
||||
return -EFAULT;
|
||||
inval:
|
||||
kfree(uref_multi);
|
||||
return -EINVAL;
|
||||
return hiddev_ioctl_usage(hiddev, cmd, user_arg);
|
||||
|
||||
case HIDIOCGCOLLECTIONINFO:
|
||||
if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
|
@ -77,7 +78,7 @@ struct usbhid_device {
|
|||
unsigned long stop_retry; /* Time to give up, in jiffies */
|
||||
unsigned int retry_delay; /* Delay length in ms */
|
||||
struct work_struct reset_work; /* Task context for resets */
|
||||
|
||||
wait_queue_head_t wait; /* For sleeping */
|
||||
};
|
||||
|
||||
#define hid_to_usb_dev(hid_dev) \
|
||||
|
|
|
@ -211,7 +211,9 @@ unifdef-y += hdlcdrv.h
|
|||
unifdef-y += hdlc.h
|
||||
unifdef-y += hdreg.h
|
||||
unifdef-y += hdsmart.h
|
||||
unifdef-y += hid.h
|
||||
unifdef-y += hiddev.h
|
||||
unifdef-y += hidraw.h
|
||||
unifdef-y += hpet.h
|
||||
unifdef-y += i2c.h
|
||||
unifdef-y += i2c-dev.h
|
||||
|
|
|
@ -284,6 +284,7 @@ struct hid_item {
|
|||
#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000
|
||||
#define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000
|
||||
#define HID_QUIRK_MICROSOFT_KEYS 0x08000000
|
||||
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
|
||||
|
||||
/*
|
||||
* Separate quirks for runtime report descriptor fixup
|
||||
|
@ -296,6 +297,8 @@ struct hid_item {
|
|||
#define HID_QUIRK_RDESC_MACBOOK_JIS 0x00000010
|
||||
#define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020
|
||||
#define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040
|
||||
#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080
|
||||
#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP 0x00000100
|
||||
|
||||
/*
|
||||
* This is the global environment of the parser. This information is
|
||||
|
@ -320,7 +323,7 @@ struct hid_global {
|
|||
* This is the local environment. It is persistent up the next main-item.
|
||||
*/
|
||||
|
||||
#define HID_MAX_USAGES 8192
|
||||
#define HID_MAX_USAGES 12288
|
||||
#define HID_DEFAULT_NUM_COLLECTIONS 16
|
||||
|
||||
struct hid_local {
|
||||
|
@ -421,6 +424,7 @@ struct hid_control_fifo {
|
|||
#define HID_RESET_PENDING 4
|
||||
#define HID_SUSPENDED 5
|
||||
#define HID_CLEAR_HALT 6
|
||||
#define HID_DISCONNECTED 7
|
||||
|
||||
struct hid_input {
|
||||
struct list_head list;
|
||||
|
@ -452,8 +456,6 @@ struct hid_device { /* device report descriptor */
|
|||
void *hidraw;
|
||||
int minor; /* Hiddev minor number */
|
||||
|
||||
wait_queue_head_t wait; /* For sleeping */
|
||||
|
||||
int open; /* is the device open by anyone? */
|
||||
char name[128]; /* Device name */
|
||||
char phys[64]; /* Device physical location */
|
||||
|
@ -530,14 +532,12 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int
|
|||
int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *);
|
||||
int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
|
||||
int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32);
|
||||
void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
|
||||
void hid_output_report(struct hid_report *report, __u8 *data);
|
||||
void hid_free_device(struct hid_device *device);
|
||||
struct hid_device *hid_parse_report(__u8 *start, unsigned size);
|
||||
|
||||
/* HID quirks API */
|
||||
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
|
||||
int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks);
|
||||
int usbhid_quirks_init(char **quirks_param);
|
||||
void usbhid_quirks_exit(void);
|
||||
void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
|
||||
|
@ -546,6 +546,7 @@ void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char
|
|||
int hid_ff_init(struct hid_device *hid);
|
||||
|
||||
int hid_lgff_init(struct hid_device *hid);
|
||||
int hid_lg2ff_init(struct hid_device *hid);
|
||||
int hid_plff_init(struct hid_device *hid);
|
||||
int hid_tmff_init(struct hid_device *hid);
|
||||
int hid_zpff_init(struct hid_device *hid);
|
||||
|
@ -566,7 +567,11 @@ static inline int hid_ff_init(struct hid_device *hid) { return -1; }
|
|||
#define dbg_hid_line(format, arg...) if (hid_debug) \
|
||||
printk(format, ## arg)
|
||||
#else
|
||||
#define dbg_hid(format, arg...) do {} while (0)
|
||||
static inline int __attribute__((format(printf, 1, 2)))
|
||||
dbg_hid(const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define dbg_hid_line dbg_hid
|
||||
#endif
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct hidraw_report_descriptor {
|
||||
__u32 size;
|
||||
|
|
Загрузка…
Ссылка в новой задаче