diff options
author | Jan Kratochvil <honza@jikos.cz> | 2007-05-09 00:27:37 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-07-10 00:35:15 -0400 |
commit | c7d9f7eb30dccf601cbdc67d5bd452f54ce90ce4 (patch) | |
tree | 0ca1ade773b9b1f6db1f49bd0c60084753eda9ef /drivers/input/joystick/xpad.c | |
parent | f836ac808f031e84d7d73a3540f30f38036bb41e (diff) |
Input: xpad - add support for Xbox 360 gamepad
Xbox 360 gamepad is slightly different then the previous model so it has
its own version of process_packet method. Detection of this new device
relies on USB_DEVICE_INTERFACE_PROTOCOL macro. This device got vendor
specific subclass so it can't be matched with USB_INTERFACE_INFO and
we need only one interface protocol from four availaible. It means
USB_DEVICE can't be used either.
Added xpad360_btn structure with additional buttons for x360 gamepad.
Added xtype into xpad_device structure to distinguish between different
types of xbox devices.
Signed-off-by: Jan Kratochvil <honza@jikos.cz>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/joystick/xpad.c')
-rw-r--r-- | drivers/input/joystick/xpad.c | 151 |
1 files changed, 117 insertions, 34 deletions
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 8c8cd95a6989..f21f84a2dfff 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * Ivan Hawkes <blackhawk@ivanhawkes.com> | 8 | * Ivan Hawkes <blackhawk@ivanhawkes.com> |
9 | * 2005 Dominic Cerquetti <binary1230@yahoo.com> | 9 | * 2005 Dominic Cerquetti <binary1230@yahoo.com> |
10 | * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> | 10 | * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> |
11 | * 2007 Jan Kratochvil <honza@jikos.cz> | ||
11 | * | 12 | * |
12 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License as | 14 | * modify it under the terms of the GNU General Public License as |
@@ -28,6 +29,7 @@ | |||
28 | * - information from http://euc.jp/periphs/xbox-controller.ja.html | 29 | * - information from http://euc.jp/periphs/xbox-controller.ja.html |
29 | * - the iForce driver drivers/char/joystick/iforce.c | 30 | * - the iForce driver drivers/char/joystick/iforce.c |
30 | * - the skeleton-driver drivers/usb/usb-skeleton.c | 31 | * - the skeleton-driver drivers/usb/usb-skeleton.c |
32 | * - Xbox 360 information http://www.free60.org/wiki/Gamepad | ||
31 | * | 33 | * |
32 | * Thanks to: | 34 | * Thanks to: |
33 | * - ITO Takayuki for providing essential xpad information on his website | 35 | * - ITO Takayuki for providing essential xpad information on his website |
@@ -88,6 +90,9 @@ | |||
88 | #define MAP_DPAD_TO_AXES 1 | 90 | #define MAP_DPAD_TO_AXES 1 |
89 | #define MAP_DPAD_UNKNOWN -1 | 91 | #define MAP_DPAD_UNKNOWN -1 |
90 | 92 | ||
93 | #define XTYPE_XBOX 0 | ||
94 | #define XTYPE_XBOX360 1 | ||
95 | |||
91 | static int dpad_to_buttons; | 96 | static int dpad_to_buttons; |
92 | module_param(dpad_to_buttons, bool, S_IRUGO); | 97 | module_param(dpad_to_buttons, bool, S_IRUGO); |
93 | MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); | 98 | MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); |
@@ -97,40 +102,42 @@ static const struct xpad_device { | |||
97 | u16 idProduct; | 102 | u16 idProduct; |
98 | char *name; | 103 | char *name; |
99 | u8 dpad_mapping; | 104 | u8 dpad_mapping; |
105 | u8 xtype; | ||
100 | } xpad_device[] = { | 106 | } xpad_device[] = { |
101 | { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES }, | 107 | { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
102 | { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES }, | 108 | { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
103 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES }, | 109 | { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
104 | { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES }, | 110 | { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
105 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS }, | 111 | { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
106 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES }, | 112 | { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
107 | { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES }, | 113 | { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
108 | { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES }, | 114 | { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
109 | { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES }, | 115 | { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
110 | { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES }, | 116 | { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
111 | { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES }, | 117 | { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
112 | { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES }, | 118 | { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
113 | { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES }, | 119 | { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
114 | { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES }, | 120 | { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
115 | { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS }, | 121 | { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
116 | { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES }, | 122 | { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
117 | { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS }, | 123 | { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
118 | { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, | 124 | { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
119 | { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, | 125 | { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
120 | { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES }, | 126 | { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
121 | { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES }, | 127 | { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
122 | { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES}, | 128 | { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
123 | { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES }, | 129 | { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
124 | { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES }, | 130 | { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
125 | { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES }, | 131 | { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
126 | { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES }, | 132 | { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
127 | { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES }, | 133 | { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
128 | { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES }, | 134 | { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
129 | { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES }, | 135 | { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
130 | { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS }, | 136 | { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
131 | { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS }, | 137 | { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, |
132 | { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES }, | 138 | { 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, |
133 | { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN } | 139 | { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, |
140 | { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN, XTYPE_XBOX } | ||
134 | }; | 141 | }; |
135 | 142 | ||
136 | static const signed short xpad_btn[] = { | 143 | static const signed short xpad_btn[] = { |
@@ -146,6 +153,12 @@ static const signed short xpad_btn_pad[] = { | |||
146 | -1 /* terminating entry */ | 153 | -1 /* terminating entry */ |
147 | }; | 154 | }; |
148 | 155 | ||
156 | static const signed short xpad360_btn[] = { /* buttons for x360 controller */ | ||
157 | BTN_TL, BTN_TR, /* Button LB/RB */ | ||
158 | BTN_MODE, /* The big X button */ | ||
159 | -1 | ||
160 | }; | ||
161 | |||
149 | static const signed short xpad_abs[] = { | 162 | static const signed short xpad_abs[] = { |
150 | ABS_X, ABS_Y, /* left stick */ | 163 | ABS_X, ABS_Y, /* left stick */ |
151 | ABS_RX, ABS_RY, /* right stick */ | 164 | ABS_RX, ABS_RY, /* right stick */ |
@@ -159,8 +172,12 @@ static const signed short xpad_abs_pad[] = { | |||
159 | -1 /* terminating entry */ | 172 | -1 /* terminating entry */ |
160 | }; | 173 | }; |
161 | 174 | ||
175 | /* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only | ||
176 | * USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols, | ||
177 | * but we need only one of them. */ | ||
162 | static struct usb_device_id xpad_table [] = { | 178 | static struct usb_device_id xpad_table [] = { |
163 | { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ | 179 | { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ |
180 | { USB_DEVICE_INTERFACE_PROTOCOL(0x045e, 0x028e, 1) }, /* X-Box 360 controller */ | ||
164 | { } | 181 | { } |
165 | }; | 182 | }; |
166 | 183 | ||
@@ -177,6 +194,7 @@ struct usb_xpad { | |||
177 | char phys[65]; /* physical device path */ | 194 | char phys[65]; /* physical device path */ |
178 | 195 | ||
179 | int dpad_mapping; /* map d-pad to buttons or to axes */ | 196 | int dpad_mapping; /* map d-pad to buttons or to axes */ |
197 | int xtype; /* type of xbox device */ | ||
180 | }; | 198 | }; |
181 | 199 | ||
182 | /* | 200 | /* |
@@ -235,6 +253,64 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d | |||
235 | input_sync(dev); | 253 | input_sync(dev); |
236 | } | 254 | } |
237 | 255 | ||
256 | /* | ||
257 | * xpad360_process_packet | ||
258 | * | ||
259 | * Completes a request by converting the data into events for the | ||
260 | * input subsystem. It is version for xbox 360 controller | ||
261 | * | ||
262 | * The used report descriptor was taken from: | ||
263 | * http://www.free60.org/wiki/Gamepad | ||
264 | */ | ||
265 | |||
266 | static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) | ||
267 | { | ||
268 | struct input_dev *dev = xpad->dev; | ||
269 | |||
270 | /* digital pad */ | ||
271 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { | ||
272 | input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x01) - !!((data[2] & 0x08) >> 3)); | ||
273 | input_report_abs(dev, ABS_HAT0Y, !!((data[2] & 0x02) >> 1) - !!((data[2] & 0x04) >> 2)); | ||
274 | } else if ( xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS ) { | ||
275 | /* dpad as buttons (right, left, down, up) */ | ||
276 | input_report_key(dev, BTN_RIGHT, (data[2] & 0x01)); | ||
277 | input_report_key(dev, BTN_LEFT, (data[2] & 0x08) >> 3); | ||
278 | input_report_key(dev, BTN_0, (data[2] & 0x02) >> 1); | ||
279 | input_report_key(dev, BTN_1, (data[2] & 0x04) >> 2); | ||
280 | } | ||
281 | |||
282 | /* start/back buttons */ | ||
283 | input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); | ||
284 | input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); | ||
285 | |||
286 | /* stick press left/right */ | ||
287 | input_report_key(dev, BTN_THUMBL, data[2] & 0x40); | ||
288 | input_report_key(dev, BTN_THUMBR, data[2] & 0x80); | ||
289 | |||
290 | /* buttons A,B,X,Y,TL,TR and MODE */ | ||
291 | input_report_key(dev, BTN_A, (data[3] & 0x10) >> 4); | ||
292 | input_report_key(dev, BTN_B, (data[3] & 0x20) >> 5); | ||
293 | input_report_key(dev, BTN_X, (data[3] & 0x40) >> 6); | ||
294 | input_report_key(dev, BTN_Y, (data[3] & 0x80) >> 7); | ||
295 | input_report_key(dev, BTN_TL, data[3] & 0x01 ); | ||
296 | input_report_key(dev, BTN_TR, (data[3] & 0x02) >> 1); | ||
297 | input_report_key(dev, BTN_MODE, (data[3] & 0x04) >> 2); | ||
298 | |||
299 | /* left stick */ | ||
300 | input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6])); | ||
301 | input_report_abs(dev, ABS_Y, ~(__s16) (((__s16)data[9] << 8) | (__s16)data[8])); | ||
302 | |||
303 | /* right stick */ | ||
304 | input_report_abs(dev, ABS_RY, ~(__s16) (((__s16)data[13] << 8) | (__s16)data[12])); | ||
305 | input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10])); | ||
306 | |||
307 | /* triggers left/right */ | ||
308 | input_report_abs(dev, ABS_Z, data[4]); | ||
309 | input_report_abs(dev, ABS_RZ, data[5]); | ||
310 | |||
311 | input_sync(dev); | ||
312 | } | ||
313 | |||
238 | static void xpad_irq_in(struct urb *urb) | 314 | static void xpad_irq_in(struct urb *urb) |
239 | { | 315 | { |
240 | struct usb_xpad *xpad = urb->context; | 316 | struct usb_xpad *xpad = urb->context; |
@@ -255,7 +331,10 @@ static void xpad_irq_in(struct urb *urb) | |||
255 | goto exit; | 331 | goto exit; |
256 | } | 332 | } |
257 | 333 | ||
258 | xpad_process_packet(xpad, 0, xpad->idata); | 334 | if (xpad->xtype == XTYPE_XBOX360) |
335 | xpad360_process_packet(xpad, 0, xpad->idata); | ||
336 | else | ||
337 | xpad_process_packet(xpad, 0, xpad->idata); | ||
259 | 338 | ||
260 | exit: | 339 | exit: |
261 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 340 | retval = usb_submit_urb (urb, GFP_ATOMIC); |
@@ -335,6 +414,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
335 | 414 | ||
336 | xpad->udev = udev; | 415 | xpad->udev = udev; |
337 | xpad->dpad_mapping = xpad_device[i].dpad_mapping; | 416 | xpad->dpad_mapping = xpad_device[i].dpad_mapping; |
417 | xpad->xtype = xpad_device[i].xtype; | ||
338 | if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) | 418 | if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) |
339 | xpad->dpad_mapping = dpad_to_buttons; | 419 | xpad->dpad_mapping = dpad_to_buttons; |
340 | xpad->dev = input_dev; | 420 | xpad->dev = input_dev; |
@@ -356,6 +436,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
356 | /* set up buttons */ | 436 | /* set up buttons */ |
357 | for (i = 0; xpad_btn[i] >= 0; i++) | 437 | for (i = 0; xpad_btn[i] >= 0; i++) |
358 | set_bit(xpad_btn[i], input_dev->keybit); | 438 | set_bit(xpad_btn[i], input_dev->keybit); |
439 | if (xpad->xtype == XTYPE_XBOX360) | ||
440 | for (i = 0; xpad360_btn[i] >= 0; i++) | ||
441 | set_bit(xpad360_btn[i], input_dev->keybit); | ||
359 | if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) | 442 | if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) |
360 | for (i = 0; xpad_btn_pad[i] >= 0; i++) | 443 | for (i = 0; xpad_btn_pad[i] >= 0; i++) |
361 | set_bit(xpad_btn_pad[i], input_dev->keybit); | 444 | set_bit(xpad_btn_pad[i], input_dev->keybit); |