Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
f0fab8e0
Commit
f0fab8e0
authored
Apr 04, 2008
by
Dmitry Torokhov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'xbox'
parents
5550fbae
6eae9b0a
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
187 additions
and
24 deletions
+187
-24
drivers/input/joystick/xpad.c
drivers/input/joystick/xpad.c
+187
-24
No files found.
drivers/input/joystick/xpad.c
View file @
f0fab8e0
/*
* X-Box gamepad
- v0.0.6
* X-Box gamepad
driver
*
* Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
* 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>,
...
...
@@ -68,6 +68,8 @@
* - dance pads will map D-PAD to buttons, not axes
* - pass the module paramater 'dpad_to_buttons' to force
* the D-PAD to map to buttons if your pad is not detected
*
* Later changes can be tracked in SCM.
*/
#include <linux/kernel.h>
...
...
@@ -77,7 +79,6 @@
#include <linux/module.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.0.6"
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
...
...
@@ -87,10 +88,12 @@
but we map them to axes when possible to simplify things */
#define MAP_DPAD_TO_BUTTONS 0
#define MAP_DPAD_TO_AXES 1
#define MAP_DPAD_UNKNOWN
-1
#define MAP_DPAD_UNKNOWN
2
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
#define XTYPE_XBOX360W 2
#define XTYPE_UNKNOWN 3
static
int
dpad_to_buttons
;
module_param
(
dpad_to_buttons
,
bool
,
S_IRUGO
);
...
...
@@ -107,8 +110,10 @@ static const struct xpad_device {
{
0x045e
,
0x0289
,
"Microsoft X-Box pad v2 (US)"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x045e
,
0x0285
,
"Microsoft X-Box pad (Japan)"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x045e
,
0x0287
,
"Microsoft Xbox Controller S"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x045e
,
0x0719
,
"Xbox 360 Wireless Receiver"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX360W
},
{
0x0c12
,
0x8809
,
"RedOctane Xbox Dance Pad"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX
},
{
0x044f
,
0x0f07
,
"Thrustmaster, Inc. Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x046d
,
0xc242
,
"Logitech Chillstream Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX360
},
{
0x046d
,
0xca84
,
"Logitech Xbox Cordless Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x046d
,
0xca88
,
"Logitech Compact Controller for Xbox"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x05fd
,
0x1007
,
"Mad Catz Controller (unverified)"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
...
...
@@ -135,18 +140,26 @@ static const struct xpad_device {
{
0x0f30
,
0x8888
,
"BigBen XBMiniPad Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x102c
,
0xff0c
,
"Joytech Wireless Advanced Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x12ab
,
0x8809
,
"Xbox DDR dancepad"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX
},
{
0x1430
,
0x4748
,
"RedOctane Guitar Hero X-plorer"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX360
},
{
0x1430
,
0x8888
,
"TX6500+ Dance Pad (first generation)"
,
MAP_DPAD_TO_BUTTONS
,
XTYPE_XBOX
},
{
0x045e
,
0x028e
,
"Microsoft X-Box 360 pad"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX360
},
{
0xffff
,
0xffff
,
"Chinese-made Xbox Controller"
,
MAP_DPAD_TO_AXES
,
XTYPE_XBOX
},
{
0x0000
,
0x0000
,
"Generic X-Box pad"
,
MAP_DPAD_UNKNOWN
,
XTYPE_
XBOX
}
{
0x0000
,
0x0000
,
"Generic X-Box pad"
,
MAP_DPAD_UNKNOWN
,
XTYPE_
UNKNOWN
}
};
static
const
signed
short
xpad_btn
[]
=
{
BTN_A
,
BTN_B
,
BTN_C
,
BTN_X
,
BTN_Y
,
BTN_Z
,
/* "analog" buttons */
/* buttons shared with xbox and xbox360 */
static
const
signed
short
xpad_common_btn
[]
=
{
BTN_A
,
BTN_B
,
BTN_X
,
BTN_Y
,
/* "analog" buttons */
BTN_START
,
BTN_BACK
,
BTN_THUMBL
,
BTN_THUMBR
,
/* start/back/sticks */
-
1
/* terminating entry */
};
/* original xbox controllers only */
static
const
signed
short
xpad_btn
[]
=
{
BTN_C
,
BTN_Z
,
/* "analog" buttons */
-
1
/* terminating entry */
};
/* only used if MAP_DPAD_TO_BUTTONS */
static
const
signed
short
xpad_btn_pad
[]
=
{
BTN_LEFT
,
BTN_RIGHT
,
/* d-pad left, right */
...
...
@@ -173,12 +186,27 @@ static const signed short xpad_abs_pad[] = {
-
1
/* terminating entry */
};
/* Xbox 360 has a vendor-specific (sub)class, so we cannot match it with only
* USB_INTERFACE_INFO, more to that this device has 4 InterfaceProtocols,
* but we need only one of them. */
/* Xbox 360 has a vendor-specific class, so we cannot match it with only
* USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
* match against vendor id as well. Wired Xbox 360 devices have protocol 1,
* wireless controllers have protocol 129. */
#define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
.idVendor = (vend), \
.bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
.bInterfaceSubClass = 93, \
.bInterfaceProtocol = (pr)
#define XPAD_XBOX360_VENDOR(vend) \
{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
{ XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
static
struct
usb_device_id
xpad_table
[]
=
{
{
USB_INTERFACE_INFO
(
'X'
,
'B'
,
0
)
},
/* X-Box USB-IF not approved class */
{
USB_DEVICE_INTERFACE_PROTOCOL
(
0x045e
,
0x028e
,
1
)
},
/* X-Box 360 controller */
XPAD_XBOX360_VENDOR
(
0x045e
),
/* Microsoft X-Box 360 controllers */
XPAD_XBOX360_VENDOR
(
0x046d
),
/* Logitech X-Box 360 style controllers */
XPAD_XBOX360_VENDOR
(
0x0738
),
/* Mad Catz X-Box 360 controllers */
XPAD_XBOX360_VENDOR
(
0x0e6f
),
/* 0x0e6f X-Box 360 controllers */
XPAD_XBOX360_VENDOR
(
0x1430
),
/* RedOctane X-Box 360 controllers */
{
}
};
...
...
@@ -188,10 +216,15 @@ struct usb_xpad {
struct
input_dev
*
dev
;
/* input device interface */
struct
usb_device
*
udev
;
/* usb device */
int
pad_present
;
struct
urb
*
irq_in
;
/* urb for interrupt in report */
unsigned
char
*
idata
;
/* input data */
dma_addr_t
idata_dma
;
struct
urb
*
bulk_out
;
unsigned
char
*
bdata
;
#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct
urb
*
irq_out
;
/* urb for interrupt out report */
unsigned
char
*
odata
;
/* output data */
...
...
@@ -227,13 +260,13 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
input_report_abs
(
dev
,
ABS_X
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
input_report_abs
(
dev
,
ABS_Y
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
14
)));
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
14
)));
/* right stick */
input_report_abs
(
dev
,
ABS_RX
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
16
)));
input_report_abs
(
dev
,
ABS_RY
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
18
)));
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
18
)));
/* triggers left/right */
input_report_abs
(
dev
,
ABS_Z
,
data
[
10
]);
...
...
@@ -321,13 +354,13 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_report_abs
(
dev
,
ABS_X
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
6
)));
input_report_abs
(
dev
,
ABS_Y
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
8
)));
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
8
)));
/* right stick */
input_report_abs
(
dev
,
ABS_RX
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
10
)));
input_report_abs
(
dev
,
ABS_RY
,
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
~
(
__s16
)
le16_to_cpup
((
__le16
*
)(
data
+
12
)));
/* triggers left/right */
input_report_abs
(
dev
,
ABS_Z
,
data
[
4
]);
...
...
@@ -336,6 +369,39 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
input_sync
(
dev
);
}
/*
* xpad360w_process_packet
*
* Completes a request by converting the data into events for the
* input subsystem. It is version for xbox 360 wireless controller.
*
* Byte.Bit
* 00.1 - Status change: The controller or headset has connected/disconnected
* Bits 01.7 and 01.6 are valid
* 01.7 - Controller present
* 01.6 - Headset present
* 01.1 - Pad state (Bytes 4+) valid
*
*/
static
void
xpad360w_process_packet
(
struct
usb_xpad
*
xpad
,
u16
cmd
,
unsigned
char
*
data
)
{
/* Presence change */
if
(
data
[
0
]
&
0x08
)
{
if
(
data
[
1
]
&
0x80
)
{
xpad
->
pad_present
=
1
;
usb_submit_urb
(
xpad
->
bulk_out
,
GFP_ATOMIC
);
}
else
xpad
->
pad_present
=
0
;
}
/* Valid pad data */
if
(
!
(
data
[
1
]
&
0x1
))
return
;
xpad360_process_packet
(
xpad
,
cmd
,
&
data
[
4
]);
}
static
void
xpad_irq_in
(
struct
urb
*
urb
)
{
struct
usb_xpad
*
xpad
=
urb
->
context
;
...
...
@@ -358,10 +424,16 @@ static void xpad_irq_in(struct urb *urb)
goto
exit
;
}
if
(
xpad
->
xtype
==
XTYPE_XBOX360
)
switch
(
xpad
->
xtype
)
{
case
XTYPE_XBOX360
:
xpad360_process_packet
(
xpad
,
0
,
xpad
->
idata
);
else
break
;
case
XTYPE_XBOX360W
:
xpad360w_process_packet
(
xpad
,
0
,
xpad
->
idata
);
break
;
default:
xpad_process_packet
(
xpad
,
0
,
xpad
->
idata
);
}
exit:
retval
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
...
...
@@ -399,6 +471,23 @@ static void xpad_irq_out(struct urb *urb)
__FUNCTION__
,
retval
);
}
static
void
xpad_bulk_out
(
struct
urb
*
urb
)
{
switch
(
urb
->
status
)
{
case
0
:
/* success */
break
;
case
-
ECONNRESET
:
case
-
ENOENT
:
case
-
ESHUTDOWN
:
/* this urb is terminated, clean up */
dbg
(
"%s - urb shutting down with status: %d"
,
__FUNCTION__
,
urb
->
status
);
break
;
default:
dbg
(
"%s - nonzero urb status received: %d"
,
__FUNCTION__
,
urb
->
status
);
}
}
static
int
xpad_init_output
(
struct
usb_interface
*
intf
,
struct
usb_xpad
*
xpad
)
{
struct
usb_endpoint_descriptor
*
ep_irq_out
;
...
...
@@ -408,7 +497,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
return
0
;
xpad
->
odata
=
usb_buffer_alloc
(
xpad
->
udev
,
XPAD_PKT_LEN
,
GFP_
ATOMIC
,
&
xpad
->
odata_dma
);
GFP_
KERNEL
,
&
xpad
->
odata_dma
);
if
(
!
xpad
->
odata
)
goto
fail1
;
...
...
@@ -477,6 +566,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data,
static
int
xpad_init_ff
(
struct
usb_xpad
*
xpad
)
{
if
(
xpad
->
xtype
!=
XTYPE_XBOX360
)
return
0
;
input_set_capability
(
xpad
->
dev
,
EV_FF
,
FF_RUMBLE
);
return
input_ff_create_memless
(
xpad
->
dev
,
NULL
,
xpad_play_effect
);
...
...
@@ -574,6 +666,10 @@ static int xpad_open(struct input_dev *dev)
{
struct
usb_xpad
*
xpad
=
input_get_drvdata
(
dev
);
/* 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
))
return
-
EIO
;
...
...
@@ -585,7 +681,8 @@ static void xpad_close(struct input_dev *dev)
{
struct
usb_xpad
*
xpad
=
input_get_drvdata
(
dev
);
usb_kill_urb
(
xpad
->
irq_in
);
if
(
xpad
->
xtype
!=
XTYPE_XBOX360W
)
usb_kill_urb
(
xpad
->
irq_in
);
xpad_stop_output
(
xpad
);
}
...
...
@@ -632,7 +729,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto
fail1
;
xpad
->
idata
=
usb_buffer_alloc
(
udev
,
XPAD_PKT_LEN
,
GFP_
ATOMIC
,
&
xpad
->
idata_dma
);
GFP_
KERNEL
,
&
xpad
->
idata_dma
);
if
(
!
xpad
->
idata
)
goto
fail1
;
...
...
@@ -644,7 +741,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad
->
dpad_mapping
=
xpad_device
[
i
].
dpad_mapping
;
xpad
->
xtype
=
xpad_device
[
i
].
xtype
;
if
(
xpad
->
dpad_mapping
==
MAP_DPAD_UNKNOWN
)
xpad
->
dpad_mapping
=
dpad_to_buttons
;
xpad
->
dpad_mapping
=
!
dpad_to_buttons
;
if
(
xpad
->
xtype
==
XTYPE_UNKNOWN
)
{
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceClass
==
USB_CLASS_VENDOR_SPEC
)
{
if
(
intf
->
cur_altsetting
->
desc
.
bInterfaceProtocol
==
129
)
xpad
->
xtype
=
XTYPE_XBOX360W
;
else
xpad
->
xtype
=
XTYPE_XBOX360
;
}
else
xpad
->
xtype
=
XTYPE_XBOX
;
}
xpad
->
dev
=
input_dev
;
usb_make_path
(
udev
,
xpad
->
phys
,
sizeof
(
xpad
->
phys
));
strlcat
(
xpad
->
phys
,
"/input0"
,
sizeof
(
xpad
->
phys
));
...
...
@@ -662,11 +768,14 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev
->
evbit
[
0
]
=
BIT_MASK
(
EV_KEY
)
|
BIT_MASK
(
EV_ABS
);
/* set up buttons */
for
(
i
=
0
;
xpad_btn
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_btn
[
i
],
input_dev
->
keybit
);
if
(
xpad
->
xtype
==
XTYPE_XBOX360
)
for
(
i
=
0
;
xpad_
common_
btn
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_
common_
btn
[
i
],
input_dev
->
keybit
);
if
(
(
xpad
->
xtype
==
XTYPE_XBOX360
)
||
(
xpad
->
xtype
==
XTYPE_XBOX360W
)
)
for
(
i
=
0
;
xpad360_btn
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad360_btn
[
i
],
input_dev
->
keybit
);
else
for
(
i
=
0
;
xpad_btn
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_btn
[
i
],
input_dev
->
keybit
);
if
(
xpad
->
dpad_mapping
==
MAP_DPAD_TO_BUTTONS
)
for
(
i
=
0
;
xpad_btn_pad
[
i
]
>=
0
;
i
++
)
set_bit
(
xpad_btn_pad
[
i
],
input_dev
->
keybit
);
...
...
@@ -703,8 +812,57 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto
fail4
;
usb_set_intfdata
(
intf
,
xpad
);
/*
* Submit the int URB immediatly rather than waiting for open
* because we get status messages from the device whether
* or not any controllers are attached. In fact, it's
* exactly the message that a controller has arrived that
* we're waiting for.
*/
if
(
xpad
->
xtype
==
XTYPE_XBOX360W
)
{
xpad
->
irq_in
->
dev
=
xpad
->
udev
;
error
=
usb_submit_urb
(
xpad
->
irq_in
,
GFP_KERNEL
);
if
(
error
)
goto
fail4
;
/*
* Setup the message to set the LEDs on the
* controller when it shows up
*/
xpad
->
bulk_out
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
if
(
!
xpad
->
bulk_out
)
goto
fail5
;
xpad
->
bdata
=
kzalloc
(
XPAD_PKT_LEN
,
GFP_KERNEL
);
if
(
!
xpad
->
bdata
)
goto
fail6
;
xpad
->
bdata
[
2
]
=
0x08
;
switch
(
intf
->
cur_altsetting
->
desc
.
bInterfaceNumber
)
{
case
0
:
xpad
->
bdata
[
3
]
=
0x42
;
break
;
case
2
:
xpad
->
bdata
[
3
]
=
0x43
;
break
;
case
4
:
xpad
->
bdata
[
3
]
=
0x44
;
break
;
case
6
:
xpad
->
bdata
[
3
]
=
0x45
;
}
ep_irq_in
=
&
intf
->
cur_altsetting
->
endpoint
[
1
].
desc
;
usb_fill_bulk_urb
(
xpad
->
bulk_out
,
udev
,
usb_sndbulkpipe
(
udev
,
ep_irq_in
->
bEndpointAddress
),
xpad
->
bdata
,
XPAD_PKT_LEN
,
xpad_bulk_out
,
xpad
);
}
return
0
;
fail6:
usb_free_urb
(
xpad
->
bulk_out
);
fail5:
usb_kill_urb
(
xpad
->
irq_in
);
fail4:
usb_free_urb
(
xpad
->
irq_in
);
fail3:
xpad_deinit_output
(
xpad
);
fail2:
usb_buffer_free
(
udev
,
XPAD_PKT_LEN
,
xpad
->
idata
,
xpad
->
idata_dma
);
...
...
@@ -723,6 +881,11 @@ static void xpad_disconnect(struct usb_interface *intf)
xpad_led_disconnect
(
xpad
);
input_unregister_device
(
xpad
->
dev
);
xpad_deinit_output
(
xpad
);
if
(
xpad
->
xtype
==
XTYPE_XBOX360W
)
{
usb_kill_urb
(
xpad
->
bulk_out
);
usb_free_urb
(
xpad
->
bulk_out
);
usb_kill_urb
(
xpad
->
irq_in
);
}
usb_free_urb
(
xpad
->
irq_in
);
usb_buffer_free
(
xpad
->
udev
,
XPAD_PKT_LEN
,
xpad
->
idata
,
xpad
->
idata_dma
);
...
...
@@ -741,7 +904,7 @@ static int __init usb_xpad_init(void)
{
int
result
=
usb_register
(
&
xpad_driver
);
if
(
result
==
0
)
info
(
DRIVER_DESC
":"
DRIVER_VERSION
);
info
(
DRIVER_DESC
);
return
result
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment