Skip to content

Commit f567d6e

Browse files
gentoo-rootJiri Kosina
authored andcommitted
HID: plantronics: Workaround for double volume key presses
Plantronics Blackwire 3220 Series (047f:c056) sends HID reports twice for each volume key press. This patch adds a quirk to hid-plantronics for this product ID, which will ignore the second volume key press if it happens within 5 ms from the last one that was handled. The patch was tested on the mentioned model only, it shouldn't affect other models, however, this quirk might be needed for them too. Auto-repeat (when a key is held pressed) is not affected, because the rate is about 3 times per second, which is far less frequent than once in 5 ms. Fixes: 81bb773 ("HID: plantronics: Update to map volume up/down controls") Signed-off-by: Maxim Mikityanskiy <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 69aea9d commit f567d6e

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
@@ -944,6 +944,7 @@
944944
#define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S 0x8003
945945

946946
#define USB_VENDOR_ID_PLANTRONICS 0x047f
947+
#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES 0xc056
947948

948949
#define USB_VENDOR_ID_PANASONIC 0x04da
949950
#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
@@ -262,6 +262,8 @@ struct hid_item {
262262
#define HID_CP_SELECTION 0x000c0080
263263
#define HID_CP_MEDIASELECTION 0x000c0087
264264
#define HID_CP_SELECTDISC 0x000c00ba
265+
#define HID_CP_VOLUMEUP 0x000c00e9
266+
#define HID_CP_VOLUMEDOWN 0x000c00ea
265267
#define HID_CP_PLAYBACKSPEED 0x000c00f1
266268
#define HID_CP_PROXIMITY 0x000c0109
267269
#define HID_CP_SPEAKERSYSTEM 0x000c0160

0 commit comments

Comments
 (0)