1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * HID driver for zydacron remote control 4 * 5 * Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk> 6 */ 7 8 /* 9 */ 10 11 #include <linux/device.h> 12 #include <linux/hid.h> 13 #include <linux/module.h> 14 15 #include "hid-ids.h" 16 17 struct zc_device { 18 struct input_dev *input_ep81; 19 unsigned short last_key[4]; 20 }; 21 22 23 /* 24 * Zydacron remote control has an invalid HID report descriptor, 25 * that needs fixing before we can parse it. 26 */ 27 static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc, 28 unsigned int *rsize) 29 { 30 if (*rsize >= 253 && 31 rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff && 32 rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff && 33 rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) { 34 hid_info(hdev, 35 "fixing up zydacron remote control report descriptor\n"); 36 rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c; 37 rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00; 38 } 39 return rdesc; 40 } 41 42 #define zc_map_key_clear(c) \ 43 hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 44 45 static int zc_input_mapping(struct hid_device *hdev, struct hid_input *hi, 46 struct hid_field *field, struct hid_usage *usage, 47 unsigned long **bit, int *max) 48 { 49 int i; 50 struct zc_device *zc = hid_get_drvdata(hdev); 51 zc->input_ep81 = hi->input; 52 53 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) 54 return 0; 55 56 dbg_hid("zynacron input mapping event [0x%x]\n", 57 usage->hid & HID_USAGE); 58 59 switch (usage->hid & HID_USAGE) { 60 /* report 2 */ 61 case 0x10: 62 zc_map_key_clear(KEY_MODE); 63 break; 64 case 0x30: 65 zc_map_key_clear(KEY_SCREEN); 66 break; 67 case 0x70: 68 zc_map_key_clear(KEY_INFO); 69 break; 70 /* report 3 */ 71 case 0x04: 72 zc_map_key_clear(KEY_RADIO); 73 break; 74 /* report 4 */ 75 case 0x0d: 76 zc_map_key_clear(KEY_PVR); 77 break; 78 case 0x25: 79 zc_map_key_clear(KEY_TV); 80 break; 81 case 0x47: 82 zc_map_key_clear(KEY_AUDIO); 83 break; 84 case 0x49: 85 zc_map_key_clear(KEY_AUX); 86 break; 87 case 0x4a: 88 zc_map_key_clear(KEY_VIDEO); 89 break; 90 case 0x48: 91 zc_map_key_clear(KEY_DVD); 92 break; 93 case 0x24: 94 zc_map_key_clear(KEY_MENU); 95 break; 96 case 0x32: 97 zc_map_key_clear(KEY_TEXT); 98 break; 99 default: 100 return 0; 101 } 102 103 for (i = 0; i < 4; i++) 104 zc->last_key[i] = 0; 105 106 return 1; 107 } 108 109 static int zc_raw_event(struct hid_device *hdev, struct hid_report *report, 110 u8 *data, int size) 111 { 112 struct zc_device *zc = hid_get_drvdata(hdev); 113 int ret = 0; 114 unsigned key; 115 unsigned short index; 116 117 if (report->id == data[0]) { 118 119 /* break keys */ 120 for (index = 0; index < 4; index++) { 121 key = zc->last_key[index]; 122 if (key) { 123 input_event(zc->input_ep81, EV_KEY, key, 0); 124 zc->last_key[index] = 0; 125 } 126 } 127 128 key = 0; 129 switch (report->id) { 130 case 0x02: 131 case 0x03: 132 switch (data[1]) { 133 case 0x10: 134 key = KEY_MODE; 135 index = 0; 136 break; 137 case 0x30: 138 key = KEY_SCREEN; 139 index = 1; 140 break; 141 case 0x70: 142 key = KEY_INFO; 143 index = 2; 144 break; 145 case 0x04: 146 key = KEY_RADIO; 147 index = 3; 148 break; 149 } 150 151 if (key) { 152 input_event(zc->input_ep81, EV_KEY, key, 1); 153 zc->last_key[index] = key; 154 } 155 156 ret = 1; 157 break; 158 } 159 } 160 161 return ret; 162 } 163 164 static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id) 165 { 166 int ret; 167 struct zc_device *zc; 168 169 zc = devm_kzalloc(&hdev->dev, sizeof(*zc), GFP_KERNEL); 170 if (zc == NULL) { 171 hid_err(hdev, "can't alloc descriptor\n"); 172 return -ENOMEM; 173 } 174 175 hid_set_drvdata(hdev, zc); 176 177 ret = hid_parse(hdev); 178 if (ret) { 179 hid_err(hdev, "parse failed\n"); 180 return ret; 181 } 182 183 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 184 if (ret) { 185 hid_err(hdev, "hw start failed\n"); 186 return ret; 187 } 188 189 return 0; 190 } 191 192 static const struct hid_device_id zc_devices[] = { 193 { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, 194 { } 195 }; 196 MODULE_DEVICE_TABLE(hid, zc_devices); 197 198 static struct hid_driver zc_driver = { 199 .name = "zydacron", 200 .id_table = zc_devices, 201 .report_fixup = zc_report_fixup, 202 .input_mapping = zc_input_mapping, 203 .raw_event = zc_raw_event, 204 .probe = zc_probe, 205 }; 206 module_hid_driver(zc_driver); 207 208 MODULE_DESCRIPTION("HID driver for zydacron remote control"); 209 MODULE_LICENSE("GPL"); 210