aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerry Junge <terry.junge@plantronics.com>2015-06-08 17:27:57 -0400
committerJiri Kosina <jkosina@suse.cz>2015-06-12 09:04:17 -0400
commit81bb773faed7f5f0e82f14cdfcfe4e89fbea0e19 (patch)
tree0dbc8bd289f8b2db60b97ee235fce711f926163a
parent6efdb114b430000b6b96d5beb78cd1345d4513dd (diff)
HID: plantronics: Update to map volume up/down controls
Update Kconfig with enhanced help text for hid-plantronics driver. Update hid-plantronics.c to identify device type and correctly map either the vendor unique or consumer control volume up/down usages to KEY_VOLUMEUP and KEY_VOLUMEDOWN events. Unmapped usages are ignored to prevent core mapping of unknown usages to random mouse events. Tested on ChromeBox/ChromeBook with various Plantronics devices. Signed-off-by: Terry Junge <terry.junge@plantronics.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/Kconfig7
-rw-r--r--drivers/hid/hid-plantronics.c132
2 files changed, 130 insertions, 9 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 15338afdf7f9..cc4c6649d195 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -634,7 +634,12 @@ config HID_PLANTRONICS
634 tristate "Plantronics USB HID Driver" 634 tristate "Plantronics USB HID Driver"
635 depends on HID 635 depends on HID
636 ---help--- 636 ---help---
637 Provides HID support for Plantronics telephony devices. 637 Provides HID support for Plantronics USB audio devices.
638 Correctly maps vendor unique volume up/down HID usages to
639 KEY_VOLUMEUP and KEY_VOLUMEDOWN events and prevents core mapping
640 of other vendor unique HID usages to random mouse events.
641
642 Say M here if you may ever plug in a Plantronics USB audio device.
638 643
639config HID_PRIMAX 644config HID_PRIMAX
640 tristate "Primax non-fully HID-compliant devices" 645 tristate "Primax non-fully HID-compliant devices"
diff --git a/drivers/hid/hid-plantronics.c b/drivers/hid/hid-plantronics.c
index 2180e0789b76..febb21ee190e 100644
--- a/drivers/hid/hid-plantronics.c
+++ b/drivers/hid/hid-plantronics.c
@@ -2,7 +2,7 @@
2 * Plantronics USB HID Driver 2 * Plantronics USB HID Driver
3 * 3 *
4 * Copyright (c) 2014 JD Cole <jd.cole@plantronics.com> 4 * Copyright (c) 2014 JD Cole <jd.cole@plantronics.com>
5 * Copyright (c) 2014 Terry Junge <terry.junge@plantronics.com> 5 * Copyright (c) 2015 Terry Junge <terry.junge@plantronics.com>
6 */ 6 */
7 7
8/* 8/*
@@ -17,23 +17,138 @@
17#include <linux/hid.h> 17#include <linux/hid.h>
18#include <linux/module.h> 18#include <linux/module.h>
19 19
20#define PLT_HID_1_0_PAGE 0xffa00000
21#define PLT_HID_2_0_PAGE 0xffa20000
22
23#define PLT_BASIC_TELEPHONY 0x0003
24#define PLT_BASIC_EXCEPTION 0x0005
25
26#define PLT_VOL_UP 0x00b1
27#define PLT_VOL_DOWN 0x00b2
28
29#define PLT1_VOL_UP (PLT_HID_1_0_PAGE | PLT_VOL_UP)
30#define PLT1_VOL_DOWN (PLT_HID_1_0_PAGE | PLT_VOL_DOWN)
31#define PLT2_VOL_UP (PLT_HID_2_0_PAGE | PLT_VOL_UP)
32#define PLT2_VOL_DOWN (PLT_HID_2_0_PAGE | PLT_VOL_DOWN)
33
34#define PLT_DA60 0xda60
35#define PLT_BT300_MIN 0x0413
36#define PLT_BT300_MAX 0x0418
37
38
39#define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \
40 (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
41
20static int plantronics_input_mapping(struct hid_device *hdev, 42static int plantronics_input_mapping(struct hid_device *hdev,
21 struct hid_input *hi, 43 struct hid_input *hi,
22 struct hid_field *field, 44 struct hid_field *field,
23 struct hid_usage *usage, 45 struct hid_usage *usage,
24 unsigned long **bit, int *max) 46 unsigned long **bit, int *max)
25{ 47{
26 if (field->application == HID_CP_CONSUMERCONTROL 48 unsigned short mapped_key;
27 && (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) { 49 unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev);
28 hid_dbg(hdev, "usage: %08x (appl: %08x) - defaulted\n", 50
29 usage->hid, field->application); 51 /* handle volume up/down mapping */
30 return 0; 52 /* non-standard types or multi-HID interfaces - plt_type is PID */
53 if (!(plt_type & HID_USAGE_PAGE)) {
54 switch (plt_type) {
55 case PLT_DA60:
56 if (PLT_ALLOW_CONSUMER)
57 goto defaulted;
58 goto ignored;
59 default:
60 if (PLT_ALLOW_CONSUMER)
61 goto defaulted;
62 }
63 }
64 /* handle standard types - plt_type is 0xffa0uuuu or 0xffa2uuuu */
65 /* 'basic telephony compliant' - allow default consumer page map */
66 else if ((plt_type & HID_USAGE) >= PLT_BASIC_TELEPHONY &&
67 (plt_type & HID_USAGE) != PLT_BASIC_EXCEPTION) {
68 if (PLT_ALLOW_CONSUMER)
69 goto defaulted;
70 }
71 /* not 'basic telephony' - apply legacy mapping */
72 /* only map if the field is in the device's primary vendor page */
73 else if (!((field->application ^ plt_type) & HID_USAGE_PAGE)) {
74 switch (usage->hid) {
75 case PLT1_VOL_UP:
76 case PLT2_VOL_UP:
77 mapped_key = KEY_VOLUMEUP;
78 goto mapped;
79 case PLT1_VOL_DOWN:
80 case PLT2_VOL_DOWN:
81 mapped_key = KEY_VOLUMEDOWN;
82 goto mapped;
83 }
31 } 84 }
32 85
33 hid_dbg(hdev, "usage: %08x (appl: %08x) - ignored\n", 86/*
34 usage->hid, field->application); 87 * Future mapping of call control or other usages,
88 * if and when keys are defined would go here
89 * otherwise, ignore everything else that was not mapped
90 */
35 91
92ignored:
36 return -1; 93 return -1;
94
95defaulted:
96 hid_dbg(hdev, "usage: %08x (appl: %08x) - defaulted\n",
97 usage->hid, field->application);
98 return 0;
99
100mapped:
101 hid_map_usage_clear(hi, usage, bit, max, EV_KEY, mapped_key);
102 hid_dbg(hdev, "usage: %08x (appl: %08x) - mapped to key %d\n",
103 usage->hid, field->application, mapped_key);
104 return 1;
105}
106
107static unsigned long plantronics_device_type(struct hid_device *hdev)
108{
109 unsigned i, col_page;
110 unsigned long plt_type = hdev->product;
111
112 /* multi-HID interfaces? - plt_type is PID */
113 if (plt_type >= PLT_BT300_MIN && plt_type <= PLT_BT300_MAX)
114 goto exit;
115
116 /* determine primary vendor page */
117 for (i = 0; i < hdev->maxcollection; i++) {
118 col_page = hdev->collection[i].usage & HID_USAGE_PAGE;
119 if (col_page == PLT_HID_2_0_PAGE) {
120 plt_type = hdev->collection[i].usage;
121 break;
122 }
123 if (col_page == PLT_HID_1_0_PAGE)
124 plt_type = hdev->collection[i].usage;
125 }
126
127exit:
128 hid_dbg(hdev, "plt_type decoded as: %08lx\n", plt_type);
129 return plt_type;
130}
131
132static int plantronics_probe(struct hid_device *hdev,
133 const struct hid_device_id *id)
134{
135 int ret;
136
137 ret = hid_parse(hdev);
138 if (ret) {
139 hid_err(hdev, "parse failed\n");
140 goto err;
141 }
142
143 hid_set_drvdata(hdev, (void *)plantronics_device_type(hdev));
144
145 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
146 HID_CONNECT_HIDINPUT_FORCE | HID_CONNECT_HIDDEV_FORCE);
147 if (ret)
148 hid_err(hdev, "hw start failed\n");
149
150err:
151 return ret;
37} 152}
38 153
39static const struct hid_device_id plantronics_devices[] = { 154static const struct hid_device_id plantronics_devices[] = {
@@ -46,6 +161,7 @@ static struct hid_driver plantronics_driver = {
46 .name = "plantronics", 161 .name = "plantronics",
47 .id_table = plantronics_devices, 162 .id_table = plantronics_devices,
48 .input_mapping = plantronics_input_mapping, 163 .input_mapping = plantronics_input_mapping,
164 .probe = plantronics_probe,
49}; 165};
50module_hid_driver(plantronics_driver); 166module_hid_driver(plantronics_driver);
51 167