Root/drivers/hid/hid-zydacron.c

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 = kzalloc(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        goto err_free;
184    }
185
186    ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
187    if (ret) {
188        hid_err(hdev, "hw start failed\n");
189        goto err_free;
190    }
191
192    return 0;
193err_free:
194    kfree(zc);
195
196    return ret;
197}
198
199static void zc_remove(struct hid_device *hdev)
200{
201    struct zc_device *zc = hid_get_drvdata(hdev);
202
203    hid_hw_stop(hdev);
204    kfree(zc);
205}
206
207static const struct hid_device_id zc_devices[] = {
208    { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
209    { }
210};
211MODULE_DEVICE_TABLE(hid, zc_devices);
212
213static struct hid_driver zc_driver = {
214    .name = "zydacron",
215    .id_table = zc_devices,
216    .report_fixup = zc_report_fixup,
217    .input_mapping = zc_input_mapping,
218    .raw_event = zc_raw_event,
219    .probe = zc_probe,
220    .remove = zc_remove,
221};
222
223static int __init zc_init(void)
224{
225    return hid_register_driver(&zc_driver);
226}
227
228static void __exit zc_exit(void)
229{
230    hid_unregister_driver(&zc_driver);
231}
232
233module_init(zc_init);
234module_exit(zc_exit);
235MODULE_LICENSE("GPL");
236

Archive Download this file



interactive