mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-24 11:16:51 +00:00
Merge pull request #4033 from zzattack/xpad-steamos
[xpad] update steamos patch with urb reuse fix
This commit is contained in:
commit
3e5f7f3c01
941
packages/linux/patches/3.19.2/linux-061-xpad_steamos.patch
vendored
Normal file
941
packages/linux/patches/3.19.2/linux-061-xpad_steamos.patch
vendored
Normal file
@ -0,0 +1,941 @@
|
||||
--- linux-3.19.2.orig/drivers/input/joystick/xpad.c 2015-03-22 15:23:17.000000000 +0100
|
||||
+++ linux-3.19.2/drivers/input/joystick/xpad.c 2015-03-22 15:18:03.000000000 +0100
|
||||
@@ -74,6 +74,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
+#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/module.h>
|
||||
@@ -315,6 +316,12 @@
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, xpad_table);
|
||||
|
||||
+struct irq_out_data {
|
||||
+ struct list_head list;
|
||||
+ unsigned char odata[XPAD_PKT_LEN];
|
||||
+ u32 odata_length;
|
||||
+};
|
||||
+
|
||||
struct usb_xpad {
|
||||
struct input_dev *dev; /* input device interface */
|
||||
struct usb_device *udev; /* usb device */
|
||||
@@ -330,20 +337,30 @@
|
||||
unsigned char *bdata;
|
||||
|
||||
struct urb *irq_out; /* urb for interrupt out report */
|
||||
+ int irq_out_busy; /* is urb submitted, odata_lock must be held */
|
||||
unsigned char *odata; /* output data */
|
||||
dma_addr_t odata_dma;
|
||||
- struct mutex odata_mutex;
|
||||
+ spinlock_t odata_lock;
|
||||
+ struct list_head odata_list; /* odata_lock must be held */
|
||||
+
|
||||
+ unsigned char odata_serial; /* serial number for xbox one protocol */
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
+static int xpad_send_ff(struct usb_xpad *xpad, int strong, int weak);
|
||||
+
|
||||
/*
|
||||
* xpad_process_packet
|
||||
*
|
||||
@@ -485,6 +502,116 @@
|
||||
|
||||
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;
|
||||
+ int ret;
|
||||
+
|
||||
+ 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 ||
|
||||
+ xpad->xtype == XTYPE_XBOXONE) {
|
||||
+ 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]);
|
||||
+ }
|
||||
+
|
||||
+ ret = input_register_device(xpad->dev);
|
||||
+
|
||||
+ if (ret == 0)
|
||||
+ {
|
||||
+ 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);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ printk("xpad: Unable to register input device: %d\n", ret);
|
||||
+ }
|
||||
+
|
||||
+ xpad_init_ff(xpad);
|
||||
+ } else {
|
||||
+ input_unregister_device(xpad->dev);
|
||||
+ }
|
||||
+
|
||||
+ kfree( (void *)work );
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
|
||||
/*
|
||||
* xpad360w_process_packet
|
||||
@@ -506,11 +633,35 @@
|
||||
/* 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_KERNEL);
|
||||
+ 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_KERNEL);
|
||||
+ 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))
|
||||
@@ -625,6 +776,8 @@
|
||||
int retval, status;
|
||||
|
||||
status = urb->status;
|
||||
+
|
||||
+// printk("xpad_irq_in %i\n", status);
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
@@ -686,18 +839,45 @@
|
||||
}
|
||||
}
|
||||
|
||||
+/* odata_lock must be held */
|
||||
+static void xpad_clear_odata_list(struct usb_xpad *xpad)
|
||||
+{
|
||||
+ struct list_head *n, *p;
|
||||
+
|
||||
+ list_for_each_safe(p, n, &xpad->odata_list) {
|
||||
+ struct irq_out_data *out = list_entry(p, struct irq_out_data, list);
|
||||
+ list_del(&out->list);
|
||||
+ kfree(out);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void xpad_irq_out(struct urb *urb)
|
||||
{
|
||||
struct usb_xpad *xpad = urb->context;
|
||||
struct device *dev = &xpad->intf->dev;
|
||||
int retval, status;
|
||||
+ unsigned long flags;
|
||||
+ struct irq_out_data *out;
|
||||
+
|
||||
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||
|
||||
status = urb->status;
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
- /* success */
|
||||
- return;
|
||||
+ /* success, submit next packet from queue, if not empty */
|
||||
+ if (!list_empty(&xpad->odata_list)) {
|
||||
+ out = list_first_entry(&xpad->odata_list,
|
||||
+ struct irq_out_data,
|
||||
+ list);
|
||||
+ list_del(&out->list);
|
||||
+ memcpy(xpad->odata, out->odata, out->odata_length);
|
||||
+ urb->transfer_buffer_length = out->odata_length;
|
||||
+ kfree(out);
|
||||
+ goto resubmit;
|
||||
+ }
|
||||
+ xpad->irq_out_busy = 0;
|
||||
+ goto exit;
|
||||
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
@@ -705,19 +885,24 @@
|
||||
/* this urb is terminated, clean up */
|
||||
dev_dbg(dev, "%s - urb shutting down with status: %d\n",
|
||||
__func__, status);
|
||||
- return;
|
||||
+ xpad_clear_odata_list(xpad);
|
||||
+ xpad->irq_out_busy = 0;
|
||||
+ // TODO: Clean odata_list ?
|
||||
+ goto exit;
|
||||
|
||||
default:
|
||||
dev_dbg(dev, "%s - nonzero urb status received: %d\n",
|
||||
__func__, status);
|
||||
- goto exit;
|
||||
+ goto resubmit;
|
||||
}
|
||||
|
||||
-exit:
|
||||
+resubmit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
|
||||
__func__, retval);
|
||||
+exit:
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
}
|
||||
|
||||
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
@@ -736,14 +921,15 @@
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
- mutex_init(&xpad->odata_mutex);
|
||||
-
|
||||
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!xpad->irq_out) {
|
||||
error = -ENOMEM;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
+ INIT_LIST_HEAD(&xpad->odata_list);
|
||||
+ spin_lock_init(&xpad->odata_lock);
|
||||
+
|
||||
/* Xbox One controller has in/out endpoints swapped. */
|
||||
ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1;
|
||||
ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc;
|
||||
@@ -763,8 +949,22 @@
|
||||
|
||||
static void xpad_stop_output(struct usb_xpad *xpad)
|
||||
{
|
||||
- if (xpad->xtype != XTYPE_UNKNOWN)
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ if (xpad->xtype != XTYPE_UNKNOWN) {
|
||||
usb_kill_urb(xpad->irq_out);
|
||||
+
|
||||
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||
+
|
||||
+ /* Empty odata_list, in case URB was not pending */
|
||||
+ xpad_clear_odata_list(xpad);
|
||||
+ xpad->irq_out_busy = 0;
|
||||
+
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
+
|
||||
+ /* Stop rumble */
|
||||
+ xpad_send_ff(xpad, 0, 0);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void xpad_deinit_output(struct usb_xpad *xpad)
|
||||
@@ -776,64 +976,157 @@
|
||||
}
|
||||
}
|
||||
|
||||
+/* xpad->odata_lock must be held */
|
||||
+static unsigned char* xpad_get_irq_out_buffer(struct usb_xpad *xpad)
|
||||
+{
|
||||
+ struct irq_out_data *out;
|
||||
+
|
||||
+ if (xpad->irq_out_busy) {
|
||||
+ /* Allocate list item and add to the end of odata_list */
|
||||
+ out = kzalloc(sizeof(*out), GFP_ATOMIC);
|
||||
+ if (!out)
|
||||
+ return NULL;
|
||||
+ INIT_LIST_HEAD(&out->list);
|
||||
+ list_add_tail(&out->list, &xpad->odata_list);
|
||||
+ return out->odata;
|
||||
+ } else {
|
||||
+ return xpad->odata;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* xpad->odata_lock must be held */
|
||||
+static int xpad_submit_irq_out_buffer(struct usb_xpad *xpad, unsigned char* buf, u32 length)
|
||||
+{
|
||||
+ struct irq_out_data *out;
|
||||
+
|
||||
+ if (xpad->irq_out_busy) {
|
||||
+ /* Get the last entry of the list */
|
||||
+ out = list_entry(xpad->odata_list.prev, struct irq_out_data, list);
|
||||
+ if (buf == out->odata) {
|
||||
+ out->odata_length = length;
|
||||
+ } else {
|
||||
+ dev_err(&xpad->intf->dev, "%s - bad odata_list item! %p %p\n",
|
||||
+ __func__, out, buf);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (buf == xpad->irq_out->transfer_buffer) {
|
||||
+ xpad->irq_out_busy = 1;
|
||||
+ xpad->irq_out->transfer_buffer_length = length;
|
||||
+ return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
+ } else {
|
||||
+ dev_err(&xpad->intf->dev, "%s - bad irq_out odata! %p %p\n",
|
||||
+ __func__, xpad->irq_out->transfer_buffer, buf);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
#ifdef CONFIG_JOYSTICK_XPAD_FF
|
||||
-static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||
+static int xpad_send_ff(struct usb_xpad *xpad, int strong, int weak)
|
||||
{
|
||||
- struct usb_xpad *xpad = input_get_drvdata(dev);
|
||||
+ unsigned char *odata;
|
||||
+ u32 transfer_length = 0;
|
||||
+ unsigned long flags;
|
||||
+ int error = 0;
|
||||
|
||||
- if (effect->type == FF_RUMBLE) {
|
||||
- __u16 strong = effect->u.rumble.strong_magnitude;
|
||||
- __u16 weak = effect->u.rumble.weak_magnitude;
|
||||
+ /* Check type, fall fast for unsupported types */
|
||||
+ switch (xpad->xtype) {
|
||||
+ case XTYPE_XBOX:
|
||||
+ case XTYPE_XBOX360:
|
||||
+ case XTYPE_XBOX360W:
|
||||
+ case XTYPE_XBOXONE:
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||
|
||||
- switch (xpad->xtype) {
|
||||
+ odata = xpad_get_irq_out_buffer(xpad);
|
||||
+ if (!odata) {
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ switch (xpad->xtype) {
|
||||
|
||||
case XTYPE_XBOX:
|
||||
- xpad->odata[0] = 0x00;
|
||||
- xpad->odata[1] = 0x06;
|
||||
- xpad->odata[2] = 0x00;
|
||||
- xpad->odata[3] = strong / 256; /* left actuator */
|
||||
- xpad->odata[4] = 0x00;
|
||||
- xpad->odata[5] = weak / 256; /* right actuator */
|
||||
- xpad->irq_out->transfer_buffer_length = 6;
|
||||
+ odata[0] = 0x00;
|
||||
+ odata[1] = 0x06;
|
||||
+ odata[2] = 0x00;
|
||||
+ odata[3] = strong / 256; /* left actuator */
|
||||
+ odata[4] = 0x00;
|
||||
+ odata[5] = weak / 256; /* right actuator */
|
||||
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
+ transfer_length = 6;
|
||||
+ break;
|
||||
|
||||
case XTYPE_XBOX360:
|
||||
- xpad->odata[0] = 0x00;
|
||||
- xpad->odata[1] = 0x08;
|
||||
- xpad->odata[2] = 0x00;
|
||||
- xpad->odata[3] = strong / 256; /* left actuator? */
|
||||
- xpad->odata[4] = weak / 256; /* right actuator? */
|
||||
- xpad->odata[5] = 0x00;
|
||||
- xpad->odata[6] = 0x00;
|
||||
- xpad->odata[7] = 0x00;
|
||||
- xpad->irq_out->transfer_buffer_length = 8;
|
||||
+ odata[0] = 0x00;
|
||||
+ odata[1] = 0x08;
|
||||
+ odata[2] = 0x00;
|
||||
+ odata[3] = strong / 256; /* left actuator? */
|
||||
+ odata[4] = weak / 256; /* right actuator? */
|
||||
+ odata[5] = 0x00;
|
||||
+ odata[6] = 0x00;
|
||||
+ odata[7] = 0x00;
|
||||
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
+ transfer_length = 8;
|
||||
+ break;
|
||||
|
||||
case XTYPE_XBOX360W:
|
||||
- xpad->odata[0] = 0x00;
|
||||
- xpad->odata[1] = 0x01;
|
||||
- xpad->odata[2] = 0x0F;
|
||||
- xpad->odata[3] = 0xC0;
|
||||
- xpad->odata[4] = 0x00;
|
||||
- xpad->odata[5] = strong / 256;
|
||||
- xpad->odata[6] = weak / 256;
|
||||
- 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;
|
||||
+ odata[0] = 0x00;
|
||||
+ odata[1] = 0x01;
|
||||
+ odata[2] = 0x0F;
|
||||
+ odata[3] = 0xC0;
|
||||
+ odata[4] = 0x00;
|
||||
+ odata[5] = strong / 256;
|
||||
+ odata[6] = weak / 256;
|
||||
+ odata[7] = 0x00;
|
||||
+ odata[8] = 0x00;
|
||||
+ odata[9] = 0x00;
|
||||
+ odata[10] = 0x00;
|
||||
+ odata[11] = 0x00;
|
||||
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
+ transfer_length = 12;
|
||||
+ break;
|
||||
|
||||
- default:
|
||||
- dev_dbg(&xpad->dev->dev,
|
||||
- "%s - rumble command sent to unsupported xpad type: %d\n",
|
||||
- __func__, xpad->xtype);
|
||||
- return -1;
|
||||
- }
|
||||
+ case XTYPE_XBOXONE:
|
||||
+ odata[0] = 0x09;
|
||||
+ odata[1] = 0x00;
|
||||
+ odata[2] = xpad->odata_serial++;
|
||||
+ odata[3] = 0x09;
|
||||
+ odata[4] = 0x00;
|
||||
+ odata[5] = 0x0F;
|
||||
+ odata[6] = 0x00;
|
||||
+ odata[7] = 0x00;
|
||||
+ odata[8] = strong / 512;
|
||||
+ odata[9] = weak / 512;
|
||||
+ odata[10] = 0xFF;
|
||||
+ odata[11] = 0x00;
|
||||
+ odata[12] = 0x00;
|
||||
+
|
||||
+ transfer_length = 13;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ error = xpad_submit_irq_out_buffer(xpad, odata, transfer_length);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||
+{
|
||||
+ struct usb_xpad *xpad = input_get_drvdata(dev);
|
||||
+
|
||||
+ if (effect->type == FF_RUMBLE) {
|
||||
+ __u16 strong = effect->u.rumble.strong_magnitude;
|
||||
+ __u16 weak = effect->u.rumble.weak_magnitude;
|
||||
+
|
||||
+ return xpad_send_ff(xpad, strong, weak);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -841,7 +1134,7 @@
|
||||
|
||||
static int xpad_init_ff(struct usb_xpad *xpad)
|
||||
{
|
||||
- if (xpad->xtype == XTYPE_UNKNOWN || xpad->xtype == XTYPE_XBOXONE)
|
||||
+ if (xpad->xtype == XTYPE_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
|
||||
@@ -851,6 +1144,7 @@
|
||||
|
||||
#else
|
||||
static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
|
||||
+static int xpad_send_ff(struct usb_xpad *xpad, int strong, int weak) { return 0; }
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
|
||||
@@ -864,15 +1158,52 @@
|
||||
|
||||
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;
|
||||
- xpad->irq_out->transfer_buffer_length = 3;
|
||||
- usb_submit_urb(xpad->irq_out, GFP_KERNEL);
|
||||
- mutex_unlock(&xpad->odata_mutex);
|
||||
+ unsigned char *odata;
|
||||
+ u32 transfer_length = 0;
|
||||
+ unsigned long flags;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if ((unsigned)command > 15)
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||
+
|
||||
+ odata = xpad_get_irq_out_buffer(xpad);
|
||||
+ if (!odata) {
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ switch (xpad->xtype) {
|
||||
+
|
||||
+ case XTYPE_XBOX360:
|
||||
+ odata[0] = 0x01;
|
||||
+ odata[1] = 0x03;
|
||||
+ odata[2] = command;
|
||||
+ transfer_length = 3;
|
||||
+ break;
|
||||
+
|
||||
+ case XTYPE_XBOX360W:
|
||||
+ odata[0] = 0x00;
|
||||
+ odata[1] = 0x00;
|
||||
+ odata[2] = 0x08;
|
||||
+ odata[3] = 0x40 + (command % 0x0e);
|
||||
+ odata[4] = 0x00;
|
||||
+ odata[5] = 0x00;
|
||||
+ odata[6] = 0x00;
|
||||
+ odata[7] = 0x00;
|
||||
+ odata[8] = 0x00;
|
||||
+ odata[9] = 0x00;
|
||||
+ odata[10] = 0x00;
|
||||
+ odata[11] = 0x00;
|
||||
+ transfer_length = 12;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (transfer_length) {
|
||||
+ error = xpad_submit_irq_out_buffer(xpad, odata, transfer_length);
|
||||
}
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
}
|
||||
|
||||
static void xpad_led_set(struct led_classdev *led_cdev,
|
||||
@@ -886,22 +1217,24 @@
|
||||
|
||||
static int xpad_led_probe(struct usb_xpad *xpad)
|
||||
{
|
||||
- static atomic_t led_seq = ATOMIC_INIT(-1);
|
||||
- unsigned long led_no;
|
||||
+ static atomic_t led_seq = ATOMIC_INIT(0);
|
||||
+ long led_no;
|
||||
struct xpad_led *led;
|
||||
struct led_classdev *led_cdev;
|
||||
int error;
|
||||
+
|
||||
+// printk("xpad_led_probe\n");
|
||||
|
||||
- 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);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
- led_no = atomic_inc_return(&led_seq);
|
||||
+ led_no = (long)atomic_inc_return(&led_seq) - 1;
|
||||
|
||||
- snprintf(led->name, sizeof(led->name), "xpad%lu", led_no);
|
||||
+ snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
|
||||
led->xpad = xpad;
|
||||
|
||||
led_cdev = &led->led_cdev;
|
||||
@@ -915,11 +1248,6 @@
|
||||
return error;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * Light up the segment corresponding to controller number
|
||||
- */
|
||||
- xpad_send_led_command(xpad, (led_no % 4) + 2);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -940,7 +1268,11 @@
|
||||
|
||||
static int xpad_open(struct input_dev *dev)
|
||||
{
|
||||
+ unsigned long flags;
|
||||
+ int ret;
|
||||
+ unsigned char *odata;
|
||||
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)
|
||||
@@ -951,11 +1283,25 @@
|
||||
return -EIO;
|
||||
|
||||
if (xpad->xtype == XTYPE_XBOXONE) {
|
||||
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||
+
|
||||
+ odata = xpad_get_irq_out_buffer(xpad);
|
||||
+ if (!odata) {
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ xpad->odata_serial = 0;
|
||||
/* Xbox one controller needs to be initialized. */
|
||||
- xpad->odata[0] = 0x05;
|
||||
- xpad->odata[1] = 0x20;
|
||||
- xpad->irq_out->transfer_buffer_length = 2;
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
|
||||
+ odata[0] = 0x05;
|
||||
+ odata[1] = 0x20;
|
||||
+ odata[2] = xpad->odata_serial++; /* packet serial */
|
||||
+ odata[3] = 0x01; /* rumble bit enable? */
|
||||
+ odata[4] = 0x00;
|
||||
+ ret = xpad_submit_irq_out_buffer(xpad, odata, 5);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1001,19 +1347,24 @@
|
||||
{
|
||||
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 ep_irq_in_idx;
|
||||
int i, error;
|
||||
+ unsigned long flags;
|
||||
+ unsigned char *odata;
|
||||
+
|
||||
+ 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) &&
|
||||
(le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
|
||||
break;
|
||||
}
|
||||
-
|
||||
+
|
||||
if (xpad_device[i].xtype == XTYPE_XBOXONE &&
|
||||
- intf->cur_altsetting->desc.bInterfaceNumber != 0) {
|
||||
+ intf->cur_altsetting->desc.bInterfaceNumber != 0) {
|
||||
/*
|
||||
* The Xbox One controller lists three interfaces all with the
|
||||
* same interface class, subclass and protocol. Differentiate by
|
||||
@@ -1023,12 +1374,9 @@
|
||||
}
|
||||
|
||||
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);
|
||||
if (!xpad->idata) {
|
||||
@@ -1064,66 +1412,12 @@
|
||||
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 ||
|
||||
- xpad->xtype == XTYPE_XBOXONE) {
|
||||
- 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)
|
||||
@@ -1140,10 +1434,6 @@
|
||||
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) {
|
||||
@@ -1151,6 +1441,7 @@
|
||||
* Setup the message to set the LEDs on the
|
||||
* controller when it shows up
|
||||
*/
|
||||
+ spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||
xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!xpad->bulk_out) {
|
||||
error = -ENOMEM;
|
||||
@@ -1179,19 +1470,9 @@
|
||||
}
|
||||
|
||||
ep_irq_in = &intf->cur_altsetting->endpoint[1].desc;
|
||||
- if (usb_endpoint_is_bulk_out(ep_irq_in)) {
|
||||
- usb_fill_bulk_urb(xpad->bulk_out, udev,
|
||||
- usb_sndbulkpipe(udev,
|
||||
- ep_irq_in->bEndpointAddress),
|
||||
- xpad->bdata, XPAD_PKT_LEN,
|
||||
- xpad_bulk_out, xpad);
|
||||
- } else {
|
||||
- usb_fill_int_urb(xpad->bulk_out, udev,
|
||||
- usb_sndintpipe(udev,
|
||||
- ep_irq_in->bEndpointAddress),
|
||||
- xpad->bdata, XPAD_PKT_LEN,
|
||||
- xpad_bulk_out, xpad, 0);
|
||||
- }
|
||||
+ usb_fill_bulk_urb(xpad->bulk_out, udev,
|
||||
+ usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress),
|
||||
+ xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad);
|
||||
|
||||
/*
|
||||
* Submit the int URB immediately rather than waiting for open
|
||||
@@ -1202,23 +1483,60 @@
|
||||
*/
|
||||
xpad->irq_in->dev = xpad->udev;
|
||||
error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
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_irqsave(&xpad->odata_lock, flags);
|
||||
+
|
||||
+ odata = xpad_get_irq_out_buffer(xpad);
|
||||
+ if (odata) {
|
||||
+ odata[0] = 0x00;
|
||||
+ odata[1] = 0x00;
|
||||
+ odata[2] = 0x08;
|
||||
+ odata[3] = 0xC0;
|
||||
+ odata[4] = 0x00;
|
||||
+ odata[5] = 0x00;
|
||||
+ odata[6] = 0x00;
|
||||
+ odata[7] = 0x00;
|
||||
+ odata[8] = 0x00;
|
||||
+ odata[9] = 0x00;
|
||||
+ odata[10] = 0x00;
|
||||
+ odata[11] = 0x00;
|
||||
+ xpad_submit_irq_out_buffer(xpad, odata, 12);
|
||||
+ }
|
||||
+ spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||
+ } 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;
|
||||
- fail6: xpad_led_disconnect(xpad);
|
||||
- fail5: if (input_dev)
|
||||
- input_ff_destroy(input_dev);
|
||||
- fail4: xpad_deinit_output(xpad);
|
||||
+ 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);
|
||||
+ fail1: //input_free_device(input_dev);
|
||||
kfree(xpad);
|
||||
return error;
|
||||
|
||||
@@ -1228,8 +1546,14 @@
|
||||
{
|
||||
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) {
|
Loading…
x
Reference in New Issue
Block a user