Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 *  Bluetooth Wacom Tablet support
  3 *
  4 *  Copyright (c) 1999 Andreas Gal
  5 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  6 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  7 *  Copyright (c) 2006-2007 Jiri Kosina
  8 *  Copyright (c) 2007 Paul Walmsley
  9 *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
 10 *  Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
 11 *  Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
 12 */
 13
 14/*
 15 * This program is free software; you can redistribute it and/or modify it
 16 * under the terms of the GNU General Public License as published by the Free
 17 * Software Foundation; either version 2 of the License, or (at your option)
 18 * any later version.
 19 */
 20
 21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 22
 23#include <linux/device.h>
 24#include <linux/hid.h>
 25#include <linux/module.h>
 26#include <linux/slab.h>
 27#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 28#include <linux/power_supply.h>
 29#endif
 30
 31#include "hid-ids.h"
 32
 33struct wacom_data {
 34	__u16 tool;
 35	unsigned char butstate;
 36	unsigned char high_speed;
 37#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 38	int battery_capacity;
 39	struct power_supply battery;
 40	struct power_supply ac;
 41#endif
 42};
 43
 44#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
 45/*percent of battery capacity, 0 means AC online*/
 46static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
 47
 48static enum power_supply_property wacom_battery_props[] = {
 49	POWER_SUPPLY_PROP_PRESENT,
 50	POWER_SUPPLY_PROP_CAPACITY
 51};
 52
 53static enum power_supply_property wacom_ac_props[] = {
 54	POWER_SUPPLY_PROP_PRESENT,
 55	POWER_SUPPLY_PROP_ONLINE
 56};
 57
 58static int wacom_battery_get_property(struct power_supply *psy,
 59				enum power_supply_property psp,
 60				union power_supply_propval *val)
 61{
 62	struct wacom_data *wdata = container_of(psy,
 63					struct wacom_data, battery);
 64	int power_state = batcap[wdata->battery_capacity];
 65	int ret = 0;
 66
 67	switch (psp) {
 68	case POWER_SUPPLY_PROP_PRESENT:
 69		val->intval = 1;
 70		break;
 71	case POWER_SUPPLY_PROP_CAPACITY:
 72		/* show 100% battery capacity when charging */
 73		if (power_state == 0)
 74			val->intval = 100;
 75		else
 76			val->intval = power_state;
 77		break;
 78	default:
 79		ret = -EINVAL;
 80		break;
 81	}
 82	return ret;
 83}
 84
 85static int wacom_ac_get_property(struct power_supply *psy,
 86				enum power_supply_property psp,
 87				union power_supply_propval *val)
 88{
 89	struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
 90	int power_state = batcap[wdata->battery_capacity];
 91	int ret = 0;
 92
 93	switch (psp) {
 94	case POWER_SUPPLY_PROP_PRESENT:
 95		/* fall through */
 96	case POWER_SUPPLY_PROP_ONLINE:
 97		if (power_state == 0)
 98			val->intval = 1;
 99		else
100			val->intval = 0;
101		break;
102	default:
103		ret = -EINVAL;
104		break;
105	}
106	return ret;
107}
108#endif
109
110static void wacom_poke(struct hid_device *hdev, u8 speed)
111{
112	struct wacom_data *wdata = hid_get_drvdata(hdev);
113	int limit, ret;
114	char rep_data[2];
115
116	rep_data[0] = 0x03 ; rep_data[1] = 0x00;
117	limit = 3;
118	do {
119		ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
120				HID_FEATURE_REPORT);
121	} while (ret < 0 && limit-- > 0);
122
123	if (ret >= 0) {
124		if (speed == 0)
125			rep_data[0] = 0x05;
126		else
127			rep_data[0] = 0x06;
128
129		rep_data[1] = 0x00;
130		limit = 3;
131		do {
132			ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
133					HID_FEATURE_REPORT);
134		} while (ret < 0 && limit-- > 0);
135
136		if (ret >= 0) {
137			wdata->high_speed = speed;
138			return;
139		}
140	}
141
142	/*
143	 * Note that if the raw queries fail, it's not a hard failure and it
144	 * is safe to continue
145	 */
146	hid_warn(hdev, "failed to poke device, command %d, err %d\n",
147		 rep_data[0], ret);
148	return;
149}
150
151static ssize_t wacom_show_speed(struct device *dev,
152				struct device_attribute
153				*attr, char *buf)
154{
155	struct wacom_data *wdata = dev_get_drvdata(dev);
156
157	return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed);
158}
159
160static ssize_t wacom_store_speed(struct device *dev,
161				struct device_attribute *attr,
162				const char *buf, size_t count)
163{
164	struct hid_device *hdev = container_of(dev, struct hid_device, dev);
165	int new_speed;
166
167	if (sscanf(buf, "%1d", &new_speed ) != 1)
168		return -EINVAL;
169
170	if (new_speed == 0 || new_speed == 1) {
171		wacom_poke(hdev, new_speed);
172		return strnlen(buf, PAGE_SIZE);
173	} else
174		return -EINVAL;
175}
176
177static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
178		wacom_show_speed, wacom_store_speed);
179
180static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
181		u8 *raw_data, int size)
182{
183	struct wacom_data *wdata = hid_get_drvdata(hdev);
184	struct hid_input *hidinput;
185	struct input_dev *input;
186	unsigned char *data = (unsigned char *) raw_data;
187	int tool, x, y, rw;
188
189	if (!(hdev->claimed & HID_CLAIMED_INPUT))
190		return 0;
191
192	tool = 0;
193	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
194	input = hidinput->input;
195
196	/* Check if this is a tablet report */
197	if (data[0] != 0x03)
198		return 0;
199
200	/* Get X & Y positions */
201	x = le16_to_cpu(*(__le16 *) &data[2]);
202	y = le16_to_cpu(*(__le16 *) &data[4]);
203
204	/* Get current tool identifier */
205	if (data[1] & 0x90) { /* If pen is in the in/active area */
206		switch ((data[1] >> 5) & 3) {
207		case 0:	/* Pen */
208			tool = BTN_TOOL_PEN;
209			break;
210
211		case 1: /* Rubber */
212			tool = BTN_TOOL_RUBBER;
213			break;
214
215		case 2: /* Mouse with wheel */
216		case 3: /* Mouse without wheel */
217			tool = BTN_TOOL_MOUSE;
218			break;
219		}
220
221		/* Reset tool if out of active tablet area */
222		if (!(data[1] & 0x10))
223			tool = 0;
224	}
225
226	/* If tool changed, notify input subsystem */
227	if (wdata->tool != tool) {
228		if (wdata->tool) {
229			/* Completely reset old tool state */
230			if (wdata->tool == BTN_TOOL_MOUSE) {
231				input_report_key(input, BTN_LEFT, 0);
232				input_report_key(input, BTN_RIGHT, 0);
233				input_report_key(input, BTN_MIDDLE, 0);
234				input_report_abs(input, ABS_DISTANCE,
235					input_abs_get_max(input, ABS_DISTANCE));
236			} else {
237				input_report_key(input, BTN_TOUCH, 0);
238				input_report_key(input, BTN_STYLUS, 0);
239				input_report_key(input, BTN_STYLUS2, 0);
240				input_report_abs(input, ABS_PRESSURE, 0);
241			}
242			input_report_key(input, wdata->tool, 0);
243			input_sync(input);
244		}
245		wdata->tool = tool;
246		if (tool)
247			input_report_key(input, tool, 1);
248	}
249
250	if (tool) {
251		input_report_abs(input, ABS_X, x);
252		input_report_abs(input, ABS_Y, y);
253
254		switch ((data[1] >> 5) & 3) {
255		case 2: /* Mouse with wheel */
256			input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
257			rw = (data[6] & 0x01) ? -1 :
258				(data[6] & 0x02) ? 1 : 0;
259			input_report_rel(input, REL_WHEEL, rw);
260			/* fall through */
261
262		case 3: /* Mouse without wheel */
263			input_report_key(input, BTN_LEFT, data[1] & 0x01);
264			input_report_key(input, BTN_RIGHT, data[1] & 0x02);
265			/* Compute distance between mouse and tablet */
266			rw = 44 - (data[6] >> 2);
267			if (rw < 0)
268				rw = 0;
269			else if (rw > 31)
270				rw = 31;
271			input_report_abs(input, ABS_DISTANCE, rw);
272			break;
273
274		default:
275			input_report_abs(input, ABS_PRESSURE,
276					data[6] | (((__u16) (data[1] & 0x08)) << 5));
277			input_report_key(input, BTN_TOUCH, data[1] & 0x01);
278			input_report_key(input, BTN_STYLUS, data[1] & 0x02);
279			input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
280			break;
281		}
282
283		input_sync(input);
284	}
285
286	/* Report the state of the two buttons at the top of the tablet
287	 * as two extra fingerpad keys (buttons 4 & 5). */
288	rw = data[7] & 0x03;
289	if (rw != wdata->butstate) {
290		wdata->butstate = rw;
291		input_report_key(input, BTN_0, rw & 0x02);
292		input_report_key(input, BTN_1, rw & 0x01);
293		input_report_key(input, BTN_TOOL_FINGER, 0xf0);
294		input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
295		input_sync(input);
296	}
297
298#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
299	/* Store current battery capacity */
300	rw = (data[7] >> 2 & 0x07);
301	if (rw != wdata->battery_capacity)
302		wdata->battery_capacity = rw;
303#endif
304	return 1;
305}
306
307static int wacom_probe(struct hid_device *hdev,
308		const struct hid_device_id *id)
309{
310	struct hid_input *hidinput;
311	struct input_dev *input;
312	struct wacom_data *wdata;
313	int ret;
314
315	wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
316	if (wdata == NULL) {
317		hid_err(hdev, "can't alloc wacom descriptor\n");
318		return -ENOMEM;
319	}
320
321	hid_set_drvdata(hdev, wdata);
322
323	/* Parse the HID report now */
324	ret = hid_parse(hdev);
325	if (ret) {
326		hid_err(hdev, "parse failed\n");
327		goto err_free;
328	}
329
330	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
331	if (ret) {
332		hid_err(hdev, "hw start failed\n");
333		goto err_free;
334	}
335
336	ret = device_create_file(&hdev->dev, &dev_attr_speed);
337	if (ret)
338		hid_warn(hdev,
339			 "can't create sysfs speed attribute err: %d\n", ret);
340
341	/* Set Wacom mode 2 with high reporting speed */
342	wacom_poke(hdev, 1);
343
344#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
345	wdata->battery.properties = wacom_battery_props;
346	wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
347	wdata->battery.get_property = wacom_battery_get_property;
348	wdata->battery.name = "wacom_battery";
349	wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
350	wdata->battery.use_for_apm = 0;
351
352	ret = power_supply_register(&hdev->dev, &wdata->battery);
353	if (ret) {
354		hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
355			 ret);
356		goto err_battery;
357	}
358
359	wdata->ac.properties = wacom_ac_props;
360	wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props);
361	wdata->ac.get_property = wacom_ac_get_property;
362	wdata->ac.name = "wacom_ac";
363	wdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
364	wdata->ac.use_for_apm = 0;
365
366	ret = power_supply_register(&hdev->dev, &wdata->ac);
367	if (ret) {
368		hid_warn(hdev,
369			 "can't create ac battery attribute, err: %d\n", ret);
370		goto err_ac;
371	}
372#endif
373	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
374	input = hidinput->input;
375
376	__set_bit(INPUT_PROP_POINTER, input->propbit);
377
378	/* Basics */
379	input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
380
381	__set_bit(REL_WHEEL, input->relbit);
382
383	__set_bit(BTN_TOOL_PEN, input->keybit);
384	__set_bit(BTN_TOUCH, input->keybit);
385	__set_bit(BTN_STYLUS, input->keybit);
386	__set_bit(BTN_STYLUS2, input->keybit);
387	__set_bit(BTN_LEFT, input->keybit);
388	__set_bit(BTN_RIGHT, input->keybit);
389	__set_bit(BTN_MIDDLE, input->keybit);
390
391	/* Pad */
392	input->evbit[0] |= BIT(EV_MSC);
393
394	__set_bit(MSC_SERIAL, input->mscbit);
395
396	__set_bit(BTN_0, input->keybit);
397	__set_bit(BTN_1, input->keybit);
398	__set_bit(BTN_TOOL_FINGER, input->keybit);
399
400	/* Distance, rubber and mouse */
401	__set_bit(BTN_TOOL_RUBBER, input->keybit);
402	__set_bit(BTN_TOOL_MOUSE, input->keybit);
403
404	input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
405	input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
406	input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
407	input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
408
409	return 0;
410
411#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
412err_ac:
413	power_supply_unregister(&wdata->battery);
414err_battery:
415	device_remove_file(&hdev->dev, &dev_attr_speed);
416	hid_hw_stop(hdev);
417#endif
418err_free:
419	kfree(wdata);
420	return ret;
421}
422
423static void wacom_remove(struct hid_device *hdev)
424{
425#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
426	struct wacom_data *wdata = hid_get_drvdata(hdev);
427#endif
428	device_remove_file(&hdev->dev, &dev_attr_speed);
429	hid_hw_stop(hdev);
430
431#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
432	power_supply_unregister(&wdata->battery);
433	power_supply_unregister(&wdata->ac);
434#endif
435	kfree(hid_get_drvdata(hdev));
436}
437
438static const struct hid_device_id wacom_devices[] = {
439	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
440
441	{ }
442};
443MODULE_DEVICE_TABLE(hid, wacom_devices);
444
445static struct hid_driver wacom_driver = {
446	.name = "wacom",
447	.id_table = wacom_devices,
448	.probe = wacom_probe,
449	.remove = wacom_remove,
450	.raw_event = wacom_raw_event,
451};
452
453static int __init wacom_init(void)
454{
455	int ret;
456
457	ret = hid_register_driver(&wacom_driver);
458	if (ret)
459		pr_err("can't register wacom driver\n");
460	return ret;
461}
462
463static void __exit wacom_exit(void)
464{
465	hid_unregister_driver(&wacom_driver);
466}
467
468module_init(wacom_init);
469module_exit(wacom_exit);
470MODULE_LICENSE("GPL");
471