xref: /linux/drivers/hid/hid-a4tech.c (revision b7e1b2039de3a028fba46fbaca58a45c23a417ec)
114a21cd4SJiri Slaby /*
214a21cd4SJiri Slaby  *  HID driver for some a4tech "special" devices
314a21cd4SJiri Slaby  *
414a21cd4SJiri Slaby  *  Copyright (c) 1999 Andreas Gal
514a21cd4SJiri Slaby  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
614a21cd4SJiri Slaby  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
714a21cd4SJiri Slaby  *  Copyright (c) 2006-2007 Jiri Kosina
814a21cd4SJiri Slaby  *  Copyright (c) 2007 Paul Walmsley
914a21cd4SJiri Slaby  *  Copyright (c) 2008 Jiri Slaby
1014a21cd4SJiri Slaby  */
1114a21cd4SJiri Slaby 
1214a21cd4SJiri Slaby /*
1314a21cd4SJiri Slaby  * This program is free software; you can redistribute it and/or modify it
1414a21cd4SJiri Slaby  * under the terms of the GNU General Public License as published by the Free
1514a21cd4SJiri Slaby  * Software Foundation; either version 2 of the License, or (at your option)
1614a21cd4SJiri Slaby  * any later version.
1714a21cd4SJiri Slaby  */
1814a21cd4SJiri Slaby 
1914a21cd4SJiri Slaby #include <linux/device.h>
2014a21cd4SJiri Slaby #include <linux/input.h>
2114a21cd4SJiri Slaby #include <linux/hid.h>
2214a21cd4SJiri Slaby #include <linux/module.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
2414a21cd4SJiri Slaby 
2514a21cd4SJiri Slaby #include "hid-ids.h"
2614a21cd4SJiri Slaby 
2714a21cd4SJiri Slaby #define A4_2WHEEL_MOUSE_HACK_7	0x01
2814a21cd4SJiri Slaby #define A4_2WHEEL_MOUSE_HACK_B8	0x02
2914a21cd4SJiri Slaby 
3014a21cd4SJiri Slaby struct a4tech_sc {
3114a21cd4SJiri Slaby 	unsigned long quirks;
3214a21cd4SJiri Slaby 	unsigned int hw_wheel;
3314a21cd4SJiri Slaby 	__s32 delayed_value;
3414a21cd4SJiri Slaby };
3514a21cd4SJiri Slaby 
3614a21cd4SJiri Slaby static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
3714a21cd4SJiri Slaby 		struct hid_field *field, struct hid_usage *usage,
3814a21cd4SJiri Slaby 		unsigned long **bit, int *max)
3914a21cd4SJiri Slaby {
4014a21cd4SJiri Slaby 	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
4114a21cd4SJiri Slaby 
4214a21cd4SJiri Slaby 	if (usage->type == EV_REL && usage->code == REL_WHEEL)
4314a21cd4SJiri Slaby 		set_bit(REL_HWHEEL, *bit);
4414a21cd4SJiri Slaby 
4514a21cd4SJiri Slaby 	if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
4614a21cd4SJiri Slaby 		return -1;
4714a21cd4SJiri Slaby 
4814a21cd4SJiri Slaby 	return 0;
4914a21cd4SJiri Slaby }
5014a21cd4SJiri Slaby 
5114a21cd4SJiri Slaby static int a4_event(struct hid_device *hdev, struct hid_field *field,
5214a21cd4SJiri Slaby 		struct hid_usage *usage, __s32 value)
5314a21cd4SJiri Slaby {
5414a21cd4SJiri Slaby 	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
5514a21cd4SJiri Slaby 	struct input_dev *input;
5614a21cd4SJiri Slaby 
5714a21cd4SJiri Slaby 	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
5814a21cd4SJiri Slaby 			!usage->type)
5914a21cd4SJiri Slaby 		return 0;
6014a21cd4SJiri Slaby 
6114a21cd4SJiri Slaby 	input = field->hidinput->input;
6214a21cd4SJiri Slaby 
6314a21cd4SJiri Slaby 	if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
6414a21cd4SJiri Slaby 		if (usage->type == EV_REL && usage->code == REL_WHEEL) {
6514a21cd4SJiri Slaby 			a4->delayed_value = value;
6614a21cd4SJiri Slaby 			return 1;
6714a21cd4SJiri Slaby 		}
6814a21cd4SJiri Slaby 
6914a21cd4SJiri Slaby 		if (usage->hid == 0x000100b8) {
7014a21cd4SJiri Slaby 			input_event(input, EV_REL, value ? REL_HWHEEL :
7114a21cd4SJiri Slaby 					REL_WHEEL, a4->delayed_value);
7214a21cd4SJiri Slaby 			return 1;
7314a21cd4SJiri Slaby 		}
7414a21cd4SJiri Slaby 	}
7514a21cd4SJiri Slaby 
7614a21cd4SJiri Slaby 	if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {
7714a21cd4SJiri Slaby 		a4->hw_wheel = !!value;
7814a21cd4SJiri Slaby 		return 1;
7914a21cd4SJiri Slaby 	}
8014a21cd4SJiri Slaby 
8114a21cd4SJiri Slaby 	if (usage->code == REL_WHEEL && a4->hw_wheel) {
8214a21cd4SJiri Slaby 		input_event(input, usage->type, REL_HWHEEL, value);
8314a21cd4SJiri Slaby 		return 1;
8414a21cd4SJiri Slaby 	}
8514a21cd4SJiri Slaby 
8614a21cd4SJiri Slaby 	return 0;
8714a21cd4SJiri Slaby }
8814a21cd4SJiri Slaby 
8914a21cd4SJiri Slaby static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
9014a21cd4SJiri Slaby {
9114a21cd4SJiri Slaby 	struct a4tech_sc *a4;
9214a21cd4SJiri Slaby 	int ret;
9314a21cd4SJiri Slaby 
9414a21cd4SJiri Slaby 	a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
9514a21cd4SJiri Slaby 	if (a4 == NULL) {
9614a21cd4SJiri Slaby 		dev_err(&hdev->dev, "can't alloc device descriptor\n");
9714a21cd4SJiri Slaby 		ret = -ENOMEM;
9814a21cd4SJiri Slaby 		goto err_free;
9914a21cd4SJiri Slaby 	}
10014a21cd4SJiri Slaby 
10114a21cd4SJiri Slaby 	a4->quirks = id->driver_data;
10214a21cd4SJiri Slaby 
10314a21cd4SJiri Slaby 	hid_set_drvdata(hdev, a4);
10414a21cd4SJiri Slaby 
10514a21cd4SJiri Slaby 	ret = hid_parse(hdev);
10614a21cd4SJiri Slaby 	if (ret) {
10714a21cd4SJiri Slaby 		dev_err(&hdev->dev, "parse failed\n");
10814a21cd4SJiri Slaby 		goto err_free;
10914a21cd4SJiri Slaby 	}
11014a21cd4SJiri Slaby 
11193c10132SJiri Slaby 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
11214a21cd4SJiri Slaby 	if (ret) {
11314a21cd4SJiri Slaby 		dev_err(&hdev->dev, "hw start failed\n");
11414a21cd4SJiri Slaby 		goto err_free;
11514a21cd4SJiri Slaby 	}
11614a21cd4SJiri Slaby 
11714a21cd4SJiri Slaby 	return 0;
11814a21cd4SJiri Slaby err_free:
11914a21cd4SJiri Slaby 	kfree(a4);
12014a21cd4SJiri Slaby 	return ret;
12114a21cd4SJiri Slaby }
12214a21cd4SJiri Slaby 
12314a21cd4SJiri Slaby static void a4_remove(struct hid_device *hdev)
12414a21cd4SJiri Slaby {
12514a21cd4SJiri Slaby 	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
12614a21cd4SJiri Slaby 
12714a21cd4SJiri Slaby 	hid_hw_stop(hdev);
12814a21cd4SJiri Slaby 	kfree(a4);
12914a21cd4SJiri Slaby }
13014a21cd4SJiri Slaby 
13114a21cd4SJiri Slaby static const struct hid_device_id a4_devices[] = {
13214a21cd4SJiri Slaby 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),
13314a21cd4SJiri Slaby 		.driver_data = A4_2WHEEL_MOUSE_HACK_7 },
13414a21cd4SJiri Slaby 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
13514a21cd4SJiri Slaby 		.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
136*b7e1b203SLech Perczak 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649),
137*b7e1b203SLech Perczak 		.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
13814a21cd4SJiri Slaby 	{ }
13914a21cd4SJiri Slaby };
14014a21cd4SJiri Slaby MODULE_DEVICE_TABLE(hid, a4_devices);
14114a21cd4SJiri Slaby 
14214a21cd4SJiri Slaby static struct hid_driver a4_driver = {
14314a21cd4SJiri Slaby 	.name = "a4tech",
14414a21cd4SJiri Slaby 	.id_table = a4_devices,
14514a21cd4SJiri Slaby 	.input_mapped = a4_input_mapped,
14614a21cd4SJiri Slaby 	.event = a4_event,
14714a21cd4SJiri Slaby 	.probe = a4_probe,
14814a21cd4SJiri Slaby 	.remove = a4_remove,
14914a21cd4SJiri Slaby };
15014a21cd4SJiri Slaby 
151a24f423bSPeter Huewe static int __init a4_init(void)
15214a21cd4SJiri Slaby {
15314a21cd4SJiri Slaby 	return hid_register_driver(&a4_driver);
15414a21cd4SJiri Slaby }
15514a21cd4SJiri Slaby 
156a24f423bSPeter Huewe static void __exit a4_exit(void)
15714a21cd4SJiri Slaby {
15814a21cd4SJiri Slaby 	hid_unregister_driver(&a4_driver);
15914a21cd4SJiri Slaby }
16014a21cd4SJiri Slaby 
16114a21cd4SJiri Slaby module_init(a4_init);
16214a21cd4SJiri Slaby module_exit(a4_exit);
16314a21cd4SJiri Slaby MODULE_LICENSE("GPL");
164