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 const __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 (size < 2) 118 return 0; 119 120 if (report->id == data[0] && (hdev->claimed & HID_CLAIMED_INPUT)) { 121 122 /* break keys */ 123 for (index = 0; index < 4; index++) { 124 key = zc->last_key[index]; 125 if (key) { 126 input_event(zc->input_ep81, EV_KEY, key, 0); 127 zc->last_key[index] = 0; 128 } 129 } 130 131 key = 0; 132 switch (report->id) { 133 case 0x02: 134 case 0x03: 135 switch (data[1]) { 136 case 0x10: 137 key = KEY_MODE; 138 index = 0; 139 break; 140 case 0x30: 141 key = KEY_SCREEN; 142 index = 1; 143 break; 144 case 0x70: 145 key = KEY_INFO; 146 index = 2; 147 break; 148 case 0x04: 149 key = KEY_RADIO; 150 index = 3; 151 break; 152 } 153 154 if (key) { 155 input_event(zc->input_ep81, EV_KEY, key, 1); 156 zc->last_key[index] = key; 157 } 158 159 ret = 1; 160 break; 161 } 162 } 163 164 return ret; 165 } 166 167 static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id) 168 { 169 int ret; 170 struct zc_device *zc; 171 172 zc = devm_kzalloc(&hdev->dev, sizeof(*zc), GFP_KERNEL); 173 if (zc == NULL) { 174 hid_err(hdev, "can't alloc descriptor\n"); 175 return -ENOMEM; 176 } 177 178 hid_set_drvdata(hdev, zc); 179 180 ret = hid_parse(hdev); 181 if (ret) { 182 hid_err(hdev, "parse failed\n"); 183 return ret; 184 } 185 186 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 187 if (ret) { 188 hid_err(hdev, "hw start failed\n"); 189 return ret; 190 } 191 192 return 0; 193 } 194 195 static const struct hid_device_id zc_devices[] = { 196 { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, 197 { } 198 }; 199 MODULE_DEVICE_TABLE(hid, zc_devices); 200 201 static struct hid_driver zc_driver = { 202 .name = "zydacron", 203 .id_table = zc_devices, 204 .report_fixup = zc_report_fixup, 205 .input_mapping = zc_input_mapping, 206 .raw_event = zc_raw_event, 207 .probe = zc_probe, 208 }; 209 module_hid_driver(zc_driver); 210 211 MODULE_DESCRIPTION("HID driver for zydacron remote control"); 212 MODULE_LICENSE("GPL"); 213