Commit f4eb1423 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID fixes from Jiri Kosina:

 - functional regression fix for some of the Logitech unifying devices,
   from Hans de Goede

 - race condition fix in hid-sony for bug severely affecting
   Valve/Android deployments, from Roderick Colenbrander

 - several fixes for issues found by syzbot/kasan, from Oliver Neukum
   and Hillf Danton

 - functional regression fix for Wacom Cintiq device, from Aaron
   Armstrong Skomra

 - a few other assorted device-specific quirks

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: sony: Fix race condition between rumble and device remove.
  HID: hiddev: do cleanup in failure of opening a device
  HID: hiddev: avoid opening a disconnected device
  HID: input: fix a4tech horizontal wheel custom usage
  HID: Add quirk for HP X1200 PIXART OEM mouse
  HID: holtek: test for sanity of intfdata
  HID: wacom: fix bit shift for Cintiq Companion 2
  HID: quirks: Set the INCREMENT_USAGE_ON_DUPLICATE quirk on Saitek X52
  HID: logitech-dj: Really fix return value of logi_dj_recv_query_hidpp_devices
  HID: Add 044f:b320 ThrustMaster, Inc. 2 in 1 DT
  HID: logitech-dj: add the Powerplay receiver
  HID: logitech-hidpp: add USB PID for a few more supported mice
  HID: logitech-dj: rename "gaming" receiver to "lightspeed"
