Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
54021f90
Commit
54021f90
authored
Nov 01, 2023
by
Jiri Kosina
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-6.7/logitech' into for-linus
- big cleanup of logitech-hidpp probe code (Hans de Goede)
parents
7601fef4
3e6b0bb2
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
63 additions
and
111 deletions
+63
-111
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-logitech-hidpp.c
+63
-111
No files found.
drivers/hid/hid-logitech-hidpp.c
View file @
54021f90
...
...
@@ -69,12 +69,11 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
#define HIDPP_QUIRK_DELAYED_INIT BIT(23)
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
#define HIDPP_QUIRK_UNIFYING BIT(25)
#define HIDPP_QUIRK_HIDPP_WHEELS BIT(26)
#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(27)
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(28)
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(29)
#define HIDPP_QUIRK_WIRELESS_STATUS BIT(30)
#define HIDPP_QUIRK_HIDPP_WHEELS BIT(25)
#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(26)
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(27)
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(28)
#define HIDPP_QUIRK_WIRELESS_STATUS BIT(29)
/* These are just aliases for now */
#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
...
...
@@ -194,7 +193,6 @@ struct hidpp_device {
struct
work_struct
work
;
struct
kfifo
delayed_work_fifo
;
atomic_t
connected
;
struct
input_dev
*
delayed_input
;
unsigned
long
quirks
;
...
...
@@ -235,8 +233,6 @@ struct hidpp_device {
#define HIDPP20_ERROR_UNSUPPORTED 0x09
#define HIDPP20_ERROR 0xff
static
void
hidpp_connect_event
(
struct
hidpp_device
*
hidpp_dev
);
static
int
__hidpp_send_report
(
struct
hid_device
*
hdev
,
struct
hidpp_report
*
hidpp_report
)
{
...
...
@@ -450,13 +446,6 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
return
ret
;
}
static
void
delayed_work_cb
(
struct
work_struct
*
work
)
{
struct
hidpp_device
*
hidpp
=
container_of
(
work
,
struct
hidpp_device
,
work
);
hidpp_connect_event
(
hidpp
);
}
static
inline
bool
hidpp_match_answer
(
struct
hidpp_report
*
question
,
struct
hidpp_report
*
answer
)
{
...
...
@@ -1835,15 +1824,14 @@ static int hidpp_battery_get_property(struct power_supply *psy,
/* -------------------------------------------------------------------------- */
#define HIDPP_PAGE_WIRELESS_DEVICE_STATUS 0x1d4b
static
int
hidpp_
set_wireless_feature_index
(
struct
hidpp_device
*
hidpp
)
static
int
hidpp_
get_wireless_feature_index
(
struct
hidpp_device
*
hidpp
,
u8
*
feature_index
)
{
u8
feature_type
;
int
ret
;
ret
=
hidpp_root_get_feature
(
hidpp
,
HIDPP_PAGE_WIRELESS_DEVICE_STATUS
,
&
hidpp
->
wireless_feature_index
,
&
feature_type
);
feature_index
,
&
feature_type
);
return
ret
;
}
...
...
@@ -3142,7 +3130,7 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id)
return
0
;
};
static
int
wtp_connect
(
struct
hid_device
*
hdev
,
bool
connected
)
static
int
wtp_connect
(
struct
hid_device
*
hdev
)
{
struct
hidpp_device
*
hidpp
=
hid_get_drvdata
(
hdev
);
struct
wtp_data
*
wd
=
hidpp
->
private_data
;
...
...
@@ -3204,7 +3192,7 @@ static const u8 m560_config_parameter[] = {0x00, 0xaf, 0x03};
#define M560_SUB_ID 0x0a
#define M560_BUTTON_MODE_REGISTER 0x35
static
int
m560_send_config_command
(
struct
hid_device
*
hdev
,
bool
connected
)
static
int
m560_send_config_command
(
struct
hid_device
*
hdev
)
{
struct
hidpp_report
response
;
struct
hidpp_device
*
hidpp_dev
;
...
...
@@ -3399,7 +3387,7 @@ static int k400_allocate(struct hid_device *hdev)
return
0
;
};
static
int
k400_connect
(
struct
hid_device
*
hdev
,
bool
connected
)
static
int
k400_connect
(
struct
hid_device
*
hdev
)
{
struct
hidpp_device
*
hidpp
=
hid_get_drvdata
(
hdev
);
...
...
@@ -3894,8 +3882,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
}
if
(
unlikely
(
hidpp_report_is_connect_event
(
hidpp
,
report
)))
{
atomic_set
(
&
hidpp
->
connected
,
!
(
report
->
rap
.
params
[
0
]
&
(
1
<<
6
)));
if
(
schedule_work
(
&
hidpp
->
work
)
==
0
)
dbg_hid
(
"%s: connect event already queued
\n
"
,
__func__
);
return
1
;
...
...
@@ -4131,24 +4117,22 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
return
ret
;
}
static
void
hidpp_overwrite_name
(
struct
hid_device
*
hdev
)
/* Get name + serial for USB and Bluetooth HID++ devices */
static
void
hidpp_non_unifying_init
(
struct
hidpp_device
*
hidpp
)
{
struct
hid
pp_device
*
hidpp
=
hid_get_drvdata
(
hdev
)
;
struct
hid
_device
*
hdev
=
hidpp
->
hid_dev
;
char
*
name
;
if
(
hidpp
->
protocol_major
<
2
)
return
;
/* Bluetooth devices already have their serialnr set */
if
(
hid_is_usb
(
hdev
))
hidpp_serial_init
(
hidpp
);
name
=
hidpp_get_device_name
(
hidpp
);
if
(
!
name
)
{
hid_err
(
hdev
,
"unable to retrieve the name of the device"
);
}
else
{
if
(
name
)
{
dbg_hid
(
"HID++: Got name: %s
\n
"
,
name
);
snprintf
(
hdev
->
name
,
sizeof
(
hdev
->
name
),
"%s"
,
name
);
}
kfree
(
name
);
}
}
static
int
hidpp_input_open
(
struct
input_dev
*
dev
)
...
...
@@ -4189,15 +4173,18 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
return
input_dev
;
}
static
void
hidpp_connect_event
(
struct
hidpp_device
*
hidpp
)
static
void
hidpp_connect_event
(
struct
work_struct
*
work
)
{
struct
hidpp_device
*
hidpp
=
container_of
(
work
,
struct
hidpp_device
,
work
);
struct
hid_device
*
hdev
=
hidpp
->
hid_dev
;
int
ret
=
0
;
bool
connected
=
atomic_read
(
&
hidpp
->
connected
);
struct
input_dev
*
input
;
char
*
name
,
*
devm_name
;
int
ret
;
if
(
!
connected
)
{
/* Get device version to check if it is connected */
ret
=
hidpp_root_get_protocol_version
(
hidpp
);
if
(
ret
)
{
hid_info
(
hidpp
->
hid_dev
,
"Disconnected
\n
"
);
if
(
hidpp
->
battery
.
ps
)
{
hidpp
->
battery
.
online
=
false
;
hidpp
->
battery
.
status
=
POWER_SUPPLY_STATUS_UNKNOWN
;
...
...
@@ -4208,15 +4195,15 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
}
if
(
hidpp
->
quirks
&
HIDPP_QUIRK_CLASS_WTP
)
{
ret
=
wtp_connect
(
hdev
,
connected
);
ret
=
wtp_connect
(
hdev
);
if
(
ret
)
return
;
}
else
if
(
hidpp
->
quirks
&
HIDPP_QUIRK_CLASS_M560
)
{
ret
=
m560_send_config_command
(
hdev
,
connected
);
ret
=
m560_send_config_command
(
hdev
);
if
(
ret
)
return
;
}
else
if
(
hidpp
->
quirks
&
HIDPP_QUIRK_CLASS_K400
)
{
ret
=
k400_connect
(
hdev
,
connected
);
ret
=
k400_connect
(
hdev
);
if
(
ret
)
return
;
}
...
...
@@ -4239,14 +4226,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
return
;
}
/* the device is already connected, we can ask for its name and
* protocol */
if
(
!
hidpp
->
protocol_major
)
{
ret
=
hidpp_root_get_protocol_version
(
hidpp
);
if
(
ret
)
{
hid_err
(
hdev
,
"Can not get the protocol version.
\n
"
);
return
;
}
if
(
hidpp
->
protocol_major
>=
2
)
{
u8
feature_index
;
if
(
!
hidpp_get_wireless_feature_index
(
hidpp
,
&
feature_index
))
hidpp
->
wireless_feature_index
=
feature_index
;
}
if
(
hidpp
->
name
==
hdev
->
name
&&
hidpp
->
protocol_major
>=
2
)
{
...
...
@@ -4391,10 +4375,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct
hidpp_device
*
hidpp
;
int
ret
;
bool
connected
;
unsigned
int
connect_mask
=
HID_CONNECT_DEFAULT
;
struct
hidpp_ff_private_data
data
;
bool
will_restart
=
false
;
/* report_fixup needs drvdata to be set before we call hid_parse */
hidpp
=
devm_kzalloc
(
&
hdev
->
dev
,
sizeof
(
*
hidpp
),
GFP_KERNEL
);
...
...
@@ -4423,9 +4404,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return
hid_hw_start
(
hdev
,
HID_CONNECT_DEFAULT
);
}
if
(
id
->
group
==
HID_GROUP_LOGITECH_DJ_DEVICE
)
hidpp
->
quirks
|=
HIDPP_QUIRK_UNIFYING
;
if
(
id
->
group
==
HID_GROUP_LOGITECH_27MHZ_DEVICE
&&
hidpp_application_equals
(
hdev
,
HID_GD_MOUSE
))
hidpp
->
quirks
|=
HIDPP_QUIRK_HIDPP_WHEELS
|
...
...
@@ -4445,11 +4423,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return
ret
;
}
if
(
hidpp
->
quirks
&
HIDPP_QUIRK_DELAYED_INIT
||
hidpp
->
quirks
&
HIDPP_QUIRK_UNIFYING
)
will_restart
=
true
;
INIT_WORK
(
&
hidpp
->
work
,
delayed_work_cb
);
INIT_WORK
(
&
hidpp
->
work
,
hidpp_connect_event
);
mutex_init
(
&
hidpp
->
send_mutex
);
init_waitqueue_head
(
&
hidpp
->
wait
);
...
...
@@ -4460,10 +4434,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev
->
name
);
/*
* Plain USB connections need to actually call start and open
* on the transport driver to allow incoming data.
* First call hid_hw_start(hdev, 0) to allow IO without connecting any
* hid subdrivers (hid-input, hidraw). This allows retrieving the dev's
* name and serial number and store these in hdev->name and hdev->uniq,
* before the hid-input and hidraw drivers expose these to userspace.
*/
ret
=
hid_hw_start
(
hdev
,
will_restart
?
0
:
connect_mask
);
ret
=
hid_hw_start
(
hdev
,
0
);
if
(
ret
)
{
hid_err
(
hdev
,
"hw start failed
\n
"
);
goto
hid_hw_start_fail
;
...
...
@@ -4479,70 +4455,46 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
/* Allow incoming packets */
hid_device_io_start
(
hdev
);
if
(
hidpp
->
quirks
&
HIDPP_QUIRK_UNIFYING
)
/* Get name + serial, store in hdev->name + hdev->uniq */
if
(
id
->
group
==
HID_GROUP_LOGITECH_DJ_DEVICE
)
hidpp_unifying_init
(
hidpp
);
else
if
(
hid_is_usb
(
hidpp
->
hid_dev
))
hidpp_serial_init
(
hidpp
);
connected
=
hidpp_root_get_protocol_version
(
hidpp
)
==
0
;
atomic_set
(
&
hidpp
->
connected
,
connected
);
if
(
!
(
hidpp
->
quirks
&
HIDPP_QUIRK_UNIFYING
))
{
if
(
!
connected
)
{
ret
=
-
ENODEV
;
hid_err
(
hdev
,
"Device not connected"
);
goto
hid_hw_init_fail
;
}
hidpp_overwrite_name
(
hdev
);
}
if
(
connected
&&
hidpp
->
protocol_major
>=
2
)
{
ret
=
hidpp_set_wireless_feature_index
(
hidpp
);
if
(
ret
==
-
ENOENT
)
hidpp
->
wireless_feature_index
=
0
;
else
if
(
ret
)
goto
hid_hw_init_fail
;
ret
=
0
;
}
if
(
connected
&&
(
hidpp
->
quirks
&
HIDPP_QUIRK_CLASS_WTP
))
{
ret
=
wtp_get_config
(
hidpp
);
if
(
ret
)
goto
hid_hw_init_fail
;
}
else
if
(
connected
&&
(
hidpp
->
quirks
&
HIDPP_QUIRK_CLASS_G920
))
{
ret
=
g920_get_config
(
hidpp
,
&
data
);
if
(
ret
)
goto
hid_hw_init_fail
;
}
schedule_work
(
&
hidpp
->
work
);
flush_work
(
&
hidpp
->
work
);
if
(
will_restart
)
{
/* Reset the HID node state */
hid_device_io_stop
(
hdev
);
hid_hw_close
(
hdev
);
hid_hw_stop
(
hdev
);
else
hidpp_non_unifying_init
(
hidpp
);
if
(
hidpp
->
quirks
&
HIDPP_QUIRK_DELAYED_INIT
)
connect_mask
&=
~
HID_CONNECT_HIDINPUT
;
/* Now export the actual inputs and hidraw nodes to the world */
ret
=
hid_hw_start
(
hdev
,
connect_mask
);
hid_device_io_stop
(
hdev
);
ret
=
hid_connect
(
hdev
,
connect_mask
);
if
(
ret
)
{
hid_err
(
hdev
,
"%s:hid_hw_start returned error
\n
"
,
__func__
);
goto
hid_hw_start_fail
;
}
hid_err
(
hdev
,
"%s:hid_connect returned error %d
\n
"
,
__func__
,
ret
);
goto
hid_hw_init_fail
;
}
/* Check for connected devices now that incoming packets will not be disabled again */
hid_device_io_start
(
hdev
);
schedule_work
(
&
hidpp
->
work
);
flush_work
(
&
hidpp
->
work
);
if
(
hidpp
->
quirks
&
HIDPP_QUIRK_CLASS_G920
)
{
struct
hidpp_ff_private_data
data
;
ret
=
g920_get_config
(
hidpp
,
&
data
);
if
(
!
ret
)
ret
=
hidpp_ff_init
(
hidpp
,
&
data
);
if
(
ret
)
hid_warn
(
hidpp
->
hid_dev
,
"Unable to initialize force feedback support, errno %d
\n
"
,
ret
);
}
/*
* This relies on logi_dj_ll_close() being a no-op so that DJ connection
* events will still be received.
*/
hid_hw_close
(
hdev
);
return
ret
;
hid_hw_init_fail:
...
...
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