summaryrefslogtreecommitdiff
path: root/drivers/hid/hid-elo.c
blob: 56143e011f22b7a26ce9268533285e8eb8388378 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * HID driver for ELO usb touchscreen 4000/4500
 *
 * Copyright (c) 2013 Jiri Slaby
 *
 * Data parsing taken from elousb driver by Vojtech Pavlik.
 *
 * This driver is licensed under the terms of GPLv2.
 */

#include <linux/hid.h>
#include <linux/input.h>
#include <linux/module.h>

#include "hid-ids.h"

static void elo_input_configured(struct hid_device *hdev,
		struct hid_input *hidinput)
{
	struct input_dev *input = hidinput->input;

	set_bit(BTN_TOUCH, input->keybit);
	set_bit(ABS_PRESSURE, input->absbit);
	input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
}

static void elo_process_data(struct input_dev *input, const u8 *data, int size)
{
	int press;

	input_report_abs(input, ABS_X, (data[3] << 8) | data[2]);
	input_report_abs(input, ABS_Y, (data[5] << 8) | data[4]);

	press = 0;
	if (data[1] & 0x80)
		press = (data[7] << 8) | data[6];
	input_report_abs(input, ABS_PRESSURE, press);

	if (data[1] & 0x03) {
		input_report_key(input, BTN_TOUCH, 1);
		input_sync(input);
	}

	if (data[1] & 0x04)
		input_report_key(input, BTN_TOUCH, 0);

	input_sync(input);
}

static int elo_raw_event(struct hid_device *hdev, struct hid_report *report,
	 u8 *data, int size)
{
	struct hid_input *hidinput;

	if (!(hdev->claimed & HID_CLAIMED_INPUT) || list_empty(&hdev->inputs))
		return 0;

	hidinput = list_first_entry(&hdev->inputs, struct hid_input, list);

	switch (report->id) {
	case 0:
		if (data[0] == 'T') {	/* Mandatory ELO packet marker */
			elo_process_data(hidinput->input, data, size);
			return 1;
		}
		break;
	default:	/* unknown report */
		/* Unknown report type; pass upstream */
		hid_info(hdev, "unknown report type %d\n", report->id);
		break;
	}

	return 0;
}

static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
	int ret;

	ret = hid_parse(hdev);
	if (ret) {
		hid_err(hdev, "parse failed\n");
		goto err_free;
	}

	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
	if (ret) {
		hid_err(hdev, "hw start failed\n");
		goto err_free;
	}

	return 0;
err_free:
	return ret;
}

static void elo_remove(struct hid_device *hdev)
{
	hid_hw_stop(hdev);
}

static const struct hid_device_id elo_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009), },
	{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030), },
	{ }
};
MODULE_DEVICE_TABLE(hid, elo_devices);

static struct hid_driver elo_driver = {
	.name = "elo",
	.id_table = elo_devices,
	.probe = elo_probe,
	.remove = elo_remove,
	.raw_event = elo_raw_event,
	.input_configured = elo_input_configured,
};

static int __init elo_driver_init(void)
{
	return hid_register_driver(&elo_driver);
}
module_init(elo_driver_init);

static void __exit elo_driver_exit(void)
{
	hid_unregister_driver(&elo_driver);
}
module_exit(elo_driver_exit);

MODULE_AUTHOR("Jiri Slaby <jslaby@suse.cz>");
MODULE_LICENSE("GPL");