Merge branch 'for-5.13/plantronics' into for-linus
- Workaround for broken behavior of Plantronics Blackwire from Maxim Mikityanskiy
This commit is contained in:
Коммит
cfc9bdfb6b
|
@ -955,6 +955,7 @@
|
|||
#define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S 0x8003
|
||||
|
||||
#define USB_VENDOR_ID_PLANTRONICS 0x047f
|
||||
#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES 0xc056
|
||||
|
||||
#define USB_VENDOR_ID_PANASONIC 0x04da
|
||||
#define USB_DEVICE_ID_PANABOARD_UBT780 0x1044
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#define PLT_HID_1_0_PAGE 0xffa00000
|
||||
#define PLT_HID_2_0_PAGE 0xffa20000
|
||||
|
@ -36,6 +37,16 @@
|
|||
#define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \
|
||||
(usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
|
||||
|
||||
#define PLT_QUIRK_DOUBLE_VOLUME_KEYS BIT(0)
|
||||
|
||||
#define PLT_DOUBLE_KEY_TIMEOUT 5 /* ms */
|
||||
|
||||
struct plt_drv_data {
|
||||
unsigned long device_type;
|
||||
unsigned long last_volume_key_ts;
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
static int plantronics_input_mapping(struct hid_device *hdev,
|
||||
struct hid_input *hi,
|
||||
struct hid_field *field,
|
||||
|
@ -43,7 +54,8 @@ static int plantronics_input_mapping(struct hid_device *hdev,
|
|||
unsigned long **bit, int *max)
|
||||
{
|
||||
unsigned short mapped_key;
|
||||
unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev);
|
||||
struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
|
||||
unsigned long plt_type = drv_data->device_type;
|
||||
|
||||
/* special case for PTT products */
|
||||
if (field->application == HID_GD_JOYSTICK)
|
||||
|
@ -105,6 +117,30 @@ mapped:
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int plantronics_event(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
|
||||
|
||||
if (drv_data->quirks & PLT_QUIRK_DOUBLE_VOLUME_KEYS) {
|
||||
unsigned long prev_ts, cur_ts;
|
||||
|
||||
/* Usages are filtered in plantronics_usages. */
|
||||
|
||||
if (!value) /* Handle key presses only. */
|
||||
return 0;
|
||||
|
||||
prev_ts = drv_data->last_volume_key_ts;
|
||||
cur_ts = jiffies;
|
||||
if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_DOUBLE_KEY_TIMEOUT)
|
||||
return 1; /* Ignore the repeated key. */
|
||||
|
||||
drv_data->last_volume_key_ts = cur_ts;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long plantronics_device_type(struct hid_device *hdev)
|
||||
{
|
||||
unsigned i, col_page;
|
||||
|
@ -133,15 +169,24 @@ exit:
|
|||
static int plantronics_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
struct plt_drv_data *drv_data;
|
||||
int ret;
|
||||
|
||||
drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
hid_err(hdev, "parse failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
hid_set_drvdata(hdev, (void *)plantronics_device_type(hdev));
|
||||
drv_data->device_type = plantronics_device_type(hdev);
|
||||
drv_data->quirks = id->driver_data;
|
||||
drv_data->last_volume_key_ts = jiffies - msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT);
|
||||
|
||||
hid_set_drvdata(hdev, drv_data);
|
||||
|
||||
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
|
||||
HID_CONNECT_HIDINPUT_FORCE | HID_CONNECT_HIDDEV_FORCE);
|
||||
|
@ -153,15 +198,26 @@ err:
|
|||
}
|
||||
|
||||
static const struct hid_device_id plantronics_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS,
|
||||
USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES),
|
||||
.driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, plantronics_devices);
|
||||
|
||||
static const struct hid_usage_id plantronics_usages[] = {
|
||||
{ HID_CP_VOLUMEUP, EV_KEY, HID_ANY_ID },
|
||||
{ HID_CP_VOLUMEDOWN, EV_KEY, HID_ANY_ID },
|
||||
{ HID_TERMINATOR, HID_TERMINATOR, HID_TERMINATOR }
|
||||
};
|
||||
|
||||
static struct hid_driver plantronics_driver = {
|
||||
.name = "plantronics",
|
||||
.id_table = plantronics_devices,
|
||||
.usage_table = plantronics_usages,
|
||||
.input_mapping = plantronics_input_mapping,
|
||||
.event = plantronics_event,
|
||||
.probe = plantronics_probe,
|
||||
};
|
||||
module_hid_driver(plantronics_driver);
|
||||
|
|
|
@ -263,6 +263,8 @@ struct hid_item {
|
|||
#define HID_CP_SELECTION 0x000c0080
|
||||
#define HID_CP_MEDIASELECTION 0x000c0087
|
||||
#define HID_CP_SELECTDISC 0x000c00ba
|
||||
#define HID_CP_VOLUMEUP 0x000c00e9
|
||||
#define HID_CP_VOLUMEDOWN 0x000c00ea
|
||||
#define HID_CP_PLAYBACKSPEED 0x000c00f1
|
||||
#define HID_CP_PROXIMITY 0x000c0109
|
||||
#define HID_CP_SPEAKERSYSTEM 0x000c0160
|
||||
|
|
Загрузка…
Ссылка в новой задаче