1/* 2* HID driver for zydacron remote control 3* 4* Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk> 5*/ 6 7/* 8* This program is free software; you can redistribute it and/or modify it 9* under the terms of the GNU General Public License as published by the Free 10* Software Foundation; either version 2 of the License, or (at your option) 11* any later version. 12*/ 13 14#include <linux/device.h> 15#include <linux/hid.h> 16#include <linux/module.h> 17 18#include "hid-ids.h" 19 20struct zc_device { 21 struct input_dev *input_ep81; 22 unsigned short last_key[4]; 23}; 24 25 26/* 27* Zydacron remote control has an invalid HID report descriptor, 28* that needs fixing before we can parse it. 29*/ 30static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc, 31 unsigned int *rsize) 32{ 33 if (*rsize >= 253 && 34 rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff && 35 rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff && 36 rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) { 37 hid_info(hdev, 38 "fixing up zydacron remote control report descriptor\n"); 39 rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c; 40 rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00; 41 } 42 return rdesc; 43} 44 45#define zc_map_key_clear(c) \ 46 hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) 47 48static int zc_input_mapping(struct hid_device *hdev, struct hid_input *hi, 49 struct hid_field *field, struct hid_usage *usage, 50 unsigned long **bit, int *max) 51{ 52 int i; 53 struct zc_device *zc = hid_get_drvdata(hdev); 54 zc->input_ep81 = hi->input; 55 56 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) 57 return 0; 58 59 dbg_hid("zynacron input mapping event [0x%x]\n", 60 usage->hid & HID_USAGE); 61 62 switch (usage->hid & HID_USAGE) { 63 /* report 2 */ 64 case 0x10: 65 zc_map_key_clear(KEY_MODE); 66 break; 67 case 0x30: 68 zc_map_key_clear(KEY_SCREEN); 69 break; 70 case 0x70: 71 zc_map_key_clear(KEY_INFO); 72 break; 73 /* report 3 */ 74 case 0x04: 75 zc_map_key_clear(KEY_RADIO); 76 break; 77 /* report 4 */ 78 case 0x0d: 79 zc_map_key_clear(KEY_PVR); 80 break; 81 case 0x25: 82 zc_map_key_clear(KEY_TV); 83 break; 84 case 0x47: 85 zc_map_key_clear(KEY_AUDIO); 86 break; 87 case 0x49: 88 zc_map_key_clear(KEY_AUX); 89 break; 90 case 0x4a: 91 zc_map_key_clear(KEY_VIDEO); 92 break; 93 case 0x48: 94 zc_map_key_clear(KEY_DVD); 95 break; 96 case 0x24: 97 zc_map_key_clear(KEY_MENU); 98 break; 99 case 0x32: 100 zc_map_key_clear(KEY_TEXT); 101 break; 102 default: 103 return 0; 104 } 105 106 for (i = 0; i < 4; i++) 107 zc->last_key[i] = 0; 108 109 return 1; 110} 111 112static int zc_raw_event(struct hid_device *hdev, struct hid_report *report, 113 u8 *data, int size) 114{ 115 struct zc_device *zc = hid_get_drvdata(hdev); 116 int ret = 0; 117 unsigned key; 118 unsigned short index; 119 120 if (report->id == data[0]) { 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 167static 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 195static const struct hid_device_id zc_devices[] = { 196 { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, 197 { } 198}; 199MODULE_DEVICE_TABLE(hid, zc_devices); 200 201static 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}; 209module_hid_driver(zc_driver); 210 211MODULE_LICENSE("GPL"); 212