diff options
author | Simon Wood <simon@mungewell.org> | 2013-01-31 10:07:10 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-01-31 10:39:32 -0500 |
commit | e25d780581dc4d261c66e072a59c34782bd03e0a (patch) | |
tree | 89430326b367f3ed05b3254d86885e5515e60039 /drivers/hid | |
parent | 2e2daff3a51f2d10155b03f461f4e29eaf80dcbd (diff) |
USB: HID: Steelseries SRW-S1 Add support controlling all LEDs simultaneously
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>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-steelseries-srws1.c | 65 |
1 files changed, 61 insertions, 4 deletions
diff --git a/drivers/hid/hid-steelseries-srws1.c b/drivers/hid/hid-steelseries-srws1.c index a7386699ba7d..365bc9ef1e79 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) | |||
136 | /* Note: LED change does not show on device until the device is read/polled */ | 136 | /* Note: LED change does not show on device until the device is read/polled */ |
137 | } | 137 | } |
138 | 138 | ||
139 | static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cdev, | ||
140 | enum led_brightness value) | ||
141 | { | ||
142 | struct device *dev = led_cdev->dev->parent; | ||
143 | struct hid_device *hid = container_of(dev, struct hid_device, dev); | ||
144 | struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid); | ||
145 | |||
146 | if (!drv_data) { | ||
147 | hid_err(hid, "Device data not found."); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | if (value == LED_OFF) | ||
152 | drv_data->led_state = 0; | ||
153 | else | ||
154 | drv_data->led_state = (1 << (SRWS1_NUMBER_LEDS + 1)) - 1; | ||
155 | |||
156 | steelseries_srws1_set_leds(hid, drv_data->led_state); | ||
157 | } | ||
158 | |||
159 | static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev) | ||
160 | { | ||
161 | struct device *dev = led_cdev->dev->parent; | ||
162 | struct hid_device *hid = container_of(dev, struct hid_device, dev); | ||
163 | struct steelseries_srws1_data *drv_data; | ||
164 | |||
165 | drv_data = hid_get_drvdata(hid); | ||
166 | |||
167 | if (!drv_data) { | ||
168 | hid_err(hid, "Device data not found."); | ||
169 | return LED_OFF; | ||
170 | } | ||
171 | |||
172 | return (drv_data->led_state >> SRWS1_NUMBER_LEDS) ? LED_FULL : LED_OFF; | ||
173 | } | ||
174 | |||
139 | static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev, | 175 | static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev, |
140 | enum led_brightness value) | 176 | enum led_brightness value) |
141 | { | 177 | { |
@@ -219,13 +255,34 @@ static int steelseries_srws1_probe(struct hid_device *hdev, | |||
219 | 255 | ||
220 | /* register led subsystem */ | 256 | /* register led subsystem */ |
221 | drv_data->led_state = 0; | 257 | drv_data->led_state = 0; |
222 | for (i = 0; i < SRWS1_NUMBER_LEDS; i++) | 258 | for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) |
223 | drv_data->led[i] = NULL; | 259 | drv_data->led[i] = NULL; |
224 | 260 | ||
225 | steelseries_srws1_set_leds(hdev, 0); | 261 | steelseries_srws1_set_leds(hdev, 0); |
226 | 262 | ||
227 | name_sz = strlen(hdev->uniq) + 15; | 263 | name_sz = strlen(hdev->uniq) + 16; |
264 | |||
265 | /* 'ALL', for setting all LEDs simultaneously */ | ||
266 | led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); | ||
267 | if (!led) { | ||
268 | hid_err(hdev, "can't allocate memory for LED ALL\n"); | ||
269 | goto err_led; | ||
270 | } | ||
271 | |||
272 | name = (void *)(&led[1]); | ||
273 | snprintf(name, name_sz, "SRWS1::%s::RPMALL", hdev->uniq); | ||
274 | led->name = name; | ||
275 | led->brightness = 0; | ||
276 | led->max_brightness = 1; | ||
277 | led->brightness_get = steelseries_srws1_led_all_get_brightness; | ||
278 | led->brightness_set = steelseries_srws1_led_all_set_brightness; | ||
279 | |||
280 | drv_data->led[SRWS1_NUMBER_LEDS] = led; | ||
281 | ret = led_classdev_register(&hdev->dev, led); | ||
282 | if (ret) | ||
283 | goto err_led; | ||
228 | 284 | ||
285 | /* Each individual LED */ | ||
229 | for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { | 286 | for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { |
230 | led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); | 287 | led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); |
231 | if (!led) { | 288 | if (!led) { |
@@ -248,7 +305,7 @@ static int steelseries_srws1_probe(struct hid_device *hdev, | |||
248 | hid_err(hdev, "failed to register LED %d. Aborting.\n", i); | 305 | hid_err(hdev, "failed to register LED %d. Aborting.\n", i); |
249 | err_led: | 306 | err_led: |
250 | /* Deregister all LEDs (if any) */ | 307 | /* Deregister all LEDs (if any) */ |
251 | for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { | 308 | for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { |
252 | led = drv_data->led[i]; | 309 | led = drv_data->led[i]; |
253 | drv_data->led[i] = NULL; | 310 | drv_data->led[i] = NULL; |
254 | if (!led) | 311 | if (!led) |
@@ -275,7 +332,7 @@ static void steelseries_srws1_remove(struct hid_device *hdev) | |||
275 | 332 | ||
276 | if (drv_data) { | 333 | if (drv_data) { |
277 | /* Deregister LEDs (if any) */ | 334 | /* Deregister LEDs (if any) */ |
278 | for (i = 0; i < SRWS1_NUMBER_LEDS; i++) { | 335 | for (i = 0; i < SRWS1_NUMBER_LEDS + 1; i++) { |
279 | led = drv_data->led[i]; | 336 | led = drv_data->led[i]; |
280 | drv_data->led[i] = NULL; | 337 | drv_data->led[i] = NULL; |
281 | if (!led) | 338 | if (!led) |