mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
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:
commit
0d07a15bdb
14 changed files with 431 additions and 209 deletions
|
@ -44,8 +44,8 @@
|
||||||
|
|
||||||
#ifdef CONFIG_HID_DEBUG
|
#ifdef CONFIG_HID_DEBUG
|
||||||
int hid_debug = 0;
|
int hid_debug = 0;
|
||||||
module_param_named(debug, hid_debug, bool, 0600);
|
module_param_named(debug, hid_debug, int, 0600);
|
||||||
MODULE_PARM_DESC(debug, "Turn HID debugging mode on and off");
|
MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)");
|
||||||
EXPORT_SYMBOL_GPL(hid_debug);
|
EXPORT_SYMBOL_GPL(hid_debug);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
|
||||||
field->index = report->maxfield++;
|
field->index = report->maxfield++;
|
||||||
report->field[field->index] = field;
|
report->field[field->index] = field;
|
||||||
field->usage = (struct hid_usage *)(field + 1);
|
field->usage = (struct hid_usage *)(field + 1);
|
||||||
field->value = (unsigned *)(field->usage + usages);
|
field->value = (s32 *)(field->usage + usages);
|
||||||
field->report = report;
|
field->report = report;
|
||||||
|
|
||||||
return field;
|
return field;
|
||||||
|
@ -830,7 +830,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
|
||||||
* reporting to the layer).
|
* 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 n;
|
||||||
unsigned count = field->report_count;
|
unsigned count = field->report_count;
|
||||||
|
@ -876,7 +877,6 @@ void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data
|
||||||
exit:
|
exit:
|
||||||
kfree(value);
|
kfree(value);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hid_input_field);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Output the field into the report.
|
* 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)
|
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
|
||||||
hid->hiddev_report_event(hid, report);
|
hid->hiddev_report_event(hid, report);
|
||||||
if (hid->claimed & HID_CLAIMED_HIDRAW)
|
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);
|
hidraw_report_event(hid, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
for (n = 0; n < report->maxfield; n++)
|
for (n = 0; n < report->maxfield; n++)
|
||||||
hid_input_field(hid, report->field[n], data, interrupt);
|
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);
|
EXPORT_SYMBOL_GPL(hid_dump_device);
|
||||||
|
|
||||||
void hid_dump_input(struct hid_usage *usage, __s32 value) {
|
void hid_dump_input(struct hid_usage *usage, __s32 value) {
|
||||||
if (!hid_debug)
|
if (hid_debug < 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
printk(KERN_DEBUG "hid-debug: input ");
|
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;
|
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 VENDOR_ID_BELKIN 0x1020
|
||||||
#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006
|
#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 VENDOR_ID_PETALYNX 0x18b1
|
||||||
#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
|
#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
|
||||||
|
|
||||||
|
#define VENDOR_ID_SUNPLUS 0x04fc
|
||||||
|
#define DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
|
||||||
|
|
||||||
static const struct hid_input_blacklist {
|
static const struct hid_input_blacklist {
|
||||||
__u16 idVendor;
|
__u16 idVendor;
|
||||||
__u16 idProduct;
|
__u16 idProduct;
|
||||||
|
@ -333,7 +351,9 @@ static const struct hid_input_blacklist {
|
||||||
|
|
||||||
{ VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
|
{ 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,
|
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
|
Note: if you say N here, this device will still be supported, but without
|
||||||
force feedback.
|
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
|
config PANTHERLORD_FF
|
||||||
bool "PantherLord/GreenAsia based device support"
|
bool "PantherLord/GreenAsia based device support"
|
||||||
depends on HID_FF
|
depends on HID_FF
|
||||||
|
@ -80,8 +88,8 @@ config PANTHERLORD_FF
|
||||||
or adapter and want to enable force feedback support for it.
|
or adapter and want to enable force feedback support for it.
|
||||||
|
|
||||||
config THRUSTMASTER_FF
|
config THRUSTMASTER_FF
|
||||||
bool "ThrustMaster devices support (EXPERIMENTAL)"
|
bool "ThrustMaster devices support"
|
||||||
depends on HID_FF && EXPERIMENTAL
|
depends on HID_FF
|
||||||
select INPUT_FF_MEMLESS if USB_HID
|
select INPUT_FF_MEMLESS if USB_HID
|
||||||
help
|
help
|
||||||
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
|
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
|
||||||
|
|
|
@ -16,6 +16,9 @@ endif
|
||||||
ifeq ($(CONFIG_LOGITECH_FF),y)
|
ifeq ($(CONFIG_LOGITECH_FF),y)
|
||||||
usbhid-objs += hid-lgff.o
|
usbhid-objs += hid-lgff.o
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y)
|
||||||
|
usbhid-objs += hid-lg2ff.o
|
||||||
|
endif
|
||||||
ifeq ($(CONFIG_PANTHERLORD_FF),y)
|
ifeq ($(CONFIG_PANTHERLORD_FF),y)
|
||||||
usbhid-objs += hid-plff.o
|
usbhid-objs += hid-plff.o
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -82,6 +82,7 @@ static int hid_start_in(struct hid_device *hid)
|
||||||
|
|
||||||
spin_lock_irqsave(&usbhid->inlock, flags);
|
spin_lock_irqsave(&usbhid->inlock, flags);
|
||||||
if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
|
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)) {
|
!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
|
||||||
rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
|
rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
|
@ -155,7 +156,7 @@ static void hid_io_error(struct hid_device *hid)
|
||||||
spin_lock_irqsave(&usbhid->inlock, flags);
|
spin_lock_irqsave(&usbhid->inlock, flags);
|
||||||
|
|
||||||
/* Stop when disconnected */
|
/* Stop when disconnected */
|
||||||
if (usb_get_intfdata(usbhid->intf) == NULL)
|
if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* If it has been a while since the last error, we'll assume
|
/* 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 (usbhid->outhead != usbhid->outtail) {
|
||||||
if (hid_submit_out(hid)) {
|
if (hid_submit_out(hid)) {
|
||||||
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
||||||
wake_up(&hid->wait);
|
wake_up(&usbhid->wait);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&usbhid->outlock, flags);
|
spin_unlock_irqrestore(&usbhid->outlock, flags);
|
||||||
return;
|
return;
|
||||||
|
@ -349,7 +350,7 @@ static void hid_irq_out(struct urb *urb)
|
||||||
|
|
||||||
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
|
||||||
spin_unlock_irqrestore(&usbhid->outlock, flags);
|
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 (usbhid->ctrlhead != usbhid->ctrltail) {
|
||||||
if (hid_submit_ctrl(hid)) {
|
if (hid_submit_ctrl(hid)) {
|
||||||
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
||||||
wake_up(&hid->wait);
|
wake_up(&usbhid->wait);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
|
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
|
||||||
return;
|
return;
|
||||||
|
@ -399,7 +400,7 @@ static void hid_ctrl(struct urb *urb)
|
||||||
|
|
||||||
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
|
||||||
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
|
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)
|
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
|
||||||
|
@ -478,7 +479,8 @@ int usbhid_wait_io(struct hid_device *hid)
|
||||||
{
|
{
|
||||||
struct usbhid_device *usbhid = hid->driver_data;
|
struct usbhid_device *usbhid = hid->driver_data;
|
||||||
|
|
||||||
if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
|
if (!wait_event_timeout(usbhid->wait,
|
||||||
|
(!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
|
||||||
!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
|
!test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
|
||||||
10*HZ)) {
|
10*HZ)) {
|
||||||
dbg_hid("timeout waiting for ctrl or out queue to clear\n");
|
dbg_hid("timeout waiting for ctrl or out queue to clear\n");
|
||||||
|
@ -610,10 +612,11 @@ static void usbhid_set_leds(struct hid_device *hid)
|
||||||
/*
|
/*
|
||||||
* Traverse the supplied list of reports and find the longest
|
* 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;
|
struct hid_report *report;
|
||||||
int size;
|
unsigned int size;
|
||||||
|
|
||||||
list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
|
list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
|
||||||
size = ((report->size - 1) >> 3) + 1;
|
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_descriptor *hdesc;
|
||||||
struct hid_device *hid;
|
struct hid_device *hid;
|
||||||
u32 quirks = 0;
|
u32 quirks = 0;
|
||||||
unsigned rsize = 0;
|
unsigned int insize = 0, rsize = 0;
|
||||||
char *rdesc;
|
char *rdesc;
|
||||||
int n, len, insize = 0;
|
int n, len;
|
||||||
struct usbhid_device *usbhid;
|
struct usbhid_device *usbhid;
|
||||||
|
|
||||||
quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
|
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;
|
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++) {
|
for (n = 0; n < interface->desc.bNumEndpoints; n++) {
|
||||||
|
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
struct usb_endpoint_descriptor *endpoint;
|
||||||
|
@ -812,6 +831,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
||||||
|
|
||||||
interval = endpoint->bInterval;
|
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. */
|
/* Change the polling interval of mice. */
|
||||||
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
|
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
|
||||||
interval = hid_mousepoll_interval;
|
interval = hid_mousepoll_interval;
|
||||||
|
@ -844,8 +871,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_waitqueue_head(&hid->wait);
|
init_waitqueue_head(&usbhid->wait);
|
||||||
|
|
||||||
INIT_WORK(&usbhid->reset_work, hid_reset);
|
INIT_WORK(&usbhid->reset_work, hid_reset);
|
||||||
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
|
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->intf = intf;
|
||||||
usbhid->ifnum = interface->desc.bInterfaceNumber;
|
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->bus = BUS_USB;
|
||||||
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
|
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
|
||||||
hid->product = le16_to_cpu(dev->descriptor.idProduct);
|
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 */
|
spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
|
||||||
usb_set_intfdata(intf, NULL);
|
usb_set_intfdata(intf, NULL);
|
||||||
|
set_bit(HID_DISCONNECTED, &usbhid->iofl);
|
||||||
spin_unlock_irq(&usbhid->inlock);
|
spin_unlock_irq(&usbhid->inlock);
|
||||||
usb_kill_urb(usbhid->urbin);
|
usb_kill_urb(usbhid->urbin);
|
||||||
usb_kill_urb(usbhid->urbout);
|
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, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
|
||||||
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
|
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_LOGIRUMBLEPAD2_FF
|
||||||
|
{ 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_PANTHERLORD_FF
|
#ifdef CONFIG_PANTHERLORD_FF
|
||||||
{ 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
|
{ 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
|
||||||
{ 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */
|
{ 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */
|
||||||
|
|
114
drivers/hid/usbhid/hid-lg2ff.c
Normal file
114
drivers/hid/usbhid/hid-lg2ff.c
Normal file
|
@ -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_VENDOR_ID_ADS_TECH 0x06e1
|
||||||
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
|
#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_VENDOR_ID_AIPTEK 0x08ca
|
||||||
#define USB_DEVICE_ID_AIPTEK_01 0x0001
|
#define USB_DEVICE_ID_AIPTEK_01 0x0001
|
||||||
#define USB_DEVICE_ID_AIPTEK_10 0x0010
|
#define USB_DEVICE_ID_AIPTEK_10 0x0010
|
||||||
|
@ -124,6 +127,9 @@
|
||||||
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
|
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
|
||||||
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
|
#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_VENDOR_ID_ELO 0x04E7
|
||||||
#define USB_DEVICE_ID_ELO_TS2700 0x0020
|
#define USB_DEVICE_ID_ELO_TS2700 0x0020
|
||||||
|
|
||||||
|
@ -199,17 +205,6 @@
|
||||||
#define USB_DEVICE_ID_GTCO_502 0x0502
|
#define USB_DEVICE_ID_GTCO_502 0x0502
|
||||||
#define USB_DEVICE_ID_GTCO_503 0x0503
|
#define USB_DEVICE_ID_GTCO_503 0x0503
|
||||||
#define USB_DEVICE_ID_GTCO_504 0x0504
|
#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_1000 0x1000
|
||||||
#define USB_DEVICE_ID_GTCO_1001 0x1001
|
#define USB_DEVICE_ID_GTCO_1001 0x1001
|
||||||
#define USB_DEVICE_ID_GTCO_1002 0x1002
|
#define USB_DEVICE_ID_GTCO_1002 0x1002
|
||||||
|
@ -320,6 +315,7 @@
|
||||||
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
|
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
|
||||||
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
|
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
|
||||||
#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
|
#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
|
||||||
|
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
|
||||||
|
|
||||||
#define USB_VENDOR_ID_MCC 0x09db
|
#define USB_VENDOR_ID_MCC 0x09db
|
||||||
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
|
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
|
||||||
|
@ -332,6 +328,7 @@
|
||||||
#define USB_VENDOR_ID_MICROSOFT 0x045e
|
#define USB_VENDOR_ID_MICROSOFT 0x045e
|
||||||
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
|
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
|
||||||
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
|
#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_NE4K 0x00db
|
||||||
#define USB_DEVICE_ID_MS_LK6K 0x00f9
|
#define USB_DEVICE_ID_MS_LK6K 0x00f9
|
||||||
|
|
||||||
|
@ -377,6 +374,9 @@
|
||||||
#define USB_VENDOR_ID_SUN 0x0430
|
#define USB_VENDOR_ID_SUN 0x0430
|
||||||
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
|
#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_VENDOR_ID_TOPMAX 0x0663
|
||||||
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
|
#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_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_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_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_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_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
|
||||||
|
|
||||||
{ USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
|
{ 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_502, HID_QUIRK_IGNORE },
|
||||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, 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_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_1000, HID_QUIRK_IGNORE },
|
||||||
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, 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 },
|
{ 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_2PORTKVM, HID_QUIRK_NOGET },
|
||||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, 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_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_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_EXTREME_3D, HID_QUIRK_NOGET },
|
||||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, 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_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_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_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, 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_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_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, HID_QUIRK_RDESC_LOGITECH },
|
||||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, 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 },
|
{ 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_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_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
|
||||||
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
|
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
|
||||||
|
|
||||||
|
@ -793,7 +791,7 @@ static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
|
||||||
*
|
*
|
||||||
* Returns: 0 OK, -error on failure.
|
* Returns: 0 OK, -error on failure.
|
||||||
*/
|
*/
|
||||||
int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
|
static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
|
||||||
const u32 quirks)
|
const u32 quirks)
|
||||||
{
|
{
|
||||||
struct quirks_list_struct *q_new, *q;
|
struct quirks_list_struct *q_new, *q;
|
||||||
|
@ -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).
|
* 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)
|
static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
|
||||||
{
|
{
|
||||||
if ((quirks & HID_QUIRK_RDESC_CYMOTION))
|
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)
|
if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
|
||||||
usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
|
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)
|
else if (paramVendor == idVendor && paramProduct == idProduct)
|
||||||
__usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
|
__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
|
* "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)
|
static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct hiddev_list *list = file->private_data;
|
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_collection_info cinfo;
|
||||||
struct hiddev_report_info rinfo;
|
struct hiddev_report_info rinfo;
|
||||||
struct hiddev_field_info finfo;
|
struct hiddev_field_info finfo;
|
||||||
struct hiddev_usage_ref_multi *uref_multi = NULL;
|
|
||||||
struct hiddev_usage_ref *uref;
|
|
||||||
struct hiddev_devinfo dinfo;
|
struct hiddev_devinfo dinfo;
|
||||||
struct hid_report *report;
|
struct hid_report *report;
|
||||||
struct hid_field *field;
|
struct hid_field *field;
|
||||||
|
@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
case HIDIOCGSTRING:
|
case HIDIOCGSTRING:
|
||||||
{
|
return hiddev_ioctl_string(hiddev, cmd, user_arg);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
case HIDIOCINITREPORT:
|
case HIDIOCINITREPORT:
|
||||||
usbhid_init_reports(hid);
|
usbhid_init_reports(hid);
|
||||||
|
@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case HIDIOCGUCODE:
|
case HIDIOCGUCODE:
|
||||||
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
|
/* fall through */
|
||||||
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;
|
|
||||||
|
|
||||||
case HIDIOCGUSAGE:
|
case HIDIOCGUSAGE:
|
||||||
case HIDIOCSUSAGE:
|
case HIDIOCSUSAGE:
|
||||||
case HIDIOCGUSAGES:
|
case HIDIOCGUSAGES:
|
||||||
case HIDIOCSUSAGES:
|
case HIDIOCSUSAGES:
|
||||||
case HIDIOCGCOLLECTIONINDEX:
|
case HIDIOCGCOLLECTIONINDEX:
|
||||||
uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
|
return hiddev_ioctl_usage(hiddev, cmd, user_arg);
|
||||||
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;
|
|
||||||
|
|
||||||
case HIDIOCGCOLLECTIONINFO:
|
case HIDIOCGCOLLECTIONINFO:
|
||||||
if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
|
if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ struct usbhid_device {
|
||||||
unsigned long stop_retry; /* Time to give up, in jiffies */
|
unsigned long stop_retry; /* Time to give up, in jiffies */
|
||||||
unsigned int retry_delay; /* Delay length in ms */
|
unsigned int retry_delay; /* Delay length in ms */
|
||||||
struct work_struct reset_work; /* Task context for resets */
|
struct work_struct reset_work; /* Task context for resets */
|
||||||
|
wait_queue_head_t wait; /* For sleeping */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define hid_to_usb_dev(hid_dev) \
|
#define hid_to_usb_dev(hid_dev) \
|
||||||
|
|
|
@ -211,7 +211,9 @@ unifdef-y += hdlcdrv.h
|
||||||
unifdef-y += hdlc.h
|
unifdef-y += hdlc.h
|
||||||
unifdef-y += hdreg.h
|
unifdef-y += hdreg.h
|
||||||
unifdef-y += hdsmart.h
|
unifdef-y += hdsmart.h
|
||||||
|
unifdef-y += hid.h
|
||||||
unifdef-y += hiddev.h
|
unifdef-y += hiddev.h
|
||||||
|
unifdef-y += hidraw.h
|
||||||
unifdef-y += hpet.h
|
unifdef-y += hpet.h
|
||||||
unifdef-y += i2c.h
|
unifdef-y += i2c.h
|
||||||
unifdef-y += i2c-dev.h
|
unifdef-y += i2c-dev.h
|
||||||
|
|
|
@ -284,6 +284,7 @@ struct hid_item {
|
||||||
#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000
|
#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000
|
||||||
#define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000
|
#define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000
|
||||||
#define HID_QUIRK_MICROSOFT_KEYS 0x08000000
|
#define HID_QUIRK_MICROSOFT_KEYS 0x08000000
|
||||||
|
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Separate quirks for runtime report descriptor fixup
|
* 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_MACBOOK_JIS 0x00000010
|
||||||
#define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020
|
#define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020
|
||||||
#define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040
|
#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
|
* 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.
|
* 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
|
#define HID_DEFAULT_NUM_COLLECTIONS 16
|
||||||
|
|
||||||
struct hid_local {
|
struct hid_local {
|
||||||
|
@ -421,6 +424,7 @@ struct hid_control_fifo {
|
||||||
#define HID_RESET_PENDING 4
|
#define HID_RESET_PENDING 4
|
||||||
#define HID_SUSPENDED 5
|
#define HID_SUSPENDED 5
|
||||||
#define HID_CLEAR_HALT 6
|
#define HID_CLEAR_HALT 6
|
||||||
|
#define HID_DISCONNECTED 7
|
||||||
|
|
||||||
struct hid_input {
|
struct hid_input {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
@ -452,8 +456,6 @@ struct hid_device { /* device report descriptor */
|
||||||
void *hidraw;
|
void *hidraw;
|
||||||
int minor; /* Hiddev minor number */
|
int minor; /* Hiddev minor number */
|
||||||
|
|
||||||
wait_queue_head_t wait; /* For sleeping */
|
|
||||||
|
|
||||||
int open; /* is the device open by anyone? */
|
int open; /* is the device open by anyone? */
|
||||||
char name[128]; /* Device name */
|
char name[128]; /* Device name */
|
||||||
char phys[64]; /* Device physical location */
|
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_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_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);
|
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_output_report(struct hid_report *report, __u8 *data);
|
||||||
void hid_free_device(struct hid_device *device);
|
void hid_free_device(struct hid_device *device);
|
||||||
struct hid_device *hid_parse_report(__u8 *start, unsigned size);
|
struct hid_device *hid_parse_report(__u8 *start, unsigned size);
|
||||||
|
|
||||||
/* HID quirks API */
|
/* HID quirks API */
|
||||||
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
|
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);
|
int usbhid_quirks_init(char **quirks_param);
|
||||||
void usbhid_quirks_exit(void);
|
void usbhid_quirks_exit(void);
|
||||||
void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
|
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_ff_init(struct hid_device *hid);
|
||||||
|
|
||||||
int hid_lgff_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_plff_init(struct hid_device *hid);
|
||||||
int hid_tmff_init(struct hid_device *hid);
|
int hid_tmff_init(struct hid_device *hid);
|
||||||
int hid_zpff_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) \
|
#define dbg_hid_line(format, arg...) if (hid_debug) \
|
||||||
printk(format, ## arg)
|
printk(format, ## arg)
|
||||||
#else
|
#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
|
#define dbg_hid_line dbg_hid
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/hid.h>
|
#include <linux/hid.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
struct hidraw_report_descriptor {
|
struct hidraw_report_descriptor {
|
||||||
__u32 size;
|
__u32 size;
|
||||||
|
|
Loading…
Reference in a new issue