hid-a4tech.c 3.28 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
Jiri Slaby's avatar
Jiri Slaby committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 *  HID driver for some a4tech "special" devices
 *
 *  Copyright (c) 1999 Andreas Gal
 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
 *  Copyright (c) 2006-2007 Jiri Kosina
 *  Copyright (c) 2008 Jiri Slaby
 */

/*
 */

#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
#include <linux/module.h>
19
#include <linux/slab.h>
Jiri Slaby's avatar
Jiri Slaby committed
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

#include "hid-ids.h"

#define A4_2WHEEL_MOUSE_HACK_7	0x01
#define A4_2WHEEL_MOUSE_HACK_B8	0x02

struct a4tech_sc {
	unsigned long quirks;
	unsigned int hw_wheel;
	__s32 delayed_value;
};

static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
		struct hid_field *field, struct hid_usage *usage,
		unsigned long **bit, int *max)
{
	struct a4tech_sc *a4 = hid_get_drvdata(hdev);

38
	if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {
Jiri Slaby's avatar
Jiri Slaby committed
39
		set_bit(REL_HWHEEL, *bit);
40 41
		set_bit(REL_HWHEEL_HI_RES, *bit);
	}
Jiri Slaby's avatar
Jiri Slaby committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

	if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
		return -1;

	return 0;
}

static int a4_event(struct hid_device *hdev, struct hid_field *field,
		struct hid_usage *usage, __s32 value)
{
	struct a4tech_sc *a4 = hid_get_drvdata(hdev);
	struct input_dev *input;

	if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
			!usage->type)
		return 0;

	input = field->hidinput->input;

	if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
62
		if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {
Jiri Slaby's avatar
Jiri Slaby committed
63 64 65 66 67 68 69
			a4->delayed_value = value;
			return 1;
		}

		if (usage->hid == 0x000100b8) {
			input_event(input, EV_REL, value ? REL_HWHEEL :
					REL_WHEEL, a4->delayed_value);
70 71
			input_event(input, EV_REL, value ? REL_HWHEEL_HI_RES :
					REL_WHEEL_HI_RES, a4->delayed_value * 120);
Jiri Slaby's avatar
Jiri Slaby committed
72 73 74 75 76 77 78 79 80
			return 1;
		}
	}

	if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {
		a4->hw_wheel = !!value;
		return 1;
	}

81
	if (usage->code == REL_WHEEL_HI_RES && a4->hw_wheel) {
Jiri Slaby's avatar
Jiri Slaby committed
82
		input_event(input, usage->type, REL_HWHEEL, value);
83
		input_event(input, usage->type, REL_HWHEEL_HI_RES, value * 120);
Jiri Slaby's avatar
Jiri Slaby committed
84 85 86 87 88 89 90 91 92 93 94
		return 1;
	}

	return 0;
}

static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
	struct a4tech_sc *a4;
	int ret;

95
	a4 = devm_kzalloc(&hdev->dev, sizeof(*a4), GFP_KERNEL);
Jiri Slaby's avatar
Jiri Slaby committed
96
	if (a4 == NULL) {
97
		hid_err(hdev, "can't alloc device descriptor\n");
98
		return -ENOMEM;
Jiri Slaby's avatar
Jiri Slaby committed
99 100 101 102 103 104 105 106
	}

	a4->quirks = id->driver_data;

	hid_set_drvdata(hdev, a4);

	ret = hid_parse(hdev);
	if (ret) {
107
		hid_err(hdev, "parse failed\n");
108
		return ret;
Jiri Slaby's avatar
Jiri Slaby committed
109 110
	}

Jiri Slaby's avatar
Jiri Slaby committed
111
	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
Jiri Slaby's avatar
Jiri Slaby committed
112
	if (ret) {
113
		hid_err(hdev, "hw start failed\n");
114
		return ret;
Jiri Slaby's avatar
Jiri Slaby committed
115 116 117 118 119 120 121 122 123 124
	}

	return 0;
}

static const struct hid_device_id a4_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),
		.driver_data = A4_2WHEEL_MOUSE_HACK_7 },
	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
		.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
125 126
	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649),
		.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
Jiri Slaby's avatar
Jiri Slaby committed
127 128 129 130 131 132 133 134 135 136 137
	{ }
};
MODULE_DEVICE_TABLE(hid, a4_devices);

static struct hid_driver a4_driver = {
	.name = "a4tech",
	.id_table = a4_devices,
	.input_mapped = a4_input_mapped,
	.event = a4_event,
	.probe = a4_probe,
};
138
module_hid_driver(a4_driver);
Jiri Slaby's avatar
Jiri Slaby committed
139 140

MODULE_LICENSE("GPL");