mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 00:48:50 +00:00
2874c5fd28
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 3029 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070032.746973796@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
208 lines
3.9 KiB
C
208 lines
3.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* HID driver for zydacron remote control
|
|
*
|
|
* Copyright (c) 2010 Don Prince <dhprince.devel@yahoo.co.uk>
|
|
*/
|
|
|
|
/*
|
|
*/
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/hid.h>
|
|
#include <linux/module.h>
|
|
|
|
#include "hid-ids.h"
|
|
|
|
struct zc_device {
|
|
struct input_dev *input_ep81;
|
|
unsigned short last_key[4];
|
|
};
|
|
|
|
|
|
/*
|
|
* Zydacron remote control has an invalid HID report descriptor,
|
|
* that needs fixing before we can parse it.
|
|
*/
|
|
static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|
unsigned int *rsize)
|
|
{
|
|
if (*rsize >= 253 &&
|
|
rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
|
|
rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
|
|
rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
|
|
hid_info(hdev,
|
|
"fixing up zydacron remote control report descriptor\n");
|
|
rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
|
|
rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
|
|
}
|
|
return rdesc;
|
|
}
|
|
|
|
#define zc_map_key_clear(c) \
|
|
hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
|
|
|
|
static int zc_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
struct hid_field *field, struct hid_usage *usage,
|
|
unsigned long **bit, int *max)
|
|
{
|
|
int i;
|
|
struct zc_device *zc = hid_get_drvdata(hdev);
|
|
zc->input_ep81 = hi->input;
|
|
|
|
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
|
|
return 0;
|
|
|
|
dbg_hid("zynacron input mapping event [0x%x]\n",
|
|
usage->hid & HID_USAGE);
|
|
|
|
switch (usage->hid & HID_USAGE) {
|
|
/* report 2 */
|
|
case 0x10:
|
|
zc_map_key_clear(KEY_MODE);
|
|
break;
|
|
case 0x30:
|
|
zc_map_key_clear(KEY_SCREEN);
|
|
break;
|
|
case 0x70:
|
|
zc_map_key_clear(KEY_INFO);
|
|
break;
|
|
/* report 3 */
|
|
case 0x04:
|
|
zc_map_key_clear(KEY_RADIO);
|
|
break;
|
|
/* report 4 */
|
|
case 0x0d:
|
|
zc_map_key_clear(KEY_PVR);
|
|
break;
|
|
case 0x25:
|
|
zc_map_key_clear(KEY_TV);
|
|
break;
|
|
case 0x47:
|
|
zc_map_key_clear(KEY_AUDIO);
|
|
break;
|
|
case 0x49:
|
|
zc_map_key_clear(KEY_AUX);
|
|
break;
|
|
case 0x4a:
|
|
zc_map_key_clear(KEY_VIDEO);
|
|
break;
|
|
case 0x48:
|
|
zc_map_key_clear(KEY_DVD);
|
|
break;
|
|
case 0x24:
|
|
zc_map_key_clear(KEY_MENU);
|
|
break;
|
|
case 0x32:
|
|
zc_map_key_clear(KEY_TEXT);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
zc->last_key[i] = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
|
|
u8 *data, int size)
|
|
{
|
|
struct zc_device *zc = hid_get_drvdata(hdev);
|
|
int ret = 0;
|
|
unsigned key;
|
|
unsigned short index;
|
|
|
|
if (report->id == data[0]) {
|
|
|
|
/* break keys */
|
|
for (index = 0; index < 4; index++) {
|
|
key = zc->last_key[index];
|
|
if (key) {
|
|
input_event(zc->input_ep81, EV_KEY, key, 0);
|
|
zc->last_key[index] = 0;
|
|
}
|
|
}
|
|
|
|
key = 0;
|
|
switch (report->id) {
|
|
case 0x02:
|
|
case 0x03:
|
|
switch (data[1]) {
|
|
case 0x10:
|
|
key = KEY_MODE;
|
|
index = 0;
|
|
break;
|
|
case 0x30:
|
|
key = KEY_SCREEN;
|
|
index = 1;
|
|
break;
|
|
case 0x70:
|
|
key = KEY_INFO;
|
|
index = 2;
|
|
break;
|
|
case 0x04:
|
|
key = KEY_RADIO;
|
|
index = 3;
|
|
break;
|
|
}
|
|
|
|
if (key) {
|
|
input_event(zc->input_ep81, EV_KEY, key, 1);
|
|
zc->last_key[index] = key;
|
|
}
|
|
|
|
ret = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
{
|
|
int ret;
|
|
struct zc_device *zc;
|
|
|
|
zc = devm_kzalloc(&hdev->dev, sizeof(*zc), GFP_KERNEL);
|
|
if (zc == NULL) {
|
|
hid_err(hdev, "can't alloc descriptor\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
hid_set_drvdata(hdev, zc);
|
|
|
|
ret = hid_parse(hdev);
|
|
if (ret) {
|
|
hid_err(hdev, "parse failed\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
|
if (ret) {
|
|
hid_err(hdev, "hw start failed\n");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct hid_device_id zc_devices[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(hid, zc_devices);
|
|
|
|
static struct hid_driver zc_driver = {
|
|
.name = "zydacron",
|
|
.id_table = zc_devices,
|
|
.report_fixup = zc_report_fixup,
|
|
.input_mapping = zc_input_mapping,
|
|
.raw_event = zc_raw_event,
|
|
.probe = zc_probe,
|
|
};
|
|
module_hid_driver(zc_driver);
|
|
|
|
MODULE_LICENSE("GPL");
|