+ if (effect->type == FF_RUMBLE) {
+ __u16 strong = effect->u.rumble.strong_magnitude;
+ __u16 weak = effect->u.rumble.weak_magnitude;
+ xpad->odata[0] = 0x00;
+ xpad->odata[1] = 0x08;
+ xpad->odata[2] = 0x00;
+ xpad->odata[3] = strong / 256;
+ xpad->odata[4] = weak / 256;
+ xpad->odata[5] = 0x00;
+ xpad->odata[6] = 0x00;
+ xpad->odata[7] = 0x00;
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+static int xpad_init_ff(struct usb_xpad *xpad)
+{
+ input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+
+ return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
+}
+
+#else
+static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+#include <linux/leds.h>
+
+struct xpad_led {
+ char name[16];
+ struct led_classdev led_cdev;
+ struct usb_xpad *xpad;
+};
+
+static void xpad_send_led_command(struct usb_xpad *xpad, int command)
+{
+ if (command >= 0 && command < 14) {
+ mutex_lock(&xpad->odata_mutex);
+ xpad->odata[0] = 0x01;
+ xpad->odata[1] = 0x03;
+ xpad->odata[2] = command;
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ mutex_unlock(&xpad->odata_mutex);
+ }
+}
+
+static void xpad_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct xpad_led *xpad_led = container_of(led_cdev,
+ struct xpad_led, led_cdev);
+
+ xpad_send_led_command(xpad_led->xpad, value);
+}
+
+static int xpad_led_probe(struct usb_xpad *xpad)
+{
+ static atomic_t led_seq = ATOMIC_INIT(0);
+ long led_no;
+ struct xpad_led *led;
+ struct led_classdev *led_cdev;
+ int error;
+
+ if (xpad->xtype != XTYPE_XBOX360)
+ return 0;
+
+ xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led_no = (long)atomic_inc_return(&led_seq) - 1;
+
+ snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
+ led->xpad = xpad;
+
+ led_cdev = &led->led_cdev;
+ led_cdev->name = led->name;
+ led_cdev->brightness_set = xpad_led_set;
+
+ error = led_classdev_register(&xpad->udev->dev, led_cdev);
+ if (error) {
+ kfree(led);
+ xpad->led = NULL;
+ return error;
+ }
+
+ /*
+ * Light up the segment corresponding to controller number
+ */
+ xpad_send_led_command(xpad, (led_no % 4) + 2);
+
+ return 0;
+}
+
+static void xpad_led_disconnect(struct usb_xpad *xpad)
+{
+ struct xpad_led *xpad_led = xpad->led;
+
+ if (xpad_led) {
+ led_classdev_unregister(&xpad_led->led_cdev);
+ kfree(xpad_led->name);
+ }
+}