Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
65ab2fc4
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
65ab2fc4
编写于
3月 14, 2014
作者:
J
Jiri Kosina
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-3.15/sony' into for-3.15/hid-core-ll-transport-cleanup
上级
866e4797
dccf2f65
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
701 addition
and
66 deletion
+701
-66
drivers/hid/Kconfig
drivers/hid/Kconfig
+6
-4
drivers/hid/hid-sony.c
drivers/hid/hid-sony.c
+692
-62
net/bluetooth/hidp/core.c
net/bluetooth/hidp/core.c
+3
-0
未找到文件。
drivers/hid/Kconfig
浏览文件 @
65ab2fc4
...
@@ -617,25 +617,27 @@ config HID_SAMSUNG
...
@@ -617,25 +617,27 @@ config HID_SAMSUNG
Support for Samsung InfraRed remote control or keyboards.
Support for Samsung InfraRed remote control or keyboards.
config HID_SONY
config HID_SONY
tristate "Sony PS2/3 accessories"
tristate "Sony PS2/3
/4
accessories"
depends on USB_HID
depends on USB_HID
depends on NEW_LEDS
depends on NEW_LEDS
depends on LEDS_CLASS
depends on LEDS_CLASS
select POWER_SUPPLY
---help---
---help---
Support for
Support for
* Sony PS3 6-axis controllers
* Sony PS3 6-axis controllers
* Sony PS4 DualShock 4 controllers
* Buzz controllers
* Buzz controllers
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
config SONY_FF
config SONY_FF
bool "Sony PS2/3
accessories force feedback support"
bool "Sony PS2/3
/4 accessories force feedback support"
depends on HID_SONY
depends on HID_SONY
select INPUT_FF_MEMLESS
select INPUT_FF_MEMLESS
---help---
---help---
Say Y here if you have a Sony PS2/3
accessory and want to enable forc
e
Say Y here if you have a Sony PS2/3
/4 accessory and want to enabl
e
feedback support for it.
f
orce f
eedback support for it.
config HID_SPEEDLINK
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
tristate "Speedlink VAD Cezanne mouse support"
...
...
drivers/hid/hid-sony.c
浏览文件 @
65ab2fc4
...
@@ -17,7 +17,8 @@
...
@@ -17,7 +17,8 @@
* any later version.
* any later version.
*/
*/
/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
/*
* NOTE: in order for the Sony PS3 BD Remote Control to be found by
* a Bluetooth host, the key combination Start+Enter has to be kept pressed
* a Bluetooth host, the key combination Start+Enter has to be kept pressed
* for about 7 seconds with the Bluetooth Host Controller in discovering mode.
* for about 7 seconds with the Bluetooth Host Controller in discovering mode.
*
*
...
@@ -30,6 +31,10 @@
...
@@ -30,6 +31,10 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb.h>
#include <linux/leds.h>
#include <linux/leds.h>
#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/input/mt.h>
#include "hid-ids.h"
#include "hid-ids.h"
...
@@ -41,7 +46,13 @@
...
@@ -41,7 +46,13 @@
#define DUALSHOCK4_CONTROLLER_USB BIT(5)
#define DUALSHOCK4_CONTROLLER_USB BIT(5)
#define DUALSHOCK4_CONTROLLER_BT BIT(6)
#define DUALSHOCK4_CONTROLLER_BT BIT(6)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
#define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\
DUALSHOCK4_CONTROLLER_BT)
#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\
DUALSHOCK4_CONTROLLER)
#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)
#define MAX_LEDS 4
#define MAX_LEDS 4
...
@@ -73,7 +84,8 @@ static const u8 sixaxis_rdesc_fixup2[] = {
...
@@ -73,7 +84,8 @@ static const u8 sixaxis_rdesc_fixup2[] = {
0xb1
,
0x02
,
0xc0
,
0xc0
,
0xb1
,
0x02
,
0xc0
,
0xc0
,
};
};
/* The default descriptor doesn't provide mapping for the accelerometers
/*
* The default descriptor doesn't provide mapping for the accelerometers
* or orientation sensors. This fixed descriptor maps 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 0x40, 0x41 and 0x42 and maps the orientation sensors
* to usage values 0x43, 0x44 and 0x45.
* to usage values 0x43, 0x44 and 0x45.
...
@@ -332,6 +344,217 @@ static u8 dualshock4_usb_rdesc[] = {
...
@@ -332,6 +344,217 @@ static u8 dualshock4_usb_rdesc[] = {
0xC0
/* End Collection */
0xC0
/* End Collection */
};
};
/*
* The default behavior of the Dualshock 4 is to send reports using report
* type 1 when running over Bluetooth. However, as soon as it receives a
* report of type 17 to set the LEDs or rumble it starts returning it's state
* in report 17 instead of 1. 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 once a report is sent.
*/
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
,
0x0E
,
/* Usage Maximum (0Eh), */
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
,
0x00
,
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
,
0xFF
,
0xBF
,
/* Logical Minimum (-16385), */
0x26
,
0x00
,
0x40
,
/* Logical Maximum (16384), */
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
[]
=
{
static
__u8
ps3remote_rdesc
[]
=
{
0x05
,
0x01
,
/* GUsagePage Generic Desktop */
0x05
,
0x01
,
/* GUsagePage Generic Desktop */
0x09
,
0x05
,
/* LUsage 0x05 [Game Pad] */
0x09
,
0x05
,
/* LUsage 0x05 [Game Pad] */
...
@@ -449,7 +672,8 @@ static const unsigned int ps3remote_keymap_remote_buttons[] = {
...
@@ -449,7 +672,8 @@ static const unsigned int ps3remote_keymap_remote_buttons[] = {
};
};
static
const
unsigned
int
buzz_keymap
[]
=
{
static
const
unsigned
int
buzz_keymap
[]
=
{
/* The controller has 4 remote buzzers, each with one LED and 5
/*
* The controller has 4 remote buzzers, each with one LED and 5
* buttons.
* buttons.
*
*
* We use the mapping chosen by the controller, which is:
* We use the mapping chosen by the controller, which is:
...
@@ -487,18 +711,35 @@ static const unsigned int buzz_keymap[] = {
...
@@ -487,18 +711,35 @@ static const unsigned int buzz_keymap[] = {
[
20
]
=
BTN_TRIGGER_HAPPY20
,
[
20
]
=
BTN_TRIGGER_HAPPY20
,
};
};
static
enum
power_supply_property
sony_battery_props
[]
=
{
POWER_SUPPLY_PROP_PRESENT
,
POWER_SUPPLY_PROP_CAPACITY
,
POWER_SUPPLY_PROP_SCOPE
,
POWER_SUPPLY_PROP_STATUS
,
};
static
spinlock_t
sony_dev_list_lock
;
static
LIST_HEAD
(
sony_device_list
);
struct
sony_sc
{
struct
sony_sc
{
spinlock_t
lock
;
struct
list_head
list_node
;
struct
hid_device
*
hdev
;
struct
hid_device
*
hdev
;
struct
led_classdev
*
leds
[
MAX_LEDS
];
struct
led_classdev
*
leds
[
MAX_LEDS
];
struct
hid_report
*
output_report
;
unsigned
long
quirks
;
unsigned
long
quirks
;
struct
work_struct
state_worker
;
struct
work_struct
state_worker
;
struct
power_supply
battery
;
#ifdef CONFIG_SONY_FF
#ifdef CONFIG_SONY_FF
__u8
left
;
__u8
left
;
__u8
right
;
__u8
right
;
#endif
#endif
__u8
mac_address
[
6
];
__u8
worker_initialized
;
__u8
cable_state
;
__u8
battery_charging
;
__u8
battery_capacity
;
__u8
led_state
[
MAX_LEDS
];
__u8
led_state
[
MAX_LEDS
];
__u8
led_count
;
__u8
led_count
;
};
};
...
@@ -576,6 +817,10 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
...
@@ -576,6 +817,10 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info
(
hdev
,
"Using modified Dualshock 4 report descriptor with gyroscope axes
\n
"
);
hid_info
(
hdev
,
"Using modified Dualshock 4 report descriptor with gyroscope axes
\n
"
);
rdesc
=
dualshock4_usb_rdesc
;
rdesc
=
dualshock4_usb_rdesc
;
*
rsize
=
sizeof
(
dualshock4_usb_rdesc
);
*
rsize
=
sizeof
(
dualshock4_usb_rdesc
);
}
else
if
((
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
&&
*
rsize
==
357
)
{
hid_info
(
hdev
,
"Using modified Dualshock 4 Bluetooth report descriptor
\n
"
);
rdesc
=
dualshock4_bt_rdesc
;
*
rsize
=
sizeof
(
dualshock4_bt_rdesc
);
}
}
/* The HID descriptor exposed over BT has a trailing zero byte */
/* The HID descriptor exposed over BT has a trailing zero byte */
...
@@ -599,20 +844,127 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
...
@@ -599,20 +844,127 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return
rdesc
;
return
rdesc
;
}
}
static
void
sixaxis_parse_report
(
struct
sony_sc
*
sc
,
__u8
*
rd
,
int
size
)
{
static
const
__u8
sixaxis_battery_capacity
[]
=
{
0
,
1
,
25
,
50
,
75
,
100
};
unsigned
long
flags
;
__u8
cable_state
,
battery_capacity
,
battery_charging
;
/*
* The sixaxis is charging if the battery value is 0xee
* and it is fully charged if the value is 0xef.
* It does not report the actual level while charging so it
* is set to 100% while charging is in progress.
*/
if
(
rd
[
30
]
>=
0xee
)
{
battery_capacity
=
100
;
battery_charging
=
!
(
rd
[
30
]
&
0x01
);
}
else
{
__u8
index
=
rd
[
30
]
<=
5
?
rd
[
30
]
:
5
;
battery_capacity
=
sixaxis_battery_capacity
[
index
];
battery_charging
=
0
;
}
cable_state
=
!
((
rd
[
31
]
>>
4
)
&
0x01
);
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
sc
->
cable_state
=
cable_state
;
sc
->
battery_capacity
=
battery_capacity
;
sc
->
battery_charging
=
battery_charging
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
}
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
,
offset
;
__u8
cable_state
,
battery_capacity
,
battery_charging
;
/*
* Battery and touchpad data starts at byte 30 in the USB report and
* 32 in Bluetooth report.
*/
offset
=
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
?
30
:
32
;
/*
* The lower 4 bits of byte 30 contain the battery level
* and the 5th bit contains the USB cable state.
*/
cable_state
=
(
rd
[
offset
]
>>
4
)
&
0x01
;
battery_capacity
=
rd
[
offset
]
&
0x0F
;
/*
* When a USB power source is connected the battery level ranges from
* 0 to 10, and when running on battery power it ranges from 0 to 9.
* A battery level above 10 when plugged in means charge completed.
*/
if
(
!
cable_state
||
battery_capacity
>
10
)
battery_charging
=
0
;
else
battery_charging
=
1
;
if
(
!
cable_state
)
battery_capacity
++
;
if
(
battery_capacity
>
10
)
battery_capacity
=
10
;
battery_capacity
*=
10
;
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
sc
->
cable_state
=
cable_state
;
sc
->
battery_capacity
=
battery_capacity
;
sc
->
battery_charging
=
battery_charging
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
offset
+=
5
;
/*
* The Dualshock 4 multi-touch trackpad data starts at offset 35 on USB
* and 37 on Bluetooth.
* The first 7 bits of the first byte is a counter and bit 8 is a touch
* indicator that is 0 when pressed and 1 when not pressed.
* The next 3 bytes are two 12 bit touch coordinates, X and Y.
* The data for the second touch is in the same format and immediatly
* follows the data for the first.
*/
for
(
n
=
0
;
n
<
2
;
n
++
)
{
__u16
x
,
y
;
x
=
rd
[
offset
+
1
]
|
((
rd
[
offset
+
2
]
&
0xF
)
<<
8
);
y
=
((
rd
[
offset
+
2
]
&
0xF0
)
>>
4
)
|
(
rd
[
offset
+
3
]
<<
4
);
input_mt_slot
(
input_dev
,
n
);
input_mt_report_slot_state
(
input_dev
,
MT_TOOL_FINGER
,
!
(
rd
[
offset
]
>>
7
));
input_report_abs
(
input_dev
,
ABS_MT_POSITION_X
,
x
);
input_report_abs
(
input_dev
,
ABS_MT_POSITION_Y
,
y
);
offset
+=
4
;
}
}
static
int
sony_raw_event
(
struct
hid_device
*
hdev
,
struct
hid_report
*
report
,
static
int
sony_raw_event
(
struct
hid_device
*
hdev
,
struct
hid_report
*
report
,
__u8
*
rd
,
int
size
)
__u8
*
rd
,
int
size
)
{
{
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
/* Sixaxis HID report has acclerometers/gyro with MSByte first, this
/*
* Sixaxis HID report has acclerometers/gyro with MSByte first, this
* has to be BYTE_SWAPPED before passing up to joystick interface
* has to be BYTE_SWAPPED before passing up to joystick interface
*/
*/
if
((
sc
->
quirks
&
(
SIXAXIS_CONTROLLER_USB
|
SIXAXIS_CONTROLLER_BT
))
&&
if
((
sc
->
quirks
&
SIXAXIS_CONTROLLER
)
&&
rd
[
0
]
==
0x01
&&
size
==
49
)
{
rd
[
0
]
==
0x01
&&
size
==
49
)
{
swap
(
rd
[
41
],
rd
[
42
]);
swap
(
rd
[
41
],
rd
[
42
]);
swap
(
rd
[
43
],
rd
[
44
]);
swap
(
rd
[
43
],
rd
[
44
]);
swap
(
rd
[
45
],
rd
[
46
]);
swap
(
rd
[
45
],
rd
[
46
]);
swap
(
rd
[
47
],
rd
[
48
]);
swap
(
rd
[
47
],
rd
[
48
]);
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
))
{
dualshock4_parse_report
(
sc
,
rd
,
size
);
}
}
return
0
;
return
0
;
...
@@ -724,6 +1076,18 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
...
@@ -724,6 +1076,18 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
HID_FEATURE_REPORT
,
HID_REQ_SET_REPORT
);
HID_FEATURE_REPORT
,
HID_REQ_SET_REPORT
);
}
}
/*
* Requesting feature report 0x02 in Bluetooth mode changes the state of the
* controller so that it sends full input reports of type 0x11.
*/
static
int
dualshock4_set_operational_bt
(
struct
hid_device
*
hdev
)
{
__u8
buf
[
37
]
=
{
0
};
return
hid_hw_raw_request
(
hdev
,
0x02
,
buf
,
sizeof
(
buf
),
HID_FEATURE_REPORT
,
HID_REQ_GET_REPORT
);
}
static
void
buzz_set_leds
(
struct
hid_device
*
hdev
,
const
__u8
*
leds
)
static
void
buzz_set_leds
(
struct
hid_device
*
hdev
,
const
__u8
*
leds
)
{
{
struct
list_head
*
report_list
=
struct
list_head
*
report_list
=
...
@@ -751,8 +1115,7 @@ static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
...
@@ -751,8 +1115,7 @@ static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
if
(
drv_data
->
quirks
&
BUZZ_CONTROLLER
&&
count
==
4
)
{
if
(
drv_data
->
quirks
&
BUZZ_CONTROLLER
&&
count
==
4
)
{
buzz_set_leds
(
hdev
,
leds
);
buzz_set_leds
(
hdev
,
leds
);
}
else
if
((
drv_data
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
||
}
else
{
(
drv_data
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
))
{
for
(
n
=
0
;
n
<
count
;
n
++
)
for
(
n
=
0
;
n
<
count
;
n
++
)
drv_data
->
led_state
[
n
]
=
leds
[
n
];
drv_data
->
led_state
[
n
]
=
leds
[
n
];
schedule_work
(
&
drv_data
->
state_worker
);
schedule_work
(
&
drv_data
->
state_worker
);
...
@@ -792,7 +1155,6 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
...
@@ -792,7 +1155,6 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
struct
sony_sc
*
drv_data
;
struct
sony_sc
*
drv_data
;
int
n
;
int
n
;
int
on
=
0
;
drv_data
=
hid_get_drvdata
(
hdev
);
drv_data
=
hid_get_drvdata
(
hdev
);
if
(
!
drv_data
)
{
if
(
!
drv_data
)
{
...
@@ -801,13 +1163,11 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
...
@@ -801,13 +1163,11 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
}
}
for
(
n
=
0
;
n
<
drv_data
->
led_count
;
n
++
)
{
for
(
n
=
0
;
n
<
drv_data
->
led_count
;
n
++
)
{
if
(
led
==
drv_data
->
leds
[
n
])
{
if
(
led
==
drv_data
->
leds
[
n
])
on
=
!!
(
drv_data
->
led_state
[
n
]);
return
drv_data
->
led_state
[
n
];
break
;
}
}
}
return
on
?
LED_FULL
:
LED_OFF
;
return
LED_OFF
;
}
}
static
void
sony_leds_remove
(
struct
hid_device
*
hdev
)
static
void
sony_leds_remove
(
struct
hid_device
*
hdev
)
...
@@ -857,7 +1217,7 @@ static int sony_leds_init(struct hid_device *hdev)
...
@@ -857,7 +1217,7 @@ static int sony_leds_init(struct hid_device *hdev)
/* Validate expected report characteristics. */
/* Validate expected report characteristics. */
if
(
!
hid_validate_values
(
hdev
,
HID_OUTPUT_REPORT
,
0
,
0
,
7
))
if
(
!
hid_validate_values
(
hdev
,
HID_OUTPUT_REPORT
,
0
,
0
,
7
))
return
-
ENODEV
;
return
-
ENODEV
;
}
else
if
(
drv_data
->
quirks
&
DUALSHOCK4_CONTROLLER
_USB
)
{
}
else
if
(
drv_data
->
quirks
&
DUALSHOCK4_CONTROLLER
)
{
drv_data
->
led_count
=
3
;
drv_data
->
led_count
=
3
;
max_brightness
=
255
;
max_brightness
=
255
;
use_colors
=
1
;
use_colors
=
1
;
...
@@ -871,9 +1231,11 @@ static int sony_leds_init(struct hid_device *hdev)
...
@@ -871,9 +1231,11 @@ static int sony_leds_init(struct hid_device *hdev)
name_fmt
=
"%s::sony%d"
;
name_fmt
=
"%s::sony%d"
;
}
}
/* Clear LEDs as we have no way of reading their initial state. This is
/*
* Clear LEDs as we have no way of reading their initial state. This is
* only relevant if the driver is loaded after somebody actively set the
* only relevant if the driver is loaded after somebody actively set the
* LEDs to on */
* LEDs to on
*/
sony_set_leds
(
hdev
,
initial_values
,
drv_data
->
led_count
);
sony_set_leds
(
hdev
,
initial_values
,
drv_data
->
led_count
);
name_sz
=
strlen
(
dev_name
(
&
hdev
->
dev
))
+
name_len
+
1
;
name_sz
=
strlen
(
dev_name
(
&
hdev
->
dev
))
+
name_len
+
1
;
...
@@ -943,28 +1305,48 @@ static void sixaxis_state_worker(struct work_struct *work)
...
@@ -943,28 +1305,48 @@ static void sixaxis_state_worker(struct work_struct *work)
buf
[
10
]
|=
sc
->
led_state
[
2
]
<<
3
;
buf
[
10
]
|=
sc
->
led_state
[
2
]
<<
3
;
buf
[
10
]
|=
sc
->
led_state
[
3
]
<<
4
;
buf
[
10
]
|=
sc
->
led_state
[
3
]
<<
4
;
hid_output_raw_report
(
sc
->
hdev
,
buf
,
sizeof
(
buf
),
HID_OUTPUT_REPORT
);
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
hid_output_raw_report
(
sc
->
hdev
,
buf
,
sizeof
(
buf
),
HID_OUTPUT_REPORT
);
else
hid_hw_raw_request
(
sc
->
hdev
,
0x01
,
buf
,
sizeof
(
buf
),
HID_OUTPUT_REPORT
,
HID_REQ_SET_REPORT
);
}
}
static
void
dualshock4_state_worker
(
struct
work_struct
*
work
)
static
void
dualshock4_state_worker
(
struct
work_struct
*
work
)
{
{
struct
sony_sc
*
sc
=
container_of
(
work
,
struct
sony_sc
,
state_worker
);
struct
sony_sc
*
sc
=
container_of
(
work
,
struct
sony_sc
,
state_worker
);
struct
hid_device
*
hdev
=
sc
->
hdev
;
struct
hid_device
*
hdev
=
sc
->
hdev
;
struct
hid_report
*
report
=
sc
->
output_report
;
int
offset
;
__s32
*
value
=
report
->
field
[
0
]
->
value
;
__u8
buf
[
78
]
=
{
0
};
value
[
0
]
=
0x03
;
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
{
buf
[
0
]
=
0x05
;
buf
[
1
]
=
0x03
;
offset
=
4
;
}
else
{
buf
[
0
]
=
0x11
;
buf
[
1
]
=
0xB0
;
buf
[
3
]
=
0x0F
;
offset
=
6
;
}
#ifdef CONFIG_SONY_FF
#ifdef CONFIG_SONY_FF
value
[
3
]
=
sc
->
right
;
buf
[
offset
++
]
=
sc
->
right
;
value
[
4
]
=
sc
->
left
;
buf
[
offset
++
]
=
sc
->
left
;
#else
offset
+=
2
;
#endif
#endif
value
[
5
]
=
sc
->
led_state
[
0
];
buf
[
offset
++
]
=
sc
->
led_state
[
0
];
value
[
6
]
=
sc
->
led_state
[
1
];
buf
[
offset
++
]
=
sc
->
led_state
[
1
];
value
[
7
]
=
sc
->
led_state
[
2
];
buf
[
offset
++
]
=
sc
->
led_state
[
2
];
hid_hw_request
(
hdev
,
report
,
HID_REQ_SET_REPORT
);
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
hid_hw_output_report
(
hdev
,
buf
,
32
);
else
hid_hw_raw_request
(
hdev
,
0x11
,
buf
,
78
,
HID_OUTPUT_REPORT
,
HID_REQ_SET_REPORT
);
}
}
#ifdef CONFIG_SONY_FF
#ifdef CONFIG_SONY_FF
...
@@ -994,51 +1376,252 @@ static int sony_init_ff(struct hid_device *hdev)
...
@@ -994,51 +1376,252 @@ static int sony_init_ff(struct hid_device *hdev)
return
input_ff_create_memless
(
input_dev
,
NULL
,
sony_play_effect
);
return
input_ff_create_memless
(
input_dev
,
NULL
,
sony_play_effect
);
}
}
static
void
sony_destroy_ff
(
struct
hid_device
*
hdev
)
#else
static
int
sony_init_ff
(
struct
hid_device
*
hdev
)
{
{
struct
sony_sc
*
sc
=
hid_get_drvdata
(
hdev
);
return
0
;
}
#endif
cancel_work_sync
(
&
sc
->
state_worker
);
static
int
sony_battery_get_property
(
struct
power_supply
*
psy
,
enum
power_supply_property
psp
,
union
power_supply_propval
*
val
)
{
struct
sony_sc
*
sc
=
container_of
(
psy
,
struct
sony_sc
,
battery
);
unsigned
long
flags
;
int
ret
=
0
;
u8
battery_charging
,
battery_capacity
,
cable_state
;
spin_lock_irqsave
(
&
sc
->
lock
,
flags
);
battery_charging
=
sc
->
battery_charging
;
battery_capacity
=
sc
->
battery_capacity
;
cable_state
=
sc
->
cable_state
;
spin_unlock_irqrestore
(
&
sc
->
lock
,
flags
);
switch
(
psp
)
{
case
POWER_SUPPLY_PROP_PRESENT
:
val
->
intval
=
1
;
break
;
case
POWER_SUPPLY_PROP_SCOPE
:
val
->
intval
=
POWER_SUPPLY_SCOPE_DEVICE
;
break
;
case
POWER_SUPPLY_PROP_CAPACITY
:
val
->
intval
=
battery_capacity
;
break
;
case
POWER_SUPPLY_PROP_STATUS
:
if
(
battery_charging
)
val
->
intval
=
POWER_SUPPLY_STATUS_CHARGING
;
else
if
(
battery_capacity
==
100
&&
cable_state
)
val
->
intval
=
POWER_SUPPLY_STATUS_FULL
;
else
val
->
intval
=
POWER_SUPPLY_STATUS_DISCHARGING
;
break
;
default:
ret
=
-
EINVAL
;
break
;
}
return
ret
;
}
}
#else
static
int
sony_battery_probe
(
struct
sony_sc
*
sc
)
static
int
sony_init_ff
(
struct
hid_device
*
hdev
)
{
{
static
atomic_t
power_id_seq
=
ATOMIC_INIT
(
0
);
unsigned
long
power_id
;
struct
hid_device
*
hdev
=
sc
->
hdev
;
int
ret
;
/*
* Set the default battery level to 100% to avoid low battery warnings
* if the battery is polled before the first device report is received.
*/
sc
->
battery_capacity
=
100
;
power_id
=
(
unsigned
long
)
atomic_inc_return
(
&
power_id_seq
);
sc
->
battery
.
properties
=
sony_battery_props
;
sc
->
battery
.
num_properties
=
ARRAY_SIZE
(
sony_battery_props
);
sc
->
battery
.
get_property
=
sony_battery_get_property
;
sc
->
battery
.
type
=
POWER_SUPPLY_TYPE_BATTERY
;
sc
->
battery
.
use_for_apm
=
0
;
sc
->
battery
.
name
=
kasprintf
(
GFP_KERNEL
,
"sony_controller_battery_%lu"
,
power_id
);
if
(
!
sc
->
battery
.
name
)
return
-
ENOMEM
;
ret
=
power_supply_register
(
&
hdev
->
dev
,
&
sc
->
battery
);
if
(
ret
)
{
hid_err
(
hdev
,
"Unable to register battery device
\n
"
);
goto
err_free
;
}
power_supply_powers
(
&
sc
->
battery
,
&
hdev
->
dev
);
return
0
;
return
0
;
err_free:
kfree
(
sc
->
battery
.
name
);
sc
->
battery
.
name
=
NULL
;
return
ret
;
}
}
static
void
sony_
destroy_ff
(
struct
hid_device
*
hdev
)
static
void
sony_
battery_remove
(
struct
sony_sc
*
sc
)
{
{
if
(
!
sc
->
battery
.
name
)
return
;
power_supply_unregister
(
&
sc
->
battery
);
kfree
(
sc
->
battery
.
name
);
sc
->
battery
.
name
=
NULL
;
}
}
#endif
static
int
sony_set_output_report
(
struct
sony_sc
*
sc
,
int
req_id
,
int
req_size
)
static
int
sony_register_touchpad
(
struct
sony_sc
*
sc
,
int
touch_count
,
int
w
,
int
h
)
{
{
struct
list_head
*
head
,
*
list
;
struct
hid_input
*
hidinput
=
list_entry
(
sc
->
hdev
->
inputs
.
next
,
struct
hid_report
*
report
;
struct
hid_input
,
list
);
struct
hid_device
*
hdev
=
sc
->
hdev
;
struct
input_dev
*
input_dev
=
hidinput
->
input
;
int
ret
;
ret
=
input_mt_init_slots
(
input_dev
,
touch_count
,
0
);
if
(
ret
<
0
)
{
hid_err
(
sc
->
hdev
,
"Unable to initialize multi-touch slots
\n
"
);
return
ret
;
}
list
=
&
hdev
->
report_enum
[
HID_OUTPUT_REPORT
].
report_list
;
input_set_abs_params
(
input_dev
,
ABS_MT_POSITION_X
,
0
,
w
,
0
,
0
);
input_set_abs_params
(
input_dev
,
ABS_MT_POSITION_Y
,
0
,
h
,
0
,
0
);
list_for_each
(
head
,
list
)
{
return
0
;
report
=
list_entry
(
head
,
struct
hid_report
,
list
);
}
if
(
report
->
id
==
req_id
)
{
/*
if
(
report
->
size
<
req_size
)
{
* If a controller is plugged in via USB while already connected via Bluetooth
hid_err
(
hdev
,
"Output report 0x%02x (%i bits) is smaller than requested size (%i bits)
\n
"
,
* it will show up as two devices. A global list of connected controllers and
req_id
,
report
->
size
,
req_size
);
* their MAC addresses is maintained to ensure that a device is only connected
return
-
EINVAL
;
* once.
}
*/
sc
->
output_report
=
report
;
static
int
sony_check_add_dev_list
(
struct
sony_sc
*
sc
)
return
0
;
{
struct
sony_sc
*
entry
;
unsigned
long
flags
;
int
ret
;
spin_lock_irqsave
(
&
sony_dev_list_lock
,
flags
);
list_for_each_entry
(
entry
,
&
sony_device_list
,
list_node
)
{
ret
=
memcmp
(
sc
->
mac_address
,
entry
->
mac_address
,
sizeof
(
sc
->
mac_address
));
if
(
!
ret
)
{
ret
=
-
EEXIST
;
hid_info
(
sc
->
hdev
,
"controller with MAC address %pMR already connected
\n
"
,
sc
->
mac_address
);
goto
unlock
;
}
}
}
}
hid_err
(
hdev
,
"Unable to locate output report 0x%02x
\n
"
,
req_id
);
ret
=
0
;
list_add
(
&
(
sc
->
list_node
),
&
sony_device_list
);
return
-
EINVAL
;
unlock:
spin_unlock_irqrestore
(
&
sony_dev_list_lock
,
flags
);
return
ret
;
}
static
void
sony_remove_dev_list
(
struct
sony_sc
*
sc
)
{
unsigned
long
flags
;
if
(
sc
->
list_node
.
next
)
{
spin_lock_irqsave
(
&
sony_dev_list_lock
,
flags
);
list_del
(
&
(
sc
->
list_node
));
spin_unlock_irqrestore
(
&
sony_dev_list_lock
,
flags
);
}
}
}
static
int
sony_get_bt_devaddr
(
struct
sony_sc
*
sc
)
{
int
ret
;
/* HIDP stores the device MAC address as a string in the uniq field. */
ret
=
strlen
(
sc
->
hdev
->
uniq
);
if
(
ret
!=
17
)
return
-
EINVAL
;
ret
=
sscanf
(
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
]);
if
(
ret
!=
6
)
return
-
EINVAL
;
return
0
;
}
static
int
sony_check_add
(
struct
sony_sc
*
sc
)
{
int
n
,
ret
;
if
((
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_BT
)
||
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_BT
))
{
/*
* sony_get_bt_devaddr() attempts to parse the Bluetooth MAC
* address from the uniq string where HIDP stores it.
* As uniq cannot be guaranteed to be a MAC address in all cases
* a failure of this function should not prevent the connection.
*/
if
(
sony_get_bt_devaddr
(
sc
)
<
0
)
{
hid_warn
(
sc
->
hdev
,
"UNIQ does not contain a MAC address; duplicate check skipped
\n
"
);
return
0
;
}
}
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
{
__u8
buf
[
7
];
/*
* The MAC address of a DS4 controller connected via USB can be
* retrieved with feature report 0x81. The address begins at
* offset 1.
*/
ret
=
hid_hw_raw_request
(
sc
->
hdev
,
0x81
,
buf
,
sizeof
(
buf
),
HID_FEATURE_REPORT
,
HID_REQ_GET_REPORT
);
if
(
ret
!=
7
)
{
hid_err
(
sc
->
hdev
,
"failed to retrieve feature report 0x81 with the DualShock 4 MAC address
\n
"
);
return
ret
<
0
?
ret
:
-
EINVAL
;
}
memcpy
(
sc
->
mac_address
,
&
buf
[
1
],
sizeof
(
sc
->
mac_address
));
}
else
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
{
__u8
buf
[
18
];
/*
* The MAC address of a Sixaxis controller connected via USB can
* be retrieved with feature report 0xf2. The address begins at
* offset 4.
*/
ret
=
hid_hw_raw_request
(
sc
->
hdev
,
0xf2
,
buf
,
sizeof
(
buf
),
HID_FEATURE_REPORT
,
HID_REQ_GET_REPORT
);
if
(
ret
!=
18
)
{
hid_err
(
sc
->
hdev
,
"failed to retrieve feature report 0xf2 with the Sixaxis MAC address
\n
"
);
return
ret
<
0
?
ret
:
-
EINVAL
;
}
/*
* The Sixaxis device MAC in the report is big-endian and must
* be byte-swapped.
*/
for
(
n
=
0
;
n
<
6
;
n
++
)
sc
->
mac_address
[
5
-
n
]
=
buf
[
4
+
n
];
}
else
{
return
0
;
}
return
sony_check_add_dev_list
(
sc
);
}
static
int
sony_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
static
int
sony_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
{
int
ret
;
int
ret
;
...
@@ -1078,21 +1661,38 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
...
@@ -1078,21 +1661,38 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
{
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_USB
)
{
hdev
->
hid_output_raw_report
=
sixaxis_usb_output_raw_report
;
hdev
->
hid_output_raw_report
=
sixaxis_usb_output_raw_report
;
ret
=
sixaxis_set_operational_usb
(
hdev
);
ret
=
sixaxis_set_operational_usb
(
hdev
);
sc
->
worker_initialized
=
1
;
INIT_WORK
(
&
sc
->
state_worker
,
sixaxis_state_worker
);
INIT_WORK
(
&
sc
->
state_worker
,
sixaxis_state_worker
);
}
}
else
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_BT
)
{
else
if
(
sc
->
quirks
&
SIXAXIS_CONTROLLER_BT
)
ret
=
sixaxis_set_operational_bt
(
hdev
);
ret
=
sixaxis_set_operational_bt
(
hdev
);
else
if
(
sc
->
quirks
&
DUALSHOCK4_CONTROLLER_USB
)
{
sc
->
worker_initialized
=
1
;
/* Report 5 (31 bytes) is used to send data to the controller via USB */
INIT_WORK
(
&
sc
->
state_worker
,
sixaxis_state_worker
);
ret
=
sony_set_output_report
(
sc
,
0x05
,
248
);
}
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
;
}
}
/*
* The Dualshock 4 touchpad supports 2 touches and has a
* resolution of 1920x940.
*/
ret
=
sony_register_touchpad
(
sc
,
2
,
1920
,
940
);
if
(
ret
<
0
)
if
(
ret
<
0
)
goto
err_stop
;
goto
err_stop
;
sc
->
worker_initialized
=
1
;
INIT_WORK
(
&
sc
->
state_worker
,
dualshock4_state_worker
);
INIT_WORK
(
&
sc
->
state_worker
,
dualshock4_state_worker
);
}
else
{
}
else
{
ret
=
0
;
ret
=
0
;
}
}
if
(
ret
<
0
)
goto
err_stop
;
ret
=
sony_check_add
(
sc
);
if
(
ret
<
0
)
if
(
ret
<
0
)
goto
err_stop
;
goto
err_stop
;
...
@@ -1102,14 +1702,36 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
...
@@ -1102,14 +1702,36 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto
err_stop
;
goto
err_stop
;
}
}
ret
=
sony_init_ff
(
hdev
);
if
(
sc
->
quirks
&
SONY_BATTERY_SUPPORT
)
{
if
(
ret
<
0
)
ret
=
sony_battery_probe
(
sc
);
goto
err_stop
;
if
(
ret
<
0
)
goto
err_stop
;
/* Open the device to receive reports with battery info */
ret
=
hid_hw_open
(
hdev
);
if
(
ret
<
0
)
{
hid_err
(
hdev
,
"hw open failed
\n
"
);
goto
err_stop
;
}
}
if
(
sc
->
quirks
&
SONY_FF_SUPPORT
)
{
ret
=
sony_init_ff
(
hdev
);
if
(
ret
<
0
)
goto
err_close
;
}
return
0
;
return
0
;
err_close:
hid_hw_close
(
hdev
);
err_stop:
err_stop:
if
(
sc
->
quirks
&
SONY_LED_SUPPORT
)
if
(
sc
->
quirks
&
SONY_LED_SUPPORT
)
sony_leds_remove
(
hdev
);
sony_leds_remove
(
hdev
);
if
(
sc
->
quirks
&
SONY_BATTERY_SUPPORT
)
sony_battery_remove
(
sc
);
if
(
sc
->
worker_initialized
)
cancel_work_sync
(
&
sc
->
state_worker
);
sony_remove_dev_list
(
sc
);
hid_hw_stop
(
hdev
);
hid_hw_stop
(
hdev
);
return
ret
;
return
ret
;
}
}
...
@@ -1121,7 +1743,15 @@ static void sony_remove(struct hid_device *hdev)
...
@@ -1121,7 +1743,15 @@ static void sony_remove(struct hid_device *hdev)
if
(
sc
->
quirks
&
SONY_LED_SUPPORT
)
if
(
sc
->
quirks
&
SONY_LED_SUPPORT
)
sony_leds_remove
(
hdev
);
sony_leds_remove
(
hdev
);
sony_destroy_ff
(
hdev
);
if
(
sc
->
quirks
&
SONY_BATTERY_SUPPORT
)
{
hid_hw_close
(
hdev
);
sony_battery_remove
(
sc
);
}
if
(
sc
->
worker_initialized
)
cancel_work_sync
(
&
sc
->
state_worker
);
sony_remove_dev_list
(
sc
);
hid_hw_stop
(
hdev
);
hid_hw_stop
(
hdev
);
}
}
...
...
net/bluetooth/hidp/core.c
浏览文件 @
65ab2fc4
...
@@ -767,6 +767,9 @@ static int hidp_setup_hid(struct hidp_session *session,
...
@@ -767,6 +767,9 @@ static int hidp_setup_hid(struct hidp_session *session,
snprintf
(
hid
->
phys
,
sizeof
(
hid
->
phys
),
"%pMR"
,
snprintf
(
hid
->
phys
,
sizeof
(
hid
->
phys
),
"%pMR"
,
&
l2cap_pi
(
session
->
ctrl_sock
->
sk
)
->
chan
->
src
);
&
l2cap_pi
(
session
->
ctrl_sock
->
sk
)
->
chan
->
src
);
/* NOTE: Some device modules depend on the dst address being stored in
* uniq. Please be aware of this before making changes to this behavior.
*/
snprintf
(
hid
->
uniq
,
sizeof
(
hid
->
uniq
),
"%pMR"
,
snprintf
(
hid
->
uniq
,
sizeof
(
hid
->
uniq
),
"%pMR"
,
&
l2cap_pi
(
session
->
ctrl_sock
->
sk
)
->
chan
->
dst
);
&
l2cap_pi
(
session
->
ctrl_sock
->
sk
)
->
chan
->
dst
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录