mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-24 11:16:51 +00:00
linux/drivers/input/joystick/xpad: fix operation for xbox 360/one controllers
merged from https://github.com/paroj/xpad - fixed blinking LED on Xbox 360 Wireless Controllers - only expose actually connected Xbox 360 Wireless Controllers - fixed kernel warnings due to submitting active URB requests - updated Xbox One controller force feedback - controller still works after suspend/ resume - Xbox 360 Wireless button mappings are now compatible with Xbox 360 (non-wireless) mappings Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
This commit is contained in:
parent
c37b5a7eed
commit
580154c93c
887
packages/linux/patches/4.1.3/linux-063-xpad-fix_xbox360_wireless.patch
vendored
Normal file
887
packages/linux/patches/4.1.3/linux-063-xpad-fix_xbox360_wireless.patch
vendored
Normal file
@ -0,0 +1,887 @@
|
||||
From 0f578b91219bd354a170eb53359336f67bbfda57 Mon Sep 17 00:00:00 2001
|
||||
From: Matt DeVillier <matt.devillier@gmail.com>
|
||||
Date: Tue, 28 Jul 2015 11:19:40 -0500
|
||||
Subject: [PATCH 1/1] linux/drivers/input/joystick/xpad: fixes for xbox360/one controllers
|
||||
|
||||
merged from https://github.com/paroj/xpad
|
||||
|
||||
- fixed blinking LED on Xbox 360 Wireless Controllers
|
||||
- only expose actually connected Xbox 360 Wireless Controllers
|
||||
- fixed kernel warnings due to submitting active URB requests
|
||||
- updated Xbox One controller force feedback
|
||||
- controller still works after suspend/ resume
|
||||
- Xbox 360 Wireless button mappings are now compatible with Xbox 360 (non-wireless) mappings
|
||||
|
||||
Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
|
||||
---
|
||||
drivers/input/joystick/xpad.c | 599 ++++++++++++++++++++++++------------------
|
||||
1 file changed, 337 insertions(+), 262 deletions(-)
|
||||
|
||||
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
|
||||
index f8850f9..77ccd2b 100644
|
||||
--- a/drivers/input/joystick/xpad.c
|
||||
+++ b/drivers/input/joystick/xpad.c
|
||||
@@ -74,7 +74,7 @@
|
||||
*
|
||||
* Later changes can be tracked in SCM.
|
||||
*/
|
||||
-
|
||||
+#define DEBUG
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
@@ -328,10 +328,8 @@ struct usb_xpad {
|
||||
unsigned char *idata; /* input data */
|
||||
dma_addr_t idata_dma;
|
||||
|
||||
- struct urb *bulk_out;
|
||||
- unsigned char *bdata;
|
||||
-
|
||||
struct urb *irq_out; /* urb for interrupt out report */
|
||||
+ int irq_out_active; /* we must not use an active URB */
|
||||
unsigned char *odata; /* output data */
|
||||
dma_addr_t odata_dma;
|
||||
struct mutex odata_mutex;
|
||||
@@ -344,9 +342,17 @@ struct usb_xpad {
|
||||
|
||||
int mapping; /* map d-pad to buttons or to axes */
|
||||
int xtype; /* type of xbox device */
|
||||
- unsigned long led_no; /* led to lit on xbox360 controllers */
|
||||
+ unsigned long pad_nr; /* the order x360 pads were attached */
|
||||
+ const char *name; /* name of the device */
|
||||
+ struct work_struct work; /* init/remove device from callback */
|
||||
+ unsigned char odata_serial; /* serial number for xbox one protocol */
|
||||
};
|
||||
|
||||
+static unsigned long xpad_pad_seq;
|
||||
+
|
||||
+static int xpad_init_input(struct usb_xpad *xpad);
|
||||
+static void xpad_deinit_input(struct usb_xpad *xpad);
|
||||
+
|
||||
/*
|
||||
* xpad_process_packet
|
||||
*
|
||||
@@ -356,7 +362,6 @@ struct usb_xpad {
|
||||
* The used report descriptor was taken from ITO Takayukis website:
|
||||
* http://euc.jp/periphs/xbox-controller.ja.html
|
||||
*/
|
||||
-
|
||||
static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
|
||||
{
|
||||
struct input_dev *dev = xpad->dev;
|
||||
@@ -439,7 +444,14 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
|
||||
input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
|
||||
- } else {
|
||||
+ }
|
||||
+ /* this should be a simple else block. However historically xbox360w
|
||||
+ * has mapped DPAD to buttons while xbox360 did not.
|
||||
+ * This made no sense, but now we can not just switch back and have to
|
||||
+ * support both behaviors.
|
||||
+ */
|
||||
+ if (!(xpad->mapping & MAP_DPAD_TO_BUTTONS) ||
|
||||
+ xpad->xtype == XTYPE_XBOX360W) {
|
||||
input_report_abs(dev, ABS_HAT0X,
|
||||
!!(data[2] & 0x08) - !!(data[2] & 0x04));
|
||||
input_report_abs(dev, ABS_HAT0Y,
|
||||
@@ -491,6 +503,22 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
|
||||
|
||||
static void xpad_identify_controller(struct usb_xpad *xpad);
|
||||
|
||||
+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 {
|
||||
+ xpad_deinit_input(xpad);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* xpad360w_process_packet
|
||||
*
|
||||
@@ -505,21 +533,18 @@ static void xpad_identify_controller(struct usb_xpad *xpad);
|
||||
* 01.1 - Pad state (Bytes 4+) valid
|
||||
*
|
||||
*/
|
||||
-
|
||||
static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
|
||||
{
|
||||
+ int presence;
|
||||
+
|
||||
/* Presence change */
|
||||
if (data[0] & 0x08) {
|
||||
- if (data[1] & 0x80) {
|
||||
- xpad->pad_present = 1;
|
||||
- usb_submit_urb(xpad->bulk_out, GFP_ATOMIC);
|
||||
- /*
|
||||
- * Light up the segment corresponding to
|
||||
- * controller number.
|
||||
- */
|
||||
- xpad_identify_controller(xpad);
|
||||
- } else
|
||||
- xpad->pad_present = 0;
|
||||
+ presence = (data[1] & 0x80) != 0;
|
||||
+
|
||||
+ if (xpad->pad_present != presence) {
|
||||
+ xpad->pad_present = presence;
|
||||
+ schedule_work(&xpad->work);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Valid pad data */
|
||||
@@ -674,28 +699,6 @@ exit:
|
||||
__func__, retval);
|
||||
}
|
||||
|
||||
-static void xpad_bulk_out(struct urb *urb)
|
||||
-{
|
||||
- struct usb_xpad *xpad = urb->context;
|
||||
- struct device *dev = &xpad->intf->dev;
|
||||
-
|
||||
- switch (urb->status) {
|
||||
- case 0:
|
||||
- /* success */
|
||||
- break;
|
||||
- case -ECONNRESET:
|
||||
- case -ENOENT:
|
||||
- case -ESHUTDOWN:
|
||||
- /* this urb is terminated, clean up */
|
||||
- dev_dbg(dev, "%s - urb shutting down with status: %d\n",
|
||||
- __func__, urb->status);
|
||||
- break;
|
||||
- default:
|
||||
- dev_dbg(dev, "%s - nonzero urb status received: %d\n",
|
||||
- __func__, urb->status);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static void xpad_irq_out(struct urb *urb)
|
||||
{
|
||||
struct usb_xpad *xpad = urb->context;
|
||||
@@ -707,6 +710,7 @@ static void xpad_irq_out(struct urb *urb)
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* success */
|
||||
+ xpad->irq_out_active = 0;
|
||||
return;
|
||||
|
||||
case -ECONNRESET:
|
||||
@@ -715,6 +719,7 @@ static void xpad_irq_out(struct urb *urb)
|
||||
/* this urb is terminated, clean up */
|
||||
dev_dbg(dev, "%s - urb shutting down with status: %d\n",
|
||||
__func__, status);
|
||||
+ xpad->irq_out_active = 0;
|
||||
return;
|
||||
|
||||
default:
|
||||
@@ -734,7 +739,6 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_irq_out;
|
||||
int ep_irq_out_idx;
|
||||
- int error;
|
||||
|
||||
if (xpad->xtype == XTYPE_UNKNOWN)
|
||||
return 0;
|
||||
@@ -742,16 +746,15 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
GFP_KERNEL, &xpad->odata_dma);
|
||||
if (!xpad->odata) {
|
||||
- error = -ENOMEM;
|
||||
- goto fail1;
|
||||
+ return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_init(&xpad->odata_mutex);
|
||||
|
||||
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!xpad->irq_out) {
|
||||
- error = -ENOMEM;
|
||||
- goto fail2;
|
||||
+ usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
||||
+ return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Xbox One controller has in/out endpoints swapped. */
|
||||
@@ -766,9 +769,6 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
||||
xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
return 0;
|
||||
-
|
||||
- fail2: usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
|
||||
- fail1: return error;
|
||||
}
|
||||
|
||||
static void xpad_stop_output(struct usb_xpad *xpad)
|
||||
@@ -790,80 +790,94 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
|
||||
static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||
{
|
||||
struct usb_xpad *xpad = input_get_drvdata(dev);
|
||||
+ __u16 strong;
|
||||
+ __u16 weak;
|
||||
+ int retval;
|
||||
|
||||
- if (effect->type == FF_RUMBLE) {
|
||||
- __u16 strong = effect->u.rumble.strong_magnitude;
|
||||
- __u16 weak = effect->u.rumble.weak_magnitude;
|
||||
-
|
||||
- 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;
|
||||
-
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
-
|
||||
- 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;
|
||||
-
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
-
|
||||
- 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;
|
||||
-
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
-
|
||||
- case XTYPE_XBOXONE:
|
||||
- xpad->odata[0] = 0x09; /* activate rumble */
|
||||
- xpad->odata[1] = 0x08;
|
||||
- xpad->odata[2] = 0x00;
|
||||
- xpad->odata[3] = 0x08; /* continuous effect */
|
||||
- xpad->odata[4] = 0x00; /* simple rumble mode */
|
||||
- xpad->odata[5] = 0x03; /* L and R actuator only */
|
||||
- xpad->odata[6] = 0x00; /* TODO: LT actuator */
|
||||
- xpad->odata[7] = 0x00; /* TODO: RT actuator */
|
||||
- xpad->odata[8] = strong / 256; /* left actuator */
|
||||
- xpad->odata[9] = weak / 256; /* right actuator */
|
||||
- xpad->odata[10] = 0x80; /* length of pulse */
|
||||
- xpad->odata[11] = 0x00; /* stop period of pulse */
|
||||
- xpad->irq_out->transfer_buffer_length = 12;
|
||||
-
|
||||
- return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
-
|
||||
- default:
|
||||
- dev_dbg(&xpad->dev->dev,
|
||||
- "%s - rumble command sent to unsupported xpad type: %d\n",
|
||||
- __func__, xpad->xtype);
|
||||
- return -1;
|
||||
- }
|
||||
+ if (effect->type != FF_RUMBLE)
|
||||
+ return 0;
|
||||
+
|
||||
+ strong = effect->u.rumble.strong_magnitude;
|
||||
+ weak = effect->u.rumble.weak_magnitude;
|
||||
+
|
||||
+ mutex_lock(&xpad->odata_mutex);
|
||||
+
|
||||
+ 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;
|
||||
+ 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;
|
||||
+ 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;
|
||||
+ break;
|
||||
+
|
||||
+ case XTYPE_XBOXONE:
|
||||
+ xpad->odata[0] = 0x09; /* activate rumble */
|
||||
+ xpad->odata[1] = 0x08;
|
||||
+ xpad->odata[2] = xpad->odata_serial++;
|
||||
+ xpad->odata[3] = 0x08; /* continuous effect */
|
||||
+ xpad->odata[4] = 0x00; /* simple rumble mode */
|
||||
+ xpad->odata[5] = 0x03; /* L and R actuator only */
|
||||
+ xpad->odata[6] = 0x00; /* TODO: LT actuator */
|
||||
+ xpad->odata[7] = 0x00; /* TODO: RT actuator */
|
||||
+ xpad->odata[8] = strong / 512; /* left actuator */
|
||||
+ xpad->odata[9] = weak / 512; /* right actuator */
|
||||
+ xpad->odata[10] = 0x80; /* length of pulse */
|
||||
+ xpad->odata[11] = 0x00; /* stop period of pulse */
|
||||
+ xpad->odata[12] = 0x00;
|
||||
+ xpad->irq_out->transfer_buffer_length = 13;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ mutex_unlock(&xpad->odata_mutex);
|
||||
+ dev_dbg(&xpad->dev->dev,
|
||||
+ "%s - rumble command sent to unsupported xpad type: %d\n",
|
||||
+ __func__, xpad->xtype);
|
||||
+ return -EINVAL;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ if (!xpad->irq_out_active) {
|
||||
+ retval = usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
+ xpad->irq_out_active = 1;
|
||||
+ } else {
|
||||
+ retval = -EIO;
|
||||
+ dev_dbg(&xpad->dev->dev, "%s - dropped, irq_out is active\n",
|
||||
+ __func__);
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&xpad->odata_mutex);
|
||||
+
|
||||
+ return retval;
|
||||
}
|
||||
|
||||
static int xpad_init_ff(struct usb_xpad *xpad)
|
||||
@@ -890,6 +904,7 @@ struct xpad_led {
|
||||
};
|
||||
|
||||
/**
|
||||
+ * set the LEDs on Xbox360 / Wireless Controllers
|
||||
* @param command
|
||||
* 0: off
|
||||
* 1: all blink, then previous setting
|
||||
@@ -938,14 +953,28 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
|
||||
break;
|
||||
}
|
||||
|
||||
- usb_submit_urb(xpad->irq_out, GFP_KERNEL);
|
||||
+ if (!xpad->irq_out_active) {
|
||||
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
|
||||
+ xpad->irq_out_active = 1;
|
||||
+ } else
|
||||
+ dev_dbg(&xpad->dev->dev, "%s - dropped, irq_out is active\n",
|
||||
+ __func__);
|
||||
+
|
||||
mutex_unlock(&xpad->odata_mutex);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Light up the segment corresponding to the pad number on Xbox 360 Controllers
|
||||
+ */
|
||||
static void xpad_identify_controller(struct usb_xpad *xpad)
|
||||
{
|
||||
- /* Light up the segment corresponding to controller number */
|
||||
- xpad_send_led_command(xpad, (xpad->led_no % 4) + 2);
|
||||
+ if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX360W)
|
||||
+ return;
|
||||
+
|
||||
+ xpad->pad_nr = find_first_zero_bit(&xpad_pad_seq, 32);
|
||||
+ set_bit(xpad->pad_nr, &xpad_pad_seq);
|
||||
+
|
||||
+ xpad_send_led_command(xpad, (xpad->pad_nr % 4) + 2);
|
||||
}
|
||||
|
||||
static void xpad_led_set(struct led_classdev *led_cdev,
|
||||
@@ -959,7 +988,6 @@ static void xpad_led_set(struct led_classdev *led_cdev,
|
||||
|
||||
static int xpad_led_probe(struct usb_xpad *xpad)
|
||||
{
|
||||
- static atomic_t led_seq = ATOMIC_INIT(-1);
|
||||
struct xpad_led *led;
|
||||
struct led_classdev *led_cdev;
|
||||
int error;
|
||||
@@ -971,9 +999,7 @@ static int xpad_led_probe(struct usb_xpad *xpad)
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
- xpad->led_no = atomic_inc_return(&led_seq);
|
||||
-
|
||||
- snprintf(led->name, sizeof(led->name), "xpad%lu", xpad->led_no);
|
||||
+ snprintf(led->name, sizeof(led->name), "xpad%lu", xpad->pad_nr);
|
||||
led->xpad = xpad;
|
||||
|
||||
led_cdev = &led->led_cdev;
|
||||
@@ -987,9 +1013,6 @@ static int xpad_led_probe(struct usb_xpad *xpad)
|
||||
return error;
|
||||
}
|
||||
|
||||
- /* Light up the segment corresponding to controller number */
|
||||
- xpad_identify_controller(xpad);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1012,6 +1035,7 @@ static void xpad_identify_controller(struct usb_xpad *xpad) { }
|
||||
static int xpad_open(struct input_dev *dev)
|
||||
{
|
||||
struct usb_xpad *xpad = input_get_drvdata(dev);
|
||||
+ int retval;
|
||||
|
||||
/* URB was submitted in probe */
|
||||
if (xpad->xtype == XTYPE_XBOX360W)
|
||||
@@ -1022,11 +1046,17 @@ static int xpad_open(struct input_dev *dev)
|
||||
return -EIO;
|
||||
|
||||
if (xpad->xtype == XTYPE_XBOXONE) {
|
||||
+ mutex_lock(&xpad->odata_mutex);
|
||||
/* 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);
|
||||
+ xpad->odata[2] = xpad->odata_serial++; /* packet serial */
|
||||
+ xpad->odata[3] = 0x01; /* rumble bit enable? */
|
||||
+ xpad->odata[4] = 0x00;
|
||||
+ xpad->irq_out->transfer_buffer_length = 5;
|
||||
+ retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL);
|
||||
+ mutex_unlock(&xpad->odata_mutex);
|
||||
+ return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1068,11 +1098,103 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
|
||||
}
|
||||
}
|
||||
|
||||
+static int xpad_init_input(struct usb_xpad *xpad)
|
||||
+{
|
||||
+ struct input_dev *input_dev;
|
||||
+ int i, error;
|
||||
+
|
||||
+ input_dev = input_allocate_device();
|
||||
+ if (!input_dev)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ 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);
|
||||
+ }
|
||||
+ /* this should be a simple else block. However historically xbox360w
|
||||
+ * has mapped DPAD to buttons while xbox360 did not.
|
||||
+ * This made no sense, but now we can not just switch back and have to
|
||||
+ * support both behaviors.
|
||||
+ */
|
||||
+ if(!(xpad->mapping & MAP_DPAD_TO_BUTTONS) ||
|
||||
+ xpad->xtype == XTYPE_XBOX360W) {
|
||||
+ 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]);
|
||||
+ }
|
||||
+
|
||||
+ xpad_identify_controller(xpad);
|
||||
+
|
||||
+ error = xpad_init_ff(xpad);
|
||||
+ if (error)
|
||||
+ goto fail_init_ff;
|
||||
+
|
||||
+ error = xpad_led_probe(xpad);
|
||||
+ if (error)
|
||||
+ goto fail_init_led;
|
||||
+
|
||||
+ error = input_register_device(xpad->dev);
|
||||
+ if (error)
|
||||
+ goto fail_input_register;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+fail_input_register:
|
||||
+ xpad_led_disconnect(xpad);
|
||||
+
|
||||
+fail_init_led:
|
||||
+ input_ff_destroy(input_dev);
|
||||
+
|
||||
+fail_init_ff:
|
||||
+ 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 input_dev *input_dev;
|
||||
struct usb_endpoint_descriptor *ep_irq_in;
|
||||
int ep_irq_in_idx;
|
||||
int i, error;
|
||||
@@ -1094,12 +1216,14 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
}
|
||||
|
||||
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
|
||||
- input_dev = input_allocate_device();
|
||||
- if (!xpad || !input_dev) {
|
||||
+ 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) {
|
||||
@@ -1117,6 +1241,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
xpad->intf = intf;
|
||||
xpad->mapping = xpad_device[i].mapping;
|
||||
xpad->xtype = xpad_device[i].xtype;
|
||||
+ xpad->name = xpad_device[i].name;
|
||||
+ INIT_WORK(&xpad->work, presence_work_function);
|
||||
|
||||
if (xpad->xtype == XTYPE_UNKNOWN) {
|
||||
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
|
||||
@@ -1135,71 +1261,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
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;
|
||||
-
|
||||
- error = xpad_led_probe(xpad);
|
||||
- if (error)
|
||||
- goto fail5;
|
||||
-
|
||||
/* Xbox One controller has in/out endpoints swapped. */
|
||||
ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
|
||||
ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc;
|
||||
@@ -1211,60 +1276,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
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) {
|
||||
/*
|
||||
- * Setup the message to set the LEDs on the
|
||||
- * controller when it shows up
|
||||
- */
|
||||
- xpad->bulk_out = usb_alloc_urb(0, GFP_KERNEL);
|
||||
- if (!xpad->bulk_out) {
|
||||
- error = -ENOMEM;
|
||||
- goto fail7;
|
||||
- }
|
||||
-
|
||||
- xpad->bdata = kzalloc(XPAD_PKT_LEN, GFP_KERNEL);
|
||||
- if (!xpad->bdata) {
|
||||
- error = -ENOMEM;
|
||||
- goto fail8;
|
||||
- }
|
||||
-
|
||||
- xpad->bdata[2] = 0x08;
|
||||
- switch (intf->cur_altsetting->desc.bInterfaceNumber) {
|
||||
- case 0:
|
||||
- xpad->bdata[3] = 0x42;
|
||||
- break;
|
||||
- case 2:
|
||||
- xpad->bdata[3] = 0x43;
|
||||
- break;
|
||||
- case 4:
|
||||
- xpad->bdata[3] = 0x44;
|
||||
- break;
|
||||
- case 6:
|
||||
- xpad->bdata[3] = 0x45;
|
||||
- }
|
||||
-
|
||||
- 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);
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
* Submit the int URB immediately rather than waiting for open
|
||||
* because we get status messages from the device whether
|
||||
* or not any controllers are attached. In fact, it's
|
||||
@@ -1273,56 +1288,116 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
*/
|
||||
xpad->irq_in->dev = xpad->udev;
|
||||
error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
|
||||
+ if (error) {
|
||||
+ usb_kill_urb(xpad->irq_in);
|
||||
+ goto fail4;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * send presence packet
|
||||
+ * This will force the controller to resend connection packets.
|
||||
+ * This is useful in the case we activate the module after the
|
||||
+ * adapter has been plugged in, as it won't automatically
|
||||
+ * send us info about the controllers.
|
||||
+ */
|
||||
+ mutex_lock(&xpad->odata_mutex);
|
||||
+ xpad->odata[0] = 0x08;
|
||||
+ xpad->odata[1] = 0x00;
|
||||
+ xpad->odata[2] = 0x0F;
|
||||
+ 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;
|
||||
+
|
||||
+ if (!xpad->irq_out_active) {
|
||||
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
|
||||
+ xpad->irq_out_active = 1;
|
||||
+ } else
|
||||
+ dev_dbg(&xpad->dev->dev,
|
||||
+ "%s - dropped, irq_out is active\n", __func__);
|
||||
+
|
||||
+ mutex_unlock(&xpad->odata_mutex);
|
||||
+ } else {
|
||||
+ xpad->pad_present = 1;
|
||||
+ error = xpad_init_input(xpad);
|
||||
if (error)
|
||||
- goto fail9;
|
||||
+ goto fail4;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
-static void xpad_disconnect(struct usb_interface *intf)
|
||||
+static void xpad_deinit_input(struct usb_xpad *xpad)
|
||||
{
|
||||
- struct usb_xpad *xpad = usb_get_intfdata (intf);
|
||||
-
|
||||
xpad_led_disconnect(xpad);
|
||||
input_unregister_device(xpad->dev);
|
||||
- xpad_deinit_output(xpad);
|
||||
+
|
||||
+ if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX360W)
|
||||
+ return;
|
||||
+
|
||||
+ clear_bit(xpad->pad_nr, &xpad_pad_seq);
|
||||
+}
|
||||
+
|
||||
+static void xpad_stop_communication(struct usb_xpad *xpad) {
|
||||
+ xpad_stop_output(xpad);
|
||||
|
||||
if (xpad->xtype == XTYPE_XBOX360W) {
|
||||
- usb_kill_urb(xpad->bulk_out);
|
||||
- usb_free_urb(xpad->bulk_out);
|
||||
usb_kill_urb(xpad->irq_in);
|
||||
}
|
||||
|
||||
+ cancel_work_sync(&xpad->work);
|
||||
+}
|
||||
+
|
||||
+static void xpad_disconnect(struct usb_interface *intf)
|
||||
+{
|
||||
+ struct usb_xpad *xpad = usb_get_intfdata (intf);
|
||||
+
|
||||
+ if (xpad->pad_present)
|
||||
+ xpad_deinit_input(xpad);
|
||||
+
|
||||
+ xpad_stop_communication(xpad);
|
||||
+
|
||||
+ xpad_deinit_output(xpad);
|
||||
+
|
||||
usb_free_urb(xpad->irq_in);
|
||||
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
xpad->idata, xpad->idata_dma);
|
||||
|
||||
- kfree(xpad->bdata);
|
||||
kfree(xpad);
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
}
|
||||
|
||||
+static int xpad_suspend(struct usb_interface *intf, pm_message_t message) {
|
||||
+ struct usb_xpad *xpad = usb_get_intfdata (intf);
|
||||
+ xpad_stop_communication(xpad);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int xpad_resume(struct usb_interface *intf) {
|
||||
+ usb_queue_reset_device(intf);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static struct usb_driver xpad_driver = {
|
||||
.name = "xpad",
|
||||
.probe = xpad_probe,
|
||||
.disconnect = xpad_disconnect,
|
||||
+ .suspend = xpad_suspend,
|
||||
+ .resume = xpad_resume,
|
||||
.id_table = xpad_table,
|
||||
};
|
||||
|
||||
--
|
||||
1.9.1
|
||||
|
Loading…
x
Reference in New Issue
Block a user