Merge branch 'next' into for-linus
Prepare second round of input updates for 4.5 merge window.
This commit is contained in:
commit
b26a95d435
|
@ -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 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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 {
|
||||||
{ 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[] = {
|
||||||
|
|
||||||
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 {
|
||||||
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
|
||||||
* 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,
|
||||||
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);
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
|
|
||||||
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 @@ exit:
|
||||||
__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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
xpad->odata[0] = 0x08;
|
packet->data[0] = 0x08;
|
||||||
xpad->odata[1] = 0x00;
|
packet->data[1] = 0x00;
|
||||||
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] = 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;
|
||||||
|
|
||||||
retval = usb_submit_urb(xpad->irq_out, GFP_KERNEL);
|
/* Reset the sequence so we send out presence first */
|
||||||
|
xpad->last_out_packet = -1;
|
||||||
|
retval = xpad_try_sending_next_out_packet(xpad);
|
||||||
|
|
||||||
mutex_unlock(&xpad->odata_mutex);
|
spin_unlock_irqrestore(&xpad->odata_lock, flags);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&xpad->odata_lock, flags);
|
||||||
|
|
||||||
|
/* 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)
|
||||||
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
|
||||||
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 {
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
if (error)
|
if (error)
|
||||||
goto err_free_id;
|
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;
|
return 0;
|
||||||
|
|
||||||
|
@ -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_stop_input(struct usb_xpad *xpad)
|
||||||
|
{
|
||||||
|
usb_kill_urb(xpad->irq_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xpad360w_start_input(struct usb_xpad *xpad)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
static void xpad_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct usb_xpad *xpad = input_get_drvdata(dev);
|
struct usb_xpad *xpad = input_get_drvdata(dev);
|
||||||
|
|
||||||
if (xpad->xtype != XTYPE_XBOX360W)
|
xpad_stop_input(xpad);
|
||||||
usb_kill_urb(xpad->irq_in);
|
|
||||||
|
|
||||||
xpad_stop_output(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,9 +1307,12 @@ 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)
|
||||||
{
|
{
|
||||||
|
if (xpad->input_created) {
|
||||||
|
xpad->input_created = false;
|
||||||
xpad_led_disconnect(xpad);
|
xpad_led_disconnect(xpad);
|
||||||
input_unregister_device(xpad->dev);
|
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)
|
||||||
|
|
||||||
input_set_drvdata(input_dev, xpad);
|
input_set_drvdata(input_dev, xpad);
|
||||||
|
|
||||||
|
if (xpad->xtype != XTYPE_XBOX360W) {
|
||||||
input_dev->open = xpad_open;
|
input_dev->open = xpad_open;
|
||||||
input_dev->close = xpad_close;
|
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)
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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
|
||||||
* 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 @@ err_free_idata:
|
||||||
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);
|
||||||
|
|
||||||
xpad_deinit_input(xpad);
|
if (xpad->xtype == XTYPE_XBOX360W)
|
||||||
xpad_deinit_output(xpad);
|
xpad360w_stop_input(xpad);
|
||||||
|
|
||||||
if (xpad->xtype == XTYPE_XBOX360W) {
|
xpad_deinit_input(xpad);
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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 {
|
||||||
#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 {
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
"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)
|
||||||
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");
|
||||||
|
|
Loading…
Reference in New Issue