diff --git a/packages/linux/patches/3.19.2/linux-061-xpad_steamos.patch b/packages/linux/patches/3.19.2/linux-061-xpad_steamos.patch new file mode 100644 index 0000000000..a4207d6b49 --- /dev/null +++ b/packages/linux/patches/3.19.2/linux-061-xpad_steamos.patch @@ -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 ++#include + #include + #include + #include +@@ -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) {