summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/Makefile6
-rw-r--r--drivers/hid/hid-core.c31
-rw-r--r--drivers/hid/hid-cypress.c6
-rw-r--r--drivers/hid/hid-ids.h28
-rw-r--r--drivers/hid/hid-input.c3
-rw-r--r--drivers/hid/hid-lenovo.c9
-rw-r--r--drivers/hid/hid-lg.c24
-rw-r--r--drivers/hid/hid-lg4ff.c458
-rw-r--r--drivers/hid/hid-lg4ff.h4
-rw-r--r--drivers/hid/hid-logitech-hidpp.c227
-rw-r--r--drivers/hid/hid-microsoft.c2
-rw-r--r--drivers/hid/hid-prodikeys.c3
-rw-r--r--drivers/hid/hid-rmi.c6
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c6
-rw-r--r--drivers/hid/usbhid/hid-quirks.c4
-rw-r--r--drivers/usb/misc/ldusb.c10
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