summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/joystick/xpad.c592
-rw-r--r--drivers/input/keyboard/adp5589-keys.c7
-rw-r--r--drivers/input/keyboard/cap11xx.c8
-rw-r--r--drivers/input/keyboard/gpio_keys.c6
-rw-r--r--drivers/input/misc/Kconfig2
-rw-r--r--drivers/input/misc/sirfsoc-onkey.c2
-rw-r--r--drivers/input/mouse/vmmouse.c13
-rw-r--r--drivers/input/serio/serio.c2
-rw-r--r--drivers/input/touchscreen/Kconfig2
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c68
-rw-r--r--drivers/input/touchscreen/colibri-vf50-ts.c1
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c18
12 files changed, 489 insertions, 232 deletions
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index fd4100d56d8c..e8a84d12b7ff 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -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 @@ exit:
__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;
@@ -1033,40 +1207,75 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
#else
static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
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 +1306,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 +1330,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 +1395,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 +1456,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 +1493,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 +1501,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 +1528,24 @@ err_free_idata:
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 +1556,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,
};
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index 4d446d5085aa..c01a1d648f9f 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -235,7 +235,7 @@ struct adp5589_kpad {
unsigned short gpimapsize;
unsigned extend_cfg;
bool is_adp5585;
- bool adp5585_support_row5;
+ bool support_row5;
#ifdef CONFIG_GPIOLIB
unsigned char gpiomap[ADP5589_MAXGPIO];
bool export_gpio;
@@ -485,7 +485,7 @@ static int adp5589_build_gpiomap(struct adp5589_kpad *kpad,
if (kpad->extend_cfg & C4_EXTEND_CFG)
pin_used[kpad->var->c4_extend_cfg] = true;
- if (!kpad->adp5585_support_row5)
+ if (!kpad->support_row5)
pin_used[5] = true;
for (i = 0; i < kpad->var->maxgpio; i++)
@@ -884,12 +884,13 @@ static int adp5589_probe(struct i2c_client *client,
switch (id->driver_data) {
case ADP5585_02:
- kpad->adp5585_support_row5 = true;
+ kpad->support_row5 = true;
case ADP5585_01:
kpad->is_adp5585 = true;
kpad->var = &const_adp5585;
break;
case ADP5589:
+ kpad->support_row5 = true;
kpad->var = &const_adp5589;
break;
}
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 378db10001df..4401be225d64 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -304,8 +304,10 @@ static int cap11xx_init_leds(struct device *dev,
led->cdev.brightness = LED_OFF;
error = of_property_read_u32(child, "reg", &reg);
- if (error != 0 || reg >= num_leds)
+ if (error != 0 || reg >= num_leds) {
+ of_node_put(child);
return -EINVAL;
+ }
led->reg = reg;
led->priv = priv;
@@ -313,8 +315,10 @@ static int cap11xx_init_leds(struct device *dev,
INIT_WORK(&led->work, cap11xx_led_work);
error = devm_led_classdev_register(dev, &led->cdev);
- if (error)
+ if (error) {
+ of_node_put(child);
return error;
+ }
priv->num_leds++;
led++;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index b9f01bd1b7ef..29093657f2ef 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -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++];
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index d6d16fa78281..1f2337abcf2f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -733,7 +733,7 @@ config INPUT_XEN_KBDDEV_FRONTEND
module will be called xen-kbdfront.
config INPUT_SIRFSOC_ONKEY
- bool "CSR SiRFSoC power on/off/suspend key support"
+ tristate "CSR SiRFSoC power on/off/suspend key support"
depends on ARCH_SIRF && OF
default y
help
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
index 9d5b89befe6f..ed7237f19539 100644
--- a/drivers/input/misc/sirfsoc-onkey.c
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -101,7 +101,7 @@ static void sirfsoc_pwrc_close(struct input_dev *input)
static const struct of_device_id sirfsoc_pwrc_of_match[] = {
{ .compatible = "sirf,prima2-pwrc" },
{},
-}
+};
MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
static int sirfsoc_pwrc_probe(struct platform_device *pdev)
diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c
index e272f06258ce..a3f0f5a47490 100644
--- a/drivers/input/mouse/vmmouse.c
+++ b/drivers/input/mouse/vmmouse.c
@@ -458,8 +458,6 @@ int vmmouse_init(struct psmouse *psmouse)
priv->abs_dev = abs_dev;
psmouse->private = priv;
- input_set_capability(rel_dev, EV_REL, REL_WHEEL);
-
/* Set up and register absolute device */
snprintf(priv->phys, sizeof(priv->phys), "%s/input1",
psmouse->ps2dev.serio->phys);
@@ -475,10 +473,6 @@ int vmmouse_init(struct psmouse *psmouse)
abs_dev->id.version = psmouse->model;
abs_dev->dev.parent = &psmouse->ps2dev.serio->dev;
- error = input_register_device(priv->abs_dev);
- if (error)
- goto init_fail;
-
/* Set absolute device capabilities */
input_set_capability(abs_dev, EV_KEY, BTN_LEFT);
input_set_capability(abs_dev, EV_KEY, BTN_RIGHT);
@@ -488,6 +482,13 @@ int vmmouse_init(struct psmouse *psmouse)
input_set_abs_params(abs_dev, ABS_X, 0, VMMOUSE_MAX_X, 0, 0);
input_set_abs_params(abs_dev, ABS_Y, 0, VMMOUSE_MAX_Y, 0, 0);
+ error = input_register_device(priv->abs_dev);
+ if (error)
+ goto init_fail;
+
+ /* Add wheel capability to the relative device */
+ input_set_capability(rel_dev, EV_REL, REL_WHEEL);
+
psmouse->protocol_handler = vmmouse_process_byte;
psmouse->disconnect = vmmouse_disconnect;
psmouse->reconnect = vmmouse_reconnect;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 8f828975ab10..1ca7f551e2da 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -134,7 +134,7 @@ static void serio_find_driver(struct serio *serio)
int error;
error = device_attach(&serio->dev);
- if (error < 0)
+ if (error < 0 && error != -EPROBE_DEFER)
dev_warn(&serio->dev,
"device_attach() failed for %s (%s), error: %d\n",
serio->phys, serio->name, error);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 53a97b379c9f..66c62641b59a 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -376,7 +376,7 @@ config TOUCHSCREEN_IPROC
config TOUCHSCREEN_S3C2410
tristate "Samsung S3C2410/generic touchscreen input driver"
depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
- select S3C_ADC
+ depends on S3C_ADC
help
Say Y here if you have the s3c2410 touchscreen.
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2d5794ec338b..2160512e861a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -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");
diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c
index 5d4903a402cc..69828d015d45 100644
--- a/drivers/input/touchscreen/colibri-vf50-ts.c
+++ b/drivers/input/touchscreen/colibri-vf50-ts.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 0b0f8c17f3f7..23fbe382da8b 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -822,16 +822,22 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev,
int error;
error = device_property_read_u32(dev, "threshold", &val);
- if (!error)
- reg_addr->reg_threshold = val;
+ if (!error) {
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, val);
+ tsdata->threshold = val;
+ }
error = device_property_read_u32(dev, "gain", &val);
- if (!error)
- reg_addr->reg_gain = val;
+ if (!error) {
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, val);
+ tsdata->gain = val;
+ }
error = device_property_read_u32(dev, "offset", &val);
- if (!error)
- reg_addr->reg_offset = val;
+ if (!error) {
+ edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val);
+ tsdata->offset = val;
+ }
}
static void
OpenPOWER on IntegriCloud