aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorJan Kratochvil <honza@jikos.cz>2007-07-18 00:35:40 -0400
committerDmitry Torokhov <dtor@insightbb.com>2007-07-18 00:35:40 -0400
commit4994cd8dadcf9d484ab3ec19f3c7c7a4e5353c1c (patch)
tree787afb858825b3e747bf8cbe04419fae80302d0d /drivers/input
parentcb32da0416b823b7f4b65e7e85d6cba16ca4d1e1 (diff)
Input: xpad - add support for leds on xbox 360 pad
Export LEDs on Xbox360 pad via led subsystem as a single device in /sys/class/leds/xpad[0-9]+. Xbox360 pad has four leds, which form a circle. Unfortunately the leds can't be controlled independently and can only display a predefined set of patterns (for example one is turned on wile others are off or a rotating pattern - 1-2-3-4). To activate a pattern one needs to send a specific command to the device (see http://www.free60.org/wiki/Gamepad). Led subsystem allows us to set brightness, but there is nothing like brightness on this device. So brightness is actually interpreted as the command (only values between 0 and 14 are accepted). Signed-off-by: Jan Kratochvil <honza@jikos.cz> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/joystick/Kconfig7
-rw-r--r--drivers/input/joystick/xpad.c190
2 files changed, 155 insertions, 42 deletions
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 12db72d83ea0..e2abe18e575d 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -275,4 +275,11 @@ config JOYSTICK_XPAD_FF
275 ---help--- 275 ---help---
276 Say Y here if you want to take advantage of xbox 360 rumble features. 276 Say Y here if you want to take advantage of xbox 360 rumble features.
277 277
278config JOYSTICK_XPAD_LEDS
279 bool "LED Support for Xbox360 controller 'BigX' LED"
280 depends on LEDS_CLASS && JOYSTICK_XPAD
281 ---help---
282 This option enables support for the LED which surrounds the Big X on
283 XBox 360 controller.
284
278endif 285endif
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 244089c52650..28080395899c 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -191,13 +191,18 @@ struct usb_xpad {
191 unsigned char *idata; /* input data */ 191 unsigned char *idata; /* input data */
192 dma_addr_t idata_dma; 192 dma_addr_t idata_dma;
193 193
194#ifdef CONFIG_JOYSTICK_XPAD_FF 194#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
195 struct urb *irq_out; /* urb for interrupt out report */ 195 struct urb *irq_out; /* urb for interrupt out report */
196 unsigned char *odata; /* output data */ 196 unsigned char *odata; /* output data */
197 dma_addr_t odata_dma; 197 dma_addr_t odata_dma;
198 struct mutex odata_mutex;
199#endif
200
201#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
202 struct xpad_led *led;
198#endif 203#endif
199 204
200 char phys[65]; /* physical device path */ 205 char phys[64]; /* physical device path */
201 206
202 int dpad_mapping; /* map d-pad to buttons or to axes */ 207 int dpad_mapping; /* map d-pad to buttons or to axes */
203 int xtype; /* type of xbox device */ 208 int xtype; /* type of xbox device */
@@ -349,7 +354,7 @@ exit:
349 __FUNCTION__, retval); 354 __FUNCTION__, retval);
350} 355}
351 356
352#ifdef CONFIG_JOYSTICK_XPAD_FF 357#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
353static void xpad_irq_out(struct urb *urb) 358static void xpad_irq_out(struct urb *urb)
354{ 359{
355 int retval; 360 int retval;
@@ -376,29 +381,7 @@ exit:
376 __FUNCTION__, retval); 381 __FUNCTION__, retval);
377} 382}
378 383
379static int xpad_play_effect(struct input_dev *dev, void *data, 384static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
380 struct ff_effect *effect)
381{
382 struct usb_xpad *xpad = input_get_drvdata(dev);
383
384 if (effect->type == FF_RUMBLE) {
385 __u16 strong = effect->u.rumble.strong_magnitude;
386 __u16 weak = effect->u.rumble.weak_magnitude;
387 xpad->odata[0] = 0x00;
388 xpad->odata[1] = 0x08;
389 xpad->odata[2] = 0x00;
390 xpad->odata[3] = strong / 256;
391 xpad->odata[4] = weak / 256;
392 xpad->odata[5] = 0x00;
393 xpad->odata[6] = 0x00;
394 xpad->odata[7] = 0x00;
395 usb_submit_urb(xpad->irq_out, GFP_KERNEL);
396 }
397
398 return 0;
399}
400
401static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
402{ 385{
403 struct usb_endpoint_descriptor *ep_irq_out; 386 struct usb_endpoint_descriptor *ep_irq_out;
404 int error = -ENOMEM; 387 int error = -ENOMEM;
@@ -411,6 +394,8 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
411 if (!xpad->odata) 394 if (!xpad->odata)
412 goto fail1; 395 goto fail1;
413 396
397 mutex_init(&xpad->odata_mutex);
398
414 xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); 399 xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
415 if (!xpad->irq_out) 400 if (!xpad->irq_out)
416 goto fail2; 401 goto fail2;
@@ -423,25 +408,19 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
423 xpad->irq_out->transfer_dma = xpad->odata_dma; 408 xpad->irq_out->transfer_dma = xpad->odata_dma;
424 xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 409 xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
425 410
426 input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
427
428 error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
429 if (error)
430 goto fail2;
431
432 return 0; 411 return 0;
433 412
434 fail2: usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); 413 fail2: usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
435 fail1: return error; 414 fail1: return error;
436} 415}
437 416
438static void xpad_stop_ff(struct usb_xpad *xpad) 417static void xpad_stop_output(struct usb_xpad *xpad)
439{ 418{
440 if (xpad->xtype == XTYPE_XBOX360) 419 if (xpad->xtype == XTYPE_XBOX360)
441 usb_kill_urb(xpad->irq_out); 420 usb_kill_urb(xpad->irq_out);
442} 421}
443 422
444static void xpad_deinit_ff(struct usb_xpad *xpad) 423static void xpad_deinit_output(struct usb_xpad *xpad)
445{ 424{
446 if (xpad->xtype == XTYPE_XBOX360) { 425 if (xpad->xtype == XTYPE_XBOX360) {
447 usb_free_urb(xpad->irq_out); 426 usb_free_urb(xpad->irq_out);
@@ -449,13 +428,130 @@ static void xpad_deinit_ff(struct usb_xpad *xpad)
449 xpad->odata, xpad->odata_dma); 428 xpad->odata, xpad->odata_dma);
450 } 429 }
451} 430}
431#else
432static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
433static void xpad_deinit_output(struct usb_xpad *xpad) {}
434static void xpad_stop_output(struct usb_xpad *xpad) {}
435#endif
436
437#ifdef CONFIG_JOYSTICK_XPAD_FF
438static int xpad_play_effect(struct input_dev *dev, void *data,
439 struct ff_effect *effect)
440{
441 struct usb_xpad *xpad = input_get_drvdata(dev);
452 442
443 if (effect->type == FF_RUMBLE) {
444 __u16 strong = effect->u.rumble.strong_magnitude;
445 __u16 weak = effect->u.rumble.weak_magnitude;
446 xpad->odata[0] = 0x00;
447 xpad->odata[1] = 0x08;
448 xpad->odata[2] = 0x00;
449 xpad->odata[3] = strong / 256;
450 xpad->odata[4] = weak / 256;
451 xpad->odata[5] = 0x00;
452 xpad->odata[6] = 0x00;
453 xpad->odata[7] = 0x00;
454 usb_submit_urb(xpad->irq_out, GFP_KERNEL);
455 }
456
457 return 0;
458}
459
460static int xpad_init_ff(struct usb_xpad *xpad)
461{
462 input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
463
464 return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
465}
466
467#else
468static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
469#endif
470
471#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
472#include <linux/leds.h>
473
474struct xpad_led {
475 char name[16];
476 struct led_classdev led_cdev;
477 struct usb_xpad *xpad;
478};
479
480static void xpad_send_led_command(struct usb_xpad *xpad, int command)
481{
482 if (command >= 0 && command < 14) {
483 mutex_lock(&xpad->odata_mutex);
484 xpad->odata[0] = 0x01;
485 xpad->odata[1] = 0x03;
486 xpad->odata[2] = command;
487 usb_submit_urb(xpad->irq_out, GFP_KERNEL);
488 mutex_unlock(&xpad->odata_mutex);
489 }
490}
491
492static void xpad_led_set(struct led_classdev *led_cdev,
493 enum led_brightness value)
494{
495 struct xpad_led *xpad_led = container_of(led_cdev,
496 struct xpad_led, led_cdev);
497
498 xpad_send_led_command(xpad_led->xpad, value);
499}
500
501static int xpad_led_probe(struct usb_xpad *xpad)
502{
503 static atomic_t led_seq = ATOMIC_INIT(0);
504 long led_no;
505 struct xpad_led *led;
506 struct led_classdev *led_cdev;
507 int error;
508
509 if (xpad->xtype != XTYPE_XBOX360)
510 return 0;
511
512 xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
513 if (!led)
514 return -ENOMEM;
515
516 led_no = (long)atomic_inc_return(&led_seq) - 1;
517
518 snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
519 led->xpad = xpad;
520
521 led_cdev = &led->led_cdev;
522 led_cdev->name = led->name;
523 led_cdev->brightness_set = xpad_led_set;
524
525 error = led_classdev_register(&xpad->udev->dev, led_cdev);
526 if (error) {
527 kfree(led);
528 xpad->led = NULL;
529 return error;
530 }
531
532 /*
533 * Light up the segment corresponding to controller number
534 */
535 xpad_send_led_command(xpad, (led_no % 4) + 2);
536
537 return 0;
538}
539
540static void xpad_led_disconnect(struct usb_xpad *xpad)
541{
542 struct xpad_led *xpad_led = xpad->led;
543
544 if (xpad_led) {
545 led_classdev_unregister(&xpad_led->led_cdev);
546 kfree(xpad_led->name);
547 }
548}
453#else 549#else
454static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; } 550static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
455static void xpad_stop_ff(struct usb_xpad *xpad) { } 551static void xpad_led_disconnect(struct usb_xpad *xpad) { }
456static void xpad_deinit_ff(struct usb_xpad *xpad) { }
457#endif 552#endif
458 553
554
459static int xpad_open(struct input_dev *dev) 555static int xpad_open(struct input_dev *dev)
460{ 556{
461 struct usb_xpad *xpad = input_get_drvdata(dev); 557 struct usb_xpad *xpad = input_get_drvdata(dev);
@@ -472,7 +568,7 @@ static void xpad_close(struct input_dev *dev)
472 struct usb_xpad *xpad = input_get_drvdata(dev); 568 struct usb_xpad *xpad = input_get_drvdata(dev);
473 569
474 usb_kill_urb(xpad->irq_in); 570 usb_kill_urb(xpad->irq_in);
475 xpad_stop_ff(xpad); 571 xpad_stop_output(xpad);
476} 572}
477 573
478static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) 574static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -564,10 +660,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
564 for (i = 0; xpad_abs_pad[i] >= 0; i++) 660 for (i = 0; xpad_abs_pad[i] >= 0; i++)
565 xpad_set_up_abs(input_dev, xpad_abs_pad[i]); 661 xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
566 662
567 error = xpad_init_ff(intf, xpad); 663 error = xpad_init_output(intf, xpad);
568 if (error) 664 if (error)
569 goto fail2; 665 goto fail2;
570 666
667 error = xpad_init_ff(xpad);
668 if (error)
669 goto fail3;
670
671 error = xpad_led_probe(xpad);
672 if (error)
673 goto fail3;
674
571 ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; 675 ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
572 usb_fill_int_urb(xpad->irq_in, udev, 676 usb_fill_int_urb(xpad->irq_in, udev,
573 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), 677 usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -578,12 +682,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
578 682
579 error = input_register_device(xpad->dev); 683 error = input_register_device(xpad->dev);
580 if (error) 684 if (error)
581 goto fail3; 685 goto fail4;
582 686
583 usb_set_intfdata(intf, xpad); 687 usb_set_intfdata(intf, xpad);
584 return 0; 688 return 0;
585 689
586 fail3: usb_free_urb(xpad->irq_in); 690 fail4: usb_free_urb(xpad->irq_in);
691 fail3: xpad_deinit_output(xpad);
587 fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); 692 fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
588 fail1: input_free_device(input_dev); 693 fail1: input_free_device(input_dev);
589 kfree(xpad); 694 kfree(xpad);
@@ -597,8 +702,9 @@ static void xpad_disconnect(struct usb_interface *intf)
597 702
598 usb_set_intfdata(intf, NULL); 703 usb_set_intfdata(intf, NULL);
599 if (xpad) { 704 if (xpad) {
705 xpad_led_disconnect(xpad);
600 input_unregister_device(xpad->dev); 706 input_unregister_device(xpad->dev);
601 xpad_deinit_ff(xpad); 707 xpad_deinit_output(xpad);
602 usb_free_urb(xpad->irq_in); 708 usb_free_urb(xpad->irq_in);
603 usb_buffer_free(xpad->udev, XPAD_PKT_LEN, 709 usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
604 xpad->idata, xpad->idata_dma); 710 xpad->idata, xpad->idata_dma);