提交 31dced41 编写于 作者: L Linus Torvalds

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: (61 commits)
  HID: hid-magicmouse: Magic Trackpad has 1 button, not 2
  HID: Add device IDs for more SJOY adapters
  HID: primax: remove spurious dependency
  HID: support primax keyboards violating USB HID spec
  HID: usbhid: cancel timer for retry synchronously
  HID: wacom: Set input bits before registration
  HID: consolidate MacbookAir 4,1 mappings
  HID: MacbookAir4,1 and MacbookAir4,2 need entry in hid_mouse_ignore_list[]
  HID: Add support MacbookAir 4,1 keyboard
  HID: hidraw: open count should not increase if error
  HID: hiddev: potential info leak in hiddev_ioctl()
  HID: multitouch: decide if hid-multitouch needs to handle mt devices
  HID: add autodetection of multitouch devices
  HID: "hid-logitech" driver with Logitech Driving Force GT
  HID: hid-logitech-dj: fix off by one
  HID: hidraw: protect hidraw_disconnect() better
  HID: hid-multitouch: add support for the IDEACOM 6650 chip
  HID: Add full support for Logitech Unifying receivers
  HID: hidraw: free list for all error in hidraw_open
  HID: roccat: Kone now reports external profile changes via roccat device
  ...
上级 7c1953dd b3aec7b6
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
What: /sys/module/hid_logitech/drivers/hid:logitech/<dev>/range.
Date: July 2011
KernelVersion: 3.2
Contact: Michal Malý <madcatxster@gmail.com>
Description: Display minimum, maximum and current range of the steering
wheel. Writing a value within min and max boundaries sets the
range of the wheel.
...@@ -7147,6 +7147,12 @@ L: linux-scsi@vger.kernel.org ...@@ -7147,6 +7147,12 @@ L: linux-scsi@vger.kernel.org
S: Maintained S: Maintained
F: drivers/scsi/wd7000.c F: drivers/scsi/wd7000.c
WIIMOTE HID DRIVER
M: David Herrmann <dh.herrmann@googlemail.com>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/hid-wiimote*
WINBOND CIR DRIVER WINBOND CIR DRIVER
M: David Härdeman <david@hardeman.nu> M: David Härdeman <david@hardeman.nu>
S: Maintained S: Maintained
......
...@@ -69,7 +69,7 @@ config HID_ACRUX ...@@ -69,7 +69,7 @@ config HID_ACRUX
Say Y here if you want to enable support for ACRUX game controllers. Say Y here if you want to enable support for ACRUX game controllers.
config HID_ACRUX_FF config HID_ACRUX_FF
tristate "ACRUX force feedback support" bool "ACRUX force feedback support"
depends on HID_ACRUX depends on HID_ACRUX
select INPUT_FF_MEMLESS select INPUT_FF_MEMLESS
---help--- ---help---
...@@ -245,6 +245,15 @@ config HID_LOGITECH ...@@ -245,6 +245,15 @@ config HID_LOGITECH
---help--- ---help---
Support for Logitech devices that are not fully compliant with HID standard. Support for Logitech devices that are not fully compliant with HID standard.
config HID_LOGITECH_DJ
tristate "Logitech Unifying receivers full support"
depends on HID_LOGITECH
default m
---help---
Say Y if you want support for Logitech Unifying receivers and devices.
Unifying receivers are capable of pairing up to 6 Logitech compliant
devices to the same receiver.
config LOGITECH_FF config LOGITECH_FF
bool "Logitech force feedback support" bool "Logitech force feedback support"
depends on HID_LOGITECH depends on HID_LOGITECH
...@@ -278,13 +287,21 @@ config LOGIG940_FF ...@@ -278,13 +287,21 @@ config LOGIG940_FF
Say Y here if you want to enable force feedback support for Logitech Say Y here if you want to enable force feedback support for Logitech
Flight System G940 devices. Flight System G940 devices.
config LOGIWII_FF config LOGIWHEELS_FF
bool "Logitech Speed Force Wireless force feedback support" bool "Logitech wheels configuration and force feedback support"
depends on HID_LOGITECH depends on HID_LOGITECH
select INPUT_FF_MEMLESS select INPUT_FF_MEMLESS
default LOGITECH_FF
help help
Say Y here if you want to enable force feedback support for Logitech Say Y here if you want to enable force feedback and range setting
Speed Force Wireless (Wii) devices. support for following Logitech wheels:
- Logitech Driving Force
- Logitech Driving Force Pro
- Logitech Driving Force GT
- Logitech G25
- Logitech G27
- Logitech MOMO/MOMO 2
- Logitech Formula Force EX
config HID_MAGICMOUSE config HID_MAGICMOUSE
tristate "Apple MagicMouse multi-touch support" tristate "Apple MagicMouse multi-touch support"
...@@ -328,6 +345,7 @@ config HID_MULTITOUCH ...@@ -328,6 +345,7 @@ config HID_MULTITOUCH
- Hanvon dual touch panels - Hanvon dual touch panels
- Ilitek dual touch panels - Ilitek dual touch panels
- IrTouch Infrared USB panels - IrTouch Infrared USB panels
- LG Display panels (Dell ST2220Tc)
- Lumio CrystalTouch panels - Lumio CrystalTouch panels
- MosArt dual-touch panels - MosArt dual-touch panels
- PenMount dual touch panels - PenMount dual touch panels
...@@ -441,6 +459,13 @@ config HID_PICOLCD_LEDS ...@@ -441,6 +459,13 @@ config HID_PICOLCD_LEDS
---help--- ---help---
Provide access to PicoLCD's GPO pins via leds class. Provide access to PicoLCD's GPO pins via leds class.
config HID_PRIMAX
tristate "Primax non-fully HID-compliant devices"
depends on USB_HID
---help---
Support for Primax devices that are not fully compliant with the
HID standard.
config HID_QUANTA config HID_QUANTA
tristate "Quanta Optical Touch panels" tristate "Quanta Optical Touch panels"
depends on USB_HID depends on USB_HID
...@@ -539,7 +564,11 @@ config HID_SMARTJOYPLUS ...@@ -539,7 +564,11 @@ config HID_SMARTJOYPLUS
tristate "SmartJoy PLUS PS2/USB adapter support" tristate "SmartJoy PLUS PS2/USB adapter support"
depends on USB_HID depends on USB_HID
---help--- ---help---
Support for SmartJoy PLUS PS2/USB adapter. Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box,
Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro.
Note that DDR (Dance Dance Revolution) mode is not supported, nor
is pressure sensitive buttons on the pro models.
config SMARTJOYPLUS_FF config SMARTJOYPLUS_FF
bool "SmartJoy PLUS PS2/USB adapter force feedback support" bool "SmartJoy PLUS PS2/USB adapter force feedback support"
...@@ -590,6 +619,7 @@ config HID_WIIMOTE ...@@ -590,6 +619,7 @@ config HID_WIIMOTE
tristate "Nintendo Wii Remote support" tristate "Nintendo Wii Remote support"
depends on BT_HIDP depends on BT_HIDP
depends on LEDS_CLASS depends on LEDS_CLASS
select POWER_SUPPLY
---help--- ---help---
Support for the Nintendo Wii Remote bluetooth device. Support for the Nintendo Wii Remote bluetooth device.
......
...@@ -21,7 +21,7 @@ endif ...@@ -21,7 +21,7 @@ endif
ifdef CONFIG_LOGIG940_FF ifdef CONFIG_LOGIG940_FF
hid-logitech-y += hid-lg3ff.o hid-logitech-y += hid-lg3ff.o
endif endif
ifdef CONFIG_LOGIWII_FF ifdef CONFIG_LOGIWHEELS_FF
hid-logitech-y += hid-lg4ff.o hid-logitech-y += hid-lg4ff.o
endif endif
...@@ -43,6 +43,7 @@ obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o ...@@ -43,6 +43,7 @@ obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_KYE) += hid-kye.o
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
...@@ -54,6 +55,7 @@ obj-$(CONFIG_HID_QUANTA) += hid-quanta.o ...@@ -54,6 +55,7 @@ obj-$(CONFIG_HID_QUANTA) += hid-quanta.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
......
...@@ -183,6 +183,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, ...@@ -183,6 +183,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
table = macbookair_fn_keys; table = macbookair_fn_keys;
else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI &&
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS)
table = macbookair_fn_keys;
else if (hid->product < 0x21d || hid->product >= 0x300) else if (hid->product < 0x21d || hid->product >= 0x300)
table = powerbook_fn_keys; table = powerbook_fn_keys;
else else
...@@ -493,6 +496,18 @@ static const struct hid_device_id apple_devices[] = { ...@@ -493,6 +496,18 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
.driver_data = APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI),
.driver_data = APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO),
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Xbox 360 controller. * Xbox 360 controller.
* *
* 1a34:0802 "ACRUX USB GAMEPAD 8116" * 1a34:0802 "ACRUX USB GAMEPAD 8116"
* - tested with a EXEQ EQ-PCU-02090 game controller. * - tested with an EXEQ EQ-PCU-02090 game controller.
* *
* Copyright (c) 2010 Sergei Kolzun <x0r@dv-life.ru> * Copyright (c) 2010 Sergei Kolzun <x0r@dv-life.ru>
*/ */
...@@ -45,7 +45,10 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect ...@@ -45,7 +45,10 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect
{ {
struct hid_device *hid = input_get_drvdata(dev); struct hid_device *hid = input_get_drvdata(dev);
struct axff_device *axff = data; struct axff_device *axff = data;
struct hid_report *report = axff->report;
int field_count = 0;
int left, right; int left, right;
int i, j;
left = effect->u.rumble.strong_magnitude; left = effect->u.rumble.strong_magnitude;
right = effect->u.rumble.weak_magnitude; right = effect->u.rumble.weak_magnitude;
...@@ -55,10 +58,14 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect ...@@ -55,10 +58,14 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect
left = left * 0xff / 0xffff; left = left * 0xff / 0xffff;
right = right * 0xff / 0xffff; right = right * 0xff / 0xffff;
axff->report->field[0]->value[0] = left; for (i = 0; i < report->maxfield; i++) {
axff->report->field[1]->value[0] = right; for (j = 0; j < report->field[i]->report_count; j++) {
axff->report->field[2]->value[0] = left; report->field[i]->value[j] =
axff->report->field[3]->value[0] = right; field_count % 2 ? right : left;
field_count++;
}
}
dbg_hid("running with 0x%02x 0x%02x", left, right); dbg_hid("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, axff->report, USB_DIR_OUT); usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
...@@ -72,6 +79,8 @@ static int axff_init(struct hid_device *hid) ...@@ -72,6 +79,8 @@ static int axff_init(struct hid_device *hid)
struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list); struct hid_input *hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list; struct list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input; struct input_dev *dev = hidinput->input;
int field_count = 0;
int i, j;
int error; int error;
if (list_empty(report_list)) { if (list_empty(report_list)) {
...@@ -80,9 +89,16 @@ static int axff_init(struct hid_device *hid) ...@@ -80,9 +89,16 @@ static int axff_init(struct hid_device *hid)
} }
report = list_first_entry(report_list, struct hid_report, list); report = list_first_entry(report_list, struct hid_report, list);
for (i = 0; i < report->maxfield; i++) {
for (j = 0; j < report->field[i]->report_count; j++) {
report->field[i]->value[j] = 0x00;
field_count++;
}
}
if (report->maxfield < 4) { if (field_count < 4) {
hid_err(hid, "no fields in the report: %d\n", report->maxfield); hid_err(hid, "not enough fields in the report: %d\n",
field_count);
return -ENODEV; return -ENODEV;
} }
...@@ -97,13 +113,9 @@ static int axff_init(struct hid_device *hid) ...@@ -97,13 +113,9 @@ static int axff_init(struct hid_device *hid)
goto err_free_mem; goto err_free_mem;
axff->report = report; axff->report = report;
axff->report->field[0]->value[0] = 0x00;
axff->report->field[1]->value[0] = 0x00;
axff->report->field[2]->value[0] = 0x00;
axff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, axff->report, USB_DIR_OUT); usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n"); hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru>\n");
return 0; return 0;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hiddev.h> #include <linux/hiddev.h>
...@@ -1085,16 +1086,25 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i ...@@ -1085,16 +1086,25 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
struct hid_report *report; struct hid_report *report;
char *buf; char *buf;
unsigned int i; unsigned int i;
int ret; int ret = 0;
if (!hid || !hid->driver) if (!hid)
return -ENODEV; return -ENODEV;
if (down_trylock(&hid->driver_lock))
return -EBUSY;
if (!hid->driver) {
ret = -ENODEV;
goto unlock;
}
report_enum = hid->report_enum + type; report_enum = hid->report_enum + type;
hdrv = hid->driver; hdrv = hid->driver;
if (!size) { if (!size) {
dbg_hid("empty report\n"); dbg_hid("empty report\n");
return -1; ret = -1;
goto unlock;
} }
buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
...@@ -1118,18 +1128,24 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i ...@@ -1118,18 +1128,24 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
nomem: nomem:
report = hid_get_report(report_enum, data); report = hid_get_report(report_enum, data);
if (!report) if (!report) {
return -1; ret = -1;
goto unlock;
}
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
ret = hdrv->raw_event(hid, report, data, size); ret = hdrv->raw_event(hid, report, data, size);
if (ret != 0) if (ret != 0) {
return ret < 0 ? ret : 0; ret = ret < 0 ? ret : 0;
goto unlock;
}
} }
hid_report_raw_event(hid, type, data, size, interrupt); hid_report_raw_event(hid, type, data, size, interrupt);
return 0; unlock:
up(&hid->driver_lock);
return ret;
} }
EXPORT_SYMBOL_GPL(hid_input_report); EXPORT_SYMBOL_GPL(hid_input_report);
...@@ -1212,6 +1228,12 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) ...@@ -1212,6 +1228,12 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev, if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
connect_mask & HID_CONNECT_HIDINPUT_FORCE)) connect_mask & HID_CONNECT_HIDINPUT_FORCE))
hdev->claimed |= HID_CLAIMED_INPUT; hdev->claimed |= HID_CLAIMED_INPUT;
if (hdev->quirks & HID_QUIRK_MULTITOUCH) {
/* this device should be handled by hid-multitouch, skip it */
hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
return -ENODEV;
}
if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect && if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
!hdev->hiddev_connect(hdev, !hdev->hiddev_connect(hdev,
connect_mask & HID_CONNECT_HIDDEV_FORCE)) connect_mask & HID_CONNECT_HIDDEV_FORCE))
...@@ -1343,6 +1365,12 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1343,6 +1365,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
...@@ -1391,6 +1419,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1391,6 +1419,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
...@@ -1399,6 +1428,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1399,6 +1428,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
...@@ -1420,8 +1450,11 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1420,8 +1450,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
...@@ -1461,6 +1494,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1461,6 +1494,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) }, { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
...@@ -1501,6 +1535,10 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1501,6 +1535,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
...@@ -1620,10 +1658,15 @@ static int hid_device_probe(struct device *dev) ...@@ -1620,10 +1658,15 @@ static int hid_device_probe(struct device *dev)
const struct hid_device_id *id; const struct hid_device_id *id;
int ret = 0; int ret = 0;
if (down_interruptible(&hdev->driver_lock))
return -EINTR;
if (!hdev->driver) { if (!hdev->driver) {
id = hid_match_device(hdev, hdrv); id = hid_match_device(hdev, hdrv);
if (id == NULL) if (id == NULL) {
return -ENODEV; ret = -ENODEV;
goto unlock;
}
hdev->driver = hdrv; hdev->driver = hdrv;
if (hdrv->probe) { if (hdrv->probe) {
...@@ -1636,14 +1679,20 @@ static int hid_device_probe(struct device *dev) ...@@ -1636,14 +1679,20 @@ static int hid_device_probe(struct device *dev)
if (ret) if (ret)
hdev->driver = NULL; hdev->driver = NULL;
} }
unlock:
up(&hdev->driver_lock);
return ret; return ret;
} }
static int hid_device_remove(struct device *dev) static int hid_device_remove(struct device *dev)
{ {
struct hid_device *hdev = container_of(dev, struct hid_device, dev); struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct hid_driver *hdrv = hdev->driver; struct hid_driver *hdrv;
if (down_interruptible(&hdev->driver_lock))
return -EINTR;
hdrv = hdev->driver;
if (hdrv) { if (hdrv) {
if (hdrv->remove) if (hdrv->remove)
hdrv->remove(hdev); hdrv->remove(hdev);
...@@ -1652,6 +1701,7 @@ static int hid_device_remove(struct device *dev) ...@@ -1652,6 +1701,7 @@ static int hid_device_remove(struct device *dev)
hdev->driver = NULL; hdev->driver = NULL;
} }
up(&hdev->driver_lock);
return 0; return 0;
} }
...@@ -1892,6 +1942,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { ...@@ -1892,6 +1942,12 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ } { }
...@@ -1999,6 +2055,7 @@ struct hid_device *hid_allocate_device(void) ...@@ -1999,6 +2055,7 @@ struct hid_device *hid_allocate_device(void)
init_waitqueue_head(&hdev->debug_wait); init_waitqueue_head(&hdev->debug_wait);
INIT_LIST_HEAD(&hdev->debug_list); INIT_LIST_HEAD(&hdev->debug_list);
sema_init(&hdev->driver_lock, 1);
return hdev; return hdev;
err: err:
......
...@@ -450,6 +450,11 @@ void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) { ...@@ -450,6 +450,11 @@ void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) {
seq_printf(f, "Logical("); seq_printf(f, "Logical(");
hid_resolv_usage(field->logical, f); seq_printf(f, ")\n"); hid_resolv_usage(field->logical, f); seq_printf(f, ")\n");
} }
if (field->application) {
tab(n, f);
seq_printf(f, "Application(");
hid_resolv_usage(field->application, f); seq_printf(f, ")\n");
}
tab(n, f); seq_printf(f, "Usage(%d)\n", field->maxusage); tab(n, f); seq_printf(f, "Usage(%d)\n", field->maxusage);
for (j = 0; j < field->maxusage; j++) { for (j = 0; j < field->maxusage; j++) {
tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n"); tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n");
......
...@@ -112,6 +112,12 @@ ...@@ -112,6 +112,12 @@
#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f #define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f
#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250 #define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250
#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251 #define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251
#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249
#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a
#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b
#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
...@@ -351,6 +357,9 @@ ...@@ -351,6 +357,9 @@
#define USB_DEVICE_ID_UGCI_FLYING 0x0020 #define USB_DEVICE_ID_UGCI_FLYING 0x0020
#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 #define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
#define USB_VENDOR_ID_IDEACOM 0x1cb6
#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650
#define USB_VENDOR_ID_ILITEK 0x222a #define USB_VENDOR_ID_ILITEK 0x222a
#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 #define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
...@@ -423,6 +432,9 @@ ...@@ -423,6 +432,9 @@
#define USB_DEVICE_ID_LD_HYBRID 0x2090 #define USB_DEVICE_ID_LD_HYBRID 0x2090
#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 #define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0
#define USB_VENDOR_ID_LG 0x1fd2
#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
#define USB_VENDOR_ID_LOGITECH 0x046d #define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
...@@ -440,6 +452,7 @@ ...@@ -440,6 +452,7 @@
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298 #define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
#define USB_DEVICE_ID_LOGITECH_DFGT_WHEEL 0xc29a
#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b #define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c #define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
...@@ -447,6 +460,8 @@ ...@@ -447,6 +460,8 @@
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#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_LOGITECH_UNIFYING_RECEIVER 0xc52b
#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623 #define USB_DEVICE_ID_SPACETRAVELLER 0xc623
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626 #define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704 #define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
...@@ -678,6 +693,9 @@ ...@@ -678,6 +693,9 @@
#define USB_VENDOR_ID_WISEGROUP_LTD 0x6666 #define USB_VENDOR_ID_WISEGROUP_LTD 0x6666
#define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677 #define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677
#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 #define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
#define USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO 0x8801
#define USB_DEVICE_ID_SUPER_DUAL_BOX_PRO 0x8802
#define USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO 0x8804
#define USB_VENDOR_ID_X_TENSIONS 0x1ae7 #define USB_VENDOR_ID_X_TENSIONS 0x1ae7
#define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001 #define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001
...@@ -693,4 +711,7 @@ ...@@ -693,4 +711,7 @@
#define USB_VENDOR_ID_ZYDACRON 0x13EC #define USB_VENDOR_ID_ZYDACRON 0x13EC
#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006 #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006
#define USB_VENDOR_ID_PRIMAX 0x0461
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
#endif #endif
...@@ -474,6 +474,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -474,6 +474,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key_clear(BTN_STYLUS2); map_key_clear(BTN_STYLUS2);
break; break;
case 0x51: /* ContactID */
device->quirks |= HID_QUIRK_MULTITOUCH;
goto unknown;
default: goto unknown; default: goto unknown;
} }
break; break;
...@@ -978,6 +982,13 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -978,6 +982,13 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
} }
} }
if (hid->quirks & HID_QUIRK_MULTITOUCH) {
/* generic hid does not know how to handle multitouch devices */
if (hidinput)
goto out_cleanup;
goto out_unwind;
}
if (hidinput && input_register_device(hidinput->input)) if (hidinput && input_register_device(hidinput->input))
goto out_cleanup; goto out_cleanup;
......
...@@ -363,7 +363,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -363,7 +363,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free; goto err_free;
} }
if (quirks & (LG_FF | LG_FF2 | LG_FF3)) if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
connect_mask &= ~HID_CONNECT_FF; connect_mask &= ~HID_CONNECT_FF;
ret = hid_hw_start(hdev, connect_mask); ret = hid_hw_start(hdev, connect_mask);
...@@ -372,7 +372,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -372,7 +372,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free; goto err_free;
} }
if (quirks & LG_FF4) { /* Setup wireless link with Logitech Wii wheel */
if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
...@@ -405,6 +406,15 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -405,6 +406,15 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret; return ret;
} }
static void lg_remove(struct hid_device *hdev)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
if(quirks & LG_FF4)
lg4ff_deinit(hdev);
hid_hw_stop(hdev);
}
static const struct hid_device_id lg_devices[] = { static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
.driver_data = LG_RDESC | LG_WIRELESS }, .driver_data = LG_RDESC | LG_WIRELESS },
...@@ -431,7 +441,7 @@ static const struct hid_device_id lg_devices[] = { ...@@ -431,7 +441,7 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
.driver_data = LG_NOGET }, .driver_data = LG_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
.driver_data = LG_NOGET | LG_FF }, .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
.driver_data = LG_FF2 }, .driver_data = LG_FF2 },
...@@ -444,15 +454,17 @@ static const struct hid_device_id lg_devices[] = { ...@@ -444,15 +454,17 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
.driver_data = LG_FF }, .driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
.driver_data = LG_FF }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
.driver_data = LG_FF }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
.driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
.driver_data = LG_FF }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
.driver_data = LG_NOGET | LG_FF }, .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
.driver_data = LG_FF4 }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
...@@ -478,6 +490,7 @@ static struct hid_driver lg_driver = { ...@@ -478,6 +490,7 @@ static struct hid_driver lg_driver = {
.input_mapped = lg_input_mapped, .input_mapped = lg_input_mapped,
.event = lg_event, .event = lg_event,
.probe = lg_probe, .probe = lg_probe,
.remove = lg_remove,
}; };
static int __init lg_init(void) static int __init lg_init(void)
......
...@@ -19,10 +19,12 @@ int lg3ff_init(struct hid_device *hdev); ...@@ -19,10 +19,12 @@ int lg3ff_init(struct hid_device *hdev);
static inline int lg3ff_init(struct hid_device *hdev) { return -1; } static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
#endif #endif
#ifdef CONFIG_LOGIWII_FF #ifdef CONFIG_LOGIWHEELS_FF
int lg4ff_init(struct hid_device *hdev); int lg4ff_init(struct hid_device *hdev);
int lg4ff_deinit(struct hid_device *hdev);
#else #else
static inline int lg4ff_init(struct hid_device *hdev) { return -1; } static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
#endif #endif
#endif #endif
...@@ -29,19 +29,108 @@ ...@@ -29,19 +29,108 @@
#include "usbhid/usbhid.h" #include "usbhid/usbhid.h"
#include "hid-lg.h" #include "hid-lg.h"
#include "hid-ids.h"
struct lg4ff_device { #define DFGT_REV_MAJ 0x13
struct hid_report *report; #define DFGT_REV_MIN 0x22
#define DFP_REV_MAJ 0x11
#define DFP_REV_MIN 0x06
#define FFEX_REV_MAJ 0x21
#define FFEX_REV_MIN 0x00
#define G25_REV_MAJ 0x12
#define G25_REV_MIN 0x22
#define G27_REV_MAJ 0x12
#define G27_REV_MIN 0x38
#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
static bool list_inited;
struct lg4ff_device_entry {
char *device_id; /* Use name in respective kobject structure's address as the ID */
__u16 range;
__u16 min_range;
__u16 max_range;
__u8 leds;
struct list_head list;
void (*set_range)(struct hid_device *hid, u16 range);
}; };
static const signed short ff4_wheel_ac[] = { static struct lg4ff_device_entry device_list;
static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT, FF_CONSTANT,
FF_AUTOCENTER, FF_AUTOCENTER,
-1 -1
}; };
static int hid_lg4ff_play(struct input_dev *dev, void *data, struct lg4ff_wheel {
struct ff_effect *effect) const __u32 product_id;
const signed short *ff_effects;
const __u16 min_range;
const __u16 max_range;
void (*set_range)(struct hid_device *hid, u16 range);
};
static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
{USB_DEVICE_ID_LOGITECH_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_dfp},
{USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
{USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
{USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
{USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}
};
struct lg4ff_native_cmd {
const __u8 cmd_num; /* Number of commands to send */
const __u8 cmd[];
};
struct lg4ff_usb_revision {
const __u16 rev_maj;
const __u16 rev_min;
const struct lg4ff_native_cmd *command;
};
static const struct lg4ff_native_cmd native_dfp = {
1,
{0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
};
static const struct lg4ff_native_cmd native_dfgt = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
0xf8, 0x09, 0x03, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
};
static const struct lg4ff_native_cmd native_g25 = {
1,
{0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}
};
static const struct lg4ff_native_cmd native_g27 = {
2,
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1st command */
0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* 2nd command */
};
static const struct lg4ff_usb_revision lg4ff_revs[] = {
{DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
{DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
{G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
{G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
};
static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{ {
struct hid_device *hid = input_get_drvdata(dev); struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
...@@ -55,13 +144,12 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, ...@@ -55,13 +144,12 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data,
x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */
CLAMP(x); CLAMP(x);
report->field[0]->value[0] = 0x11; /* Slot 1 */ report->field[0]->value[0] = 0x11; /* Slot 1 */
report->field[0]->value[1] = 0x10; report->field[0]->value[1] = 0x08;
report->field[0]->value[2] = x; report->field[0]->value[2] = x;
report->field[0]->value[3] = 0x00; report->field[0]->value[3] = 0x80;
report->field[0]->value[4] = 0x00; report->field[0]->value[4] = 0x00;
report->field[0]->value[5] = 0x08; report->field[0]->value[5] = 0x00;
report->field[0]->value[6] = 0x00; report->field[0]->value[6] = 0x00;
dbg_hid("Autocenter, x=0x%02X\n", x);
usbhid_submit_report(hid, report, USB_DIR_OUT); usbhid_submit_report(hid, report, USB_DIR_OUT);
break; break;
...@@ -69,24 +157,184 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, ...@@ -69,24 +157,184 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data,
return 0; return 0;
} }
static void hid_lg4ff_set_autocenter(struct input_dev *dev, u16 magnitude) /* Sends default autocentering command compatible with
* all wheels except Formula Force EX */
static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude)
{ {
struct hid_device *hid = input_get_drvdata(dev); struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list); struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
__s32 *value = report->field[0]->value;
*value++ = 0xfe; report->field[0]->value[0] = 0xfe;
*value++ = 0x0d; report->field[0]->value[1] = 0x0d;
*value++ = 0x07; report->field[0]->value[2] = magnitude >> 13;
*value++ = 0x07; report->field[0]->value[3] = magnitude >> 13;
*value++ = (magnitude >> 8) & 0xff; report->field[0]->value[4] = magnitude >> 8;
*value++ = 0x00; report->field[0]->value[5] = 0x00;
*value = 0x00; report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
}
/* Sends autocentering command compatible with Formula Force EX */
static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
{
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
magnitude = magnitude * 90 / 65535;
report->field[0]->value[0] = 0xfe;
report->field[0]->value[1] = 0x03;
report->field[0]->value[2] = magnitude >> 14;
report->field[0]->value[3] = magnitude >> 14;
report->field[0]->value[4] = magnitude;
report->field[0]->value[5] = 0x00;
report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
}
/* Sends command to set range compatible with G25/G27/Driving Force GT */
static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
{
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
dbg_hid("G25/G27/DFGT: setting range to %u\n", range);
report->field[0]->value[0] = 0xf8;
report->field[0]->value[1] = 0x81;
report->field[0]->value[2] = range & 0x00ff;
report->field[0]->value[3] = (range & 0xff00) >> 8;
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);
}
/* Sends commands to set range compatible with Driving Force Pro wheel */
static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
{
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
int start_left, start_right, full_range;
dbg_hid("Driving Force Pro: setting range to %u\n", range);
/* Prepare "coarse" limit command */
report->field[0]->value[0] = 0xf8;
report->field[0]->value[1] = 0x00; /* Set later */
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;
if (range > 200) {
report->field[0]->value[1] = 0x03;
full_range = 900;
} else {
report->field[0]->value[1] = 0x02;
full_range = 200;
}
usbhid_submit_report(hid, report, USB_DIR_OUT);
/* Prepare "fine" limit command */
report->field[0]->value[0] = 0x81;
report->field[0]->value[1] = 0x0b;
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;
if (range == 200 || range == 900) { /* Do not apply any fine limit */
usbhid_submit_report(hid, report, USB_DIR_OUT);
return;
}
/* Construct fine limit command */
start_left = (((full_range - range + 1) * 2047) / full_range);
start_right = 0xfff - start_left;
report->field[0]->value[2] = start_left >> 4;
report->field[0]->value[3] = start_right >> 4;
report->field[0]->value[4] = 0xff;
report->field[0]->value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
report->field[0]->value[6] = 0xff;
usbhid_submit_report(hid, report, USB_DIR_OUT); usbhid_submit_report(hid, report, USB_DIR_OUT);
} }
static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd)
{
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
__u8 i, j;
j = 0;
while (j < 7*cmd->cmd_num) {
for (i = 0; i < 7; i++)
report->field[0]->value[i] = cmd->cmd[j++];
usbhid_submit_report(hid, report, USB_DIR_OUT);
}
}
/* Read current range and display it in terminal */
static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lg4ff_device_entry *uninitialized_var(entry);
struct list_head *h;
struct hid_device *hid = to_hid_device(dev);
size_t count;
list_for_each(h, &device_list.list) {
entry = list_entry(h, struct lg4ff_device_entry, list);
if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
break;
}
if (h == &device_list.list) {
dbg_hid("Device not found!");
return 0;
}
count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->range);
return count;
}
/* Set range to user specified value, call appropriate function
* according to the type of the wheel */
static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct lg4ff_device_entry *uninitialized_var(entry);
struct list_head *h;
struct hid_device *hid = to_hid_device(dev);
__u16 range = simple_strtoul(buf, NULL, 10);
list_for_each(h, &device_list.list) {
entry = list_entry(h, struct lg4ff_device_entry, list);
if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
break;
}
if (h == &device_list.list) {
dbg_hid("Device not found!");
return count;
}
if (range == 0)
range = entry->max_range;
/* Check if the wheel supports range setting
* and that the range is within limits for the wheel */
if (entry->set_range != NULL && range >= entry->min_range && range <= entry->max_range) {
entry->set_range(hid, range);
entry->range = range;
}
return count;
}
int lg4ff_init(struct hid_device *hid) int lg4ff_init(struct hid_device *hid)
{ {
...@@ -95,9 +343,10 @@ int lg4ff_init(struct hid_device *hid) ...@@ -95,9 +343,10 @@ int lg4ff_init(struct hid_device *hid)
struct input_dev *dev = hidinput->input; struct input_dev *dev = hidinput->input;
struct hid_report *report; struct hid_report *report;
struct hid_field *field; struct hid_field *field;
const signed short *ff_bits = ff4_wheel_ac; struct lg4ff_device_entry *entry;
int error; struct usb_device_descriptor *udesc;
int i; int error, i, j;
__u16 bcdDevice, rev_maj, rev_min;
/* Find the report to use */ /* Find the report to use */
if (list_empty(report_list)) { if (list_empty(report_list)) {
...@@ -118,18 +367,122 @@ int lg4ff_init(struct hid_device *hid) ...@@ -118,18 +367,122 @@ int lg4ff_init(struct hid_device *hid)
return -1; return -1;
} }
for (i = 0; ff_bits[i] >= 0; i++) /* Check what wheel has been connected */
set_bit(ff_bits[i], dev->ffbit); for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
if (hid->product == lg4ff_devices[i].product_id) {
dbg_hid("Found compatible device, product ID %04X\n", lg4ff_devices[i].product_id);
break;
}
}
if (i == ARRAY_SIZE(lg4ff_devices)) {
hid_err(hid, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to"
"LKML, Simon Wood <simon@mungewell.org> or Michal Maly <madcatxster@gmail.com>\n");
return -1;
}
/* Attempt to switch wheel to native mode when applicable */
udesc = &(hid_to_usb_dev(hid)->descriptor);
if (!udesc) {
hid_err(hid, "NULL USB device descriptor\n");
return -1;
}
bcdDevice = le16_to_cpu(udesc->bcdDevice);
rev_maj = bcdDevice >> 8;
rev_min = bcdDevice & 0xff;
if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_WHEEL) {
dbg_hid("Generic wheel detected, can it do native?\n");
dbg_hid("USB revision: %2x.%02x\n", rev_maj, rev_min);
for (j = 0; j < ARRAY_SIZE(lg4ff_revs); j++) {
if (lg4ff_revs[j].rev_maj == rev_maj && lg4ff_revs[j].rev_min == rev_min) {
hid_lg4ff_switch_native(hid, lg4ff_revs[j].command);
hid_info(hid, "Switched to native mode\n");
}
}
}
/* Set supported force feedback capabilities */
for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++)
set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit);
error = input_ff_create_memless(dev, NULL, hid_lg4ff_play); error = input_ff_create_memless(dev, NULL, hid_lg4ff_play);
if (error) if (error)
return error; return error;
if (test_bit(FF_AUTOCENTER, dev->ffbit)) /* Check if autocentering is available and
dev->ff->set_autocenter = hid_lg4ff_set_autocenter; * set the centering force to zero by default */
if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
if(rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
else
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
dev->ff->set_autocenter(dev, 0);
}
/* Initialize device_list if this is the first device to handle by lg4ff */
if (!list_inited) {
INIT_LIST_HEAD(&device_list.list);
list_inited = 1;
}
/* Add the device to device_list */
entry = (struct lg4ff_device_entry *)kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
if (!entry) {
hid_err(hid, "Cannot add device, insufficient memory.\n");
return -ENOMEM;
}
entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL);
if (!entry->device_id) {
hid_err(hid, "Cannot set device_id, insufficient memory.\n");
kfree(entry);
return -ENOMEM;
}
entry->min_range = lg4ff_devices[i].min_range;
entry->max_range = lg4ff_devices[i].max_range;
entry->set_range = lg4ff_devices[i].set_range;
list_add(&entry->list, &device_list.list);
/* Create sysfs interface */
error = device_create_file(&hid->dev, &dev_attr_range);
if (error)
return error;
dbg_hid("sysfs interface created\n");
/* Set the maximum range to start with */
entry->range = entry->max_range;
if (entry->set_range != NULL)
entry->set_range(hid, entry->range);
hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
return 0; return 0;
} }
int lg4ff_deinit(struct hid_device *hid)
{
bool found = 0;
struct lg4ff_device_entry *entry;
struct list_head *h, *g;
list_for_each_safe(h, g, &device_list.list) {
entry = list_entry(h, struct lg4ff_device_entry, list);
if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) {
list_del(h);
kfree(entry->device_id);
kfree(entry);
found = 1;
break;
}
}
if (!found) {
dbg_hid("Device entry not found!\n");
return -1;
}
device_remove_file(&hid->dev, &dev_attr_range);
dbg_hid("Device successfully unregistered\n");
return 0;
}
...@@ -58,12 +58,6 @@ static const signed short ff_joystick_ac[] = { ...@@ -58,12 +58,6 @@ static const signed short ff_joystick_ac[] = {
-1 -1
}; };
static const signed short ff_wheel[] = {
FF_CONSTANT,
FF_AUTOCENTER,
-1
};
static const struct dev_type devices[] = { static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc219, ff_rumble },
...@@ -71,14 +65,7 @@ static const struct dev_type devices[] = { ...@@ -71,14 +65,7 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc286, ff_joystick_ac }, { 0x046d, 0xc286, ff_joystick_ac },
{ 0x046d, 0xc287, ff_joystick_ac }, { 0x046d, 0xc287, ff_joystick_ac },
{ 0x046d, 0xc293, ff_joystick }, { 0x046d, 0xc293, ff_joystick },
{ 0x046d, 0xc294, ff_wheel },
{ 0x046d, 0xc298, ff_wheel },
{ 0x046d, 0xc299, ff_wheel },
{ 0x046d, 0xc29b, ff_wheel },
{ 0x046d, 0xc295, ff_joystick }, { 0x046d, 0xc295, ff_joystick },
{ 0x046d, 0xc298, ff_wheel },
{ 0x046d, 0xc299, ff_wheel },
{ 0x046d, 0xca03, ff_wheel },
}; };
static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
......
此差异已折叠。
#ifndef __HID_LOGITECH_DJ_H
#define __HID_LOGITECH_DJ_H
/*
* HID driver for Logitech Unifying receivers
*
* Copyright (c) 2011 Logitech
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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/kfifo.h>
#define DJ_MAX_PAIRED_DEVICES 6
#define DJ_MAX_NUMBER_NOTIFICATIONS 8
#define DJ_DEVICE_INDEX_MIN 1
#define DJ_DEVICE_INDEX_MAX 6
#define DJREPORT_SHORT_LENGTH 15
#define DJREPORT_LONG_LENGTH 32
#define REPORT_ID_DJ_SHORT 0x20
#define REPORT_ID_DJ_LONG 0x21
#define REPORT_TYPE_RFREPORT_FIRST 0x01
#define REPORT_TYPE_RFREPORT_LAST 0x1F
/* Command Switch to DJ mode */
#define REPORT_TYPE_CMD_SWITCH 0x80
#define CMD_SWITCH_PARAM_DEVBITFIELD 0x00
#define CMD_SWITCH_PARAM_TIMEOUT_SECONDS 0x01
#define TIMEOUT_NO_KEEPALIVE 0x00
/* Command to Get the list of Paired devices */
#define REPORT_TYPE_CMD_GET_PAIRED_DEVICES 0x81
/* Device Paired Notification */
#define REPORT_TYPE_NOTIF_DEVICE_PAIRED 0x41
#define SPFUNCTION_MORE_NOTIF_EXPECTED 0x01
#define SPFUNCTION_DEVICE_LIST_EMPTY 0x02
#define DEVICE_PAIRED_PARAM_SPFUNCTION 0x00
#define DEVICE_PAIRED_PARAM_EQUAD_ID_LSB 0x01
#define DEVICE_PAIRED_PARAM_EQUAD_ID_MSB 0x02
#define DEVICE_PAIRED_RF_REPORT_TYPE 0x03
/* Device Un-Paired Notification */
#define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED 0x40
/* Connection Status Notification */
#define REPORT_TYPE_NOTIF_CONNECTION_STATUS 0x42
#define CONNECTION_STATUS_PARAM_STATUS 0x00
#define STATUS_LINKLOSS 0x01
/* Error Notification */
#define REPORT_TYPE_NOTIF_ERROR 0x7F
#define NOTIF_ERROR_PARAM_ETYPE 0x00
#define ETYPE_KEEPALIVE_TIMEOUT 0x01
/* supported DJ HID && RF report types */
#define REPORT_TYPE_KEYBOARD 0x01
#define REPORT_TYPE_MOUSE 0x02
#define REPORT_TYPE_CONSUMER_CONTROL 0x03
#define REPORT_TYPE_SYSTEM_CONTROL 0x04
#define REPORT_TYPE_MEDIA_CENTER 0x08
#define REPORT_TYPE_LEDS 0x0E
/* RF Report types bitfield */
#define STD_KEYBOARD 0x00000002
#define STD_MOUSE 0x00000004
#define MULTIMEDIA 0x00000008
#define POWER_KEYS 0x00000010
#define MEDIA_CENTER 0x00000100
#define KBD_LEDS 0x00004000
struct dj_report {
u8 report_id;
u8 device_index;
u8 report_type;
u8 report_params[DJREPORT_SHORT_LENGTH - 3];
};
struct dj_receiver_dev {
struct hid_device *hdev;
struct dj_device *paired_dj_devices[DJ_MAX_PAIRED_DEVICES +
DJ_DEVICE_INDEX_MIN];
struct work_struct work;
struct kfifo notif_fifo;
spinlock_t lock;
};
struct dj_device {
struct hid_device *hdev;
struct dj_receiver_dev *dj_receiver_dev;
u32 reports_supported;
u8 device_index;
};
/**
* is_dj_device - know if the given dj_device is not the receiver.
* @dj_dev: the dj device to test
*
* This macro tests if a struct dj_device pointer is a device created
* by the bus enumarator.
*/
#define is_dj_device(dj_dev) \
(&(dj_dev)->dj_receiver_dev->hdev->dev == (dj_dev)->hdev->dev.parent)
#endif
...@@ -405,6 +405,13 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h ...@@ -405,6 +405,13 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
__set_bit(REL_HWHEEL, input->relbit); __set_bit(REL_HWHEEL, input->relbit);
} }
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
/* input->keybit is initialized with incorrect button info
* for Magic Trackpad. There really is only one physical
* button (BTN_LEFT == BTN_MOUSE). Make sure we don't
* advertise buttons that don't exist...
*/
__clear_bit(BTN_RIGHT, input->keybit);
__clear_bit(BTN_MIDDLE, input->keybit);
__set_bit(BTN_MOUSE, input->keybit); __set_bit(BTN_MOUSE, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit); __set_bit(BTN_TOOL_FINGER, input->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input->keybit); __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
......
...@@ -47,10 +47,11 @@ MODULE_LICENSE("GPL"); ...@@ -47,10 +47,11 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1) #define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
#define MT_QUIRK_CYPRESS (1 << 2) #define MT_QUIRK_CYPRESS (1 << 2)
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) #define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
#define MT_QUIRK_VALID_IS_INRANGE (1 << 4) #define MT_QUIRK_ALWAYS_VALID (1 << 4)
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) #define MT_QUIRK_VALID_IS_INRANGE (1 << 5)
#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 7) #define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 7)
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)
struct mt_slot { struct mt_slot {
__s32 x, y, p, w, h; __s32 x, y, p, w, h;
...@@ -86,11 +87,12 @@ struct mt_class { ...@@ -86,11 +87,12 @@ struct mt_class {
/* classes of device behavior */ /* classes of device behavior */
#define MT_CLS_DEFAULT 0x0001 #define MT_CLS_DEFAULT 0x0001
#define MT_CLS_CONFIDENCE 0x0002 #define MT_CLS_SERIAL 0x0002
#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0003 #define MT_CLS_CONFIDENCE 0x0003
#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0004 #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0004
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0005 #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0005
#define MT_CLS_DUAL_NSMU_CONTACTID 0x0006 #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0006
#define MT_CLS_DUAL_NSMU_CONTACTID 0x0007
/* vendor specific classes */ /* vendor specific classes */
#define MT_CLS_3M 0x0101 #define MT_CLS_3M 0x0101
...@@ -134,6 +136,8 @@ static int find_slot_from_contactid(struct mt_device *td) ...@@ -134,6 +136,8 @@ static int find_slot_from_contactid(struct mt_device *td)
struct mt_class mt_classes[] = { struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT, { .name = MT_CLS_DEFAULT,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
{ .name = MT_CLS_SERIAL,
.quirks = MT_QUIRK_ALWAYS_VALID},
{ .name = MT_CLS_CONFIDENCE, { .name = MT_CLS_CONFIDENCE,
.quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, .quirks = MT_QUIRK_VALID_IS_CONFIDENCE },
{ .name = MT_CLS_CONFIDENCE_MINUS_ONE, { .name = MT_CLS_CONFIDENCE_MINUS_ONE,
...@@ -213,6 +217,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -213,6 +217,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct mt_class *cls = td->mtclass; struct mt_class *cls = td->mtclass;
__s32 quirks = cls->quirks; __s32 quirks = cls->quirks;
/* Only map fields from TouchScreen or TouchPad collections.
* We need to ignore fields that belong to other collections
* such as Mouse that might have the same GenericDesktop usages. */
if (field->application == HID_DG_TOUCHSCREEN)
set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
else if (field->application == HID_DG_TOUCHPAD)
set_bit(INPUT_PROP_POINTER, hi->input->propbit);
else
return 0;
switch (usage->hid & HID_USAGE_PAGE) { switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK: case HID_UP_GENDESK:
...@@ -277,6 +291,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -277,6 +291,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
td->last_mt_collection = usage->collection_index; td->last_mt_collection = usage->collection_index;
hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
return 1; return 1;
case HID_DG_WIDTH: case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
...@@ -435,7 +450,9 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -435,7 +450,9 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INRANGE: case HID_DG_INRANGE:
if (quirks & MT_QUIRK_VALID_IS_INRANGE) if (quirks & MT_QUIRK_ALWAYS_VALID)
td->curvalid = true;
else if (quirks & MT_QUIRK_VALID_IS_INRANGE)
td->curvalid = value; td->curvalid = value;
break; break;
case HID_DG_TIPSWITCH: case HID_DG_TIPSWITCH:
...@@ -513,12 +530,44 @@ static void mt_set_input_mode(struct hid_device *hdev) ...@@ -513,12 +530,44 @@ static void mt_set_input_mode(struct hid_device *hdev)
} }
} }
/* a list of devices for which there is a specialized multitouch driver */
static const struct hid_device_id mt_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, 0x0001) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ }
};
static bool mt_match_one_id(struct hid_device *hdev,
const struct hid_device_id *id)
{
return id->bus == hdev->bus &&
(id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
(id->product == HID_ANY_ID || id->product == hdev->product);
}
static const struct hid_device_id *mt_match_id(struct hid_device *hdev,
const struct hid_device_id *id)
{
for (; id->bus; id++)
if (mt_match_one_id(hdev, id))
return id;
return NULL;
}
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
int ret, i; int ret, i;
struct mt_device *td; struct mt_device *td;
struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
if (mt_match_id(hdev, mt_have_special_driver))
return -ENODEV;
for (i = 0; mt_classes[i].name ; i++) { for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) { if (id->driver_data == mt_classes[i].name) {
mtclass = &(mt_classes[i]); mtclass = &(mt_classes[i]);
...@@ -526,10 +575,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -526,10 +575,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
} }
} }
/* This allows the driver to correctly support devices
* that emit events over several HID messages.
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL); td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
if (!td) { if (!td) {
...@@ -545,10 +590,16 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -545,10 +590,16 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret != 0) if (ret != 0)
goto fail; goto fail;
hdev->quirks |= HID_QUIRK_MULTITOUCH;
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) if (ret)
goto fail; goto fail;
/* This allows the driver to correctly support devices
* that emit events over several HID messages.
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
GFP_KERNEL); GFP_KERNEL);
if (!td->slots) { if (!td->slots) {
...@@ -662,6 +713,11 @@ static const struct hid_device_id mt_devices[] = { ...@@ -662,6 +713,11 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
USB_DEVICE_ID_GOODTOUCH_000f) }, USB_DEVICE_ID_GOODTOUCH_000f) },
/* Ideacom panel */
{ .driver_data = MT_CLS_SERIAL,
HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
USB_DEVICE_ID_IDEACOM_IDC6650) },
/* Ilitek dual touch panel */ /* Ilitek dual touch panel */
{ .driver_data = MT_CLS_DEFAULT, { .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
...@@ -672,6 +728,11 @@ static const struct hid_device_id mt_devices[] = { ...@@ -672,6 +728,11 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
/* LG Display panels */
{ .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(USB_VENDOR_ID_LG,
USB_DEVICE_ID_LG_MULTITOUCH) },
/* Lumio panels */ /* Lumio panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
...@@ -732,6 +793,10 @@ static const struct hid_device_id mt_devices[] = { ...@@ -732,6 +793,10 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_XAT, HID_USB_DEVICE(USB_VENDOR_ID_XAT,
USB_DEVICE_ID_XAT_CSR) }, USB_DEVICE_ID_XAT_CSR) },
/* Rest of the world */
{ .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, mt_devices); MODULE_DEVICE_TABLE(hid, mt_devices);
......
/*
* HID driver for primax and similar keyboards with in-band modifiers
*
* Copyright 2011 Google Inc. All Rights Reserved
*
* Author:
* Terry Lambert <tlambert@google.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
static int px_raw_event(struct hid_device *hid, struct hid_report *report,
u8 *data, int size)
{
int idx = size;
switch (report->id) {
case 0: /* keyboard input */
/*
* Convert in-band modifier key values into out of band
* modifier bits and pull the key strokes from the report.
* Thus a report data set which looked like:
*
* [00][00][E0][30][00][00][00][00]
* (no modifier bits + "Left Shift" key + "1" key)
*
* Would be converted to:
*
* [01][00][00][30][00][00][00][00]
* (Left Shift modifier bit + "1" key)
*
* As long as it's in the size range, the upper level
* drivers don't particularly care if there are in-band
* 0-valued keys, so they don't stop parsing.
*/
while (--idx > 1) {
if (data[idx] < 0xE0 || data[idx] > 0xE7)
continue;
data[0] |= (1 << (data[idx] - 0xE0));
data[idx] = 0;
}
hid_report_raw_event(hid, HID_INPUT_REPORT, data, size, 0);
return 1;
default: /* unknown report */
/* Unknown report type; pass upstream */
hid_info(hid, "unknown report type %d\n", report->id);
break;
}
return 0;
}
static int px_probe(struct hid_device *hid, const struct hid_device_id *id)
{
int ret;
ret = hid_parse(hid);
if (ret) {
hid_err(hid, "parse failed\n");
goto fail;
}
ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
if (ret)
hid_err(hid, "hw start failed\n");
fail:
return ret;
}
static void px_remove(struct hid_device *hid)
{
hid_hw_stop(hid);
}
static const struct hid_device_id px_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
{ }
};
MODULE_DEVICE_TABLE(hid, px_devices);
static struct hid_driver px_driver = {
.name = "primax",
.id_table = px_devices,
.raw_event = px_raw_event,
.probe = px_probe,
.remove = px_remove,
};
static int __init px_init(void)
{
return hid_register_driver(&px_driver);
}
static void __exit px_exit(void)
{
hid_unregister_driver(&px_driver);
}
module_init(px_init);
module_exit(px_exit);
MODULE_AUTHOR("Terry Lambert <tlambert@google.com>");
MODULE_LICENSE("GPL");
...@@ -816,7 +816,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -816,7 +816,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (pm == NULL) { if (pm == NULL) {
hid_err(hdev, "can't alloc descriptor\n"); hid_err(hdev, "can't alloc descriptor\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err_free; goto err_free_pk;
} }
pm->pk = pk; pm->pk = pk;
...@@ -849,10 +849,10 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -849,10 +849,10 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
err_stop: err_stop:
hid_hw_stop(hdev); hid_hw_stop(hdev);
err_free: err_free:
if (pm != NULL) kfree(pm);
kfree(pm); err_free_pk:
kfree(pk); kfree(pk);
return ret; return ret;
} }
......
...@@ -37,6 +37,21 @@ ...@@ -37,6 +37,21 @@
static uint profile_numbers[5] = {0, 1, 2, 3, 4}; static uint profile_numbers[5] = {0, 1, 2, 3, 4};
static void kone_profile_activated(struct kone_device *kone, uint new_profile)
{
kone->actual_profile = new_profile;
kone->actual_dpi = kone->profiles[new_profile - 1].startup_dpi;
}
static void kone_profile_report(struct kone_device *kone, uint new_profile)
{
struct kone_roccat_report roccat_report;
roccat_report.event = kone_mouse_event_switch_profile;
roccat_report.value = new_profile;
roccat_report.key = 0;
roccat_report_event(kone->chrdev_minor, (uint8_t *)&roccat_report);
}
static int kone_receive(struct usb_device *usb_dev, uint usb_command, static int kone_receive(struct usb_device *usb_dev, uint usb_command,
void *data, uint size) void *data, uint size)
{ {
...@@ -283,7 +298,7 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj, ...@@ -283,7 +298,7 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0, difference; int retval = 0, difference, old_profile;
/* I need to get my data in one piece */ /* I need to get my data in one piece */
if (off != 0 || count != sizeof(struct kone_settings)) if (off != 0 || count != sizeof(struct kone_settings))
...@@ -294,21 +309,20 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj, ...@@ -294,21 +309,20 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
if (difference) { if (difference) {
retval = kone_set_settings(usb_dev, retval = kone_set_settings(usb_dev,
(struct kone_settings const *)buf); (struct kone_settings const *)buf);
if (!retval) if (retval) {
memcpy(&kone->settings, buf, mutex_unlock(&kone->kone_lock);
sizeof(struct kone_settings)); return retval;
} }
mutex_unlock(&kone->kone_lock);
if (retval) old_profile = kone->settings.startup_profile;
return retval; memcpy(&kone->settings, buf, sizeof(struct kone_settings));
/* kone_profile_activated(kone, kone->settings.startup_profile);
* If we get here, treat settings as okay and update actual values
* according to startup_profile if (kone->settings.startup_profile != old_profile)
*/ kone_profile_report(kone, kone->settings.startup_profile);
kone->actual_profile = kone->settings.startup_profile; }
kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi; mutex_unlock(&kone->kone_lock);
return sizeof(struct kone_settings); return sizeof(struct kone_settings);
} }
...@@ -501,6 +515,8 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev, ...@@ -501,6 +515,8 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
goto exit_no_settings; goto exit_no_settings;
goto exit_unlock; goto exit_unlock;
} }
/* calibration resets profile */
kone_profile_activated(kone, kone->settings.startup_profile);
} }
retval = size; retval = size;
...@@ -544,16 +560,16 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev, ...@@ -544,16 +560,16 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
kone_set_settings_checksum(&kone->settings); kone_set_settings_checksum(&kone->settings);
retval = kone_set_settings(usb_dev, &kone->settings); retval = kone_set_settings(usb_dev, &kone->settings);
if (retval) {
mutex_unlock(&kone->kone_lock); mutex_unlock(&kone->kone_lock);
if (retval)
return retval; return retval;
}
/* changing the startup profile immediately activates this profile */ /* changing the startup profile immediately activates this profile */
kone->actual_profile = new_startup_profile; kone_profile_activated(kone, new_startup_profile);
kone->actual_dpi = kone->profiles[kone->actual_profile - 1].startup_dpi; kone_profile_report(kone, new_startup_profile);
mutex_unlock(&kone->kone_lock);
return size; return size;
} }
...@@ -665,8 +681,7 @@ static int kone_init_kone_device_struct(struct usb_device *usb_dev, ...@@ -665,8 +681,7 @@ static int kone_init_kone_device_struct(struct usb_device *usb_dev,
if (retval) if (retval)
return retval; return retval;
kone->actual_profile = kone->settings.startup_profile; kone_profile_activated(kone, kone->settings.startup_profile);
kone->actual_dpi = kone->profiles[kone->actual_profile].startup_dpi;
return 0; return 0;
} }
...@@ -776,10 +791,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone, ...@@ -776,10 +791,10 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
{ {
switch (event->event) { switch (event->event) {
case kone_mouse_event_switch_profile: case kone_mouse_event_switch_profile:
kone->actual_dpi = kone->profiles[event->value - 1].
startup_dpi;
case kone_mouse_event_osd_profile: case kone_mouse_event_osd_profile:
kone->actual_profile = event->value; kone->actual_profile = event->value;
kone->actual_dpi = kone->profiles[kone->actual_profile - 1].
startup_dpi;
break; break;
case kone_mouse_event_switch_dpi: case kone_mouse_event_switch_dpi:
case kone_mouse_event_osd_dpi: case kone_mouse_event_osd_dpi:
......
...@@ -323,6 +323,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, ...@@ -323,6 +323,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
struct usb_device *usb_dev; struct usb_device *usb_dev;
unsigned long profile; unsigned long profile;
int retval; int retval;
struct kovaplus_roccat_report roccat_report;
dev = dev->parent->parent; dev = dev->parent->parent;
kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
...@@ -337,10 +338,22 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, ...@@ -337,10 +338,22 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
mutex_lock(&kovaplus->kovaplus_lock); mutex_lock(&kovaplus->kovaplus_lock);
retval = kovaplus_set_actual_profile(usb_dev, profile); retval = kovaplus_set_actual_profile(usb_dev, profile);
if (retval) {
mutex_unlock(&kovaplus->kovaplus_lock);
return retval;
}
kovaplus_profile_activated(kovaplus, profile); kovaplus_profile_activated(kovaplus, profile);
roccat_report.type = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1;
roccat_report.profile = profile + 1;
roccat_report.button = 0;
roccat_report.data1 = profile + 1;
roccat_report.data2 = 0;
roccat_report_event(kovaplus->chrdev_minor,
(uint8_t const *)&roccat_report);
mutex_unlock(&kovaplus->kovaplus_lock); mutex_unlock(&kovaplus->kovaplus_lock);
if (retval)
return retval;
return size; return size;
} }
......
...@@ -298,6 +298,7 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, ...@@ -298,6 +298,7 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0; int retval = 0;
int difference; int difference;
struct pyra_roccat_report roccat_report;
if (off != 0 || count != sizeof(struct pyra_settings)) if (off != 0 || count != sizeof(struct pyra_settings))
return -EINVAL; return -EINVAL;
...@@ -307,17 +308,23 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, ...@@ -307,17 +308,23 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
if (difference) { if (difference) {
retval = pyra_set_settings(usb_dev, retval = pyra_set_settings(usb_dev,
(struct pyra_settings const *)buf); (struct pyra_settings const *)buf);
if (!retval) if (retval) {
memcpy(&pyra->settings, buf, mutex_unlock(&pyra->pyra_lock);
sizeof(struct pyra_settings)); return retval;
} }
mutex_unlock(&pyra->pyra_lock);
if (retval) memcpy(&pyra->settings, buf,
return retval; sizeof(struct pyra_settings));
profile_activated(pyra, pyra->settings.startup_profile); profile_activated(pyra, pyra->settings.startup_profile);
roccat_report.type = PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2;
roccat_report.value = pyra->settings.startup_profile + 1;
roccat_report.key = 0;
roccat_report_event(pyra->chrdev_minor,
(uint8_t const *)&roccat_report);
}
mutex_unlock(&pyra->pyra_lock);
return sizeof(struct pyra_settings); return sizeof(struct pyra_settings);
} }
......
...@@ -65,8 +65,7 @@ static int sjoyff_init(struct hid_device *hid) ...@@ -65,8 +65,7 @@ static int sjoyff_init(struct hid_device *hid)
{ {
struct sjoyff_device *sjoyff; struct sjoyff_device *sjoyff;
struct hid_report *report; struct hid_report *report;
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input *hidinput;
struct hid_input, list);
struct list_head *report_list = struct list_head *report_list =
&hid->report_enum[HID_OUTPUT_REPORT].report_list; &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct list_head *report_ptr = report_list; struct list_head *report_ptr = report_list;
...@@ -78,43 +77,45 @@ static int sjoyff_init(struct hid_device *hid) ...@@ -78,43 +77,45 @@ static int sjoyff_init(struct hid_device *hid)
return -ENODEV; return -ENODEV;
} }
report_ptr = report_ptr->next; list_for_each_entry(hidinput, &hid->inputs, list) {
report_ptr = report_ptr->next;
if (report_ptr == report_list) { if (report_ptr == report_list) {
hid_err(hid, "required output report is missing\n"); hid_err(hid, "required output report is missing\n");
return -ENODEV; return -ENODEV;
} }
report = list_entry(report_ptr, struct hid_report, list); report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) { if (report->maxfield < 1) {
hid_err(hid, "no fields in the report\n"); hid_err(hid, "no fields in the report\n");
return -ENODEV; return -ENODEV;
} }
if (report->field[0]->report_count < 3) { if (report->field[0]->report_count < 3) {
hid_err(hid, "not enough values in the field\n"); hid_err(hid, "not enough values in the field\n");
return -ENODEV; return -ENODEV;
} }
sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL); sjoyff = kzalloc(sizeof(struct sjoyff_device), GFP_KERNEL);
if (!sjoyff) if (!sjoyff)
return -ENOMEM; return -ENOMEM;
dev = hidinput->input; dev = hidinput->input;
set_bit(FF_RUMBLE, dev->ffbit); set_bit(FF_RUMBLE, dev->ffbit);
error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play); error = input_ff_create_memless(dev, sjoyff, hid_sjoyff_play);
if (error) { if (error) {
kfree(sjoyff); kfree(sjoyff);
return error; return error;
} }
sjoyff->report = report; sjoyff->report = report;
sjoyff->report->field[0]->value[0] = 0x01; sjoyff->report->field[0]->value[0] = 0x01;
sjoyff->report->field[0]->value[1] = 0x00; sjoyff->report->field[0]->value[1] = 0x00;
sjoyff->report->field[0]->value[2] = 0x00; sjoyff->report->field[0]->value[2] = 0x00;
usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT); usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
}
hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n"); hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
...@@ -131,6 +132,8 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -131,6 +132,8 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
int ret; int ret;
hdev->quirks |= id->driver_data;
ret = hid_parse(hdev); ret = hid_parse(hdev);
if (ret) { if (ret) {
hid_err(hdev, "parse failed\n"); hid_err(hdev, "parse failed\n");
...@@ -151,7 +154,17 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -151,7 +154,17 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
} }
static const struct hid_device_id sjoy_devices[] = { static const struct hid_device_id sjoy_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO),
.driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO),
.driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD),
.driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET |
HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, sjoy_devices); MODULE_DEVICE_TABLE(hid, sjoy_devices);
......
...@@ -304,11 +304,51 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, ...@@ -304,11 +304,51 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
return 1; return 1;
} }
static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
int *max)
{
struct input_dev *input = hi->input;
__set_bit(INPUT_PROP_POINTER, input->propbit);
/* Basics */
input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
__set_bit(REL_WHEEL, input->relbit);
__set_bit(BTN_TOOL_PEN, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_STYLUS, input->keybit);
__set_bit(BTN_STYLUS2, input->keybit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
__set_bit(BTN_MIDDLE, input->keybit);
/* Pad */
input->evbit[0] |= BIT(EV_MSC);
__set_bit(MSC_SERIAL, input->mscbit);
__set_bit(BTN_0, input->keybit);
__set_bit(BTN_1, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
/* Distance, rubber and mouse */
__set_bit(BTN_TOOL_RUBBER, input->keybit);
__set_bit(BTN_TOOL_MOUSE, input->keybit);
input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
return 0;
}
static int wacom_probe(struct hid_device *hdev, static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id) const struct hid_device_id *id)
{ {
struct hid_input *hidinput;
struct input_dev *input;
struct wacom_data *wdata; struct wacom_data *wdata;
int ret; int ret;
...@@ -370,42 +410,6 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -370,42 +410,6 @@ static int wacom_probe(struct hid_device *hdev,
goto err_ac; goto err_ac;
} }
#endif #endif
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
__set_bit(INPUT_PROP_POINTER, input->propbit);
/* Basics */
input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
__set_bit(REL_WHEEL, input->relbit);
__set_bit(BTN_TOOL_PEN, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_STYLUS, input->keybit);
__set_bit(BTN_STYLUS2, input->keybit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
__set_bit(BTN_MIDDLE, input->keybit);
/* Pad */
input->evbit[0] |= BIT(EV_MSC);
__set_bit(MSC_SERIAL, input->mscbit);
__set_bit(BTN_0, input->keybit);
__set_bit(BTN_1, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
/* Distance, rubber and mouse */
__set_bit(BTN_TOOL_RUBBER, input->keybit);
__set_bit(BTN_TOOL_MOUSE, input->keybit);
input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
return 0; return 0;
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY #ifdef CONFIG_HID_WACOM_POWER_SUPPLY
...@@ -448,6 +452,7 @@ static struct hid_driver wacom_driver = { ...@@ -448,6 +452,7 @@ static struct hid_driver wacom_driver = {
.probe = wacom_probe, .probe = wacom_probe,
.remove = wacom_remove, .remove = wacom_remove,
.raw_event = wacom_raw_event, .raw_event = wacom_raw_event,
.input_mapped = wacom_input_mapped,
}; };
static int __init wacom_init(void) static int __init wacom_init(void)
......
此差异已折叠。
...@@ -201,9 +201,7 @@ static void zc_remove(struct hid_device *hdev) ...@@ -201,9 +201,7 @@ static void zc_remove(struct hid_device *hdev)
struct zc_device *zc = hid_get_drvdata(hdev); struct zc_device *zc = hid_get_drvdata(hdev);
hid_hw_stop(hdev); hid_hw_stop(hdev);
kfree(zc);
if (NULL != zc)
kfree(zc);
} }
static const struct hid_device_id zc_devices[] = { static const struct hid_device_id zc_devices[] = {
......
...@@ -259,7 +259,6 @@ static int hidraw_open(struct inode *inode, struct file *file) ...@@ -259,7 +259,6 @@ static int hidraw_open(struct inode *inode, struct file *file)
mutex_lock(&minors_lock); mutex_lock(&minors_lock);
if (!hidraw_table[minor]) { if (!hidraw_table[minor]) {
kfree(list);
err = -ENODEV; err = -ENODEV;
goto out_unlock; goto out_unlock;
} }
...@@ -272,8 +271,10 @@ static int hidraw_open(struct inode *inode, struct file *file) ...@@ -272,8 +271,10 @@ static int hidraw_open(struct inode *inode, struct file *file)
dev = hidraw_table[minor]; dev = hidraw_table[minor];
if (!dev->open++) { if (!dev->open++) {
err = hid_hw_power(dev->hid, PM_HINT_FULLON); err = hid_hw_power(dev->hid, PM_HINT_FULLON);
if (err < 0) if (err < 0) {
dev->open--;
goto out_unlock; goto out_unlock;
}
err = hid_hw_open(dev->hid); err = hid_hw_open(dev->hid);
if (err < 0) { if (err < 0) {
...@@ -285,6 +286,8 @@ static int hidraw_open(struct inode *inode, struct file *file) ...@@ -285,6 +286,8 @@ static int hidraw_open(struct inode *inode, struct file *file)
out_unlock: out_unlock:
mutex_unlock(&minors_lock); mutex_unlock(&minors_lock);
out: out:
if (err < 0)
kfree(list);
return err; return err;
} }
...@@ -510,13 +513,12 @@ void hidraw_disconnect(struct hid_device *hid) ...@@ -510,13 +513,12 @@ void hidraw_disconnect(struct hid_device *hid)
{ {
struct hidraw *hidraw = hid->hidraw; struct hidraw *hidraw = hid->hidraw;
mutex_lock(&minors_lock);
hidraw->exist = 0; hidraw->exist = 0;
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
mutex_lock(&minors_lock);
hidraw_table[hidraw->minor] = NULL; hidraw_table[hidraw->minor] = NULL;
mutex_unlock(&minors_lock);
if (hidraw->open) { if (hidraw->open) {
hid_hw_close(hid); hid_hw_close(hid);
...@@ -524,6 +526,7 @@ void hidraw_disconnect(struct hid_device *hid) ...@@ -524,6 +526,7 @@ void hidraw_disconnect(struct hid_device *hid)
} else { } else {
kfree(hidraw); kfree(hidraw);
} }
mutex_unlock(&minors_lock);
} }
EXPORT_SYMBOL_GPL(hidraw_disconnect); EXPORT_SYMBOL_GPL(hidraw_disconnect);
......
...@@ -1270,7 +1270,7 @@ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid) ...@@ -1270,7 +1270,7 @@ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
static void hid_cease_io(struct usbhid_device *usbhid) static void hid_cease_io(struct usbhid_device *usbhid)
{ {
del_timer(&usbhid->io_retry); del_timer_sync(&usbhid->io_retry);
usb_kill_urb(usbhid->urbin); usb_kill_urb(usbhid->urbin);
usb_kill_urb(usbhid->urbctrl); usb_kill_urb(usbhid->urbctrl);
usb_kill_urb(usbhid->urbout); usb_kill_urb(usbhid->urbout);
......
...@@ -80,10 +80,8 @@ static const struct hid_blacklist { ...@@ -80,10 +80,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, 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_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE }, { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
......
...@@ -641,6 +641,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -641,6 +641,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct usb_device *dev = hid_to_usb_dev(hid); struct usb_device *dev = hid_to_usb_dev(hid);
struct usbhid_device *usbhid = hid->driver_data; struct usbhid_device *usbhid = hid->driver_data;
memset(&dinfo, 0, sizeof(dinfo));
dinfo.bustype = BUS_USB; dinfo.bustype = BUS_USB;
dinfo.busnum = dev->bus->busnum; dinfo.busnum = dev->bus->busnum;
dinfo.devnum = dev->devnum; dinfo.devnum = dev->devnum;
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/semaphore.h>
/* /*
* We parse each description item into this structure. Short items data * We parse each description item into this structure. Short items data
...@@ -312,6 +313,7 @@ struct hid_item { ...@@ -312,6 +313,7 @@ struct hid_item {
#define HID_QUIRK_BADPAD 0x00000020 #define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040 #define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080 #define HID_QUIRK_HIDINPUT_FORCE 0x00000080
#define HID_QUIRK_MULTITOUCH 0x00000100
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000 #define HID_QUIRK_NO_INIT_REPORTS 0x20000000
...@@ -475,6 +477,7 @@ struct hid_device { /* device report descriptor */ ...@@ -475,6 +477,7 @@ struct hid_device { /* device report descriptor */
unsigned country; /* HID country */ unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES]; struct hid_report_enum report_enum[HID_REPORT_TYPES];
struct semaphore driver_lock; /* protects the current driver */
struct device dev; /* device */ struct device dev; /* device */
struct hid_driver *driver; struct hid_driver *driver;
struct hid_ll_driver *ll_driver; struct hid_ll_driver *ll_driver;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部