linux/drivers/hid/hid-zydacron.c
<<
>>
Prefs
   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
  17struct 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*/
  27static __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
  45static 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
 109static 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
 164static 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
 192static const struct hid_device_id zc_devices[] = {
 193        { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
 194        { }
 195};
 196MODULE_DEVICE_TABLE(hid, zc_devices);
 197
 198static 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};
 206module_hid_driver(zc_driver);
 207
 208MODULE_LICENSE("GPL");
 209