Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
33238632
K
Kernel
项目概览
openeuler
/
Kernel
大约 2 年 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
33238632
编写于
2月 22, 2023
作者:
B
Benjamin Tissoires
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-6.3/bigben' into for-linus
UAF protection in work struct (Pietro Borrello)
上级
94109c9f
b94335f8
变更
1
显示空白变更内容
内联
并排
Showing
1 changed file
with
63 addition
and
12 deletion
+63
-12
drivers/hid/hid-bigbenff.c
drivers/hid/hid-bigbenff.c
+63
-12
未找到文件。
drivers/hid/hid-bigbenff.c
浏览文件 @
33238632
...
@@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = {
...
@@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = {
struct
bigben_device
{
struct
bigben_device
{
struct
hid_device
*
hid
;
struct
hid_device
*
hid
;
struct
hid_report
*
report
;
struct
hid_report
*
report
;
spinlock_t
lock
;
bool
removed
;
bool
removed
;
u8
led_state
;
/* LED1 = 1 .. LED4 = 8 */
u8
led_state
;
/* LED1 = 1 .. LED4 = 8 */
u8
right_motor_on
;
/* right motor off/on 0/1 */
u8
right_motor_on
;
/* right motor off/on 0/1 */
...
@@ -184,18 +185,39 @@ struct bigben_device {
...
@@ -184,18 +185,39 @@ struct bigben_device {
struct
work_struct
worker
;
struct
work_struct
worker
;
};
};
static
inline
void
bigben_schedule_work
(
struct
bigben_device
*
bigben
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
bigben
->
lock
,
flags
);
if
(
!
bigben
->
removed
)
schedule_work
(
&
bigben
->
worker
);
spin_unlock_irqrestore
(
&
bigben
->
lock
,
flags
);
}
static
void
bigben_worker
(
struct
work_struct
*
work
)
static
void
bigben_worker
(
struct
work_struct
*
work
)
{
{
struct
bigben_device
*
bigben
=
container_of
(
work
,
struct
bigben_device
*
bigben
=
container_of
(
work
,
struct
bigben_device
,
worker
);
struct
bigben_device
,
worker
);
struct
hid_field
*
report_field
=
bigben
->
report
->
field
[
0
];
struct
hid_field
*
report_field
=
bigben
->
report
->
field
[
0
];
bool
do_work_led
=
false
;
if
(
bigben
->
removed
||
!
report_field
)
bool
do_work_ff
=
false
;
u8
*
buf
;
u32
len
;
unsigned
long
flags
;
buf
=
hid_alloc_report_buf
(
bigben
->
report
,
GFP_KERNEL
);
if
(
!
buf
)
return
;
return
;
len
=
hid_report_len
(
bigben
->
report
);
/* LED work */
spin_lock_irqsave
(
&
bigben
->
lock
,
flags
);
if
(
bigben
->
work_led
)
{
if
(
bigben
->
work_led
)
{
bigben
->
work_led
=
false
;
bigben
->
work_led
=
false
;
do_work_led
=
true
;
report_field
->
value
[
0
]
=
0x01
;
/* 1 = led message */
report_field
->
value
[
0
]
=
0x01
;
/* 1 = led message */
report_field
->
value
[
1
]
=
0x08
;
/* reserved value, always 8 */
report_field
->
value
[
1
]
=
0x08
;
/* reserved value, always 8 */
report_field
->
value
[
2
]
=
bigben
->
led_state
;
report_field
->
value
[
2
]
=
bigben
->
led_state
;
...
@@ -204,11 +226,22 @@ static void bigben_worker(struct work_struct *work)
...
@@ -204,11 +226,22 @@ static void bigben_worker(struct work_struct *work)
report_field
->
value
[
5
]
=
0x00
;
/* padding */
report_field
->
value
[
5
]
=
0x00
;
/* padding */
report_field
->
value
[
6
]
=
0x00
;
/* padding */
report_field
->
value
[
6
]
=
0x00
;
/* padding */
report_field
->
value
[
7
]
=
0x00
;
/* padding */
report_field
->
value
[
7
]
=
0x00
;
/* padding */
hid_hw_request
(
bigben
->
hid
,
bigben
->
report
,
HID_REQ_SET_REPORT
);
hid_output_report
(
bigben
->
report
,
buf
);
}
spin_unlock_irqrestore
(
&
bigben
->
lock
,
flags
);
if
(
do_work_led
)
{
hid_hw_raw_request
(
bigben
->
hid
,
bigben
->
report
->
id
,
buf
,
len
,
bigben
->
report
->
type
,
HID_REQ_SET_REPORT
);
}
}
/* FF work */
spin_lock_irqsave
(
&
bigben
->
lock
,
flags
);
if
(
bigben
->
work_ff
)
{
if
(
bigben
->
work_ff
)
{
bigben
->
work_ff
=
false
;
bigben
->
work_ff
=
false
;
do_work_ff
=
true
;
report_field
->
value
[
0
]
=
0x02
;
/* 2 = rumble effect message */
report_field
->
value
[
0
]
=
0x02
;
/* 2 = rumble effect message */
report_field
->
value
[
1
]
=
0x08
;
/* reserved value, always 8 */
report_field
->
value
[
1
]
=
0x08
;
/* reserved value, always 8 */
report_field
->
value
[
2
]
=
bigben
->
right_motor_on
;
report_field
->
value
[
2
]
=
bigben
->
right_motor_on
;
...
@@ -217,8 +250,17 @@ static void bigben_worker(struct work_struct *work)
...
@@ -217,8 +250,17 @@ static void bigben_worker(struct work_struct *work)
report_field
->
value
[
5
]
=
0x00
;
/* padding */
report_field
->
value
[
5
]
=
0x00
;
/* padding */
report_field
->
value
[
6
]
=
0x00
;
/* padding */
report_field
->
value
[
6
]
=
0x00
;
/* padding */
report_field
->
value
[
7
]
=
0x00
;
/* padding */
report_field
->
value
[
7
]
=
0x00
;
/* padding */
hid_
hw_request
(
bigben
->
hid
,
bigben
->
report
,
HID_REQ_SET_REPORT
);
hid_
output_report
(
bigben
->
report
,
buf
);
}
}
spin_unlock_irqrestore
(
&
bigben
->
lock
,
flags
);
if
(
do_work_ff
)
{
hid_hw_raw_request
(
bigben
->
hid
,
bigben
->
report
->
id
,
buf
,
len
,
bigben
->
report
->
type
,
HID_REQ_SET_REPORT
);
}
kfree
(
buf
);
}
}
static
int
hid_bigben_play_effect
(
struct
input_dev
*
dev
,
void
*
data
,
static
int
hid_bigben_play_effect
(
struct
input_dev
*
dev
,
void
*
data
,
...
@@ -228,6 +270,7 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
...
@@ -228,6 +270,7 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
struct
bigben_device
*
bigben
=
hid_get_drvdata
(
hid
);
struct
bigben_device
*
bigben
=
hid_get_drvdata
(
hid
);
u8
right_motor_on
;
u8
right_motor_on
;
u8
left_motor_force
;
u8
left_motor_force
;
unsigned
long
flags
;
if
(
!
bigben
)
{
if
(
!
bigben
)
{
hid_err
(
hid
,
"no device data
\n
"
);
hid_err
(
hid
,
"no device data
\n
"
);
...
@@ -242,10 +285,13 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
...
@@ -242,10 +285,13 @@ static int hid_bigben_play_effect(struct input_dev *dev, void *data,
if
(
right_motor_on
!=
bigben
->
right_motor_on
||
if
(
right_motor_on
!=
bigben
->
right_motor_on
||
left_motor_force
!=
bigben
->
left_motor_force
)
{
left_motor_force
!=
bigben
->
left_motor_force
)
{
spin_lock_irqsave
(
&
bigben
->
lock
,
flags
);
bigben
->
right_motor_on
=
right_motor_on
;
bigben
->
right_motor_on
=
right_motor_on
;
bigben
->
left_motor_force
=
left_motor_force
;
bigben
->
left_motor_force
=
left_motor_force
;
bigben
->
work_ff
=
true
;
bigben
->
work_ff
=
true
;
schedule_work
(
&
bigben
->
worker
);
spin_unlock_irqrestore
(
&
bigben
->
lock
,
flags
);
bigben_schedule_work
(
bigben
);
}
}
return
0
;
return
0
;
...
@@ -259,6 +305,7 @@ static void bigben_set_led(struct led_classdev *led,
...
@@ -259,6 +305,7 @@ static void bigben_set_led(struct led_classdev *led,
struct
bigben_device
*
bigben
=
hid_get_drvdata
(
hid
);
struct
bigben_device
*
bigben
=
hid_get_drvdata
(
hid
);
int
n
;
int
n
;
bool
work
;
bool
work
;
unsigned
long
flags
;
if
(
!
bigben
)
{
if
(
!
bigben
)
{
hid_err
(
hid
,
"no device data
\n
"
);
hid_err
(
hid
,
"no device data
\n
"
);
...
@@ -267,6 +314,7 @@ static void bigben_set_led(struct led_classdev *led,
...
@@ -267,6 +314,7 @@ static void bigben_set_led(struct led_classdev *led,
for
(
n
=
0
;
n
<
NUM_LEDS
;
n
++
)
{
for
(
n
=
0
;
n
<
NUM_LEDS
;
n
++
)
{
if
(
led
==
bigben
->
leds
[
n
])
{
if
(
led
==
bigben
->
leds
[
n
])
{
spin_lock_irqsave
(
&
bigben
->
lock
,
flags
);
if
(
value
==
LED_OFF
)
{
if
(
value
==
LED_OFF
)
{
work
=
(
bigben
->
led_state
&
BIT
(
n
));
work
=
(
bigben
->
led_state
&
BIT
(
n
));
bigben
->
led_state
&=
~
BIT
(
n
);
bigben
->
led_state
&=
~
BIT
(
n
);
...
@@ -274,10 +322,11 @@ static void bigben_set_led(struct led_classdev *led,
...
@@ -274,10 +322,11 @@ static void bigben_set_led(struct led_classdev *led,
work
=
!
(
bigben
->
led_state
&
BIT
(
n
));
work
=
!
(
bigben
->
led_state
&
BIT
(
n
));
bigben
->
led_state
|=
BIT
(
n
);
bigben
->
led_state
|=
BIT
(
n
);
}
}
spin_unlock_irqrestore
(
&
bigben
->
lock
,
flags
);
if
(
work
)
{
if
(
work
)
{
bigben
->
work_led
=
true
;
bigben
->
work_led
=
true
;
schedule_work
(
&
bigben
->
worker
);
bigben_schedule_work
(
bigben
);
}
}
return
;
return
;
}
}
...
@@ -307,8 +356,12 @@ static enum led_brightness bigben_get_led(struct led_classdev *led)
...
@@ -307,8 +356,12 @@ static enum led_brightness bigben_get_led(struct led_classdev *led)
static
void
bigben_remove
(
struct
hid_device
*
hid
)
static
void
bigben_remove
(
struct
hid_device
*
hid
)
{
{
struct
bigben_device
*
bigben
=
hid_get_drvdata
(
hid
);
struct
bigben_device
*
bigben
=
hid_get_drvdata
(
hid
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
bigben
->
lock
,
flags
);
bigben
->
removed
=
true
;
bigben
->
removed
=
true
;
spin_unlock_irqrestore
(
&
bigben
->
lock
,
flags
);
cancel_work_sync
(
&
bigben
->
worker
);
cancel_work_sync
(
&
bigben
->
worker
);
hid_hw_stop
(
hid
);
hid_hw_stop
(
hid
);
}
}
...
@@ -318,7 +371,6 @@ static int bigben_probe(struct hid_device *hid,
...
@@ -318,7 +371,6 @@ static int bigben_probe(struct hid_device *hid,
{
{
struct
bigben_device
*
bigben
;
struct
bigben_device
*
bigben
;
struct
hid_input
*
hidinput
;
struct
hid_input
*
hidinput
;
struct
list_head
*
report_list
;
struct
led_classdev
*
led
;
struct
led_classdev
*
led
;
char
*
name
;
char
*
name
;
size_t
name_sz
;
size_t
name_sz
;
...
@@ -343,14 +395,12 @@ static int bigben_probe(struct hid_device *hid,
...
@@ -343,14 +395,12 @@ static int bigben_probe(struct hid_device *hid,
return
error
;
return
error
;
}
}
report_list
=
&
hid
->
report_enum
[
HID_OUTPUT_REPORT
].
report_list
;
bigben
->
report
=
hid_validate_values
(
hid
,
HID_OUTPUT_REPORT
,
0
,
0
,
8
)
;
if
(
list_empty
(
report_list
)
)
{
if
(
!
bigben
->
report
)
{
hid_err
(
hid
,
"no output report found
\n
"
);
hid_err
(
hid
,
"no output report found
\n
"
);
error
=
-
ENODEV
;
error
=
-
ENODEV
;
goto
error_hw_stop
;
goto
error_hw_stop
;
}
}
bigben
->
report
=
list_entry
(
report_list
->
next
,
struct
hid_report
,
list
);
if
(
list_empty
(
&
hid
->
inputs
))
{
if
(
list_empty
(
&
hid
->
inputs
))
{
hid_err
(
hid
,
"no inputs found
\n
"
);
hid_err
(
hid
,
"no inputs found
\n
"
);
...
@@ -362,6 +412,7 @@ static int bigben_probe(struct hid_device *hid,
...
@@ -362,6 +412,7 @@ static int bigben_probe(struct hid_device *hid,
set_bit
(
FF_RUMBLE
,
hidinput
->
input
->
ffbit
);
set_bit
(
FF_RUMBLE
,
hidinput
->
input
->
ffbit
);
INIT_WORK
(
&
bigben
->
worker
,
bigben_worker
);
INIT_WORK
(
&
bigben
->
worker
,
bigben_worker
);
spin_lock_init
(
&
bigben
->
lock
);
error
=
input_ff_create_memless
(
hidinput
->
input
,
NULL
,
error
=
input_ff_create_memless
(
hidinput
->
input
,
NULL
,
hid_bigben_play_effect
);
hid_bigben_play_effect
);
...
@@ -402,7 +453,7 @@ static int bigben_probe(struct hid_device *hid,
...
@@ -402,7 +453,7 @@ static int bigben_probe(struct hid_device *hid,
bigben
->
left_motor_force
=
0
;
bigben
->
left_motor_force
=
0
;
bigben
->
work_led
=
true
;
bigben
->
work_led
=
true
;
bigben
->
work_ff
=
true
;
bigben
->
work_ff
=
true
;
schedule_work
(
&
bigben
->
worker
);
bigben_schedule_work
(
bigben
);
hid_info
(
hid
,
"LED and force feedback support for BigBen gamepad
\n
"
);
hid_info
(
hid
,
"LED and force feedback support for BigBen gamepad
\n
"
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录