xref: /linux/drivers/hid/hid-rapoo.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
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