parents 4368c4bc e0f6974a
...@@ -23,12 +23,36 @@ ...@@ -23,12 +23,36 @@
#define A4_2WHEEL_MOUSE_HACK_7 0x01 #define A4_2WHEEL_MOUSE_HACK_7 0x01
#define A4_2WHEEL_MOUSE_HACK_B8 0x02 #define A4_2WHEEL_MOUSE_HACK_B8 0x02
#define A4_WHEEL_ORIENTATION (HID_UP_GENDESK | 0x000000b8)
struct a4tech_sc { struct a4tech_sc {
unsigned long quirks; unsigned long quirks;
unsigned int hw_wheel; unsigned int hw_wheel;
__s32 delayed_value; __s32 delayed_value;
}; };
static int a4_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
struct a4tech_sc *a4 = hid_get_drvdata(hdev);
if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8 &&
usage->hid == A4_WHEEL_ORIENTATION) {
/*
* We do not want to have this usage mapped to anything as it's
* nonstandard and doesn't really behave like an HID report.
* It's only selecting the orientation (vertical/horizontal) of
* the previous mouse wheel report. The input_events will be
* generated once both reports are recorded in a4_event().
*/
return -1;
}
return 0;
}
static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi, static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max) unsigned long **bit, int *max)
...@@ -52,8 +76,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field, ...@@ -52,8 +76,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field,
struct a4tech_sc *a4 = hid_get_drvdata(hdev); struct a4tech_sc *a4 = hid_get_drvdata(hdev);
struct input_dev *input; struct input_dev *input;
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput)
!usage->type)
return 0; return 0;
input = field->hidinput->input; input = field->hidinput->input;
...@@ -64,7 +87,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field, ...@@ -64,7 +87,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field,
return 1; return 1;
} }
if (usage->hid == 0x000100b8) { if (usage->hid == A4_WHEEL_ORIENTATION) {
input_event(input, EV_REL, value ? REL_HWHEEL : input_event(input, EV_REL, value ? REL_HWHEEL :
REL_WHEEL, a4->delayed_value); REL_WHEEL, a4->delayed_value);
input_event(input, EV_REL, value ? REL_HWHEEL_HI_RES : input_event(input, EV_REL, value ? REL_HWHEEL_HI_RES :
...@@ -131,6 +154,7 @@ MODULE_DEVICE_TABLE(hid, a4_devices); ...@@ -131,6 +154,7 @@ MODULE_DEVICE_TABLE(hid, a4_devices);
static struct hid_driver a4_driver = { static struct hid_driver a4_driver = {
.name = "a4tech", .name = "a4tech",
.id_table = a4_devices, .id_table = a4_devices,
.input_mapping = a4_input_mapping,
.input_mapped = a4_input_mapped, .input_mapped = a4_input_mapped,
.event = a4_event, .event = a4_event,
.probe = a4_probe, .probe = a4_probe,
......
...@@ -123,9 +123,14 @@ static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type, ...@@ -123,9 +123,14 @@ static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type,
/* Locate the boot interface, to receive the LED change events */ /* Locate the boot interface, to receive the LED change events */
struct usb_interface *boot_interface = usb_ifnum_to_if(usb_dev, 0); struct usb_interface *boot_interface = usb_ifnum_to_if(usb_dev, 0);
struct hid_device *boot_hid;
struct hid_input *boot_hid_input;
struct hid_device *boot_hid = usb_get_intfdata(boot_interface); if (unlikely(boot_interface == NULL))
struct hid_input *boot_hid_input = list_first_entry(&boot_hid->inputs, return -ENODEV;
boot_hid = usb_get_intfdata(boot_interface);
boot_hid_input = list_first_entry(&boot_hid->inputs,
struct hid_input, list); struct hid_input, list);
return boot_hid_input->input->event(boot_hid_input->input, type, code, return boot_hid_input->input->event(boot_hid_input->input, type, code,
......
...@@ -568,6 +568,7 @@ ...@@ -568,6 +568,7 @@
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
#define USB_VENDOR_ID_HUION 0x256c #define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e #define USB_DEVICE_ID_HUION_TABLET 0x006e
...@@ -768,7 +769,8 @@ ...@@ -768,7 +769,8 @@
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f
#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532 #define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING 0xc539 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED 0xc539
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
#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
...@@ -989,6 +991,7 @@ ...@@ -989,6 +991,7 @@
#define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7 #define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7
#define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa #define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa
#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0 #define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
#define USB_DEVICE_ID_SAITEK_X52 0x075c
#define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
......
...@@ -1125,7 +1125,7 @@ static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev) ...@@ -1125,7 +1125,7 @@ static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
HID_REQ_SET_REPORT); HID_REQ_SET_REPORT);
kfree(hidpp_report); kfree(hidpp_report);
return retval; return (retval < 0) ? retval : 0;
} }
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
...@@ -1832,13 +1832,17 @@ static const struct hid_device_id logi_dj_receivers[] = { ...@@ -1832,13 +1832,17 @@ static const struct hid_device_id logi_dj_receivers[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
.driver_data = recvr_type_hidpp}, .driver_data = recvr_type_hidpp},
{ /* Logitech gaming receiver (0xc539) */ { /* Logitech lightspeed receiver (0xc539) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED),
.driver_data = recvr_type_gaming_hidpp}, .driver_data = recvr_type_gaming_hidpp},
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */ { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
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 = recvr_type_27mhz}, .driver_data = recvr_type_27mhz},
{ /* Logitech powerplay receiver (0xc53a) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY),
.driver_data = recvr_type_gaming_hidpp},
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */ { /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_S510_RECEIVER_2), USB_DEVICE_ID_S510_RECEIVER_2),
......
...@@ -3749,15 +3749,45 @@ static const struct hid_device_id hidpp_devices[] = { ...@@ -3749,15 +3749,45 @@ static const struct hid_device_id hidpp_devices[] = {
{ L27MHZ_DEVICE(HID_ANY_ID) }, { L27MHZ_DEVICE(HID_ANY_ID) },
{ /* Logitech G403 Gaming Mouse over USB */ { /* Logitech G203/Prodigy Gaming Mouse */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC084) },
{ /* Logitech G302 Gaming Mouse */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07F) },
{ /* Logitech G303 Gaming Mouse */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC080) },
{ /* Logitech G400 Gaming Mouse */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07E) },
{ /* Logitech G403 Wireless Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) }, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) },
{ /* Logitech G403 Gaming Mouse */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC083) },
{ /* Logitech G403 Hero Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08F) },
{ /* Logitech G502 Proteus Core Gaming Mouse */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07D) },
{ /* Logitech G502 Proteus Spectrum Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC332) },
{ /* Logitech G502 Hero Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC08B) },
{ /* Logitech G700 Gaming Mouse over USB */ { /* Logitech G700 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC06B) }, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC06B) },
{ /* Logitech G700s Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC07C) },
{ /* Logitech G703 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC087) },
{ /* Logitech G703 Hero Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC090) },
{ /* Logitech G900 Gaming Mouse over USB */ { /* Logitech G900 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC081) }, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC081) },
{ /* Logitech G903 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC086) },
{ /* Logitech G903 Hero Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC091) },
{ /* Logitech G920 Wheel over USB */ { /* Logitech G920 Wheel over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
{ /* Logitech G Pro Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
{ /* MX5000 keyboard over Bluetooth */ { /* MX5000 keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305), HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305),
......
...@@ -92,6 +92,7 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -92,6 +92,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
...@@ -141,6 +142,7 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -141,6 +142,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPAD), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPAD), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS }, { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
......
...@@ -585,10 +585,14 @@ static void sony_set_leds(struct sony_sc *sc); ...@@ -585,10 +585,14 @@ static void sony_set_leds(struct sony_sc *sc);
static inline void sony_schedule_work(struct sony_sc *sc, static inline void sony_schedule_work(struct sony_sc *sc,
enum sony_worker which) enum sony_worker which)
{ {
unsigned long flags;
switch (which) { switch (which) {
case SONY_WORKER_STATE: case SONY_WORKER_STATE:
if (!sc->defer_initialization) spin_lock_irqsave(&sc->lock, flags);
if (!sc->defer_initialization && sc->state_worker_initialized)
schedule_work(&sc->state_worker); schedule_work(&sc->state_worker);
spin_unlock_irqrestore(&sc->lock, flags);
break; break;
case SONY_WORKER_HOTPLUG: case SONY_WORKER_HOTPLUG:
if (sc->hotplug_worker_initialized) if (sc->hotplug_worker_initialized)
...@@ -2558,13 +2562,18 @@ static inline void sony_init_output_report(struct sony_sc *sc, ...@@ -2558,13 +2562,18 @@ static inline void sony_init_output_report(struct sony_sc *sc,
static inline void sony_cancel_work_sync(struct sony_sc *sc) static inline void sony_cancel_work_sync(struct sony_sc *sc)
{ {
unsigned long flags;
if (sc->hotplug_worker_initialized) if (sc->hotplug_worker_initialized)
cancel_work_sync(&sc->hotplug_worker); cancel_work_sync(&sc->hotplug_worker);
if (sc->state_worker_initialized) if (sc->state_worker_initialized) {
spin_lock_irqsave(&sc->lock, flags);
sc->state_worker_initialized = 0;
spin_unlock_irqrestore(&sc->lock, flags);
cancel_work_sync(&sc->state_worker); cancel_work_sync(&sc->state_worker);
}
} }
static int sony_input_configured(struct hid_device *hdev, static int sony_input_configured(struct hid_device *hdev,
struct hid_input *hidinput) struct hid_input *hidinput)
{ {
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include "hid-ids.h" #include "hid-ids.h"
#define THRUSTMASTER_DEVICE_ID_2_IN_1_DT 0xb320
static const signed short ff_rumble[] = { static const signed short ff_rumble[] = {
FF_RUMBLE, FF_RUMBLE,
-1 -1
...@@ -76,6 +78,7 @@ static int tmff_play(struct input_dev *dev, void *data, ...@@ -76,6 +78,7 @@ static int tmff_play(struct input_dev *dev, void *data,
struct hid_field *ff_field = tmff->ff_field; struct hid_field *ff_field = tmff->ff_field;
int x, y; int x, y;
int left, right; /* Rumbling */ int left, right; /* Rumbling */
int motor_swap;
switch (effect->type) { switch (effect->type) {
case FF_CONSTANT: case FF_CONSTANT:
...@@ -100,6 +103,13 @@ static int tmff_play(struct input_dev *dev, void *data, ...@@ -100,6 +103,13 @@ static int tmff_play(struct input_dev *dev, void *data,
ff_field->logical_minimum, ff_field->logical_minimum,
ff_field->logical_maximum); ff_field->logical_maximum);
/* 2-in-1 strong motor is left */
if (hid->product == THRUSTMASTER_DEVICE_ID_2_IN_1_DT) {
motor_swap = left;
left = right;
right = motor_swap;
}
dbg_hid("(left,right)=(%08x, %08x)\n", left, right); dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
ff_field->value[0] = left; ff_field->value[0] = left;
ff_field->value[1] = right; ff_field->value[1] = right;
...@@ -226,6 +236,8 @@ static const struct hid_device_id tm_devices[] = { ...@@ -226,6 +236,8 @@ static const struct hid_device_id tm_devices[] = {
.driver_data = (unsigned long)ff_rumble }, .driver_data = (unsigned long)ff_rumble },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304), /* FireStorm Dual Power 2 (and 3) */ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304), /* FireStorm Dual Power 2 (and 3) */
.driver_data = (unsigned long)ff_rumble }, .driver_data = (unsigned long)ff_rumble },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, THRUSTMASTER_DEVICE_ID_2_IN_1_DT), /* Dual Trigger 2-in-1 */
.driver_data = (unsigned long)ff_rumble },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323), /* Dual Trigger 3-in-1 (PC Mode) */ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323), /* Dual Trigger 3-in-1 (PC Mode) */
.driver_data = (unsigned long)ff_rumble }, .driver_data = (unsigned long)ff_rumble },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324), /* Dual Trigger 3-in-1 (PS3 Mode) */ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324), /* Dual Trigger 3-in-1 (PS3 Mode) */
......
...@@ -284,6 +284,14 @@ static int hiddev_open(struct inode *inode, struct file *file) ...@@ -284,6 +284,14 @@ static int hiddev_open(struct inode *inode, struct file *file)
spin_unlock_irq(&list->hiddev->list_lock); spin_unlock_irq(&list->hiddev->list_lock);
mutex_lock(&hiddev->existancelock); mutex_lock(&hiddev->existancelock);
/*
* recheck exist with existance lock held to
* avoid opening a disconnected device
*/
if (!list->hiddev->exist) {
res = -ENODEV;
goto bail_unlock;
}
if (!list->hiddev->open++) if (!list->hiddev->open++)
if (list->hiddev->exist) { if (list->hiddev->exist) {
struct hid_device *hid = hiddev->hid; struct hid_device *hid = hiddev->hid;
...@@ -300,6 +308,10 @@ static int hiddev_open(struct inode *inode, struct file *file) ...@@ -300,6 +308,10 @@ static int hiddev_open(struct inode *inode, struct file *file)
hid_hw_power(hid, PM_HINT_NORMAL); hid_hw_power(hid, PM_HINT_NORMAL);
bail_unlock: bail_unlock:
mutex_unlock(&hiddev->existancelock); mutex_unlock(&hiddev->existancelock);
spin_lock_irq(&list->hiddev->list_lock);
list_del(&list->node);
spin_unlock_irq(&list->hiddev->list_lock);
bail: bail:
file->private_data = NULL; file->private_data = NULL;
vfree(list); vfree(list);
......
...@@ -533,14 +533,14 @@ static int wacom_intuos_pad(struct wacom_wac *wacom) ...@@ -533,14 +533,14 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
*/ */
buttons = (data[4] << 1) | (data[3] & 0x01); buttons = (data[4] << 1) | (data[3] & 0x01);
} else if (features->type == CINTIQ_COMPANION_2) { } else if (features->type == CINTIQ_COMPANION_2) {
/* d-pad right -> data[4] & 0x10 /* d-pad right -> data[2] & 0x10
* d-pad up -> data[4] & 0x20 * d-pad up -> data[2] & 0x20
* d-pad left -> data[4] & 0x40 * d-pad left -> data[2] & 0x40
* d-pad down -> data[4] & 0x80 * d-pad down -> data[2] & 0x80
* d-pad center -> data[3] & 0x01 * d-pad center -> data[1] & 0x01
*/ */
buttons = ((data[2] >> 4) << 7) | buttons = ((data[2] >> 4) << 7) |
((data[1] & 0x04) << 6) | ((data[1] & 0x04) << 4) |
((data[2] & 0x0F) << 2) | ((data[2] & 0x0F) << 2) |
(data[1] & 0x03); (data[1] & 0x03);
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) { } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment