^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * HID driver for some petalynx "special" devices
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 1999 Andreas Gal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (c) 2006-2007 Jiri Kosina
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (c) 2008 Jiri Slaby
^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) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/hid.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "hid-ids.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /* Petalynx Maxter Remote has maximum for consumer page set too low */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned int *rsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) rdesc[60] = 0xfa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) rdesc[40] = 0xfa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return rdesc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define pl_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) EV_KEY, (c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static int pl_input_mapping(struct hid_device *hdev, struct hid_input *hi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct hid_field *field, struct hid_usage *usage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned long **bit, int *max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) switch (usage->hid & HID_USAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) case 0x05a: pl_map_key_clear(KEY_TEXT); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) case 0x05b: pl_map_key_clear(KEY_RED); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) case 0x05c: pl_map_key_clear(KEY_GREEN); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) case 0x05d: pl_map_key_clear(KEY_YELLOW); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) case 0x05e: pl_map_key_clear(KEY_BLUE); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) switch (usage->hid & HID_USAGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) case 0x0f6: pl_map_key_clear(KEY_NEXT); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) case 0x0fa: pl_map_key_clear(KEY_BACK); break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) hdev->quirks |= HID_QUIRK_NOGET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ret = hid_parse(hdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) hid_err(hdev, "parse failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) hid_err(hdev, "hw start failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) goto err_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) err_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static const struct hid_device_id pl_devices[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) MODULE_DEVICE_TABLE(hid, pl_devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static struct hid_driver pl_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .name = "petalynx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .id_table = pl_devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .report_fixup = pl_report_fixup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .input_mapping = pl_input_mapping,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .probe = pl_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) module_hid_driver(pl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) MODULE_LICENSE("GPL");