linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver
@ 2013-01-25  6:34 Simon Wood
  2013-01-25  6:34 ` [PATCH 2/4] USB: HID: SRW-S1 Add support for dials Simon Wood
                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: Simon Wood @ 2013-01-25  6:34 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

From: simon <simon@simon-virtual-machine.(none)>

Add support the SRW-S1 by patching HID descriptor to read axis
as Generic Desktop X, Y and Z (rather than Usage page being
'Simulation').

Signed-off-by: Simon Wood <simon@mungewell.org>
tested-by: John Murphy <rosegardener@freeode.co.uk>

---
 drivers/hid/Kconfig     |    6 +++++
 drivers/hid/Makefile    |    1 +
 drivers/hid/hid-core.c  |    1 +
 drivers/hid/hid-ids.h   |    3 +++
 drivers/hid/hid-srws1.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 drivers/hid/hid-srws1.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e7d6a13..3c98517 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -596,6 +596,12 @@ config HID_SPEEDLINK
 	---help---
 	Support for Speedlink Vicious and Divine Cezanne mouse.
 
+config HID_SRWS1
+	tristate "Steelseries SRW-S1 steering wheel support"
+	depends on USB_HID
+	---help---
+	Support for Steelseries SRW-S1 steering wheel
+
 config HID_SUNPLUS
 	tristate "Sunplus wireless desktop"
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index b622157..d3102e2 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
 obj-$(CONFIG_HID_SONY)		+= hid-sony.o
 obj-$(CONFIG_HID_SPEEDLINK)	+= hid-speedlink.o
+obj-$(CONFIG_HID_SRWS1)    	+= hid-srws1.o
 obj-$(CONFIG_HID_SUNPLUS)	+= hid-sunplus.o
 obj-$(CONFIG_HID_GREENASIA)	+= hid-gaff.o
 obj-$(CONFIG_HID_THRUSTMASTER)	+= hid-tmff.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index eb2ee11..65cda7f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1697,6 +1697,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 4dfa605..f5976f3 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -723,6 +723,9 @@
 #define USB_VENDOR_ID_STANTUM_SITRONIX		0x1403
 #define USB_DEVICE_ID_MTP_SITRONIX		0x5001
 
+#define USB_VENDOR_ID_STEELSERIES	0x1038
+#define USB_DEVICE_ID_STEELSERIES_SRWS1	0x1410
+
 #define USB_VENDOR_ID_SUN		0x0430
 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
 
diff --git a/drivers/hid/hid-srws1.c b/drivers/hid/hid-srws1.c
new file mode 100644
index 0000000..7776d74
--- /dev/null
+++ b/drivers/hid/hid-srws1.c
@@ -0,0 +1,58 @@
+/*
+ *  HID driver for Steelseries SRW-S1
+ *
+ *  Copyright (c) 2013 Simon Wood
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 *srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
+{
+	if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8
+			&& rdesc[29] == 0xbb && rdesc[40] == 0xc5) {
+		hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n");
+		rdesc[11] = 0x01;
+		rdesc[13] = 0x30;
+		rdesc[29] = 0x31;
+		rdesc[40] = 0x32;
+	}
+	return rdesc;
+}
+
+static const struct hid_device_id srws1_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, srws1_devices);
+
+static struct hid_driver srws1_driver = {
+	.name = "srws1",
+	.id_table = srws1_devices,
+	.report_fixup = srws1_report_fixup
+};
+
+static int __init srws1_init(void)
+{
+	return hid_register_driver(&srws1_driver);
+}
+
+static void __exit srws1_exit(void)
+{
+	hid_unregister_driver(&srws1_driver);
+}
+
+module_init(srws1_init);
+module_exit(srws1_exit);
+MODULE_LICENSE("GPL");
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/4] USB: HID: SRW-S1 Add support for dials
  2013-01-25  6:34 [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Simon Wood
@ 2013-01-25  6:34 ` Simon Wood
  2013-01-25  6:34 ` [PATCH 3/4] USB: HID: SRW-S1 Add support for LEDs Simon Wood
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 20+ messages in thread
From: Simon Wood @ 2013-01-25  6:34 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

From: simon <simon@simon-virtual-machine.(none)>

This patch to the SRW-S1 driver re-writes the HID descriptor
to insert a section for the 3 dials on the device, previously
these were contained within a 'Manufacturer Specific' usage
page.

Signed-off-by: Simon Wood <simon@mungewell.org>
tested-by: John Murphy <rosegardener@freeode.co.uk>

---
 drivers/hid/hid-srws1.c |   86 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 82 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/hid-srws1.c b/drivers/hid/hid-srws1.c
index 7776d74..4d8a86b 100644
--- a/drivers/hid/hid-srws1.c
+++ b/drivers/hid/hid-srws1.c
@@ -17,16 +17,94 @@
 
 #include "hid-ids.h"
 
+/* Fixed report descriptor for Steelseries SRW-S1 wheel controller
+ *
+ * The original descriptor hides the sensitivity and assists dials
+ * a custom vendor usage page. This inserts a patch to make them
+ * appear in the 'Generic Desktop' usage.
+ */
+
+static __u8 srws1_rdesc_fixed[] = {
+0x05, 0x01,         /*  Usage Page (Desktop)                */
+0x09, 0x08,         /*  Usage (MultiAxis), Changed          */
+0xA1, 0x01,         /*  Collection (Application),           */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x95, 0x01,         /*          Report Count (1),           */
+0x05, 0x01,         /* Changed  Usage Page (Desktop),       */
+0x09, 0x30,         /* Changed  Usage (X),                  */
+0x16, 0xF8, 0xF8,   /*          Logical Minimum (-1800),    */
+0x26, 0x08, 0x07,   /*          Logical Maximum (1800),     */
+0x65, 0x14,         /*          Unit (Degrees),             */
+0x55, 0x0F,         /*          Unit Exponent (15),         */
+0x75, 0x10,         /*          Report Size (16),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x31,         /* Changed  Usage (Y),                  */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+0x75, 0x0C,         /*          Report Size (12),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x32,         /* Changed  Usage (Z),                  */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+0x75, 0x0C,         /*          Report Size (12),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x05, 0x01,         /*          Usage Page (Desktop),       */
+0x09, 0x39,         /*          Usage (Hat Switch),         */
+0x25, 0x07,         /*          Logical Maximum (7),        */
+0x35, 0x00,         /*          Physical Minimum (0),       */
+0x46, 0x3B, 0x01,   /*          Physical Maximum (315),     */
+0x65, 0x14,         /*          Unit (Degrees),             */
+0x75, 0x04,         /*          Report Size (4),            */
+0x95, 0x01,         /*          Report Count (1),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x25, 0x01,         /*          Logical Maximum (1),        */
+0x45, 0x01,         /*          Physical Maximum (1),       */
+0x65, 0x00,         /*          Unit,                       */
+0x75, 0x01,         /*          Report Size (1),            */
+0x95, 0x03,         /*          Report Count (3),           */
+0x81, 0x01,         /*          Input (Constant),           */
+0x05, 0x09,         /*          Usage Page (Button),        */
+0x19, 0x01,         /*          Usage Minimum (01h),        */
+0x29, 0x11,         /*          Usage Maximum (11h),        */
+0x95, 0x11,         /*          Report Count (17),          */
+0x81, 0x02,         /*          Input (Variable),           */
+                    /*   ---- Dial patch starts here ----   */
+0x05, 0x01,         /*          Usage Page (Desktop),       */
+0x09, 0x33,         /*          Usage (RX),                 */
+0x75, 0x04,         /*          Report Size (4),            */
+0x95, 0x02,         /*          Report Count (2),           */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x25, 0x0b,         /*          Logical Maximum (b),        */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x35,         /*          Usage (RZ),                 */
+0x75, 0x04,         /*          Report Size (4),            */
+0x95, 0x01,         /*          Report Count (1),           */
+0x25, 0x03,         /*          Logical Maximum (3),        */
+0x81, 0x02,         /*          Input (Variable),           */
+                    /*    ---- Dial patch ends here ----    */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+0x09, 0x01,         /*          Usage (01h),                */
+0x75, 0x04,         /* Changed  Report Size (4),            */
+0x95, 0x0D,         /* Changed  Report Count (13),          */
+0x81, 0x02,         /*          Input (Variable),           */
+0xC0,               /*      End Collection,                 */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x09, 0x02,         /*          Usage (02h),                */
+0x75, 0x08,         /*          Report Size (8),            */
+0x95, 0x10,         /*          Report Count (16),          */
+0x91, 0x02,         /*          Output (Variable),          */
+0xC0,               /*      End Collection,                 */
+0xC0                /*  End Collection                      */
+};
+
 static __u8 *srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
 	if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8
 			&& rdesc[29] == 0xbb && rdesc[40] == 0xc5) {
 		hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n");
-		rdesc[11] = 0x01;
-		rdesc[13] = 0x30;
-		rdesc[29] = 0x31;
-		rdesc[40] = 0x32;
+		rdesc = srws1_rdesc_fixed;
+		*rsize = sizeof(srws1_rdesc_fixed);
 	}
 	return rdesc;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/4] USB: HID: SRW-S1 Add support for LEDs
  2013-01-25  6:34 [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Simon Wood
  2013-01-25  6:34 ` [PATCH 2/4] USB: HID: SRW-S1 Add support for dials Simon Wood
