aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/input/xpad.c139
1 files changed, 95 insertions, 44 deletions
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
index cebb6c463bfb..6a12a943b938 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/usb/input/xpad.c
@@ -1,8 +1,9 @@
1/* 1/*
2 * X-Box gamepad - v0.0.5 2 * X-Box gamepad - v0.0.6
3 * 3 *
4 * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> 4 * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
5 * 5 * 2005 Dominic Cerquetti <binary1230@yahoo.com>
6 * 2006 Adam Buchbinder <adam.buchbinder@gmail.com>
6 * 7 *
7 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as 9 * modify it under the terms of the GNU General Public License as
@@ -30,9 +31,10 @@
30 * - Greg Kroah-Hartman - usb-skeleton driver 31 * - Greg Kroah-Hartman - usb-skeleton driver
31 * 32 *
32 * TODO: 33 * TODO:
33 * - fine tune axes 34 * - fine tune axes (especially trigger axes)
34 * - fix "analog" buttons (reported as digital now) 35 * - fix "analog" buttons (reported as digital now)
35 * - get rumble working 36 * - get rumble working
37 * - need USB IDs for other dance pads
36 * 38 *
37 * History: 39 * History:
38 * 40 *
@@ -57,25 +59,40 @@
57#include <linux/kernel.h> 59#include <linux/kernel.h>
58#include <linux/init.h> 60#include <linux/init.h>
59#include <linux/slab.h> 61#include <linux/slab.h>
62#include <linux/stat.h>
60#include <linux/module.h> 63#include <linux/module.h>
64#include <linux/moduleparam.h>
61#include <linux/smp_lock.h> 65#include <linux/smp_lock.h>
62#include <linux/usb/input.h> 66#include <linux/usb/input.h>
63 67
64#define DRIVER_VERSION "v0.0.5" 68#define DRIVER_VERSION "v0.0.6"
65#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" 69#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
66#define DRIVER_DESC "X-Box pad driver" 70#define DRIVER_DESC "X-Box pad driver"
67 71
68#define XPAD_PKT_LEN 32 72#define XPAD_PKT_LEN 32
69 73
74/* xbox d-pads should map to buttons, as is required for DDR pads
75 but we map them to axes when possible to simplify things */
76#define MAP_DPAD_TO_BUTTONS 0
77#define MAP_DPAD_TO_AXES 1
78#define MAP_DPAD_UNKNOWN -1
79
80static int dpad_to_buttons;
81module_param(dpad_to_buttons, bool, S_IRUGO);
82MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
83
70static const struct xpad_device { 84static const struct xpad_device {
71 u16 idVendor; 85 u16 idVendor;
72 u16 idProduct; 86 u16 idProduct;
73 char *name; 87 char *name;
88 u8 dpad_mapping;
74} xpad_device[] = { 89} xpad_device[] = {
75 { 0x045e, 0x0202, "Microsoft X-Box pad (US)" }, 90 { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES },
76 { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" }, 91 { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES },
77 { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" }, 92 { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES },
78 { 0x0000, 0x0000, "X-Box pad" } 93 { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES },
94 { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS },
95 { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN }
79}; 96};
80 97
81static const signed short xpad_btn[] = { 98static const signed short xpad_btn[] = {
@@ -84,11 +101,23 @@ static const signed short xpad_btn[] = {
84 -1 /* terminating entry */ 101 -1 /* terminating entry */
85}; 102};
86 103
104/* only used if MAP_DPAD_TO_BUTTONS */
105static const signed short xpad_btn_pad[] = {
106 BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
107 BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
108 -1 /* terminating entry */
109};
110
87static const signed short xpad_abs[] = { 111static const signed short xpad_abs[] = {
88 ABS_X, ABS_Y, /* left stick */ 112 ABS_X, ABS_Y, /* left stick */
89 ABS_RX, ABS_RY, /* right stick */ 113 ABS_RX, ABS_RY, /* right stick */
90 ABS_Z, ABS_RZ, /* triggers left/right */ 114 ABS_Z, ABS_RZ, /* triggers left/right */
91 ABS_HAT0X, ABS_HAT0Y, /* digital pad */ 115 -1 /* terminating entry */
116};
117
118/* only used if MAP_DPAD_TO_AXES */
119static const signed short xpad_abs_pad[] = {
120 ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */
92 -1 /* terminating entry */ 121 -1 /* terminating entry */
93}; 122};
94 123
@@ -100,14 +129,16 @@ static struct usb_device_id xpad_table [] = {
100MODULE_DEVICE_TABLE (usb, xpad_table); 129MODULE_DEVICE_TABLE (usb, xpad_table);
101 130
102struct usb_xpad { 131struct usb_xpad {
103 struct input_dev *dev; /* input device interface */ 132 struct input_dev *dev; /* input device interface */
104 struct usb_device *udev; /* usb device */ 133 struct usb_device *udev; /* usb device */
105 134
106 struct urb *irq_in; /* urb for interrupt in report */ 135 struct urb *irq_in; /* urb for interrupt in report */
107 unsigned char *idata; /* input data */ 136 unsigned char *idata; /* input data */
108 dma_addr_t idata_dma; 137 dma_addr_t idata_dma;
109 138
110 char phys[65]; /* physical device path */ 139 char phys[65]; /* physical device path */
140
141 int dpad_mapping; /* map d-pad to buttons or to axes */
111}; 142};
112 143
113/* 144/*
@@ -137,14 +168,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
137 input_report_abs(dev, ABS_RZ, data[11]); 168 input_report_abs(dev, ABS_RZ, data[11]);
138 169
139 /* digital pad */ 170 /* digital pad */
140 input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); 171 if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
141 input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); 172 input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
173 input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
174 } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
175 input_report_key(dev, BTN_LEFT, data[2] & 0x04);
176 input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
177 input_report_key(dev, BTN_0, data[2] & 0x01); // up
178 input_report_key(dev, BTN_1, data[2] & 0x02); // down
179 }
142 180
143 /* start/back buttons and stick press left/right */ 181 /* start/back buttons and stick press left/right */
144 input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); 182 input_report_key(dev, BTN_START, data[2] & 0x10);
145 input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); 183 input_report_key(dev, BTN_BACK, data[2] & 0x20);
146 input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); 184 input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
147 input_report_key(dev, BTN_THUMBR, data[2] >> 7); 185 input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
148 186
149 /* "analog" buttons A, B, X, Y */ 187 /* "analog" buttons A, B, X, Y */
150 input_report_key(dev, BTN_A, data[4]); 188 input_report_key(dev, BTN_A, data[4]);
@@ -206,6 +244,28 @@ static void xpad_close (struct input_dev *dev)
206 usb_kill_urb(xpad->irq_in); 244 usb_kill_urb(xpad->irq_in);
207} 245}
208 246
247static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
248{
249 set_bit(abs, input_dev->absbit);
250
251 switch (abs) {
252 case ABS_X:
253 case ABS_Y:
254 case ABS_RX:
255 case ABS_RY: /* the two sticks */
256 input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
257 break;
258 case ABS_Z:
259 case ABS_RZ: /* the triggers */
260 input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
261 break;
262 case ABS_HAT0X:
263 case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
264 input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
265 break;
266 }
267}
268
209static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) 269static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
210{ 270{
211 struct usb_device *udev = interface_to_usbdev (intf); 271 struct usb_device *udev = interface_to_usbdev (intf);
@@ -235,6 +295,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
235 goto fail2; 295 goto fail2;
236 296
237 xpad->udev = udev; 297 xpad->udev = udev;
298 xpad->dpad_mapping = xpad_device[i].dpad_mapping;
299 if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
300 xpad->dpad_mapping = dpad_to_buttons;
238 xpad->dev = input_dev; 301 xpad->dev = input_dev;
239 usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); 302 usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
240 strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); 303 strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
@@ -249,32 +312,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
249 312
250 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); 313 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
251 314
315 /* set up buttons */
252 for (i = 0; xpad_btn[i] >= 0; i++) 316 for (i = 0; xpad_btn[i] >= 0; i++)
253 set_bit(xpad_btn[i], input_dev->keybit); 317 set_bit(xpad_btn[i], input_dev->keybit);
318 if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
319 for (i = 0; xpad_btn_pad[i] >= 0; i++)
320 set_bit(xpad_btn_pad[i], input_dev->keybit);
254 321
255 for (i = 0; xpad_abs[i] >= 0; i++) { 322 /* set up axes */
256 323 for (i = 0; xpad_abs[i] >= 0; i++)
257 signed short t = xpad_abs[i]; 324 xpad_set_up_abs(input_dev, xpad_abs[i]);
258 325 if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
259 set_bit(t, input_dev->absbit); 326 for (i = 0; xpad_abs_pad[i] >= 0; i++)
260 327 xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
261 switch (t) {
262 case ABS_X:
263 case ABS_Y:
264 case ABS_RX:
265 case ABS_RY: /* the two sticks */
266 input_set_abs_params(input_dev, t, -32768, 32767, 16, 128);
267 break;
268 case ABS_Z:
269 case ABS_RZ: /* the triggers */
270 input_set_abs_params(input_dev, t, 0, 255, 0, 0);
271 break;
272 case ABS_HAT0X:
273 case ABS_HAT0Y: /* the d-pad */
274 input_set_abs_params(input_dev, t, -1, 1, 0, 0);
275 break;
276 }
277 }
278 328
279 ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; 329 ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
280 usb_fill_int_urb(xpad->irq_in, udev, 330 usb_fill_int_urb(xpad->irq_in, udev,
@@ -305,7 +355,8 @@ static void xpad_disconnect(struct usb_interface *intf)
305 usb_kill_urb(xpad->irq_in); 355 usb_kill_urb(xpad->irq_in);
306 input_unregister_device(xpad->dev); 356 input_unregister_device(xpad->dev);
307 usb_free_urb(xpad->irq_in); 357 usb_free_urb(xpad->irq_in);
308 usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); 358 usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN,
359 xpad->idata, xpad->idata_dma);
309 kfree(xpad); 360 kfree(xpad);
310 } 361 }
311} 362}