1*b3b1c68fSNguyen Dinh Dang Duong // SPDX-License-Identifier: GPL-2.0 2*b3b1c68fSNguyen Dinh Dang Duong #include <asm-generic/errno-base.h> 3*b3b1c68fSNguyen Dinh Dang Duong #include <asm-generic/int-ll64.h> 4*b3b1c68fSNguyen Dinh Dang Duong #include <linux/bitops.h> 5*b3b1c68fSNguyen Dinh Dang Duong #include <linux/input.h> 6*b3b1c68fSNguyen Dinh Dang Duong #include <linux/input-event-codes.h> 7*b3b1c68fSNguyen Dinh Dang Duong #include <linux/module.h> 8*b3b1c68fSNguyen Dinh Dang Duong #include <linux/hid.h> 9*b3b1c68fSNguyen Dinh Dang Duong #include <linux/usb.h> 10*b3b1c68fSNguyen Dinh Dang Duong 11*b3b1c68fSNguyen Dinh Dang Duong #include "hid-ids.h" 12*b3b1c68fSNguyen Dinh Dang Duong 13*b3b1c68fSNguyen Dinh Dang Duong #define RAPOO_BTN_BACK 0x08 14*b3b1c68fSNguyen Dinh Dang Duong #define RAPOO_BTN_FORWARD 0x10 15*b3b1c68fSNguyen Dinh Dang Duong 16*b3b1c68fSNguyen Dinh Dang Duong static const struct hid_device_id rapoo_devices[] = { 17*b3b1c68fSNguyen Dinh Dang Duong { HID_USB_DEVICE(USB_VENDOR_ID_RAPOO, USB_DEVICE_ID_RAPOO_2_4G_RECEIVER) }, 18*b3b1c68fSNguyen Dinh Dang Duong { } 19*b3b1c68fSNguyen Dinh Dang Duong }; 20*b3b1c68fSNguyen Dinh Dang Duong MODULE_DEVICE_TABLE(hid, rapoo_devices); 21*b3b1c68fSNguyen Dinh Dang Duong 22*b3b1c68fSNguyen Dinh Dang Duong static int rapoo_probe(struct hid_device *hdev, const struct hid_device_id *id) 23*b3b1c68fSNguyen Dinh Dang Duong { 24*b3b1c68fSNguyen Dinh Dang Duong int ret; 25*b3b1c68fSNguyen Dinh Dang Duong struct input_dev *input; 26*b3b1c68fSNguyen Dinh Dang Duong 27*b3b1c68fSNguyen Dinh Dang Duong ret = hid_parse(hdev); 28*b3b1c68fSNguyen Dinh Dang Duong if (ret) { 29*b3b1c68fSNguyen Dinh Dang Duong hid_err(hdev, "parse failed\n"); 30*b3b1c68fSNguyen Dinh Dang Duong return ret; 31*b3b1c68fSNguyen Dinh Dang Duong } 32*b3b1c68fSNguyen Dinh Dang Duong 33*b3b1c68fSNguyen Dinh Dang Duong ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 34*b3b1c68fSNguyen Dinh Dang Duong if (ret) { 35*b3b1c68fSNguyen Dinh Dang Duong hid_err(hdev, "start failed\n"); 36*b3b1c68fSNguyen Dinh Dang Duong return ret; 37*b3b1c68fSNguyen Dinh Dang Duong } 38*b3b1c68fSNguyen Dinh Dang Duong 39*b3b1c68fSNguyen Dinh Dang Duong if (hdev->bus == BUS_USB) { 40*b3b1c68fSNguyen Dinh Dang Duong struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 41*b3b1c68fSNguyen Dinh Dang Duong 42*b3b1c68fSNguyen Dinh Dang Duong if (intf->cur_altsetting->desc.bInterfaceNumber != 1) 43*b3b1c68fSNguyen Dinh Dang Duong return 0; 44*b3b1c68fSNguyen Dinh Dang Duong } 45*b3b1c68fSNguyen Dinh Dang Duong 46*b3b1c68fSNguyen Dinh Dang Duong input = devm_input_allocate_device(&hdev->dev); 47*b3b1c68fSNguyen Dinh Dang Duong if (!input) 48*b3b1c68fSNguyen Dinh Dang Duong return -ENOMEM; 49*b3b1c68fSNguyen Dinh Dang Duong 50*b3b1c68fSNguyen Dinh Dang Duong input->name = "Rapoo 2.4G Wireless Mouse"; 51*b3b1c68fSNguyen Dinh Dang Duong input->phys = "rapoo/input1"; 52*b3b1c68fSNguyen Dinh Dang Duong input->id.bustype = hdev->bus; 53*b3b1c68fSNguyen Dinh Dang Duong input->id.vendor = hdev->vendor; 54*b3b1c68fSNguyen Dinh Dang Duong input->id.product = hdev->product; 55*b3b1c68fSNguyen Dinh Dang Duong input->id.version = hdev->version; 56*b3b1c68fSNguyen Dinh Dang Duong 57*b3b1c68fSNguyen Dinh Dang Duong __set_bit(EV_KEY, input->evbit); 58*b3b1c68fSNguyen Dinh Dang Duong __set_bit(KEY_BACK, input->keybit); 59*b3b1c68fSNguyen Dinh Dang Duong __set_bit(KEY_FORWARD, input->keybit); 60*b3b1c68fSNguyen Dinh Dang Duong 61*b3b1c68fSNguyen Dinh Dang Duong ret = input_register_device(input); 62*b3b1c68fSNguyen Dinh Dang Duong if (ret) 63*b3b1c68fSNguyen Dinh Dang Duong return ret; 64*b3b1c68fSNguyen Dinh Dang Duong 65*b3b1c68fSNguyen Dinh Dang Duong hid_set_drvdata(hdev, input); 66*b3b1c68fSNguyen Dinh Dang Duong 67*b3b1c68fSNguyen Dinh Dang Duong return ret; 68*b3b1c68fSNguyen Dinh Dang Duong } 69*b3b1c68fSNguyen Dinh Dang Duong 70*b3b1c68fSNguyen Dinh Dang Duong static int rapoo_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) 71*b3b1c68fSNguyen Dinh Dang Duong { 72*b3b1c68fSNguyen Dinh Dang Duong struct input_dev *input = hid_get_drvdata(hdev); 73*b3b1c68fSNguyen Dinh Dang Duong 74*b3b1c68fSNguyen Dinh Dang Duong if (!input) 75*b3b1c68fSNguyen Dinh Dang Duong return 0; 76*b3b1c68fSNguyen Dinh Dang Duong 77*b3b1c68fSNguyen Dinh Dang Duong if (report->id == 1 && size >= 2) { 78*b3b1c68fSNguyen Dinh Dang Duong u8 btn = data[1]; 79*b3b1c68fSNguyen Dinh Dang Duong 80*b3b1c68fSNguyen Dinh Dang Duong input_report_key(input, KEY_BACK, btn & RAPOO_BTN_BACK); 81*b3b1c68fSNguyen Dinh Dang Duong input_report_key(input, KEY_FORWARD, btn & RAPOO_BTN_FORWARD); 82*b3b1c68fSNguyen Dinh Dang Duong input_sync(input); 83*b3b1c68fSNguyen Dinh Dang Duong return 1; 84*b3b1c68fSNguyen Dinh Dang Duong } 85*b3b1c68fSNguyen Dinh Dang Duong 86*b3b1c68fSNguyen Dinh Dang Duong return 0; 87*b3b1c68fSNguyen Dinh Dang Duong } 88*b3b1c68fSNguyen Dinh Dang Duong 89*b3b1c68fSNguyen Dinh Dang Duong static struct hid_driver rapoo_driver = { 90*b3b1c68fSNguyen Dinh Dang Duong .name = "hid-rapoo", 91*b3b1c68fSNguyen Dinh Dang Duong .id_table = rapoo_devices, 92*b3b1c68fSNguyen Dinh Dang Duong .probe = rapoo_probe, 93*b3b1c68fSNguyen Dinh Dang Duong .raw_event = rapoo_raw_event, 94*b3b1c68fSNguyen Dinh Dang Duong }; 95*b3b1c68fSNguyen Dinh Dang Duong 96*b3b1c68fSNguyen Dinh Dang Duong module_hid_driver(rapoo_driver); 97*b3b1c68fSNguyen Dinh Dang Duong 98*b3b1c68fSNguyen Dinh Dang Duong MODULE_LICENSE("GPL"); 99*b3b1c68fSNguyen Dinh Dang Duong MODULE_AUTHOR("Nguyen Dinh Dang Duong <dangduong31205@gmail.com>"); 100*b3b1c68fSNguyen Dinh Dang Duong MODULE_DESCRIPTION("RAPOO 2.4G Wireless Device Driver"); 101*b3b1c68fSNguyen Dinh Dang Duong 102