|
1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | 2 | /* |
3 | 3 | * HID driver for CMedia CM6533 audio jack controls |
| 4 | + * and HS100B mute buttons |
4 | 5 | * |
5 | 6 | * Copyright (C) 2015 Ben Chen <ben_chen@bizlinktech.com> |
| 7 | + * Copyright (C) 2021 Thomas Weißschuh <linux@weissschuh.net> |
6 | 8 | */ |
7 | 9 |
|
8 | 10 | #include <linux/device.h> |
|
11 | 13 | #include "hid-ids.h" |
12 | 14 |
|
13 | 15 | MODULE_AUTHOR("Ben Chen"); |
14 | | -MODULE_DESCRIPTION("CM6533 HID jack controls"); |
| 16 | +MODULE_AUTHOR("Thomas Weißschuh"); |
| 17 | +MODULE_DESCRIPTION("CM6533 HID jack controls and HS100B mute button"); |
15 | 18 | MODULE_LICENSE("GPL"); |
16 | 19 |
|
17 | 20 | #define CM6533_JD_TYPE_COUNT 1 |
18 | 21 | #define CM6533_JD_RAWEV_LEN 16 |
19 | 22 | #define CM6533_JD_SFX_OFFSET 8 |
20 | 23 |
|
| 24 | +#define HS100B_RDESC_ORIG_SIZE 60 |
| 25 | + |
| 26 | +/* Fixed report descriptor of HS-100B audio chip |
| 27 | + * Bit 4 is an abolute Microphone mute usage instead of being unassigned. |
| 28 | + */ |
| 29 | +static __u8 hs100b_rdesc_fixed[] = { |
| 30 | + 0x05, 0x0C, /* Usage Page (Consumer), */ |
| 31 | + 0x09, 0x01, /* Usage (Consumer Control), */ |
| 32 | + 0xA1, 0x01, /* Collection (Application), */ |
| 33 | + 0x15, 0x00, /* Logical Minimum (0), */ |
| 34 | + 0x25, 0x01, /* Logical Maximum (1), */ |
| 35 | + 0x09, 0xE9, /* Usage (Volume Inc), */ |
| 36 | + 0x09, 0xEA, /* Usage (Volume Dec), */ |
| 37 | + 0x75, 0x01, /* Report Size (1), */ |
| 38 | + 0x95, 0x02, /* Report Count (2), */ |
| 39 | + 0x81, 0x02, /* Input (Variable), */ |
| 40 | + 0x09, 0xE2, /* Usage (Mute), */ |
| 41 | + 0x95, 0x01, /* Report Count (1), */ |
| 42 | + 0x81, 0x06, /* Input (Variable, Relative), */ |
| 43 | + 0x05, 0x0B, /* Usage Page (Telephony), */ |
| 44 | + 0x09, 0x2F, /* Usage (2Fh), */ |
| 45 | + 0x81, 0x02, /* Input (Variable), */ |
| 46 | + 0x09, 0x20, /* Usage (20h), */ |
| 47 | + 0x81, 0x06, /* Input (Variable, Relative), */ |
| 48 | + 0x05, 0x0C, /* Usage Page (Consumer), */ |
| 49 | + 0x09, 0x00, /* Usage (00h), */ |
| 50 | + 0x95, 0x03, /* Report Count (3), */ |
| 51 | + 0x81, 0x02, /* Input (Variable), */ |
| 52 | + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ |
| 53 | + 0x09, 0x00, /* Usage (00h), */ |
| 54 | + 0x75, 0x08, /* Report Size (8), */ |
| 55 | + 0x95, 0x03, /* Report Count (3), */ |
| 56 | + 0x81, 0x02, /* Input (Variable), */ |
| 57 | + 0x09, 0x00, /* Usage (00h), */ |
| 58 | + 0x95, 0x04, /* Report Count (4), */ |
| 59 | + 0x91, 0x02, /* Output (Variable), */ |
| 60 | + 0xC0 /* End Collection */ |
| 61 | +}; |
| 62 | + |
21 | 63 | /* |
22 | 64 | * |
23 | 65 | *CM6533 audio jack HID raw events: |
@@ -156,5 +198,49 @@ static struct hid_driver cmhid_driver = { |
156 | 198 | .remove = cmhid_remove, |
157 | 199 | .input_mapping = cmhid_input_mapping, |
158 | 200 | }; |
159 | | -module_hid_driver(cmhid_driver); |
160 | 201 |
|
| 202 | +static __u8 *cmhid_hs100b_report_fixup(struct hid_device *hid, __u8 *rdesc, |
| 203 | + unsigned int *rsize) |
| 204 | +{ |
| 205 | + if (*rsize == HS100B_RDESC_ORIG_SIZE) { |
| 206 | + hid_info(hid, "Fixing CMedia HS-100B report descriptor\n"); |
| 207 | + rdesc = hs100b_rdesc_fixed; |
| 208 | + *rsize = sizeof(hs100b_rdesc_fixed); |
| 209 | + } |
| 210 | + return rdesc; |
| 211 | +} |
| 212 | + |
| 213 | +static const struct hid_device_id cmhid_hs100b_devices[] = { |
| 214 | + { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CMEDIA_HS100B) }, |
| 215 | + { } |
| 216 | +}; |
| 217 | +MODULE_DEVICE_TABLE(hid, cmhid_hs100b_devices); |
| 218 | + |
| 219 | +static struct hid_driver cmhid_hs100b_driver = { |
| 220 | + .name = "cmedia_hs100b", |
| 221 | + .id_table = cmhid_hs100b_devices, |
| 222 | + .report_fixup = cmhid_hs100b_report_fixup, |
| 223 | +}; |
| 224 | + |
| 225 | +static int cmedia_init(void) |
| 226 | +{ |
| 227 | + int ret; |
| 228 | + |
| 229 | + ret = hid_register_driver(&cmhid_driver); |
| 230 | + if (ret) |
| 231 | + return ret; |
| 232 | + |
| 233 | + ret = hid_register_driver(&cmhid_hs100b_driver); |
| 234 | + if (ret) |
| 235 | + hid_unregister_driver(&cmhid_driver); |
| 236 | + |
| 237 | + return ret; |
| 238 | +} |
| 239 | +module_init(cmedia_init); |
| 240 | + |
| 241 | +static void cmedia_exit(void) |
| 242 | +{ |
| 243 | + hid_unregister_driver(&cmhid_driver); |
| 244 | + hid_unregister_driver(&cmhid_hs100b_driver); |
| 245 | +} |
| 246 | +module_exit(cmedia_exit); |
0 commit comments