Commit d0742abaa1c396a26bb3d3ce2732988cd3faa020

Authored by Jiri Kosina
1 parent b355850ba3

HID: add omitted hid-zydacron.c file

Commit a9885c8f7bf62e251fc178 ("HID: Zydacron Remote Control driver") added
hid-zydracon driver by Don Prince, but mistakenly omitted hid-zydracon.c
file itself. Properly add the file.

Reported-by: Don Prince <dhprince.devel@yahoo.co.uk>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

Showing 1 changed file with 237 additions and 0 deletions Side-by-side Diff

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 +
  20 +struct 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 +*/
  30 +static void 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 + dev_info(&hdev->dev,
  38 + "fixing up zydacron remote control report "
  39 + "descriptor\n");
  40 + rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
  41 + rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
  42 + }
  43 +}
  44 +
  45 +#define zc_map_key_clear(c) \
  46 + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
  47 +
  48 +static 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 +
  112 +static 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 +
  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 = kzalloc(sizeof(*zc), GFP_KERNEL);
  173 + if (zc == NULL) {
  174 + dev_err(&hdev->dev, "zydacron: 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 + dev_err(&hdev->dev, "zydacron: parse failed\n");
  183 + goto err_free;
  184 + }
  185 +
  186 + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
  187 + if (ret) {
  188 + dev_err(&hdev->dev, "zydacron: hw start failed\n");
  189 + goto err_free;
  190 + }
  191 +
  192 + return 0;
  193 +err_free:
  194 + kfree(zc);
  195 +
  196 + return ret;
  197 +}
  198 +
  199 +static void zc_remove(struct hid_device *hdev)
  200 +{
  201 + struct zc_device *zc = hid_get_drvdata(hdev);
  202 +
  203 + hid_hw_stop(hdev);
  204 +
  205 + if (NULL != zc)
  206 + kfree(zc);
  207 +}
  208 +
  209 +static const struct hid_device_id zc_devices[] = {
  210 + { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
  211 + { }
  212 +};
  213 +MODULE_DEVICE_TABLE(hid, zc_devices);
  214 +
  215 +static struct hid_driver zc_driver = {
  216 + .name = "zydacron",
  217 + .id_table = zc_devices,
  218 + .report_fixup = zc_report_fixup,
  219 + .input_mapping = zc_input_mapping,
  220 + .raw_event = zc_raw_event,
  221 + .probe = zc_probe,
  222 + .remove = zc_remove,
  223 +};
  224 +
  225 +static int __init zc_init(void)
  226 +{
  227 + return hid_register_driver(&zc_driver);
  228 +}
  229 +
  230 +static void __exit zc_exit(void)
  231 +{
  232 + hid_unregister_driver(&zc_driver);
  233 +}
  234 +
  235 +module_init(zc_init);
  236 +module_exit(zc_exit);
  237 +MODULE_LICENSE("GPL");