@ 2013-01-25  6:34 ` Simon Wood
  2013-01-25  6:34 ` [PATCH 4/4] USB: HID: SRW-S1 Add support controlling all LEDs simultaneously Simon Wood
  2013-01-28 14:59 ` [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Jiri Kosina
  3 siblings, 0 replies; 20+ messages in thread
From: Simon Wood @ 2013-01-25  6:34 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

From: simon <simon@simon-virtual-machine.(none)>

This patch to the SRW-S1 driver adds support for the LED RPM
meter on the front of the device. The LEDs are controlled via
/sys/class/leds interface, with an individual control for each
of the 15 LEDs.

Signed-off-by: Simon Wood <simon@mungewell.org>
tested-by: John Murphy <rosegardener@freeode.co.uk>

---
 Documentation/ABI/testing/sysfs-driver-hid-srws1 |   20 +++
 drivers/hid/hid-srws1.c                          |  199 ++++++++++++++++++++++
 2 files changed, 219 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-srws1

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-srws1 b/Documentation/ABI/testing/sysfs-driver-hid-srws1
new file mode 100644
index 0000000..c27b34d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-srws1
@@ -0,0 +1,20 @@
+What:		/sys/class/leds/SRWS1::<serial>::RPM1
+What:		/sys/class/leds/SRWS1::<serial>::RPM2
+What:		/sys/class/leds/SRWS1::<serial>::RPM3
+What:		/sys/class/leds/SRWS1::<serial>::RPM4
+What:		/sys/class/leds/SRWS1::<serial>::RPM5
+What:		/sys/class/leds/SRWS1::<serial>::RPM6
+What:		/sys/class/leds/SRWS1::<serial>::RPM7
+What:		/sys/class/leds/SRWS1::<serial>::RPM8
+What:		/sys/class/leds/SRWS1::<serial>::RPM9
+What:		/sys/class/leds/SRWS1::<serial>::RPM10
+What:		/sys/class/leds/SRWS1::<serial>::RPM11
+What:		/sys/class/leds/SRWS1::<serial>::RPM12
+What:		/sys/class/leds/SRWS1::<serial>::RPM13
+What:		/sys/class/leds/SRWS1::<serial>::RPM14
+What:		/sys/class/leds/SRWS1::<serial>::RPM15
+Date:		Jan 2013
+KernelVersion:	3.9
+Contact:	Simon Wood <simon@mungewell.org>
+Description:	Provides a control for turning on/off the LEDs which form
+		an RPM meter on the front of the controller
diff --git a/drivers/hid/hid-srws1.c b/drivers/hid/hid-srws1.c
index 4d8a86b..6005b84 100644
--- a/drivers/hid/hid-srws1.c
+++ b/drivers/hid/hid-srws1.c
@@ -12,11 +12,21 @@
  */
 
 #include <linux/device.h>
+#include <linux/usb.h>
 #include <linux/hid.h>
 #include <linux/module.h>
 
+#include "usbhid/usbhid.h"
 #include "hid-ids.h"
 
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#define SRWS1_NUMBER_LEDS 15
+struct srws1_data {
+	__u16 led_state;
+	struct led_classdev *led[SRWS1_NUMBER_LEDS];
+};
+#endif
+
 /* Fixed report descriptor for Steelseries SRW-S1 wheel controller
  *
  * The original descriptor hides the sensitivity and assists dials
@@ -97,6 +107,191 @@ static __u8 srws1_rdesc_fixed[] = {
 0xC0                /*  End Collection                      */
 };
 
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+static void srws1_set_leds(struct hid_device *hdev, __u16 leds)
+{
+	struct list_head *report_list = &hdev->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[0] = 0x40;
+	value[1] = leds;
+	value[2] = leds >> 8;
+	value[3] = 0x00;
+	value[4] = 0x00;
+	value[5] = 0x00;
+	value[6] = 0x00;
+	value[7] = 0x00;
+	value[8] = 0x00;
+	value[9] = 0x00;
+	value[10] = 0x00;
+	value[11] = 0x00;
+	value[12] = 0x00;
+	value[13] = 0x00;
+	value[14] = 0x00;
+	value[15] = 0x00;
+
+	usbhid_submit_report(hdev, report, USB_DIR_OUT);
+
+	/* Note: LED change does not show on device until the device is read/polled */
+}
+
+static void srws1_led_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct srws1_data *drv_data = hid_get_drvdata(hid);
+	int i, state = 0;
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return;
+	}
+
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+		if (led_cdev != drv_data->led[i])
+			continue;
+
+		state = (drv_data->led_state >> i) & 1;
+		if (value == LED_OFF && state) {
+			drv_data->led_state &= ~(1 << i);
+			srws1_set_leds(hid, drv_data->led_state);
+		} else if (value != LED_OFF && !state) {
+			drv_data->led_state |= 1 << i;
+			srws1_set_leds(hid, drv_data->led_state);
+		}
+		break;
+	}
+}
+
+static enum led_brightness srws1_led_get_brightness(struct led_classdev *led_cdev)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct srws1_data *drv_data;
+	int i, value = 0;
+
+	drv_data = hid_get_drvdata(hid);
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return LED_OFF;
+	}
+
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
+		if (led_cdev == drv_data->led[i]) {
+			value = (drv_data->led_state >> i) & 1;
+			break;
+		}
+
+	return value ? LED_FULL : LED_OFF;
+}
+
+static int srws1_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	int ret, i;
+	struct led_classdev *led;
+	size_t name_sz;
+	char *name;
+
+	struct srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+
+	if (drv_data == NULL) {
+		hid_err(hdev, "can't alloc SRW-S1 memory\n");
+		return -ENOMEM;
+	}
+
+	hid_set_drvdata(hdev, drv_data);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		goto err_free;
+	}
+
+	/* register led subsystem */
+	drv_data->led_state = 0;
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
+		drv_data->led[i] = NULL;
+
+	srws1_set_leds(hdev, 0);
+
+	name_sz = strlen(hdev->uniq) + 15;
+
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+		if (!led) {
+			hid_err(hdev, "can't allocate memory for LED %d\n", i);
+			goto err_led;
+		}
+
+		name = (void *)(&led[1]);
+		snprintf(name, name_sz, "SRWS1::%s::RPM%d", hdev->uniq, i+1);
+		led->name = name;
+		led->brightness = 0;
+		led->max_brightness = 1;
+		led->brightness_get = srws1_led_get_brightness;
+		led->brightness_set = srws1_led_set_brightness;
+
+		drv_data->led[i] = led;
+		ret = led_classdev_register(&hdev->dev, led);
+
+		if (ret) {
+			hid_err(hdev, "failed to register LED %d. Aborting.\n", i);
+err_led:
+			/* Deregister all LEDs (if any) */
+			for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+				led = drv_data->led[i];
+				drv_data->led[i] = NULL;
+				if (!led)
+					continue;
+				led_classdev_unregister(led);
+				kfree(led);
+			}
+			goto out;	/* but let the driver continue without LEDs */
+		}
+	}
+out:
+	return 0;
+err_free:
+	kfree(drv_data);
+	return ret;
+}
+
+static void srws1_remove(struct hid_device *hdev)
+{
+	int i;
+	struct led_classdev *led;
+
+	struct srws1_data *drv_data = hid_get_drvdata(hdev);
+
+	if (drv_data) {
+		/* Deregister LEDs (if any) */
+		for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+			led = drv_data->led[i];
+			drv_data->led[i] = NULL;
+			if (!led)
+				continue;
+			led_classdev_unregister(led);
+			kfree(led);
+		}
+
+	}
+
+	hid_hw_stop(hdev);
+	kfree(drv_data);
+	return;
+}
+#endif
+
 static __u8 *srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
@@ -118,6 +313,10 @@ MODULE_DEVICE_TABLE(hid, srws1_devices);
 static struct hid_driver srws1_driver = {
 	.name = "srws1",
 	.id_table = srws1_devices,
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+	.probe = srws1_probe,
+	.remove = srws1_remove,
+#endif
 	.report_fixup = srws1_report_fixup
 };
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/4] USB: HID: SRW-S1 Add support controlling all LEDs simultaneously
  2013-01-25  6:34 [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Simon Wood
  2013-01-25  6:34 ` [PATCH 2/4] USB: HID: SRW-S1 Add support for dials Simon Wood
  2013-01-25  6:34 ` [PATCH 3/4] USB: HID: SRW-S1 Add support for LEDs Simon Wood
@ 2013-01-25  6:34 ` Simon Wood
  2013-01-28 15:02   ` Jiri Kosina
  2013-01-28 14:59 ` [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Jiri Kosina
  3 siblings, 1 reply; 20+ messages in thread
From: Simon Wood @ 2013-01-25  6:34 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

From: simon <simon@simon-virtual-machine.(none)>

This patch to the SRW-S1 driver adds the ability to control all
LEDs simultaneously as testing showed that it was slow (noticably!!)
when seting or clearing all the LEDs in turn.

It adds a 'RPMALL' LED, whose behavoir is asserted to all the LEDs in
the bar graph, individual LEDs can subsequently be turned on/off
individually.

Signed-off-by: Simon Wood <simon@mungewell.org>
tested-by: John Murphy <rosegardener@freeode.co.uk>

---
 Documentation/ABI/testing/sysfs-driver-hid-srws1 |    1 +
 drivers/hid/hid-srws1.c                          |   67 ++++++++++++++++++++--
 2 files changed, 63 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-srws1 b/Documentation/ABI/testing/sysfs-driver-hid-srws1
index c27b34d..d0eba70 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-srws1
+++ b/Documentation/ABI/testing/sysfs-driver-hid-srws1
@@ -13,6 +13,7 @@ What:		/sys/class/leds/SRWS1::<serial>::RPM12
 What:		/sys/class/leds/SRWS1::<serial>::RPM13
 What:		/sys/class/leds/SRWS1::<serial>::RPM14
 What:		/sys/class/leds/SRWS1::<serial>::RPM15
+What:		/sys/class/leds/SRWS1::<serial>::RPMALL
 Date:		Jan 2013
 KernelVersion:	3.9
 Contact:	Simon Wood <simon@mungewell.org>
diff --git a/drivers/hid/hid-srws1.c b/drivers/hid/hid-srws1.c
index 6005b84..2604e4e 100644
--- a/drivers/hid/hid-srws1.c
+++ b/drivers/hid/hid-srws1.c
@@ -23,7 +23,7 @@
 #define SRWS1_NUMBER_LEDS 15
 struct srws1_data {
 	__u16 led_state;
-	struct led_classdev *led[SRWS1_NUMBER_LEDS];
+	struct led_classdev *led[SRWS1_NUMBER_LEDS + 1]; /* including 'ALL' led */
 };
 #endif
 
@@ -136,6 +136,42 @@ static void srws1_set_leds(struct hid_device *hdev, __u16 leds)
 	/* Note: LED change does not show on device until the device is read/polled */
 }
 
