aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Leitner <colin.leitner@googlemail.com>2013-05-27 17:41:05 -0400
committerJiri Kosina <jkosina@suse.cz>2013-05-28 04:16:49 -0400
commitf04d51404f51947d3feabf2518495ba5aa3bb2c4 (patch)
tree5de567d8ef3cf1baf1ae0c314c55909b05e14afd
parentf755407dd19072b7d20719bc5454caed9ab41cc1 (diff)
HID: driver for PS2/3 Buzz controllers
This patch adds support for PS2/3 Buzz controllers into hid-sony It has been tested on Debian 7 with kernel version 3.10.0-rc2. Unfortunately I can't test the patch with a regular six-axis controller myself. Signed-off-by: Colin Leitner <colin.leitner@gmail.com> Cc: Jiri Kosina <jkosina@suse.cz> Cc: linux-input@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/Kconfig9
-rw-r--r--drivers/hid/hid-core.c2
-rw-r--r--drivers/hid/hid-ids.h2
-rw-r--r--drivers/hid/hid-sony.c310
4 files changed, 312 insertions, 11 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fb52f3f6de80..53caf0b115cb 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -594,10 +594,15 @@ config HID_SAMSUNG
594 Support for Samsung InfraRed remote control or keyboards. 594 Support for Samsung InfraRed remote control or keyboards.
595 595
596config HID_SONY 596config HID_SONY
597 tristate "Sony PS3 controller" 597 tristate "Sony PS2/3 accessories"
598 depends on USB_HID 598 depends on USB_HID
599 select NEW_LEDS
600 select LEDS_CLASS
599 ---help--- 601 ---help---
600 Support for Sony PS3 6-axis controllers. 602 Support for
603
604 * Sony PS3 6-axis controllers
605 * Buzz controllers
601 606
602 Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE. 607 Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE.
603 608
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 264f55099940..ecd1107a5488 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1680,6 +1680,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
1680 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, 1680 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
1681 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, 1681 { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
1682 { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, 1682 { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
1683 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) },
1684 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) },
1683 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, 1685 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
1684 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 1686 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
1685 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, 1687 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 38535c9243d5..508c0072b630 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -734,6 +734,8 @@
734#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 734#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
735#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 735#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
736#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f 736#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
737#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
738#define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000
737 739
738#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 740#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
739#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 741#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 312098e4af4f..41e829c8bc48 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -6,6 +6,7 @@
6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
7 * Copyright (c) 2008 Jiri Slaby 7 * Copyright (c) 2008 Jiri Slaby
8 * Copyright (c) 2006-2008 Jiri Kosina 8 * Copyright (c) 2006-2008 Jiri Kosina
9 * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
9 */ 10 */
10 11
11/* 12/*
@@ -26,6 +27,7 @@
26#define VAIO_RDESC_CONSTANT (1 << 0) 27#define VAIO_RDESC_CONSTANT (1 << 0)
27#define SIXAXIS_CONTROLLER_USB (1 << 1) 28#define SIXAXIS_CONTROLLER_USB (1 << 1)
28#define SIXAXIS_CONTROLLER_BT (1 << 2) 29#define SIXAXIS_CONTROLLER_BT (1 << 2)
30#define BUZZ_CONTROLLER (1 << 3)
29 31
30static const u8 sixaxis_rdesc_fixup[] = { 32static const u8 sixaxis_rdesc_fixup[] = {
31 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C, 33 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C,
@@ -55,8 +57,56 @@ static const u8 sixaxis_rdesc_fixup2[] = {
55 0xb1, 0x02, 0xc0, 0xc0, 57 0xb1, 0x02, 0xc0, 0xc0,
56}; 58};
57 59
60static const unsigned int buzz_keymap[] = {
61 /* The controller has 4 remote buzzers, each with one LED and 5
62 * buttons.
63 *
64 * We use the mapping chosen by the controller, which is:
65 *
66 * Key Offset
67 * -------------------
68 * Buzz 1
69 * Blue 5
70 * Orange 4
71 * Green 3
72 * Yellow 2
73 *
74 * So, for example, the orange button on the third buzzer is mapped to
75 * BTN_TRIGGER_HAPPY14
76 */
77 [ 1] = BTN_TRIGGER_HAPPY1,
78 [ 2] = BTN_TRIGGER_HAPPY2,
79 [ 3] = BTN_TRIGGER_HAPPY3,
80 [ 4] = BTN_TRIGGER_HAPPY4,
81 [ 5] = BTN_TRIGGER_HAPPY5,
82 [ 6] = BTN_TRIGGER_HAPPY6,
83 [ 7] = BTN_TRIGGER_HAPPY7,
84 [ 8] = BTN_TRIGGER_HAPPY8,
85 [ 9] = BTN_TRIGGER_HAPPY9,
86 [10] = BTN_TRIGGER_HAPPY10,
87 [11] = BTN_TRIGGER_HAPPY11,
88 [12] = BTN_TRIGGER_HAPPY12,
89 [13] = BTN_TRIGGER_HAPPY13,
90 [14] = BTN_TRIGGER_HAPPY14,
91 [15] = BTN_TRIGGER_HAPPY15,
92 [16] = BTN_TRIGGER_HAPPY16,
93 [17] = BTN_TRIGGER_HAPPY17,
94 [18] = BTN_TRIGGER_HAPPY18,
95 [19] = BTN_TRIGGER_HAPPY19,
96 [20] = BTN_TRIGGER_HAPPY20,
97};
98
58struct sony_sc { 99struct sony_sc {
59 unsigned long quirks; 100 unsigned long quirks;
101
102 void *extra;
103};
104
105struct buzz_extra {
106#ifdef CONFIG_LEDS_CLASS
107 int led_state;
108 struct led_classdev *leds[4];
109#endif
60}; 110};
61 111
62/* Sony Vaio VGX has wrongly mouse pointer declared as constant */ 112/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
@@ -117,6 +167,38 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
117 return 0; 167 return 0;
118} 168}
119 169
170static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
171 struct hid_field *field, struct hid_usage *usage,
172 unsigned long **bit, int *max)
173{
174 struct sony_sc *sc = hid_get_drvdata(hdev);
175
176 if (sc->quirks & BUZZ_CONTROLLER) {
177 unsigned int key = usage->hid & HID_USAGE;
178
179 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
180 return -1;
181
182 switch (usage->collection_index) {
183 case 1:
184 if (key >= ARRAY_SIZE(buzz_keymap))
185 return -1;
186
187 key = buzz_keymap[key];
188 if (!key)
189 return -1;
190 break;
191 default:
192 return -1;
193 }
194
195 hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
196 return 1;
197 }
198
199 return -1;
200}
201
120/* 202/*
121 * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP 203 * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
122 * like it should according to usbhid/hid-core.c::usbhid_output_raw_report() 204 * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
@@ -192,11 +274,201 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
192 return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 274 return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
193} 275}
194 276
277#ifdef CONFIG_LEDS_CLASS
278static void buzz_set_leds(struct hid_device *hdev, int leds)
279{
280 struct list_head *report_list =
281 &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
282 struct hid_report *report = list_entry(report_list->next,
283 struct hid_report, list);
284 __s32 *value = report->field[0]->value;
285
286 value[0] = 0x00;
287 value[1] = (leds & 1) ? 0xff : 0x00;
288 value[2] = (leds & 2) ? 0xff : 0x00;
289 value[3] = (leds & 4) ? 0xff : 0x00;
290 value[4] = (leds & 8) ? 0xff : 0x00;
291 value[5] = 0x00;
292 value[6] = 0x00;
293 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
294}
295
296static void buzz_led_set_brightness(struct led_classdev *led,
297 enum led_brightness value)
298{
299 struct device *dev = led->dev->parent;
300 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
301 struct sony_sc *drv_data;
302 struct buzz_extra *buzz;
303
304 int n;
305
306 drv_data = hid_get_drvdata(hdev);
307 if (!drv_data || !drv_data->extra) {
308 hid_err(hdev, "No device data\n");
309 return;
310 }
311 buzz = drv_data->extra;
312
313 for (n = 0; n < 4; n++) {
314 if (led == buzz->leds[n]) {
315 int on = !! (buzz->led_state & (1 << n));
316 if (value == LED_OFF && on) {
317 buzz->led_state &= ~(1 << n);
318 buzz_set_leds(hdev, buzz->led_state);
319 } else if (value != LED_OFF && !on) {
320 buzz->led_state |= (1 << n);
321 buzz_set_leds(hdev, buzz->led_state);
322 }
323 break;
324 }
325 }
326}
327
328static enum led_brightness buzz_led_get_brightness(struct led_classdev *led)
329{
330 struct device *dev = led->dev->parent;
331 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
332 struct sony_sc *drv_data;
333 struct buzz_extra *buzz;
334
335 int n;
336 int on = 0;
337
338 drv_data = hid_get_drvdata(hdev);
339 if (!drv_data || !drv_data->extra) {
340 hid_err(hdev, "No device data\n");
341 return LED_OFF;
342 }
343 buzz = drv_data->extra;
344
345 for (n = 0; n < 4; n++) {
346 if (led == buzz->leds[n]) {
347 on = !! (buzz->led_state & (1 << n));
348 break;
349 }
350 }
351
352 return on ? LED_FULL : LED_OFF;
353}
354#endif
355
356static int buzz_init(struct hid_device *hdev)
357{
358 struct sony_sc *drv_data;
359 struct buzz_extra *buzz;
360 int ret = 0;
361
362 drv_data = hid_get_drvdata(hdev);
363 BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
364
365 buzz = kzalloc(sizeof(*buzz), GFP_KERNEL);
366 if (!buzz) {
367 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
368 return -ENOMEM;
369 }
370 drv_data->extra = buzz;
371
372 /* Clear LEDs as we have no way of reading their initial state. This is
373 * only relevant if the driver is loaded after somebody actively set the
374 * LEDs to on */
375 buzz_set_leds(hdev, 0x00);
376
377#ifdef CONFIG_LEDS_CLASS
378 {
379 int n;
380 struct led_classdev *led;
381 size_t name_sz;
382 char *name;
383
384 name_sz = strlen(dev_name(&hdev->dev)) + strlen("::buzz#") + 1;
385
386 for (n = 0; n < 4; n++) {
387 led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
388 if (!led) {
389 hid_err(hdev, "Couldn't allocate memory for LED %d\n", n);
390 goto error_leds;
391 }
392
393 name = (void *)(&led[1]);
394 snprintf(name, name_sz, "%s::buzz%d", dev_name(&hdev->dev), n + 1);
395 led->name = name;
396 led->brightness = 0;
397 led->max_brightness = 1;
398 led->brightness_get = buzz_led_get_brightness;
399 led->brightness_set = buzz_led_set_brightness;
400
401 if (led_classdev_register(&hdev->dev, led)) {
402 hid_err(hdev, "Failed to register LED %d\n", n);
403 kfree(led);
404 goto error_leds;
405 }
406
407 buzz->leds[n] = led;
408 }
409 }
410#endif
411
412 return ret;
413
414#ifdef CONFIG_LEDS_CLASS
415error_leds:
416 {
417 int n;
418 struct led_classdev *led;
419
420 for (n = 0; n < 4; n++) {
421 led = buzz->leds[n];
422 buzz->leds[n] = NULL;
423 if (!led)
424 continue;
425 led_classdev_unregister(led);
426 kfree(led);
427 }
428 }
429
430 kfree(drv_data->extra);
431 drv_data->extra = NULL;
432 return ret;
433#endif
434}
435
436static void buzz_remove(struct hid_device *hdev)
437{
438 struct sony_sc *drv_data;
439 struct buzz_extra *buzz;
440
441 drv_data = hid_get_drvdata(hdev);
442 BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
443
444 buzz = drv_data->extra;
445
446#ifdef CONFIG_LEDS_CLASS
447 {
448 int n;
449 struct led_classdev *led;
450
451 for (n = 0; n < 4; n++) {
452 led = buzz->leds[n];
453 buzz->leds[n] = NULL;
454 if (!led)
455 continue;
456 led_classdev_unregister(led);
457 kfree(led);
458 }
459 }
460#endif
461
462 kfree(drv_data->extra);
463 drv_data->extra = NULL;
464}
465
195static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) 466static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
196{ 467{
197 int ret; 468 int ret;
198 unsigned long quirks = id->driver_data; 469 unsigned long quirks = id->driver_data;
199 struct sony_sc *sc; 470 struct sony_sc *sc;
471 unsigned int connect_mask = HID_CONNECT_DEFAULT;
200 472
201 sc = kzalloc(sizeof(*sc), GFP_KERNEL); 473 sc = kzalloc(sizeof(*sc), GFP_KERNEL);
202 if (sc == NULL) { 474 if (sc == NULL) {
@@ -213,8 +485,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
213 goto err_free; 485 goto err_free;
214 } 486 }
215 487
216 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | 488 if (sc->quirks & VAIO_RDESC_CONSTANT)
217 HID_CONNECT_HIDDEV_FORCE); 489 connect_mask |= HID_CONNECT_HIDDEV_FORCE;
490 else if (sc->quirks & SIXAXIS_CONTROLLER_USB)
491 connect_mask |= HID_CONNECT_HIDDEV_FORCE;
492 else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
493 connect_mask |= HID_CONNECT_HIDDEV_FORCE;
494
495 ret = hid_hw_start(hdev, connect_mask);
218 if (ret) { 496 if (ret) {
219 hid_err(hdev, "hw start failed\n"); 497 hid_err(hdev, "hw start failed\n");
220 goto err_free; 498 goto err_free;
@@ -226,6 +504,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
226 } 504 }
227 else if (sc->quirks & SIXAXIS_CONTROLLER_BT) 505 else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
228 ret = sixaxis_set_operational_bt(hdev); 506 ret = sixaxis_set_operational_bt(hdev);
507 else if (sc->quirks & BUZZ_CONTROLLER)
508 ret = buzz_init(hdev);
229 else 509 else
230 ret = 0; 510 ret = 0;
231 511
@@ -242,8 +522,13 @@ err_free:
242 522
243static void sony_remove(struct hid_device *hdev) 523static void sony_remove(struct hid_device *hdev)
244{ 524{
525 struct sony_sc *sc = hid_get_drvdata(hdev);
526
527 if (sc->quirks & BUZZ_CONTROLLER)
528 buzz_remove(hdev);
529
245 hid_hw_stop(hdev); 530 hid_hw_stop(hdev);
246 kfree(hid_get_drvdata(hdev)); 531 kfree(sc);
247} 532}
248 533
249static const struct hid_device_id sony_devices[] = { 534static const struct hid_device_id sony_devices[] = {
@@ -257,17 +542,24 @@ static const struct hid_device_id sony_devices[] = {
257 .driver_data = VAIO_RDESC_CONSTANT }, 542 .driver_data = VAIO_RDESC_CONSTANT },
258 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE), 543 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE),
259 .driver_data = VAIO_RDESC_CONSTANT }, 544 .driver_data = VAIO_RDESC_CONSTANT },
545 /* Wired Buzz Controller. Reported as Sony Hub from its USB ID and as
546 * Logitech joystick from the device descriptor. */
547 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER),
548 .driver_data = BUZZ_CONTROLLER },
549 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER),
550 .driver_data = BUZZ_CONTROLLER },
260 { } 551 { }
261}; 552};
262MODULE_DEVICE_TABLE(hid, sony_devices); 553MODULE_DEVICE_TABLE(hid, sony_devices);
263 554
264static struct hid_driver sony_driver = { 555static struct hid_driver sony_driver = {
265 .name = "sony", 556 .name = "sony",
266 .id_table = sony_devices, 557 .id_table = sony_devices,
267 .probe = sony_probe, 558 .input_mapping = sony_mapping,
268 .remove = sony_remove, 559 .probe = sony_probe,
269 .report_fixup = sony_report_fixup, 560 .remove = sony_remove,
270 .raw_event = sony_raw_event 561 .report_fixup = sony_report_fixup,
562 .raw_event = sony_raw_event
271}; 563};
272module_hid_driver(sony_driver); 564module_hid_driver(sony_driver);
273 565