^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * HID driver for TwinHan IR remote control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Based on hid-gyration.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2009 Bruno Prémont <bonbons@linux-vserver.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/hid.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "hid-ids.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* Remote control key layout + listing:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * Full Screen Power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * KEY_SCREEN KEY_POWER2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * 1 2 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * KEY_NUMERIC_1 KEY_NUMERIC_2 KEY_NUMERIC_3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * 4 5 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * KEY_NUMERIC_4 KEY_NUMERIC_5 KEY_NUMERIC_6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * 7 8 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * KEY_NUMERIC_7 KEY_NUMERIC_8 KEY_NUMERIC_9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * REC 0 Favorite
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * KEY_RECORD KEY_NUMERIC_0 KEY_FAVORITES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Rewind Forward
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * KEY_REWIND CH+ KEY_FORWARD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * KEY_CHANNELUP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * VOL- > VOL+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * KEY_VOLUMEDOWN KEY_PLAY KEY_VOLUMEUP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * CH-
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * KEY_CHANNELDOWN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Recall Stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * KEY_RESTART KEY_STOP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * Timeshift/Pause Mute Cancel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * KEY_PAUSE KEY_MUTE KEY_CANCEL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * Capture Preview EPG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * KEY_PRINT KEY_PROGRAM KEY_EPG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * Record List Tab Teletext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * KEY_LIST KEY_TAB KEY_TEXT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define th_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) EV_KEY, (c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int twinhan_input_mapping(struct hid_device *hdev, struct hid_input *hi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct hid_field *field, struct hid_usage *usage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long **bit, int *max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if ((usage->hid & HID_USAGE_PAGE) != HID_UP_KEYBOARD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) switch (usage->hid & HID_USAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* Map all keys from Twinhan Remote */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) case 0x004: th_map_key_clear(KEY_TEXT); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) case 0x006: th_map_key_clear(KEY_RESTART); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) case 0x008: th_map_key_clear(KEY_EPG); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) case 0x00c: th_map_key_clear(KEY_REWIND); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) case 0x00e: th_map_key_clear(KEY_PROGRAM); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) case 0x00f: th_map_key_clear(KEY_LIST); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) case 0x010: th_map_key_clear(KEY_MUTE); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) case 0x011: th_map_key_clear(KEY_FORWARD); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) case 0x013: th_map_key_clear(KEY_PRINT); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) case 0x017: th_map_key_clear(KEY_PAUSE); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) case 0x019: th_map_key_clear(KEY_FAVORITES); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) case 0x01d: th_map_key_clear(KEY_SCREEN); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) case 0x01e: th_map_key_clear(KEY_NUMERIC_1); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) case 0x01f: th_map_key_clear(KEY_NUMERIC_2); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) case 0x020: th_map_key_clear(KEY_NUMERIC_3); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) case 0x021: th_map_key_clear(KEY_NUMERIC_4); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) case 0x022: th_map_key_clear(KEY_NUMERIC_5); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) case 0x023: th_map_key_clear(KEY_NUMERIC_6); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) case 0x024: th_map_key_clear(KEY_NUMERIC_7); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) case 0x025: th_map_key_clear(KEY_NUMERIC_8); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) case 0x026: th_map_key_clear(KEY_NUMERIC_9); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case 0x027: th_map_key_clear(KEY_NUMERIC_0); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) case 0x028: th_map_key_clear(KEY_PLAY); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) case 0x029: th_map_key_clear(KEY_CANCEL); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case 0x02b: th_map_key_clear(KEY_TAB); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* Power = 0x0e0 + 0x0e1 + 0x0e2 + 0x03f */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case 0x03f: th_map_key_clear(KEY_POWER2); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) case 0x04a: th_map_key_clear(KEY_RECORD); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case 0x04b: th_map_key_clear(KEY_CHANNELUP); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case 0x04d: th_map_key_clear(KEY_STOP); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case 0x04e: th_map_key_clear(KEY_CHANNELDOWN); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* Volume down = 0x0e1 + 0x051 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) case 0x051: th_map_key_clear(KEY_VOLUMEDOWN); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* Volume up = 0x0e1 + 0x052 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) case 0x052: th_map_key_clear(KEY_VOLUMEUP); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* Kill the extra keys used for multi-key "power" and "volume" keys
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * as well as continuously to release CTRL,ALT,META,... keys */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) case 0x0e0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) case 0x0e1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) case 0x0e2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) case 0x0e3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) case 0x0e4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) case 0x0e5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) case 0x0e6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) case 0x0e7:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static const struct hid_device_id twinhan_devices[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) MODULE_DEVICE_TABLE(hid, twinhan_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static struct hid_driver twinhan_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .name = "twinhan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .id_table = twinhan_devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .input_mapping = twinhan_input_mapping,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) module_hid_driver(twinhan_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) MODULE_LICENSE("GPL");