+static void srws1_led_all_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct srws1_data *drv_data = hid_get_drvdata(hid);
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return;
+	}
+
+	if (value == LED_OFF)
+		drv_data->led_state = 0;
+	else
+		drv_data->led_state = (1 << (SRWS1_NUMBER_LEDS + 1)) - 1;
+
+	srws1_set_leds(hid, drv_data->led_state);
+}
+
+static enum led_brightness srws1_led_all_get_brightness(struct led_classdev *led_cdev)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct srws1_data *drv_data;
+
+	drv_data = hid_get_drvdata(hid);
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return LED_OFF;
+	}
+
+	return (drv_data->led_state >> SRWS1_NUMBER_LEDS) ? LED_FULL : LED_OFF;
+}
+
 static void srws1_led_set_brightness(struct led_classdev *led_cdev,
 			enum led_brightness value)
 {
@@ -219,13 +255,34 @@ static int srws1_probe(struct hid_device *hdev,
 
 	/* register led subsystem */
 	drv_data->led_state = 0;
-	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
+	for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++)
 		drv_data->led[i] = NULL;
 
 	srws1_set_leds(hdev, 0);
 
-	name_sz = strlen(hdev->uniq) + 15;
+	name_sz = strlen(hdev->uniq) + 16;
+
+	/* 'ALL', for setting all LEDs simultaneously */
+	led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+	if (!led) {
+		hid_err(hdev, "can't allocate memory for LED ALL\n");
+		goto err_led;
+	}
+
+	name = (void *)(&led[1]);
+	snprintf(name, name_sz, "SRWS1::%s::RPMALL", hdev->uniq);
+	led->name = name;
+	led->brightness = 0;
+	led->max_brightness = 1;
+	led->brightness_get = srws1_led_all_get_brightness;
+	led->brightness_set = srws1_led_all_set_brightness;
+
+	drv_data->led[SRWS1_NUMBER_LEDS] = led;
+	ret = led_classdev_register(&hdev->dev, led);
+	if (ret)
+		goto err_led;
 
+	/* Each individual LED */
 	for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
 		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
 		if (!led) {
@@ -248,7 +305,7 @@ static int srws1_probe(struct hid_device *hdev,
 			hid_err(hdev, "failed to register LED %d. Aborting.\n", i);
 err_led:
 			/* Deregister all LEDs (if any) */
-			for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+			for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
 				led = drv_data->led[i];
 				drv_data->led[i] = NULL;
 				if (!led)
@@ -275,7 +332,7 @@ static void srws1_remove(struct hid_device *hdev)
 
 	if (drv_data) {
 		/* Deregister LEDs (if any) */
-		for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+		for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
 			led = drv_data->led[i];
 			drv_data->led[i] = NULL;
 			if (!led)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-25  6:34 [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Simon Wood
                   ` (2 preceding siblings ...)
  2013-01-25  6:34 ` [PATCH 4/4] USB: HID: SRW-S1 Add support controlling all LEDs simultaneously Simon Wood
@ 2013-01-28 14:59 ` Jiri Kosina
  2013-01-28 15:38   ` simon
  3 siblings, 1 reply; 20+ messages in thread
From: Jiri Kosina @ 2013-01-28 14:59 UTC (permalink / raw)
  To: Simon Wood; +Cc: linux-input, linux-kernel, rosegardener

On Thu, 24 Jan 2013, Simon Wood wrote:

> From: simon <simon@simon-virtual-machine.(none)>
> 
> Add support the SRW-S1 by patching HID descriptor to read axis
> as Generic Desktop X, Y and Z (rather than Usage page being
> 'Simulation').
> 
> Signed-off-by: Simon Wood <simon@mungewell.org>
> tested-by: John Murphy <rosegardener@freeode.co.uk>

Hi Simon,

thanks for the patch.

> 
> ---
>  drivers/hid/Kconfig     |    6 +++++
>  drivers/hid/Makefile    |    1 +
>  drivers/hid/hid-core.c  |    1 +
>  drivers/hid/hid-ids.h   |    3 +++
>  drivers/hid/hid-srws1.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++

Is hid-srws1 really the best name? My understanding is that the vendor is 
called Steelseries, and we mostly stick to calling the drivers according 
to the device vendors (and grouping the quirks accordingly).

So how about hid-steelseries? 

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/4] USB: HID: SRW-S1 Add support controlling all LEDs simultaneously
  2013-01-25  6:34 ` [PATCH 4/4] USB: HID: SRW-S1 Add support controlling all LEDs simultaneously Simon Wood
@ 2013-01-28 15:02   ` Jiri Kosina
  2013-01-28 15:24     ` simon
  0 siblings, 1 reply; 20+ messages in thread
From: Jiri Kosina @ 2013-01-28 15:02 UTC (permalink / raw)
  To: Simon Wood; +Cc: linux-input, linux-kernel, rosegardener

On Thu, 24 Jan 2013, Simon Wood wrote:

> From: simon <simon@simon-virtual-machine.(none)>
> 
> This patch to the SRW-S1 driver adds the ability to control all
> LEDs simultaneously as testing showed that it was slow (noticably!!)
> when seting or clearing all the LEDs in turn.
> 
> It adds a 'RPMALL' LED, whose behavoir is asserted to all the LEDs in
> the bar graph, individual LEDs can subsequently be turned on/off
> individually.
> 
> Signed-off-by: Simon Wood <simon@mungewell.org>
> tested-by: John Murphy <rosegardener@freeode.co.uk>
[ ... snip ... ]

> @@ -219,13 +255,34 @@ static int srws1_probe(struct hid_device *hdev,
>  
>  	/* register led subsystem */
>  	drv_data->led_state = 0;
> -	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
> +	for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++)
>  		drv_data->led[i] = NULL;
>  
>  	srws1_set_leds(hdev, 0);
>  
> -	name_sz = strlen(hdev->uniq) + 15;
> +	name_sz = strlen(hdev->uniq) + 16;
> +
> +	/* 'ALL', for setting all LEDs simultaneously */
> +	led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);

Is this memory ever freed?

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/4] USB: HID: SRW-S1 Add support controlling all LEDs simultaneously
  2013-01-28 15:02   ` Jiri Kosina
@ 2013-01-28 15:24     ` simon
  0 siblings, 0 replies; 20+ messages in thread
From: simon @ 2013-01-28 15:24 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Simon Wood, linux-input, linux-kernel, rosegardener

> On Thu, 24 Jan 2013, Simon Wood wrote:
>
>> From: simon <simon@simon-virtual-machine.(none)>
>>
>> This patch to the SRW-S1 driver adds the ability to control all
>> LEDs simultaneously as testing showed that it was slow (noticably!!)
>> when seting or clearing all the LEDs in turn.
>>
>> It adds a 'RPMALL' LED, whose behavoir is asserted to all the LEDs in
>> the bar graph, individual LEDs can subsequently be turned on/off
>> individually.
>>
>> Signed-off-by: Simon Wood <simon@mungewell.org>
>> tested-by: John Murphy <rosegardener@freeode.co.uk>
> [ ... snip ... ]
>
>> @@ -219,13 +255,34 @@ static int srws1_probe(struct hid_device *hdev,
>>
>>  	/* register led subsystem */
>>  	drv_data->led_state = 0;
>> -	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
>> +	for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++)
>>  		drv_data->led[i] = NULL;
>>
>>  	srws1_set_leds(hdev, 0);
>>
>> -	name_sz = strlen(hdev->uniq) + 15;
>> +	name_sz = strlen(hdev->uniq) + 16;
>> +
>> +	/* 'ALL', for setting all LEDs simultaneously */
>> +	led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
>
> Is this memory ever freed?

Yes. The pointer to it is stored at the end of the drv_data leds[] array
(line 280), and will be free'd on probe fail (line 314) or when device is
removed (line 341).

Simon


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-28 14:59 ` [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Jiri Kosina
@ 2013-01-28 15:38   ` simon
  2013-01-28 16:56     ` Jiri Kosina
  0 siblings, 1 reply; 20+ messages in thread
From: simon @ 2013-01-28 15:38 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Simon Wood, linux-input, linux-kernel, rosegardener

> On Thu, 24 Jan 2013, Simon Wood wrote:
>
>> From: simon <simon@simon-virtual-machine.(none)>
>>
>> Add support the SRW-S1 by patching HID descriptor to read axis
>> as Generic Desktop X, Y and Z (rather than Usage page being
>> 'Simulation').
>>
>> Signed-off-by: Simon Wood <simon@mungewell.org>
>> tested-by: John Murphy <rosegardener@freeode.co.uk>
>
> Hi Simon,
>
> thanks for the patch.
>
>>
>> ---
>>  drivers/hid/Kconfig     |    6 +++++
>>  drivers/hid/Makefile    |    1 +
>>  drivers/hid/hid-core.c  |    1 +
>>  drivers/hid/hid-ids.h   |    3 +++
>>  drivers/hid/hid-srws1.c |   58
>> +++++++++++++++++++++++++++++++++++++++++++++++
>
> Is hid-srws1 really the best name? My understanding is that the vendor is
> called Steelseries, and we mostly stick to calling the drivers according
> to the device vendors (and grouping the quirks accordingly).
>
> So how about hid-steelseries?

I'm happy to change it; However Steelseries' other devices are all
keyboards/mice intended for/marketed at gamers. Since other Steelseries
devices are unlikely to have the same structure (OK I'm just guessing on
that) is it better to keep this driver somewhat 'seperated'?

I mean, not make life difficult trying to merge keyboard code in with this
wheel's code.... if that is required in future.

If you still would prefer a name change I can do that. In which case is
the naming of the LED interfaces still OK?

ie.
--
echo 1 > /sys/class/leds/SRWS1\:\:69005002125011007452\:\:RPM3/brightness
--

Thanks,
Simon.



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-28 15:38   ` simon
@ 2013-01-28 16:56     ` Jiri Kosina
  2013-01-28 17:00       ` simon
  0 siblings, 1 reply; 20+ messages in thread
From: Jiri Kosina @ 2013-01-28 16:56 UTC (permalink / raw)
  To: Simon Wood; +Cc: linux-input, linux-kernel, rosegardener

On Mon, 28 Jan 2013, simon@mungewell.org wrote:

> >> From: simon <simon@simon-virtual-machine.(none)>
> >>
> >> Add support the SRW-S1 by patching HID descriptor to read axis
> >> as Generic Desktop X, Y and Z (rather than Usage page being
> >> 'Simulation').
> >>
> >> Signed-off-by: Simon Wood <simon@mungewell.org>
> >> tested-by: John Murphy <rosegardener@freeode.co.uk>
> >
> > Hi Simon,
> >
> > thanks for the patch.
> >
> >>
> >> ---
> >>  drivers/hid/Kconfig     |    6 +++++
> >>  drivers/hid/Makefile    |    1 +
> >>  drivers/hid/hid-core.c  |    1 +
> >>  drivers/hid/hid-ids.h   |    3 +++
> >>  drivers/hid/hid-srws1.c |   58
> >> +++++++++++++++++++++++++++++++++++++++++++++++
> >
> > Is hid-srws1 really the best name? My understanding is that the vendor is
> > called Steelseries, and we mostly stick to calling the drivers according
> > to the device vendors (and grouping the quirks accordingly).
> >
> > So how about hid-steelseries?
> 
> I'm happy to change it; However Steelseries' other devices are all
> keyboards/mice intended for/marketed at gamers. Since other Steelseries
> devices are unlikely to have the same structure (OK I'm just guessing on
> that) is it better to keep this driver somewhat 'seperated'?
> 
> I mean, not make life difficult trying to merge keyboard code in with this
> wheel's code.... if that is required in future.

I don't think it's strictly required, but it seems to work quite nicely 
for other drivers as well.

Of course, if in the future it turns out that we will need a completely 
different driver for some other device produced by this vendor, we can 
operatively decide on a different naming for the future.

> If you still would prefer a name change I can do that. In which case is
> the naming of the LED interfaces still OK?
> 
> ie.
> --
> echo 1 > /sys/class/leds/SRWS1\:\:69005002125011007452\:\:RPM3/brightness
> --

Yes, that seems fine. Thanks,

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-28 16:56     ` Jiri Kosina
@ 2013-01-28 17:00       ` simon
  2013-01-29  9:57         ` Jiri Kosina
  0 siblings, 1 reply; 20+ messages in thread
From: simon @ 2013-01-28 17:00 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Simon Wood, linux-input, linux-kernel, rosegardener

> On Mon, 28 Jan 2013, simon@mungewell.org wrote:
>
>> >> From: simon <simon@simon-virtual-machine.(none)>
>> >>
>> >> Add support the SRW-S1 by patching HID descriptor to read axis
>> >> as Generic Desktop X, Y and Z (rather than Usage page being
>> >> 'Simulation').
>> >>
>> >> Signed-off-by: Simon Wood <simon@mungewell.org>
>> >> tested-by: John Murphy <rosegardener@freeode.co.uk>
>> >
>> > Hi Simon,
>> >
>> > thanks for the patch.
>> >
>> >>
>> >> ---
>> >>  drivers/hid/Kconfig     |    6 +++++
>> >>  drivers/hid/Makefile    |    1 +
>> >>  drivers/hid/hid-core.c  |    1 +
>> >>  drivers/hid/hid-ids.h   |    3 +++
>> >>  drivers/hid/hid-srws1.c |   58
>> >> +++++++++++++++++++++++++++++++++++++++++++++++
>> >
>> > Is hid-srws1 really the best name? My understanding is that the vendor
>> is
>> > called Steelseries, and we mostly stick to calling the drivers
>> according
>> > to the device vendors (and grouping the quirks accordingly).
>> >
>> > So how about hid-steelseries?
>>
>> I'm happy to change it; However Steelseries' other devices are all
>> keyboards/mice intended for/marketed at gamers. Since other Steelseries
>> devices are unlikely to have the same structure (OK I'm just guessing on
>> that) is it better to keep this driver somewhat 'seperated'?
>>
>> I mean, not make life difficult trying to merge keyboard code in with
>> this
>> wheel's code.... if that is required in future.
>
> I don't think it's strictly required, but it seems to work quite nicely
> for other drivers as well.

OK I'll wait a couple of days in-case any more comments come in and re-do
the patch with the file name 'hid-steelseries.c' towards the end of the
week.

Thanks,
Simon


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-28 17:00       ` simon
@ 2013-01-29  9:57         ` Jiri Kosina
  2013-01-31 15:07           ` [PATCH 1/5] " Simon Wood
  0 siblings, 1 reply; 20+ messages in thread
From: Jiri Kosina @ 2013-01-29  9:57 UTC (permalink / raw)
  To: Simon Wood; +Cc: linux-input, linux-kernel, rosegardener

On Mon, 28 Jan 2013, simon@mungewell.org wrote:

> >> I'm happy to change it; However Steelseries' other devices are all
> >> keyboards/mice intended for/marketed at gamers. Since other Steelseries
> >> devices are unlikely to have the same structure (OK I'm just guessing on
> >> that) is it better to keep this driver somewhat 'seperated'?
> >>
> >> I mean, not make life difficult trying to merge keyboard code in with
> >> this
> >> wheel's code.... if that is required in future.
> >
> > I don't think it's strictly required, but it seems to work quite nicely
> > for other drivers as well.
> 
> OK I'll wait a couple of days in-case any more comments come in and re-do
> the patch with the file name 'hid-steelseries.c' towards the end of the
> week.

Works for me. I have finished the review and don't have any other 
comments.

Thanks,

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-29  9:57         ` Jiri Kosina
@ 2013-01-31 15:07           ` Simon Wood
  2013-01-31 15:07             ` [PATCH 2/5] USB: HID: Steelseries SRW-S1 Add support for dials Simon Wood
                               ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Simon Wood @ 2013-01-31 15:07 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

Add support the SRW-S1 by patching HID descriptor to read axis
as Generic Desktop X, Y and Z (rather than Usage page being
'Simulation').

Signed-off-by: Simon Wood <simon@mungewell.org>
Tested-by: John Murphy <rosegardener@freeode.co.uk>
---
 drivers/hid/Kconfig                 |    6 ++++
 drivers/hid/Makefile                |    1 +
 drivers/hid/hid-core.c              |    1 +
 drivers/hid/hid-ids.h               |    3 ++
 drivers/hid/hid-steelseries-srws1.c |   58 +++++++++++++++++++++++++++++++++++
 5 files changed, 69 insertions(+)
 create mode 100644 drivers/hid/hid-steelseries-srws1.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e7d6a13..37df92f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -596,6 +596,12 @@ config HID_SPEEDLINK
 	---help---
 	Support for Speedlink Vicious and Divine Cezanne mouse.
 
+config HID_STEELSERIES_SRWS1
+	tristate "Steelseries SRW-S1 steering wheel support"
+	depends on USB_HID
+	---help---
+	Support for Steelseries SRW-S1 steering wheel
+
 config HID_SUNPLUS
 	tristate "Sunplus wireless desktop"
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index b622157..bbebe0a 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
 obj-$(CONFIG_HID_SONY)		+= hid-sony.o
 obj-$(CONFIG_HID_SPEEDLINK)	+= hid-speedlink.o
+obj-$(CONFIG_HID_STEELSERIES_SRWS1)    	+= hid-steelseries-srws1.o
 obj-$(CONFIG_HID_SUNPLUS)	+= hid-sunplus.o
 obj-$(CONFIG_HID_GREENASIA)	+= hid-gaff.o
 obj-$(CONFIG_HID_THRUSTMASTER)	+= hid-tmff.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index eb2ee11..65cda7f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1697,6 +1697,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 4dfa605..f5976f3 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -723,6 +723,9 @@
 #define USB_VENDOR_ID_STANTUM_SITRONIX		0x1403
 #define USB_DEVICE_ID_MTP_SITRONIX		0x5001
 
+#define USB_VENDOR_ID_STEELSERIES	0x1038
+#define USB_DEVICE_ID_STEELSERIES_SRWS1	0x1410
+
 #define USB_VENDOR_ID_SUN		0x0430
 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
 
diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c
new file mode 100644
index 0000000..4a5386b
--- /dev/null
+++ b/drivers/hid/hid-steelseries-srws1.c
@@ -0,0 +1,58 @@
+/*
+ *  HID driver for Steelseries SRW-S1
+ *
+ *  Copyright (c) 2013 Simon Wood
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
+{
+	if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8
+			&& rdesc[29] == 0xbb && rdesc[40] == 0xc5) {
+		hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n");
+		rdesc[11] = 0x01;
+		rdesc[13] = 0x30;
+		rdesc[29] = 0x31;
+		rdesc[40] = 0x32;
+	}
+	return rdesc;
+}
+
+static const struct hid_device_id steelseries_srws1_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, steelseries_srws1_devices);
+
+static struct hid_driver steelseries_srws1_driver = {
+	.name = "steelseries_srws1",
+	.id_table = steelseries_srws1_devices,
+	.report_fixup = steelseries_srws1_report_fixup
+};
+
+static int __init steelseries_srws1_init(void)
+{
+	return hid_register_driver(&steelseries_srws1_driver);
+}
+
+static void __exit steelseries_srws1_exit(void)
+{
+	hid_unregister_driver(&steelseries_srws1_driver);
+}
+
+module_init(steelseries_srws1_init);
+module_exit(steelseries_srws1_exit);
+MODULE_LICENSE("GPL");
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/5] USB: HID: Steelseries SRW-S1 Add support for dials
  2013-01-31 15:07           ` [PATCH 1/5] " Simon Wood
@ 2013-01-31 15:07             ` Simon Wood
  2013-01-31 15:07             ` [PATCH 3/5] USB: HID: Steelseries SRW-S1 Add support for LEDs Simon Wood
                               ` (3 subsequent siblings)
  4 siblings, 0 replies; 20+ messages in thread
From: Simon Wood @ 2013-01-31 15:07 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

This patch to the SRW-S1 driver re-writes the HID descriptor
to insert a section for the 3 dials on the device, previously
these were contained within a 'Manufacturer Specific' usage
page.

Signed-off-by: Simon Wood <simon@mungewell.org>
Tested-by: John Murphy <rosegardener@freeode.co.uk>
---
 drivers/hid/hid-steelseries-srws1.c |   86 +++++++++++++++++++++++++++++++++--
 1 file changed, 82 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c
index 4a5386b..38b0a24 100644
--- a/drivers/hid/hid-steelseries-srws1.c
+++ b/drivers/hid/hid-steelseries-srws1.c
@@ -17,16 +17,94 @@
 
 #include "hid-ids.h"
 
+/* Fixed report descriptor for Steelseries SRW-S1 wheel controller
+ *
+ * The original descriptor hides the sensitivity and assists dials
+ * a custom vendor usage page. This inserts a patch to make them
+ * appear in the 'Generic Desktop' usage.
+ */
+
+static __u8 steelseries_srws1_rdesc_fixed[] = {
+0x05, 0x01,         /*  Usage Page (Desktop)                */
+0x09, 0x08,         /*  Usage (MultiAxis), Changed          */
+0xA1, 0x01,         /*  Collection (Application),           */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x95, 0x01,         /*          Report Count (1),           */
+0x05, 0x01,         /* Changed  Usage Page (Desktop),       */
+0x09, 0x30,         /* Changed  Usage (X),                  */
+0x16, 0xF8, 0xF8,   /*          Logical Minimum (-1800),    */
+0x26, 0x08, 0x07,   /*          Logical Maximum (1800),     */
+0x65, 0x14,         /*          Unit (Degrees),             */
+0x55, 0x0F,         /*          Unit Exponent (15),         */
+0x75, 0x10,         /*          Report Size (16),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x31,         /* Changed  Usage (Y),                  */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+0x75, 0x0C,         /*          Report Size (12),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x32,         /* Changed  Usage (Z),                  */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+0x75, 0x0C,         /*          Report Size (12),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x05, 0x01,         /*          Usage Page (Desktop),       */
+0x09, 0x39,         /*          Usage (Hat Switch),         */
+0x25, 0x07,         /*          Logical Maximum (7),        */
+0x35, 0x00,         /*          Physical Minimum (0),       */
+0x46, 0x3B, 0x01,   /*          Physical Maximum (315),     */
+0x65, 0x14,         /*          Unit (Degrees),             */
+0x75, 0x04,         /*          Report Size (4),            */
+0x95, 0x01,         /*          Report Count (1),           */
+0x81, 0x02,         /*          Input (Variable),           */
+0x25, 0x01,         /*          Logical Maximum (1),        */
+0x45, 0x01,         /*          Physical Maximum (1),       */
+0x65, 0x00,         /*          Unit,                       */
+0x75, 0x01,         /*          Report Size (1),            */
+0x95, 0x03,         /*          Report Count (3),           */
+0x81, 0x01,         /*          Input (Constant),           */
+0x05, 0x09,         /*          Usage Page (Button),        */
+0x19, 0x01,         /*          Usage Minimum (01h),        */
+0x29, 0x11,         /*          Usage Maximum (11h),        */
+0x95, 0x11,         /*          Report Count (17),          */
+0x81, 0x02,         /*          Input (Variable),           */
+                    /*   ---- Dial patch starts here ----   */
+0x05, 0x01,         /*          Usage Page (Desktop),       */
+0x09, 0x33,         /*          Usage (RX),                 */
+0x75, 0x04,         /*          Report Size (4),            */
+0x95, 0x02,         /*          Report Count (2),           */
+0x15, 0x00,         /*          Logical Minimum (0),        */
+0x25, 0x0b,         /*          Logical Maximum (b),        */
+0x81, 0x02,         /*          Input (Variable),           */
+0x09, 0x35,         /*          Usage (RZ),                 */
+0x75, 0x04,         /*          Report Size (4),            */
+0x95, 0x01,         /*          Report Count (1),           */
+0x25, 0x03,         /*          Logical Maximum (3),        */
+0x81, 0x02,         /*          Input (Variable),           */
+                    /*    ---- Dial patch ends here ----    */
+0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
+0x09, 0x01,         /*          Usage (01h),                */
+0x75, 0x04,         /* Changed  Report Size (4),            */
+0x95, 0x0D,         /* Changed  Report Count (13),          */
+0x81, 0x02,         /*          Input (Variable),           */
+0xC0,               /*      End Collection,                 */
+0xA1, 0x02,         /*      Collection (Logical),           */
+0x09, 0x02,         /*          Usage (02h),                */
+0x75, 0x08,         /*          Report Size (8),            */
+0x95, 0x10,         /*          Report Count (16),          */
+0x91, 0x02,         /*          Output (Variable),          */
+0xC0,               /*      End Collection,                 */
+0xC0                /*  End Collection                      */
+};
+
 static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
 	if (*rsize >= 115 && rdesc[11] == 0x02 && rdesc[13] == 0xc8
 			&& rdesc[29] == 0xbb && rdesc[40] == 0xc5) {
 		hid_info(hdev, "Fixing up Steelseries SRW-S1 report descriptor\n");
-		rdesc[11] = 0x01;
-		rdesc[13] = 0x30;
-		rdesc[29] = 0x31;
-		rdesc[40] = 0x32;
+		rdesc = steelseries_srws1_rdesc_fixed;
+		*rsize = sizeof(steelseries_srws1_rdesc_fixed);
 	}
 	return rdesc;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/5] USB: HID: Steelseries SRW-S1 Add support for LEDs
  2013-01-31 15:07           ` [PATCH 1/5] " Simon Wood
  2013-01-31 15:07             ` [PATCH 2/5] USB: HID: Steelseries SRW-S1 Add support for dials Simon Wood
@ 2013-01-31 15:07             ` Simon Wood
  2013-01-31 15:07             ` [PATCH 4/5] USB: HID: Steelseries SRW-S1 Add support controlling all LEDs simultaneously Simon Wood
                               ` (2 subsequent siblings)
  4 siblings, 0 replies; 20+ messages in thread
From: Simon Wood @ 2013-01-31 15:07 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

This patch to the SRW-S1 driver adds support for the LED RPM
meter on the front of the device. The LEDs are controlled via
/sys/class/leds interface, with an individual control for each
of the 15 LEDs.

Signed-off-by: Simon Wood <simon@mungewell.org>
Tested-by: John Murphy <rosegardener@freeode.co.uk>
---
 Documentation/ABI/testing/sysfs-driver-hid-srws1 |   20 +++
 drivers/hid/hid-steelseries-srws1.c              |  199 ++++++++++++++++++++++
 2 files changed, 219 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-srws1

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-srws1 b/Documentation/ABI/testing/sysfs-driver-hid-srws1
new file mode 100644
index 0000000..c27b34d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-srws1
@@ -0,0 +1,20 @@
+What:		/sys/class/leds/SRWS1::<serial>::RPM1
+What:		/sys/class/leds/SRWS1::<serial>::RPM2
+What:		/sys/class/leds/SRWS1::<serial>::RPM3
+What:		/sys/class/leds/SRWS1::<serial>::RPM4
+What:		/sys/class/leds/SRWS1::<serial>::RPM5
+What:		/sys/class/leds/SRWS1::<serial>::RPM6
+What:		/sys/class/leds/SRWS1::<serial>::RPM7
+What:		/sys/class/leds/SRWS1::<serial>::RPM8
+What:		/sys/class/leds/SRWS1::<serial>::RPM9
+What:		/sys/class/leds/SRWS1::<serial>::RPM10
+What:		/sys/class/leds/SRWS1::<serial>::RPM11
+What:		/sys/class/leds/SRWS1::<serial>::RPM12
+What:		/sys/class/leds/SRWS1::<serial>::RPM13
+What:		/sys/class/leds/SRWS1::<serial>::RPM14
+What:		/sys/class/leds/SRWS1::<serial>::RPM15
+Date:		Jan 2013
+KernelVersion:	3.9
+Contact:	Simon Wood <simon@mungewell.org>
+Description:	Provides a control for turning on/off the LEDs which form
+		an RPM meter on the front of the controller
diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c
index 38b0a24..ba2e2c3 100644
--- a/drivers/hid/hid-steelseries-srws1.c
+++ b/drivers/hid/hid-steelseries-srws1.c
@@ -12,11 +12,21 @@
  */
 
 #include <linux/device.h>
+#include <linux/usb.h>
 #include <linux/hid.h>
 #include <linux/module.h>
 
+#include "usbhid/usbhid.h"
 #include "hid-ids.h"
 
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#define SRWS1_NUMBER_LEDS 15
+struct steelseries_srws1_data {
+	__u16 led_state;
+	struct led_classdev *led[SRWS1_NUMBER_LEDS];
+};
+#endif
+
 /* Fixed report descriptor for Steelseries SRW-S1 wheel controller
  *
  * The original descriptor hides the sensitivity and assists dials
@@ -97,6 +107,191 @@ static __u8 steelseries_srws1_rdesc_fixed[] = {
 0xC0                /*  End Collection                      */
 };
 
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds)
+{
+	struct list_head *report_list = &hdev->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[0] = 0x40;
+	value[1] = leds & 0xFF;
+	value[2] = leds >> 8;
+	value[3] = 0x00;
+	value[4] = 0x00;
+	value[5] = 0x00;
+	value[6] = 0x00;
+	value[7] = 0x00;
+	value[8] = 0x00;
+	value[9] = 0x00;
+	value[10] = 0x00;
+	value[11] = 0x00;
+	value[12] = 0x00;
+	value[13] = 0x00;
+	value[14] = 0x00;
+	value[15] = 0x00;
+
+	usbhid_submit_report(hdev, report, USB_DIR_OUT);
+
+	/* Note: LED change does not show on device until the device is read/polled */
+}
+
+static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
+	int i, state = 0;
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return;
+	}
+
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+		if (led_cdev != drv_data->led[i])
+			continue;
+
+		state = (drv_data->led_state >> i) & 1;
+		if (value == LED_OFF && state) {
+			drv_data->led_state &= ~(1 << i);
+			steelseries_srws1_set_leds(hid, drv_data->led_state);
+		} else if (value != LED_OFF && !state) {
+			drv_data->led_state |= 1 << i;
+			steelseries_srws1_set_leds(hid, drv_data->led_state);
+		}
+		break;
+	}
+}
+
+static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct steelseries_srws1_data *drv_data;
+	int i, value = 0;
+
+	drv_data = hid_get_drvdata(hid);
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return LED_OFF;
+	}
+
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
+		if (led_cdev == drv_data->led[i]) {
+			value = (drv_data->led_state >> i) & 1;
+			break;
+		}
+
+	return value ? LED_FULL : LED_OFF;
+}
+
+static int steelseries_srws1_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	int ret, i;
+	struct led_classdev *led;
+	size_t name_sz;
+	char *name;
+
+	struct steelseries_srws1_data *drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+
+	if (drv_data == NULL) {
+		hid_err(hdev, "can't alloc SRW-S1 memory\n");
+		return -ENOMEM;
+	}
+
+	hid_set_drvdata(hdev, drv_data);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		goto err_free;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		goto err_free;
+	}
+
+	/* register led subsystem */
+	drv_data->led_state = 0;
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
+		drv_data->led[i] = NULL;
+
+	steelseries_srws1_set_leds(hdev, 0);
+
+	name_sz = strlen(hdev->uniq) + 15;
+
+	for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+		if (!led) {
+			hid_err(hdev, "can't allocate memory for LED %d\n", i);
+			goto err_led;
+		}
+
+		name = (void *)(&led[1]);
+		snprintf(name, name_sz, "SRWS1::%s::RPM%d", hdev->uniq, i+1);
+		led->name = name;
+		led->brightness = 0;
+		led->max_brightness = 1;
+		led->brightness_get = steelseries_srws1_led_get_brightness;
+		led->brightness_set = steelseries_srws1_led_set_brightness;
+
+		drv_data->led[i] = led;
+		ret = led_classdev_register(&hdev->dev, led);
+
+		if (ret) {
+			hid_err(hdev, "failed to register LED %d. Aborting.\n", i);
+err_led:
+			/* Deregister all LEDs (if any) */
+			for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+				led = drv_data->led[i];
+				drv_data->led[i] = NULL;
+				if (!led)
+					continue;
+				led_classdev_unregister(led);
+				kfree(led);
+			}
+			goto out;	/* but let the driver continue without LEDs */
+		}
+	}
+out:
+	return 0;
+err_free:
+	kfree(drv_data);
+	return ret;
+}
+
+static void steelseries_srws1_remove(struct hid_device *hdev)
+{
+	int i;
+	struct led_classdev *led;
+
+	struct steelseries_srws1_data *drv_data = hid_get_drvdata(hdev);
+
+	if (drv_data) {
+		/* Deregister LEDs (if any) */
+		for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+			led = drv_data->led[i];
+			drv_data->led[i] = NULL;
+			if (!led)
+				continue;
+			led_classdev_unregister(led);
+			kfree(led);
+		}
+
+	}
+
+	hid_hw_stop(hdev);
+	kfree(drv_data);
+	return;
+}
+#endif
+
 static __u8 *steelseries_srws1_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
@@ -118,6 +313,10 @@ MODULE_DEVICE_TABLE(hid, steelseries_srws1_devices);
 static struct hid_driver steelseries_srws1_driver = {
 	.name = "steelseries_srws1",
 	.id_table = steelseries_srws1_devices,
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+	.probe = steelseries_srws1_probe,
+	.remove = steelseries_srws1_remove,
+#endif
 	.report_fixup = steelseries_srws1_report_fixup
 };
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/5] USB: HID: Steelseries SRW-S1 Add support controlling all LEDs simultaneously
  2013-01-31 15:07           ` [PATCH 1/5] " Simon Wood
  2013-01-31 15:07             ` [PATCH 2/5] USB: HID: Steelseries SRW-S1 Add support for dials Simon Wood
  2013-01-31 15:07             ` [PATCH 3/5] USB: HID: Steelseries SRW-S1 Add support for LEDs Simon Wood
@ 2013-01-31 15:07             ` Simon Wood
  2013-01-31 15:15             ` [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver simon
  2013-01-31 15:23             ` Jiri Kosina
  4 siblings, 0 replies; 20+ messages in thread
From: Simon Wood @ 2013-01-31 15:07 UTC (permalink / raw)
  To: linux-input; +Cc: Jiri Kosina, linux-kernel, simon, rosegardener

This patch to the SRW-S1 driver adds the ability to control all
LEDs simultaneously as testing showed that it was slow (noticably!!)
when seting or clearing all the LEDs in turn.

It adds a 'RPMALL' LED, whose behavoir is asserted to all the LEDs in
the bar graph, individual LEDs can subsequently be turned on/off
individually.

Signed-off-by: Simon Wood <simon@mungewell.org>
Tested-by: John Murphy <rosegardener@freeode.co.uk>
---
 Documentation/ABI/testing/sysfs-driver-hid-srws1 |    1 +
 drivers/hid/hid-steelseries-srws1.c              |   65 ++++++++++++++++++++--
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-hid-srws1 b/Documentation/ABI/testing/sysfs-driver-hid-srws1
index c27b34d..d0eba70 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-srws1
+++ b/Documentation/ABI/testing/sysfs-driver-hid-srws1
@@ -13,6 +13,7 @@ What:		/sys/class/leds/SRWS1::<serial>::RPM12
 What:		/sys/class/leds/SRWS1::<serial>::RPM13
 What:		/sys/class/leds/SRWS1::<serial>::RPM14
 What:		/sys/class/leds/SRWS1::<serial>::RPM15
+What:		/sys/class/leds/SRWS1::<serial>::RPMALL
 Date:		Jan 2013
 KernelVersion:	3.9
 Contact:	Simon Wood <simon@mungewell.org>
diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c
index ba2e2c3..ea07a24 100644
--- a/drivers/hid/hid-steelseries-srws1.c
+++ b/drivers/hid/hid-steelseries-srws1.c
@@ -136,6 +136,42 @@ static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds)
 	/* Note: LED change does not show on device until the device is read/polled */
 }
 
+static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cdev,
+			enum led_brightness value)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return;
+	}
+
+	if (value == LED_OFF)
+		drv_data->led_state = 0;
+	else
+		drv_data->led_state = (1 << (SRWS1_NUMBER_LEDS + 1)) - 1;
+
+	steelseries_srws1_set_leds(hid, drv_data->led_state);
+}
+
+static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev)
+{
+	struct device *dev = led_cdev->dev->parent;
+	struct hid_device *hid = container_of(dev, struct hid_device, dev);
+	struct steelseries_srws1_data *drv_data;
+
+	drv_data = hid_get_drvdata(hid);
+
+	if (!drv_data) {
+		hid_err(hid, "Device data not found.");
+		return LED_OFF;
+	}
+
+	return (drv_data->led_state >> SRWS1_NUMBER_LEDS) ? LED_FULL : LED_OFF;
+}
+
 static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
 			enum led_brightness value)
 {
@@ -219,13 +255,34 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
 
 	/* register led subsystem */
 	drv_data->led_state = 0;
-	for (i = 0; i < SRWS1_NUMBER_LEDS; i++)
+	for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++)
 		drv_data->led[i] = NULL;
 
 	steelseries_srws1_set_leds(hdev, 0);
 
-	name_sz = strlen(hdev->uniq) + 15;
+	name_sz = strlen(hdev->uniq) + 16;
+
+	/* 'ALL', for setting all LEDs simultaneously */
+	led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+	if (!led) {
+		hid_err(hdev, "can't allocate memory for LED ALL\n");
+		goto err_led;
+	}
+
+	name = (void *)(&led[1]);
+	snprintf(name, name_sz, "SRWS1::%s::RPMALL", hdev->uniq);
+	led->name = name;
+	led->brightness = 0;
+	led->max_brightness = 1;
+	led->brightness_get = steelseries_srws1_led_all_get_brightness;
+	led->brightness_set = steelseries_srws1_led_all_set_brightness;
+
+	drv_data->led[SRWS1_NUMBER_LEDS] = led;
+	ret = led_classdev_register(&hdev->dev, led);
+	if (ret)
+		goto err_led;
 
+	/* Each individual LED */
 	for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
 		led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
 		if (!led) {
@@ -248,7 +305,7 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
 			hid_err(hdev, "failed to register LED %d. Aborting.\n", i);
 err_led:
 			/* Deregister all LEDs (if any) */
-			for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+			for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
 				led = drv_data->led[i];
 				drv_data->led[i] = NULL;
 				if (!led)
@@ -275,7 +332,7 @@ static void steelseries_srws1_remove(struct hid_device *hdev)
 
 	if (drv_data) {
 		/* Deregister LEDs (if any) */
-		for (i = 0; i < SRWS1_NUMBER_LEDS; i++) {
+		for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) {
 			led = drv_data->led[i];
 			drv_data->led[i] = NULL;
 			if (!led)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-31 15:07           ` [PATCH 1/5] " Simon Wood
                               ` (2 preceding siblings ...)
  2013-01-31 15:07             ` [PATCH 4/5] USB: HID: Steelseries SRW-S1 Add support controlling all LEDs simultaneously Simon Wood
@ 2013-01-31 15:15             ` simon
  2013-01-31 15:23             ` Jiri Kosina
  4 siblings, 0 replies; 20+ messages in thread
From: simon @ 2013-01-31 15:15 UTC (permalink / raw)
  To: Simon Wood; +Cc: linux-input, Jiri Kosina, linux-kernel, simon, rosegardener

> Add support the SRW-S1 by patching HID descriptor to read axis
> as Generic Desktop X, Y and Z (rather than Usage page being
> 'Simulation').

Slight glitch in making this patch set, there is no [5/5] - just the 4
parts as sent.... sorry if this causes confusion.

Simon.


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-31 15:07           ` [PATCH 1/5] " Simon Wood
                               ` (3 preceding siblings ...)
  2013-01-31 15:15             ` [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver simon
@ 2013-01-31 15:23             ` Jiri Kosina
  2013-01-31 15:36               ` simon
  4 siblings, 1 reply; 20+ messages in thread
From: Jiri Kosina @ 2013-01-31 15:23 UTC (permalink / raw)
  To: Simon Wood; +Cc: linux-input, linux-kernel, rosegardener

On Thu, 31 Jan 2013, Simon Wood wrote:

> Add support the SRW-S1 by patching HID descriptor to read axis
> as Generic Desktop X, Y and Z (rather than Usage page being
> 'Simulation').
> 
> Signed-off-by: Simon Wood <simon@mungewell.org>
> Tested-by: John Murphy <rosegardener@freeode.co.uk>
> ---
>  drivers/hid/Kconfig                 |    6 ++++
>  drivers/hid/Makefile                |    1 +
>  drivers/hid/hid-core.c              |    1 +
>  drivers/hid/hid-ids.h               |    3 ++
>  drivers/hid/hid-steelseries-srws1.c |   58 +++++++++++++++++++++++++++++++++++
>  5 files changed, 69 insertions(+)
>  create mode 100644 drivers/hid/hid-steelseries-srws1.c
> 
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index e7d6a13..37df92f 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -596,6 +596,12 @@ config HID_SPEEDLINK
>  	---help---
>  	Support for Speedlink Vicious and Divine Cezanne mouse.
>  
> +config HID_STEELSERIES_SRWS1
> +	tristate "Steelseries SRW-S1 steering wheel support"
> +	depends on USB_HID
> +	---help---
> +	Support for Steelseries SRW-S1 steering wheel
> +
>  config HID_SUNPLUS
>  	tristate "Sunplus wireless desktop"
>  	depends on USB_HID
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index b622157..bbebe0a 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -101,6 +101,7 @@ obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
>  obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
>  obj-$(CONFIG_HID_SONY)		+= hid-sony.o
>  obj-$(CONFIG_HID_SPEEDLINK)	+= hid-speedlink.o
> +obj-$(CONFIG_HID_STEELSERIES_SRWS1)    	+= hid-steelseries-srws1.o

Simon,

thanks for respin of the patchset.

I thought we converged to hid-steelseries name in the end originally?

If you agree, I'll change it and apply.

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-31 15:23             ` Jiri Kosina
@ 2013-01-31 15:36               ` simon
  2013-01-31 15:54                 ` Jiri Kosina
  0 siblings, 1 reply; 20+ messages in thread
From: simon @ 2013-01-31 15:36 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Simon Wood, linux-input, linux-kernel, rosegardener


> Simon,
>
> thanks for respin of the patchset.
>
> I thought we converged to hid-steelseries name in the end originally?
>
> If you agree, I'll change it and apply.

I'd be OK with that,
Simon


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-31 15:36               ` simon
@ 2013-01-31 15:54                 ` Jiri Kosina
  2013-01-31 16:15                   ` simon
  0 siblings, 1 reply; 20+ messages in thread
From: Jiri Kosina @ 2013-01-31 15:54 UTC (permalink / raw)
  To: Simon Wood; +Cc: linux-input, linux-kernel, rosegardener

On Thu, 31 Jan 2013, simon@mungewell.org wrote:

> > I thought we converged to hid-steelseries name in the end originally?
> >
> > If you agree, I'll change it and apply.
> 
> I'd be OK with that,

Thanks. I will also apply this patch on top, otherwise we'll be corrupting 
memory in steelseries_srws1_probe() here:

	drv_data->led[SRWS1_NUMBER_LEDS] = led;



From: Jiri Kosina <jkosina@suse.cz>
Subject: [PATCH] HID: steelseries: fix out of bound array access

The last field of the driver_data->leds[] array is used to store the
special toggle for setting all leds simultaneously, so we need to allocate
appropriate number of led_classdev pointers.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-steelseries.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
index 365bc9e..2ed995c 100644
--- a/drivers/hid/hid-steelseries.c
+++ b/drivers/hid/hid-steelseries.c
@@ -23,7 +23,8 @@
 #define SRWS1_NUMBER_LEDS 15
 struct steelseries_srws1_data {
 	__u16 led_state;
-	struct led_classdev *led[SRWS1_NUMBER_LEDS];
+	/* the last element is used for setting all leds simultaneously */
+	struct led_classdev *led[SRWS1_NUMBER_LEDS + 1];
 };
 #endif
 
-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver
  2013-01-31 15:54                 ` Jiri Kosina
@ 2013-01-31 16:15                   ` simon
  0 siblings, 0 replies; 20+ messages in thread
From: simon @ 2013-01-31 16:15 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: Simon Wood, linux-input, linux-kernel, rosegardener

> On Thu, 31 Jan 2013, simon@mungewell.org wrote:
>
>> > I thought we converged to hid-steelseries name in the end originally?
>> >
>> > If you agree, I'll change it and apply.
>>
>> I'd be OK with that,
>
> Thanks. I will also apply this patch on top, otherwise we'll be corrupting
> memory in steelseries_srws1_probe() here:
>
> 	drv_data->led[SRWS1_NUMBER_LEDS] = led;
>


You are correct.

Bugger! I had that in the original patch, but must have missed it when
copying over to new file name.

Thanks,
Simon.


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2013-01-31 16:16 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-25  6:34 [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Simon Wood
2013-01-25  6:34 ` [PATCH 2/4] USB: HID: SRW-S1 Add support for dials Simon Wood
2013-01-25  6:34 ` [PATCH 3/4] USB: HID: SRW-S1 Add support for LEDs Simon Wood
2013-01-25  6:34 ` [PATCH 4/4] USB: HID: SRW-S1 Add support controlling all LEDs simultaneously Simon Wood
2013-01-28 15:02   ` Jiri Kosina
2013-01-28 15:24     ` simon
2013-01-28 14:59 ` [PATCH 1/4] USB: HID: SRW-S1 Gaming Wheel Driver Jiri Kosina
2013-01-28 15:38   ` simon
2013-01-28 16:56     ` Jiri Kosina
2013-01-28 17:00       ` simon
2013-01-29  9:57         ` Jiri Kosina
2013-01-31 15:07           ` [PATCH 1/5] " Simon Wood
2013-01-31 15:07             ` [PATCH 2/5] USB: HID: Steelseries SRW-S1 Add support for dials Simon Wood
2013-01-31 15:07             ` [PATCH 3/5] USB: HID: Steelseries SRW-S1 Add support for LEDs Simon Wood
2013-01-31 15:07             ` [PATCH 4/5] USB: HID: Steelseries SRW-S1 Add support controlling all LEDs simultaneously Simon Wood
2013-01-31 15:15             ` [PATCH 1/5] USB: HID: SRW-S1 Gaming Wheel Driver simon
2013-01-31 15:23             ` Jiri Kosina
2013-01-31 15:36               ` simon
2013-01-31 15:54                 ` Jiri Kosina
2013-01-31 16:15                   ` simon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).