diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hid/Makefile | 6 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 31 | ||||
-rw-r--r-- | drivers/hid/hid-cypress.c | 6 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 28 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-lenovo.c | 9 | ||||
-rw-r--r-- | drivers/hid/hid-lg.c | 24 | ||||
-rw-r--r-- | drivers/hid/hid-lg4ff.c | 458 | ||||
-rw-r--r-- | drivers/hid/hid-lg4ff.h | 4 | ||||
-rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 227 | ||||
-rw-r--r-- | drivers/hid/hid-microsoft.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-prodikeys.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-rmi.c | 6 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 6 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 4 | ||||
-rw-r--r-- | drivers/usb/misc/ldusb.c | 10 |
16 files changed, 583 insertions, 244 deletions
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index e4a21dfd7ef3..2f8a41dc3cc8 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o -obj-$(CONFIG_HID_AUREAL) += hid-aureal.o +obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o @@ -46,12 +46,12 @@ obj-$(CONFIG_HID_ICADE) += hid-icade.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.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_LENOVO) += hid-lenovo.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.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_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 722a925795a2..d74f0fb14b81 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -706,7 +706,8 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) if (hid->vendor == USB_VENDOR_ID_MICROSOFT && (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP) && + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP || + hid->product == USB_DEVICE_ID_MS_POWER_COVER) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; @@ -1061,13 +1062,13 @@ static u32 s32ton(__s32 value, unsigned n) * Search linux-kernel and linux-usb-devel archives for "hid-core extract". */ -static __u32 extract(const struct hid_device *hid, __u8 *report, +__u32 hid_field_extract(const struct hid_device *hid, __u8 *report, unsigned offset, unsigned n) { u64 x; if (n > 32) - hid_warn(hid, "extract() called with n (%d) > 32! (%s)\n", + hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n", n, current->comm); report += offset >> 3; /* adjust byte index */ @@ -1076,6 +1077,7 @@ static __u32 extract(const struct hid_device *hid, __u8 *report, x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ return (u32) x; } +EXPORT_SYMBOL_GPL(hid_field_extract); /* * "implement" : set bits in a little endian bit stream. @@ -1221,9 +1223,9 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, for (n = 0; n < count; n++) { value[n] = min < 0 ? - snto32(extract(hid, data, offset + n * size, size), - size) : - extract(hid, data, offset + n * size, size); + snto32(hid_field_extract(hid, data, offset + n * size, + size), size) : + hid_field_extract(hid, data, offset + n * size, size); /* Ignore report if ErrorRollOver */ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && @@ -1901,6 +1903,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, @@ -2265,14 +2268,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) }, @@ -2399,14 +2394,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) }, { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) }, #endif - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) }, { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) }, { } diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index c4ef3bc726e3..1b764d1745f3 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -41,13 +41,9 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, for (i = 0; i < *rsize - 4; i++) if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) { - __u8 tmp; - rdesc[i] = 0x19; rdesc[i + 2] = 0x29; - tmp = rdesc[i + 3]; - rdesc[i + 3] = rdesc[i + 1]; - rdesc[i + 1] = tmp; + swap(rdesc[i + 3], rdesc[i + 1]); } return rdesc; } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 51028ae32293..36da5a41a44a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -364,16 +364,6 @@ #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A 0x010a #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100 -#define USB_VENDOR_ID_GLAB 0x06c2 -#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 -#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 -#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040 -#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044 -#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045 -#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051 -#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053 -#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058 - #define USB_VENDOR_ID_GOODTOUCH 0x1aad #define USB_DEVICE_ID_GOODTOUCH_000f 0x000f @@ -674,6 +664,7 @@ #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc #define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd +#define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 @@ -959,13 +950,6 @@ #define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061 #define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068 -#define USB_VENDOR_ID_VERNIER 0x08f7 -#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 -#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 -#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 -#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 -#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006 - #define USB_VENDOR_ID_VTL 0x0306 #define USB_DEVICE_ID_VTL_MULTITOUCH_FF3F 0xff3f @@ -984,9 +968,6 @@ #define USB_VENDOR_ID_WISEGROUP 0x0925 #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 -#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 -#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 -#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201 #define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 #define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800 #define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866 @@ -1040,4 +1021,11 @@ #define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */ #define USB_DEVICE_ID_RI_KA_WEBMAIL 0x1320 /* Webmail Notifier */ +#define USB_VENDOR_ID_MULTIPLE_1781 0x1781 +#define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a8d + +#define USB_VENDOR_ID_DRACAL_RAPHNET 0x289b +#define USB_DEVICE_ID_RAPHNET_2NES2SNES 0x0002 +#define USB_DEVICE_ID_RAPHNET_4NES4SNES 0x0003 + #endif diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 008e89bf6f3c..3511bbaba505 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1157,7 +1157,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; /* report the usage code as scancode if the key status has changed */ - if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) + if (usage->type == EV_KEY && + (!test_bit(usage->code, input->key)) == value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); input_event(input, usage->type, usage->code, value); diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index c4c3f0952521..64ed3e3f227a 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -599,7 +599,8 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) GFP_KERNEL); if (data_pointer == NULL) { hid_err(hdev, "Could not allocate memory for driver data\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } // set same default values as windows driver @@ -610,7 +611,8 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); if (name_mute == NULL || name_micmute == NULL) { hid_err(hdev, "Could not allocate memory for led data\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); @@ -634,6 +636,9 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) lenovo_features_set_tpkbd(hdev); return 0; +err: + sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd); + return ret; } static int lenovo_probe_cptkbd(struct hid_device *hdev) diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index b86c18e651ed..429340d809b5 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -700,7 +700,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) /* insert a little delay of 10 jiffies ~ 40ms */ wait_queue_head_t wait; init_waitqueue_head (&wait); - wait_event_interruptible_timeout(wait, 0, 10); + wait_event_interruptible_timeout(wait, 0, + msecs_to_jiffies(40)); /* Select random Address */ buf[1] = 0xB2; @@ -712,13 +713,16 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) } if (drv_data->quirks & LG_FF) - lgff_init(hdev); - if (drv_data->quirks & LG_FF2) - lg2ff_init(hdev); - if (drv_data->quirks & LG_FF3) - lg3ff_init(hdev); - if (drv_data->quirks & LG_FF4) - lg4ff_init(hdev); + ret = lgff_init(hdev); + else if (drv_data->quirks & LG_FF2) + ret = lg2ff_init(hdev); + else if (drv_data->quirks & LG_FF3) + ret = lg3ff_init(hdev); + else if (drv_data->quirks & LG_FF4) + ret = lg4ff_init(hdev); + + if (ret) + goto err_free; return 0; err_free: @@ -731,8 +735,8 @@ static void lg_remove(struct hid_device *hdev) struct lg_drv_data *drv_data = hid_get_drvdata(hdev); if (drv_data->quirks & LG_FF4) lg4ff_deinit(hdev); - - hid_hw_stop(hdev); + else + hid_hw_stop(hdev); kfree(drv_data); } diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 1232210b1cc5..02cec83caac3 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -68,26 +68,32 @@ #define LG4FF_FFEX_REV_MAJ 0x21 #define LG4FF_FFEX_REV_MIN 0x00 -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); - -struct lg4ff_device_entry { - __u32 product_id; - __u16 range; - __u16 min_range; - __u16 max_range; +static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range); +static void lg4ff_set_range_g25(struct hid_device *hid, u16 range); + +struct lg4ff_wheel_data { + const u32 product_id; + u16 range; + const u16 min_range; + const u16 max_range; #ifdef CONFIG_LEDS_CLASS - __u8 led_state; + u8 led_state; struct led_classdev *led[5]; #endif - u32 alternate_modes; - const char *real_tag; - const char *real_name; - u16 real_product_id; - struct list_head list; + const u32 alternate_modes; + const char * const real_tag; + const char * const real_name; + const u16 real_product_id; + void (*set_range)(struct hid_device *hid, u16 range); }; +struct lg4ff_device_entry { + spinlock_t report_lock; /* Protect output HID report */ + struct hid_report *report; + struct lg4ff_wheel_data wdata; +}; + static const signed short lg4ff_wheel_effects[] = { FF_CONSTANT, FF_AUTOCENTER, @@ -95,16 +101,16 @@ static const signed short lg4ff_wheel_effects[] = { }; struct lg4ff_wheel { - const __u32 product_id; + const u32 product_id; const signed short *ff_effects; - const __u16 min_range; - const __u16 max_range; + const u16 min_range; + const u16 max_range; void (*set_range)(struct hid_device *hid, u16 range); }; struct lg4ff_compat_mode_switch { - const __u8 cmd_count; /* Number of commands to send */ - const __u8 cmd[]; + const u8 cmd_count; /* Number of commands to send */ + const u8 cmd[]; }; struct lg4ff_wheel_ident_info { @@ -134,10 +140,10 @@ struct lg4ff_alternate_mode { 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_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_dfp}, + {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, 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} }; @@ -245,10 +251,10 @@ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext16_g25 = { }; /* Recalculates X axis value accordingly to currently selected range */ -static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) +static s32 lg4ff_adjust_dfp_x_axis(s32 value, u16 range) { - __u16 max_range; - __s32 new_value; + u16 max_range; + s32 new_value; if (range == 900) return value; @@ -269,21 +275,21 @@ static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) } int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) + struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data) { struct lg4ff_device_entry *entry = drv_data->device_props; - __s32 new_value = 0; + s32 new_value = 0; if (!entry) { hid_err(hid, "Device properties not found"); return 0; } - switch (entry->product_id) { + switch (entry->wdata.product_id) { case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: switch (usage->code) { case ABS_X: - new_value = lg4ff_adjust_dfp_x_axis(value, entry->range); + new_value = lg4ff_adjust_dfp_x_axis(value, entry->wdata.range); input_event(field->hidinput->input, usage->type, usage->code, new_value); return 1; default: @@ -294,14 +300,56 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, } } -static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) +static void lg4ff_init_wheel_data(struct lg4ff_wheel_data * const wdata, const struct lg4ff_wheel *wheel, + const struct lg4ff_multimode_wheel *mmode_wheel, + const u16 real_product_id) +{ + u32 alternate_modes = 0; + const char *real_tag = NULL; + const char *real_name = NULL; + + if (mmode_wheel) { + alternate_modes = mmode_wheel->alternate_modes; + real_tag = mmode_wheel->real_tag; + real_name = mmode_wheel->real_name; + } + + { + struct lg4ff_wheel_data t_wdata = { .product_id = wheel->product_id, + .real_product_id = real_product_id, + .min_range = wheel->min_range, + .max_range = wheel->max_range, + .set_range = wheel->set_range, + .alternate_modes = alternate_modes, + .real_tag = real_tag, + .real_name = real_name }; + + memcpy(wdata, &t_wdata, sizeof(t_wdata)); + } +} + +static int 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; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; + s32 *value; int x; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return -EINVAL; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return -EINVAL; + } + value = entry->report->field[0]->value; + #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) switch (effect->type) { @@ -309,6 +357,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ CLAMP(x); + spin_lock_irqsave(&entry->report_lock, flags); if (x == 0x80) { /* De-activate force in slot-1*/ value[0] = 0x13; @@ -319,7 +368,8 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); return 0; } @@ -331,7 +381,8 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); break; } return 0; @@ -339,15 +390,16 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e /* 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) +static void 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; - __u32 expand_a, expand_b; + s32 *value = report->field[0]->value; + u32 expand_a, expand_b; struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; + unsigned long flags; drv_data = hid_get_drvdata(hid); if (!drv_data) { @@ -360,8 +412,10 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud hid_err(hid, "Device properties not found!\n"); return; } + value = entry->report->field[0]->value; /* De-activate Auto-Center */ + spin_lock_irqsave(&entry->report_lock, flags); if (magnitude == 0) { value[0] = 0xf5; value[1] = 0x00; @@ -371,7 +425,8 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); return; } @@ -384,7 +439,7 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud } /* Adjust for non-MOMO wheels */ - switch (entry->product_id) { + switch (entry->wdata.product_id) { case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: break; @@ -401,7 +456,7 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); /* Activate Auto-Center */ value[0] = 0x14; @@ -412,18 +467,34 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } /* Sends autocentering command compatible with Formula Force EX */ -static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) +static void 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); - __s32 *value = report->field[0]->value; + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; + s32 *value; magnitude = magnitude * 90 / 65535; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return; + } + value = entry->report->field[0]->value; + + spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xfe; value[1] = 0x03; value[2] = magnitude >> 14; @@ -432,18 +503,33 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } /* 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) +static void 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); - __s32 *value = report->field[0]->value; + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; + s32 *value; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return; + } + value = entry->report->field[0]->value; dbg_hid("G25/G27/DFGT: setting range to %u\n", range); + spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xf8; value[1] = 0x81; value[2] = range & 0x00ff; @@ -452,20 +538,35 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } /* Sends commands to set range compatible with Driving Force Pro wheel */ -static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) +static void 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); + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; int start_left, start_right, full_range; - __s32 *value = report->field[0]->value; + s32 *value; + + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return; + } + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return; + } + value = entry->report->field[0]->value; dbg_hid("Driving Force Pro: setting range to %u\n", range); /* Prepare "coarse" limit command */ + spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xf8; value[1] = 0x00; /* Set later */ value[2] = 0x00; @@ -475,13 +576,13 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) value[6] = 0x00; if (range > 200) { - report->field[0]->value[1] = 0x03; + value[1] = 0x03; full_range = 900; } else { - report->field[0]->value[1] = 0x02; + value[1] = 0x02; full_range = 200; } - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); /* Prepare "fine" limit command */ value[0] = 0x81; @@ -493,7 +594,8 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) value[6] = 0x00; if (range == 200 || range == 900) { /* Do not apply any fine limit */ - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); return; } @@ -507,7 +609,8 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); value[6] = 0xff; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(const u16 real_product_id, const u16 target_product_id) @@ -569,19 +672,35 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct lg4ff_compat_mode_switch *s) { - 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; + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; + s32 *value; u8 i; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return -EINVAL; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return -EINVAL; + } + value = entry->report->field[0]->value; + + spin_lock_irqsave(&entry->report_lock, flags); for (i = 0; i < s->cmd_count; i++) { u8 j; for (j = 0; j < 7; j++) value[j] = s->cmd[j + (7*i)]; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); } + spin_unlock_irqrestore(&entry->report_lock, flags); hid_hw_wait(hid); return 0; } @@ -606,23 +725,23 @@ static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct device_attr return 0; } - if (!entry->real_name) { + if (!entry->wdata.real_name) { hid_err(hid, "NULL pointer to string\n"); return 0; } for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) { - if (entry->alternate_modes & BIT(i)) { + if (entry->wdata.alternate_modes & BIT(i)) { /* Print tag and full name */ count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s", lg4ff_alternate_modes[i].tag, - !lg4ff_alternate_modes[i].product_id ? entry->real_name : lg4ff_alternate_modes[i].name); + !lg4ff_alternate_modes[i].product_id ? entry->wdata.real_name : lg4ff_alternate_modes[i].name); if (count >= PAGE_SIZE - 1) return count; /* Mark the currently active mode with an asterisk */ - if (lg4ff_alternate_modes[i].product_id == entry->product_id || - (lg4ff_alternate_modes[i].product_id == 0 && entry->product_id == entry->real_product_id)) + if (lg4ff_alternate_modes[i].product_id == entry->wdata.product_id || + (lg4ff_alternate_modes[i].product_id == 0 && entry->wdata.product_id == entry->wdata.real_product_id)) count += scnprintf(buf + count, PAGE_SIZE - count, " *\n"); else count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); @@ -675,10 +794,10 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att const u16 mode_product_id = lg4ff_alternate_modes[i].product_id; const char *tag = lg4ff_alternate_modes[i].tag; - if (entry->alternate_modes & BIT(i)) { + if (entry->wdata.alternate_modes & BIT(i)) { if (!strcmp(tag, lbuf)) { if (!mode_product_id) - target_product_id = entry->real_product_id; + target_product_id = entry->wdata.real_product_id; else target_product_id = mode_product_id; break; @@ -693,24 +812,24 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att } kfree(lbuf); /* Not needed anymore */ - if (target_product_id == entry->product_id) /* Nothing to do */ + if (target_product_id == entry->wdata.product_id) /* Nothing to do */ return count; /* Automatic switching has to be disabled for the switch to DF-EX mode to work correctly */ if (target_product_id == USB_DEVICE_ID_LOGITECH_WHEEL && !lg4ff_no_autoswitch) { hid_info(hid, "\"%s\" cannot be switched to \"DF-EX\" mode. Load the \"hid_logitech\" module with \"lg4ff_no_autoswitch=1\" parameter set and try again\n", - entry->real_name); + entry->wdata.real_name); return -EINVAL; } /* Take care of hardware limitations */ - if ((entry->real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) && - entry->product_id > target_product_id) { - hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->real_name, lg4ff_alternate_modes[i].name); + if ((entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) && + entry->wdata.product_id > target_product_id) { + hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->wdata.real_name, lg4ff_alternate_modes[i].name); return -EINVAL; } - s = lg4ff_get_mode_switch_command(entry->real_product_id, target_product_id); + s = lg4ff_get_mode_switch_command(entry->wdata.real_product_id, target_product_id); if (!s) { hid_err(hid, "Invalid target product ID %X\n", target_product_id); return -EINVAL; @@ -721,9 +840,9 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct devic |