Commit b26a95d4 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge branch 'next' into for-linus

Prepare second round of input updates for 4.5 merge window.
parents 009f7738 809d9516
...@@ -6,6 +6,7 @@ Required properties: ...@@ -6,6 +6,7 @@ Required properties:
Optional properties: Optional properties:
- autorepeat: Boolean, Enable auto repeat feature of Linux input - autorepeat: Boolean, Enable auto repeat feature of Linux input
subsystem. subsystem.
- label: String, name of the input device.
Each button (key) is represented as a sub-node of "gpio-keys": Each button (key) is represented as a sub-node of "gpio-keys":
Subnode properties: Subnode properties:
......
...@@ -76,10 +76,13 @@ ...@@ -76,10 +76,13 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/input.h>
#include <linux/rcupdate.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb/input.h> #include <linux/usb/input.h>
#include <linux/usb/quirks.h>
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver" #define DRIVER_DESC "X-Box pad driver"
...@@ -125,7 +128,7 @@ static const struct xpad_device { ...@@ -125,7 +128,7 @@ static const struct xpad_device {
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Covert Forces)", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
...@@ -317,21 +320,42 @@ static struct usb_device_id xpad_table[] = { ...@@ -317,21 +320,42 @@ static struct usb_device_id xpad_table[] = {
MODULE_DEVICE_TABLE(usb, xpad_table); MODULE_DEVICE_TABLE(usb, xpad_table);
struct xpad_output_packet {
u8 data[XPAD_PKT_LEN];
u8 len;
bool pending;
};
#define XPAD_OUT_CMD_IDX 0
#define XPAD_OUT_FF_IDX 1
#define XPAD_OUT_LED_IDX (1 + IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF))
#define XPAD_NUM_OUT_PACKETS (1 + \
IS_ENABLED(CONFIG_JOYSTICK_XPAD_FF) + \
IS_ENABLED(CONFIG_JOYSTICK_XPAD_LEDS))
struct usb_xpad { struct usb_xpad {
struct input_dev *dev; /* input device interface */ struct input_dev *dev; /* input device interface */
struct input_dev __rcu *x360w_dev;
struct usb_device *udev; /* usb device */ struct usb_device *udev; /* usb device */
struct usb_interface *intf; /* usb interface */ struct usb_interface *intf; /* usb interface */
int pad_present; bool pad_present;
bool input_created;
struct urb *irq_in; /* urb for interrupt in report */ struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */ unsigned char *idata; /* input data */
dma_addr_t idata_dma; dma_addr_t idata_dma;
struct urb *irq_out; /* urb for interrupt out report */ struct urb *irq_out; /* urb for interrupt out report */
struct usb_anchor irq_out_anchor;
bool irq_out_active; /* we must not use an active URB */
u8 odata_serial; /* serial number for xbox one protocol */
unsigned char *odata; /* output data */ unsigned char *odata; /* output data */
dma_addr_t odata_dma; dma_addr_t odata_dma;
struct mutex odata_mutex; spinlock_t odata_lock;
struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS];
int last_out_packet;
#if defined(CONFIG_JOYSTICK_XPAD_LEDS) #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct xpad_led *led; struct xpad_led *led;
...@@ -343,8 +367,12 @@ struct usb_xpad { ...@@ -343,8 +367,12 @@ struct usb_xpad {
int xtype; /* type of xbox device */ int xtype; /* type of xbox device */
int pad_nr; /* the order x360 pads were attached */ int pad_nr; /* the order x360 pads were attached */
const char *name; /* name of the device */ const char *name; /* name of the device */
struct work_struct work; /* init/remove device from callback */
}; };
static int xpad_init_input(struct usb_xpad *xpad);
static void xpad_deinit_input(struct usb_xpad *xpad);
/* /*
* xpad_process_packet * xpad_process_packet
* *
...@@ -424,11 +452,9 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d ...@@ -424,11 +452,9 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
* http://www.free60.org/wiki/Gamepad * http://www.free60.org/wiki/Gamepad
*/ */
static void xpad360_process_packet(struct usb_xpad *xpad, static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
u16 cmd, unsigned char *data) u16 cmd, unsigned char *data)
{ {
struct input_dev *dev = xpad->dev;
/* digital pad */ /* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (left, right, up, down) */ /* dpad as buttons (left, right, up, down) */
...@@ -495,7 +521,30 @@ static void xpad360_process_packet(struct usb_xpad *xpad, ...@@ -495,7 +521,30 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_sync(dev); input_sync(dev);
} }
static void xpad_identify_controller(struct usb_xpad *xpad); static void xpad_presence_work(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: %d\n", error);
} else {
rcu_assign_pointer(xpad->x360w_dev, xpad->dev);
}
} else {
RCU_INIT_POINTER(xpad->x360w_dev, NULL);
synchronize_rcu();
/*
* Now that we are sure xpad360w_process_packet is not
* using input device we can get rid of it.
*/
xpad_deinit_input(xpad);
}
}
/* /*
* xpad360w_process_packet * xpad360w_process_packet
...@@ -513,24 +562,28 @@ static void xpad_identify_controller(struct usb_xpad *xpad); ...@@ -513,24 +562,28 @@ static void xpad_identify_controller(struct usb_xpad *xpad);
*/ */
static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
{ {
struct input_dev *dev;
bool present;
/* Presence change */ /* Presence change */
if (data[0] & 0x08) { if (data[0] & 0x08) {
if (data[1] & 0x80) { present = (data[1] & 0x80) != 0;
xpad->pad_present = 1;
/* if (xpad->pad_present != present) {
* Light up the segment corresponding to xpad->pad_present = present;
* controller number. schedule_work(&xpad->work);
*/ }
xpad_identify_controller(xpad);
} else
xpad->pad_present = 0;
} }
/* Valid pad data */ /* Valid pad data */
if (!(data[1] & 0x1)) if (data[1] != 0x1)
return; return;
xpad360_process_packet(xpad, cmd, &data[4]); rcu_read_lock();
dev = rcu_dereference(xpad->x360w_dev);
if (dev)
xpad360_process_packet(xpad, dev, cmd, &data[4]);
rcu_read_unlock();
} }
/* /*
...@@ -659,7 +712,7 @@ static void xpad_irq_in(struct urb *urb) ...@@ -659,7 +712,7 @@ static void xpad_irq_in(struct urb *urb)
switch (xpad->xtype) { switch (xpad->xtype) {
case XTYPE_XBOX360: case XTYPE_XBOX360:
xpad360_process_packet(xpad, 0, xpad->idata); xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata);
break; break;
case XTYPE_XBOX360W: case XTYPE_XBOX360W:
xpad360w_process_packet(xpad, 0, xpad->idata); xpad360w_process_packet(xpad, 0, xpad->idata);
...@@ -678,18 +731,73 @@ static void xpad_irq_in(struct urb *urb) ...@@ -678,18 +731,73 @@ static void xpad_irq_in(struct urb *urb)
__func__, retval); __func__, retval);
} }
/* Callers must hold xpad->odata_lock spinlock */
static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad)
{
struct xpad_output_packet *pkt, *packet = NULL;
int i;
for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) {
if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS)
xpad->last_out_packet = 0;
pkt = &xpad->out_packets[xpad->last_out_packet];
if (pkt->pending) {
dev_dbg(&xpad->intf->dev,
"%s - found pending output packet %d\n",
__func__, xpad->last_out_packet);
packet = pkt;
break;
}
}
if (packet) {
memcpy(xpad->odata, packet->data, packet->len);
xpad->irq_out->transfer_buffer_length = packet->len;
return true;
}
return false;
}
/* Callers must hold xpad->odata_lock spinlock */
static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad)
{
int error;
if (!xpad->irq_out_active && xpad_prepare_next_out_packet(xpad)) {
usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor);
error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
if (error) {
dev_err(&xpad->intf->dev,
"%s - usb_submit_urb failed with result %d\n",
__func__, error);
usb_unanchor_urb(xpad->irq_out);
return -EIO;
}
xpad->irq_out_active = true;
}
return 0;
}
static void xpad_irq_out(struct urb *urb) static void xpad_irq_out(struct urb *urb)
{ {
struct usb_xpad *xpad = urb->context; struct usb_xpad *xpad = urb->context;
struct device *dev = &xpad->intf->dev; struct device *dev = &xpad->intf->dev;
int retval, status; int status = urb->status;
int error;
unsigned long flags;
status = urb->status; spin_lock_irqsave(&xpad->odata_lock, flags);
switch (status) { switch (status) {
case 0: case 0:
/* success */ /* success */
return; xpad->out_packets[xpad->last_out_packet].pending = false;
xpad->irq_out_active = xpad_prepare_next_out_packet(xpad);
break;
case -ECONNRESET: case -ECONNRESET:
case -ENOENT: case -ENOENT:
...@@ -697,19 +805,28 @@ static void xpad_irq_out(struct urb *urb) ...@@ -697,19 +805,28 @@ static void xpad_irq_out(struct urb *urb)
/* this urb is terminated, clean up */ /* this urb is terminated, clean up */
dev_dbg(dev, "%s - urb shutting down with status: %d\n", dev_dbg(dev, "%s - urb shutting down with status: %d\n",
__func__, status); __func__, status);
return; xpad->irq_out_active = false;
break;
default: default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n", dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, status); __func__, status);
goto exit; break;
} }
exit: if (xpad->irq_out_active) {
retval = usb_submit_urb(urb, GFP_ATOMIC); usb_anchor_urb(urb, &xpad->irq_out_anchor);
if (retval) error = usb_submit_urb(urb, GFP_ATOMIC);
dev_err(dev, "%s - usb_submit_urb failed with result %d\n", if (error) {
__func__, retval); dev_err(dev,
"%s - usb_submit_urb failed with result %d\n",
__func__, error);
usb_unanchor_urb(urb);
xpad->irq_out_active = false;
}
}
spin_unlock_irqrestore(&xpad->odata_lock, flags);
} }
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
...@@ -721,6 +838,8 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) ...@@ -721,6 +838,8 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
if (xpad->xtype == XTYPE_UNKNOWN) if (xpad->xtype == XTYPE_UNKNOWN)
return 0; return 0;
init_usb_anchor(&xpad->irq_out_anchor);
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->odata_dma); GFP_KERNEL, &xpad->odata_dma);
if (!xpad->odata) { if (!xpad->odata) {
...@@ -728,7 +847,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) ...@@ -728,7 +847,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
goto fail1; goto fail1;
} }
mutex_init(&xpad->odata_mutex); spin_lock_init(&xpad->odata_lock);
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL); xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_out) { if (!xpad->irq_out) {
...@@ -755,8 +874,14 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) ...@@ -755,8 +874,14 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
static void xpad_stop_output(struct usb_xpad *xpad) static void xpad_stop_output(struct usb_xpad *xpad)
{ {
if (xpad->xtype != XTYPE_UNKNOWN) if (xpad->xtype != XTYPE_UNKNOWN) {
usb_kill_urb(xpad->irq_out); if (!usb_wait_anchor_empty_timeout(&xpad->irq_out_anchor,
5000)) {
dev_warn(&xpad->intf->dev,
"timed out waiting for output URB to complete, killing\n");
usb_kill_anchored_urbs(&xpad->irq_out_anchor);
}
}
} }
static void xpad_deinit_output(struct usb_xpad *xpad) static void xpad_deinit_output(struct usb_xpad *xpad)
...@@ -770,27 +895,60 @@ static void xpad_deinit_output(struct usb_xpad *xpad) ...@@ -770,27 +895,60 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
{ {
struct xpad_output_packet *packet =
&xpad->out_packets[XPAD_OUT_CMD_IDX];
unsigned long flags;
int retval; int retval;
mutex_lock(&xpad->odata_mutex); spin_lock_irqsave(&xpad->odata_lock, flags);
packet->data[0] = 0x08;
packet->data[1] = 0x00;
packet->data[2] = 0x0F;
packet->data[3] = 0xC0;
packet->data[4] = 0x00;
packet->data[5] = 0x00;
packet->data[6] = 0x00;
packet->data[7] = 0x00;
packet->data[8] = 0x00;
packet->data[9] = 0x00;
packet->data[10] = 0x00;
packet->data[11] = 0x00;
packet->len = 12;
packet->pending = true;
/* Reset the sequence so we send out presence first */
xpad->last_out_packet = -1;
retval = xpad_try_sending_next_out_packet(xpad);
spin_unlock_irqrestore(&xpad->odata_lock, flags);
xpad->odata[0] = 0x08; return retval;
xpad->odata[1] = 0x00; }
xpad->odata[2] = 0x0F;
xpad->odata[3] = 0xC0; static int xpad_start_xbox_one(struct usb_xpad *xpad)
xpad->odata[4] = 0x00; {
xpad->odata[5] = 0x00; struct xpad_output_packet *packet =
xpad->odata[6] = 0x00; &xpad->out_packets[XPAD_OUT_CMD_IDX];
xpad->odata[7] = 0x00; unsigned long flags;
xpad->odata[8] = 0x00; int retval;
xpad->odata[9] = 0x00;
xpad->odata[10] = 0x00;
xpad->odata[11] = 0x00;
xpad->irq_out->transfer_buffer_length = 12;
retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL); spin_lock_irqsave(&xpad->odata_lock, flags);
mutex_unlock(&xpad->odata_mutex); /* Xbox one controller needs to be initialized. */
packet->data[0] = 0x05;
packet->data[1] = 0x20;
packet->data[2] = xpad->odata_serial++; /* packet serial */
packet->data[3] = 0x01; /* rumble bit enable? */
packet->data[4] = 0x00;
packet->len = 5;
packet->pending = true;
/* Reset the sequence so we send out start packet first */
xpad->last_out_packet = -1;
retval = xpad_try_sending_next_out_packet(xpad);
spin_unlock_irqrestore(&xpad->odata_lock, flags);
return retval; return retval;
} }
...@@ -799,8 +957,11 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) ...@@ -799,8 +957,11 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
{ {
struct usb_xpad *xpad = input_get_drvdata(dev); struct usb_xpad *xpad = input_get_drvdata(dev);
struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX];
__u16 strong; __u16 strong;
__u16 weak; __u16 weak;
int retval;
unsigned long flags;
if (effect->type != FF_RUMBLE) if (effect->type != FF_RUMBLE)
return 0; return 0;
...@@ -808,69 +969,81 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect ...@@ -808,69 +969,81 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
strong = effect->u.rumble.strong_magnitude; strong = effect->u.rumble.strong_magnitude;
weak = effect->u.rumble.weak_magnitude; weak = effect->u.rumble.weak_magnitude;
spin_lock_irqsave(&xpad->odata_lock, flags);
switch (xpad->xtype) { switch (xpad->xtype) {
case XTYPE_XBOX: case XTYPE_XBOX:
xpad->odata[0] = 0x00; packet->data[0] = 0x00;
xpad->odata[1] = 0x06; packet->data[1] = 0x06;
xpad->odata[2] = 0x00; packet->data[2] = 0x00;
xpad->odata[3] = strong / 256; /* left actuator */ packet->data[3] = strong / 256; /* left actuator */
xpad->odata[4] = 0x00; packet->data[4] = 0x00;
xpad->odata[5] = weak / 256; /* right actuator */ packet->data[5] = weak / 256; /* right actuator */
xpad->irq_out->transfer_buffer_length = 6; packet->len = 6;
packet->pending = true;
break; break;
case XTYPE_XBOX360: case XTYPE_XBOX360:
xpad->odata[0] = 0x00; packet->data[0] = 0x00;
xpad->odata[1] = 0x08; packet->data[1] = 0x08;
xpad->odata[2] = 0x00; packet->data[2] = 0x00;
xpad->odata[3] = strong / 256; /* left actuator? */ packet->data[3] = strong / 256; /* left actuator? */
xpad->odata[4] = weak / 256; /* right actuator? */ packet->data[4] = weak / 256; /* right actuator? */
xpad->odata[5] = 0x00; packet->data[5] = 0x00;
xpad->odata[6] = 0x00; packet->data[6] = 0x00;
xpad->odata[7] = 0x00; packet->data[7] = 0x00;
xpad->irq_out->transfer_buffer_length = 8; packet->len = 8;
packet->pending = true;
break; break;
case XTYPE_XBOX360W: case XTYPE_XBOX360W:
xpad->odata[0] = 0x00; packet->data[0] = 0x00;
xpad->odata[1] = 0x01; packet->data[1] = 0x01;
xpad->odata[2] = 0x0F; packet->data[2] = 0x0F;
xpad->odata[3] = 0xC0; packet->data[3] = 0xC0;
xpad->odata[4] = 0x00; packet->data[4] = 0x00;
xpad->odata[5] = strong / 256; packet->data[5] = strong / 256;
xpad->odata[6] = weak / 256; packet->data[6] = weak / 256;
xpad->odata[7] = 0x00; packet->data[7] = 0x00;
xpad->odata[8] = 0x00; packet->data[8] = 0x00;
xpad->odata[9] = 0x00; packet->data[9] = 0x00;
xpad->odata[10] = 0x00; packet->data[10] = 0x00;
xpad->odata[11] = 0x00; packet->data[11] = 0x00;
xpad->irq_out->transfer_buffer_length = 12; packet->len = 12;
packet->pending = true;
break; break;
case XTYPE_XBOXONE: case XTYPE_XBOXONE:
xpad->odata[0] = 0x09; /* activate rumble */ packet->data[0] = 0x09; /* activate rumble */
xpad->odata[1] = 0x08; packet->data[1] = 0x08;
xpad->odata[2] = 0x00; packet->data[2] = xpad->odata_serial++;
xpad->odata[3] = 0x08; /* continuous effect */ packet->data[3] = 0x08; /* continuous effect */
xpad->odata[4] = 0x00; /* simple rumble mode */ packet->data[4] = 0x00; /* simple rumble mode */
xpad->odata[5] = 0x03; /* L and R actuator only */ packet->data[5] = 0x03; /* L and R actuator only */
xpad->odata[6] = 0x00; /* TODO: LT actuator */ packet->data[6] = 0x00; /* TODO: LT actuator */
xpad->odata[7] = 0x00; /* TODO: RT actuator */ packet->data[7] = 0x00; /* TODO: RT actuator */
xpad->odata[8] = strong / 256; /* left actuator */ packet->data[8] = strong / 512; /* left actuator */
xpad->odata[9] = weak / 256; /* right actuator */ packet->data[9] = weak / 512; /* right actuator */
xpad->odata[10] = 0x80; /* length of pulse */ packet->data[10] = 0x80; /* length of pulse */
xpad->odata[11] = 0x00; /* stop period of pulse */ packet->data[11] = 0x00; /* stop period of pulse */
xpad->irq_out->transfer_buffer_length = 12; packet->data[12] = 0x00;
packet->len = 13;
packet->pending = true;
break; break;
default: default:
dev_dbg(&xpad->dev->dev, dev_dbg(&xpad->dev->dev,
"%s - rumble command sent to unsupported xpad type: %d\n", "%s - rumble command sent to unsupported xpad type: %d\n",
__func__, xpad->xtype); __func__, xpad->xtype);
return -EINVAL; retval = -EINVAL;
goto out;
} }
return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); retval = xpad_try_sending_next_out_packet(xpad);
out:
spin_unlock_irqrestore(&xpad->odata_lock, flags);
return retval;
} }
static int xpad_init_ff(struct usb_xpad *xpad) static int xpad_init_ff(struct usb_xpad *xpad)
...@@ -921,36 +1094,44 @@ struct xpad_led { ...@@ -921,36 +1094,44 @@ struct xpad_led {
*/ */
static void xpad_send_led_command(struct usb_xpad *xpad, int command) static void xpad_send_led_command(struct usb_xpad *xpad, int command)
{ {
struct xpad_output_packet *packet =
&xpad->out_packets[XPAD_OUT_LED_IDX];
unsigned long flags;
command %= 16; command %= 16;
mutex_lock(&xpad->odata_mutex); spin_lock_irqsave(&xpad->odata_lock, flags);
switch (xpad->xtype) { switch (xpad->xtype) {
case XTYPE_XBOX360: case XTYPE_XBOX360:
xpad->odata[0] = 0x01; packet->data[0] = 0x01;
xpad->odata[1] = 0x03; packet->data[1] = 0x03;
xpad->odata[2] = command; packet->data[2] = command;
xpad->irq_out->transfer_buffer_length = 3; packet->len = 3;
packet->pending = true;
break; break;
case XTYPE_XBOX360W: case XTYPE_XBOX360W:
xpad->odata[0] = 0x00; packet->data[0] = 0x00;
xpad->odata[1] = 0x00; packet->data[1] = 0x00;
xpad->odata[2] = 0x08; packet->data[2] = 0x08;
xpad->odata[3] = 0x40 + command; packet->data[3] = 0x40 + command;
xpad->odata[4] = 0x00; packet->data[4] = 0x00;
xpad->odata[5] = 0x00; packet->data[5] = 0x00;
xpad->odata[6] = 0x00; packet->data[6] = 0x00;
xpad->odata[7] = 0x00; packet->data[7] = 0x00;
xpad->odata[8] = 0x00; packet->data[8] = 0x00;
xpad->odata[9] = 0x00; packet->data[9] = 0x00;
xpad->odata[10] = 0x00; packet->data[10] = 0x00;
xpad->odata[11] = 0x00; packet->data[11] = 0x00;
xpad->irq_out->transfer_buffer_length = 12; packet->len = 12;
packet->pending = true;
break; break;
} }
usb_submit_urb(xpad->irq_out, GFP_KERNEL); xpad_try_sending_next_out_packet(xpad);
mutex_unlock(&xpad->odata_mutex);
spin_unlock_irqrestore(&xpad->odata_lock, flags);
} }
/* /*
...@@ -959,7 +1140,7 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) ...@@ -959,7 +1140,7 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
*/ */
static void xpad_identify_controller(struct usb_xpad *xpad) static void xpad_identify_controller(struct usb_xpad *xpad)
{ {
xpad_send_led_command(xpad, (xpad->pad_nr % 4) + 2); led_set_brightness(&xpad->led->led_cdev, (xpad->pad_nr % 4) + 2);
} }
static void xpad_led_set(struct led_classdev *led_cdev, static void xpad_led_set(struct led_classdev *led_cdev,
...@@ -1001,14 +1182,7 @@ static int xpad_led_probe(struct usb_xpad *xpad) ...@@ -1001,14 +1182,7 @@ static int xpad_led_probe(struct usb_xpad *xpad)
if (error) if (error)
goto err_free_id; goto err_free_id;
if (xpad->xtype == XTYPE_XBOX360) { xpad_identify_controller(xpad);
/*
* Light up the segment corresponding to controller
* number on wired devices. On wireless we'll do that
* when they respond to "presence" packet.
*/
xpad_identify_controller(xpad);
}
return 0; return 0;
...@@ -1036,37 +1210,73 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { } ...@@ -1036,37 +1210,73 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { }
static void xpad_identify_controller(struct usb_xpad *xpad) { } static void xpad_identify_controller(struct usb_xpad *xpad) { }
#endif #endif
static int xpad_open(struct input_dev *dev) static int xpad_start_input(struct usb_xpad *xpad)
{ {
struct usb_xpad *xpad = input_get_drvdata(dev); int error;
/* URB was submitted in probe */
if (xpad->xtype == XTYPE_XBOX360W)
return 0;
xpad->irq_in->dev = xpad->udev;
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
return -EIO; return -EIO;
if (xpad->xtype == XTYPE_XBOXONE) { if (xpad->xtype == XTYPE_XBOXONE) {
/* Xbox one controller needs to be initialized. */ error = xpad_start_xbox_one(xpad);
xpad->odata[0] = 0x05; if (error) {
xpad->odata[1] = 0x20; usb_kill_urb(xpad->irq_in);
xpad->irq_out->transfer_buffer_length = 2; return error;
return usb_submit_urb(xpad->irq_out, GFP_KERNEL); }
} }
return 0; return 0;
} }
static void xpad_close(struct input_dev *dev) static void xpad_stop_input(struct usb_xpad *xpad)
{ {
struct usb_xpad *xpad = input_get_drvdata(dev); usb_kill_urb(xpad->irq_in);
}
static int xpad360w_start_input(struct usb_xpad *xpad)
{
int error;
if (xpad->xtype != XTYPE_XBOX360W) error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
if (error)
return -EIO;
/*
* 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.
*/
error = xpad_inquiry_pad_presence(xpad);
if (error) {
usb_kill_urb(xpad->irq_in); usb_kill_urb(xpad->irq_in);
return error;
}
xpad_stop_output(xpad); return 0;
}
static void xpad360w_stop_input(struct usb_xpad *xpad)
{
usb_kill_urb(xpad->irq_in);
/* Make sure we are done with presence work if it was scheduled */
flush_work(&xpad->work);
}
static int xpad_open(struct input_dev *dev)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
return xpad_start_input(xpad);
}
static void xpad_close(struct input_dev *dev)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
xpad_stop_input(xpad);
} }
static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
...@@ -1097,8 +1307,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) ...@@ -1097,8 +1307,11 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
static void xpad_deinit_input(struct usb_xpad *xpad) static void xpad_deinit_input(struct usb_xpad *xpad)
{ {
xpad_led_disconnect(xpad); if (xpad->input_created) {
input_unregister_device(xpad->dev); xpad->input_created = false;
xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
}
} }
static int xpad_init_input(struct usb_xpad *xpad) static int xpad_init_input(struct usb_xpad *xpad)
...@@ -1118,8 +1331,10 @@ static int xpad_init_input(struct usb_xpad *xpad) ...@@ -1118,8 +1331,10 @@ static int xpad_init_input(struct usb_xpad *xpad)
input_set_drvdata(input_dev, xpad); input_set_drvdata(input_dev, xpad);
input_dev->open = xpad_open; if (xpad->xtype != XTYPE_XBOX360W) {
input_dev->close = xpad_close; input_dev->open = xpad_open;
input_dev->close = xpad_close;
}
__set_bit(EV_KEY, input_dev->evbit); __set_bit(EV_KEY, input_dev->evbit);
...@@ -1181,6 +1396,7 @@ static int xpad_init_input(struct usb_xpad *xpad) ...@@ -1181,6 +1396,7 @@ static int xpad_init_input(struct usb_xpad *xpad)
if (error) if (error)
goto err_disconnect_led; goto err_disconnect_led;
xpad->input_created = true;
return 0; return 0;
err_disconnect_led: err_disconnect_led:
...@@ -1241,6 +1457,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -1241,6 +1457,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->mapping = xpad_device[i].mapping; xpad->mapping = xpad_device[i].mapping;
xpad->xtype = xpad_device[i].xtype; xpad->xtype = xpad_device[i].xtype;
xpad->name = xpad_device[i].name; xpad->name = xpad_device[i].name;
INIT_WORK(&xpad->work, xpad_presence_work);
if (xpad->xtype == XTYPE_UNKNOWN) { if (xpad->xtype == XTYPE_UNKNOWN) {
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) { if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
...@@ -1277,10 +1494,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -1277,10 +1494,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
usb_set_intfdata(intf, xpad); usb_set_intfdata(intf, xpad);
error = xpad_init_input(xpad);
if (error)
goto err_deinit_output;
if (xpad->xtype == XTYPE_XBOX360W) { if (xpad->xtype == XTYPE_XBOX360W) {
/* /*
* Submit the int URB immediately rather than waiting for open * Submit the int URB immediately rather than waiting for open
...@@ -1289,28 +1502,24 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -1289,28 +1502,24 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
* exactly the message that a controller has arrived that * exactly the message that a controller has arrived that
* we're waiting for. * we're waiting for.
*/ */
xpad->irq_in->dev = xpad->udev; error = xpad360w_start_input(xpad);
error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
if (error) if (error)
goto err_deinit_input; goto err_deinit_output;
/* /*
* Send presence packet. * Wireless controllers require RESET_RESUME to work properly
* This will force the controller to resend connection packets. * after suspend. Ideally this quirk should be in usb core
* This is useful in the case we activate the module after the * quirk list, but we have too many vendors producing these
* adapter has been plugged in, as it won't automatically * controllers and we'd need to maintain 2 identical lists
* send us info about the controllers. * here in this driver and in usb core.
*/ */
error = xpad_inquiry_pad_presence(xpad); udev->quirks |= USB_QUIRK_RESET_RESUME;
} else {
error = xpad_init_input(xpad);
if (error) if (error)
goto err_kill_in_urb; goto err_deinit_output;
} }
return 0; return 0;
err_kill_in_urb:
usb_kill_urb(xpad->irq_in);
err_deinit_input:
xpad_deinit_input(xpad);
err_deinit_output: err_deinit_output:
xpad_deinit_output(xpad); xpad_deinit_output(xpad);
err_free_in_urb: err_free_in_urb:
...@@ -1320,19 +1529,24 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id ...@@ -1320,19 +1529,24 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
err_free_mem: err_free_mem:
kfree(xpad); kfree(xpad);
return error; return error;
} }
static void xpad_disconnect(struct usb_interface *intf) static void xpad_disconnect(struct usb_interface *intf)
{ {
struct usb_xpad *xpad = usb_get_intfdata (intf); struct usb_xpad *xpad = usb_get_intfdata(intf);
if (xpad->xtype == XTYPE_XBOX360W)
xpad360w_stop_input(xpad);
xpad_deinit_input(xpad); xpad_deinit_input(xpad);
xpad_deinit_output(xpad);
if (xpad->xtype == XTYPE_XBOX360W) { /*
usb_kill_urb(xpad->irq_in); * Now that both input device and LED device are gone we can
} * stop output URB.
*/
xpad_stop_output(xpad);
xpad_deinit_output(xpad);
usb_free_urb(xpad->irq_in); usb_free_urb(xpad->irq_in);
usb_free_coherent(xpad->udev, XPAD_PKT_LEN, usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
...@@ -1343,10 +1557,55 @@ static void xpad_disconnect(struct usb_interface *intf) ...@@ -1343,10 +1557,55 @@ static void xpad_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL); 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);
struct input_dev *input = xpad->dev;
if (xpad->xtype == XTYPE_XBOX360W) {
/*
* Wireless controllers always listen to input so
* they are notified when controller shows up
* or goes away.
*/
xpad360w_stop_input(xpad);
} else {
mutex_lock(&input->mutex);
if (input->users)
xpad_stop_input(xpad);
mutex_unlock(&input->mutex);
}
xpad_stop_output(xpad);
return 0;
}
static int xpad_resume(struct usb_interface *intf)
{
struct usb_xpad *xpad = usb_get_intfdata(intf);
struct input_dev *input = xpad->dev;
int retval = 0;
if (xpad->xtype == XTYPE_XBOX360W) {
retval = xpad360w_start_input(xpad);
} else {
mutex_lock(&input->mutex);
if (input->users)
retval = xpad_start_input(xpad);
mutex_unlock(&input->mutex);
}
return retval;
}
static struct usb_driver xpad_driver = { static struct usb_driver xpad_driver = {
.name = "xpad", .name = "xpad",
.probe = xpad_probe, .probe = xpad_probe,
.disconnect = xpad_disconnect, .disconnect = xpad_disconnect,
.suspend = xpad_suspend,
.resume = xpad_resume,
.reset_resume = xpad_resume,
.id_table = xpad_table, .id_table = xpad_table,
}; };
......
...@@ -630,7 +630,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -630,7 +630,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (!node) if (!node)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
nbuttons = of_get_child_count(node); nbuttons = of_get_available_child_count(node);
if (nbuttons == 0) if (nbuttons == 0)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
...@@ -645,8 +645,10 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -645,8 +645,10 @@ gpio_keys_get_devtree_pdata(struct device *dev)
pdata->rep = !!of_get_property(node, "autorepeat", NULL); pdata->rep = !!of_get_property(node, "autorepeat", NULL);
of_property_read_string(node, "label", &pdata->name);
i = 0; i = 0;
for_each_child_of_node(node, pp) { for_each_available_child_of_node(node, pp) {
enum of_gpio_flags flags; enum of_gpio_flags flags;
button = &pdata->buttons[i++]; button = &pdata->buttons[i++];
......
...@@ -113,8 +113,8 @@ struct t7_config { ...@@ -113,8 +113,8 @@ struct t7_config {
#define MXT_T9_DETECT (1 << 7) #define MXT_T9_DETECT (1 << 7)
struct t9_range { struct t9_range {
u16 x; __le16 x;
u16 y; __le16 y;
} __packed; } __packed;
/* MXT_TOUCH_MULTI_T9 orient */ /* MXT_TOUCH_MULTI_T9 orient */
...@@ -216,6 +216,7 @@ struct mxt_data { ...@@ -216,6 +216,7 @@ struct mxt_data {
unsigned int irq; unsigned int irq;
unsigned int max_x; unsigned int max_x;
unsigned int max_y; unsigned int max_y;
bool xy_switch;
bool in_bootloader; bool in_bootloader;
u16 mem_size; u16 mem_size;
u8 t100_aux_ampl; u8 t100_aux_ampl;
...@@ -1665,8 +1666,8 @@ static int mxt_read_t9_resolution(struct mxt_data *data) ...@@ -1665,8 +1666,8 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
if (error) if (error)
return error; return error;
le16_to_cpus(&range.x); data->max_x = get_unaligned_le16(&range.x);
le16_to_cpus(&range.y); data->max_y = get_unaligned_le16(&range.y);
error = __mxt_read_reg(client, error = __mxt_read_reg(client,
object->start_address + MXT_T9_ORIENT, object->start_address + MXT_T9_ORIENT,
...@@ -1674,23 +1675,7 @@ static int mxt_read_t9_resolution(struct mxt_data *data) ...@@ -1674,23 +1675,7 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
if (error) if (error)
return error; return error;
/* Handle default values */ data->xy_switch = orient & MXT_T9_ORIENT_SWITCH;
if (range.x == 0)
range.x = 1023;
if (range.y == 0)
range.y = 1023;
if (orient & MXT_T9_ORIENT_SWITCH) {
data->max_x = range.y;
data->max_y = range.x;
} else {
data->max_x = range.x;
data->max_y = range.y;
}
dev_dbg(&client->dev,
"Touchscreen size X%uY%u\n", data->max_x, data->max_y);
return 0; return 0;
} }
...@@ -1708,13 +1693,14 @@ static int mxt_read_t100_config(struct mxt_data *data) ...@@ -1708,13 +1693,14 @@ static int mxt_read_t100_config(struct mxt_data *data)
if (!object) if (!object)
return -EINVAL; return -EINVAL;
/* read touchscreen dimensions */
error = __mxt_read_reg(client, error = __mxt_read_reg(client,
object->start_address + MXT_T100_XRANGE, object->start_address + MXT_T100_XRANGE,
sizeof(range_x), &range_x); sizeof(range_x), &range_x);
if (error) if (error)
return error; return error;
le16_to_cpus(&range_x); data->max_x = get_unaligned_le16(&range_x);
error = __mxt_read_reg(client, error = __mxt_read_reg(client,
object->start_address + MXT_T100_YRANGE, object->start_address + MXT_T100_YRANGE,
...@@ -1722,36 +1708,24 @@ static int mxt_read_t100_config(struct mxt_data *data) ...@@ -1722,36 +1708,24 @@ static int mxt_read_t100_config(struct mxt_data *data)
if (error) if (error)
return error; return error;
le16_to_cpus(&range_y); data->max_y = get_unaligned_le16(&range_y);
/* read orientation config */
error = __mxt_read_reg(client, error = __mxt_read_reg(client,
object->start_address + MXT_T100_CFG1, object->start_address + MXT_T100_CFG1,
1, &cfg); 1, &cfg);
if (error) if (error)
return error; return error;
data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY;
/* allocate aux bytes */
error = __mxt_read_reg(client, error = __mxt_read_reg(client,
object->start_address + MXT_T100_TCHAUX, object->start_address + MXT_T100_TCHAUX,
1, &tchaux); 1, &tchaux);
if (error) if (error)
return error; return error;
/* Handle default values */
if (range_x == 0)
range_x = 1023;
if (range_y == 0)
range_y = 1023;
if (cfg & MXT_T100_CFG_SWITCHXY) {
data->max_x = range_y;
data->max_y = range_x;
} else {
data->max_x = range_x;
data->max_y = range_y;
}
/* allocate aux bytes */
aux = 6; aux = 6;
if (tchaux & MXT_T100_TCHAUX_VECT) if (tchaux & MXT_T100_TCHAUX_VECT)
...@@ -1767,9 +1741,6 @@ static int mxt_read_t100_config(struct mxt_data *data) ...@@ -1767,9 +1741,6 @@ static int mxt_read_t100_config(struct mxt_data *data)
"T100 aux mappings vect:%u ampl:%u area:%u\n", "T100 aux mappings vect:%u ampl:%u area:%u\n",
data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area); data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area);
dev_info(&client->dev,
"T100 Touchscreen size X%uY%u\n", data->max_x, data->max_y);
return 0; return 0;
} }
...@@ -1828,6 +1799,19 @@ static int mxt_initialize_input_device(struct mxt_data *data) ...@@ -1828,6 +1799,19 @@ static int mxt_initialize_input_device(struct mxt_data *data)
return -EINVAL; return -EINVAL;
} }
/* Handle default values and orientation switch */
if (data->max_x == 0)
data->max_x = 1023;
if (data->max_y == 0)
data->max_y = 1023;
if (data->xy_switch)
swap(data->max_x, data->max_y);
dev_info(dev, "Touchscreen size X%uY%u\n", data->max_x, data->max_y);
/* Register input device */
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) { if (!input_dev) {
dev_err(dev, "Failed to allocate memory\n"); dev_err(dev, "Failed to allocate memory\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment