162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * HID driver for some cherry "special" devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 1999 Andreas Gal 662306a36Sopenharmony_ci * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 762306a36Sopenharmony_ci * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 862306a36Sopenharmony_ci * Copyright (c) 2006-2007 Jiri Kosina 962306a36Sopenharmony_ci * Copyright (c) 2008 Jiri Slaby 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/device.h> 1662306a36Sopenharmony_ci#include <linux/hid.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "hid-ids.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * Cherry Cymotion keyboard have an invalid HID report descriptor, 2362306a36Sopenharmony_ci * that needs fixing before we can parse it. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_cistatic __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, 2662306a36Sopenharmony_ci unsigned int *rsize) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { 2962306a36Sopenharmony_ci hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n"); 3062306a36Sopenharmony_ci rdesc[11] = rdesc[16] = 0xff; 3162306a36Sopenharmony_ci rdesc[12] = rdesc[17] = 0x03; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci return rdesc; 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \ 3762306a36Sopenharmony_ci EV_KEY, (c)) 3862306a36Sopenharmony_cistatic int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, 3962306a36Sopenharmony_ci struct hid_field *field, struct hid_usage *usage, 4062306a36Sopenharmony_ci unsigned long **bit, int *max) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci switch (usage->hid & HID_USAGE) { 4662306a36Sopenharmony_ci case 0x301: ch_map_key_clear(KEY_PROG1); break; 4762306a36Sopenharmony_ci case 0x302: ch_map_key_clear(KEY_PROG2); break; 4862306a36Sopenharmony_ci case 0x303: ch_map_key_clear(KEY_PROG3); break; 4962306a36Sopenharmony_ci default: 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci return 1; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic const struct hid_device_id ch_devices[] = { 5762306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, 5862306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, 5962306a36Sopenharmony_ci { } 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, ch_devices); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic struct hid_driver ch_driver = { 6462306a36Sopenharmony_ci .name = "cherry", 6562306a36Sopenharmony_ci .id_table = ch_devices, 6662306a36Sopenharmony_ci .report_fixup = ch_report_fixup, 6762306a36Sopenharmony_ci .input_mapping = ch_input_mapping, 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_cimodule_hid_driver(ch_driver); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 72