mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (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 ...
This commit is contained in:
@@ -0,0 +1,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
|
||||
S: Maintained
|
||||
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
|
||||
M: David Härdeman <david@hardeman.nu>
|
||||
S: Maintained
|
||||
|
||||
@@ -69,7 +69,7 @@ config HID_ACRUX
|
||||
Say Y here if you want to enable support for ACRUX game controllers.
|
||||
|
||||
config HID_ACRUX_FF
|
||||
tristate "ACRUX force feedback support"
|
||||
bool "ACRUX force feedback support"
|
||||
depends on HID_ACRUX
|
||||
select INPUT_FF_MEMLESS
|
||||
---help---
|
||||
@@ -245,6 +245,15 @@ config HID_LOGITECH
|
||||
---help---
|
||||
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
|
||||
bool "Logitech force feedback support"
|
||||
depends on HID_LOGITECH
|
||||
@@ -278,13 +287,21 @@ config LOGIG940_FF
|
||||
Say Y here if you want to enable force feedback support for Logitech
|
||||
Flight System G940 devices.
|
||||
|
||||
config LOGIWII_FF
|
||||
bool "Logitech Speed Force Wireless force feedback support"
|
||||
config LOGIWHEELS_FF
|
||||
bool "Logitech wheels configuration and force feedback support"
|
||||
depends on HID_LOGITECH
|
||||
select INPUT_FF_MEMLESS
|
||||
default LOGITECH_FF
|
||||
help
|
||||
Say Y here if you want to enable force feedback support for Logitech
|
||||
Speed Force Wireless (Wii) devices.
|
||||
Say Y here if you want to enable force feedback and range setting
|
||||
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
|
||||
tristate "Apple MagicMouse multi-touch support"
|
||||
@@ -328,6 +345,7 @@ config HID_MULTITOUCH
|
||||
- Hanvon dual touch panels
|
||||
- Ilitek dual touch panels
|
||||
- IrTouch Infrared USB panels
|
||||
- LG Display panels (Dell ST2220Tc)
|
||||
- Lumio CrystalTouch panels
|
||||
- MosArt dual-touch panels
|
||||
- PenMount dual touch panels
|
||||
@@ -441,6 +459,13 @@ config HID_PICOLCD_LEDS
|
||||
---help---
|
||||
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
|
||||
tristate "Quanta Optical Touch panels"
|
||||
depends on USB_HID
|
||||
@@ -539,7 +564,11 @@ config HID_SMARTJOYPLUS
|
||||
tristate "SmartJoy PLUS PS2/USB adapter support"
|
||||
depends on USB_HID
|
||||
---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
|
||||
bool "SmartJoy PLUS PS2/USB adapter force feedback support"
|
||||
@@ -590,6 +619,7 @@ config HID_WIIMOTE
|
||||
tristate "Nintendo Wii Remote support"
|
||||
depends on BT_HIDP
|
||||
depends on LEDS_CLASS
|
||||
select POWER_SUPPLY
|
||||
---help---
|
||||
Support for the Nintendo Wii Remote bluetooth device.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ endif
|
||||
ifdef CONFIG_LOGIG940_FF
|
||||
hid-logitech-y += hid-lg3ff.o
|
||||
endif
|
||||
ifdef CONFIG_LOGIWII_FF
|
||||
ifdef CONFIG_LOGIWHEELS_FF
|
||||
hid-logitech-y += hid-lg4ff.o
|
||||
endif
|
||||
|
||||
@@ -43,6 +43,7 @@ obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
|
||||
obj-$(CONFIG_HID_KYE) += hid-kye.o
|
||||
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.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_MICROSOFT) += hid-microsoft.o
|
||||
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
|
||||
@@ -54,6 +55,7 @@ obj-$(CONFIG_HID_QUANTA) += hid-quanta.o
|
||||
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
|
||||
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.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_COMMON) += hid-roccat-common.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,
|
||||
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
|
||||
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
|
||||
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)
|
||||
table = powerbook_fn_keys;
|
||||
else
|
||||
@@ -493,6 +496,18 @@ static const struct hid_device_id apple_devices[] = {
|
||||
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_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),
|
||||
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Xbox 360 controller.
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
@@ -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 axff_device *axff = data;
|
||||
struct hid_report *report = axff->report;
|
||||
int field_count = 0;
|
||||
int left, right;
|
||||
int i, j;
|
||||
|
||||
left = effect->u.rumble.strong_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
|
||||
left = left * 0xff / 0xffff;
|
||||
right = right * 0xff / 0xffff;
|
||||
|
||||
axff->report->field[0]->value[0] = left;
|
||||
axff->report->field[1]->value[0] = right;
|
||||
axff->report->field[2]->value[0] = left;
|
||||
axff->report->field[3]->value[0] = right;
|
||||
for (i = 0; i < report->maxfield; i++) {
|
||||
for (j = 0; j < report->field[i]->report_count; j++) {
|
||||
report->field[i]->value[j] =
|
||||
field_count % 2 ? right : left;
|
||||
field_count++;
|
||||
}
|
||||
}
|
||||
|
||||
dbg_hid("running with 0x%02x 0x%02x", left, right);
|
||||
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
|
||||
|
||||
@@ -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 list_head *report_list =&hid->report_enum[HID_OUTPUT_REPORT].report_list;
|
||||
struct input_dev *dev = hidinput->input;
|
||||
int field_count = 0;
|
||||
int i, j;
|
||||
int error;
|
||||
|
||||
if (list_empty(report_list)) {
|
||||
@@ -80,9 +89,16 @@ static int axff_init(struct hid_device *hid)
|
||||
}
|
||||
|
||||
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) {
|
||||
hid_err(hid, "no fields in the report: %d\n", report->maxfield);
|
||||
if (field_count < 4) {
|
||||
hid_err(hid, "not enough fields in the report: %d\n",
|
||||
field_count);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -97,13 +113,9 @@ static int axff_init(struct hid_device *hid)
|
||||
goto err_free_mem;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/wait.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#include <linux/hid.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
|
||||
struct hid_report *report;
|
||||
char *buf;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (!hid || !hid->driver)
|
||||
if (!hid)
|
||||
return -ENODEV;
|
||||
|
||||
if (down_trylock(&hid->driver_lock))
|
||||
return -EBUSY;
|
||||
|
||||
if (!hid->driver) {
|
||||
ret = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
report_enum = hid->report_enum + type;
|
||||
hdrv = hid->driver;
|
||||
|
||||
if (!size) {
|
||||
dbg_hid("empty report\n");
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
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
|
||||
nomem:
|
||||
report = hid_get_report(report_enum, data);
|
||||
|
||||
if (!report)
|
||||
return -1;
|
||||
if (!report) {
|
||||
ret = -1;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
|
||||
ret = hdrv->raw_event(hid, report, data, size);
|
||||
if (ret != 0)
|
||||
return ret < 0 ? ret : 0;
|
||||
if (ret != 0) {
|
||||
ret = ret < 0 ? ret : 0;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
hid_report_raw_event(hid, type, data, size, interrupt);
|
||||
|
||||
return 0;
|
||||
unlock:
|
||||
up(&hid->driver_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_input_report);
|
||||
|
||||
@@ -1212,6 +1228,12 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
||||
if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
|
||||
connect_mask & HID_CONNECT_HIDINPUT_FORCE))
|
||||
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 &&
|
||||
!hdev->hiddev_connect(hdev,
|
||||
connect_mask & HID_CONNECT_HIDDEV_FORCE))
|
||||
@@ -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_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_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_ISO) },
|
||||
{ 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[] = {
|
||||
{ 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_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_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
|
||||
{ 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[] = {
|
||||
{ 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_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_S510_RECEIVER) },
|
||||
{ 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[] = {
|
||||
{ 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_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_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_RUMBLEPAD2) },
|
||||
{ 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[] = {
|
||||
{ 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_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_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
|
||||
{ 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[] = {
|
||||
{ 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_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_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) },
|
||||
@@ -1620,10 +1658,15 @@ static int hid_device_probe(struct device *dev)
|
||||
const struct hid_device_id *id;
|
||||
int ret = 0;
|
||||
|
||||
if (down_interruptible(&hdev->driver_lock))
|
||||
return -EINTR;
|
||||
|
||||
if (!hdev->driver) {
|
||||
id = hid_match_device(hdev, hdrv);
|
||||
if (id == NULL)
|
||||
return -ENODEV;
|
||||
if (id == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
hdev->driver = hdrv;
|
||||
if (hdrv->probe) {
|
||||
@@ -1636,14 +1679,20 @@ static int hid_device_probe(struct device *dev)
|
||||
if (ret)
|
||||
hdev->driver = NULL;
|
||||
}
|
||||
unlock:
|
||||
up(&hdev->driver_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hid_device_remove(struct 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->remove)
|
||||
hdrv->remove(hdev);
|
||||
@@ -1652,6 +1701,7 @@ static int hid_device_remove(struct device *dev)
|
||||
hdev->driver = NULL;
|
||||
}
|
||||
|
||||
up(&hdev->driver_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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_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_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_GEYSER1_TP_ONLY) },
|
||||
{ }
|
||||
@@ -1999,6 +2055,7 @@ struct hid_device *hid_allocate_device(void)
|
||||
|
||||
init_waitqueue_head(&hdev->debug_wait);
|
||||
INIT_LIST_HEAD(&hdev->debug_list);
|
||||
sema_init(&hdev->driver_lock, 1);
|
||||
|
||||
return hdev;
|
||||
err:
|
||||
|
||||
@@ -450,6 +450,11 @@ void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) {
|
||||
seq_printf(f, "Logical(");
|
||||
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);
|
||||
for (j = 0; j < field->maxusage; j++) {
|
||||
tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n");
|
||||
|
||||
@@ -112,6 +112,12 @@
|
||||
#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_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_ISO 0x023a
|
||||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
|
||||
@@ -351,6 +357,9 @@
|
||||
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
|
||||
#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_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
|
||||
|
||||
@@ -423,6 +432,9 @@
|
||||
#define USB_DEVICE_ID_LD_HYBRID 0x2090
|
||||
#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_DEVICE_ID_LOGITECH_RECEIVER 0xc101
|
||||
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
|
||||
@@ -440,6 +452,7 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
|
||||
#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
|
||||
#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_WII_WHEEL 0xc29c
|
||||
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
|
||||
@@ -447,6 +460,8 @@
|
||||
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
|
||||
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
|
||||
#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_SPACENAVIGATOR 0xc626
|
||||
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
|
||||
@@ -678,6 +693,9 @@
|
||||
#define USB_VENDOR_ID_WISEGROUP_LTD 0x6666
|
||||
#define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677
|
||||
#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_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001
|
||||
@@ -693,4 +711,7 @@
|
||||
#define USB_VENDOR_ID_ZYDACRON 0x13EC
|
||||
#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006
|
||||
|
||||
#define USB_VENDOR_ID_PRIMAX 0x0461
|
||||
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
|
||||
|
||||
#endif
|
||||
|
||||
@@ -474,6 +474,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
map_key_clear(BTN_STYLUS2);
|
||||
break;
|
||||
|
||||
case 0x51: /* ContactID */
|
||||
device->quirks |= HID_QUIRK_MULTITOUCH;
|
||||
goto unknown;
|
||||
|
||||
default: goto unknown;
|
||||
}
|
||||
break;
|
||||
@@ -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))
|
||||
goto out_cleanup;
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
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;
|
||||
|
||||
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)
|
||||
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 };
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
|
||||
@@ -405,6 +406,15 @@ err_free:
|
||||
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[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
|
||||
.driver_data = LG_RDESC | LG_WIRELESS },
|
||||
@@ -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),
|
||||
.driver_data = LG_NOGET },
|
||||
{ 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),
|
||||
.driver_data = LG_FF2 },
|
||||
@@ -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),
|
||||
.driver_data = LG_FF },
|
||||
{ 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),
|
||||
.driver_data = LG_FF },
|
||||
.driver_data = LG_FF4 },
|
||||
{ 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),
|
||||
.driver_data = LG_FF },
|
||||
.driver_data = LG_FF4 },
|
||||
{ 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),
|
||||
.driver_data = LG_FF4 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
|
||||
@@ -478,6 +490,7 @@ static struct hid_driver lg_driver = {
|
||||
.input_mapped = lg_input_mapped,
|
||||
.event = lg_event,
|
||||
.probe = lg_probe,
|
||||
.remove = lg_remove,
|
||||
};
|
||||
|
||||
static int __init lg_init(void)
|
||||
|
||||
@@ -19,10 +19,12 @@ int lg3ff_init(struct hid_device *hdev);
|
||||
static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LOGIWII_FF
|
||||
#ifdef CONFIG_LOGIWHEELS_FF
|
||||
int lg4ff_init(struct hid_device *hdev);
|
||||
int lg4ff_deinit(struct hid_device *hdev);
|
||||
#else
|
||||
static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
|
||||
static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,19 +29,108 @@
|
||||
|
||||
#include "usbhid/usbhid.h"
|
||||
#include "hid-lg.h"
|
||||
#include "hid-ids.h"
|
||||
|
||||
struct lg4ff_device {
|
||||
struct hid_report *report;
|
||||
#define DFGT_REV_MAJ 0x13
|
||||
#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_AUTOCENTER,
|
||||
-1
|
||||
};
|
||||
|
||||
static int hid_lg4ff_play(struct input_dev *dev, void *data,
|
||||
struct ff_effect *effect)
|
||||
struct lg4ff_wheel {
|
||||
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 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,
|
||||
x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */
|
||||
CLAMP(x);
|
||||
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[3] = 0x00;
|
||||
report->field[0]->value[3] = 0x80;
|
||||
report->field[0]->value[4] = 0x00;
|
||||
report->field[0]->value[5] = 0x08;
|
||||
report->field[0]->value[5] = 0x00;
|
||||
report->field[0]->value[6] = 0x00;
|
||||
dbg_hid("Autocenter, x=0x%02X\n", x);
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
break;
|
||||
@@ -69,24 +157,184 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data,
|
||||
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 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);
|
||||
__s32 *value = report->field[0]->value;
|
||||
|
||||
*value++ = 0xfe;
|
||||
*value++ = 0x0d;
|
||||
*value++ = 0x07;
|
||||
*value++ = 0x07;
|
||||
*value++ = (magnitude >> 8) & 0xff;
|
||||
*value++ = 0x00;
|
||||
*value = 0x00;
|
||||
report->field[0]->value[0] = 0xfe;
|
||||
report->field[0]->value[1] = 0x0d;
|
||||
report->field[0]->value[2] = magnitude >> 13;
|
||||
report->field[0]->value[3] = magnitude >> 13;
|
||||
report->field[0]->value[4] = magnitude >> 8;
|
||||
report->field[0]->value[5] = 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -95,9 +343,10 @@ int lg4ff_init(struct hid_device *hid)
|
||||
struct input_dev *dev = hidinput->input;
|
||||
struct hid_report *report;
|
||||
struct hid_field *field;
|
||||
const signed short *ff_bits = ff4_wheel_ac;
|
||||
int error;
|
||||
int i;
|
||||
struct lg4ff_device_entry *entry;
|
||||
struct usb_device_descriptor *udesc;
|
||||
int error, i, j;
|
||||
__u16 bcdDevice, rev_maj, rev_min;
|
||||
|
||||
/* Find the report to use */
|
||||
if (list_empty(report_list)) {
|
||||
@@ -118,18 +367,122 @@ int lg4ff_init(struct hid_device *hid)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; ff_bits[i] >= 0; i++)
|
||||
set_bit(ff_bits[i], dev->ffbit);
|
||||
/* Check what wheel has been connected */
|
||||
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);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (test_bit(FF_AUTOCENTER, dev->ffbit))
|
||||
dev->ff->set_autocenter = hid_lg4ff_set_autocenter;
|
||||
/* Check if autocentering is available and
|
||||
* 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");
|
||||
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[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const signed short ff_wheel[] = {
|
||||
FF_CONSTANT,
|
||||
FF_AUTOCENTER,
|
||||
-1
|
||||
};
|
||||
|
||||
static const struct dev_type devices[] = {
|
||||
{ 0x046d, 0xc211, ff_rumble },
|
||||
{ 0x046d, 0xc219, ff_rumble },
|
||||
@@ -71,14 +65,7 @@ static const struct dev_type devices[] = {
|
||||
{ 0x046d, 0xc286, ff_joystick_ac },
|
||||
{ 0x046d, 0xc287, ff_joystick_ac },
|
||||
{ 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, 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)
|
||||
|
||||
922
drivers/hid/hid-logitech-dj.c
Normal file
922
drivers/hid/hid-logitech-dj.c
Normal file
File diff suppressed because it is too large
Load Diff
123
drivers/hid/hid-logitech-dj.h
Normal file
123
drivers/hid/hid-logitech-dj.h
Normal file
@@ -0,0 +1,123 @@
|
||||
#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
|
||||
__set_bit(REL_HWHEEL, input->relbit);
|
||||
}
|
||||
} 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_TOOL_FINGER, input->keybit);
|
||||
__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
|
||||
|
||||
@@ -47,10 +47,11 @@ MODULE_LICENSE("GPL");
|
||||
#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
|
||||
#define MT_QUIRK_CYPRESS (1 << 2)
|
||||
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
|
||||
#define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
|
||||
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
|
||||
#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6)
|
||||
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 7)
|
||||
#define MT_QUIRK_ALWAYS_VALID (1 << 4)
|
||||
#define MT_QUIRK_VALID_IS_INRANGE (1 << 5)
|
||||
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)
|
||||
#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 7)
|
||||
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)
|
||||
|
||||
struct mt_slot {
|
||||
__s32 x, y, p, w, h;
|
||||
@@ -86,11 +87,12 @@ struct mt_class {
|
||||
/* classes of device behavior */
|
||||
#define MT_CLS_DEFAULT 0x0001
|
||||
|
||||
#define MT_CLS_CONFIDENCE 0x0002
|
||||
#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0003
|
||||
#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0004
|
||||
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0005
|
||||
#define MT_CLS_DUAL_NSMU_CONTACTID 0x0006
|
||||
#define MT_CLS_SERIAL 0x0002
|
||||
#define MT_CLS_CONFIDENCE 0x0003
|
||||
#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0004
|
||||
#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0005
|
||||
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0006
|
||||
#define MT_CLS_DUAL_NSMU_CONTACTID 0x0007
|
||||
|
||||
/* vendor specific classes */
|
||||
#define MT_CLS_3M 0x0101
|
||||
@@ -134,6 +136,8 @@ static int find_slot_from_contactid(struct mt_device *td)
|
||||
struct mt_class mt_classes[] = {
|
||||
{ .name = MT_CLS_DEFAULT,
|
||||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
|
||||
{ .name = MT_CLS_SERIAL,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID},
|
||||
{ .name = MT_CLS_CONFIDENCE,
|
||||
.quirks = MT_QUIRK_VALID_IS_CONFIDENCE },
|
||||
{ .name = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||
@@ -213,6 +217,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct mt_class *cls = td->mtclass;
|
||||
__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) {
|
||||
|
||||
case HID_UP_GENDESK:
|
||||
@@ -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_field_index = field->index;
|
||||
td->last_mt_collection = usage->collection_index;
|
||||
hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
|
||||
return 1;
|
||||
case HID_DG_WIDTH:
|
||||
hid_map_usage(hi, usage, bit, max,
|
||||
@@ -435,7 +450,9 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
|
||||
switch (usage->hid) {
|
||||
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;
|
||||
break;
|
||||
case HID_DG_TIPSWITCH:
|
||||
@@ -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)
|
||||
{
|
||||
int ret, i;
|
||||
struct mt_device *td;
|
||||
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++) {
|
||||
if (id->driver_data == mt_classes[i].name) {
|
||||
mtclass = &(mt_classes[i]);
|
||||
@@ -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);
|
||||
if (!td) {
|
||||
@@ -545,10 +590,16 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
if (ret != 0)
|
||||
goto fail;
|
||||
|
||||
hdev->quirks |= HID_QUIRK_MULTITOUCH;
|
||||
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
||||
if (ret)
|
||||
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),
|
||||
GFP_KERNEL);
|
||||
if (!td->slots) {
|
||||
@@ -662,6 +713,11 @@ static const struct hid_device_id mt_devices[] = {
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
|
||||
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 */
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
|
||||
@@ -672,6 +728,11 @@ static const struct hid_device_id mt_devices[] = {
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
|
||||
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 */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
|
||||
@@ -732,6 +793,10 @@ static const struct hid_device_id mt_devices[] = {
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_XAT,
|
||||
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);
|
||||
|
||||
117
drivers/hid/hid-primax.c
Normal file
117
drivers/hid/hid-primax.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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)
|
||||
if (pm == NULL) {
|
||||
hid_err(hdev, "can't alloc descriptor\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
goto err_free_pk;
|
||||
}
|
||||
|
||||
pm->pk = pk;
|
||||
@@ -849,10 +849,10 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
err_stop:
|
||||
hid_hw_stop(hdev);
|
||||
err_free:
|
||||
if (pm != NULL)
|
||||
kfree(pm);
|
||||
|
||||
kfree(pm);
|
||||
err_free_pk:
|
||||
kfree(pk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user