diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-24 16:42:19 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-24 16:42:19 -0800 |
commit | 72145f96a0bb72231891d63309bbd1b586a8704b (patch) | |
tree | 43eb43c1ec04a417b9cdc689c25b2db380bce453 | |
parent | 798d88bf9ea205e79d015893b1f616d1de6ab039 (diff) | |
download | patches-72145f96a0bb72231891d63309bbd1b586a8704b.tar.gz |
xpad patches
-rw-r--r-- | defer-input-nodes-and-led-support | 417 | ||||
-rw-r--r-- | input-xpad-disconnect-all-wireless-controllers-at-init.patch | 73 | ||||
-rw-r--r-- | input-xpad-handle-present-and-gone-correctly.patch | 87 | ||||
-rw-r--r-- | input-xpad-move-the-input-device-creation-to-a-new-function.patch | 252 | ||||
-rw-r--r-- | input-xpad-set-the-correct-led-number.patch | 78 | ||||
-rw-r--r-- | input-xpad-set-the-leds-properly-on-xbox-wireless-controllers.patch | 71 | ||||
-rw-r--r-- | series | 7 |
7 files changed, 985 insertions, 0 deletions
diff --git a/defer-input-nodes-and-led-support b/defer-input-nodes-and-led-support new file mode 100644 index 00000000000000..f17bbfc6eab65f --- /dev/null +++ b/defer-input-nodes-and-led-support @@ -0,0 +1,417 @@ + + +--- + drivers/input/joystick/xpad.c | 273 ++++++++++++++++++++++++++++-------------- + 1 file changed, 188 insertions(+), 85 deletions(-) + +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -281,17 +281,21 @@ struct usb_xpad { + struct urb *irq_out; /* urb for interrupt out report */ + unsigned char *odata; /* output data */ + dma_addr_t odata_dma; +- struct mutex odata_mutex; ++ spinlock_t odata_lock; + #endif + + #if defined(CONFIG_JOYSTICK_XPAD_LEDS) + struct xpad_led *led; + #endif + ++ int joydev_id; ++ + char phys[64]; /* physical device path */ + + int mapping; /* map d-pad to buttons or to axes */ + int xtype; /* type of xbox device */ ++ ++ const char *name; + }; + + /* +@@ -435,6 +439,109 @@ static void xpad360_process_packet(struc + + input_sync(dev); + } ++static void xpad_send_led_command(struct usb_xpad *xpad, int command); ++static int xpad_open(struct input_dev *dev); ++static void xpad_close(struct input_dev *dev); ++static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs); ++static int xpad_init_ff(struct usb_xpad *xpad); ++static int xpad_find_joydev(struct device *dev, void *data) ++{ ++ if (strstr(dev_name(dev), "js")) ++ return 1; ++ ++ return 0; ++} ++ ++static struct workqueue_struct *my_wq; ++ ++typedef struct { ++ struct work_struct my_work; ++ struct usb_xpad *xpad; ++} my_work_t; ++ ++static void my_wq_function( struct work_struct *work) ++{ ++ my_work_t *my_work = (my_work_t *)work; ++ ++ struct usb_xpad *xpad = my_work->xpad; ++ ++ if (xpad->pad_present) { ++ ++ struct input_dev *input_dev; ++ int i; ++ ++ input_dev = input_allocate_device(); ++ ++ xpad->dev = input_dev; ++ input_dev->name = xpad->name; ++ input_dev->phys = xpad->phys; ++ usb_to_input_id(xpad->udev, &input_dev->id); ++ input_dev->dev.parent = &xpad->intf->dev; ++ ++ input_set_drvdata(input_dev, xpad); ++ ++ input_dev->open = xpad_open; ++ input_dev->close = xpad_close; ++ ++ input_dev->evbit[0] = BIT_MASK(EV_KEY); ++ ++ if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { ++ input_dev->evbit[0] |= BIT_MASK(EV_ABS); ++ /* set up axes */ ++ for (i = 0; xpad_abs[i] >= 0; i++) ++ xpad_set_up_abs(input_dev, xpad_abs[i]); ++ } ++ ++ /* set up standard buttons */ ++ for (i = 0; xpad_common_btn[i] >= 0; i++) ++ __set_bit(xpad_common_btn[i], input_dev->keybit); ++ ++ /* set up model-specific ones */ ++ if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) { ++ for (i = 0; xpad360_btn[i] >= 0; i++) ++ __set_bit(xpad360_btn[i], input_dev->keybit); ++ } else { ++ for (i = 0; xpad_btn[i] >= 0; i++) ++ __set_bit(xpad_btn[i], input_dev->keybit); ++ } ++ ++ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { ++ for (i = 0; xpad_btn_pad[i] >= 0; i++) ++ __set_bit(xpad_btn_pad[i], input_dev->keybit); ++ } else { ++ for (i = 0; xpad_abs_pad[i] >= 0; i++) ++ xpad_set_up_abs(input_dev, xpad_abs_pad[i]); ++ } ++ ++ if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { ++ for (i = 0; xpad_btn_triggers[i] >= 0; i++) ++ __set_bit(xpad_btn_triggers[i], input_dev->keybit); ++ } else { ++ for (i = 0; xpad_abs_triggers[i] >= 0; i++) ++ xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); ++ } ++ ++ input_register_device(xpad->dev); ++ ++ { ++ struct device* joydev_dev = device_find_child(&xpad->dev->dev, NULL, xpad_find_joydev); ++ ++ if (joydev_dev) { ++// printk("found joydev child with minor %i\n", MINOR(joydev_dev->devt)); ++ xpad->joydev_id = MINOR(joydev_dev->devt); ++ xpad_send_led_command(xpad, (xpad->joydev_id % 4) + 2); ++ } ++ } ++ ++ xpad_init_ff(xpad); ++ } else { ++ input_unregister_device(xpad->dev); ++ } ++ ++ kfree( (void *)work ); ++ ++ return; ++} + + /* + * xpad360w_process_packet +@@ -456,12 +563,32 @@ static void xpad360w_process_packet(stru + /* Presence change */ + if (data[0] & 0x08) { + if (data[1] & 0x80) { +- xpad->pad_present = 1; +- usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); +- } else +- xpad->pad_present = 0; ++ if (!xpad->pad_present) { ++ my_work_t * work; ++ xpad->pad_present = 1; ++ usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); ++ ++ work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_ATOMIC); ++ INIT_WORK( (struct work_struct *)work, my_wq_function ); ++ work->xpad = xpad; ++ queue_work( my_wq, (struct work_struct *)work ); ++ } ++ } else { ++ if (xpad->pad_present) { ++ my_work_t * work; ++ xpad->pad_present = 0; ++ ++ work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_ATOMIC); ++ INIT_WORK( (struct work_struct *)work, my_wq_function ); ++ work->xpad = xpad; ++ queue_work( my_wq, (struct work_struct *)work ); ++ } ++// printk("got kill packet for id %i\n", xpad->joydev_id); ++ } + } + ++// printk("xpad packet %hhX %hhX %hhX %hhX %hhX %hhX\n", data[0], data[1], data[2], data[3], data[4], data[5]); ++ + /* Valid pad data */ + if (!(data[1] & 0x1)) + return; +@@ -584,8 +711,6 @@ static int xpad_init_output(struct usb_i + goto fail1; + } + +- mutex_init(&xpad->odata_mutex); +- + xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->irq_out) { + error = -ENOMEM; +@@ -717,7 +842,7 @@ static void xpad_send_led_command(struct + if (command > 15) + return; + +- mutex_lock(&xpad->odata_mutex); ++ spin_lock(&xpad->odata_lock); + + switch (xpad->xtype) { + case XTYPE_XBOX360: +@@ -744,7 +869,7 @@ static void xpad_send_led_command(struct + } + + usb_submit_urb(xpad->irq_out, GFP_KERNEL); +- mutex_unlock(&xpad->odata_mutex); ++ spin_unlock(&xpad->odata_lock); + } + + static void xpad_led_set(struct led_classdev *led_cdev, +@@ -787,11 +912,6 @@ static int xpad_led_probe(struct usb_xpa + return error; + } + +- /* +- * Light up the segment corresponding to controller number +- */ +- xpad_send_led_command(xpad, (led_no % 4) + 2); +- + return 0; + } + +@@ -813,6 +933,7 @@ static void xpad_led_disconnect(struct u + static int xpad_open(struct input_dev *dev) + { + struct usb_xpad *xpad = input_get_drvdata(dev); ++// printk("xpad open driver data %x\n", (unsigned int)xpad); + + /* URB was submitted in probe */ + if (xpad->xtype == XTYPE_XBOX360W) +@@ -861,9 +982,13 @@ static int xpad_probe(struct usb_interfa + { + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_xpad *xpad; +- struct input_dev *input_dev; + struct usb_endpoint_descriptor *ep_irq_in; + int i, error; ++// struct input_dev *input_dev; ++ ++ if (!my_wq) { ++ my_wq = create_workqueue("xpad_queue"); ++ } + + for (i = 0; xpad_device[i].idVendor; i++) { + if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && +@@ -872,11 +997,8 @@ static int xpad_probe(struct usb_interfa + } + + xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); +- input_dev = input_allocate_device(); +- if (!xpad || !input_dev) { +- error = -ENOMEM; +- goto fail1; +- } ++ ++ xpad->name = xpad_device[i].name; + + xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN, + GFP_KERNEL, &xpad->idata_dma); +@@ -913,65 +1035,12 @@ static int xpad_probe(struct usb_interfa + xpad->mapping |= MAP_STICKS_TO_NULL; + } + +- xpad->dev = input_dev; +- usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); +- strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); +- +- input_dev->name = xpad_device[i].name; +- input_dev->phys = xpad->phys; +- usb_to_input_id(udev, &input_dev->id); +- input_dev->dev.parent = &intf->dev; +- +- input_set_drvdata(input_dev, xpad); +- +- input_dev->open = xpad_open; +- input_dev->close = xpad_close; +- +- input_dev->evbit[0] = BIT_MASK(EV_KEY); +- +- if (!(xpad->mapping & MAP_STICKS_TO_NULL)) { +- input_dev->evbit[0] |= BIT_MASK(EV_ABS); +- /* set up axes */ +- for (i = 0; xpad_abs[i] >= 0; i++) +- xpad_set_up_abs(input_dev, xpad_abs[i]); +- } +- +- /* set up standard buttons */ +- for (i = 0; xpad_common_btn[i] >= 0; i++) +- __set_bit(xpad_common_btn[i], input_dev->keybit); +- +- /* set up model-specific ones */ +- if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) { +- for (i = 0; xpad360_btn[i] >= 0; i++) +- __set_bit(xpad360_btn[i], input_dev->keybit); +- } else { +- for (i = 0; xpad_btn[i] >= 0; i++) +- __set_bit(xpad_btn[i], input_dev->keybit); +- } +- +- if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { +- for (i = 0; xpad_btn_pad[i] >= 0; i++) +- __set_bit(xpad_btn_pad[i], input_dev->keybit); +- } else { +- for (i = 0; xpad_abs_pad[i] >= 0; i++) +- xpad_set_up_abs(input_dev, xpad_abs_pad[i]); +- } +- +- if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) { +- for (i = 0; xpad_btn_triggers[i] >= 0; i++) +- __set_bit(xpad_btn_triggers[i], input_dev->keybit); +- } else { +- for (i = 0; xpad_abs_triggers[i] >= 0; i++) +- xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); +- } +- + error = xpad_init_output(intf, xpad); + if (error) + goto fail3; + +- error = xpad_init_ff(xpad); +- if (error) +- goto fail4; ++ usb_make_path(xpad->udev, xpad->phys, sizeof(xpad->phys)); ++ strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); + + error = xpad_led_probe(xpad); + if (error) +@@ -985,10 +1054,6 @@ static int xpad_probe(struct usb_interfa + xpad->irq_in->transfer_dma = xpad->idata_dma; + xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +- error = input_register_device(xpad->dev); +- if (error) +- goto fail6; +- + usb_set_intfdata(intf, xpad); + + if (xpad->xtype == XTYPE_XBOX360W) { +@@ -996,6 +1061,7 @@ static int xpad_probe(struct usb_interfa + * Setup the message to set the LEDs on the + * controller when it shows up + */ ++ spin_lock(&xpad->odata_lock); + xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->bulk_out) { + error = -ENOMEM; +@@ -1037,23 +1103,55 @@ static int xpad_probe(struct usb_interfa + */ + xpad->irq_in->dev = xpad->udev; + error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); ++ ++ spin_unlock(&xpad->odata_lock); + if (error) + goto fail9; ++ ++ // I don't know how to check controller state on driver load so just slam them ++ // off so that people have to turn them on, triggering a state update ++ ++ // got the power off packet from an OSX reverse-engineered driver: ++ // http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/OsxDriver#toc1 ++ spin_lock(&xpad->odata_lock); ++ xpad->odata[0] = 0x00; ++ xpad->odata[1] = 0x00; ++ xpad->odata[2] = 0x08; ++ xpad->odata[3] = 0xC0; ++ xpad->odata[4] = 0x00; ++ xpad->odata[5] = 0x00; ++ xpad->odata[6] = 0x00; ++ xpad->odata[7] = 0x00; ++ xpad->odata[8] = 0x00; ++ xpad->odata[9] = 0x00; ++ xpad->odata[10] = 0x00; ++ xpad->odata[11] = 0x00; ++ xpad->irq_out->transfer_buffer_length = 12; ++ usb_submit_urb(xpad->irq_out, GFP_KERNEL); ++ spin_unlock(&xpad->odata_lock); ++ } else { ++ my_work_t *work; ++ xpad->pad_present = 1; ++ ++ work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL); ++ INIT_WORK( (struct work_struct *)work, my_wq_function ); ++ work->xpad = xpad; ++ queue_work( my_wq, (struct work_struct *)work ); + } + + return 0; + + fail9: kfree(xpad->bdata); + fail8: usb_free_urb(xpad->bulk_out); +- fail7: input_unregister_device(input_dev); +- input_dev = NULL; ++ fail7: //input_unregister_device(input_dev); ++ //input_dev = NULL; + fail6: xpad_led_disconnect(xpad); +- fail5: if (input_dev) +- input_ff_destroy(input_dev); ++ fail5: //if (input_dev) ++ //input_ff_destroy(input_dev); + fail4: xpad_deinit_output(xpad); + fail3: usb_free_urb(xpad->irq_in); + fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); +- fail1: input_free_device(input_dev); ++ fail1: //input_free_device(input_dev); + kfree(xpad); + return error; + +@@ -1063,8 +1161,13 @@ static void xpad_disconnect(struct usb_i + { + struct usb_xpad *xpad = usb_get_intfdata (intf); + ++// printk("xpad_disconnect\n"); + xpad_led_disconnect(xpad); +- input_unregister_device(xpad->dev); ++ ++ if (xpad->pad_present) { ++ xpad->pad_present = 0; ++ input_unregister_device(xpad->dev); ++ } + xpad_deinit_output(xpad); + + if (xpad->xtype == XTYPE_XBOX360W) { diff --git a/input-xpad-disconnect-all-wireless-controllers-at-init.patch b/input-xpad-disconnect-all-wireless-controllers-at-init.patch new file mode 100644 index 00000000000000..36cc4ae77aba77 --- /dev/null +++ b/input-xpad-disconnect-all-wireless-controllers-at-init.patch @@ -0,0 +1,73 @@ +From foo@baz Fri Jan 24 11:58:18 PST 2014 +Date: Fri, 24 Jan 2014 11:58:18 -0800 +To: Greg KH <gregkh@linuxfoundation.org> +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> +Subject: [PATCH] Input: xpad: disconnect all Wireless controllers at init + +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> + +We initializing the driver/device, we really don't know how many +controllers are connected. So send a "disconnect all" command to the +base-station, and let the user pair the controllers in the order in +which they want them assigned. + +Note, this means we now do not "preallocate" all 4 devices when a single +wireless base station is seen, but require the device to be properly +connected to the base station before that can happen. The allocation of +the device happens in the next patch, not here, so in a way, this patch +breaks all wireless devices... + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> + +--- + drivers/input/joystick/xpad.c | 38 ++++++++++++++++++++++++++++++++++---- + 1 file changed, 34 insertions(+), 4 deletions(-) + +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -1074,11 +1074,41 @@ static int xpad_probe(struct usb_interfa + usb_kill_urb(xpad->irq_in); + goto fail9; + } ++ ++ /* ++ * We don't know how to check the controller state at driver ++ * load, so just disconnect them all, requiring the user to ++ * repair the device in the order they want them used. Good ++ * point is that we don't connect devices in "random" order, ++ * but the extra step seems a bit harsh as other operating ++ * systems don't require this at the moment. ++ * ++ * Power-off packet information came from an OS-X ++ * reverse-engineered driver located at: ++ * http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/OsxDriver#toc1 ++ */ ++ mutex_lock(&xpad->odata_mutex); ++ xpad->odata[0] = 0x00; ++ xpad->odata[1] = 0x00; ++ xpad->odata[2] = 0x08; ++ xpad->odata[3] = 0xC0; ++ xpad->odata[4] = 0x00; ++ xpad->odata[5] = 0x00; ++ xpad->odata[6] = 0x00; ++ xpad->odata[7] = 0x00; ++ xpad->odata[8] = 0x00; ++ xpad->odata[9] = 0x00; ++ xpad->odata[10] = 0x00; ++ xpad->odata[11] = 0x00; ++ xpad->irq_out->transfer_buffer_length = 12; ++ usb_submit_urb(xpad->irq_out, GFP_KERNEL); ++ mutex_unlock(&xpad->odata_mutex); ++ } else { ++ xpad->pad_present = 1; ++ error = xpad_init_input(xpad); ++ if (error) ++ goto fail9; + } +- xpad->pad_present = 1; +- error = xpad_init_input(xpad); +- if (error) +- goto fail9; + + return 0; + diff --git a/input-xpad-handle-present-and-gone-correctly.patch b/input-xpad-handle-present-and-gone-correctly.patch new file mode 100644 index 00000000000000..e093ec98de782b --- /dev/null +++ b/input-xpad-handle-present-and-gone-correctly.patch @@ -0,0 +1,87 @@ +From foo@baz Fri Jan 24 11:59:45 PST 2014 +Date: Fri, 24 Jan 2014 11:59:45 -0800 +To: Greg KH <gregkh@linuxfoundation.org> +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> +Subject: [PATCH] Input: xpad: handle "present" and "gone" correctly + +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> + +Handle the "a new device is present" message properly by dynamically +creating the input device at this point in time. This requires a +workqueue as we are in interrupt context when we learn about this. + +Also properly disconnect any devices that we are told are removed. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> + +--- + drivers/input/joystick/xpad.c | 37 ++++++++++++++++++++++++++++++++----- + 1 file changed, 32 insertions(+), 5 deletions(-) + +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -294,8 +294,11 @@ struct usb_xpad { + int xtype; /* type of xbox device */ + int joydev_id; /* the minor of the device */ + const char *name; /* name of the device */ ++ struct work_struct work; /* to init/remove device from callback */ + }; + ++static int xpad_init_input(struct usb_xpad *xpad); ++ + /* + * xpad_process_packet + * +@@ -438,6 +441,22 @@ static void xpad360_process_packet(struc + input_sync(dev); + } + ++static void presence_work_function(struct work_struct *work) ++{ ++ struct usb_xpad *xpad = container_of(work, struct usb_xpad, work); ++ int error; ++ ++ if (xpad->pad_present) { ++ error = xpad_init_input(xpad); ++ if (error) { ++ /* complain only, not much else we can do here */ ++ dev_err(&xpad->dev->dev, "unable to init device\n"); ++ } ++ } else { ++ input_unregister_device(xpad->dev); ++ } ++} ++ + /* + * xpad360w_process_packet + * +@@ -452,16 +471,24 @@ static void xpad360_process_packet(struc + * 01.1 - Pad state (Bytes 4+) valid + * + */ +- + static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) + { + /* Presence change */ + if (data[0] & 0x08) { + if (data[1] & 0x80) { +- xpad->pad_present = 1; +- usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); +- } else +- xpad->pad_present = 0; ++ if (!xpad_present) { ++ xpad->pad_present = 1; ++ usb_submit_urb(xpad->bulk_out, GFP_ATOMIC); ++ INIT_WORK(&xpad->work, presence_work_function); ++ schedule_work(&xpad->work); ++ } ++ } else { ++ if (xpad->present) { ++ xpad->pad_present = 0; ++ INIT_WORK(&xpad->work, presence_work_function); ++ schedule_work(&xpad->work); ++ } ++ } + } + + /* Valid pad data */ diff --git a/input-xpad-move-the-input-device-creation-to-a-new-function.patch b/input-xpad-move-the-input-device-creation-to-a-new-function.patch new file mode 100644 index 00000000000000..62664704be9f46 --- /dev/null +++ b/input-xpad-move-the-input-device-creation-to-a-new-function.patch @@ -0,0 +1,252 @@ +From foo@baz Fri Jan 24 11:15:28 PST 2014 +Date: Fri, 24 Jan 2014 11:15:28 -0800 +To: Greg KH <gregkh@linuxfoundation.org> +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> +Subject: [PATCH] Input: xpad: move the input device creation to a new function + +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> + +To allow us to later create / destroy the input device from the urb +callback, we need to initialize the input device from a separate +function. So pull that logic out now to make later patches more +"obvious" as to what they do. + + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/input/joystick/xpad.c | 163 +++++++++++++++++++++++------------------- + 1 file changed, 91 insertions(+), 72 deletions(-) + +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -292,6 +292,7 @@ struct usb_xpad { + + int mapping; /* map d-pad to buttons or to axes */ + int xtype; /* type of xbox device */ ++ const char *name; /* name of the device */ + }; + + /* +@@ -857,70 +858,21 @@ static void xpad_set_up_abs(struct input + } + } + +-static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) ++static int xpad_init_input(struct usb_xpad *xpad) + { +- struct usb_device *udev = interface_to_usbdev(intf); +- struct usb_xpad *xpad; + struct input_dev *input_dev; +- struct usb_endpoint_descriptor *ep_irq_in; + int i, error; + +- for (i = 0; xpad_device[i].idVendor; i++) { +- if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && +- (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct)) +- break; +- } +- +- xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); + input_dev = input_allocate_device(); +- if (!xpad || !input_dev) { +- error = -ENOMEM; +- goto fail1; +- } +- +- xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN, +- GFP_KERNEL, &xpad->idata_dma); +- if (!xpad->idata) { +- error = -ENOMEM; +- goto fail1; +- } +- +- xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); +- if (!xpad->irq_in) { +- error = -ENOMEM; +- goto fail2; +- } +- +- xpad->udev = udev; +- xpad->intf = intf; +- xpad->mapping = xpad_device[i].mapping; +- xpad->xtype = xpad_device[i].xtype; +- +- if (xpad->xtype == XTYPE_UNKNOWN) { +- if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { +- if (intf->cur_altsetting->desc.bInterfaceProtocol == 129) +- xpad->xtype = XTYPE_XBOX360W; +- else +- xpad->xtype = XTYPE_XBOX360; +- } else +- xpad->xtype = XTYPE_XBOX; +- +- if (dpad_to_buttons) +- xpad->mapping |= MAP_DPAD_TO_BUTTONS; +- if (triggers_to_buttons) +- xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS; +- if (sticks_to_null) +- xpad->mapping |= MAP_STICKS_TO_NULL; +- } ++ if (!input_dev) ++ return -ENOMEM; + + xpad->dev = input_dev; +- usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); +- strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); + +- input_dev->name = xpad_device[i].name; ++ input_dev->name = xpad->name; + input_dev->phys = xpad->phys; +- usb_to_input_id(udev, &input_dev->id); +- input_dev->dev.parent = &intf->dev; ++ usb_to_input_id(xpad->udev, &input_dev->id); ++ input_dev->dev.parent = &xpad->intf->dev; + + input_set_drvdata(input_dev, xpad); + +@@ -965,17 +917,87 @@ static int xpad_probe(struct usb_interfa + xpad_set_up_abs(input_dev, xpad_abs_triggers[i]); + } + +- error = xpad_init_output(intf, xpad); ++ error = xpad_init_ff(xpad); + if (error) +- goto fail3; ++ goto fail_init_ff; + +- error = xpad_init_ff(xpad); ++ error = input_register_device(xpad->dev); + if (error) +- goto fail4; ++ goto fail_input_register; ++ ++fail_init_ff: ++ input_ff_destroy(input_dev); ++ ++fail_input_register: ++ input_free_device(input_dev); ++ return error; ++} ++ ++static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) ++{ ++ struct usb_device *udev = interface_to_usbdev(intf); ++ struct usb_xpad *xpad; ++ struct usb_endpoint_descriptor *ep_irq_in; ++ int i, error; ++ ++ for (i = 0; xpad_device[i].idVendor; i++) { ++ if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) && ++ (le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct)) ++ break; ++ } ++ ++ xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL); ++ if (!xpad) { ++ error = -ENOMEM; ++ goto fail1; ++ } ++ ++ usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); ++ strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); ++ ++ xpad->idata = usb_alloc_coherent(udev, XPAD_PKT_LEN, ++ GFP_KERNEL, &xpad->idata_dma); ++ if (!xpad->idata) { ++ error = -ENOMEM; ++ goto fail1; ++ } ++ ++ xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL); ++ if (!xpad->irq_in) { ++ error = -ENOMEM; ++ goto fail2; ++ } ++ ++ xpad->udev = udev; ++ xpad->intf = intf; ++ xpad->mapping = xpad_device[i].mapping; ++ xpad->xtype = xpad_device[i].xtype; ++ xpad->name = xpad_device[i].name; ++ ++ if (xpad->xtype == XTYPE_UNKNOWN) { ++ if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { ++ if (intf->cur_altsetting->desc.bInterfaceProtocol == 129) ++ xpad->xtype = XTYPE_XBOX360W; ++ else ++ xpad->xtype = XTYPE_XBOX360; ++ } else ++ xpad->xtype = XTYPE_XBOX; ++ ++ if (dpad_to_buttons) ++ xpad->mapping |= MAP_DPAD_TO_BUTTONS; ++ if (triggers_to_buttons) ++ xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS; ++ if (sticks_to_null) ++ xpad->mapping |= MAP_STICKS_TO_NULL; ++ } ++ ++ error = xpad_init_output(intf, xpad); ++ if (error) ++ goto fail3; + + error = xpad_led_probe(xpad); + if (error) +- goto fail5; ++ goto fail4; + + ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; + usb_fill_int_urb(xpad->irq_in, udev, +@@ -985,10 +1007,6 @@ static int xpad_probe(struct usb_interfa + xpad->irq_in->transfer_dma = xpad->idata_dma; + xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + +- error = input_register_device(xpad->dev); +- if (error) +- goto fail6; +- + usb_set_intfdata(intf, xpad); + + if (xpad->xtype == XTYPE_XBOX360W) { +@@ -999,7 +1017,7 @@ static int xpad_probe(struct usb_interfa + xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL); + if (!xpad->bulk_out) { + error = -ENOMEM; +- goto fail7; ++ goto fail6; + } + + xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL); +@@ -1037,24 +1055,25 @@ static int xpad_probe(struct usb_interfa + */ + xpad->irq_in->dev = xpad->udev; + error = usb_submit_urb(xpad->irq_in, GFP_KERNEL); +- if (error) ++ if (error) { ++ usb_kill_urb(xpad->irq_in); + goto fail9; ++ } + } ++ xpad->pad_present = 1; ++ error = xpad_init_input(xpad); ++ if (error) ++ goto fail9; + + return 0; + + fail9: kfree(xpad->bdata); + fail8: usb_free_urb(xpad->bulk_out); +- fail7: input_unregister_device(input_dev); +- input_dev = NULL; + fail6: xpad_led_disconnect(xpad); +- fail5: if (input_dev) +- input_ff_destroy(input_dev); + fail4: xpad_deinit_output(xpad); + fail3: usb_free_urb(xpad->irq_in); + fail2: usb_free_coherent(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); +- fail1: input_free_device(input_dev); +- kfree(xpad); ++ fail1: kfree(xpad); + return error; + + } diff --git a/input-xpad-set-the-correct-led-number.patch b/input-xpad-set-the-correct-led-number.patch new file mode 100644 index 00000000000000..6c4b9a01685b38 --- /dev/null +++ b/input-xpad-set-the-correct-led-number.patch @@ -0,0 +1,78 @@ +From foo@baz Fri Jan 24 11:26:09 PST 2014 +Date: Fri, 24 Jan 2014 11:26:09 -0800 +To: Greg KH <gregkh@linuxfoundation.org> +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> +Subject: [PATCH] Input: xpad: Set the correct LED number + +The LED number should not just be incremented every time, that doesn't +work, set the number based on the number it actually is. + +Note, the joydev subsystem doesn't allow us to easily find out the minor +number, so we have to walk all devices in order to find a joystick +device by looking at the name of the device. Odds are, this isn't the +best way to do it, but I don't know of any other way at the moment. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> + +--- + drivers/input/joystick/xpad.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -292,6 +292,7 @@ struct usb_xpad { + + int mapping; /* map d-pad to buttons or to axes */ + int xtype; /* type of xbox device */ ++ int joydev_id; /* the minor of the device */ + const char *name; /* name of the device */ + }; + +@@ -788,11 +789,6 @@ static int xpad_led_probe(struct usb_xpa + return error; + } + +- /* +- * Light up the segment corresponding to controller number +- */ +- xpad_send_led_command(xpad, (led_no % 4) + 2); +- + return 0; + } + +@@ -858,9 +854,17 @@ static void xpad_set_up_abs(struct input + } + } + ++static int xpad_find_joydev(struct device *dev, void *data) ++{ ++ if (strstr(dev_name(dev), "js")) ++ return 1; ++ return 0; ++} ++ + static int xpad_init_input(struct usb_xpad *xpad) + { + struct input_dev *input_dev; ++ struct device *joydev_dev; + int i, error; + + input_dev = input_allocate_device(); +@@ -925,6 +929,17 @@ static int xpad_init_input(struct usb_xp + if (error) + goto fail_input_register; + ++ joydev_dev = device_find_child(&xpad->dev->dev, NULL, ++ xpad_find_joydev); ++ if (joydev_dev) { ++ dev_dbg(&xpad->dev->dev, "Found xpad with minor %i\n", ++ MINOR(joydev_dev->devt)); ++ xpad->joydev_id = MINOR(joydev_dev->devt); ++ ++ /* Light up the segment corresponding to controller number */ ++ xpad_send_led_command(xpad, (xpad->joydev_id % 4) + 2); ++ } ++ + fail_init_ff: + input_ff_destroy(input_dev); + diff --git a/input-xpad-set-the-leds-properly-on-xbox-wireless-controllers.patch b/input-xpad-set-the-leds-properly-on-xbox-wireless-controllers.patch new file mode 100644 index 00000000000000..b746a0f1fce0af --- /dev/null +++ b/input-xpad-set-the-leds-properly-on-xbox-wireless-controllers.patch @@ -0,0 +1,71 @@ +From foo@baz Fri Jan 24 09:30:08 PST 2014 +Date: Fri, 24 Jan 2014 09:30:08 -0800 +To: Greg KH <gregkh@linuxfoundation.org> +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> +Subject: [PATCH] Input: xpad: set the LEDs properly on XBox Wireless controllers + +From: "Pierre-Loup A. Griffais" <pgriffais@valvesoftware.com> + +Add the logic to set the LEDs on XBox Wireless controllers. Command +sequence found by sniffing the Windows data stream when plugging the +device in. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> + +--- + drivers/input/joystick/xpad.c | 32 +++++++++++++++++++++++++++----- + 1 file changed, 27 insertions(+), 5 deletions(-) + +--- a/drivers/input/joystick/xpad.c ++++ b/drivers/input/joystick/xpad.c +@@ -714,15 +714,37 @@ struct xpad_led { + + static void xpad_send_led_command(struct usb_xpad *xpad, int command) + { +- if (command >= 0 && command < 14) { +- mutex_lock(&xpad->odata_mutex); ++ if (command > 15) ++ return; ++ ++ mutex_lock(&xpad->odata_mutex); ++ ++ switch (xpad->xtype) { ++ case XTYPE_XBOX360: + xpad->odata[0] = 0x01; + xpad->odata[1] = 0x03; + xpad->odata[2] = command; + xpad->irq_out->transfer_buffer_length = 3; +- usb_submit_urb(xpad->irq_out, GFP_KERNEL); +- mutex_unlock(&xpad->odata_mutex); ++ break; ++ case XTYPE_XBOX360W: ++ xpad->odata[0] = 0x00; ++ xpad->odata[1] = 0x00; ++ xpad->odata[2] = 0x08; ++ xpad->odata[3] = 0x40 + (command % 0x0e); ++ xpad->odata[4] = 0x00; ++ xpad->odata[5] = 0x00; ++ xpad->odata[6] = 0x00; ++ xpad->odata[7] = 0x00; ++ xpad->odata[8] = 0x00; ++ xpad->odata[9] = 0x00; ++ xpad->odata[10] = 0x00; ++ xpad->odata[11] = 0x00; ++ xpad->irq_out->transfer_buffer_length = 12; ++ break; + } ++ ++ usb_submit_urb(xpad->irq_out, GFP_KERNEL); ++ mutex_unlock(&xpad->odata_mutex); + } + + static void xpad_led_set(struct led_classdev *led_cdev, +@@ -742,7 +764,7 @@ static int xpad_led_probe(struct usb_xpa + struct led_classdev *led_cdev; + int error; + +- if (xpad->xtype != XTYPE_XBOX360) ++ if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX360W) + return 0; + + xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL); @@ -1,3 +1,10 @@ +input-xpad-set-the-leds-properly-on-xbox-wireless-controllers.patch +input-xpad-move-the-input-device-creation-to-a-new-function.patch +input-xpad-set-the-correct-led-number.patch +input-xpad-disconnect-all-wireless-controllers-at-init.patch +input-xpad-handle-present-and-gone-correctly.patch +#defer-input-nodes-and-led-support + staging-rtl8812ae-add-realtek-8821-pci-wifi-driver.patch staging-rtl8821ae-rc.c-fix-up-function-prototypes.patch staging-rtl8821ae-removed-unused-functions-and-variables.patch |