Commit 5430dfe9 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull more input updates from Dmitry Torokhov:
 "The second round of updates for the input subsystem, mainly changes to
  xpad driver to better hanlde Xbox One controllers"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: gpio-keys - allow disabling individual buttons in DT
  Input: gpio-keys - allow setting input device name in DT
  Input: xpad - correct xbox one pad device name
  Input: atmel_mxt_ts - improve touchscreen size/orientation handling
  Input: xpad - use LED API when identifying wireless controllers
  Input: xpad - workaround dead irq_out after suspend/ resume
  Input: xpad - update Xbox One Force Feedback Support
  Input: xpad - correctly handle concurrent LED and FF requests
  Input: xpad - handle "present" and "gone" correctly
  Input: xpad - remove spurious events of wireless xpad 360 controller
parents 4adea1fd b26a95d4
......@@ -6,6 +6,7 @@ Required properties:
Optional properties:
- autorepeat: Boolean, Enable auto repeat feature of Linux input
subsystem.
- label: String, name of the input device.
Each button (key) is represented as a sub-node of "gpio-keys":
Subnode properties:
......
......@@ -76,10 +76,13 @@
*/
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/usb/input.h>
#include <linux/usb/quirks.h>
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
......@@ -125,7 +128,7 @@ static const struct xpad_device {
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 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, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
......@@ -317,21 +320,42 @@ static struct usb_device_id 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 input_dev *dev; /* input device interface */
struct input_dev __rcu *x360w_dev;
struct usb_device *udev; /* usb device */
struct usb_interface *intf; /* usb interface */
int pad_present;
bool pad_present;
bool input_created;
struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */
dma_addr_t idata_dma;
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 */
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)
struct xpad_led *led;
......@@ -343,8 +367,12 @@ struct usb_xpad {
int xtype; /* type of xbox device */
int pad_nr; /* the order x360 pads were attached */
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
*
......@@ -424,11 +452,9 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
* 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)
{
struct input_dev *dev = xpad->dev;
/* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (left, right, up, down) */
......@@ -495,7 +521,30 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
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
......@@ -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)
{
struct input_dev *dev;
bool present;
/* Presence change */
if (data[0] & 0x08) {
if (data[1] & 0x80) {
xpad->pad_present = 1;
/*
* Light up the segment corresponding to
* controller number.
*/
xpad_identify_controller(xpad);
} else
xpad->pad_present = 0;
present = (data[1] & 0x80) != 0;
if (xpad->pad_present != present) {
xpad->pad_present = present;
schedule_work(&xpad->work);
}
}
/* Valid pad data */
if (!(data[1] & 0x1))
if (data[1] != 0x1)
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)
switch (xpad->xtype) {
case XTYPE_XBOX360:
xpad360_process_packet(xpad, 0, xpad->idata);
xpad360_process_packet(xpad, xpad->dev, 0, xpad->idata);
break;
case XTYPE_XBOX360W:
xpad360w_process_packet(xpad, 0, xpad->idata);
......@@ -678,18 +731,73 @@ static void xpad_irq_in(struct urb *urb)
__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)
{
struct usb_xpad *xpad = urb->context;
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) {
case 0:
/* 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 -ENOENT:
......@@ -697,19 +805,28 @@ 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);
return;
xpad->irq_out_active = false;
break;
default:
dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, status);
goto exit;
break;
}
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
if (xpad->irq_out_active) {
usb_anchor_urb(urb, &xpad->irq_out_anchor);
error = usb_submit_urb(urb, GFP_ATOMIC);
if (error) {
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)
......@@ -721,6 +838,8 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
if (xpad->xtype == XTYPE_UNKNOWN)
return 0;
init_usb_anchor(&xpad->irq_out_anchor);
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
GFP_KERNEL, &xpad->odata_dma);
if (!xpad->odata) {
......@@ -728,7 +847,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
goto fail1;
}
mutex_init(&xpad->odata_mutex);
spin_lock_init(&xpad->odata_lock);
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_out) {
......@@ -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)
{
if (xpad->xtype != XTYPE_UNKNOWN)
usb_kill_urb(xpad->irq_out);
if (xpad->xtype != XTYPE_UNKNOWN) {
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)
......@@ -770,27 +895,60 @@ static void xpad_deinit_output(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;
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;
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;
return retval;
}
static int xpad_start_xbox_one(struct usb_xpad *xpad)
{
struct xpad_output_packet *packet =
&xpad->out_packets[XPAD_OUT_CMD_IDX];
unsigned long flags;
int retval;
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;
}
......@@ -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)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX];
__u16 strong;
__u16 weak;
int retval;
unsigned long flags;
if (effect->type != FF_RUMBLE)
return 0;
......@@ -808,69 +969,81 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
strong = effect->u.rumble.strong_magnitude;
weak = effect->u.rumble.weak_magnitude;
spin_lock_irqsave(&xpad->odata_lock, flags);
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;
packet->data[0] = 0x00;
packet->data[1] = 0x06;
packet->data[2] = 0x00;
packet->data[3] = strong / 256; /* left actuator */
packet->data[4] = 0x00;
packet->data[5] = weak / 256; /* right actuator */
packet->len = 6;
packet->pending = true;
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;
packet->data[0] = 0x00;
packet->data[1] = 0x08;
packet->data[2] = 0x00;
packet->data[3] = strong / 256; /* left actuator? */
packet->data[4] = weak / 256; /* right actuator? */
packet->data[5] = 0x00;
packet->data[6] = 0x00;
packet->data[7] = 0x00;
packet->len = 8;
packet->pending = true;
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;
packet->data[0] = 0x00;
packet->data[1] = 0x01;
packet->data[2] = 0x0F;
packet->data[3] = 0xC0;
packet->data[4] = 0x00;
packet->data[5] = strong / 256;
packet->data[6] = weak / 256;
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;
break;
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;
packet->data[0] = 0x09; /* activate rumble */
packet->data[1] = 0x08;
packet->data[2] = xpad->odata_serial++;
packet->data[3] = 0x08; /* continuous effect */
packet->data[4] = 0x00; /* simple rumble mode */
packet->data[5] = 0x03; /* L and R actuator only */
packet->data[6] = 0x00; /* TODO: LT actuator */
packet->data[7] = 0x00; /* TODO: RT actuator */
packet->data[8] = strong / 512; /* left actuator */
packet->data[9] = weak / 512; /* right actuator */
packet->data[10] = 0x80; /* length of pulse */
packet->data[11] = 0x00; /* stop period of pulse */
packet->data[12] = 0x00;
packet->len = 13;
packet->pending = true;
break;
default:
dev_dbg(&xpad->dev->dev,
"%s - rumble command sent to unsupported xpad type: %d\n",
__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)
......@@ -921,36 +1094,44 @@ struct xpad_led {
*/
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;
mutex_lock(&xpad->odata_mutex);
spin_lock_irqsave(&xpad->odata_lock, flags);
switch (xpad->xtype) {
case XTYPE_XBOX360:
xpad->odata[0] = 0x01;
xpad->odata[1] = 0x03;
xpad->odata[2] = command;
xpad->irq_out->transfer_buffer_length = 3;
packet->data[0] = 0x01;
packet->data[1] = 0x03;
packet->data[2] = command;
packet->len = 3;
packet->pending = true;
break;
case XTYPE_XBOX360W:
xpad->odata[0] = 0x00;
xpad->odata[1] = 0x00;
xpad->odata[2] = 0x08;
xpad->odata[3] = 0x40 + command;
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;
packet->data[0] = 0x00;
packet->data[1] = 0x00;
packet->data[2] = 0x08;
packet->data[3] = 0x40 + command;
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;
break;
}
usb_submit_urb(xpad->irq_out, GFP_KERNEL);
mutex_unlock(&xpad->odata_mutex);
xpad_try_sending_next_out_packet(xpad);
spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
/*
......@@ -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)
{
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,
......@@ -1001,14 +1182,7 @@ static int xpad_led_probe(struct usb_xpad *xpad)
if (error)
goto err_free_id;
if (xpad->xtype == XTYPE_XBOX360) {
/*
* 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);
}
xpad_identify_controller(xpad);
return 0;
......@@ -1036,37 +1210,73 @@ static void xpad_led_disconnect(struct usb_xpad *xpad) { }
static void xpad_identify_controller(struct usb_xpad *xpad) { }
#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);
/* URB was submitted in probe */
if (xpad->xtype == XTYPE_XBOX360W)
return 0;
int error;
xpad->irq_in->dev = xpad->udev;
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
return -EIO;
if (xpad->xtype == XTYPE_XBOXONE) {
/* 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);
error = xpad_start_xbox_one(xpad);
if (error) {
usb_kill_urb(xpad->irq_in);
return error;
}
}
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);
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)
......@@ -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)
{
xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
if (xpad->input_created) {
xpad->input_created = false;
xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
}
}
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_dev->open = xpad_open;
input_dev->close = xpad_close;
if (xpad->xtype != XTYPE_XBOX360W) {
input_dev->open = xpad_open;
input_dev->close = xpad_close;
}
__set_bit(EV_KEY, input_dev->evbit);
......@@ -1181,6 +1396,7 @@ static int xpad_init_input(struct usb_xpad *xpad)
if (error)
goto err_disconnect_led;
xpad->input_created = true;
return 0;
err_disconnect_led:
......@@ -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->xtype = xpad_device[i].xtype;
xpad->name = xpad_device[i].name;
INIT_WORK(&xpad->work, xpad_presence_work);
if (xpad->xtype == XTYPE_UNKNOWN) {
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
usb_set_intfdata(intf, xpad);
error = xpad_init_input(xpad);
if (error)
goto err_deinit_output;
if (xpad->xtype == XTYPE_XBOX360W) {
/*
* 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
* exactly the message that a controller has arrived that
* we're waiting for.
*/
xpad->irq_in->dev = xpad->udev;
error = usb_submit_urb(xpad->irq_in, GFP_KERNEL);
error = xpad360w_start_input(xpad);
if (error)
goto err_deinit_input;
goto err_deinit_output;
/*
* 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.
* Wireless controllers require RESET_RESUME to work properly
* after suspend. Ideally this quirk should be in usb core
* quirk list, but we have too many vendors producing these
* controllers and we'd need to maintain 2 identical lists
* 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)
goto err_kill_in_urb;
goto err_deinit_output;
}
return 0;
err_kill_in_urb:
usb_kill_urb(xpad->irq_in);
err_deinit_input:
xpad_deinit_input(xpad);
err_deinit_output:
xpad_deinit_output(xpad);
err_free_in_urb:
......@@ -1320,19 +1529,24 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
err_free_mem:
kfree(xpad);
return error;
}
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_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_coherent(xpad->udev, XPAD_PKT_LEN,
......@@ -1343,10 +1557,55 @@ static void xpad_disconnect(struct usb_interface *intf)
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 = {
.name = "xpad",
.probe = xpad_probe,
.disconnect = xpad_disconnect,
.suspend = xpad_suspend,
.resume = xpad_resume,
.reset_resume = xpad_resume,
.id_table = xpad_table,
};
......
......@@ -630,7 +630,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (!node)
return ERR_PTR(-ENODEV);
nbuttons = of_get_child_count(node);
nbuttons = of_get_available_child_count(node);
if (nbuttons == 0)
return ERR_PTR(-ENODEV);
......@@ -645,8 +645,10 @@ gpio_keys_get_devtree_pdata(struct device *dev)
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
of_property_read_string(node, "label", &pdata->name);
i = 0;
for_each_child_of_node(node, pp) {
for_each_available_child_of_node(node, pp) {
enum of_gpio_flags flags;
button = &pdata->buttons[i++];
......
......@@ -113,8 +113,8 @@ struct t7_config {
#define MXT_T9_DETECT (1 << 7)
struct t9_range {
u16 x;
u16 y;
__le16 x;
__le16 y;
} __packed;
/* MXT_TOUCH_MULTI_T9 orient */
......@@ -216,6 +216,7 @@ struct mxt_data {
unsigned int irq;
unsigned int max_x;
unsigned int max_y;
bool xy_switch;
bool in_bootloader;
u16 mem_size;
u8 t100_aux_ampl;
......@@ -1665,8 +1666,8 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
if (error)
return error;
le16_to_cpus(&range.x);
le16_to_cpus(&range.y);
data->max_x = get_unaligned_le16(&range.x);
data->max_y = get_unaligned_le16(&range.y);
error = __mxt_read_reg(client,
object->start_address + MXT_T9_ORIENT,
......@@ -1674,23 +1675,7 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
if (error)
return error;
/* Handle default values */
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);
data->xy_switch = orient & MXT_T9_ORIENT_SWITCH;
return 0;
}
......@@ -1708,13 +1693,14 @@ static int mxt_read_t100_config(struct mxt_data *data)
if (!object)
return -EINVAL;
/* read touchscreen dimensions */
error = __mxt_read_reg(client,
object->start_address + MXT_T100_XRANGE,
sizeof(range_x), &range_x);
if (error)
return error;
le16_to_cpus(&range_x);
data->max_x = get_unaligned_le16(&range_x);
error = __mxt_read_reg(client,
object->start_address + MXT_T100_YRANGE,
......@@ -1722,36 +1708,24 @@ static int mxt_read_t100_config(struct mxt_data *data)
if (error)
return error;
le16_to_cpus(&range_y);
data->max_y = get_unaligned_le16(&range_y);
/* read orientation config */
error = __mxt_read_reg(client,
object->start_address + MXT_T100_CFG1,
1, &cfg);
if (error)
return error;
data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY;
/* allocate aux bytes */
error = __mxt_read_reg(client,
object->start_address + MXT_T100_TCHAUX,
1, &tchaux);
if (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;
if (tchaux & MXT_T100_TCHAUX_VECT)
......@@ -1767,9 +1741,6 @@ static int mxt_read_t100_config(struct mxt_data *data)
"T100 aux mappings vect:%u ampl:%u area:%u\n",
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;
}
......@@ -1828,6 +1799,19 @@ static int mxt_initialize_input_device(struct mxt_data *data)
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();
if (!input_dev) {
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