Skip to content

Commit cfc9bdf

Browse files
author
Jiri Kosina
committed
Merge branch 'for-5.13/plantronics' into for-linus
- Workaround for broken behavior of Plantronics Blackwire from Maxim Mikityanskiy
2 parents 275ac61 + f567d6e commit cfc9bdf

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,7 @@
955955
#define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S 0x8003
956956

957957
#define USB_VENDOR_ID_PLANTRONICS 0x047f
958+
#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES 0xc056
958959

959960
#define USB_VENDOR_ID_PANASONIC 0x04da
960961
#define USB_DEVICE_ID_PANABOARD_UBT780 0x1044

drivers/hid/hid-plantronics.c

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <linux/hid.h>
1515
#include <linux/module.h>
16+
#include <linux/jiffies.h>
1617

1718
#define PLT_HID_1_0_PAGE 0xffa00000
1819
#define PLT_HID_2_0_PAGE 0xffa20000
@@ -36,14 +37,25 @@
3637
#define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \
3738
(usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
3839

40+
#define PLT_QUIRK_DOUBLE_VOLUME_KEYS BIT(0)
41+
42+
#define PLT_DOUBLE_KEY_TIMEOUT 5 /* ms */
43+
44+
struct plt_drv_data {
45+
unsigned long device_type;
46+
unsigned long last_volume_key_ts;
47+
u32 quirks;
48+
};
49+
3950
static int plantronics_input_mapping(struct hid_device *hdev,
4051
struct hid_input *hi,
4152
struct hid_field *field,
4253
struct hid_usage *usage,
4354
unsigned long **bit, int *max)
4455
{
4556
unsigned short mapped_key;
46-
unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev);
57+
struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
58+
unsigned long plt_type = drv_data->device_type;
4759

4860
/* special case for PTT products */
4961
if (field->application == HID_GD_JOYSTICK)
@@ -105,6 +117,30 @@ static int plantronics_input_mapping(struct hid_device *hdev,
105117
return 1;
106118
}
107119

120+
static int plantronics_event(struct hid_device *hdev, struct hid_field *field,
121+
struct hid_usage *usage, __s32 value)
122+
{
123+
struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
124+
125+
if (drv_data->quirks & PLT_QUIRK_DOUBLE_VOLUME_KEYS) {
126+
unsigned long prev_ts, cur_ts;
127+
128+
/* Usages are filtered in plantronics_usages. */
129+
130+
if (!value) /* Handle key presses only. */
131+
return 0;
132+
133+
prev_ts = drv_data->last_volume_key_ts;
134+
cur_ts = jiffies;
135+
if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_DOUBLE_KEY_TIMEOUT)
136+
return 1; /* Ignore the repeated key. */
137+
138+
drv_data->last_volume_key_ts = cur_ts;
139+
}
140+
141+
return 0;
142+
}
143+
108144
static unsigned long plantronics_device_type(struct hid_device *hdev)
109145
{
110146
unsigned i, col_page;
@@ -133,15 +169,24 @@ static unsigned long plantronics_device_type(struct hid_device *hdev)
133169
static int plantronics_probe(struct hid_device *hdev,
134170
const struct hid_device_id *id)
135171
{
172+
struct plt_drv_data *drv_data;
136173
int ret;
137174

175+
drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL);
176+
if (!drv_data)
177+
return -ENOMEM;
178+
138179
ret = hid_parse(hdev);
139180
if (ret) {
140181
hid_err(hdev, "parse failed\n");
141182
goto err;
142183
}
143184

144-
hid_set_drvdata(hdev, (void *)plantronics_device_type(hdev));
185+
drv_data->device_type = plantronics_device_type(hdev);
186+
drv_data->quirks = id->driver_data;
187+
drv_data->last_volume_key_ts = jiffies - msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT);
188+
189+
hid_set_drvdata(hdev, drv_data);
145190

146191
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
147192
HID_CONNECT_HIDINPUT_FORCE | HID_CONNECT_HIDDEV_FORCE);
@@ -153,15 +198,26 @@ static int plantronics_probe(struct hid_device *hdev,
153198
}
154199

155200
static const struct hid_device_id plantronics_devices[] = {
201+
{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS,
202+
USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES),
203+
.driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS },
156204
{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
157205
{ }
158206
};
159207
MODULE_DEVICE_TABLE(hid, plantronics_devices);
160208

209+
static const struct hid_usage_id plantronics_usages[] = {
210+
{ HID_CP_VOLUMEUP, EV_KEY, HID_ANY_ID },
211+
{ HID_CP_VOLUMEDOWN, EV_KEY, HID_ANY_ID },
212+
{ HID_TERMINATOR, HID_TERMINATOR, HID_TERMINATOR }
213+
};
214+
161215
static struct hid_driver plantronics_driver = {
162216
.name = "plantronics",
163217
.id_table = plantronics_devices,
218+
.usage_table = plantronics_usages,
164219
.input_mapping = plantronics_input_mapping,
220+
.event = plantronics_event,
165221
.probe = plantronics_probe,
166222
};
167223
module_hid_driver(plantronics_driver);

include/linux/hid.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ struct hid_item {
263263
#define HID_CP_SELECTION 0x000c0080
264264
#define HID_CP_MEDIASELECTION 0x000c0087
265265
#define HID_CP_SELECTDISC 0x000c00ba
266+
#define HID_CP_VOLUMEUP 0x000c00e9
267+
#define HID_CP_VOLUMEDOWN 0x000c00ea
266268
#define HID_CP_PLAYBACKSPEED 0x000c00f1
267269
#define HID_CP_PROXIMITY 0x000c0109
268270
#define HID_CP_SPEAKERSYSTEM 0x000c0160

0 commit comments

Comments
 (0)