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
nexedi
linux
Commits
800f3eef
Commit
800f3eef
authored
May 02, 2017
by
Jiri Kosina
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-4.12/sony' into for-linus
parents
18fc2163
040fc001
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
876 additions
and
814 deletions
+876
-814
Documentation/input/event-codes.txt
Documentation/input/event-codes.txt
+4
-1
drivers/hid/hid-sony.c
drivers/hid/hid-sony.c
+864
-810
include/uapi/linux/input.h
include/uapi/linux/input.h
+8
-3
No files found.
Documentation/input/event-codes.txt
View file @
800f3eef
...
...
@@ -301,7 +301,10 @@ them as any other INPUT_PROP_BUTTONPAD device.
INPUT_PROP_ACCELEROMETER
-------------------------
Directional axes on this device (absolute and/or relative x, y, z) represent
accelerometer data. All other axes retain their meaning. A device must not mix
accelerometer data. Some devices also report gyroscope data, which devices
can report through the rotational axes (absolute and/or relative rx, ry, rz).
All other axes retain their meaning. A device must not mix
regular directional axes and accelerometer axes on the same event node.
Guidelines:
...
...
drivers/hid/hid-sony.c
View file @
800f3eef
...
...
@@ -48,19 +48,21 @@
#define PS3REMOTE BIT(4)
#define DUALSHOCK4_CONTROLLER_USB BIT(5)
#define DUALSHOCK4_CONTROLLER_BT BIT(6)
#define MOTION_CONTROLLER_USB BIT(7)
#define MOTION_CONTROLLER_BT BIT(8)
#define NAVIGATION_CONTROLLER_USB BIT(9)
#define NAVIGATION_CONTROLLER_BT BIT(10)
#define SINO_LITE_CONTROLLER BIT(11)
#define FUTUREMAX_DANCE_MAT BIT(12)
#define DUALSHOCK4_DONGLE BIT(7)
#define MOTION_CONTROLLER_USB BIT(8)
#define MOTION_CONTROLLER_BT BIT(9)
#define NAVIGATION_CONTROLLER_USB BIT(10)
#define NAVIGATION_CONTROLLER_BT BIT(11)
#define SINO_LITE_CONTROLLER BIT(12)
#define FUTUREMAX_DANCE_MAT BIT(13)
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
#define NAVIGATION_CONTROLLER (NAVIGATION_CONTROLLER_USB |\
NAVIGATION_CONTROLLER_BT)
#define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\
DUALSHOCK4_CONTROLLER_BT)
DUALSHOCK4_CONTROLLER_BT | \
DUALSHOCK4_DONGLE)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\
DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER |\
NAVIGATION_CONTROLLER)
...
...
@@ -73,89 +75,6 @@
#define MAX_LEDS 4
/*
* The Sixaxis reports both digital and analog values for each button on the
* controller except for Start, Select and the PS button. The controller ends
* up reporting 27 axes which causes them to spill over into the multi-touch
* axis values. Additionally, the controller only has 20 actual, physical axes
* so there are several unused axes in between the used ones.
*/
static
u8
sixaxis_rdesc
[]
=
{
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x04
,
/* Usage (Joystick), */
0xA1
,
0x01
,
/* Collection (Application), */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0x01
,
/* Report ID (1), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x01
,
/* Report Count (1), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x81
,
0x03
,
/* Input (Constant, Variable), */
0x75
,
0x01
,
/* Report Size (1), */
0x95
,
0x13
,
/* Report Count (19), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x01
,
/* Logical Maximum (1), */
0x35
,
0x00
,
/* Physical Minimum (0), */
0x45
,
0x01
,
/* Physical Maximum (1), */
0x05
,
0x09
,
/* Usage Page (Button), */
0x19
,
0x01
,
/* Usage Minimum (01h), */
0x29
,
0x13
,
/* Usage Maximum (13h), */
0x81
,
0x02
,
/* Input (Variable), */
0x75
,
0x01
,
/* Report Size (1), */
0x95
,
0x0D
,
/* Report Count (13), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x81
,
0x03
,
/* Input (Constant, Variable), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xA1
,
0x00
,
/* Collection (Physical), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x04
,
/* Report Count (4), */
0x35
,
0x00
,
/* Physical Minimum (0), */
0x46
,
0xFF
,
0x00
,
/* Physical Maximum (255), */
0x09
,
0x30
,
/* Usage (X), */
0x09
,
0x31
,
/* Usage (Y), */
0x09
,
0x32
,
/* Usage (Z), */
0x09
,
0x35
,
/* Usage (Rz), */
0x81
,
0x02
,
/* Input (Variable), */
0xC0
,
/* End Collection, */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x95
,
0x13
,
/* Report Count (19), */
0x09
,
0x01
,
/* Usage (Pointer), */
0x81
,
0x02
,
/* Input (Variable), */
0x95
,
0x0C
,
/* Report Count (12), */
0x81
,
0x01
,
/* Input (Constant), */
0x75
,
0x10
,
/* Report Size (16), */
0x95
,
0x04
,
/* Report Count (4), */
0x26
,
0xFF
,
0x03
,
/* Logical Maximum (1023), */
0x46
,
0xFF
,
0x03
,
/* Physical Maximum (1023), */
0x09
,
0x01
,
/* Usage (Pointer), */
0x81
,
0x02
,
/* Input (Variable), */
0xC0
,
/* End Collection, */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0x02
,
/* Report ID (2), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
,
/* End Collection, */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0xEE
,
/* Report ID (238), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
,
/* End Collection, */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0xEF
,
/* Report ID (239), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
,
/* End Collection, */
0xC0
/* End Collection */
};
/* PS/3 Motion controller */
static
u8
motion_rdesc
[]
=
{
...
...
@@ -254,567 +173,6 @@ static u8 motion_rdesc[] = {
0xC0
/* End Collection */
};
/* PS/3 Navigation controller */
static
u8
navigation_rdesc
[]
=
{
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x04
,
/* Usage (Joystick), */
0xA1
,
0x01
,
/* Collection (Application), */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0x01
,
/* Report ID (1), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x01
,
/* Report Count (1), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x81
,
0x03
,
/* Input (Constant, Variable), */
0x75
,
0x01
,
/* Report Size (1), */
0x95
,
0x13
,
/* Report Count (19), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x01
,
/* Logical Maximum (1), */
0x35
,
0x00
,
/* Physical Minimum (0), */
0x45
,
0x01
,
/* Physical Maximum (1), */
0x05
,
0x09
,
/* Usage Page (Button), */
0x19
,
0x01
,
/* Usage Minimum (01h), */
0x29
,
0x13
,
/* Usage Maximum (13h), */
0x81
,
0x02
,
/* Input (Variable), */
0x75
,
0x01
,
/* Report Size (1), */
0x95
,
0x0D
,
/* Report Count (13), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x81
,
0x03
,
/* Input (Constant, Variable), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xA1
,
0x00
,
/* Collection (Physical), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x02
,
/* Report Count (2), */
0x35
,
0x00
,
/* Physical Minimum (0), */
0x46
,
0xFF
,
0x00
,
/* Physical Maximum (255), */
0x09
,
0x30
,
/* Usage (X), */
0x09
,
0x31
,
/* Usage (Y), */
0x81
,
0x02
,
/* Input (Variable), */
0xC0
,
/* End Collection, */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x95
,
0x06
,
/* Report Count (6), */
0x81
,
0x03
,
/* Input (Constant, Variable), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x05
,
/* Report Count (5), */
0x09
,
0x01
,
/* Usage (Pointer), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x95
,
0x01
,
/* Report Count (1), */
0x81
,
0x02
,
/* Input (Variable), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x95
,
0x01
,
/* Report Count (1), */
0x09
,
0x01
,
/* Usage (Pointer), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x95
,
0x1E
,
/* Report Count (24), */
0x81
,
0x02
,
/* Input (Variable), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0x91
,
0x02
,
/* Output (Variable), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
,
/* End Collection, */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0x02
,
/* Report ID (2), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
,
/* End Collection, */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0xEE
,
/* Report ID (238), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
,
/* End Collection, */
0xA1
,
0x02
,
/* Collection (Logical), */
0x85
,
0xEF
,
/* Report ID (239), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x30
,
/* Report Count (48), */
0x09
,
0x01
,
/* Usage (Pointer), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
,
/* End Collection, */
0xC0
/* End Collection */
};
/*
* The default descriptor doesn't provide mapping for the accelerometers
* or orientation sensors. This fixed descriptor maps the accelerometers
* to usage values 0x40, 0x41 and 0x42 and maps the orientation sensors
* to usage values 0x43, 0x44 and 0x45.
*/
static
u8
dualshock4_usb_rdesc
[]
=
{
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x05
,
/* Usage (Gamepad), */
0xA1
,
0x01
,
/* Collection (Application), */
0x85
,
0x01
,
/* Report ID (1), */
0x09
,
0x30
,
/* Usage (X), */
0x09
,
0x31
,
/* Usage (Y), */
0x09
,
0x32
,
/* Usage (Z), */
0x09
,
0x35
,
/* Usage (Rz), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x04
,
/* Report Count (4), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x39
,
/* Usage (Hat Switch), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x07
,
/* Logical Maximum (7), */
0x35
,
0x00
,
/* Physical Minimum (0), */
0x46
,
0x3B
,
0x01
,
/* Physical Maximum (315), */
0x65
,
0x14
,
/* Unit (Degrees), */
0x75
,
0x04
,
/* Report Size (4), */
0x95
,
0x01
,
/* Report Count (1), */
0x81
,
0x42
,
/* Input (Variable, Null State), */
0x65
,
0x00
,
/* Unit, */
0x05
,
0x09
,
/* Usage Page (Button), */
0x19
,
0x01
,
/* Usage Minimum (01h), */
0x29
,
0x0D
,
/* Usage Maximum (0Dh), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x01
,
/* Logical Maximum (1), */
0x75
,
0x01
,
/* Report Size (1), */
0x95
,
0x0E
,
/* Report Count (14), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x09
,
0x20
,
/* Usage (20h), */
0x75
,
0x06
,
/* Report Size (6), */
0x95
,
0x01
,
/* Report Count (1), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x3F
,
/* Logical Maximum (63), */
0x81
,
0x02
,
/* Input (Variable), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x33
,
/* Usage (Rx), */
0x09
,
0x34
,
/* Usage (Ry), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x02
,
/* Report Count (2), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x09
,
0x21
,
/* Usage (21h), */
0x95
,
0x03
,
/* Report Count (3), */
0x81
,
0x02
,
/* Input (Variable), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x19
,
0x40
,
/* Usage Minimum (40h), */
0x29
,
0x42
,
/* Usage Maximum (42h), */
0x16
,
0x00
,
0x80
,
/* Logical Minimum (-32768), */
0x26
,
0xFF
,
0x7F
,
/* Logical Maximum (32767), */
0x75
,
0x10
,
/* Report Size (16), */
0x95
,
0x03
,
/* Report Count (3), */
0x81
,
0x02
,
/* Input (Variable), */
0x19
,
0x43
,
/* Usage Minimum (43h), */
0x29
,
0x45
,
/* Usage Maximum (45h), */
0x16
,
0x00
,
0x80
,
/* Logical Minimum (-32768), */
0x26
,
0xFF
,
0x7F
,
/* Logical Maximum (32767), */
0x95
,
0x03
,
/* Report Count (3), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x09
,
0x21
,
/* Usage (21h), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x27
,
/* Report Count (39), */
0x81
,
0x02
,
/* Input (Variable), */
0x85
,
0x05
,
/* Report ID (5), */
0x09
,
0x22
,
/* Usage (22h), */
0x95
,
0x1F
,
/* Report Count (31), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x04
,
/* Report ID (4), */
0x09
,
0x23
,
/* Usage (23h), */
0x95
,
0x24
,
/* Report Count (36), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x02
,
/* Report ID (2), */
0x09
,
0x24
,
/* Usage (24h), */
0x95
,
0x24
,
/* Report Count (36), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x08
,
/* Report ID (8), */
0x09
,
0x25
,
/* Usage (25h), */
0x95
,
0x03
,
/* Report Count (3), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x10
,
/* Report ID (16), */
0x09
,
0x26
,
/* Usage (26h), */
0x95
,
0x04
,
/* Report Count (4), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x11
,
/* Report ID (17), */
0x09
,
0x27
,
/* Usage (27h), */
0x95
,
0x02
,
/* Report Count (2), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x12
,
/* Report ID (18), */
0x06
,
0x02
,
0xFF
,
/* Usage Page (FF02h), */
0x09
,
0x21
,
/* Usage (21h), */
0x95
,
0x0F
,
/* Report Count (15), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x13
,
/* Report ID (19), */
0x09
,
0x22
,
/* Usage (22h), */
0x95
,
0x16
,
/* Report Count (22), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x14
,
/* Report ID (20), */
0x06
,
0x05
,
0xFF
,
/* Usage Page (FF05h), */
0x09
,
0x20
,
/* Usage (20h), */
0x95
,
0x10
,
/* Report Count (16), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x15
,
/* Report ID (21), */
0x09
,
0x21
,
/* Usage (21h), */
0x95
,
0x2C
,
/* Report Count (44), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x06
,
0x80
,
0xFF
,
/* Usage Page (FF80h), */
0x85
,
0x80
,
/* Report ID (128), */
0x09
,
0x20
,
/* Usage (20h), */
0x95
,
0x06
,
/* Report Count (6), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x81
,
/* Report ID (129), */
0x09
,
0x21
,
/* Usage (21h), */
0x95
,
0x06
,
/* Report Count (6), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x82
,
/* Report ID (130), */
0x09
,
0x22
,
/* Usage (22h), */
0x95
,
0x05
,
/* Report Count (5), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x83
,
/* Report ID (131), */
0x09
,
0x23
,
/* Usage (23h), */
0x95
,
0x01
,
/* Report Count (1), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x84
,
/* Report ID (132), */
0x09
,
0x24
,
/* Usage (24h), */
0x95
,
0x04
,
/* Report Count (4), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x85
,
/* Report ID (133), */
0x09
,
0x25
,
/* Usage (25h), */
0x95
,
0x06
,
/* Report Count (6), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x86
,
/* Report ID (134), */
0x09
,
0x26
,
/* Usage (26h), */
0x95
,
0x06
,
/* Report Count (6), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x87
,
/* Report ID (135), */
0x09
,
0x27
,
/* Usage (27h), */
0x95
,
0x23
,
/* Report Count (35), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x88
,
/* Report ID (136), */
0x09
,
0x28
,
/* Usage (28h), */
0x95
,
0x22
,
/* Report Count (34), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x89
,
/* Report ID (137), */
0x09
,
0x29
,
/* Usage (29h), */
0x95
,
0x02
,
/* Report Count (2), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x90
,
/* Report ID (144), */
0x09
,
0x30
,
/* Usage (30h), */
0x95
,
0x05
,
/* Report Count (5), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x91
,
/* Report ID (145), */
0x09
,
0x31
,
/* Usage (31h), */
0x95
,
0x03
,
/* Report Count (3), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x92
,
/* Report ID (146), */
0x09
,
0x32
,
/* Usage (32h), */
0x95
,
0x03
,
/* Report Count (3), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x93
,
/* Report ID (147), */
0x09
,
0x33
,
/* Usage (33h), */
0x95
,
0x0C
,
/* Report Count (12), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA0
,
/* Report ID (160), */
0x09
,
0x40
,
/* Usage (40h), */
0x95
,
0x06
,
/* Report Count (6), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA1
,
/* Report ID (161), */
0x09
,
0x41
,
/* Usage (41h), */
0x95
,
0x01
,
/* Report Count (1), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA2
,
/* Report ID (162), */
0x09
,
0x42
,
/* Usage (42h), */
0x95
,
0x01
,
/* Report Count (1), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA3
,
/* Report ID (163), */
0x09
,
0x43
,
/* Usage (43h), */
0x95
,
0x30
,
/* Report Count (48), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA4
,
/* Report ID (164), */
0x09
,
0x44
,
/* Usage (44h), */
0x95
,
0x0D
,
/* Report Count (13), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA5
,
/* Report ID (165), */
0x09
,
0x45
,
/* Usage (45h), */
0x95
,
0x15
,
/* Report Count (21), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA6
,
/* Report ID (166), */
0x09
,
0x46
,
/* Usage (46h), */
0x95
,
0x15
,
/* Report Count (21), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xF0
,
/* Report ID (240), */
0x09
,
0x47
,
/* Usage (47h), */
0x95
,
0x3F
,
/* Report Count (63), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xF1
,
/* Report ID (241), */
0x09
,
0x48
,
/* Usage (48h), */
0x95
,
0x3F
,
/* Report Count (63), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xF2
,
/* Report ID (242), */
0x09
,
0x49
,
/* Usage (49h), */
0x95
,
0x0F
,
/* Report Count (15), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA7
,
/* Report ID (167), */
0x09
,
0x4A
,
/* Usage (4Ah), */
0x95
,
0x01
,
/* Report Count (1), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA8
,
/* Report ID (168), */
0x09
,
0x4B
,
/* Usage (4Bh), */
0x95
,
0x01
,
/* Report Count (1), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA9
,
/* Report ID (169), */
0x09
,
0x4C
,
/* Usage (4Ch), */
0x95
,
0x08
,
/* Report Count (8), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xAA
,
/* Report ID (170), */
0x09
,
0x4E
,
/* Usage (4Eh), */
0x95
,
0x01
,
/* Report Count (1), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xAB
,
/* Report ID (171), */
0x09
,
0x4F
,
/* Usage (4Fh), */
0x95
,
0x39
,
/* Report Count (57), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xAC
,
/* Report ID (172), */
0x09
,
0x50
,
/* Usage (50h), */
0x95
,
0x39
,
/* Report Count (57), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xAD
,
/* Report ID (173), */
0x09
,
0x51
,
/* Usage (51h), */
0x95
,
0x0B
,
/* Report Count (11), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xAE
,
/* Report ID (174), */
0x09
,
0x52
,
/* Usage (52h), */
0x95
,
0x01
,
/* Report Count (1), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xAF
,
/* Report ID (175), */
0x09
,
0x53
,
/* Usage (53h), */
0x95
,
0x02
,
/* Report Count (2), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xB0
,
/* Report ID (176), */
0x09
,
0x54
,
/* Usage (54h), */
0x95
,
0x3F
,
/* Report Count (63), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
/* End Collection */
};
/*
* The default behavior of the Dualshock 4 is to send reports using report
* type 1 when running over Bluetooth. However, when feature report 2 is
* requested during the controller initialization it starts sending input
* reports in report 17. Since report 17 is undefined in the default HID
* descriptor the button and axis definitions must be moved to report 17 or
* the HID layer won't process the received input.
*/
static
u8
dualshock4_bt_rdesc
[]
=
{
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x05
,
/* Usage (Gamepad), */
0xA1
,
0x01
,
/* Collection (Application), */
0x85
,
0x01
,
/* Report ID (1), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x0A
,
/* Report Count (9), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x04
,
0xFF
,
/* Usage Page (FF04h), */
0x85
,
0x02
,
/* Report ID (2), */
0x09
,
0x24
,
/* Usage (24h), */
0x95
,
0x24
,
/* Report Count (36), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA3
,
/* Report ID (163), */
0x09
,
0x25
,
/* Usage (25h), */
0x95
,
0x30
,
/* Report Count (48), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x05
,
/* Report ID (5), */
0x09
,
0x26
,
/* Usage (26h), */
0x95
,
0x28
,
/* Report Count (40), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x06
,
/* Report ID (6), */
0x09
,
0x27
,
/* Usage (27h), */
0x95
,
0x34
,
/* Report Count (52), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x07
,
/* Report ID (7), */
0x09
,
0x28
,
/* Usage (28h), */
0x95
,
0x30
,
/* Report Count (48), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x08
,
/* Report ID (8), */
0x09
,
0x29
,
/* Usage (29h), */
0x95
,
0x2F
,
/* Report Count (47), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x06
,
0x03
,
0xFF
,
/* Usage Page (FF03h), */
0x85
,
0x03
,
/* Report ID (3), */
0x09
,
0x21
,
/* Usage (21h), */
0x95
,
0x26
,
/* Report Count (38), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x04
,
/* Report ID (4), */
0x09
,
0x22
,
/* Usage (22h), */
0x95
,
0x2E
,
/* Report Count (46), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xF0
,
/* Report ID (240), */
0x09
,
0x47
,
/* Usage (47h), */
0x95
,
0x3F
,
/* Report Count (63), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xF1
,
/* Report ID (241), */
0x09
,
0x48
,
/* Usage (48h), */
0x95
,
0x3F
,
/* Report Count (63), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xF2
,
/* Report ID (242), */
0x09
,
0x49
,
/* Usage (49h), */
0x95
,
0x0F
,
/* Report Count (15), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x11
,
/* Report ID (17), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x09
,
0x20
,
/* Usage (20h), */
0x95
,
0x02
,
/* Report Count (2), */
0x81
,
0x02
,
/* Input (Variable), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x30
,
/* Usage (X), */
0x09
,
0x31
,
/* Usage (Y), */
0x09
,
0x32
,
/* Usage (Z), */
0x09
,
0x35
,
/* Usage (Rz), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x04
,
/* Report Count (4), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x39
,
/* Usage (Hat Switch), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x07
,
/* Logical Maximum (7), */
0x75
,
0x04
,
/* Report Size (4), */
0x95
,
0x01
,
/* Report Count (1), */
0x81
,
0x42
,
/* Input (Variable, Null State), */
0x05
,
0x09
,
/* Usage Page (Button), */
0x19
,
0x01
,
/* Usage Minimum (01h), */
0x29
,
0x0D
,
/* Usage Maximum (0Dh), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x25
,
0x01
,
/* Logical Maximum (1), */
0x75
,
0x01
,
/* Report Size (1), */
0x95
,
0x0E
,
/* Report Count (14), */
0x81
,
0x02
,
/* Input (Variable), */
0x75
,
0x06
,
/* Report Size (6), */
0x95
,
0x01
,
/* Report Count (1), */
0x81
,
0x01
,
/* Input (Constant), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x09
,
0x33
,
/* Usage (Rx), */
0x09
,
0x34
,
/* Usage (Ry), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x02
,
/* Report Count (2), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x09
,
0x20
,
/* Usage (20h), */
0x95
,
0x03
,
/* Report Count (3), */
0x81
,
0x02
,
/* Input (Variable), */
0x05
,
0x01
,
/* Usage Page (Desktop), */
0x19
,
0x40
,
/* Usage Minimum (40h), */
0x29
,
0x42
,
/* Usage Maximum (42h), */
0x16
,
0x00
,
0x80
,
/* Logical Minimum (-32768), */
0x26
,
0xFF
,
0x7F
,
/* Logical Maximum (32767), */
0x75
,
0x10
,
/* Report Size (16), */
0x95
,
0x03
,
/* Report Count (3), */
0x81
,
0x02
,
/* Input (Variable), */
0x19
,
0x43
,
/* Usage Minimum (43h), */
0x29
,
0x45
,
/* Usage Maximum (45h), */
0x16
,
0x00
,
0x80
,
/* Logical Minimum (-32768), */
0x26
,
0xFF
,
0x7F
,
/* Logical Maximum (32767), */
0x95
,
0x03
,
/* Report Count (3), */
0x81
,
0x02
,
/* Input (Variable), */
0x06
,
0x00
,
0xFF
,
/* Usage Page (FF00h), */
0x09
,
0x20
,
/* Usage (20h), */
0x15
,
0x00
,
/* Logical Minimum (0), */
0x26
,
0xFF
,
0x00
,
/* Logical Maximum (255), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x31
,
/* Report Count (51), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x21
,
/* Usage (21h), */
0x75
,
0x08
,
/* Report Size (8), */
0x95
,
0x4D
,
/* Report Count (77), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x12
,
/* Report ID (18), */
0x09
,
0x22
,
/* Usage (22h), */
0x95
,
0x8D
,
/* Report Count (141), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x23
,
/* Usage (23h), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x13
,
/* Report ID (19), */
0x09
,
0x24
,
/* Usage (24h), */
0x95
,
0xCD
,
/* Report Count (205), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x25
,
/* Usage (25h), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x14
,
/* Report ID (20), */
0x09
,
0x26
,
/* Usage (26h), */
0x96
,
0x0D
,
0x01
,
/* Report Count (269), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x27
,
/* Usage (27h), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x15
,
/* Report ID (21), */
0x09
,
0x28
,
/* Usage (28h), */
0x96
,
0x4D
,
0x01
,
/* Report Count (333), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x29
,
/* Usage (29h), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x16
,
/* Report ID (22), */
0x09
,
0x2A
,
/* Usage (2Ah), */
0x96
,
0x8D
,
0x01
,
/* Report Count (397), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x2B
,
/* Usage (2Bh), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x17
,
/* Report ID (23), */
0x09
,
0x2C
,
/* Usage (2Ch), */
0x96
,
0xCD
,
0x01
,
/* Report Count (461), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x2D
,
/* Usage (2Dh), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x18
,
/* Report ID (24), */
0x09
,
0x2E
,
/* Usage (2Eh), */
0x96
,
0x0D
,
0x02
,
/* Report Count (525), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x2F
,
/* Usage (2Fh), */
0x91
,
0x02
,
/* Output (Variable), */
0x85
,
0x19
,
/* Report ID (25), */
0x09
,
0x30
,
/* Usage (30h), */
0x96
,
0x22
,
0x02
,
/* Report Count (546), */
0x81
,
0x02
,
/* Input (Variable), */
0x09
,
0x31
,
/* Usage (31h), */
0x91
,
0x02
,
/* Output (Variable), */
0x06
,
0x80
,
0xFF
,
/* Usage Page (FF80h), */
0x85
,
0x82
,
/* Report ID (130), */
0x09
,
0x22
,
/* Usage (22h), */
0x95
,
0x3F
,
/* Report Count (63), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x83
,
/* Report ID (131), */
0x09
,
0x23
,
/* Usage (23h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x84
,
/* Report ID (132), */
0x09
,
0x24
,
/* Usage (24h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x90
,
/* Report ID (144), */
0x09
,
0x30
,
/* Usage (30h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x91
,
/* Report ID (145), */
0x09
,
0x31
,
/* Usage (31h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x92
,
/* Report ID (146), */
0x09
,
0x32
,
/* Usage (32h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0x93
,
/* Report ID (147), */
0x09
,
0x33
,
/* Usage (33h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA0
,
/* Report ID (160), */
0x09
,
0x40
,
/* Usage (40h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0x85
,
0xA4
,
/* Report ID (164), */
0x09
,
0x44
,
/* Usage (44h), */
0xB1
,
0x02
,
/* Feature (Variable), */
0xC0
/* End Collection */
};
static
u8
ps3remote_rdesc
[]
=
{
0x05
,
0x01
,
/* GUsagePage Generic Desktop */
0x09
,
0x05
,
/* LUsage 0x05 [Game Pad] */
...
...
@@ -977,6 +335,67 @@ static const unsigned int buzz_keymap[] = {
[
20
]
=
BTN_TRIGGER_HAPPY20
,
};
/* The Navigation controller is a partial DS3 and uses the same HID report
* and hence the same keymap indices, however not not all axes/buttons
* are physically present. We use the same axis and button mapping as
* the DS3, which uses the Linux gamepad spec.
*/
static
const
unsigned
int
navigation_absmap
[]
=
{
[
0x30
]
=
ABS_X
,
[
0x31
]
=
ABS_Y
,
[
0x33
]
=
ABS_Z
,
/* L2 */
};
/* Buttons not physically available on the device, but still available
* in the reports are explicitly set to 0 for documentation purposes.
*/
static
const
unsigned
int
navigation_keymap
[]
=
{
[
0x01
]
=
0
,
/* Select */
[
0x02
]
=
BTN_THUMBL
,
/* L3 */
[
0x03
]
=
0
,
/* R3 */
[
0x04
]
=
0
,
/* Start */
[
0x05
]
=
BTN_DPAD_UP
,
/* Up */
[
0x06
]
=
BTN_DPAD_RIGHT
,
/* Right */
[
0x07
]
=
BTN_DPAD_DOWN
,
/* Down */
[
0x08
]
=
BTN_DPAD_LEFT
,
/* Left */
[
0x09
]
=
BTN_TL2
,
/* L2 */
[
0x0a
]
=
0
,
/* R2 */
[
0x0b
]
=
BTN_TL
,
/* L1 */
[
0x0c
]
=
0
,
/* R1 */
[
0x0d
]
=
BTN_NORTH
,
/* Triangle */
[
0x0e
]
=
BTN_EAST
,
/* Circle */
[
0x0f
]
=
BTN_SOUTH
,
/* Cross */
[
0x10
]
=
BTN_WEST
,
/* Square */
[
0x11
]
=
BTN_MODE
,
/* PS */
};
static
const
unsigned
int
sixaxis_absmap
[]
=
{
[
0x30
]
=
ABS_X
,
[
0x31
]
=
ABS_Y
,
[
0x32
]
=
ABS_RX
,
/* right stick X */
[
0x35
]
=
ABS_RY
,
/* right stick Y */
};
static
const
unsigned
int
sixaxis_keymap
[]
=
{
[
0x01
]
=
BTN_SELECT
,
/* Select */
[
0x02
]
=
BTN_THUMBL
,
/* L3 */
[
0x03
]
=
BTN_THUMBR
,
/* R3 */
[
0x04
]
=
BTN_START
,
/* Start */
[
0x05
]
=
BTN_DPAD_UP
,
/* Up */
[
0x06
]
=
BTN_DPAD_RIGHT
,
/* Right */
[
0x07
]
=
BTN_DPAD_DOWN
,
/* Down */
[
0x08
]
=
BTN_DPAD_LEFT
,
/* Left */
[
0x09
]
=
BTN_TL2
,
/* L2 */
[
0x0a
]
=
BTN_TR2
,
/* R2 */
[
0x0b
]
=
BTN_TL
,
/* L1 */
[
0x0c
]
=
BTN_TR
,
/* R1 */
[
0x0d
]
=
BTN_NORTH
,
/* Triangle */
[
0x0e
]
=
BTN_EAST
,
/* Circle */
[
0x0f
]
=
BTN_SOUTH
,
/* Cross */
[
0x10
]
=
BTN_WEST
,
/* Square */
[
0x11
]
=
BTN_MODE
,
/* PS */
};
static
const
unsigned
int
ds4_absmap
[]
=
{
[
0x30
]
=
ABS_X
,
[
0x31
]
=
ABS_Y
,
...
...
@@ -1002,6 +421,10 @@ static const unsigned int ds4_keymap[] = {
[
0xd
]
=
BTN_MODE
,
/* PS */
};
static
const
struct
{
int
x
;
int
y
;
}
ds4_hat_mapping
[]
=
{
{
0
,
-
1
},
{
1
,
-
1
},
{
1
,
0
},
{
1
,
1
},
{
0
,
1
},
{
-
1
,
1
},
{
-
1
,
0
},
{
-
1
,
-
1
},
{
0
,
0
}
};
static
enum
power_supply_property
sony_battery_props
[]
=
{
POWER_SUPPLY_PROP_PRESENT
,
...
...
@@ -1048,6 +471,7 @@ struct motion_output_report_02 {
};
#define DS4_FEATURE_REPORT_0x02_SIZE 37
#define DS4_FEATURE_REPORT_0x05_SIZE 41
#define DS4_FEATURE_REPORT_0x81_SIZE 7
#define DS4_INPUT_REPORT_0x11_SIZE 78
#define DS4_OUTPUT_REPORT_0x05_SIZE 32
...
...
@@ -1059,23 +483,62 @@ struct motion_output_report_02 {
/* Offsets relative to USB input report (0x1). Bluetooth (0x11) requires an
* additional +2.
*/
#define DS4_INPUT_REPORT_AXIS_OFFSET 1
#define DS4_INPUT_REPORT_BUTTON_OFFSET 5
#define DS4_INPUT_REPORT_TIMESTAMP_OFFSET 10
#define DS4_INPUT_REPORT_GYRO_X_OFFSET 13
#define DS4_INPUT_REPORT_BATTERY_OFFSET 30
#define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33
#define SENSOR_SUFFIX " Motion Sensors"
#define DS4_TOUCHPAD_SUFFIX " Touchpad"
/* Default to 4ms poll interval, which is same as USB (not adjustable). */
#define DS4_BT_DEFAULT_POLL_INTERVAL_MS 4
#define DS4_BT_MAX_POLL_INTERVAL_MS 62
#define DS4_GYRO_RES_PER_DEG_S 1024
#define DS4_ACC_RES_PER_G 8192
#define SIXAXIS_INPUT_REPORT_ACC_X_OFFSET 41
#define SIXAXIS_ACC_RES_PER_G 113
static
DEFINE_SPINLOCK
(
sony_dev_list_lock
);
static
LIST_HEAD
(
sony_device_list
);
static
DEFINE_IDA
(
sony_device_id_allocator
);
/* Used for calibration of DS4 accelerometer and gyro. */
struct
ds4_calibration_data
{
int
abs_code
;
short
bias
;
/* Calibration requires scaling against a sensitivity value, which is a
* float. Store sensitivity as a fraction to limit floating point
* calculations until final calibration.
*/
int
sens_numer
;
int
sens_denom
;
};
enum
ds4_dongle_state
{
DONGLE_DISCONNECTED
,
DONGLE_CALIBRATING
,
DONGLE_CONNECTED
,
DONGLE_DISABLED
};
enum
sony_worker
{
SONY_WORKER_STATE
,
SONY_WORKER_HOTPLUG
};
struct
sony_sc
{
spinlock_t
lock
;
struct
list_head
list_node
;
struct
hid_device
*
hdev
;
struct
input_dev
*
touchpad
;
struct
input_dev
*
sensor_dev
;
struct
led_classdev
*
leds
[
MAX_LEDS
];
unsigned
long
quirks
;
struct
work_struct
hotplug_worker
;
struct
work_struct
state_worker
;
void
(
*
send_output_report
)(
struct
sony_sc
*
);
struct
power_supply
*
battery
;
...
...
@@ -1089,46 +552,87 @@ struct sony_sc {
#endif
u8
mac_address
[
6
];
u8
worker_initialized
;
u8
hotplug_worker_initialized
;
u8
state_worker_initialized
;
u8
defer_initialization
;
u8
cable_state
;
u8
battery_charging
;
u8
battery_capacity
;
u8
led_state
[
MAX_LEDS
];
u8
resume_led_state
[
MAX_LEDS
];
u8
led_delay_on
[
MAX_LEDS
];
u8
led_delay_off
[
MAX_LEDS
];
u8
led_count
;
bool
ds4_dongle_connected
;
bool
timestamp_initialized
;
u16
prev_timestamp
;
unsigned
int
timestamp_us
;
u8
ds4_bt_poll_interval
;
enum
ds4_dongle_state
ds4_dongle_state
;
/* DS4 calibration data */
struct
ds4_calibration_data
ds4_calib_data
[
6
];
};
static
void
sony_set_leds
(
struct
sony_sc
*
sc
);
static
inline
void
sony_schedule_work
(
struct
sony_sc
*
sc
)
static
inline
void
sony_schedule_work
(
struct
sony_sc
*
sc
,
enum
sony_worker
which
)
{
if
(
!
sc
->
defer_initialization
)
schedule_work
(
&
sc
->
state_worker
);
switch
(
which
)
{
case
SONY_WORKER_STATE
:
if
(
!
sc
->
defer_initialization
)
schedule_work
(
&
sc
->
state_worker
);
break
;
case
SONY_WORKER_HOTPLUG
:
if
(
sc
->
hotplug_worker_initialized
)
schedule_work
(
&
sc
->
hotplug_worker
);
break
;
}
}
static
u8
*
sixaxis_fixup
(
struct
hid_device
*
hdev
,
u8
*
rdesc
,
unsigned
int
*
rsize
)
static
ssize_t
ds4_show_poll_interval
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
*
rsize
=
sizeof
(
sixaxis_rdesc
);
return
sixaxis_rdesc
;
struct
hid_device
*
hdev
=
to_hid_device
(
dev
);
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
return
snprintf
(
buf
,
PAGE_SIZE
,
"%i
\n
"
,
sc
->
ds4_bt_poll_interval
);
}
static
u8
*
motion_fixup
(
struct
hid_device
*
hdev
,
u8
*
rdesc
,
unsigned
int
*
rsize
)
static
ssize_t
ds4_store_poll_interval
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
*
rsize
=
sizeof
(
motion_rdesc
);
return
motion_rdesc
;
struct
hid_device
*
hdev
=
to_hid_device
(
dev
);
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
unsigned
long
flags
;
u8
interval
;
if
(
kstrtou8
(
buf
,
0
,
&
interval
))
return
-
EINVAL
;
if
(
interval
>
DS4_BT_MAX_POLL_INTERVAL_MS
)
return
-
EINVAL
;
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
sc
->
ds4_bt_poll_interval
=
interval
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
sony_schedule_work
(
sc
,
SONY_WORKER_STATE
);
return
count
;
}
static
u8
*
navigation_fixup
(
struct
hid_device
*
hdev
,
u8
*
rdesc
,
static
DEVICE_ATTR
(
bt_poll_interval
,
0644
,
ds4_show_poll_interval
,
ds4_store_poll_interval
);
static
u8
*
motion_fixup
(
struct
hid_device
*
hdev
,
u8
*
rdesc
,
unsigned
int
*
rsize
)
{
*
rsize
=
sizeof
(
naviga
tion_rdesc
);
return
naviga
tion_rdesc
;
*
rsize
=
sizeof
(
mo
tion_rdesc
);
return
mo
tion_rdesc
;
}
static
u8
*
ps3remote_fixup
(
struct
hid_device
*
hdev
,
u8
*
rdesc
,
...
...
@@ -1172,6 +676,102 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
return
1
;
}
static
int
navigation_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
{
if
((
usage
->
hid
&
HID_USAGE_PAGE
)
==
HID_UP_BUTTON
)
{
unsigned
int
key
=
usage
->
hid
&
HID_USAGE
;
if
(
key
>=
ARRAY_SIZE
(
sixaxis_keymap
))
return
-
1
;
key
=
navigation_keymap
[
key
];
if
(
!
key
)
return
-
1
;
hid_map_usage_clear
(
hi
,
usage
,
bit
,
max
,
EV_KEY
,
key
);
return
1
;
}
else
if
(
usage
->
hid
==
HID_GD_POINTER
)
{
/* See comment in sixaxis_mapping, basically the L2 (and R2)
* triggers are reported through GD Pointer.
* In addition we ignore any analog button 'axes' and only
* support digital buttons.
*/
switch
(
usage
->
usage_index
)
{
case
8
:
/* L2 */
usage
->
hid
=
HID_GD_Z
;
break
;
default:
return
-
1
;
}
hid_map_usage_clear
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
usage
->
hid
&
0xf
);
return
1
;
}
else
if
((
usage
->
hid
&
HID_USAGE_PAGE
)
==
HID_UP_GENDESK
)
{
unsigned
int
abs
=
usage
->
hid
&
HID_USAGE
;
if
(
abs
>=
ARRAY_SIZE
(
navigation_absmap
))
return
-
1
;
abs
=
navigation_absmap
[
abs
];
hid_map_usage_clear
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
abs
);
return
1
;
}
return
-
1
;
}
static
int
sixaxis_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
{
if
((
usage
->
hid
&
HID_USAGE_PAGE
)
==
HID_UP_BUTTON
)
{
unsigned
int
key
=
usage
->
hid
&
HID_USAGE
;
if
(
key
>=
ARRAY_SIZE
(
sixaxis_keymap
))
return
-
1
;
key
=
sixaxis_keymap
[
key
];
hid_map_usage_clear
(
hi
,
usage
,
bit
,
max
,
EV_KEY
,
key
);
return
1
;
}
else
if
(
usage
->
hid
==
HID_GD_POINTER
)
{
/* The DS3 provides analog values for most buttons and even
* for HAT axes through GD Pointer. L2 and R2 are reported
* among these as well instead of as GD Z / RZ. Remap L2
* and R2 and ignore other analog 'button axes' as there is
* no good way for reporting them.
*/
switch
(
usage
->
usage_index
)
{
case
8
:
/* L2 */
usage
->
hid
=
HID_GD_Z
;
break
;
case
9
:
/* R2 */
usage
->
hid
=
HID_GD_RZ
;
break
;
default:
return
-
1
;
}
hid_map_usage_clear
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
usage
->
hid
&
0xf
);
return
1
;
}
else
if
((
usage
->
hid
&
HID_USAGE_PAGE
)
==
HID_UP_GENDESK
)
{
unsigned
int
abs
=
usage
->
hid
&
HID_USAGE
;
if
(
abs
>=
ARRAY_SIZE
(
sixaxis_absmap
))
return
-
1
;
abs
=
sixaxis_absmap
[
abs
];
hid_map_usage_clear
(
hi
,
usage
,
bit
,
max
,
EV_ABS
,
abs
);
return
1
;
}
return
-
1
;
}
static
int
ds4_mapping
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hi
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
unsigned
long
**
bit
,
int
*
max
)
...
...
@@ -1227,30 +827,9 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
rdesc
[
55
]
=
0x06
;
}
/*
* The default Dualshock 4 USB descriptor doesn't assign
* the gyroscope values to corresponding axes so we need a
* modified one.
*/
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
{
hid_info
(
hdev
,
"Using modified Dualshock 4 report descriptor with gyroscope axes
\n
"
);
rdesc
=
dualshock4_usb_rdesc
;
*
rsize
=
sizeof
(
dualshock4_usb_rdesc
);
}
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
{
hid_info
(
hdev
,
"Using modified Dualshock 4 Bluetooth report descriptor
\n
"
);
rdesc
=
dualshock4_bt_rdesc
;
*
rsize
=
sizeof
(
dualshock4_bt_rdesc
);
}
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER
)
return
sixaxis_fixup
(
hdev
,
rdesc
,
rsize
);
if
(
sc
->
quirks
&
MOTION_CONTROLLER
)
return
motion_fixup
(
hdev
,
rdesc
,
rsize
);
if
(
sc
->
quirks
&
NAVIGATION_CONTROLLER
)
return
navigation_fixup
(
hdev
,
rdesc
,
rsize
);
if
(
sc
->
quirks
&
PS3REMOTE
)
return
ps3remote_fixup
(
hdev
,
rdesc
,
rsize
);
...
...
@@ -1288,21 +867,131 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size)
sc
->
battery_capacity
=
battery_capacity
;
sc
->
battery_charging
=
battery_charging
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER
)
{
int
val
;
offset
=
SIXAXIS_INPUT_REPORT_ACC_X_OFFSET
;
val
=
((
rd
[
offset
+
1
]
<<
8
)
|
rd
[
offset
])
-
511
;
input_report_abs
(
sc
->
sensor_dev
,
ABS_X
,
val
);
/* Y and Z are swapped and inversed */
val
=
511
-
((
rd
[
offset
+
5
]
<<
8
)
|
rd
[
offset
+
4
]);
input_report_abs
(
sc
->
sensor_dev
,
ABS_Y
,
val
);
val
=
511
-
((
rd
[
offset
+
3
]
<<
8
)
|
rd
[
offset
+
2
]);
input_report_abs
(
sc
->
sensor_dev
,
ABS_Z
,
val
);
input_sync
(
sc
->
sensor_dev
);
}
}
static
void
dualshock4_parse_report
(
struct
sony_sc
*
sc
,
u8
*
rd
,
int
size
)
{
struct
hid_input
*
hidinput
=
list_entry
(
sc
->
hdev
->
inputs
.
next
,
struct
hid_input
,
list
);
struct
input_dev
*
input_dev
=
hidinput
->
input
;
unsigned
long
flags
;
int
n
,
m
,
offset
,
num_touch_data
,
max_touch_data
;
u8
cable_state
,
battery_capacity
,
battery_charging
;
u16
timestamp
;
/* When using Bluetooth the header is 2 bytes longer, so skip these. */
int
data_offset
=
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_
USB
)
?
0
:
2
;
int
data_offset
=
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_
BT
)
?
2
:
0
;
/* Second bit of third button byte is for the touchpad button. */
offset
=
data_offset
+
DS4_INPUT_REPORT_BUTTON_OFFSET
;
input_report_key
(
sc
->
touchpad
,
BTN_LEFT
,
rd
[
offset
+
2
]
&
0x2
);
/*
* The default behavior of the Dualshock 4 is to send reports using
* report type 1 when running over Bluetooth. However, when feature
* report 2 is requested during the controller initialization it starts
* sending input reports in report 17. Since report 17 is undefined
* in the default HID descriptor, the HID layer won't generate events.
* While it is possible (and this was done before) to fixup the HID
* descriptor to add this mapping, it was better to do this manually.
* The reason is there were various pieces software both open and closed
* source, relying on the descriptors to be the same across various
* operating systems. If the descriptors wouldn't match some
* applications e.g. games on Wine would not be able to function due
* to different descriptors, which such applications are not parsing.
*/
if
(
rd
[
0
]
==
17
)
{
int
value
;
offset
=
data_offset
+
DS4_INPUT_REPORT_AXIS_OFFSET
;
input_report_abs
(
input_dev
,
ABS_X
,
rd
[
offset
]);
input_report_abs
(
input_dev
,
ABS_Y
,
rd
[
offset
+
1
]);
input_report_abs
(
input_dev
,
ABS_RX
,
rd
[
offset
+
2
]);
input_report_abs
(
input_dev
,
ABS_RY
,
rd
[
offset
+
3
]);
value
=
rd
[
offset
+
4
]
&
0xf
;
if
(
value
>
7
)
value
=
8
;
/* Center 0, 0 */
input_report_abs
(
input_dev
,
ABS_HAT0X
,
ds4_hat_mapping
[
value
].
x
);
input_report_abs
(
input_dev
,
ABS_HAT0Y
,
ds4_hat_mapping
[
value
].
y
);
input_report_key
(
input_dev
,
BTN_WEST
,
rd
[
offset
+
4
]
&
0x10
);
input_report_key
(
input_dev
,
BTN_SOUTH
,
rd
[
offset
+
4
]
&
0x20
);
input_report_key
(
input_dev
,
BTN_EAST
,
rd
[
offset
+
4
]
&
0x40
);
input_report_key
(
input_dev
,
BTN_NORTH
,
rd
[
offset
+
4
]
&
0x80
);
input_report_key
(
input_dev
,
BTN_TL
,
rd
[
offset
+
5
]
&
0x1
);
input_report_key
(
input_dev
,
BTN_TR
,
rd
[
offset
+
5
]
&
0x2
);
input_report_key
(
input_dev
,
BTN_TL2
,
rd
[
offset
+
5
]
&
0x4
);
input_report_key
(
input_dev
,
BTN_TR2
,
rd
[
offset
+
5
]
&
0x8
);
input_report_key
(
input_dev
,
BTN_SELECT
,
rd
[
offset
+
5
]
&
0x10
);
input_report_key
(
input_dev
,
BTN_START
,
rd
[
offset
+
5
]
&
0x20
);
input_report_key
(
input_dev
,
BTN_THUMBL
,
rd
[
offset
+
5
]
&
0x40
);
input_report_key
(
input_dev
,
BTN_THUMBR
,
rd
[
offset
+
5
]
&
0x80
);
input_report_key
(
input_dev
,
BTN_MODE
,
rd
[
offset
+
6
]
&
0x1
);
input_report_abs
(
input_dev
,
ABS_Z
,
rd
[
offset
+
7
]);
input_report_abs
(
input_dev
,
ABS_RZ
,
rd
[
offset
+
8
]);
input_sync
(
input_dev
);
}
/* Convert timestamp (in 5.33us unit) to timestamp_us */
offset
=
data_offset
+
DS4_INPUT_REPORT_TIMESTAMP_OFFSET
;
timestamp
=
get_unaligned_le16
(
&
rd
[
offset
]);
if
(
!
sc
->
timestamp_initialized
)
{
sc
->
timestamp_us
=
((
unsigned
int
)
timestamp
*
16
)
/
3
;
sc
->
timestamp_initialized
=
true
;
}
else
{
u16
delta
;
if
(
sc
->
prev_timestamp
>
timestamp
)
delta
=
(
U16_MAX
-
sc
->
prev_timestamp
+
timestamp
+
1
);
else
delta
=
timestamp
-
sc
->
prev_timestamp
;
sc
->
timestamp_us
+=
(
delta
*
16
)
/
3
;
}
sc
->
prev_timestamp
=
timestamp
;
input_event
(
sc
->
sensor_dev
,
EV_MSC
,
MSC_TIMESTAMP
,
sc
->
timestamp_us
);
offset
=
data_offset
+
DS4_INPUT_REPORT_GYRO_X_OFFSET
;
for
(
n
=
0
;
n
<
6
;
n
++
)
{
/* Store data in int for more precision during mult_frac. */
int
raw_data
=
(
short
)((
rd
[
offset
+
1
]
<<
8
)
|
rd
[
offset
]);
struct
ds4_calibration_data
*
calib
=
&
sc
->
ds4_calib_data
[
n
];
/* High precision is needed during calibration, but the
* calibrated values are within 32-bit.
* Note: we swap numerator 'x' and 'numer' in mult_frac for
* precision reasons so we don't need 64-bit.
*/
int
calib_data
=
mult_frac
(
calib
->
sens_numer
,
raw_data
-
calib
->
bias
,
calib
->
sens_denom
);
input_report_abs
(
sc
->
sensor_dev
,
calib
->
abs_code
,
calib_data
);
offset
+=
2
;
}
input_sync
(
sc
->
sensor_dev
);
/*
* The lower 4 bits of byte 30 (or 32 for BT) contain the battery level
* and the 5th bit contains the USB cable state.
...
...
@@ -1341,7 +1030,7 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
* Trackpad data starts 2 bytes later (e.g. 35 for USB).
*/
offset
=
data_offset
+
DS4_INPUT_REPORT_TOUCHPAD_OFFSET
;
max_touch_data
=
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_
USB
)
?
3
:
4
;
max_touch_data
=
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_
BT
)
?
4
:
3
;
if
(
rd
[
offset
]
>
0
&&
rd
[
offset
]
<=
max_touch_data
)
num_touch_data
=
rd
[
offset
];
else
...
...
@@ -1415,47 +1104,79 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
}
else
if
((
sc
->
quirks
&
NAVIGATION_CONTROLLER
)
&&
rd
[
0
]
==
0x01
&&
size
==
49
)
{
sixaxis_parse_report
(
sc
,
rd
,
size
);
}
else
if
(((
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
&&
rd
[
0
]
==
0x01
&&
size
==
64
)
||
((
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
&&
rd
[
0
]
==
0x11
&&
size
==
78
))
{
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
{
/* CRC check */
u8
bthdr
=
0xA1
;
u32
crc
;
u32
report_crc
;
}
else
if
((
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
&&
rd
[
0
]
==
0x01
&&
size
==
64
)
{
dualshock4_parse_report
(
sc
,
rd
,
size
);
}
else
if
(((
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
&&
rd
[
0
]
==
0x11
&&
size
==
78
))
{
/* CRC check */
u8
bthdr
=
0xA1
;
u32
crc
;
u32
report_crc
;
crc
=
crc32_le
(
0xFFFFFFFF
,
&
bthdr
,
1
);
crc
=
~
crc32_le
(
crc
,
rd
,
DS4_INPUT_REPORT_0x11_SIZE
-
4
);
report_crc
=
get_unaligned_le32
(
&
rd
[
DS4_INPUT_REPORT_0x11_SIZE
-
4
]);
if
(
crc
!=
report_crc
)
{
hid_dbg
(
sc
->
hdev
,
"DualShock 4 input report's CRC check failed, received crc 0x%0x != 0x%0x
\n
"
,
report_crc
,
crc
);
return
-
EILSEQ
;
}
crc
=
crc32_le
(
0xFFFFFFFF
,
&
bthdr
,
1
);
crc
=
~
crc32_le
(
crc
,
rd
,
DS4_INPUT_REPORT_0x11_SIZE
-
4
);
report_crc
=
get_unaligned_le32
(
&
rd
[
DS4_INPUT_REPORT_0x11_SIZE
-
4
]);
if
(
crc
!=
report_crc
)
{
hid_dbg
(
sc
->
hdev
,
"DualShock 4 input report's CRC check failed, received crc 0x%0x != 0x%0x
\n
"
,
report_crc
,
crc
);
return
-
EILSEQ
;
}
dualshock4_parse_report
(
sc
,
rd
,
size
);
}
else
if
((
sc
->
quirks
&
DUALSHOCK4_DONGLE
)
&&
rd
[
0
]
==
0x01
&&
size
==
64
)
{
unsigned
long
flags
;
enum
ds4_dongle_state
dongle_state
;
/*
* In the case of a DS4 USB dongle, bit[2] of byte 31 indicates
* if a DS4 is actually connected (indicated by '0').
* For non-dongle, this bit is always 0 (connected).
*/
if
(
sc
->
hdev
->
vendor
==
USB_VENDOR_ID_SONY
&&
sc
->
hdev
->
product
==
USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE
)
{
bool
connected
=
(
rd
[
31
]
&
0x04
)
?
false
:
true
;
if
(
!
sc
->
ds4_dongle_connected
&&
connected
)
{
hid_info
(
sc
->
hdev
,
"DualShock 4 USB dongle: controller connected
\n
"
);
sony_set_leds
(
sc
);
sc
->
ds4_dongle_connected
=
true
;
}
else
if
(
sc
->
ds4_dongle_connected
&&
!
connected
)
{
hid_info
(
sc
->
hdev
,
"DualShock 4 USB dongle: controller disconnected
\n
"
);
sc
->
ds4_dongle_connected
=
false
;
/* Return 0, so hidraw can get the report. */
return
0
;
}
else
if
(
!
sc
->
ds4_dongle_connected
)
{
/* Return 0, so hidraw can get the report. */
return
0
;
}
bool
connected
=
(
rd
[
31
]
&
0x04
)
?
false
:
true
;
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
dongle_state
=
sc
->
ds4_dongle_state
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
/*
* The dongle always sends input reports even when no
* DS4 is attached. When a DS4 is connected, we need to
* obtain calibration data before we can use it.
* The code below tracks dongle state and kicks of
* calibration when needed and only allows us to process
* input if a DS4 is actually connected.
*/
if
(
dongle_state
==
DONGLE_DISCONNECTED
&&
connected
)
{
hid_info
(
sc
->
hdev
,
"DualShock 4 USB dongle: controller connected
\n
"
);
sony_set_leds
(
sc
);
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
sc
->
ds4_dongle_state
=
DONGLE_CALIBRATING
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
sony_schedule_work
(
sc
,
SONY_WORKER_HOTPLUG
);
/* Don't process the report since we don't have
* calibration data, but let hidraw have it anyway.
*/
return
0
;
}
else
if
((
dongle_state
==
DONGLE_CONNECTED
||
dongle_state
==
DONGLE_DISABLED
)
&&
!
connected
)
{
hid_info
(
sc
->
hdev
,
"DualShock 4 USB dongle: controller disconnected
\n
"
);
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
sc
->
ds4_dongle_state
=
DONGLE_DISCONNECTED
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
/* Return 0, so hidraw can get the report. */
return
0
;
}
else
if
(
dongle_state
==
DONGLE_CALIBRATING
||
dongle_state
==
DONGLE_DISABLED
||
dongle_state
==
DONGLE_DISCONNECTED
)
{
/* Return 0, so hidraw can get the report. */
return
0
;
}
dualshock4_parse_report
(
sc
,
rd
,
size
);
...
...
@@ -1463,7 +1184,7 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
if
(
sc
->
defer_initialization
)
{
sc
->
defer_initialization
=
0
;
sony_schedule_work
(
sc
);
sony_schedule_work
(
sc
,
SONY_WORKER_STATE
);
}
return
0
;
...
...
@@ -1501,10 +1222,16 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
if
(
sc
->
quirks
&
PS3REMOTE
)
return
ps3remote_mapping
(
hdev
,
hi
,
field
,
usage
,
bit
,
max
);
if
(
sc
->
quirks
&
NAVIGATION_CONTROLLER
)
return
navigation_mapping
(
hdev
,
hi
,
field
,
usage
,
bit
,
max
);
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER
)
return
sixaxis_mapping
(
hdev
,
hi
,
field
,
usage
,
bit
,
max
);
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER
)
return
ds4_mapping
(
hdev
,
hi
,
field
,
usage
,
bit
,
max
);
/* Let hid-core decide for the others */
return
0
;
}
...
...
@@ -1541,7 +1268,7 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
snprintf
(
name
,
name_sz
,
"%s"
DS4_TOUCHPAD_SUFFIX
,
sc
->
hdev
->
name
);
sc
->
touchpad
->
name
=
name
;
ret
=
input_mt_init_slots
(
sc
->
touchpad
,
touch_count
,
0
);
ret
=
input_mt_init_slots
(
sc
->
touchpad
,
touch_count
,
INPUT_MT_POINTER
);
if
(
ret
<
0
)
goto
err
;
...
...
@@ -1581,6 +1308,103 @@ static void sony_unregister_touchpad(struct sony_sc *sc)
sc
->
touchpad
=
NULL
;
}
static
int
sony_register_sensors
(
struct
sony_sc
*
sc
)
{
size_t
name_sz
;
char
*
name
;
int
ret
;
int
range
;
sc
->
sensor_dev
=
input_allocate_device
();
if
(
!
sc
->
sensor_dev
)
return
-
ENOMEM
;
input_set_drvdata
(
sc
->
sensor_dev
,
sc
);
sc
->
sensor_dev
->
dev
.
parent
=
&
sc
->
hdev
->
dev
;
sc
->
sensor_dev
->
phys
=
sc
->
hdev
->
phys
;
sc
->
sensor_dev
->
uniq
=
sc
->
hdev
->
uniq
;
sc
->
sensor_dev
->
id
.
bustype
=
sc
->
hdev
->
bus
;
sc
->
sensor_dev
->
id
.
vendor
=
sc
->
hdev
->
vendor
;
sc
->
sensor_dev
->
id
.
product
=
sc
->
hdev
->
product
;
sc
->
sensor_dev
->
id
.
version
=
sc
->
hdev
->
version
;
/* Append a suffix to the controller name as there are various
* DS4 compatible non-Sony devices with different names.
*/
name_sz
=
strlen
(
sc
->
hdev
->
name
)
+
sizeof
(
SENSOR_SUFFIX
);
name
=
kzalloc
(
name_sz
,
GFP_KERNEL
);
if
(
!
name
)
{
ret
=
-
ENOMEM
;
goto
err
;
}
snprintf
(
name
,
name_sz
,
"%s"
SENSOR_SUFFIX
,
sc
->
hdev
->
name
);
sc
->
sensor_dev
->
name
=
name
;
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER
)
{
/* For the DS3 we only support the accelerometer, which works
* quite well even without calibration. The device also has
* a 1-axis gyro, but it is very difficult to manage from within
* the driver even to get data, the sensor is inaccurate and
* the behavior is very different between hardware revisions.
*/
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_X
,
-
512
,
511
,
4
,
0
);
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_Y
,
-
512
,
511
,
4
,
0
);
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_Z
,
-
512
,
511
,
4
,
0
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_X
,
SIXAXIS_ACC_RES_PER_G
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_Y
,
SIXAXIS_ACC_RES_PER_G
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_Z
,
SIXAXIS_ACC_RES_PER_G
);
}
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER
)
{
range
=
DS4_ACC_RES_PER_G
*
4
;
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_X
,
-
range
,
range
,
16
,
0
);
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_Y
,
-
range
,
range
,
16
,
0
);
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_Z
,
-
range
,
range
,
16
,
0
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_X
,
DS4_ACC_RES_PER_G
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_Y
,
DS4_ACC_RES_PER_G
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_Z
,
DS4_ACC_RES_PER_G
);
range
=
DS4_GYRO_RES_PER_DEG_S
*
2048
;
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_RX
,
-
range
,
range
,
16
,
0
);
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_RY
,
-
range
,
range
,
16
,
0
);
input_set_abs_params
(
sc
->
sensor_dev
,
ABS_RZ
,
-
range
,
range
,
16
,
0
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_RX
,
DS4_GYRO_RES_PER_DEG_S
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_RY
,
DS4_GYRO_RES_PER_DEG_S
);
input_abs_set_res
(
sc
->
sensor_dev
,
ABS_RZ
,
DS4_GYRO_RES_PER_DEG_S
);
__set_bit
(
EV_MSC
,
sc
->
sensor_dev
->
evbit
);
__set_bit
(
MSC_TIMESTAMP
,
sc
->
sensor_dev
->
mscbit
);
}
__set_bit
(
INPUT_PROP_ACCELEROMETER
,
sc
->
sensor_dev
->
propbit
);
ret
=
input_register_device
(
sc
->
sensor_dev
);
if
(
ret
<
0
)
goto
err
;
return
0
;
err:
kfree
(
sc
->
sensor_dev
->
name
);
sc
->
sensor_dev
->
name
=
NULL
;
input_free_device
(
sc
->
sensor_dev
);
sc
->
sensor_dev
=
NULL
;
return
ret
;
}
static
void
sony_unregister_sensors
(
struct
sony_sc
*
sc
)
{
if
(
!
sc
->
sensor_dev
)
return
;
kfree
(
sc
->
sensor_dev
->
name
);
sc
->
sensor_dev
->
name
=
NULL
;
input_unregister_device
(
sc
->
sensor_dev
);
sc
->
sensor_dev
=
NULL
;
}
/*
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to "operational". Without this, the ps3 controller will not report any
...
...
@@ -1646,26 +1470,176 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
}
/*
* Request
ing feature report 0x02 in Bluetooth mode changes the state of the
*
controller so that it sends full input reports of type 0x11
.
* Request
DS4 calibration data for the motion sensors.
*
For Bluetooth this also affects the operating mode (see below)
.
*/
static
int
dualshock4_
set_operational_bt
(
struct
hid_device
*
hdev
)
static
int
dualshock4_
get_calibration_data
(
struct
sony_sc
*
sc
)
{
u8
*
buf
;
int
ret
;
short
gyro_pitch_bias
,
gyro_pitch_plus
,
gyro_pitch_minus
;
short
gyro_yaw_bias
,
gyro_yaw_plus
,
gyro_yaw_minus
;
short
gyro_roll_bias
,
gyro_roll_plus
,
gyro_roll_minus
;
short
gyro_speed_plus
,
gyro_speed_minus
;
short
acc_x_plus
,
acc_x_minus
;
short
acc_y_plus
,
acc_y_minus
;
short
acc_z_plus
,
acc_z_minus
;
int
speed_2x
;
int
range_2g
;
/* For Bluetooth we use a different request, which supports CRC.
* Note: in Bluetooth mode feature report 0x02 also changes the state
* of the controller, so that it sends input reports of type 0x11.
*/
if
(
sc
->
quirks
&
(
DUALSHOCK4_CONTROLLER_USB
|
DUALSHOCK4_DONGLE
))
{
buf
=
kmalloc
(
DS4_FEATURE_REPORT_0x02_SIZE
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
buf
=
kmalloc
(
DS4_FEATURE_REPORT_0x02_SIZE
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
ret
=
hid_hw_raw_request
(
sc
->
hdev
,
0x02
,
buf
,
DS4_FEATURE_REPORT_0x02_SIZE
,
HID_FEATURE_REPORT
,
HID_REQ_GET_REPORT
);
if
(
ret
<
0
)
goto
err_stop
;
}
else
{
u8
bthdr
=
0xA3
;
u32
crc
;
u32
report_crc
;
int
retries
;
buf
=
kmalloc
(
DS4_FEATURE_REPORT_0x05_SIZE
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
ret
=
hid_hw_raw_request
(
hdev
,
0x02
,
buf
,
DS4_FEATURE_REPORT_0x02_SIZE
,
HID_FEATURE_REPORT
,
HID_REQ_GET_REPORT
);
for
(
retries
=
0
;
retries
<
3
;
retries
++
)
{
ret
=
hid_hw_raw_request
(
sc
->
hdev
,
0x05
,
buf
,
DS4_FEATURE_REPORT_0x05_SIZE
,
HID_FEATURE_REPORT
,
HID_REQ_GET_REPORT
);
if
(
ret
<
0
)
goto
err_stop
;
kfree
(
buf
);
/* CRC check */
crc
=
crc32_le
(
0xFFFFFFFF
,
&
bthdr
,
1
);
crc
=
~
crc32_le
(
crc
,
buf
,
DS4_FEATURE_REPORT_0x05_SIZE
-
4
);
report_crc
=
get_unaligned_le32
(
&
buf
[
DS4_FEATURE_REPORT_0x05_SIZE
-
4
]);
if
(
crc
!=
report_crc
)
{
hid_warn
(
sc
->
hdev
,
"DualShock 4 calibration report's CRC check failed, received crc 0x%0x != 0x%0x
\n
"
,
report_crc
,
crc
);
if
(
retries
<
2
)
{
hid_warn
(
sc
->
hdev
,
"Retrying DualShock 4 get calibration report request
\n
"
);
continue
;
}
else
{
ret
=
-
EILSEQ
;
goto
err_stop
;
}
}
else
{
break
;
}
}
}
gyro_pitch_bias
=
get_unaligned_le16
(
&
buf
[
1
]);
gyro_yaw_bias
=
get_unaligned_le16
(
&
buf
[
3
]);
gyro_roll_bias
=
get_unaligned_le16
(
&
buf
[
5
]);
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
{
gyro_pitch_plus
=
get_unaligned_le16
(
&
buf
[
7
]);
gyro_pitch_minus
=
get_unaligned_le16
(
&
buf
[
9
]);
gyro_yaw_plus
=
get_unaligned_le16
(
&
buf
[
11
]);
gyro_yaw_minus
=
get_unaligned_le16
(
&
buf
[
13
]);
gyro_roll_plus
=
get_unaligned_le16
(
&
buf
[
15
]);
gyro_roll_minus
=
get_unaligned_le16
(
&
buf
[
17
]);
}
else
{
/* BT + Dongle */
gyro_pitch_plus
=
get_unaligned_le16
(
&
buf
[
7
]);
gyro_yaw_plus
=
get_unaligned_le16
(
&
buf
[
9
]);
gyro_roll_plus
=
get_unaligned_le16
(
&
buf
[
11
]);
gyro_pitch_minus
=
get_unaligned_le16
(
&
buf
[
13
]);
gyro_yaw_minus
=
get_unaligned_le16
(
&
buf
[
15
]);
gyro_roll_minus
=
get_unaligned_le16
(
&
buf
[
17
]);
}
gyro_speed_plus
=
get_unaligned_le16
(
&
buf
[
19
]);
gyro_speed_minus
=
get_unaligned_le16
(
&
buf
[
21
]);
acc_x_plus
=
get_unaligned_le16
(
&
buf
[
23
]);
acc_x_minus
=
get_unaligned_le16
(
&
buf
[
25
]);
acc_y_plus
=
get_unaligned_le16
(
&
buf
[
27
]);
acc_y_minus
=
get_unaligned_le16
(
&
buf
[
29
]);
acc_z_plus
=
get_unaligned_le16
(
&
buf
[
31
]);
acc_z_minus
=
get_unaligned_le16
(
&
buf
[
33
]);
/* Set gyroscope calibration and normalization parameters.
* Data values will be normalized to 1/DS4_GYRO_RES_PER_DEG_S degree/s.
*/
speed_2x
=
(
gyro_speed_plus
+
gyro_speed_minus
);
sc
->
ds4_calib_data
[
0
].
abs_code
=
ABS_RX
;
sc
->
ds4_calib_data
[
0
].
bias
=
gyro_pitch_bias
;
sc
->
ds4_calib_data
[
0
].
sens_numer
=
speed_2x
*
DS4_GYRO_RES_PER_DEG_S
;
sc
->
ds4_calib_data
[
0
].
sens_denom
=
gyro_pitch_plus
-
gyro_pitch_minus
;
sc
->
ds4_calib_data
[
1
].
abs_code
=
ABS_RY
;
sc
->
ds4_calib_data
[
1
].
bias
=
gyro_yaw_bias
;
sc
->
ds4_calib_data
[
1
].
sens_numer
=
speed_2x
*
DS4_GYRO_RES_PER_DEG_S
;
sc
->
ds4_calib_data
[
1
].
sens_denom
=
gyro_yaw_plus
-
gyro_yaw_minus
;
sc
->
ds4_calib_data
[
2
].
abs_code
=
ABS_RZ
;
sc
->
ds4_calib_data
[
2
].
bias
=
gyro_roll_bias
;
sc
->
ds4_calib_data
[
2
].
sens_numer
=
speed_2x
*
DS4_GYRO_RES_PER_DEG_S
;
sc
->
ds4_calib_data
[
2
].
sens_denom
=
gyro_roll_plus
-
gyro_roll_minus
;
/* Set accelerometer calibration and normalization parameters.
* Data values will be normalized to 1/DS4_ACC_RES_PER_G G.
*/
range_2g
=
acc_x_plus
-
acc_x_minus
;
sc
->
ds4_calib_data
[
3
].
abs_code
=
ABS_X
;
sc
->
ds4_calib_data
[
3
].
bias
=
acc_x_plus
-
range_2g
/
2
;
sc
->
ds4_calib_data
[
3
].
sens_numer
=
2
*
DS4_ACC_RES_PER_G
;
sc
->
ds4_calib_data
[
3
].
sens_denom
=
range_2g
;
range_2g
=
acc_y_plus
-
acc_y_minus
;
sc
->
ds4_calib_data
[
4
].
abs_code
=
ABS_Y
;
sc
->
ds4_calib_data
[
4
].
bias
=
acc_y_plus
-
range_2g
/
2
;
sc
->
ds4_calib_data
[
4
].
sens_numer
=
2
*
DS4_ACC_RES_PER_G
;
sc
->
ds4_calib_data
[
4
].
sens_denom
=
range_2g
;
range_2g
=
acc_z_plus
-
acc_z_minus
;
sc
->
ds4_calib_data
[
5
].
abs_code
=
ABS_Z
;
sc
->
ds4_calib_data
[
5
].
bias
=
acc_z_plus
-
range_2g
/
2
;
sc
->
ds4_calib_data
[
5
].
sens_numer
=
2
*
DS4_ACC_RES_PER_G
;
sc
->
ds4_calib_data
[
5
].
sens_denom
=
range_2g
;
err_stop:
kfree
(
buf
);
return
ret
;
}
static
void
dualshock4_calibration_work
(
struct
work_struct
*
work
)
{
struct
sony_sc
*
sc
=
container_of
(
work
,
struct
sony_sc
,
hotplug_worker
);
unsigned
long
flags
;
enum
ds4_dongle_state
dongle_state
;
int
ret
;
ret
=
dualshock4_get_calibration_data
(
sc
);
if
(
ret
<
0
)
{
/* This call is very unlikely to fail for the dongle. When it
* fails we are probably in a very bad state, so mark the
* dongle as disabled. We will re-enable the dongle if a new
* DS4 hotplug is detect from sony_raw_event as any issues
* are likely resolved then (the dongle is quite stupid).
*/
hid_err
(
sc
->
hdev
,
"DualShock 4 USB dongle: calibration failed, disabling device
\n
"
);
dongle_state
=
DONGLE_DISABLED
;
}
else
{
hid_info
(
sc
->
hdev
,
"DualShock 4 USB dongle: calibration completed
\n
"
);
dongle_state
=
DONGLE_CONNECTED
;
}
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
sc
->
ds4_dongle_state
=
dongle_state
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
}
static
void
sixaxis_set_leds_from_id
(
struct
sony_sc
*
sc
)
{
static
const
u8
sixaxis_leds
[
10
][
4
]
=
{
...
...
@@ -1696,10 +1670,10 @@ static void dualshock4_set_leds_from_id(struct sony_sc *sc)
{
/* The first 4 color/index entries match what the PS4 assigns */
static
const
u8
color_code
[
7
][
3
]
=
{
/* Blue */
{
0x00
,
0x00
,
0x
01
},
/* Red */
{
0x
01
,
0x00
,
0x00
},
/* Green */
{
0x00
,
0x
01
,
0x00
},
/* Pink */
{
0x
02
,
0x00
,
0x01
},
/* Blue */
{
0x00
,
0x00
,
0x
40
},
/* Red */
{
0x
40
,
0x00
,
0x00
},
/* Green */
{
0x00
,
0x
40
,
0x00
},
/* Pink */
{
0x
20
,
0x00
,
0x20
},
/* Orange */
{
0x02
,
0x01
,
0x00
},
/* Teal */
{
0x00
,
0x01
,
0x01
},
/* White */
{
0x01
,
0x01
,
0x01
}
...
...
@@ -1740,7 +1714,7 @@ static void buzz_set_leds(struct sony_sc *sc)
static
void
sony_set_leds
(
struct
sony_sc
*
sc
)
{
if
(
!
(
sc
->
quirks
&
BUZZ_CONTROLLER
))
sony_schedule_work
(
sc
);
sony_schedule_work
(
sc
,
SONY_WORKER_STATE
);
else
buzz_set_leds
(
sc
);
}
...
...
@@ -1851,7 +1825,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
new_off
!=
drv_data
->
led_delay_off
[
n
])
{
drv_data
->
led_delay_on
[
n
]
=
new_on
;
drv_data
->
led_delay_off
[
n
]
=
new_off
;
sony_schedule_work
(
drv_data
);
sony_schedule_work
(
drv_data
,
SONY_WORKER_STATE
);
}
return
0
;
...
...
@@ -1964,6 +1938,7 @@ static int sony_leds_init(struct sony_sc *sc)
led
->
name
=
name
;
led
->
brightness
=
sc
->
led_state
[
n
];
led
->
max_brightness
=
max_brightness
[
n
];
led
->
flags
=
LED_CORE_SUSPENDRESUME
;
led
->
brightness_get
=
sony_led_get_brightness
;
led
->
brightness_set
=
sony_led_set_brightness
;
...
...
@@ -2052,26 +2027,24 @@ static void dualshock4_send_output_report(struct sony_sc *sc)
int
offset
;
/*
* NOTE: The buf[1] field of the Bluetooth report controls
* the Dualshock 4 reporting rate.
*
* Known values include:
*
* 0x80 - 1000hz (full speed)
* 0xA0 - 31hz
* 0xB0 - 20hz
* 0xD0 - 66hz
* NOTE: The lower 6 bits of buf[1] field of the Bluetooth report
* control the interval at which Dualshock 4 reports data:
* 0x00 - 1ms
* 0x01 - 1ms
* 0x02 - 2ms
* 0x3E - 62ms
* 0x3F - disabled
*/
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
{
if
(
sc
->
quirks
&
(
DUALSHOCK4_CONTROLLER_USB
|
DUALSHOCK4_DONGLE
)
)
{
memset
(
buf
,
0
,
DS4_OUTPUT_REPORT_0x05_SIZE
);
buf
[
0
]
=
0x05
;
buf
[
1
]
=
0x
FF
;
buf
[
1
]
=
0x
07
;
/* blink + LEDs + motor */
offset
=
4
;
}
else
{
memset
(
buf
,
0
,
DS4_OUTPUT_REPORT_0x11_SIZE
);
buf
[
0
]
=
0x11
;
buf
[
1
]
=
0xC0
;
/* HID + CRC */
buf
[
3
]
=
0x0
F
;
buf
[
1
]
=
0xC0
/* HID + CRC */
|
sc
->
ds4_bt_poll_interval
;
buf
[
3
]
=
0x0
7
;
/* blink + LEDs + motor */
offset
=
6
;
}
...
...
@@ -2095,7 +2068,7 @@ static void dualshock4_send_output_report(struct sony_sc *sc)
buf
[
offset
++
]
=
sc
->
led_delay_on
[
3
];
buf
[
offset
++
]
=
sc
->
led_delay_off
[
3
];
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
if
(
sc
->
quirks
&
(
DUALSHOCK4_CONTROLLER_USB
|
DUALSHOCK4_DONGLE
)
)
hid_hw_output_report
(
hdev
,
buf
,
DS4_OUTPUT_REPORT_0x05_SIZE
);
else
{
/* CRC generation */
...
...
@@ -2152,7 +2125,7 @@ static int sony_allocate_output_report(struct sony_sc *sc)
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
sc
->
output_report_dmabuf
=
kmalloc
(
DS4_OUTPUT_REPORT_0x11_SIZE
,
GFP_KERNEL
);
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
else
if
(
sc
->
quirks
&
(
DUALSHOCK4_CONTROLLER_USB
|
DUALSHOCK4_DONGLE
)
)
sc
->
output_report_dmabuf
=
kmalloc
(
DS4_OUTPUT_REPORT_0x05_SIZE
,
GFP_KERNEL
);
else
if
(
sc
->
quirks
&
MOTION_CONTROLLER
)
...
...
@@ -2180,7 +2153,7 @@ static int sony_play_effect(struct input_dev *dev, void *data,
sc
->
left
=
effect
->
u
.
rumble
.
strong_magnitude
/
256
;
sc
->
right
=
effect
->
u
.
rumble
.
weak_magnitude
/
256
;
sony_schedule_work
(
sc
);
sony_schedule_work
(
sc
,
SONY_WORKER_STATE
);
return
0
;
}
...
...
@@ -2397,7 +2370,7 @@ static int sony_check_add(struct sony_sc *sc)
hid_warn
(
sc
->
hdev
,
"UNIQ does not contain a MAC address; duplicate check skipped
\n
"
);
return
0
;
}
}
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
{
}
else
if
(
sc
->
quirks
&
(
DUALSHOCK4_CONTROLLER_USB
|
DUALSHOCK4_DONGLE
)
)
{
buf
=
kmalloc
(
DS4_FEATURE_REPORT_0x81_SIZE
,
GFP_KERNEL
);
if
(
!
buf
)
return
-
ENOMEM
;
...
...
@@ -2451,6 +2424,12 @@ static int sony_check_add(struct sony_sc *sc)
*/
for
(
n
=
0
;
n
<
6
;
n
++
)
sc
->
mac_address
[
5
-
n
]
=
buf
[
4
+
n
];
snprintf
(
sc
->
hdev
->
uniq
,
sizeof
(
sc
->
hdev
->
uniq
),
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
,
sc
->
mac_address
[
5
],
sc
->
mac_address
[
4
],
sc
->
mac_address
[
3
],
sc
->
mac_address
[
2
],
sc
->
mac_address
[
1
],
sc
->
mac_address
[
0
]);
}
else
{
return
0
;
}
...
...
@@ -2501,18 +2480,21 @@ static inline void sony_init_output_report(struct sony_sc *sc,
{
sc
->
send_output_report
=
send_output_report
;
if
(
!
sc
->
worker_initialized
)
if
(
!
sc
->
state_
worker_initialized
)
INIT_WORK
(
&
sc
->
state_worker
,
sony_state_worker
);
sc
->
worker_initialized
=
1
;
sc
->
state_
worker_initialized
=
1
;
}
static
inline
void
sony_cancel_work_sync
(
struct
sony_sc
*
sc
)
{
if
(
sc
->
worker_initialized
)
if
(
sc
->
hotplug_worker_initialized
)
cancel_work_sync
(
&
sc
->
hotplug_worker
);
if
(
sc
->
state_worker_initialized
)
cancel_work_sync
(
&
sc
->
state_worker
);
}
static
int
sony_input_configured
(
struct
hid_device
*
hdev
,
struct
hid_input
*
hidinput
)
{
...
...
@@ -2526,14 +2508,17 @@ static int sony_input_configured(struct hid_device *hdev,
goto
err_stop
;
}
ret
=
append_dev_id
=
sony_check_add
(
sc
);
if
(
ret
<
0
)
goto
err_stop
;
ret
=
sony_allocate_output_report
(
sc
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"failed to allocate the output report buffer
\n
"
);
goto
err_stop
;
}
if
((
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
||
(
sc
->
quirks
&
NAVIGATION_CONTROLLER_USB
))
{
if
(
sc
->
quirks
&
NAVIGATION_CONTROLLER_USB
)
{
/*
* The Sony Sixaxis does not handle HID Output Reports on the
* Interrupt EP like it could, so we need to force HID Output
...
...
@@ -2553,24 +2538,79 @@ static int sony_input_configured(struct hid_device *hdev,
hdev
->
quirks
|=
HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP
;
hdev
->
quirks
|=
HID_QUIRK_SKIP_OUTPUT_REPORT_ID
;
sc
->
defer_initialization
=
1
;
ret
=
sixaxis_set_operational_usb
(
hdev
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"Failed to set controller into operational mode
\n
"
);
goto
err_stop
;
}
sony_init_output_report
(
sc
,
sixaxis_send_output_report
);
}
else
if
(
sc
->
quirks
&
NAVIGATION_CONTROLLER_BT
)
{
/*
* The Navigation controller wants output reports sent on the ctrl
* endpoint when connected via Bluetooth.
*/
hdev
->
quirks
|=
HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP
;
ret
=
sixaxis_set_operational_bt
(
hdev
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"Failed to set controller into operational mode
\n
"
);
goto
err_stop
;
}
sony_init_output_report
(
sc
,
sixaxis_send_output_report
);
}
else
if
((
sc
->
quirks
&
SIXAXIS_CONTROLLER_BT
)
||
(
sc
->
quirks
&
NAVIGATION_CONTROLLER_BT
))
{
}
else
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
{
/*
* The Sony Sixaxis does not handle HID Output Reports on the
* Interrupt EP and the device only becomes active when the
* PS button is pressed. See comment for Navigation controller
* above for more details.
*/
hdev
->
quirks
|=
HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP
;
hdev
->
quirks
|=
HID_QUIRK_SKIP_OUTPUT_REPORT_ID
;
sc
->
defer_initialization
=
1
;
ret
=
sixaxis_set_operational_usb
(
hdev
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"Failed to set controller into operational mode
\n
"
);
goto
err_stop
;
}
ret
=
sony_register_sensors
(
sc
);
if
(
ret
)
{
hid_err
(
sc
->
hdev
,
"Unable to initialize motion sensors: %d
\n
"
,
ret
);
goto
err_stop
;
}
sony_init_output_report
(
sc
,
sixaxis_send_output_report
);
}
else
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_BT
)
{
/*
* The Sixaxis wants output reports sent on the ctrl endpoint
* when connected via Bluetooth.
*/
hdev
->
quirks
|=
HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP
;
ret
=
sixaxis_set_operational_bt
(
hdev
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"Failed to set controller into operational mode
\n
"
);
goto
err_stop
;
}
ret
=
sony_register_sensors
(
sc
);
if
(
ret
)
{
hid_err
(
sc
->
hdev
,
"Unable to initialize motion sensors: %d
\n
"
,
ret
);
goto
err_stop
;
}
sony_init_output_report
(
sc
,
sixaxis_send_output_report
);
}
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER
)
{
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
{
ret
=
dualshock4_set_operational_bt
(
hdev
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"failed to set the Dualshock 4 operational mode
\n
"
);
goto
err_stop
;
}
ret
=
dualshock4_get_calibration_data
(
sc
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"Failed to get calibration data from Dualshock 4
\n
"
);
goto
err_stop
;
}
/*
...
...
@@ -2585,6 +2625,28 @@ static int sony_input_configured(struct hid_device *hdev,
goto
err_stop
;
}
ret
=
sony_register_sensors
(
sc
);
if
(
ret
)
{
hid_err
(
sc
->
hdev
,
"Unable to initialize motion sensors: %d
\n
"
,
ret
);
goto
err_stop
;
}
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
{
sc
->
ds4_bt_poll_interval
=
DS4_BT_DEFAULT_POLL_INTERVAL_MS
;
ret
=
device_create_file
(
&
sc
->
hdev
->
dev
,
&
dev_attr_bt_poll_interval
);
if
(
ret
)
hid_warn
(
sc
->
hdev
,
"can't create sysfs bt_poll_interval attribute err: %d
\n
"
,
ret
);
}
if
(
sc
->
quirks
&
DUALSHOCK4_DONGLE
)
{
INIT_WORK
(
&
sc
->
hotplug_worker
,
dualshock4_calibration_work
);
sc
->
hotplug_worker_initialized
=
1
;
sc
->
ds4_dongle_state
=
DONGLE_DISCONNECTED
;
}
sony_init_output_report
(
sc
,
dualshock4_send_output_report
);
}
else
if
(
sc
->
quirks
&
MOTION_CONTROLLER
)
{
sony_init_output_report
(
sc
,
motion_send_output_report
);
...
...
@@ -2592,13 +2654,6 @@ static int sony_input_configured(struct hid_device *hdev,
ret
=
0
;
}
if
(
ret
<
0
)
goto
err_stop
;
ret
=
append_dev_id
=
sony_check_add
(
sc
);
if
(
ret
<
0
)
goto
err_stop
;
if
(
sc
->
quirks
&
SONY_LED_SUPPORT
)
{
ret
=
sony_leds_init
(
sc
);
if
(
ret
<
0
)
...
...
@@ -2628,12 +2683,20 @@ static int sony_input_configured(struct hid_device *hdev,
err_close:
hid_hw_close
(
hdev
);
err_stop:
/* Piggy back on the default ds4_bt_ poll_interval to determine
* if we need to remove the file as we don't know for sure if we
* executed that logic.
*/
if
(
sc
->
ds4_bt_poll_interval
)
device_remove_file
(
&
sc
->
hdev
->
dev
,
&
dev_attr_bt_poll_interval
);
if
(
sc
->
quirks
&
SONY_LED_SUPPORT
)
sony_leds_remove
(
sc
);
if
(
sc
->
quirks
&
SONY_BATTERY_SUPPORT
)
sony_battery_remove
(
sc
);
if
(
sc
->
touchpad
)
sony_unregister_touchpad
(
sc
);
if
(
sc
->
sensor_dev
)
sony_unregister_sensors
(
sc
);
sony_cancel_work_sync
(
sc
);
kfree
(
sc
->
output_report_dmabuf
);
sony_remove_dev_list
(
sc
);
...
...
@@ -2675,13 +2738,13 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
else
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER
)
connect_mask
|=
HID_CONNECT_HIDDEV_FORCE
;
/* Patch the hw version on DS4 compatible devices, so applications can
/* Patch the hw version on DS
3/
4 compatible devices, so applications can
* distinguish between the default HID mappings and the mappings defined
* by the Linux game controller spec. This is important for the SDL2
* library, which has a game controller database, which uses device ids
* in combination with version as a key.
*/
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER
)
if
(
sc
->
quirks
&
(
SIXAXIS_CONTROLLER
|
DUALSHOCK4_CONTROLLER
)
)
hdev
->
version
|=
0x8000
;
ret
=
hid_hw_start
(
hdev
,
connect_mask
);
...
...
@@ -2721,6 +2784,12 @@ static void sony_remove(struct hid_device *hdev)
if
(
sc
->
touchpad
)
sony_unregister_touchpad
(
sc
);
if
(
sc
->
sensor_dev
)
sony_unregister_sensors
(
sc
);
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
device_remove_file
(
&
sc
->
hdev
->
dev
,
&
dev_attr_bt_poll_interval
);
sony_cancel_work_sync
(
sc
);
kfree
(
sc
->
output_report_dmabuf
);
...
...
@@ -2736,47 +2805,32 @@ static void sony_remove(struct hid_device *hdev)
static
int
sony_suspend
(
struct
hid_device
*
hdev
,
pm_message_t
message
)
{
/*
* On suspend save the current LED state,
* stop running force-feedback and blank the LEDS.
*/
if
(
SONY_LED_SUPPORT
||
SONY_FF_SUPPORT
)
{
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
#ifdef CONFIG_SONY_FF
sc
->
left
=
sc
->
right
=
0
;
#endif
memcpy
(
sc
->
resume_led_state
,
sc
->
led_state
,
sizeof
(
sc
->
resume_led_state
));
memset
(
sc
->
led_state
,
0
,
sizeof
(
sc
->
led_state
)
);
/* On suspend stop any running force-feedback events */
if
(
SONY_FF_SUPPORT
)
{
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
sc
->
left
=
sc
->
right
=
0
;
sony_send_output_report
(
sc
);
}
#endif
return
0
;
}
static
int
sony_resume
(
struct
hid_device
*
hdev
)
{
/* Restore the state of controller LEDs on resume */
if
(
SONY_LED_SUPPORT
)
{
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
memcpy
(
sc
->
led_state
,
sc
->
resume_led_state
,
sizeof
(
sc
->
led_state
));
/*
* The Sixaxis and navigation controllers on USB need to be
* reinitialized on resume or they won't behave properly.
*/
if
((
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
||
(
sc
->
quirks
&
NAVIGATION_CONTROLLER_USB
))
{
sixaxis_set_operational_usb
(
sc
->
hdev
);
sc
->
defer_initialization
=
1
;
}
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
sony_set_leds
(
sc
);
/*
* The Sixaxis and navigation controllers on USB need to be
* reinitialized on resume or they won't behave properly.
*/
if
((
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
||
(
sc
->
quirks
&
NAVIGATION_CONTROLLER_USB
))
{
sixaxis_set_operational_usb
(
sc
->
hdev
);
sc
->
defer_initialization
=
1
;
}
return
0
;
...
...
@@ -2828,7 +2882,7 @@ static const struct hid_device_id sony_devices[] = {
{
HID_BLUETOOTH_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_PS4_CONTROLLER_2
),
.
driver_data
=
DUALSHOCK4_CONTROLLER_BT
},
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SONY
,
USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE
),
.
driver_data
=
DUALSHOCK4_
CONTROLLER_USB
},
.
driver_data
=
DUALSHOCK4_
DONGLE
},
/* Nyko Core Controller for PS3 */
{
HID_USB_DEVICE
(
USB_VENDOR_ID_SINO_LITE
,
USB_DEVICE_ID_SINO_LITE_CONTROLLER
),
.
driver_data
=
SIXAXIS_CONTROLLER_USB
|
SINO_LITE_CONTROLLER
},
...
...
include/uapi/linux/input.h
View file @
800f3eef
...
...
@@ -61,9 +61,14 @@ struct input_id {
* Note that input core does not clamp reported values to the
* [minimum, maximum] limits, such task is left to userspace.
*
* Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
* units per millimeter (units/mm), resolution for rotational axes
* (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
* The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
* is reported in units per millimeter (units/mm), resolution
* for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported
* in units per radian.
* When INPUT_PROP_ACCELEROMETER is set the resolution changes.
* The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
* in units per g (units/g) and in units per degree per second
* (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ).
*/
struct
input_absinfo
{
__s32
value
;
...
...
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