From ec3b0e89473c27a597717433fb642ff5423fd9b7 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 2 Jul 2024 19:55:58 -0700 Subject: [PATCH 1/4] A file path change is not an error checkpatch throw a warning when it detects a file changed its path. That's a kernel upstream concern. This project doesn't follow that guideline. Ignore it. Signed-off-by: Ping Cheng --- .checkpatch.conf | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .checkpatch.conf diff --git a/.checkpatch.conf b/.checkpatch.conf new file mode 100644 index 00000000..da9bddae --- /dev/null +++ b/.checkpatch.conf @@ -0,0 +1,3 @@ +# The input-wacom paths are not from upstream. Do not check them. + +--ignore FILE_PATH_CHANGES From 3fdbd53f6933fdea812777bdbe9004547828d19f Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 2 Jul 2024 19:22:28 -0700 Subject: [PATCH 2/4] Remove 3.17 and move 4.5->4.18 directory Prepare support for kernels 4.18 and later. Plus, adjust and cleanup the configure.am and Makefile.am files for 4.18+ kernels. Signed-off-by: Ping Cheng --- 3.17/Makefile.in | 109 - 3.17/wacom.h | 254 -- 3.17/wacom_sys.c | 2825 -------------------- 3.17/wacom_w8001.c | 709 ----- 3.17/wacom_wac.c | 4976 ----------------------------------- 3.17/wacom_wac.h | 391 --- {4.5 => 4.18}/Makefile.in | 0 {4.5 => 4.18}/wacom.h | 0 {4.5 => 4.18}/wacom_i2c.c | 0 {4.5 => 4.18}/wacom_sys.c | 0 {4.5 => 4.18}/wacom_w8001.c | 0 {4.5 => 4.18}/wacom_wac.c | 0 {4.5 => 4.18}/wacom_wac.h | 0 Makefile.am | 2 +- configure.ac | 65 +- 15 files changed, 6 insertions(+), 9325 deletions(-) delete mode 100644 3.17/Makefile.in delete mode 100644 3.17/wacom.h delete mode 100644 3.17/wacom_sys.c delete mode 100644 3.17/wacom_w8001.c delete mode 100644 3.17/wacom_wac.c delete mode 100644 3.17/wacom_wac.h rename {4.5 => 4.18}/Makefile.in (100%) rename {4.5 => 4.18}/wacom.h (100%) rename {4.5 => 4.18}/wacom_i2c.c (100%) rename {4.5 => 4.18}/wacom_sys.c (100%) rename {4.5 => 4.18}/wacom_w8001.c (100%) rename {4.5 => 4.18}/wacom_wac.c (100%) rename {4.5 => 4.18}/wacom_wac.h (100%) diff --git a/3.17/Makefile.in b/3.17/Makefile.in deleted file mode 100644 index cc702268..00000000 --- a/3.17/Makefile.in +++ /dev/null @@ -1,109 +0,0 @@ -RHEL7_RELEASE := @RHEL7_RELEASE@ -MODULE_NAME := wacom - -ifeq ($(RHEL7_RELEASE),4) -MODULE_NAME := hid-wacom -endif # RHEL7_RELEASE - -############################ kernel specific compile ############################### -ifneq ($(KERNELRELEASE),) -# We were called by kbuild -# Do NOT indent stuff in this part! It has to be like this to make the -# $(error ... ) stuff work - -ifneq ($(CONFIG_HID_WACOM),y) -WCM_VERSION := $(shell cd $(KBUILD_EXTMOD)/.. && ./git-version-gen) -ccflags-y := -DWACOM_VERSION_SUFFIX=\"-$(WCM_VERSION)\" -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers $(EXTRA_CFLAGS) -$(MODULE_NAME)-objs := wacom_wac.o wacom_sys.o -obj-m += $(MODULE_NAME).o -obj-m += wacom_w8001.o -else -$(error You requested to build wacom with configure, but wacom is configured as built-in in your kernel config) -endif # CONFIG_HID_WACOM - -LINUXINCLUDE := $(subst -I, -isystem, $(LINUXINCLUDE)) - -else # We were called from command line -PWD := $(shell pwd) -UPDATE_INITRAMFS := $(shell command -v update-initramfs 2>/dev/null) -DRACUT := $(shell command -v dracut 2>/dev/null) - -WCM_KERNEL_DIR := @WCM_KERNEL_DIR@ -MODUTS := @MODUTS@ -WCM_KERNEL_VER := @WCM_KERNEL_VER@ -MODSIGN_HASHALGO := @MODSIGN_HASHALGO@ -MODSIGN_PRIVFILE := @MODSIGN_PRIVFILE@ -MODSIGN_CERTFILE := @MODSIGN_CERTFILE@ - -MODSIGN_COMMAND := -ifneq ($(strip $(MODSIGN_HASHALGO)),) -ifneq ($(strip $(MODSIGN_PRIVFILE)),) -ifneq ($(strip $(MODSIGN_CERTFILE)),) -MODSIGN_COMMAND := "$(WCM_KERNEL_DIR)/scripts/sign-file" "$(MODSIGN_HASHALGO)" "$(MODSIGN_PRIVFILE)" "$(MODSIGN_CERTFILE)" -endif -endif -endif - -all: - @echo ' Building input-wacom drivers for $(WCM_KERNEL_VER) kernel.' - $(MAKE) -C $(WCM_KERNEL_DIR) M=$(PWD) $(EXTRA_MAKEFLAGS) - -clean: - $(MAKE) -C $(WCM_KERNEL_DIR) M=$(PWD) clean - -signature: all - $(MODSIGN_COMMAND) $(MODULE_NAME).ko - $(MODSIGN_COMMAND) wacom_w8001.ko - -install modules_install: - $(MAKE) -C $(WCM_KERNEL_DIR) M=$(PWD) modules_install mod_sign_cmd='$(MODSIGN_COMMAND)' - mkdir -p /etc/depmod.d - echo "override wacom * extra" > /etc/depmod.d/input-wacom.conf - echo "override wacom_w8001 * extra" >> /etc/depmod.d/input-wacom.conf -ifeq ($(RHEL7_RELEASE),4) - echo "override hid-wacom * extra" >> /etc/depmod.d/input-wacom.conf -endif # RHEL7_RELEASE - PATH="$(PATH):/bin:/sbin" depmod -a $(MODUTS) -ifdef UPDATE_INITRAMFS - $(UPDATE_INITRAMFS) -u -k $(MODUTS) -endif -ifdef DRACUT - echo 'add_drivers+=" wacom wacom_w8001 "' > /etc/dracut.conf.d/input-wacom.conf - $(DRACUT) -f --kver=$(MODUTS) -endif - -uninstall: - @# Debian uses symlinks in the path to WCM_KERNEL_DIR - @# which causes trouble for tools like 'rm' which don't - @# see the path how you might think. As a workaround, - @# first cd into the directory and then remove. - cd $(WCM_KERNEL_DIR)/../extra; rm $(MODULE_NAME).ko* - cd $(WCM_KERNEL_DIR)/../extra; rm wacom_w8001.ko* - rm -f /etc/depmod.d/input-wacom.conf - PATH="$(PATH):/bin:/sbin" depmod -a $(MODUTS) -ifdef UPDATE_INITRAMFS - $(UPDATE_INITRAMFS) -u -k $(MODUTS) -endif -ifdef DRACUT - rm -f /etc/dracut.conf.d/input-wacom.conf - $(DRACUT) -f --kver=$(MODUTS) -endif - -endif # End kbuild check - -######################### Version independent targets ########################## - -distclean: clean - -DISTFILES = wacom.h wacom_sys.c wacom_w8001.c wacom_wac.c wacom_wac.h - -distdir: - for file in $(DISTFILES); do \ - cp -fpR ./$$file "$(distdir)" || exit 1; \ - done - -EMPTY_AUTOMAKE_TARGETS = install-data install-exec uninstall install-info -EMPTY_AUTOMAKE_TARGETS += installdirs check dvi pdf ps info html tags ctags mostlyclean maintainer-clean -EMPTY_AUTOMAKE_TARGETS += signature -.PHONY: $(EMPTY_AUTOMAKE_TARGETS) - $(EMPTY_AUTOMAKE_TARGETS): diff --git a/3.17/wacom.h b/3.17/wacom.h deleted file mode 100644 index 20889d14..00000000 --- a/3.17/wacom.h +++ /dev/null @@ -1,254 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * USB Wacom tablet support - * - * Copyright (c) 2000-2004 Vojtech Pavlik - * Copyright (c) 2000 Andreas Bach Aaen - * Copyright (c) 2000 Clifford Wolf - * Copyright (c) 2000 Sam Mosel - * Copyright (c) 2000 James E. Blair - * Copyright (c) 2000 Daniel Egger - * Copyright (c) 2001 Frederic Lepied - * Copyright (c) 2004 Panagiotis Issaris - * Copyright (c) 2002-2011 Ping Cheng - * Copyright (c) 2014 Benjamin Tissoires - * - * ChangeLog: - * v0.1 (vp) - Initial release - * v0.2 (aba) - Support for all buttons / combinations - * v0.3 (vp) - Support for Intuos added - * v0.4 (sm) - Support for more Intuos models, menustrip - * relative mode, proximity. - * v0.5 (vp) - Big cleanup, nifty features removed, - * they belong in userspace - * v1.8 (vp) - Submit URB only when operating, moved to CVS, - * use input_report_key instead of report_btn and - * other cleanups - * v1.11 (vp) - Add URB ->dev setting for new kernels - * v1.11 (jb) - Add support for the 4D Mouse & Lens - * v1.12 (de) - Add support for two more inking pen IDs - * v1.14 (vp) - Use new USB device id probing scheme. - * Fix Wacom Graphire mouse wheel - * v1.18 (vp) - Fix mouse wheel direction - * Make mouse relative - * v1.20 (fl) - Report tool id for Intuos devices - * - Multi tools support - * - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...) - * - Add PL models support - * - Fix Wacom Graphire mouse wheel again - * v1.21 (vp) - Removed protocol descriptions - * - Added MISC_SERIAL for tool serial numbers - * (gb) - Identify version on module load. - * v1.21.1 (fl) - added Graphire2 support - * v1.21.2 (fl) - added Intuos2 support - * - added all the PL ids - * v1.21.3 (fl) - added another eraser id from Neil Okamoto - * - added smooth filter for Graphire from Peri Hankey - * - added PenPartner support from Olaf van Es - * - new tool ids from Ole Martin Bjoerndalen - * v1.29 (pc) - Add support for more tablets - * - Fix pressure reporting - * v1.30 (vp) - Merge 2.4 and 2.5 drivers - * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse - * - Cleanups here and there - * v1.30.1 (pi) - Added Graphire3 support - * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ... - * v1.43 (pc) - Added support for Cintiq 21UX - * - Fixed a Graphire bug - * - Merged wacom_intuos3_irq into wacom_intuos_irq - * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc. - * - Report Device IDs - * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19 - * - Minor data report fix - * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, - * - where wacom_sys.c deals with system specific code, - * - and wacom_wac.c deals with Wacom specific code - * - Support Intuos3 4x6 - * v1.47 (pc) - Added support for Bamboo - * v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX - * v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A) - * v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28 - * v1.51 (pc) - Added support for Intuos4 - * v1.52 (pc) - Query Wacom data upon system resume - * - add defines for features->type - * - add new devices (0x9F, 0xE2, and 0XE3) - * v2.00 (bt) - conversion to a HID driver - * - integration of the Bluetooth devices - */ - -#ifndef WACOM_H -#define WACOM_H - -#include "../config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#ifndef WACOM_VERSION_SUFFIX -#define WACOM_VERSION_SUFFIX "" -#endif -#define DRIVER_VERSION "v2.00"WACOM_VERSION_SUFFIX -#define DRIVER_AUTHOR "Vojtech Pavlik " -#define DRIVER_DESC "USB Wacom tablet driver" - -#define USB_VENDOR_ID_WACOM 0x056a -#define USB_VENDOR_ID_LENOVO 0x17ef - -#ifndef fallthrough -# if defined __has_attribute -# if __has_attribute(__fallthrough__) -# define fallthrough __attribute__((__fallthrough__)) -# endif -# endif -#endif -#ifndef fallthrough -# define fallthrough do {} while (0) /* fallthrough */ -#endif - -#ifdef WACOM_POWERSUPPLY_41 -#define WACOM_POWERSUPPLY_DEVICE(ps) (ps) -#define WACOM_POWERSUPPLY_REF(ps) (ps) -#define WACOM_POWERSUPPLY_DESC(ps) (ps##_desc) -#else -#define WACOM_POWERSUPPLY_DEVICE(ps) ((ps).dev) -#define WACOM_POWERSUPPLY_REF(ps) (&(ps)) -#define WACOM_POWERSUPPLY_DESC(ps) (ps) -#endif - -#ifndef to_hid_device -#define to_hid_device(pdev) \ - container_of(pdev, struct hid_device, dev) -#endif /* to_hid_device */ - - -enum wacom_worker { - WACOM_WORKER_WIRELESS, - WACOM_WORKER_BATTERY, - WACOM_WORKER_REMOTE, - WACOM_WORKER_MODE_CHANGE, -}; - -struct wacom_group_leds { - u8 select; /* status led selector (0..3) */ -}; - -struct wacom_battery { - struct wacom *wacom; -#ifdef WACOM_POWERSUPPLY_41 - struct power_supply_desc bat_desc; - struct power_supply *battery; -#else - struct power_supply battery; -#endif - char bat_name[WACOM_NAME_MAX]; - int bat_status; - int battery_capacity; - int bat_charging; - int bat_connected; - int ps_connected; -}; - -struct wacom_remote { - spinlock_t remote_lock; - struct kfifo remote_fifo; - struct kobject *remote_dir; - struct { - struct attribute_group group; - u32 serial; - struct input_dev *input; - bool registered; - struct wacom_battery battery; - } remotes[WACOM_MAX_REMOTES]; -}; - -struct wacom { - struct usb_device *usbdev; - struct usb_interface *intf; - struct wacom_wac wacom_wac; - struct hid_device *hdev; - struct mutex lock; - struct work_struct wireless_work; - struct work_struct battery_work; - struct work_struct remote_work; - struct delayed_work init_work; - struct wacom_remote *remote; - struct work_struct mode_change_work; - struct timer_list idleprox_timer; - bool generic_has_leds; - struct wacom_leds { - struct wacom_group_leds *groups; - u8 llv; /* status led brightness no button (1..127) */ - u8 hlv; /* status led brightness button pressed (1..127) */ - u8 img_lum; /* OLED matrix display brightness */ - } led; - struct wacom_battery battery; - bool resources; -}; - -static inline void wacom_schedule_work(struct wacom_wac *wacom_wac, - enum wacom_worker which) -{ - struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); - - switch (which) { - case WACOM_WORKER_WIRELESS: - schedule_work(&wacom->wireless_work); - break; - case WACOM_WORKER_BATTERY: - schedule_work(&wacom->battery_work); - break; - case WACOM_WORKER_REMOTE: - schedule_work(&wacom->remote_work); - break; - case WACOM_WORKER_MODE_CHANGE: - schedule_work(&wacom->mode_change_work); - break; - } -} - -/* - * Convert a signed 32-bit integer to an unsigned n-bit integer. Undoes - * the normally-helpful work of 'hid_snto32' for fields that use signed - * ranges for questionable reasons. - */ -static inline __u32 wacom_s32tou(s32 value, __u8 n) -{ - switch (n) { - case 8: return ((__u8)value); - case 16: return ((__u16)value); - case 32: return ((__u32)value); - } - return value & (1 << (n - 1)) ? value & (~(~0U << n)) : value; -} - -extern const struct hid_device_id wacom_ids[]; - -void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); -void wacom_setup_device_quirks(struct wacom *wacom); -int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac); -int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac); -int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac); -void wacom_wac_usage_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage); -void wacom_wac_event(struct hid_device *hdev, struct hid_field *field, - struct hid_usage *usage, __s32 value); -void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); -void wacom_battery_work(struct work_struct *work); -int wacom_equivalent_usage(int usage); -int wacom_initialize_leds(struct wacom *wacom); -void wacom_idleprox_timeout(unsigned long data); -#endif diff --git a/3.17/wacom_sys.c b/3.17/wacom_sys.c deleted file mode 100644 index 18ae6d1a..00000000 --- a/3.17/wacom_sys.c +++ /dev/null @@ -1,2825 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * USB Wacom tablet support - system specific code - */ - -#include "wacom_wac.h" -#include "wacom.h" -#include - -#define WAC_MSG_RETRIES 5 -#define WAC_CMD_RETRIES 10 - -#define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP) -#define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP) -#define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP) - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) -static int wacom_hid_report_len(struct hid_report *report) -{ - /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */ - return ((report->size - 1) >> 3) + 1 + (report->id > 0); -} -#else -#define wacom_hid_report_len(report) hid_report_len(report) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) -__u32 hid_field_extract(const struct hid_device *hid, __u8 *report, - unsigned offset, unsigned n) -{ - u64 x; - - if (n > 32) - hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n", - n, current->comm); - - report += offset >> 3; /* adjust byte index */ - offset &= 7; /* now only need bit offset into one byte */ - x = get_unaligned_le64(report); - x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ - return (u32) x; -} -#endif - -static int __wacom_is_usb_parent(struct usb_device *usbdev, void *ptr) -{ - struct hid_device *hdev = ptr; - struct device *parent = hdev->dev.parent; - struct usb_host_config *config = usbdev->actconfig; - int i; - - for (i = 0; config && i < config->desc.bNumInterfaces; i++) { - if (&config->interface[i]->dev == parent) - return 1; - } - return 0; -} - -static bool wacom_is_using_usb_driver(struct hid_device *hdev) -{ - return hdev->bus == BUS_USB && - usb_for_each_dev(hdev, __wacom_is_usb_parent); -} - -#ifndef WACOM_DEVM_OR_RESET -static int devm_add_action_or_reset(struct device *dev, - void (*action)(void *), void *data) -{ - int ret; - - ret = devm_add_action(dev, action, data); - if (ret) - action(data); - - return ret; -} -#endif - -static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf, - size_t size, unsigned int retries) -{ - int retval; - - do { - retval = hid_hw_raw_request(hdev, buf[0], buf, size, type, - HID_REQ_GET_REPORT); - } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); - - if (retval < 0) - hid_err(hdev, "wacom_get_report: ran out of retries " - "(last error = %d)\n", retval); - - return retval; -} - -static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf, - size_t size, unsigned int retries) -{ - int retval; - - do { - retval = hid_hw_raw_request(hdev, buf[0], buf, size, type, - HID_REQ_SET_REPORT); - } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); - - if (retval < 0) - hid_err(hdev, "wacom_set_report: ran out of retries " - "(last error = %d)\n", retval); - - return retval; -} - -static void wacom_wac_queue_insert(struct hid_device *hdev, - struct kfifo_rec_ptr_2 *fifo, - u8 *raw_data, int size) -{ - bool warned = false; - - while (kfifo_avail(fifo) < size) { - if (!warned) - hid_warn(hdev, "%s: kfifo has filled, starting to drop events\n", __func__); - warned = true; - - kfifo_skip(fifo); - } - - kfifo_in(fifo, raw_data, size); -} - -static void wacom_wac_queue_flush(struct hid_device *hdev, - struct kfifo_rec_ptr_2 *fifo) -{ - while (!kfifo_is_empty(fifo)) { - u8 buf[WACOM_PKGLEN_MAX]; - int size; - int err; - - size = kfifo_out(fifo, buf, sizeof(buf)); - err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false); - if (err) { - hid_warn(hdev, "%s: unable to flush event due to error %d\n", - __func__, err); - } - } -} - -static int wacom_wac_pen_serial_enforce(struct hid_device *hdev, - struct hid_report *report, u8 *raw_data, int report_size) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - bool flush = false; - bool insert = false; - int i, j; - - if (wacom_wac->serial[0] || !(features->quirks & WACOM_QUIRK_TOOLSERIAL)) - return 0; - - /* Queue events which have invalid tool type or serial number */ - for (i = 0; i < report->maxfield; i++) { - for (j = 0; j < report->field[i]->maxusage; j++) { - struct hid_field *field = report->field[i]; - struct hid_usage *usage = &field->usage[j]; - unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); - unsigned int offset; - unsigned int size; - unsigned int value; - - if (equivalent_usage != HID_DG_INRANGE && - equivalent_usage != HID_DG_TOOLSERIALNUMBER && - equivalent_usage != WACOM_HID_WD_SERIALHI && - equivalent_usage != WACOM_HID_WD_TOOLTYPE) - continue; - - offset = field->report_offset; - size = field->report_size; - value = hid_field_extract(hdev, raw_data+1, offset + j * size, size); - - /* If we go out of range, we need to flush the queue ASAP */ - if (equivalent_usage == HID_DG_INRANGE) - value = !value; - - if (value) { - flush = true; - switch (equivalent_usage) { - case HID_DG_TOOLSERIALNUMBER: - wacom_wac->serial[0] = value; - break; - - case WACOM_HID_WD_SERIALHI: - wacom_wac->serial[0] |= ((__u64)value) << 32; - break; - - case WACOM_HID_WD_TOOLTYPE: - wacom_wac->id[0] = value; - break; - } - } - else { - insert = true; - } - } - } - - if (flush) - wacom_wac_queue_flush(hdev, wacom_wac->pen_fifo); - else if (insert) - wacom_wac_queue_insert(hdev, wacom_wac->pen_fifo, - raw_data, report_size); - - return insert && !flush; -} - -static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, - u8 *raw_data, int size) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - - if (wacom->wacom_wac.features.type == BOOTLOADER) - return 0; - - if (size > WACOM_PKGLEN_MAX) - return 1; - - if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size)) - return -1; - - memcpy(wacom->wacom_wac.data, raw_data, size); - - wacom_wac_irq(&wacom->wacom_wac, size); - - return 0; -} - -static int wacom_open(struct input_dev *dev) -{ - struct wacom *wacom = input_get_drvdata(dev); - - return hid_hw_open(wacom->hdev); -} - -static void wacom_close(struct input_dev *dev) -{ - struct wacom *wacom = input_get_drvdata(dev); - - /* - * wacom->hdev should never be null, but surprisingly, I had the case - * once while unplugging the Wacom Wireless Receiver. - */ - if (wacom->hdev) - hid_hw_close(wacom->hdev); -} - -/* - * Calculate the resolution of the X or Y axis using hidinput_calc_abs_res. - */ -static int wacom_calc_hid_res(int logical_extents, int physical_extents, - unsigned unit, int exponent) -{ - struct hid_field field = { - .logical_maximum = logical_extents, - .physical_maximum = physical_extents, - .unit = unit, - .unit_exponent = exponent, - }; - - return hidinput_calc_abs_res(&field, ABS_X); -} - -static void wacom_hid_usage_quirk(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_features *features = &wacom->wacom_wac.features; - unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); - - /* - * The Dell Canvas 27 needs to be switched to its vendor-defined - * report to provide the best resolution. - */ - if (hdev->vendor == USB_VENDOR_ID_WACOM && - hdev->product == 0x4200 && - field->application == HID_UP_MSVENDOR) { - wacom->wacom_wac.mode_report = field->report->id; - wacom->wacom_wac.mode_value = 2; - } - - /* - * ISDv4 devices which predate HID's adoption of the - * HID_DG_BARELSWITCH2 usage use 0x000D0000 in its - * position instead. We can accurately detect if a - * usage with that value should be HID_DG_BARRELSWITCH2 - * based on the surrounding usages, which have remained - * constant across generations. - */ - if (features->type == HID_GENERIC && - usage->hid == 0x000D0000 && - field->application == HID_DG_PEN && - field->physical == HID_DG_STYLUS) { - int i = usage->usage_index; - - if (i-4 >= 0 && i+1 < field->maxusage && - field->usage[i-4].hid == HID_DG_TIPSWITCH && - field->usage[i-3].hid == HID_DG_BARRELSWITCH && - field->usage[i-2].hid == HID_DG_ERASER && - field->usage[i-1].hid == HID_DG_INVERT && - field->usage[i+1].hid == HID_DG_INRANGE) { - usage->hid = HID_DG_BARRELSWITCH2; - } - } - - /* - * Wacom's AES devices use different vendor-defined usages to - * report serial number information compared to their branded - * hardware. The usages are also sometimes ill-defined and do - * not have the correct logical min/max values set. Lets patch - * the descriptor to use the branded usage convention and fix - * the errors. - */ - if (usage->hid == WACOM_HID_WT_SERIALNUMBER && - field->report_size == 16 && - field->index + 2 < field->report->maxfield) { - struct hid_field *a = field->report->field[field->index + 1]; - struct hid_field *b = field->report->field[field->index + 2]; - - if (a->maxusage > 0 && - a->usage[0].hid == HID_DG_TOOLSERIALNUMBER && - a->report_size == 32 && - b->maxusage > 0 && - b->usage[0].hid == 0xFF000000 && - b->report_size == 8) { - features->quirks |= WACOM_QUIRK_AESPEN; - usage->hid = WACOM_HID_WD_TOOLTYPE; - field->logical_minimum = S16_MIN; - field->logical_maximum = S16_MAX; - a->logical_minimum = S32_MIN; - a->logical_maximum = S32_MAX; - b->usage[0].hid = WACOM_HID_WD_SERIALHI; - b->logical_minimum = 0; - b->logical_maximum = U8_MAX; - } - } - - /* 2nd-generation Intuos Pro Large has incorrect Y maximum */ - if (hdev->vendor == USB_VENDOR_ID_WACOM && - hdev->product == 0x0358 && - WACOM_PEN_FIELD(field) && - equivalent_usage == HID_GD_Y) { - field->logical_maximum = 43200; - } -} - -static void wacom_feature_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_features *features = &wacom->wacom_wac.features; - struct hid_data *hid_data = &wacom->wacom_wac.hid_data; - unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); - u8 *data; - int ret; - u32 n; - - wacom_hid_usage_quirk(hdev, field, usage); - - switch (equivalent_usage) { - case WACOM_HID_WD_TOUCH_RING_SETTING: - wacom->generic_has_leds = true; - break; - case HID_DG_CONTACTMAX: - /* leave touch_max as is if predefined */ - if (!features->touch_max) { - /* read manually */ - n = wacom_hid_report_len(field->report); - data = hid_alloc_report_buf(field->report, GFP_KERNEL); - if (!data) - break; - data[0] = field->report->id; - ret = wacom_get_report(hdev, HID_FEATURE_REPORT, - data, n, WAC_CMD_RETRIES); - if (ret == n && features->type == HID_GENERIC) { - ret = hid_report_raw_event(hdev, - HID_FEATURE_REPORT, data, n, 0); - } else if (ret == 2 && features->type != HID_GENERIC) { - features->touch_max = data[1]; - } else { - features->touch_max = 16; - hid_warn(hdev, "wacom_feature_mapping: " - "could not get HID_DG_CONTACTMAX, " - "defaulting to %d\n", - features->touch_max); - } - kfree(data); - } - break; - case HID_DG_INPUTMODE: - /* Ignore if value index is out of bounds. */ - if (usage->usage_index >= field->report_count) { - dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n"); - break; - } - - hid_data->inputmode = field->report->id; - hid_data->inputmode_index = usage->usage_index; - break; - - case HID_UP_DIGITIZER: - if (field->report->id == 0x0B && - (field->application == WACOM_HID_G9_PEN || - field->application == WACOM_HID_G11_PEN)) { - wacom->wacom_wac.mode_report = field->report->id; - wacom->wacom_wac.mode_value = 0; - } - break; - - case WACOM_HID_WD_DATAMODE: - wacom->wacom_wac.mode_report = field->report->id; - wacom->wacom_wac.mode_value = 2; - break; - - case WACOM_HID_UP_G9: - case WACOM_HID_UP_G11: - if (field->report->id == 0x03 && - (field->application == WACOM_HID_G9_TOUCHSCREEN || - field->application == WACOM_HID_G11_TOUCHSCREEN)) { - wacom->wacom_wac.mode_report = field->report->id; - wacom->wacom_wac.mode_value = 0; - } - break; - case WACOM_HID_WD_OFFSETLEFT: - case WACOM_HID_WD_OFFSETTOP: - case WACOM_HID_WD_OFFSETRIGHT: - case WACOM_HID_WD_OFFSETBOTTOM: - /* read manually */ - n = wacom_hid_report_len(field->report); - data = hid_alloc_report_buf(field->report, GFP_KERNEL); - if (!data) - break; - data[0] = field->report->id; - ret = wacom_get_report(hdev, HID_FEATURE_REPORT, - data, n, WAC_CMD_RETRIES); - if (ret == n) { - ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, - data, n, 0); - } else { - hid_warn(hdev, "%s: could not retrieve sensor offsets\n", - __func__); - } - kfree(data); - break; - } -} - -/* - * Interface Descriptor of wacom devices can be incomplete and - * inconsistent so wacom_features table is used to store stylus - * device's packet lengths, various maximum values, and tablet - * resolution based on product ID's. - * - * For devices that contain 2 interfaces, wacom_features table is - * inaccurate for the touch interface. Since the Interface Descriptor - * for touch interfaces has pretty complete data, this function exists - * to query tablet for this missing information instead of hard coding in - * an additional table. - * - * A typical Interface Descriptor for a stylus will contain a - * boot mouse application collection that is not of interest and this - * function will ignore it. - * - * It also contains a digitizer application collection that also is not - * of interest since any information it contains would be duplicate - * of what is in wacom_features. Usually it defines a report of an array - * of bytes that could be used as max length of the stylus packet returned. - * If it happens to define a Digitizer-Stylus Physical Collection then - * the X and Y logical values contain valid data but it is ignored. - * - * A typical Interface Descriptor for a touch interface will contain a - * Digitizer-Finger Physical Collection which will define both logical - * X/Y maximum as well as the physical size of tablet. Since touch - * interfaces haven't supported pressure or distance, this is enough - * information to override invalid values in the wacom_features table. - * - * Intuos5 touch interface and 3rd gen Bamboo Touch do not contain useful - * data. We deal with them after returning from this function. - */ -static void wacom_usage_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_features *features = &wacom->wacom_wac.features; - bool finger = WACOM_FINGER_FIELD(field); - bool pen = WACOM_PEN_FIELD(field); - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - - /* - * Requiring Stylus Usage will ignore boot mouse - * X/Y values and some cases of invalid Digitizer X/Y - * values commonly reported. - */ - if (pen) - features->device_type |= WACOM_DEVICETYPE_PEN; - else if (finger) - features->device_type |= WACOM_DEVICETYPE_TOUCH; - else - return; - - wacom_hid_usage_quirk(hdev, field, usage); - - switch (equivalent_usage) { - case HID_GD_X: - features->x_max = field->logical_maximum; - if (finger) { - features->x_phy = field->physical_maximum; - if ((features->type != BAMBOO_PT) && - (features->type != BAMBOO_TOUCH)) { - features->unit = field->unit; - features->unitExpo = field->unit_exponent; - } - } - break; - case HID_GD_Y: - features->y_max = field->logical_maximum; - if (finger) { - features->y_phy = field->physical_maximum; - if ((features->type != BAMBOO_PT) && - (features->type != BAMBOO_TOUCH)) { - features->unit = field->unit; - features->unitExpo = field->unit_exponent; - } - } - break; - case HID_DG_TIPPRESSURE: - if (pen) - features->pressure_max = field->logical_maximum; - break; - } - - if (features->type == HID_GENERIC) - wacom_wac_usage_mapping(hdev, field, usage); -} - -static void wacom_post_parse_hid(struct hid_device *hdev, - struct wacom_features *features) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - - if (features->type == HID_GENERIC) { - /* Any last-minute generic device setup */ - if (wacom_wac->has_mode_change) { - if (wacom_wac->is_direct_mode) - features->device_type |= WACOM_DEVICETYPE_DIRECT; - else - features->device_type &= ~WACOM_DEVICETYPE_DIRECT; - } - - if (features->touch_max > 1) { - if (features->device_type & WACOM_DEVICETYPE_DIRECT) - input_mt_init_slots(wacom_wac->touch_input, - wacom_wac->features.touch_max, - INPUT_MT_DIRECT); - else - input_mt_init_slots(wacom_wac->touch_input, - wacom_wac->features.touch_max, - INPUT_MT_POINTER); - } - } -} - -static void wacom_parse_hid(struct hid_device *hdev, - struct wacom_features *features) -{ - struct hid_report_enum *rep_enum; - struct hid_report *hreport; - int i, j; - - /* check features first */ - rep_enum = &hdev->report_enum[HID_FEATURE_REPORT]; - list_for_each_entry(hreport, &rep_enum->report_list, list) { - for (i = 0; i < hreport->maxfield; i++) { - /* Ignore if report count is out of bounds. */ - if (hreport->field[i]->report_count < 1) - continue; - - for (j = 0; j < hreport->field[i]->maxusage; j++) { - wacom_feature_mapping(hdev, hreport->field[i], - hreport->field[i]->usage + j); - } - } - } - - /* now check the input usages */ - rep_enum = &hdev->report_enum[HID_INPUT_REPORT]; - list_for_each_entry(hreport, &rep_enum->report_list, list) { - - if (!hreport->maxfield) - continue; - - for (i = 0; i < hreport->maxfield; i++) - for (j = 0; j < hreport->field[i]->maxusage; j++) - wacom_usage_mapping(hdev, hreport->field[i], - hreport->field[i]->usage + j); - } - - wacom_post_parse_hid(hdev, features); -} - -static int wacom_hid_set_device_mode(struct hid_device *hdev) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct hid_data *hid_data = &wacom->wacom_wac.hid_data; - struct hid_report *r; - struct hid_report_enum *re; - - if (hid_data->inputmode < 0) - return 0; - - re = &(hdev->report_enum[HID_FEATURE_REPORT]); - r = re->report_id_hash[hid_data->inputmode]; - if (r) { - r->field[0]->value[hid_data->inputmode_index] = 2; - hid_hw_request(hdev, r, HID_REQ_SET_REPORT); - } - return 0; -} - -static int wacom_set_device_mode(struct hid_device *hdev, - struct wacom_wac *wacom_wac) -{ - u8 *rep_data; - struct hid_report *r; - struct hid_report_enum *re; - u32 length; - int error = -ENOMEM, limit = 0; - - if (wacom_wac->mode_report < 0) - return 0; - - re = &(hdev->report_enum[HID_FEATURE_REPORT]); - r = re->report_id_hash[wacom_wac->mode_report]; - if (!r) - return -EINVAL; - - rep_data = hid_alloc_report_buf(r, GFP_KERNEL); - if (!rep_data) - return -ENOMEM; - - length = wacom_hid_report_len(r); - - do { - rep_data[0] = wacom_wac->mode_report; - rep_data[1] = wacom_wac->mode_value; - - error = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, - length, 1); - if (error >= 0) - error = wacom_get_report(hdev, HID_FEATURE_REPORT, - rep_data, length, 1); - } while (error >= 0 && - rep_data[1] != wacom_wac->mode_report && - limit++ < WAC_MSG_RETRIES); - - kfree(rep_data); - - return error < 0 ? error : 0; -} - -static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed, - struct wacom_features *features) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - int ret; - u8 rep_data[2]; - - switch (features->type) { - case GRAPHIRE_BT: - rep_data[0] = 0x03; - rep_data[1] = 0x00; - ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2, - 3); - - if (ret >= 0) { - rep_data[0] = speed == 0 ? 0x05 : 0x06; - rep_data[1] = 0x00; - - ret = wacom_set_report(hdev, HID_FEATURE_REPORT, - rep_data, 2, 3); - - if (ret >= 0) { - wacom->wacom_wac.bt_high_speed = speed; - return 0; - } - } - - /* - * Note that if the raw queries fail, it's not a hard failure - * and it is safe to continue - */ - hid_warn(hdev, "failed to poke device, command %d, err %d\n", - rep_data[0], ret); - break; - case INTUOS4WL: - if (speed == 1) - wacom->wacom_wac.bt_features &= ~0x20; - else - wacom->wacom_wac.bt_features |= 0x20; - - rep_data[0] = 0x03; - rep_data[1] = wacom->wacom_wac.bt_features; - - ret = wacom_set_report(hdev, HID_FEATURE_REPORT, rep_data, 2, - 1); - if (ret >= 0) - wacom->wacom_wac.bt_high_speed = speed; - break; - } - - return 0; -} - -/* - * Switch the tablet into its most-capable mode. Wacom tablets are - * typically configured to power-up in a mode which sends mouse-like - * reports to the OS. To get absolute position, pressure data, etc. - * from the tablet, it is necessary to switch the tablet out of this - * mode and into one which sends the full range of tablet data. - */ -static int _wacom_query_tablet_data(struct wacom *wacom) -{ - struct hid_device *hdev = wacom->hdev; - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - - if (hdev->bus == BUS_BLUETOOTH) - return wacom_bt_query_tablet_data(hdev, 1, features); - - if (features->type != HID_GENERIC) { - if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - if (features->type > TABLETPC) { - /* MT Tablet PC touch */ - wacom_wac->mode_report = 3; - wacom_wac->mode_value = 4; - } else if (features->type == WACOM_24HDT) { - wacom_wac->mode_report = 18; - wacom_wac->mode_value = 2; - } else if (features->type == WACOM_27QHDT) { - wacom_wac->mode_report = 131; - wacom_wac->mode_value = 2; - } else if (features->type == BAMBOO_PAD) { - wacom_wac->mode_report = 2; - wacom_wac->mode_value = 2; - } - } else if (features->device_type & WACOM_DEVICETYPE_PEN) { - if (features->type <= BAMBOO_PT) { - wacom_wac->mode_report = 2; - wacom_wac->mode_value = 2; - } - } - } - - wacom_set_device_mode(hdev, wacom_wac); - - if (features->type == HID_GENERIC) - return wacom_hid_set_device_mode(hdev); - - return 0; -} - -static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, - struct wacom_features *features) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct usb_interface *intf = wacom->intf; - - /* default features */ - features->x_fuzz = 4; - features->y_fuzz = 4; - features->pressure_fuzz = 0; - features->distance_fuzz = 1; - features->tilt_fuzz = 1; - - /* - * The wireless device HID is basic and layout conflicts with - * other tablets (monitor and touch interface can look like pen). - * Skip the query for this type and modify defaults based on - * interface number. - */ - if (features->type == WIRELESS && intf) { - if (intf->cur_altsetting->desc.bInterfaceNumber == 0) - features->device_type = WACOM_DEVICETYPE_WL_MONITOR; - else - features->device_type = WACOM_DEVICETYPE_NONE; - return; - } - - wacom_parse_hid(hdev, features); -} - -struct wacom_hdev_data { - struct list_head list; - struct kref kref; - struct hid_device *dev; - struct wacom_shared shared; -}; - -static LIST_HEAD(wacom_udev_list); -static DEFINE_MUTEX(wacom_udev_list_lock); - -static bool compare_device_paths(struct hid_device *hdev_a, - struct hid_device *hdev_b, char separator) -{ - int n1 = strrchr(hdev_a->phys, separator) - hdev_a->phys; - int n2 = strrchr(hdev_b->phys, separator) - hdev_b->phys; - - if (n1 != n2 || n1 <= 0 || n2 <= 0) - return false; - - return !strncmp(hdev_a->phys, hdev_b->phys, n1); -} - -static bool wacom_are_sibling(struct hid_device *hdev, - struct hid_device *sibling) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_features *features = &wacom->wacom_wac.features; - struct wacom *sibling_wacom = hid_get_drvdata(sibling); - struct wacom_features *sibling_features = &sibling_wacom->wacom_wac.features; - __u32 oVid = features->oVid ? features->oVid : hdev->vendor; - __u32 oPid = features->oPid ? features->oPid : hdev->product; - - /* The defined oVid/oPid must match that of the sibling */ - if (features->oVid != HID_ANY_ID && sibling->vendor != oVid) - return false; - if (features->oPid != HID_ANY_ID && sibling->product != oPid) - return false; - - /* - * Devices with the same VID/PID must share the same physical - * device path, while those with different VID/PID must share - * the same physical parent device path. - */ - if (hdev->vendor == sibling->vendor && hdev->product == sibling->product) { - if (!compare_device_paths(hdev, sibling, '/')) - return false; - } else { - if (!compare_device_paths(hdev, sibling, '.')) - return false; - } - - /* Skip the remaining heuristics unless you are a HID_GENERIC device */ - if (features->type != HID_GENERIC) - return true; - - /* - * Direct-input devices may not be siblings of indirect-input - * devices. - */ - if ((features->device_type & WACOM_DEVICETYPE_DIRECT) && - !(sibling_features->device_type & WACOM_DEVICETYPE_DIRECT)) - return false; - - /* - * Indirect-input devices may not be siblings of direct-input - * devices. - */ - if (!(features->device_type & WACOM_DEVICETYPE_DIRECT) && - (sibling_features->device_type & WACOM_DEVICETYPE_DIRECT)) - return false; - - /* Pen devices may only be siblings of touch devices */ - if ((features->device_type & WACOM_DEVICETYPE_PEN) && - !(sibling_features->device_type & WACOM_DEVICETYPE_TOUCH)) - return false; - - /* Touch devices may only be siblings of pen devices */ - if ((features->device_type & WACOM_DEVICETYPE_TOUCH) && - !(sibling_features->device_type & WACOM_DEVICETYPE_PEN)) - return false; - - /* - * No reason could be found for these two devices to NOT be - * siblings, so there's a good chance they ARE siblings - */ - return true; -} - -static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev) -{ - struct wacom_hdev_data *data; - - /* Try to find an already-probed interface from the same device */ - list_for_each_entry(data, &wacom_udev_list, list) { - if (compare_device_paths(hdev, data->dev, '/')) { - kref_get(&data->kref); - return data; - } - } - - /* Fallback to finding devices that appear to be "siblings" */ - list_for_each_entry(data, &wacom_udev_list, list) { - if (wacom_are_sibling(hdev, data->dev)) { - kref_get(&data->kref); - return data; - } - } - - return NULL; -} - -static void wacom_release_shared_data(struct kref *kref) -{ - struct wacom_hdev_data *data = - container_of(kref, struct wacom_hdev_data, kref); - - mutex_lock(&wacom_udev_list_lock); - list_del(&data->list); - mutex_unlock(&wacom_udev_list_lock); - - kfree(data); -} - -static void wacom_remove_shared_data(void *res) -{ - struct wacom *wacom = res; - struct wacom_hdev_data *data; - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - - if (wacom_wac->shared) { - data = container_of(wacom_wac->shared, struct wacom_hdev_data, - shared); - - if (wacom_wac->shared->touch == wacom->hdev) - wacom_wac->shared->touch = NULL; - else if (wacom_wac->shared->pen == wacom->hdev) - wacom_wac->shared->pen = NULL; - - kref_put(&data->kref, wacom_release_shared_data); - wacom_wac->shared = NULL; - } -} - -static int wacom_add_shared_data(struct hid_device *hdev) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_hdev_data *data; - int retval = 0; - - mutex_lock(&wacom_udev_list_lock); - - data = wacom_get_hdev_data(hdev); - if (!data) { - data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL); - if (!data) { - mutex_unlock(&wacom_udev_list_lock); - return -ENOMEM; - } - - kref_init(&data->kref); - data->dev = hdev; - list_add_tail(&data->list, &wacom_udev_list); - } - - mutex_unlock(&wacom_udev_list_lock); - - wacom_wac->shared = &data->shared; - - retval = devm_add_action_or_reset(&hdev->dev, wacom_remove_shared_data, wacom); - if (retval) - return retval; - - if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) - wacom_wac->shared->touch = hdev; - else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN) - wacom_wac->shared->pen = hdev; - - return retval; -} - -static int wacom_led_control(struct wacom *wacom) -{ - unsigned char *buf; - int retval; - unsigned char report_id = WAC_CMD_LED_CONTROL; - int buf_size = 9; - - if (!wacom->led.groups) - return -ENOTSUPP; - - if (wacom->wacom_wac.features.type == REMOTE) - return -ENOTSUPP; - - if (wacom->wacom_wac.pid) { /* wireless connected */ - report_id = WAC_CMD_WL_LED_CONTROL; - buf_size = 13; - } - else if (wacom->wacom_wac.features.type == INTUOSP2_BT) { - report_id = WAC_CMD_WL_INTUOSP2; - buf_size = 51; - } - buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (wacom->wacom_wac.features.type == HID_GENERIC) { - buf[0] = WAC_CMD_LED_CONTROL_GENERIC; - buf[1] = wacom->led.llv; - buf[2] = wacom->led.groups[0].select & 0x03; - - } else if ((wacom->wacom_wac.features.type >= INTUOS5S && - wacom->wacom_wac.features.type <= INTUOSPL)) { - /* - * Touch Ring and crop mark LED luminance may take on - * one of four values: - * 0 = Low; 1 = Medium; 2 = High; 3 = Off - */ - int ring_led = wacom->led.groups[0].select & 0x03; - int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03; - int crop_lum = 0; - unsigned char led_bits = (crop_lum << 4) | (ring_lum << 2) | (ring_led); - - buf[0] = report_id; - if (wacom->wacom_wac.pid) { - wacom_get_report(wacom->hdev, HID_FEATURE_REPORT, - buf, buf_size, WAC_CMD_RETRIES); - buf[0] = report_id; - buf[4] = led_bits; - } else - buf[1] = led_bits; - } - else if (wacom->wacom_wac.features.type == INTUOSP2_BT) { - buf[0] = report_id; - buf[4] = 100; // Power Connection LED (ORANGE) - buf[5] = 100; // BT Connection LED (BLUE) - buf[6] = 100; // Paper Mode (RED?) - buf[7] = 100; // Paper Mode (GREEN?) - buf[8] = 100; // Paper Mode (BLUE?) - buf[9] = wacom->led.llv; - buf[10] = wacom->led.groups[0].select & 0x03; - } - else { - int led = wacom->led.groups[0].select | 0x4; - - if (wacom->wacom_wac.features.type == WACOM_21UX2 || - wacom->wacom_wac.features.type == WACOM_24HD) - led |= (wacom->led.groups[1].select << 4) | 0x40; - - buf[0] = report_id; - buf[1] = led; - buf[2] = wacom->led.llv; - buf[3] = wacom->led.hlv; - buf[4] = wacom->led.img_lum; - } - - retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, buf_size, - WAC_CMD_RETRIES); - kfree(buf); - - return retval; -} - -static int wacom_led_putimage(struct wacom *wacom, int button_id, u8 xfer_id, - const unsigned len, const void *img) -{ - unsigned char *buf; - int i, retval; - const unsigned chunk_len = len / 4; /* 4 chunks are needed to be sent */ - - buf = kzalloc(chunk_len + 3 , GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Send 'start' command */ - buf[0] = WAC_CMD_ICON_START; - buf[1] = 1; - retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2, - WAC_CMD_RETRIES); - if (retval < 0) - goto out; - - buf[0] = xfer_id; - buf[1] = button_id & 0x07; - for (i = 0; i < 4; i++) { - buf[2] = i; - memcpy(buf + 3, img + i * chunk_len, chunk_len); - - retval = wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, - buf, chunk_len + 3, WAC_CMD_RETRIES); - if (retval < 0) - break; - } - - /* Send 'stop' */ - buf[0] = WAC_CMD_ICON_START; - buf[1] = 0; - wacom_set_report(wacom->hdev, HID_FEATURE_REPORT, buf, 2, - WAC_CMD_RETRIES); - -out: - kfree(buf); - return retval; -} - -static ssize_t wacom_led_select_store(struct device *dev, int set_id, - const char *buf, size_t count) -{ - struct hid_device *hdev = to_hid_device(dev); - struct wacom *wacom = hid_get_drvdata(hdev); - unsigned int id; - int err; - - err = kstrtouint(buf, 10, &id); - if (err) - return err; - - mutex_lock(&wacom->lock); - - wacom->led.groups[set_id].select = id & 0x3; - err = wacom_led_control(wacom); - - mutex_unlock(&wacom->lock); - - return err < 0 ? err : count; -} - -#define DEVICE_LED_SELECT_ATTR(SET_ID) \ -static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return wacom_led_select_store(dev, SET_ID, buf, count); \ -} \ -static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct hid_device *hdev = to_hid_device(dev);\ - struct wacom *wacom = hid_get_drvdata(hdev); \ - return scnprintf(buf, PAGE_SIZE, "%d\n", \ - wacom->led.groups[SET_ID].select); \ -} \ -static DEVICE_ATTR(status_led##SET_ID##_select, DEV_ATTR_RW_PERM, \ - wacom_led##SET_ID##_select_show, \ - wacom_led##SET_ID##_select_store) - -DEVICE_LED_SELECT_ATTR(0); -DEVICE_LED_SELECT_ATTR(1); - -static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest, - const char *buf, size_t count) -{ - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - mutex_lock(&wacom->lock); - - *dest = value & 0x7f; - err = wacom_led_control(wacom); - - mutex_unlock(&wacom->lock); - - return err < 0 ? err : count; -} - -#define DEVICE_LUMINANCE_ATTR(name, field) \ -static ssize_t wacom_##name##_luminance_store(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct hid_device *hdev = to_hid_device(dev);\ - struct wacom *wacom = hid_get_drvdata(hdev); \ - \ - return wacom_luminance_store(wacom, &wacom->led.field, \ - buf, count); \ -} \ -static ssize_t wacom_##name##_luminance_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct wacom *wacom = dev_get_drvdata(dev); \ - return scnprintf(buf, PAGE_SIZE, "%d\n", wacom->led.field); \ -} \ -static DEVICE_ATTR(name##_luminance, DEV_ATTR_RW_PERM, \ - wacom_##name##_luminance_show, \ - wacom_##name##_luminance_store) - -DEVICE_LUMINANCE_ATTR(status0, llv); -DEVICE_LUMINANCE_ATTR(status1, hlv); -DEVICE_LUMINANCE_ATTR(buttons, img_lum); - -static ssize_t wacom_button_image_store(struct device *dev, int button_id, - const char *buf, size_t count) -{ - struct hid_device *hdev = to_hid_device(dev); - struct wacom *wacom = hid_get_drvdata(hdev); - int err; - unsigned len; - u8 xfer_id; - - if (hdev->bus == BUS_BLUETOOTH) { - len = 256; - xfer_id = WAC_CMD_ICON_BT_XFER; - } else { - len = 1024; - xfer_id = WAC_CMD_ICON_XFER; - } - - if (count != len) - return -EINVAL; - - mutex_lock(&wacom->lock); - - err = wacom_led_putimage(wacom, button_id, xfer_id, len, buf); - - mutex_unlock(&wacom->lock); - - return err < 0 ? err : count; -} - -#define DEVICE_BTNIMG_ATTR(BUTTON_ID) \ -static ssize_t wacom_btnimg##BUTTON_ID##_store(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return wacom_button_image_store(dev, BUTTON_ID, buf, count); \ -} \ -static DEVICE_ATTR(button##BUTTON_ID##_rawimg, DEV_ATTR_WO_PERM, \ - NULL, wacom_btnimg##BUTTON_ID##_store) - -DEVICE_BTNIMG_ATTR(0); -DEVICE_BTNIMG_ATTR(1); -DEVICE_BTNIMG_ATTR(2); -DEVICE_BTNIMG_ATTR(3); -DEVICE_BTNIMG_ATTR(4); -DEVICE_BTNIMG_ATTR(5); -DEVICE_BTNIMG_ATTR(6); -DEVICE_BTNIMG_ATTR(7); - -static struct attribute *cintiq_led_attrs[] = { - &dev_attr_status_led0_select.attr, - &dev_attr_status_led1_select.attr, - NULL -}; - -static const struct attribute_group cintiq_led_attr_group = { - .name = "wacom_led", - .attrs = cintiq_led_attrs, -}; - -static struct attribute *intuos4_led_attrs[] = { - &dev_attr_status0_luminance.attr, - &dev_attr_status1_luminance.attr, - &dev_attr_status_led0_select.attr, - &dev_attr_buttons_luminance.attr, - &dev_attr_button0_rawimg.attr, - &dev_attr_button1_rawimg.attr, - &dev_attr_button2_rawimg.attr, - &dev_attr_button3_rawimg.attr, - &dev_attr_button4_rawimg.attr, - &dev_attr_button5_rawimg.attr, - &dev_attr_button6_rawimg.attr, - &dev_attr_button7_rawimg.attr, - NULL -}; - -static const struct attribute_group intuos4_led_attr_group = { - .name = "wacom_led", - .attrs = intuos4_led_attrs, -}; - -static struct attribute *intuos5_led_attrs[] = { - &dev_attr_status0_luminance.attr, - &dev_attr_status_led0_select.attr, - NULL -}; - -static const struct attribute_group intuos5_led_attr_group = { - .name = "wacom_led", - .attrs = intuos5_led_attrs, -}; - -static struct attribute *generic_led_attrs[] = { - &dev_attr_status0_luminance.attr, - &dev_attr_status_led0_select.attr, - NULL -}; - -static const struct attribute_group generic_led_attr_group = { - .name = "wacom_led", - .attrs = generic_led_attrs, -}; - -struct wacom_sysfs_group_devres { - const struct attribute_group *group; - struct kobject *root; -}; - -static void wacom_devm_sysfs_group_release(struct device *dev, void *res) -{ - struct wacom_sysfs_group_devres *devres = res; - struct kobject *kobj = devres->root; - - dev_dbg(dev, "%s: dropping reference to %s\n", - __func__, devres->group->name); - sysfs_remove_group(kobj, devres->group); -} - -static int __wacom_devm_sysfs_create_group(struct wacom *wacom, - struct kobject *root, - const struct attribute_group *group) -{ - struct wacom_sysfs_group_devres *devres; - int error; - - devres = devres_alloc(wacom_devm_sysfs_group_release, - sizeof(struct wacom_sysfs_group_devres), - GFP_KERNEL); - if (!devres) - return -ENOMEM; - - devres->group = group; - devres->root = root; - - error = sysfs_create_group(devres->root, group); - if (error) { - devres_free(devres); - return error; - } - - devres_add(&wacom->hdev->dev, devres); - - return 0; -} - -static int wacom_devm_sysfs_create_group(struct wacom *wacom, - const struct attribute_group *group) -{ - return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj, - group); -} - -static void wacom_devm_kfifo_release(struct device *dev, void *res) -{ - struct kfifo_rec_ptr_2 *devres = res; - - kfifo_free(devres); -} - -static int wacom_devm_kfifo_alloc(struct wacom *wacom) -{ - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct kfifo_rec_ptr_2 *pen_fifo; - int error; - - pen_fifo = devres_alloc(wacom_devm_kfifo_release, - sizeof(struct kfifo_rec_ptr_2), - GFP_KERNEL); - - if (!pen_fifo) - return -ENOMEM; - - error = kfifo_alloc(pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL); - if (error) { - devres_free(pen_fifo); - return error; - } - - devres_add(&wacom->hdev->dev, pen_fifo); - wacom_wac->pen_fifo = pen_fifo; - - return 0; -} - -static void wacom_led_groups_release(void *data) -{ - struct wacom *wacom = data; - - wacom->led.groups = NULL; -} - -static inline int wac_devm_add_action_or_reset(struct device *dev, - void (*action)(void *), void *data) -{ - int ret; - - ret = devm_add_action(dev, action, data); - if (ret) - action(data); - - return ret; -} - -static int wacom_led_groups_allocate(struct wacom *wacom, int count) -{ - struct wacom_group_leds *groups; - int error; - - groups = devm_kzalloc(&wacom->hdev->dev, - sizeof(struct wacom_group_leds) * count, - GFP_KERNEL); - if (!groups) - return -ENOMEM; - - error = wac_devm_add_action_or_reset(&wacom->hdev->dev, - wacom_led_groups_release, - wacom); - if (error) - return error; - - wacom->led.groups = groups; - - return 0; -} - -int wacom_initialize_leds(struct wacom *wacom) -{ - int error; - - if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD)) - return 0; - - /* Initialize default values */ - switch (wacom->wacom_wac.features.type) { - case HID_GENERIC: - if (!wacom->generic_has_leds) - return 0; - wacom->led.llv = 100; - - error = wacom_led_groups_allocate(wacom, 1); - if (error) { - hid_err(wacom->hdev, - "cannot create leds err: %d\n", error); - return error; - } - - error = wacom_devm_sysfs_create_group(wacom, - &generic_led_attr_group); - break; - - case INTUOS4S: - case INTUOS4: - case INTUOS4WL: - case INTUOS4L: - wacom->led.llv = 10; - wacom->led.hlv = 20; - wacom->led.img_lum = 10; - - error = wacom_led_groups_allocate(wacom, 1); - if (error) { - hid_err(wacom->hdev, - "cannot create leds err: %d\n", error); - return error; - } - - error = wacom_devm_sysfs_create_group(wacom, - &intuos4_led_attr_group); - break; - - case WACOM_24HD: - case WACOM_21UX2: - wacom->led.llv = 0; - wacom->led.hlv = 0; - wacom->led.img_lum = 0; - - error = wacom_led_groups_allocate(wacom, 2); - if (error) { - hid_err(wacom->hdev, - "cannot create leds err: %d\n", error); - return error; - } - - error = wacom_devm_sysfs_create_group(wacom, - &cintiq_led_attr_group); - break; - - case INTUOS5S: - case INTUOS5: - case INTUOS5L: - case INTUOSPS: - case INTUOSPM: - case INTUOSPL: - wacom->led.llv = 32; - wacom->led.hlv = 0; - wacom->led.img_lum = 0; - - error = wacom_led_groups_allocate(wacom, 1); - if (error) { - hid_err(wacom->hdev, - "cannot create leds err: %d\n", error); - return error; - } - - error = wacom_devm_sysfs_create_group(wacom, - &intuos5_led_attr_group); - break; - - case INTUOSP2_BT: - wacom->led.llv = 50; - error = wacom_led_groups_allocate(wacom, 1); - if (error) { - hid_err(wacom->hdev, - "cannot create leds err: %d\n", error); - return error; - } - return 0; - - case REMOTE: - error = wacom_led_groups_allocate(wacom, 5); - if (error) { - hid_err(wacom->hdev, - "cannot create leds err: %d\n", error); - return error; - } - return 0; - - default: - return 0; - } - - if (error) { - hid_err(wacom->hdev, - "cannot create sysfs group err: %d\n", error); - return error; - } - - return 0; -} - -static void wacom_init_work(struct work_struct *work) -{ - struct wacom *wacom = container_of(work, struct wacom, init_work.work); - - _wacom_query_tablet_data(wacom); - wacom_led_control(wacom); -} - -static void wacom_query_tablet_data(struct wacom *wacom) -{ - schedule_delayed_work(&wacom->init_work, msecs_to_jiffies(1000)); -} - -static enum power_supply_property wacom_battery_props[] = { - POWER_SUPPLY_PROP_MODEL_NAME, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_SCOPE, - POWER_SUPPLY_PROP_CAPACITY -}; - -static int wacom_battery_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ -#ifdef WACOM_POWERSUPPLY_41 - struct wacom_battery *battery = power_supply_get_drvdata(psy); -#else - struct wacom_battery *battery = container_of(psy, struct wacom_battery, battery); -#endif - int ret = 0; - - switch (psp) { - case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = battery->wacom->wacom_wac.name; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = battery->bat_connected; - break; - case POWER_SUPPLY_PROP_SCOPE: - val->intval = POWER_SUPPLY_SCOPE_DEVICE; - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = battery->battery_capacity; - break; - case POWER_SUPPLY_PROP_STATUS: - if (battery->bat_status != WACOM_POWER_SUPPLY_STATUS_AUTO) - val->intval = battery->bat_status; - else if (battery->bat_charging) - val->intval = POWER_SUPPLY_STATUS_CHARGING; - else if (battery->battery_capacity == 100 && - battery->ps_connected) - val->intval = POWER_SUPPLY_STATUS_FULL; - else if (battery->ps_connected) - val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; - else - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -#ifndef WACOM_POWERSUPPLY_41 -static int __wacom_initialize_battery(struct wacom *wacom, - struct wacom_battery *battery) -{ - static atomic_t battery_no = ATOMIC_INIT(0); - struct device *dev = &wacom->hdev->dev; - int error; - unsigned long n; - - n = atomic_inc_return(&battery_no) - 1; - - battery->battery.properties = wacom_battery_props; - battery->battery.num_properties = ARRAY_SIZE(wacom_battery_props); - battery->battery.get_property = wacom_battery_get_property; - sprintf(wacom->battery.bat_name, "wacom_battery_%ld", n); - battery->battery.name = wacom->battery.bat_name; - battery->battery.type = POWER_SUPPLY_TYPE_USB; - battery->battery.use_for_apm = 0; - - error = power_supply_register(dev, &battery->battery); - - if (error) - return error; - - power_supply_powers(WACOM_POWERSUPPLY_REF(battery->battery), dev); - - return 0; -} - -#else -static int __wacom_initialize_battery(struct wacom *wacom, - struct wacom_battery *battery) -{ - static atomic_t battery_no = ATOMIC_INIT(0); - struct device *dev = &wacom->hdev->dev; - struct power_supply_config psy_cfg = { .drv_data = battery, }; - struct power_supply *ps_bat; - struct power_supply_desc *bat_desc = &battery->bat_desc; - unsigned long n; - int error; - - if (!devres_open_group(dev, bat_desc, GFP_KERNEL)) - return -ENOMEM; - - battery->wacom = wacom; - - n = atomic_inc_return(&battery_no) - 1; - - bat_desc->properties = wacom_battery_props; - bat_desc->num_properties = ARRAY_SIZE(wacom_battery_props); - bat_desc->get_property = wacom_battery_get_property; - sprintf(battery->bat_name, "wacom_battery_%ld", n); - bat_desc->name = battery->bat_name; - bat_desc->type = POWER_SUPPLY_TYPE_BATTERY; - bat_desc->use_for_apm = 0; - - ps_bat = devm_power_supply_register(dev, bat_desc, &psy_cfg); - if (IS_ERR(ps_bat)) { - error = PTR_ERR(ps_bat); - goto err; - } - - power_supply_powers(ps_bat, &wacom->hdev->dev); - - battery->battery = ps_bat; - - devres_close_group(dev, bat_desc); - return 0; - -err: - devres_release_group(dev, bat_desc); - return error; -} -#endif - -static int wacom_initialize_battery(struct wacom *wacom) -{ - if (wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) - return __wacom_initialize_battery(wacom, &wacom->battery); - - return 0; -} - -static void wacom_destroy_battery(struct wacom *wacom) -{ - if (WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) { -#ifdef WACOM_POWERSUPPLY_41 - devres_release_group(&wacom->hdev->dev, - &wacom->battery.bat_desc); -#else - power_supply_unregister(&wacom->battery.battery); -#endif - WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery) = NULL; - } -} - -static ssize_t wacom_show_speed(struct device *dev, - struct device_attribute - *attr, char *buf) -{ - struct hid_device *hdev = to_hid_device(dev); - struct wacom *wacom = hid_get_drvdata(hdev); - - return snprintf(buf, PAGE_SIZE, "%i\n", wacom->wacom_wac.bt_high_speed); -} - -static ssize_t wacom_store_speed(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct hid_device *hdev = to_hid_device(dev); - struct wacom *wacom = hid_get_drvdata(hdev); - u8 new_speed; - - if (kstrtou8(buf, 0, &new_speed)) - return -EINVAL; - - if (new_speed != 0 && new_speed != 1) - return -EINVAL; - - wacom_bt_query_tablet_data(hdev, new_speed, &wacom->wacom_wac.features); - - return count; -} - -static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM, - wacom_show_speed, wacom_store_speed); - - -static ssize_t wacom_show_remote_mode(struct kobject *kobj, - struct kobj_attribute *kattr, - char *buf, int index) -{ - struct device *dev = kobj_to_dev(kobj->parent); - struct hid_device *hdev = to_hid_device(dev); - struct wacom *wacom = hid_get_drvdata(hdev); - u8 mode; - - mode = wacom->led.groups[index].select; - return sprintf(buf, "%d\n", mode < 3 ? mode : -1); -} - -#define DEVICE_EKR_ATTR_GROUP(SET_ID) \ -static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj, \ - struct kobj_attribute *kattr, char *buf) \ -{ \ - return wacom_show_remote_mode(kobj, kattr, buf, SET_ID); \ -} \ -static struct kobj_attribute remote##SET_ID##_mode_attr = { \ - .attr = {.name = "remote_mode", \ - .mode = DEV_ATTR_RO_PERM}, \ - .show = wacom_show_remote##SET_ID##_mode, \ -}; \ -static struct attribute *remote##SET_ID##_serial_attrs[] = { \ - &remote##SET_ID##_mode_attr.attr, \ - NULL \ -}; \ -static const struct attribute_group remote##SET_ID##_serial_group = { \ - .name = NULL, \ - .attrs = remote##SET_ID##_serial_attrs, \ -} - -DEVICE_EKR_ATTR_GROUP(0); -DEVICE_EKR_ATTR_GROUP(1); -DEVICE_EKR_ATTR_GROUP(2); -DEVICE_EKR_ATTR_GROUP(3); -DEVICE_EKR_ATTR_GROUP(4); - -static int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, - int index) -{ - int error = 0; - struct wacom_remote *remote = wacom->remote; - - remote->remotes[index].group.name = devm_kasprintf(&wacom->hdev->dev, - GFP_KERNEL, - "%d", serial); - if (!remote->remotes[index].group.name) - return -ENOMEM; - - error = __wacom_devm_sysfs_create_group(wacom, remote->remote_dir, - &remote->remotes[index].group); - if (error) { - remote->remotes[index].group.name = NULL; - hid_err(wacom->hdev, - "cannot create sysfs group err: %d\n", error); - return error; - } - - return 0; -} - -static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector) -{ - const size_t buf_size = 2; - unsigned char *buf; - int retval; - - buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - buf[0] = WAC_CMD_DELETE_PAIRING; - buf[1] = selector; - - retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf, - buf_size, WAC_CMD_RETRIES); - kfree(buf); - - return retval; -} - -static ssize_t wacom_store_unpair_remote(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - unsigned char selector = 0; - struct device *dev = kobj_to_dev(kobj->parent); - struct hid_device *hdev = to_hid_device(dev); - struct wacom *wacom = hid_get_drvdata(hdev); - int err; - - if (!strncmp(buf, "*\n", 2)) { - selector = WAC_CMD_UNPAIR_ALL; - } else { - hid_info(wacom->hdev, "remote: unrecognized unpair code: %s\n", - buf); - return -1; - } - - mutex_lock(&wacom->lock); - - err = wacom_cmd_unpair_remote(wacom, selector); - mutex_unlock(&wacom->lock); - - return err < 0 ? err : count; -} - -static struct kobj_attribute unpair_remote_attr = { - .attr = {.name = "unpair_remote", .mode = 0200}, - .store = wacom_store_unpair_remote, -}; - -static const struct attribute *remote_unpair_attrs[] = { - &unpair_remote_attr.attr, - NULL -}; - -static void wacom_remotes_destroy(void *data) -{ - struct wacom *wacom = data; - struct wacom_remote *remote = wacom->remote; - -#ifndef WACOM_POWERSUPPLY_41 - int i; - unsigned long flags; -#endif - - if (!remote) - return; - -#ifndef WACOM_POWERSUPPLY_41 - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - if (remote->remotes[i].registered) { - spin_lock_irqsave(&remote->remote_lock, flags); - remote->remotes[i].registered = false; - spin_unlock_irqrestore(&remote->remote_lock, flags); - - if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[i].battery.battery)) { - power_supply_unregister(&remote->remotes[i].battery.battery); - } - } - } -#endif - kobject_put(remote->remote_dir); - kfifo_free(&remote->remote_fifo); - wacom->remote = NULL; -} - -static int wacom_initialize_remotes(struct wacom *wacom) -{ - int error = 0; - struct wacom_remote *remote; - int i; - - if (wacom->wacom_wac.features.type != REMOTE) - return 0; - - remote = devm_kzalloc(&wacom->hdev->dev, sizeof(*wacom->remote), - GFP_KERNEL); - if (!remote) - return -ENOMEM; - - wacom->remote = remote; - - spin_lock_init(&remote->remote_lock); - - error = kfifo_alloc(&remote->remote_fifo, - 5 * sizeof(struct wacom_remote_data), - GFP_KERNEL); - if (error) { - hid_err(wacom->hdev, "failed allocating remote_fifo\n"); - return -ENOMEM; - } - - remote->remotes[0].group = remote0_serial_group; - remote->remotes[1].group = remote1_serial_group; - remote->remotes[2].group = remote2_serial_group; - remote->remotes[3].group = remote3_serial_group; - remote->remotes[4].group = remote4_serial_group; - - remote->remote_dir = kobject_create_and_add("wacom_remote", - &wacom->hdev->dev.kobj); - if (!remote->remote_dir) - return -ENOMEM; - - error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs); - - if (error) { - hid_err(wacom->hdev, - "cannot create sysfs group err: %d\n", error); - return error; - } - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN; - remote->remotes[i].serial = 0; - } - - error = wac_devm_add_action_or_reset(&wacom->hdev->dev, - wacom_remotes_destroy, wacom); - if (error) - return error; - - return 0; -} - -static struct input_dev *wacom_allocate_input(struct wacom *wacom) -{ - struct input_dev *input_dev; - struct hid_device *hdev = wacom->hdev; - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - input_dev = devm_input_allocate_device(&hdev->dev); - if (!input_dev) - return NULL; - - input_dev->name = wacom_wac->features.name; - input_dev->phys = hdev->phys; - input_dev->dev.parent = &hdev->dev; - input_dev->open = wacom_open; - input_dev->close = wacom_close; - input_dev->uniq = hdev->uniq; - input_dev->id.bustype = hdev->bus; - input_dev->id.vendor = hdev->vendor; - input_dev->id.product = wacom_wac->pid ? wacom_wac->pid : hdev->product; - input_dev->id.version = hdev->version; - input_set_drvdata(input_dev, wacom); - - return input_dev; -} - -static int wacom_allocate_inputs(struct wacom *wacom) -{ - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - wacom_wac->pen_input = wacom_allocate_input(wacom); - wacom_wac->touch_input = wacom_allocate_input(wacom); - wacom_wac->pad_input = wacom_allocate_input(wacom); - if (!wacom_wac->pen_input || - !wacom_wac->touch_input || - !wacom_wac->pad_input) - return -ENOMEM; - - wacom_wac->pen_input->name = wacom_wac->pen_name; - wacom_wac->touch_input->name = wacom_wac->touch_name; - wacom_wac->pad_input->name = wacom_wac->pad_name; - - return 0; -} - -static int wacom_setup_inputs(struct wacom *wacom) -{ - struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - int error = 0; - - pen_input_dev = wacom_wac->pen_input; - touch_input_dev = wacom_wac->touch_input; - pad_input_dev = wacom_wac->pad_input; - - if (!pen_input_dev || !touch_input_dev || !pad_input_dev) - return -EINVAL; - - error = wacom_setup_pen_input_capabilities(pen_input_dev, wacom_wac); - if (error) { - /* no pen in use on this interface */ - input_free_device(pen_input_dev); - wacom_wac->pen_input = NULL; - pen_input_dev = NULL; - } - - error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac); - if (error) { - /* no touch in use on this interface */ - input_free_device(touch_input_dev); - wacom_wac->touch_input = NULL; - touch_input_dev = NULL; - } - - error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); - if (error) { - /* no pad events using this interface */ - input_free_device(pad_input_dev); - wacom_wac->pad_input = NULL; - pad_input_dev = NULL; - } - - return 0; -} - -static int wacom_register_inputs(struct wacom *wacom) -{ - struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - int error = 0; - - pen_input_dev = wacom_wac->pen_input; - touch_input_dev = wacom_wac->touch_input; - pad_input_dev = wacom_wac->pad_input; - - if (pen_input_dev) { - error = input_register_device(pen_input_dev); - if (error) - goto fail; - } - - if (touch_input_dev) { - error = input_register_device(touch_input_dev); - if (error) - goto fail; - } - - if (pad_input_dev) { - error = input_register_device(pad_input_dev); - if (error) - goto fail; - } - - return 0; - -fail: - wacom_wac->pad_input = NULL; - wacom_wac->touch_input = NULL; - wacom_wac->pen_input = NULL; - return error; -} - -/* - * Not all devices report physical dimensions from HID. - * Compute the default from hardcoded logical dimension - * and resolution before driver overwrites them. - */ -static void wacom_set_default_phy(struct wacom_features *features) -{ - if (features->x_resolution) { - features->x_phy = (features->x_max * 100) / - features->x_resolution; - features->y_phy = (features->y_max * 100) / - features->y_resolution; - } -} - -static void wacom_calculate_res(struct wacom_features *features) -{ - /* set unit to "100th of a mm" for devices not reported by HID */ - if (!features->unit) { - features->unit = 0x11; - features->unitExpo = -3; - } - - features->x_resolution = wacom_calc_hid_res(features->x_max, - features->x_phy, - features->unit, - features->unitExpo); - features->y_resolution = wacom_calc_hid_res(features->y_max, - features->y_phy, - features->unit, - features->unitExpo); -} - -void wacom_battery_work(struct work_struct *work) -{ - struct wacom *wacom = container_of(work, struct wacom, battery_work); - - if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) && - !WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) { - wacom_initialize_battery(wacom); - } - else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) && - WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) { - wacom_destroy_battery(wacom); - } -} - -static size_t wacom_compute_pktlen(struct hid_device *hdev) -{ - struct hid_report_enum *report_enum; - struct hid_report *report; - size_t size = 0; - - report_enum = hdev->report_enum + HID_INPUT_REPORT; - - list_for_each_entry(report, &report_enum->report_list, list) { - size_t report_size = wacom_hid_report_len(report); - if (report_size > size) - size = report_size; - } - - return size; -} - -static void wacom_update_name(struct wacom *wacom, const char *suffix) -{ - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - char name[WACOM_NAME_MAX - 20]; /* Leave some room for suffixes */ - - /* Generic devices name unspecified */ - if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) { - char *product_name = wacom->hdev->name; - - if (wacom_is_using_usb_driver(wacom->hdev)) { - struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent); - struct usb_device *dev = interface_to_usbdev(intf); - product_name = dev->product; - } - - if (wacom->hdev->bus == BUS_I2C) { - snprintf(name, sizeof(name), "%s %X", - features->name, wacom->hdev->product); - } else if (strstr(product_name, "Wacom") || - strstr(product_name, "wacom") || - strstr(product_name, "WACOM")) { - strlcpy(name, product_name, sizeof(name)); - } else { - snprintf(name, sizeof(name), "Wacom %s", product_name); - } - - /* strip out excess whitespaces */ - while (1) { - char *gap = strstr(name, " "); - if (gap == NULL) - break; - /* shift everything including the terminator */ - memmove(gap, gap+1, strlen(gap)); - } - - /* get rid of trailing whitespace */ - if (name[strlen(name)-1] == ' ') - name[strlen(name)-1] = '\0'; - } else { - strlcpy(name, features->name, sizeof(name)); - } - - snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s%s", - name, suffix); - - /* Append the device type to the name */ - snprintf(wacom_wac->pen_name, sizeof(wacom_wac->pen_name), - "%s%s Pen", name, suffix); - snprintf(wacom_wac->touch_name, sizeof(wacom_wac->touch_name), - "%s%s Finger", name, suffix); - snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), - "%s%s Pad", name, suffix); -} - -static void wacom_release_resources(struct wacom *wacom) -{ - struct hid_device *hdev = wacom->hdev; - - if (!wacom->resources) - return; - - devres_release_group(&hdev->dev, wacom); - - wacom->resources = false; - - wacom->wacom_wac.pen_input = NULL; - wacom->wacom_wac.touch_input = NULL; - wacom->wacom_wac.pad_input = NULL; -} - -static void wacom_set_shared_values(struct wacom_wac *wacom_wac) -{ - if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) { - wacom_wac->shared->type = wacom_wac->features.type; - wacom_wac->shared->touch_input = wacom_wac->touch_input; - } - - if (wacom_wac->has_mute_touch_switch) { - wacom_wac->shared->has_mute_touch_switch = true; - /* Hardware touch switch may be off. Wait until - * we know the switch state to decide is_touch_on. - * Softkey state should be initialized to "on" to - * match historic default. - */ - if (wacom_wac->is_soft_touch_switch) - wacom_wac->shared->is_touch_on = true; - } - - if (wacom_wac->shared->has_mute_touch_switch && - wacom_wac->shared->touch_input) { - set_bit(EV_SW, wacom_wac->shared->touch_input->evbit); - input_set_capability(wacom_wac->shared->touch_input, EV_SW, - SW_MUTE_DEVICE); - } -} - -static int wacom_parse_and_register(struct wacom *wacom, bool wireless) -{ - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - struct hid_device *hdev = wacom->hdev; - int error; - unsigned int connect_mask = HID_CONNECT_HIDRAW; - - features->pktlen = wacom_compute_pktlen(hdev); - if (features->pktlen > WACOM_PKGLEN_MAX) - return -EINVAL; - - if (!devres_open_group(&hdev->dev, wacom, GFP_KERNEL)) - return -ENOMEM; - - wacom->resources = true; - - error = wacom_allocate_inputs(wacom); - if (error) - goto fail_open_group; - - /* - * Bamboo Pad has a generic hid handling for the Pen, and we switch it - * into debug mode for the touch part. - * We ignore the other interfaces. - */ - if (features->type == BAMBOO_PAD) { - if (features->pktlen == WACOM_PKGLEN_PENABLED) { - features->type = HID_GENERIC; - } else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) && - (features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) { - error = -ENODEV; - goto fail_allocate_inputs; - } - } - - /* set the default size in case we do not get them from hid */ - wacom_set_default_phy(features); - - /* Retrieve the physical and logical size for touch devices */ - wacom_retrieve_hid_descriptor(hdev, features); - wacom_setup_device_quirks(wacom); - - if (features->device_type == WACOM_DEVICETYPE_NONE && - features->type != WIRELESS) { - error = features->type == HID_GENERIC ? -ENODEV : 0; - - dev_warn(&hdev->dev, "Unknown device_type for '%s'. %s.", - hdev->name, - error ? "Ignoring" : "Assuming pen"); - - if (error) - goto fail_parsed; - - features->device_type |= WACOM_DEVICETYPE_PEN; - } - - wacom_calculate_res(features); - - wacom_update_name(wacom, wireless ? " (WL)" : ""); - - /* pen only Bamboo neither support touch nor pad */ - if ((features->type == BAMBOO_PEN) && - ((features->device_type & WACOM_DEVICETYPE_TOUCH) || - (features->device_type & WACOM_DEVICETYPE_PAD))) { - error = -ENODEV; - goto fail_parsed; - } - - error = wacom_add_shared_data(hdev); - if (error) - goto fail_shared_data; - - error = wacom_setup_inputs(wacom); - if (error) - goto fail_setup_inputs; - - if (features->type == HID_GENERIC) -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) - hdev->claimed |= 8; /* HID_CLAIMED_DRIVER */ -#else - connect_mask |= HID_CONNECT_DRIVER; -#endif - - /* Regular HID work starts now */ - error = hid_hw_start(hdev, connect_mask); - if (error) { - hid_err(hdev, "hw start failed\n"); - goto fail_hw_start; - } - - error = wacom_register_inputs(wacom); - if (error) - goto fail_register_inputs; - - if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD) { - error = wacom_initialize_leds(wacom); - if (error) - goto fail_leds; - - error = wacom_initialize_remotes(wacom); - if (error) - goto fail_remote; - } - - if (!wireless) { - /* Note that if query fails it is not a hard failure */ - wacom_query_tablet_data(wacom); - } - - /* touch only Bamboo doesn't support pen */ - if ((features->type == BAMBOO_TOUCH) && - (features->device_type & WACOM_DEVICETYPE_PEN)) { - cancel_delayed_work_sync(&wacom->init_work); - _wacom_query_tablet_data(wacom); - error = -ENODEV; - goto fail_quirks; - } - - if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) { - error = hid_hw_open(hdev); - if (error) { - hid_err(hdev, "hw open failed\n"); - goto fail_quirks; - } - } - - wacom_set_shared_values(wacom_wac); - devres_close_group(&hdev->dev, wacom); - - return 0; - -fail_quirks: - hid_hw_stop(hdev); -fail_remote: -fail_leds: -fail_register_inputs: -#ifndef WACOM_POWERSUPPLY_41 - wacom_destroy_battery(wacom); -#endif -fail_hw_start: -fail_setup_inputs: -fail_shared_data: -fail_parsed: -fail_allocate_inputs: -fail_open_group: - wacom_release_resources(wacom); - return error; -} - -static void wacom_wireless_work(struct work_struct *work) -{ - struct wacom *wacom = container_of(work, struct wacom, wireless_work); - struct usb_device *usbdev = wacom->usbdev; - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct hid_device *hdev1, *hdev2; - struct wacom *wacom1, *wacom2; - struct wacom_wac *wacom_wac1, *wacom_wac2; - int error; - - /* - * Regardless if this is a disconnect or a new tablet, - * remove any existing input and battery devices. - */ - - wacom_destroy_battery(wacom); - - if (!usbdev) - return; - - /* Stylus interface */ - hdev1 = usb_get_intfdata(usbdev->config->interface[1]); - wacom1 = hid_get_drvdata(hdev1); - wacom_wac1 = &(wacom1->wacom_wac); - wacom_release_resources(wacom1); - - /* Touch interface */ - hdev2 = usb_get_intfdata(usbdev->config->interface[2]); - wacom2 = hid_get_drvdata(hdev2); - wacom_wac2 = &(wacom2->wacom_wac); - wacom_release_resources(wacom2); - - if (wacom_wac->pid == 0) { - hid_info(wacom->hdev, "wireless tablet disconnected\n"); - } else { - const struct hid_device_id *id = wacom_ids; - - hid_info(wacom->hdev, "wireless tablet connected with PID %x\n", - wacom_wac->pid); - - while (id->bus) { - if (id->vendor == USB_VENDOR_ID_WACOM && - id->product == wacom_wac->pid) - break; - id++; - } - - if (!id->bus) { - hid_info(wacom->hdev, "ignoring unknown PID.\n"); - return; - } - - /* Stylus interface */ - wacom_wac1->features = - *((struct wacom_features *)id->driver_data); - - wacom_wac1->pid = wacom_wac->pid; - hid_hw_stop(hdev1); - error = wacom_parse_and_register(wacom1, true); - if (error) - goto fail; - - /* Touch interface */ - if (wacom_wac1->features.touch_max || - (wacom_wac1->features.type >= INTUOSHT && - wacom_wac1->features.type <= BAMBOO_PT)) { - wacom_wac2->features = - *((struct wacom_features *)id->driver_data); - wacom_wac2->pid = wacom_wac->pid; - hid_hw_stop(hdev2); - error = wacom_parse_and_register(wacom2, true); - if (error) - goto fail; - } - - strlcpy(wacom_wac->name, wacom_wac1->name, - sizeof(wacom_wac->name)); - } - - return; - -fail: - wacom_release_resources(wacom1); - wacom_release_resources(wacom2); - return; -} - -#ifndef WACOM_POWERSUPPLY_41 -static void wacom_destroy_remote_battery(struct wacom_battery *battery) -{ - if (battery->battery.dev) { - power_supply_unregister(&battery->battery); - battery->battery.dev = NULL; - } -} -#endif - -static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index) -{ - struct wacom_remote *remote = wacom->remote; - u32 serial = remote->remotes[index].serial; - int i; - unsigned long flags; - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - if (remote->remotes[i].serial == serial) { - - spin_lock_irqsave(&remote->remote_lock, flags); - remote->remotes[i].registered = false; - spin_unlock_irqrestore(&remote->remote_lock, flags); - -#ifdef WACOM_POWERSUPPLY_41 - if (remote->remotes[i].battery.battery) - devres_release_group(&wacom->hdev->dev, - &remote->remotes[i].battery.bat_desc); - remote->remotes[i].battery.battery = NULL; -#else - if (remote->remotes[index].battery.battery.dev) - wacom_destroy_remote_battery(&remote->remotes[index].battery); -#endif - - if (remote->remotes[i].group.name) - devres_release_group(&wacom->hdev->dev, - &remote->remotes[i]); - - remote->remotes[i].serial = 0; - remote->remotes[i].group.name = NULL; - wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN; - } - } -} - -static int wacom_remote_create_one(struct wacom *wacom, u32 serial, - unsigned int index) -{ - struct wacom_remote *remote = wacom->remote; - struct device *dev = &wacom->hdev->dev; - int error, k; - - /* A remote can pair more than once with an EKR, - * check to make sure this serial isn't already paired. - */ - for (k = 0; k < WACOM_MAX_REMOTES; k++) { - if (remote->remotes[k].serial == serial) - break; - } - - if (k < WACOM_MAX_REMOTES) { - remote->remotes[index].serial = serial; - return 0; - } - - if (!devres_open_group(dev, &remote->remotes[index], GFP_KERNEL)) - return -ENOMEM; - - error = wacom_remote_create_attr_group(wacom, serial, index); - if (error) - goto fail; - - remote->remotes[index].input = wacom_allocate_input(wacom); - if (!remote->remotes[index].input) { - error = -ENOMEM; - goto fail; - } - remote->remotes[index].input->uniq = remote->remotes[index].group.name; - remote->remotes[index].input->name = wacom->wacom_wac.pad_name; - - if (!remote->remotes[index].input->name) { - error = -EINVAL; - goto fail; - } - - error = wacom_setup_pad_input_capabilities(remote->remotes[index].input, - &wacom->wacom_wac); - if (error) - goto fail; - - remote->remotes[index].serial = serial; - - error = input_register_device(remote->remotes[index].input); - if (error) - goto fail; - - remote->remotes[index].registered = true; - - devres_close_group(dev, &remote->remotes[index]); - return 0; - -fail: - devres_release_group(dev, &remote->remotes[index]); - remote->remotes[index].serial = 0; - return error; -} - -static int wacom_remote_attach_battery(struct wacom *wacom, int index) -{ - struct wacom_remote *remote = wacom->remote; - int error; - - if (!remote->remotes[index].registered) - return 0; - - if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[index].battery.battery)) - return 0; - - if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN) - return 0; - - error = __wacom_initialize_battery(wacom, - &wacom->remote->remotes[index].battery); - if (error) - return error; - - return 0; -} - -static void wacom_remote_work(struct work_struct *work) -{ - struct wacom *wacom = container_of(work, struct wacom, remote_work); - struct wacom_remote *remote = wacom->remote; - struct wacom_remote_data data; - unsigned long flags; - unsigned int count; - u32 serial; - int i; - - spin_lock_irqsave(&remote->remote_lock, flags); - - count = kfifo_out(&remote->remote_fifo, &data, sizeof(data)); - - if (count != sizeof(data)) { - hid_err(wacom->hdev, - "workitem triggered without status available\n"); - spin_unlock_irqrestore(&remote->remote_lock, flags); - return; - } - - if (!kfifo_is_empty(&remote->remote_fifo)) - wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_REMOTE); - - spin_unlock_irqrestore(&remote->remote_lock, flags); - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - serial = data.remote[i].serial; - if (data.remote[i].connected) { - - if (remote->remotes[i].serial == serial) { - wacom_remote_attach_battery(wacom, i); - continue; - } - - if (remote->remotes[i].serial) - wacom_remote_destroy_one(wacom, i); - - wacom_remote_create_one(wacom, serial, i); - - } else if (remote->remotes[i].serial) { - wacom_remote_destroy_one(wacom, i); - } - } -} - -static void wacom_mode_change_work(struct work_struct *work) -{ - struct wacom *wacom = container_of(work, struct wacom, mode_change_work); - struct wacom_shared *shared = wacom->wacom_wac.shared; - struct wacom *wacom1 = NULL; - struct wacom *wacom2 = NULL; - bool is_direct = wacom->wacom_wac.is_direct_mode; - int error = 0; - - if (shared->pen) { - wacom1 = hid_get_drvdata(shared->pen); - wacom_release_resources(wacom1); - hid_hw_stop(wacom1->hdev); - wacom1->wacom_wac.has_mode_change = true; - wacom1->wacom_wac.is_direct_mode = is_direct; - } - - if (shared->touch) { - wacom2 = hid_get_drvdata(shared->touch); - wacom_release_resources(wacom2); - hid_hw_stop(wacom2->hdev); - wacom2->wacom_wac.has_mode_change = true; - wacom2->wacom_wac.is_direct_mode = is_direct; - } - - if (wacom1) { - error = wacom_parse_and_register(wacom1, false); - if (error) - return; - } - - if (wacom2) { - error = wacom_parse_and_register(wacom2, false); - if (error) - return; - } - - return; -} - -static int wacom_probe(struct hid_device *hdev, - const struct hid_device_id *id) -{ - struct wacom *wacom; - struct wacom_wac *wacom_wac; - struct wacom_features *features; - int error; - - if (!id->driver_data) - return -EINVAL; - - hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; - - /* hid-core sets this quirk for the boot interface */ - hdev->quirks &= ~HID_QUIRK_NOGET; - - wacom = devm_kzalloc(&hdev->dev, sizeof(struct wacom), GFP_KERNEL); - if (!wacom) - return -ENOMEM; - - hid_set_drvdata(hdev, wacom); - wacom->hdev = hdev; - - wacom_wac = &wacom->wacom_wac; - wacom_wac->features = *((struct wacom_features *)id->driver_data); - features = &wacom_wac->features; - - if (features->check_for_hid_type && features->hid_type != hdev->type) { - error = -ENODEV; - goto fail; - } - - error = wacom_devm_kfifo_alloc(wacom); - if (error) - goto fail; - - wacom_wac->hid_data.inputmode = -1; - wacom_wac->mode_report = -1; - - if (wacom_is_using_usb_driver(hdev)) { - struct usb_interface *intf = to_usb_interface(hdev->dev.parent); - struct usb_device *dev = interface_to_usbdev(intf); - - wacom->usbdev = dev; - wacom->intf = intf; - } - - mutex_init(&wacom->lock); - INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work); - INIT_WORK(&wacom->wireless_work, wacom_wireless_work); - INIT_WORK(&wacom->battery_work, wacom_battery_work); - INIT_WORK(&wacom->remote_work, wacom_remote_work); - INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work); - setup_timer(&wacom->idleprox_timer, &wacom_idleprox_timeout, (unsigned long) wacom); - - /* ask for the report descriptor to be loaded by HID */ - error = hid_parse(hdev); - if (error) { - hid_err(hdev, "parse failed\n"); - goto fail; - } - - if (features->type == BOOTLOADER) { - hid_warn(hdev, "Using device in hidraw-only mode"); - return hid_hw_start(hdev, HID_CONNECT_HIDRAW); - } - - error = wacom_parse_and_register(wacom, false); - if (error) - goto fail; - - if (hdev->bus == BUS_BLUETOOTH) { - error = device_create_file(&hdev->dev, &dev_attr_speed); - if (error) - hid_warn(hdev, - "can't create sysfs speed attribute err: %d\n", - error); - } - - wacom_wac->probe_complete = true; - return 0; - -fail: - hid_set_drvdata(hdev, NULL); - return error; -} - -static void wacom_remove(struct hid_device *hdev) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - - if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) - hid_hw_close(hdev); - - hid_hw_stop(hdev); - - cancel_delayed_work_sync(&wacom->init_work); - cancel_work_sync(&wacom->wireless_work); - cancel_work_sync(&wacom->battery_work); - cancel_work_sync(&wacom->remote_work); - cancel_work_sync(&wacom->mode_change_work); - del_timer_sync(&wacom->idleprox_timer); - if (hdev->bus == BUS_BLUETOOTH) - device_remove_file(&hdev->dev, &dev_attr_speed); -#ifndef WACOM_POWERSUPPLY_41 - wacom_destroy_battery(wacom); -#endif - wacom_remove_shared_data(wacom); - - /* make sure we don't trigger the LEDs */ - wacom_led_groups_release(wacom); - - if (wacom->wacom_wac.features.type != REMOTE) - wacom_release_resources(wacom); - - hid_set_drvdata(hdev, NULL); -} - -#ifdef CONFIG_PM -static int wacom_resume(struct hid_device *hdev) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - - mutex_lock(&wacom->lock); - - /* switch to wacom mode first */ - _wacom_query_tablet_data(wacom); - wacom_led_control(wacom); - - mutex_unlock(&wacom->lock); - - return 0; -} - -static int wacom_reset_resume(struct hid_device *hdev) -{ - return wacom_resume(hdev); -} -#endif /* CONFIG_PM */ - -static struct hid_driver wacom_driver = { - .name = "wacom", - .id_table = wacom_ids, - .probe = wacom_probe, - .remove = wacom_remove, - .report = wacom_wac_report, -#ifdef CONFIG_PM - .resume = wacom_resume, - .reset_resume = wacom_reset_resume, -#endif - .raw_event = wacom_raw_event, -}; -module_hid_driver(wacom_driver); - -MODULE_VERSION(DRIVER_VERSION); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/3.17/wacom_w8001.c b/3.17/wacom_w8001.c deleted file mode 100644 index 691285ac..00000000 --- a/3.17/wacom_w8001.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Wacom W8001 penabled serial touchscreen driver - * - * Copyright (c) 2008 Jaya Kumar - * Copyright (c) 2010 Red Hat, Inc. - * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * Layout based on Elo serial touchscreen driver by Vojtech Pavlik - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_DESC "Wacom W8001 serial touchscreen driver" - -MODULE_AUTHOR("Jaya Kumar "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -#define W8001_MAX_PHYS 42 - -#define W8001_MAX_LENGTH 13 -#define W8001_LEAD_MASK 0x80 -#define W8001_LEAD_BYTE 0x80 -#define W8001_TAB_MASK 0x40 -#define W8001_TAB_BYTE 0x40 -/* set in first byte of touch data packets */ -#define W8001_TOUCH_MASK (0x10 | W8001_LEAD_MASK) -#define W8001_TOUCH_BYTE (0x10 | W8001_LEAD_BYTE) - -#define W8001_QUERY_PACKET 0x20 - -#define W8001_CMD_STOP '0' -#define W8001_CMD_START '1' -#define W8001_CMD_QUERY '*' -#define W8001_CMD_TOUCHQUERY '%' - -/* length of data packets in bytes, depends on device. */ -#define W8001_PKTLEN_TOUCH93 5 -#define W8001_PKTLEN_TOUCH9A 7 -#define W8001_PKTLEN_TPCPEN 9 -#define W8001_PKTLEN_TPCCTL 11 /* control packet */ -#define W8001_PKTLEN_TOUCH2FG 13 - -/* resolution in points/mm */ -#define W8001_PEN_RESOLUTION 100 -#define W8001_TOUCH_RESOLUTION 10 - -struct w8001_coord { - u8 rdy; - u8 tsw; - u8 f1; - u8 f2; - u16 x; - u16 y; - u16 pen_pressure; - u8 tilt_x; - u8 tilt_y; -}; - -/* touch query reply packet */ -struct w8001_touch_query { - u16 x; - u16 y; - u8 panel_res; - u8 capacity_res; - u8 sensor_id; -}; - -/* - * Per-touchscreen data. - */ - -struct w8001 { - struct input_dev *pen_dev; - struct input_dev *touch_dev; - struct serio *serio; - struct completion cmd_done; - int id; - int idx; - unsigned char response_type; - unsigned char response[W8001_MAX_LENGTH]; - unsigned char data[W8001_MAX_LENGTH]; - char phys[W8001_MAX_PHYS]; - int type; - unsigned int pktlen; - u16 max_touch_x; - u16 max_touch_y; - u16 max_pen_x; - u16 max_pen_y; - char pen_name[64]; - char touch_name[64]; - int open_count; - struct mutex mutex; -}; - -static void parse_pen_data(u8 *data, struct w8001_coord *coord) -{ - memset(coord, 0, sizeof(*coord)); - - coord->rdy = data[0] & 0x20; - coord->tsw = data[0] & 0x01; - coord->f1 = data[0] & 0x02; - coord->f2 = data[0] & 0x04; - - coord->x = (data[1] & 0x7F) << 9; - coord->x |= (data[2] & 0x7F) << 2; - coord->x |= (data[6] & 0x60) >> 5; - - coord->y = (data[3] & 0x7F) << 9; - coord->y |= (data[4] & 0x7F) << 2; - coord->y |= (data[6] & 0x18) >> 3; - - coord->pen_pressure = data[5] & 0x7F; - coord->pen_pressure |= (data[6] & 0x07) << 7 ; - - coord->tilt_x = data[7] & 0x7F; - coord->tilt_y = data[8] & 0x7F; -} - -static void parse_single_touch(u8 *data, struct w8001_coord *coord) -{ - coord->x = (data[1] << 7) | data[2]; - coord->y = (data[3] << 7) | data[4]; - coord->tsw = data[0] & 0x01; -} - -static void scale_touch_coordinates(struct w8001 *w8001, - unsigned int *x, unsigned int *y) -{ - if (w8001->max_pen_x && w8001->max_touch_x) - *x = *x * w8001->max_pen_x / w8001->max_touch_x; - - if (w8001->max_pen_y && w8001->max_touch_y) - *y = *y * w8001->max_pen_y / w8001->max_touch_y; -} - -static void parse_multi_touch(struct w8001 *w8001) -{ - struct input_dev *dev = w8001->touch_dev; - unsigned char *data = w8001->data; - unsigned int x, y; - int i; - int count = 0; - - for (i = 0; i < 2; i++) { - bool touch = data[0] & (1 << i); - - input_mt_slot(dev, i); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch); - if (touch) { - x = (data[6 * i + 1] << 7) | data[6 * i + 2]; - y = (data[6 * i + 3] << 7) | data[6 * i + 4]; - /* data[5,6] and [11,12] is finger capacity */ - - /* scale to pen maximum */ - scale_touch_coordinates(w8001, &x, &y); - - input_report_abs(dev, ABS_MT_POSITION_X, x); - input_report_abs(dev, ABS_MT_POSITION_Y, y); - count++; - } - } - - /* emulate single touch events when stylus is out of proximity. - * This is to make single touch backward support consistent - * across all Wacom single touch devices. - */ - if (w8001->type != BTN_TOOL_PEN && - w8001->type != BTN_TOOL_RUBBER) { - w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED; - input_mt_report_pointer_emulation(dev, true); - } - - input_sync(dev); -} - -static void parse_touchquery(u8 *data, struct w8001_touch_query *query) -{ - memset(query, 0, sizeof(*query)); - - query->panel_res = data[1]; - query->sensor_id = data[2] & 0x7; - query->capacity_res = data[7]; - - query->x = data[3] << 9; - query->x |= data[4] << 2; - query->x |= (data[2] >> 5) & 0x3; - - query->y = data[5] << 9; - query->y |= data[6] << 2; - query->y |= (data[2] >> 3) & 0x3; - - /* Early days' single-finger touch models need the following defaults */ - if (!query->x && !query->y) { - query->x = 1024; - query->y = 1024; - if (query->panel_res) - query->x = query->y = (1 << query->panel_res); - query->panel_res = W8001_TOUCH_RESOLUTION; - } -} - -static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) -{ - struct input_dev *dev = w8001->pen_dev; - - /* - * We have 1 bit for proximity (rdy) and 3 bits for tip, side, - * side2/eraser. If rdy && f2 are set, this can be either pen + side2, - * or eraser. Assume: - * - if dev is already in proximity and f2 is toggled → pen + side2 - * - if dev comes into proximity with f2 set → eraser - * If f2 disappears after assuming eraser, fake proximity out for - * eraser and in for pen. - */ - - switch (w8001->type) { - case BTN_TOOL_RUBBER: - if (!coord->f2) { - input_report_abs(dev, ABS_PRESSURE, 0); - input_report_key(dev, BTN_TOUCH, 0); - input_report_key(dev, BTN_STYLUS, 0); - input_report_key(dev, BTN_STYLUS2, 0); - input_report_key(dev, BTN_TOOL_RUBBER, 0); - input_sync(dev); - w8001->type = BTN_TOOL_PEN; - } - break; - - case BTN_TOOL_FINGER: - case KEY_RESERVED: - w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - break; - - default: - input_report_key(dev, BTN_STYLUS2, coord->f2); - break; - } - - input_report_abs(dev, ABS_X, coord->x); - input_report_abs(dev, ABS_Y, coord->y); - input_report_abs(dev, ABS_PRESSURE, coord->pen_pressure); - input_report_key(dev, BTN_TOUCH, coord->tsw); - input_report_key(dev, BTN_STYLUS, coord->f1); - input_report_key(dev, w8001->type, coord->rdy); - input_sync(dev); - - if (!coord->rdy) - w8001->type = KEY_RESERVED; -} - -static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord) -{ - struct input_dev *dev = w8001->touch_dev; - unsigned int x = coord->x; - unsigned int y = coord->y; - - /* scale to pen maximum */ - scale_touch_coordinates(w8001, &x, &y); - - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); - input_report_key(dev, BTN_TOUCH, coord->tsw); - - input_sync(dev); - - w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED; -} - -static irqreturn_t w8001_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) -{ - struct w8001 *w8001 = serio_get_drvdata(serio); - struct w8001_coord coord; - unsigned char tmp; - - w8001->data[w8001->idx] = data; - switch (w8001->idx++) { - case 0: - if ((data & W8001_LEAD_MASK) != W8001_LEAD_BYTE) { - pr_debug("w8001: unsynchronized data: 0x%02x\n", data); - w8001->idx = 0; - } - break; - - case W8001_PKTLEN_TOUCH93 - 1: - case W8001_PKTLEN_TOUCH9A - 1: - tmp = w8001->data[0] & W8001_TOUCH_BYTE; - if (tmp != W8001_TOUCH_BYTE) - break; - - if (w8001->pktlen == w8001->idx) { - w8001->idx = 0; - if (w8001->type != BTN_TOOL_PEN && - w8001->type != BTN_TOOL_RUBBER) { - parse_single_touch(w8001->data, &coord); - report_single_touch(w8001, &coord); - } - } - break; - - /* Pen coordinates packet */ - case W8001_PKTLEN_TPCPEN - 1: - tmp = w8001->data[0] & W8001_TAB_MASK; - if (unlikely(tmp == W8001_TAB_BYTE)) - break; - - tmp = w8001->data[0] & W8001_TOUCH_BYTE; - if (tmp == W8001_TOUCH_BYTE) - break; - - w8001->idx = 0; - parse_pen_data(w8001->data, &coord); - report_pen_events(w8001, &coord); - break; - - /* control packet */ - case W8001_PKTLEN_TPCCTL - 1: - tmp = w8001->data[0] & W8001_TOUCH_MASK; - if (tmp == W8001_TOUCH_BYTE) - break; - - w8001->idx = 0; - memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH); - w8001->response_type = W8001_QUERY_PACKET; - complete(&w8001->cmd_done); - break; - - /* 2 finger touch packet */ - case W8001_PKTLEN_TOUCH2FG - 1: - w8001->idx = 0; - parse_multi_touch(w8001); - break; - - default: - /* - * ThinkPad X60 Tablet PC (pen only device) sometimes - * sends invalid data packets that are larger than - * W8001_PKTLEN_TPCPEN. Let's start over again. - */ - if (!w8001->touch_dev && w8001->idx > W8001_PKTLEN_TPCPEN - 1) - w8001->idx = 0; - } - - return IRQ_HANDLED; -} - -static int w8001_command(struct w8001 *w8001, unsigned char command, - bool wait_response) -{ - int rc; - - w8001->response_type = 0; - init_completion(&w8001->cmd_done); - - rc = serio_write(w8001->serio, command); - if (rc == 0 && wait_response) { - - wait_for_completion_timeout(&w8001->cmd_done, HZ); - if (w8001->response_type != W8001_QUERY_PACKET) - rc = -EIO; - } - - return rc; -} - -static int w8001_open(struct input_dev *dev) -{ - struct w8001 *w8001 = input_get_drvdata(dev); - int err; - - err = mutex_lock_interruptible(&w8001->mutex); - if (err) - return err; - - if (w8001->open_count++ == 0) { - err = w8001_command(w8001, W8001_CMD_START, false); - if (err) - w8001->open_count--; - } - - mutex_unlock(&w8001->mutex); - return err; -} - -static void w8001_close(struct input_dev *dev) -{ - struct w8001 *w8001 = input_get_drvdata(dev); - - mutex_lock(&w8001->mutex); - - if (--w8001->open_count == 0) - w8001_command(w8001, W8001_CMD_STOP, false); - - mutex_unlock(&w8001->mutex); -} - -static int w8001_detect(struct w8001 *w8001) -{ - int error; - - error = w8001_command(w8001, W8001_CMD_STOP, false); - if (error) - return error; - - msleep(250); /* wait 250ms before querying the device */ - - return 0; -} - -static int w8001_setup_pen(struct w8001 *w8001, char *basename, - size_t basename_sz) -{ - struct input_dev *dev = w8001->pen_dev; - struct w8001_coord coord; - int error; - - /* penabled? */ - error = w8001_command(w8001, W8001_CMD_QUERY, true); - if (error) - return error; - - __set_bit(EV_KEY, dev->evbit); - __set_bit(EV_ABS, dev->evbit); - __set_bit(BTN_TOUCH, dev->keybit); - __set_bit(BTN_TOOL_PEN, dev->keybit); - __set_bit(BTN_TOOL_RUBBER, dev->keybit); - __set_bit(BTN_STYLUS, dev->keybit); - __set_bit(BTN_STYLUS2, dev->keybit); - __set_bit(INPUT_PROP_DIRECT, dev->propbit); - - parse_pen_data(w8001->response, &coord); - w8001->max_pen_x = coord.x; - w8001->max_pen_y = coord.y; - - input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); - input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); - input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION); - input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION); - input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0); - if (coord.tilt_x && coord.tilt_y) { - input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); - input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); - } - - w8001->id = 0x90; - strlcat(basename, " Penabled", basename_sz); - - return 0; -} - -static int w8001_setup_touch(struct w8001 *w8001, char *basename, - size_t basename_sz) -{ - struct input_dev *dev = w8001->touch_dev; - struct w8001_touch_query touch; - int error; - - - /* Touch enabled? */ - error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true); - if (error) - return error; - /* - * Some non-touch devices may reply to the touch query. But their - * second byte is empty, which indicates touch is not supported. - */ - if (!w8001->response[1]) - return -ENXIO; - - __set_bit(EV_KEY, dev->evbit); - __set_bit(EV_ABS, dev->evbit); - __set_bit(BTN_TOUCH, dev->keybit); - __set_bit(INPUT_PROP_DIRECT, dev->propbit); - - parse_touchquery(w8001->response, &touch); - w8001->max_touch_x = touch.x; - w8001->max_touch_y = touch.y; - - if (w8001->max_pen_x && w8001->max_pen_y) { - /* if pen is supported scale to pen maximum */ - touch.x = w8001->max_pen_x; - touch.y = w8001->max_pen_y; - touch.panel_res = W8001_PEN_RESOLUTION; - } - - input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0); - input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0); - input_abs_set_res(dev, ABS_X, touch.panel_res); - input_abs_set_res(dev, ABS_Y, touch.panel_res); - - switch (touch.sensor_id) { - case 0: - case 2: - w8001->pktlen = W8001_PKTLEN_TOUCH93; - w8001->id = 0x93; - strlcat(basename, " 1FG", basename_sz); - break; - - case 1: - case 3: - case 4: - w8001->pktlen = W8001_PKTLEN_TOUCH9A; - strlcat(basename, " 1FG", basename_sz); - w8001->id = 0x9a; - break; - - case 5: - w8001->pktlen = W8001_PKTLEN_TOUCH2FG; - - __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); - error = input_mt_init_slots(dev, 2, 0); - if (error) { - dev_err(&w8001->serio->dev, - "failed to initialize MT slots: %d\n", error); - return error; - } - - input_set_abs_params(dev, ABS_MT_POSITION_X, - 0, touch.x, 0, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, - 0, touch.y, 0, 0); - input_set_abs_params(dev, ABS_MT_TOOL_TYPE, - 0, MT_TOOL_MAX, 0, 0); - input_abs_set_res(dev, ABS_MT_POSITION_X, touch.panel_res); - input_abs_set_res(dev, ABS_MT_POSITION_Y, touch.panel_res); - - strlcat(basename, " 2FG", basename_sz); - if (w8001->max_pen_x && w8001->max_pen_y) - w8001->id = 0xE3; - else - w8001->id = 0xE2; - break; - } - - strlcat(basename, " Touchscreen", basename_sz); - - return 0; -} - -static void w8001_set_devdata(struct input_dev *dev, struct w8001 *w8001, - struct serio *serio) -{ - dev->phys = w8001->phys; - dev->id.bustype = BUS_RS232; - dev->id.product = w8001->id; - dev->id.vendor = 0x056a; - dev->id.version = 0x0100; - dev->open = w8001_open; - dev->close = w8001_close; - - dev->dev.parent = &serio->dev; - - input_set_drvdata(dev, w8001); -} - -/* - * w8001_disconnect() is the opposite of w8001_connect() - */ - -static void w8001_disconnect(struct serio *serio) -{ - struct w8001 *w8001 = serio_get_drvdata(serio); - - serio_close(serio); - - if (w8001->pen_dev) - input_unregister_device(w8001->pen_dev); - if (w8001->touch_dev) - input_unregister_device(w8001->touch_dev); - kfree(w8001); - - serio_set_drvdata(serio, NULL); -} - -/* - * w8001_connect() is the routine that is called when someone adds a - * new serio device that supports the w8001 protocol and registers it as - * an input device. - */ - -static int w8001_connect(struct serio *serio, struct serio_driver *drv) -{ - struct w8001 *w8001; - struct input_dev *input_dev_pen; - struct input_dev *input_dev_touch; - char basename[64]; - int err, err_pen, err_touch; - - w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL); - input_dev_pen = input_allocate_device(); - input_dev_touch = input_allocate_device(); - if (!w8001 || !input_dev_pen || !input_dev_touch) { - err = -ENOMEM; - goto fail1; - } - - w8001->serio = serio; - w8001->pen_dev = input_dev_pen; - w8001->touch_dev = input_dev_touch; - mutex_init(&w8001->mutex); - init_completion(&w8001->cmd_done); - snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); - - serio_set_drvdata(serio, w8001); - err = serio_open(serio, drv); - if (err) - goto fail2; - - err = w8001_detect(w8001); - if (err) - goto fail3; - - /* For backwards-compatibility we compose the basename based on - * capabilities and then just append the tool type - */ - strlcpy(basename, "Wacom Serial", sizeof(basename)); - - err_pen = w8001_setup_pen(w8001, basename, sizeof(basename)); - err_touch = w8001_setup_touch(w8001, basename, sizeof(basename)); - if (err_pen && err_touch) { - err = -ENXIO; - goto fail3; - } - - if (!err_pen) { - strlcpy(w8001->pen_name, basename, sizeof(w8001->pen_name)); - strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name)); - input_dev_pen->name = w8001->pen_name; - - w8001_set_devdata(input_dev_pen, w8001, serio); - - err = input_register_device(w8001->pen_dev); - if (err) - goto fail3; - } else { - input_free_device(input_dev_pen); - input_dev_pen = NULL; - w8001->pen_dev = NULL; - } - - if (!err_touch) { - strlcpy(w8001->touch_name, basename, sizeof(w8001->touch_name)); - strlcat(w8001->touch_name, " Finger", - sizeof(w8001->touch_name)); - input_dev_touch->name = w8001->touch_name; - - w8001_set_devdata(input_dev_touch, w8001, serio); - - err = input_register_device(w8001->touch_dev); - if (err) - goto fail4; - } else { - input_free_device(input_dev_touch); - input_dev_touch = NULL; - w8001->touch_dev = NULL; - } - - return 0; - -fail4: - if (w8001->pen_dev) - input_unregister_device(w8001->pen_dev); -fail3: - serio_close(serio); -fail2: - serio_set_drvdata(serio, NULL); -fail1: - input_free_device(input_dev_pen); - input_free_device(input_dev_touch); - kfree(w8001); - return err; -} - -static const struct serio_device_id w8001_serio_ids[] = { - { - .type = SERIO_RS232, - .proto = SERIO_W8001, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { 0 } -}; - -MODULE_DEVICE_TABLE(serio, w8001_serio_ids); - -static struct serio_driver w8001_drv = { - .driver = { - .name = "w8001", - }, - .description = DRIVER_DESC, - .id_table = w8001_serio_ids, - .interrupt = w8001_interrupt, - .connect = w8001_connect, - .disconnect = w8001_disconnect, -}; - -module_serio_driver(w8001_drv); diff --git a/3.17/wacom_wac.c b/3.17/wacom_wac.c deleted file mode 100644 index 152a14cc..00000000 --- a/3.17/wacom_wac.c +++ /dev/null @@ -1,4976 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * USB Wacom tablet support - Wacom specific code - */ - -#include "wacom_wac.h" -#include "wacom.h" -#include -#include - -#ifndef INPUT_PROP_ACCELEROMETER -#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ -#endif - -#ifndef KEY_ONSCREEN_KEYBOARD -#define KEY_ONSCREEN_KEYBOARD 0x278 -#endif - -#ifndef KEY_BUTTONCONFIG -#define KEY_BUTTONCONFIG 0x240 -#endif - -#ifndef KEY_CONTROLPANEL -#define KEY_CONTROLPANEL 0x243 -#endif - -/* resolution for penabled devices */ -#define WACOM_PL_RES 20 -#define WACOM_PENPRTN_RES 40 -#define WACOM_VOLITO_RES 50 -#define WACOM_GRAPHIRE_RES 80 -#define WACOM_INTUOS_RES 100 -#define WACOM_INTUOS3_RES 200 - -/* Newer Cintiq and DTU have an offset between tablet and screen areas */ -#define WACOM_DTU_OFFSET 200 -#define WACOM_CINTIQ_OFFSET 400 - -/* - * Scale factor relating reported contact size to logical contact area. - * 2^14/pi is a good approximation on Intuos5 and 3rd-gen Bamboo - */ -#define WACOM_CONTACT_AREA_SCALE 2607 - -static bool touch_arbitration = 1; -module_param(touch_arbitration, bool, 0644); -MODULE_PARM_DESC(touch_arbitration, " on (Y) off (N)"); - -static void wacom_report_numbered_buttons(struct input_dev *input_dev, - int button_count, int mask); - -static int wacom_numbered_button_to_key(int n); - -static void wacom_force_proxout(struct wacom_wac *wacom_wac) -{ - struct input_dev *input = wacom_wac->pen_input; - - wacom_wac->shared->stylus_in_proximity = 0; - - input_report_key(input, BTN_TOUCH, 0); - input_report_key(input, BTN_STYLUS, 0); - input_report_key(input, BTN_STYLUS2, 0); - input_report_key(input, BTN_STYLUS3, 0); - input_report_key(input, wacom_wac->tool[0], 0); - if (wacom_wac->serial[0]) { - input_report_abs(input, ABS_MISC, 0); - } - input_report_abs(input, ABS_PRESSURE, 0); - - wacom_wac->tool[0] = 0; - wacom_wac->id[0] = 0; - wacom_wac->serial[0] = 0; - - input_sync(input); -} - -void wacom_idleprox_timeout(unsigned long data) -{ - struct wacom *wacom = (struct wacom *)data; - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - - if (!wacom_wac->hid_data.sense_state) { - return; - } - - hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__); - wacom_force_proxout(wacom_wac); -} - -/* - * Percent of battery capacity for Graphire. - * 8th value means AC online and show 100% capacity. - */ -static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 }; - -/* - * Percent of battery capacity for Intuos4 WL, AC has a separate bit. - */ -static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 }; - -static void __wacom_notify_battery(struct wacom_battery *battery, - int bat_status, int bat_capacity, - bool bat_charging, bool bat_connected, - bool ps_connected) -{ - bool changed = battery->bat_status != bat_status || - battery->battery_capacity != bat_capacity || - battery->bat_charging != bat_charging || - battery->bat_connected != bat_connected || - battery->ps_connected != ps_connected; - - if (changed) { - battery->bat_status = bat_status; - battery->battery_capacity = bat_capacity; - battery->bat_charging = bat_charging; - battery->bat_connected = bat_connected; - battery->ps_connected = ps_connected; - - if (WACOM_POWERSUPPLY_DEVICE(battery->battery)) - power_supply_changed(WACOM_POWERSUPPLY_REF(battery->battery)); - } -} - -static void wacom_notify_battery(struct wacom_wac *wacom_wac, - int bat_status, int bat_capacity, bool bat_charging, - bool bat_connected, bool ps_connected) -{ - struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); - bool bat_initialized = WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery); - bool has_quirk = wacom_wac->features.quirks & WACOM_QUIRK_BATTERY; - - if (bat_initialized != has_quirk) - wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY); - - __wacom_notify_battery(&wacom->battery, bat_status, bat_capacity, - bat_charging, bat_connected, ps_connected); -} - -static int wacom_penpartner_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - - switch (data[0]) { - case 1: - if (data[5] & 0x80) { - wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID; - input_report_key(input, wacom->tool[0], 1); - input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ - input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); - input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); - input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127); - input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -127)); - input_report_key(input, BTN_STYLUS, (data[5] & 0x40)); - } else { - input_report_key(input, wacom->tool[0], 0); - input_report_abs(input, ABS_MISC, 0); /* report tool id */ - input_report_abs(input, ABS_PRESSURE, -1); - input_report_key(input, BTN_TOUCH, 0); - } - break; - - case 2: - input_report_key(input, BTN_TOOL_PEN, 1); - input_report_abs(input, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */ - input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); - input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); - input_report_abs(input, ABS_PRESSURE, (signed char)data[6] + 127); - input_report_key(input, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20)); - input_report_key(input, BTN_STYLUS, (data[5] & 0x40)); - break; - - default: - dev_dbg(input->dev.parent, - "%s: received unknown report #%d\n", __func__, data[0]); - return 0; - } - - return 1; -} - -static int wacom_pl_irq(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - int prox, pressure; - - if (data[0] != WACOM_REPORT_PENABLED) { - dev_dbg(input->dev.parent, - "%s: received unknown report #%d\n", __func__, data[0]); - return 0; - } - - prox = data[1] & 0x40; - - if (!wacom->id[0]) { - if ((data[0] & 0x10) || (data[4] & 0x20)) { - wacom->tool[0] = BTN_TOOL_RUBBER; - wacom->id[0] = ERASER_DEVICE_ID; - } - else { - wacom->tool[0] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - } - } - - /* If the eraser is in prox, STYLUS2 is always set. If we - * mis-detected the type and notice that STYLUS2 isn't set - * then force the eraser out of prox and let the pen in. - */ - if (wacom->tool[0] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { - input_report_key(input, BTN_TOOL_RUBBER, 0); - input_report_abs(input, ABS_MISC, 0); - input_sync(input); - wacom->tool[0] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - } - - if (prox) { - pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); - if (features->pressure_max > 255) - pressure = (pressure << 1) | ((data[4] >> 6) & 1); - pressure += (features->pressure_max + 1) / 2; - - input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); - input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); - input_report_abs(input, ABS_PRESSURE, pressure); - - input_report_key(input, BTN_TOUCH, data[4] & 0x08); - input_report_key(input, BTN_STYLUS, data[4] & 0x10); - /* Only allow the stylus2 button to be reported for the pen tool. */ - input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20)); - } - - if (!prox) - wacom->id[0] = 0; - input_report_key(input, wacom->tool[0], prox); - input_report_abs(input, ABS_MISC, wacom->id[0]); - return 1; -} - -static int wacom_ptu_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - - if (data[0] != WACOM_REPORT_PENABLED) { - dev_dbg(input->dev.parent, - "%s: received unknown report #%d\n", __func__, data[0]); - return 0; - } - - if (data[1] & 0x04) { - input_report_key(input, BTN_TOOL_RUBBER, data[1] & 0x20); - input_report_key(input, BTN_TOUCH, data[1] & 0x08); - wacom->id[0] = ERASER_DEVICE_ID; - } else { - input_report_key(input, BTN_TOOL_PEN, data[1] & 0x20); - input_report_key(input, BTN_TOUCH, data[1] & 0x01); - wacom->id[0] = STYLUS_DEVICE_ID; - } - input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6])); - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x10); - return 1; -} - -static int wacom_dtu_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - int prox = data[1] & 0x20; - - dev_dbg(input->dev.parent, - "%s: received report #%d", __func__, data[0]); - - if (prox) { - /* Going into proximity select tool */ - wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - if (wacom->tool[0] == BTN_TOOL_PEN) - wacom->id[0] = STYLUS_DEVICE_ID; - else - wacom->id[0] = ERASER_DEVICE_ID; - } - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x10); - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x01) << 8) | data[6]); - input_report_key(input, BTN_TOUCH, data[1] & 0x05); - if (!prox) /* out-prox */ - wacom->id[0] = 0; - input_report_key(input, wacom->tool[0], prox); - input_report_abs(input, ABS_MISC, wacom->id[0]); - return 1; -} - -static int wacom_dtus_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - unsigned short prox, pressure = 0; - - if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) { - dev_dbg(input->dev.parent, - "%s: received unknown report #%d", __func__, data[0]); - return 0; - } else if (data[0] == WACOM_REPORT_DTUSPAD) { - input = wacom->pad_input; - input_report_key(input, BTN_0, (data[1] & 0x01)); - input_report_key(input, BTN_1, (data[1] & 0x02)); - input_report_key(input, BTN_2, (data[1] & 0x04)); - input_report_key(input, BTN_3, (data[1] & 0x08)); - input_report_abs(input, ABS_MISC, - data[1] & 0x0f ? PAD_DEVICE_ID : 0); - return 1; - } else { - prox = data[1] & 0x80; - if (prox) { - switch ((data[1] >> 3) & 3) { - case 1: /* Rubber */ - wacom->tool[0] = BTN_TOOL_RUBBER; - wacom->id[0] = ERASER_DEVICE_ID; - break; - - case 2: /* Pen */ - wacom->tool[0] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - break; - } - } - - input_report_key(input, BTN_STYLUS, data[1] & 0x20); - input_report_key(input, BTN_STYLUS2, data[1] & 0x40); - input_report_abs(input, ABS_X, get_unaligned_be16(&data[3])); - input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5])); - pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff); - input_report_abs(input, ABS_PRESSURE, pressure); - input_report_key(input, BTN_TOUCH, pressure > 10); - - if (!prox) /* out-prox */ - wacom->id[0] = 0; - input_report_key(input, wacom->tool[0], prox); - input_report_abs(input, ABS_MISC, wacom->id[0]); - return 1; - } -} - -static int wacom_graphire_irq(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - struct input_dev *pad_input = wacom->pad_input; - int battery_capacity, ps_connected; - int prox; - int rw = 0; - int retval = 0; - - if (features->type == GRAPHIRE_BT) { - if (data[0] != WACOM_REPORT_PENABLED_BT) { - dev_dbg(input->dev.parent, - "%s: received unknown report #%d\n", __func__, - data[0]); - goto exit; - } - } else if (data[0] != WACOM_REPORT_PENABLED) { - dev_dbg(input->dev.parent, - "%s: received unknown report #%d\n", __func__, data[0]); - goto exit; - } - - prox = data[1] & 0x80; - if (prox || wacom->id[0]) { - if (prox) { - switch ((data[1] >> 5) & 3) { - - case 0: /* Pen */ - wacom->tool[0] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - break; - - case 1: /* Rubber */ - wacom->tool[0] = BTN_TOOL_RUBBER; - wacom->id[0] = ERASER_DEVICE_ID; - break; - - case 2: /* Mouse with wheel */ - input_report_key(input, BTN_MIDDLE, data[1] & 0x04); - fallthrough; - - case 3: /* Mouse without wheel */ - wacom->tool[0] = BTN_TOOL_MOUSE; - wacom->id[0] = CURSOR_DEVICE_ID; - break; - } - } - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - if (wacom->tool[0] != BTN_TOOL_MOUSE) { - if (features->type == GRAPHIRE_BT) - input_report_abs(input, ABS_PRESSURE, data[6] | - (((__u16) (data[1] & 0x08)) << 5)); - else - input_report_abs(input, ABS_PRESSURE, data[6] | - ((data[7] & 0x03) << 8)); - input_report_key(input, BTN_TOUCH, data[1] & 0x01); - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x04); - } else { - input_report_key(input, BTN_LEFT, data[1] & 0x01); - input_report_key(input, BTN_RIGHT, data[1] & 0x02); - if (features->type == WACOM_G4 || - features->type == WACOM_MO) { - input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f); - rw = (data[7] & 0x04) - (data[7] & 0x03); - } else if (features->type == GRAPHIRE_BT) { - /* Compute distance between mouse and tablet */ - rw = 44 - (data[6] >> 2); - rw = clamp_val(rw, 0, 31); - input_report_abs(input, ABS_DISTANCE, rw); - if (((data[1] >> 5) & 3) == 2) { - /* Mouse with wheel */ - input_report_key(input, BTN_MIDDLE, - data[1] & 0x04); - rw = (data[6] & 0x01) ? -1 : - (data[6] & 0x02) ? 1 : 0; - } else { - rw = 0; - } - } else { - input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f); - rw = -(signed char)data[6]; - } - input_report_rel(input, REL_WHEEL, rw); - } - - if (!prox) - wacom->id[0] = 0; - input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ - input_report_key(input, wacom->tool[0], prox); - input_sync(input); /* sync last event */ - } - - /* send pad data */ - switch (features->type) { - case WACOM_G4: - prox = data[7] & 0xf8; - if (prox || wacom->id[1]) { - wacom->id[1] = PAD_DEVICE_ID; - input_report_key(pad_input, BTN_BACK, (data[7] & 0x40)); - input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x80)); - rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); - input_report_rel(pad_input, REL_WHEEL, rw); - if (!prox) - wacom->id[1] = 0; - input_report_abs(pad_input, ABS_MISC, wacom->id[1]); - retval = 1; - } - break; - - case WACOM_MO: - prox = (data[7] & 0xf8) || data[8]; - if (prox || wacom->id[1]) { - wacom->id[1] = PAD_DEVICE_ID; - input_report_key(pad_input, BTN_BACK, (data[7] & 0x08)); - input_report_key(pad_input, BTN_LEFT, (data[7] & 0x20)); - input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x10)); - input_report_key(pad_input, BTN_RIGHT, (data[7] & 0x40)); - input_report_abs(pad_input, ABS_WHEEL, (data[8] & 0x7f)); - if (!prox) - wacom->id[1] = 0; - input_report_abs(pad_input, ABS_MISC, wacom->id[1]); - retval = 1; - } - break; - case GRAPHIRE_BT: - prox = data[7] & 0x03; - if (prox || wacom->id[1]) { - wacom->id[1] = PAD_DEVICE_ID; - input_report_key(pad_input, BTN_0, (data[7] & 0x02)); - input_report_key(pad_input, BTN_1, (data[7] & 0x01)); - if (!prox) - wacom->id[1] = 0; - input_report_abs(pad_input, ABS_MISC, wacom->id[1]); - retval = 1; - } - break; - } - - /* Store current battery capacity and power supply state */ - if (features->type == GRAPHIRE_BT) { - rw = (data[7] >> 2 & 0x07); - battery_capacity = batcap_gr[rw]; - ps_connected = rw == 7; - wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, - battery_capacity, ps_connected, 1, - ps_connected); - } -exit: - return retval; -} - -static void wacom_intuos_schedule_prox_event(struct work_struct *work) -{ - struct wacom_wac *wacom_wac = - container_of(work, struct wacom_wac, intuos_prox_event_worker); - struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); - struct wacom_features *features = &wacom_wac->features; - struct hid_report *r; - struct hid_report_enum *re; - - re = &(wacom->hdev->report_enum[HID_FEATURE_REPORT]); - if (features->type == INTUOSHT2) - r = re->report_id_hash[WACOM_REPORT_INTUOSHT2_ID]; - else - r = re->report_id_hash[WACOM_REPORT_INTUOS_ID1]; - if (r) { - hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT); - } -} - -static int wacom_intuos_pad(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pad_input; - int i; - int buttons = 0, nbuttons = features->numbered_buttons; - int keys = 0, nkeys = 0; - int ring1 = 0, ring2 = 0; - int strip1 = 0, strip2 = 0; - bool prox = false; - bool wrench = false, keyboard = false, mute_touch = false, menu = false, - info = false; - - /* pad packets. Works as a second tool and is always in prox */ - if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD || - data[0] == WACOM_REPORT_CINTIQPAD)) - return 0; - - if (features->type >= INTUOS4S && features->type <= INTUOS4L) { - buttons = (data[3] << 1) | (data[2] & 0x01); - ring1 = data[1]; - } else if (features->type == DTK) { - buttons = data[6]; - } else if (features->type == WACOM_13HD) { - buttons = (data[4] << 1) | (data[3] & 0x01); - } else if (features->type == WACOM_24HD) { - buttons = (data[8] << 8) | data[6]; - ring1 = data[1]; - ring2 = data[2]; - - /* - * Three "buttons" are available on the 24HD which are - * physically implemented as a touchstrip. Each button - * is approximately 3 bits wide with a 2 bit spacing. - * The raw touchstrip bits are stored at: - * ((data[3] & 0x1f) << 8) | data[4]) - */ - nkeys = 3; - keys = ((data[3] & 0x1C) ? 1<<2 : 0) | - ((data[4] & 0xE0) ? 1<<1 : 0) | - ((data[4] & 0x07) ? 1<<0 : 0); - keyboard = !!(data[4] & 0xE0); - info = !!(data[3] & 0x1C); - - if (features->oPid) { - mute_touch = !!(data[4] & 0x07); - if (mute_touch) - wacom->shared->is_touch_on = - !wacom->shared->is_touch_on; - } else { - wrench = !!(data[4] & 0x07); - } - } else if (features->type == WACOM_27QHD) { - nkeys = 3; - keys = data[2] & 0x07; - - wrench = !!(data[2] & 0x01); - keyboard = !!(data[2] & 0x02); - - if (features->oPid) { - mute_touch = !!(data[2] & 0x04); - if (mute_touch) - wacom->shared->is_touch_on = - !wacom->shared->is_touch_on; - } else { - menu = !!(data[2] & 0x04); - } - input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4])); - input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6])); - input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8])); - } else if (features->type == CINTIQ_HYBRID) { - /* - * Do not send hardware buttons under Android. They - * are already sent to the system through GPIO (and - * have different meaning). - * - * d-pad right -> data[4] & 0x10 - * d-pad up -> data[4] & 0x20 - * d-pad left -> data[4] & 0x40 - * d-pad down -> data[4] & 0x80 - * d-pad center -> data[3] & 0x01 - */ - buttons = (data[4] << 1) | (data[3] & 0x01); - } else if (features->type == CINTIQ_COMPANION_2) { - /* d-pad right -> data[2] & 0x10 - * d-pad up -> data[2] & 0x20 - * d-pad left -> data[2] & 0x40 - * d-pad down -> data[2] & 0x80 - * d-pad center -> data[1] & 0x01 - */ - buttons = ((data[2] >> 4) << 7) | - ((data[1] & 0x04) << 4) | - ((data[2] & 0x0F) << 2) | - (data[1] & 0x03); - } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) { - /* - * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in - * addition to the mechanical switch. Switch data is - * stored in data[4], capacitive data in data[5]. - * - * Touch ring mode switch (data[3]) has no capacitive sensor - */ - buttons = (data[4] << 1) | (data[3] & 0x01); - ring1 = data[2]; - } else { - if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) { - buttons = (data[8] << 10) | ((data[7] & 0x01) << 9) | - (data[6] << 1) | (data[5] & 0x01); - - if (features->type == WACOM_22HD) { - nkeys = 3; - keys = data[9] & 0x07; - - info = !!(data[9] & 0x01); - wrench = !!(data[9] & 0x02); - } - } else { - buttons = ((data[6] & 0x10) << 5) | - ((data[5] & 0x10) << 4) | - ((data[6] & 0x0F) << 4) | - (data[5] & 0x0F); - } - strip1 = ((data[1] & 0x1f) << 8) | data[2]; - strip2 = ((data[3] & 0x1f) << 8) | data[4]; - } - - prox = (buttons & ~(~0U << nbuttons)) | (keys & ~(~0U << nkeys)) | - (ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2; - - wacom_report_numbered_buttons(input, nbuttons, buttons); - - for (i = 0; i < nkeys; i++) - input_report_key(input, KEY_PROG1 + i, keys & (1 << i)); - - input_report_key(input, KEY_BUTTONCONFIG, wrench); - input_report_key(input, KEY_ONSCREEN_KEYBOARD, keyboard); - input_report_key(input, KEY_CONTROLPANEL, menu); - input_report_key(input, KEY_INFO, info); - - if (wacom->shared && wacom->shared->touch_input) { - input_report_switch(wacom->shared->touch_input, - SW_MUTE_DEVICE, - !wacom->shared->is_touch_on); - input_sync(wacom->shared->touch_input); - } - - input_report_abs(input, ABS_RX, strip1); - input_report_abs(input, ABS_RY, strip2); - - input_report_abs(input, ABS_WHEEL, (ring1 & 0x80) ? (ring1 & 0x7f) : 0); - input_report_abs(input, ABS_THROTTLE, (ring2 & 0x80) ? (ring2 & 0x7f) : 0); - - input_report_key(input, wacom->tool[1], prox ? 1 : 0); - input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0); - - input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff); - - return 1; -} - -static int wacom_intuos_id_mangle(int tool_id) -{ - return (tool_id & ~0xFFF) << 4 | (tool_id & 0xFFF); -} - -static bool wacom_is_art_pen(int tool_id) -{ - bool is_art_pen = false; - - switch (tool_id) { - case 0x885: /* Intuos3 Marker Pen */ - case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ - case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ - is_art_pen = true; - break; - } - return is_art_pen; -} - -static int wacom_intuos_get_tool_type(int tool_id) -{ - int tool_type = BTN_TOOL_PEN; - - if (wacom_is_art_pen(tool_id)) - return tool_type; - - switch (tool_id) { - case 0x812: /* Inking pen */ - case 0x801: /* Intuos3 Inking pen */ - case 0x12802: /* Intuos4/5 Inking Pen */ - case 0x012: - tool_type = BTN_TOOL_PENCIL; - break; - - case 0x822: /* Pen */ - case 0x842: - case 0x852: - case 0x823: /* Intuos3 Grip Pen */ - case 0x813: /* Intuos3 Classic Pen */ - case 0x802: /* Intuos4/5 13HD/24HD General Pen */ - case 0x8e2: /* IntuosHT2 pen */ - case 0x022: - case 0x200: /* Pro Pen 3 */ - case 0x04200: /* Pro Pen 3 */ - case 0x10842: /* MobileStudio Pro Pro Pen slim */ - case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */ - case 0x16802: /* Cintiq 13HD Pro Pen */ - case 0x18802: /* DTH2242 Pen */ - case 0x10802: /* Intuos4/5 13HD/24HD General Pen */ - case 0x80842: /* Intuos Pro and Cintiq Pro 3D Pen */ - tool_type = BTN_TOOL_PEN; - break; - - case 0x832: /* Stroke pen */ - case 0x032: - tool_type = BTN_TOOL_BRUSH; - break; - - case 0x007: /* Mouse 4D and 2D */ - case 0x09c: - case 0x094: - case 0x017: /* Intuos3 2D Mouse */ - case 0x806: /* Intuos4 Mouse */ - tool_type = BTN_TOOL_MOUSE; - break; - - case 0x096: /* Lens cursor */ - case 0x097: /* Intuos3 Lens cursor */ - case 0x006: /* Intuos4 Lens cursor */ - tool_type = BTN_TOOL_LENS; - break; - - case 0x82a: /* Eraser */ - case 0x84a: - case 0x85a: - case 0x91a: - case 0xd1a: - case 0x0fa: - case 0x82b: /* Intuos3 Grip Pen Eraser */ - case 0x81b: /* Intuos3 Classic Pen Eraser */ - case 0x91b: /* Intuos3 Airbrush Eraser */ - case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */ - case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */ - case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */ - case 0x1480a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */ - case 0x1090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */ - case 0x1080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */ - case 0x1084a: /* MobileStudio Pro Pro Pen slim Eraser */ - case 0x1680a: /* Cintiq 13HD Pro Pen Eraser */ - case 0x1880a: /* DTH2242 Eraser */ - case 0x1080a: /* Intuos4/5 13HD/24HD General Pen Eraser */ - tool_type = BTN_TOOL_RUBBER; - break; - - case 0xd12: - case 0x912: - case 0x112: - case 0x913: /* Intuos3 Airbrush */ - case 0x902: /* Intuos4/5 13HD/24HD Airbrush */ - case 0x10902: /* Intuos4/5 13HD/24HD Airbrush */ - tool_type = BTN_TOOL_AIRBRUSH; - break; - } - return tool_type; -} - -static void wacom_exit_report(struct wacom_wac *wacom) -{ - struct input_dev *input = wacom->pen_input; - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0; - - /* - * Reset all states otherwise we lose the initial states - * when in-prox next time - */ - input_report_abs(input, ABS_X, 0); - input_report_abs(input, ABS_Y, 0); - input_report_abs(input, ABS_DISTANCE, 0); - input_report_abs(input, ABS_TILT_X, 0); - input_report_abs(input, ABS_TILT_Y, 0); - if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { - input_report_key(input, BTN_LEFT, 0); - input_report_key(input, BTN_MIDDLE, 0); - input_report_key(input, BTN_RIGHT, 0); - input_report_key(input, BTN_SIDE, 0); - input_report_key(input, BTN_EXTRA, 0); - input_report_abs(input, ABS_THROTTLE, 0); - input_report_abs(input, ABS_RZ, 0); - } else { - input_report_abs(input, ABS_PRESSURE, 0); - input_report_key(input, BTN_STYLUS, 0); - input_report_key(input, BTN_STYLUS2, 0); - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_WHEEL, 0); - if (features->type >= INTUOS3S) - input_report_abs(input, ABS_Z, 0); - } - input_report_key(input, wacom->tool[idx], 0); - input_report_abs(input, ABS_MISC, 0); /* reset tool id */ - input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - wacom->id[idx] = 0; -} - -static int wacom_intuos_inout(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0; - - if (!(((data[1] & 0xfc) == 0xc0) || /* in prox */ - ((data[1] & 0xfe) == 0x20) || /* in range */ - ((data[1] & 0xfe) == 0x80))) /* out prox */ - return 0; - - /* Enter report */ - if ((data[1] & 0xfc) == 0xc0) { - /* serial number of the tool */ - wacom->serial[idx] = ((__u64)(data[3] & 0x0f) << 28) + - (data[4] << 20) + (data[5] << 12) + - (data[6] << 4) + (data[7] >> 4); - - wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) | - ((data[7] & 0x0f) << 16) | ((data[8] & 0xf0) << 8); - - wacom->tool[idx] = wacom_intuos_get_tool_type(wacom->id[idx]); - - wacom->shared->stylus_in_proximity = true; - return 1; - } - - /* in Range */ - if ((data[1] & 0xfe) == 0x20) { - if (features->type != INTUOSHT2) - wacom->shared->stylus_in_proximity = true; - - /* in Range while exiting */ - if (wacom->reporting_data) { - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max); - return 2; - } - return 1; - } - - /* Exit report */ - if ((data[1] & 0xfe) == 0x80) { - wacom->shared->stylus_in_proximity = false; - wacom->reporting_data = false; - - /* don't report exit if we don't know the ID */ - if (!wacom->id[idx]) - return 1; - - wacom_exit_report(wacom); - return 2; - } - - return 0; -} - -static inline bool touch_is_muted(struct wacom_wac *wacom_wac) -{ - return wacom_wac->probe_complete && - wacom_wac->shared->has_mute_touch_switch && - !wacom_wac->shared->is_touch_on; -} - -static inline bool report_touch_events(struct wacom_wac *wacom) -{ - return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1); -} - -static inline bool delay_pen_events(struct wacom_wac *wacom) -{ - return (wacom->shared->touch_down && touch_arbitration); -} - -static int wacom_intuos_general(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0; - unsigned char type = (data[1] >> 1) & 0x0F; - unsigned int x, y, distance, t; - - if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_CINTIQ && - data[0] != WACOM_REPORT_INTUOS_PEN) - return 0; - - if (delay_pen_events(wacom)) - return 1; - - /* don't report events if we don't know the tool ID */ - if (!wacom->id[idx]) { - /* but reschedule a read of the current tool */ - schedule_work(&wacom->intuos_prox_event_worker); - return 1; - } - - /* - * don't report events for invalid data - */ - /* older I4 styli don't work with new Cintiqs */ - if ((!((wacom->id[idx] >> 16) & 0x01) && - (features->type == WACOM_21UX2)) || - /* Only large Intuos support Lense Cursor */ - (wacom->tool[idx] == BTN_TOOL_LENS && - (features->type == INTUOS3 || - features->type == INTUOS3S || - features->type == INTUOS4 || - features->type == INTUOS4S || - features->type == INTUOS5 || - features->type == INTUOS5S || - features->type == INTUOSPM || - features->type == INTUOSPS)) || - /* Cintiq doesn't send data when RDY bit isn't set */ - (features->type == CINTIQ && !(data[1] & 0x40))) - return 1; - - x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1); - y = (be16_to_cpup((__be16 *)&data[4]) << 1) | (data[9] & 1); - distance = data[9] >> 2; - if (features->type < INTUOS3S) { - x >>= 1; - y >>= 1; - distance >>= 1; - } - if (features->type == INTUOSHT2) - distance = features->distance_max - distance; - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_DISTANCE, distance); - - switch (type) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - /* general pen packet */ - t = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | (data[1] & 1); - if (features->pressure_max < 2047) - t >>= 1; - input_report_abs(input, ABS_PRESSURE, t); - if (features->type != INTUOSHT2) { - input_report_abs(input, ABS_TILT_X, - (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64); - input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64); - } - input_report_key(input, BTN_STYLUS, data[1] & 2); - input_report_key(input, BTN_STYLUS2, data[1] & 4); - input_report_key(input, BTN_TOUCH, t > 10); - break; - - case 0x0a: - /* airbrush second packet */ - input_report_abs(input, ABS_WHEEL, - (data[6] << 2) | ((data[7] >> 6) & 3)); - input_report_abs(input, ABS_TILT_X, - (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64); - input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64); - break; - - case 0x05: - /* Rotation packet */ - if (features->type >= INTUOS3S) { - /* I3 marker pen rotation */ - t = (data[6] << 3) | ((data[7] >> 5) & 7); - t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) : - ((t-1) / 2 + 450)) : (450 - t / 2) ; - input_report_abs(input, ABS_Z, t); - } else { - /* 4D mouse 2nd packet */ - t = (data[6] << 3) | ((data[7] >> 5) & 7); - input_report_abs(input, ABS_RZ, (data[7] & 0x20) ? - ((t - 1) / 2) : -t / 2); - } - break; - - case 0x04: - /* 4D mouse 1st packet */ - input_report_key(input, BTN_LEFT, data[8] & 0x01); - input_report_key(input, BTN_MIDDLE, data[8] & 0x02); - input_report_key(input, BTN_RIGHT, data[8] & 0x04); - - input_report_key(input, BTN_SIDE, data[8] & 0x20); - input_report_key(input, BTN_EXTRA, data[8] & 0x10); - t = (data[6] << 2) | ((data[7] >> 6) & 3); - input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); - break; - - case 0x06: - /* I4 mouse */ - input_report_key(input, BTN_LEFT, data[6] & 0x01); - input_report_key(input, BTN_MIDDLE, data[6] & 0x02); - input_report_key(input, BTN_RIGHT, data[6] & 0x04); - input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7) - - ((data[7] & 0x40) >> 6)); - input_report_key(input, BTN_SIDE, data[6] & 0x08); - input_report_key(input, BTN_EXTRA, data[6] & 0x10); - - input_report_abs(input, ABS_TILT_X, - (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64); - input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64); - break; - - case 0x08: - if (wacom->tool[idx] == BTN_TOOL_MOUSE) { - /* 2D mouse packet */ - input_report_key(input, BTN_LEFT, data[8] & 0x04); - input_report_key(input, BTN_MIDDLE, data[8] & 0x08); - input_report_key(input, BTN_RIGHT, data[8] & 0x10); - input_report_rel(input, REL_WHEEL, (data[8] & 0x01) - - ((data[8] & 0x02) >> 1)); - - /* I3 2D mouse side buttons */ - if (features->type >= INTUOS3S && features->type <= INTUOS3L) { - input_report_key(input, BTN_SIDE, data[8] & 0x40); - input_report_key(input, BTN_EXTRA, data[8] & 0x20); - } - } - else if (wacom->tool[idx] == BTN_TOOL_LENS) { - /* Lens cursor packets */ - input_report_key(input, BTN_LEFT, data[8] & 0x01); - input_report_key(input, BTN_MIDDLE, data[8] & 0x02); - input_report_key(input, BTN_RIGHT, data[8] & 0x04); - input_report_key(input, BTN_SIDE, data[8] & 0x10); - input_report_key(input, BTN_EXTRA, data[8] & 0x08); - } - break; - - case 0x07: - case 0x09: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - /* unhandled */ - break; - } - - input_report_abs(input, ABS_MISC, - wacom_intuos_id_mangle(wacom->id[idx])); /* report tool id */ - input_report_key(input, wacom->tool[idx], 1); - input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - wacom->reporting_data = true; - return 2; -} - -static int wacom_intuos_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - int result; - - if (data[0] != WACOM_REPORT_PENABLED && - data[0] != WACOM_REPORT_INTUOS_ID1 && - data[0] != WACOM_REPORT_INTUOS_ID2 && - data[0] != WACOM_REPORT_INTUOSPAD && - data[0] != WACOM_REPORT_INTUOS_PEN && - data[0] != WACOM_REPORT_CINTIQ && - data[0] != WACOM_REPORT_CINTIQPAD && - data[0] != WACOM_REPORT_INTUOS5PAD) { - dev_dbg(input->dev.parent, - "%s: received unknown report #%d\n", __func__, data[0]); - return 0; - } - - /* process pad events */ - result = wacom_intuos_pad(wacom); - if (result) - return result; - - /* process in/out prox events */ - result = wacom_intuos_inout(wacom); - if (result) - return result - 1; - - /* process general packets */ - result = wacom_intuos_general(wacom); - if (result) - return result - 1; - - return 0; -} - -static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len) -{ - unsigned char *data = wacom_wac->data; - struct input_dev *input; - struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); - struct wacom_remote *remote = wacom->remote; - int bat_charging, bat_percent, touch_ring_mode; - __u32 serial; - int i, index = -1; - unsigned long flags; - - if (data[0] != WACOM_REPORT_REMOTE) { - hid_dbg(wacom->hdev, "%s: received unknown report #%d", - __func__, data[0]); - return 0; - } - - serial = data[3] + (data[4] << 8) + (data[5] << 16); - wacom_wac->id[0] = PAD_DEVICE_ID; - - spin_lock_irqsave(&remote->remote_lock, flags); - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - if (remote->remotes[i].serial == serial) { - index = i; - break; - } - } - - if (index < 0 || !remote->remotes[index].registered) - goto out; - - input = remote->remotes[index].input; - - input_report_key(input, BTN_0, (data[9] & 0x01)); - input_report_key(input, BTN_1, (data[9] & 0x02)); - input_report_key(input, BTN_2, (data[9] & 0x04)); - input_report_key(input, BTN_3, (data[9] & 0x08)); - input_report_key(input, BTN_4, (data[9] & 0x10)); - input_report_key(input, BTN_5, (data[9] & 0x20)); - input_report_key(input, BTN_6, (data[9] & 0x40)); - input_report_key(input, BTN_7, (data[9] & 0x80)); - - input_report_key(input, BTN_8, (data[10] & 0x01)); - input_report_key(input, BTN_9, (data[10] & 0x02)); - input_report_key(input, BTN_A, (data[10] & 0x04)); - input_report_key(input, BTN_B, (data[10] & 0x08)); - input_report_key(input, BTN_C, (data[10] & 0x10)); - input_report_key(input, BTN_X, (data[10] & 0x20)); - input_report_key(input, BTN_Y, (data[10] & 0x40)); - input_report_key(input, BTN_Z, (data[10] & 0x80)); - - input_report_key(input, BTN_BASE, (data[11] & 0x01)); - input_report_key(input, BTN_BASE2, (data[11] & 0x02)); - - if (data[12] & 0x80) - input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f) - 1); - else - input_report_abs(input, ABS_WHEEL, 0); - - bat_percent = data[7] & 0x7f; - bat_charging = !!(data[7] & 0x80); - - if (data[9] | data[10] | (data[11] & 0x03) | data[12]) - input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); - else - input_report_abs(input, ABS_MISC, 0); - - input_event(input, EV_MSC, MSC_SERIAL, serial); - - input_sync(input); - - /*Which mode select (LED light) is currently on?*/ - touch_ring_mode = (data[11] & 0xC0) >> 6; - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - if (remote->remotes[i].serial == serial) - wacom->led.groups[i].select = touch_ring_mode; - } - - __wacom_notify_battery(&remote->remotes[index].battery, - WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent, - bat_charging, 1, bat_charging); - -out: - spin_unlock_irqrestore(&remote->remote_lock, flags); - return 0; -} - -static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len) -{ - struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); - unsigned char *data = wacom_wac->data; - struct wacom_remote *remote = wacom->remote; - struct wacom_remote_data remote_data; - unsigned long flags; - int i, ret; - - if (data[0] != WACOM_REPORT_DEVICE_LIST) - return; - - memset(&remote_data, 0, sizeof(struct wacom_remote_data)); - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - int j = i * 6; - int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4]; - bool connected = data[j+2]; - - remote_data.remote[i].serial = serial; - remote_data.remote[i].connected = connected; - } - - spin_lock_irqsave(&remote->remote_lock, flags); - - ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data)); - if (ret != sizeof(remote_data)) { - spin_unlock_irqrestore(&remote->remote_lock, flags); - hid_err(wacom->hdev, "Can't queue Remote status event.\n"); - return; - } - - spin_unlock_irqrestore(&remote->remote_lock, flags); - - wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE); -} - -static int int_dist(int x1, int y1, int x2, int y2) -{ - int x = x2 - x1; - int y = y2 - y1; - - return int_sqrt(x*x + y*y); -} - -static void wacom_intuos_bt_process_data(struct wacom_wac *wacom, - unsigned char *data) -{ - memcpy(wacom->data, data, 10); - wacom_intuos_irq(wacom); - - input_sync(wacom->pen_input); - if (wacom->pad_input) - input_sync(wacom->pad_input); -} - -static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) -{ - unsigned char data[WACOM_PKGLEN_MAX]; - int i = 1; - unsigned power_raw, battery_capacity, bat_charging, ps_connected; - - memcpy(data, wacom->data, len); - - switch (data[0]) { - case 0x04: - wacom_intuos_bt_process_data(wacom, data + i); - i += 10; - fallthrough; - case 0x03: - wacom_intuos_bt_process_data(wacom, data + i); - i += 10; - wacom_intuos_bt_process_data(wacom, data + i); - i += 10; - power_raw = data[i]; - bat_charging = (power_raw & 0x08) ? 1 : 0; - ps_connected = (power_raw & 0x10) ? 1 : 0; - battery_capacity = batcap_i4[power_raw & 0x07]; - wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, - battery_capacity, bat_charging, - battery_capacity || bat_charging, - ps_connected); - break; - default: - dev_dbg(wacom->pen_input->dev.parent, - "Unknown report: %d,%d size:%zu\n", - data[0], data[1], len); - return 0; - } - return 0; -} - -static int wacom_wac_finger_count_touches(struct wacom_wac *wacom) -{ - struct input_dev *input = wacom->touch_input; - unsigned touch_max = wacom->features.touch_max; - int count = 0; - int i; - - if (!touch_max) - return 0; - - if (touch_max == 1) - return test_bit(BTN_TOUCH, input->key) && - report_touch_events(wacom); - - for (i = 0; i < input->mt->num_slots; i++) { - struct input_mt_slot *ps = &input->mt->slots[i]; - int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); - if (id >= 0) - count++; - } - - return count; -} - -static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) -{ - int pen_frame_len, pen_frames; - - struct input_dev *pen_input = wacom->pen_input; - unsigned char *data = wacom->data; - int i; - - if (wacom->features.type == INTUOSP2_BT || - wacom->features.type == INTUOSP2S_BT) { - wacom->serial[0] = get_unaligned_le64(&data[99]); - wacom->id[0] = get_unaligned_le16(&data[107]); - pen_frame_len = 14; - pen_frames = 7; - } else { - wacom->serial[0] = get_unaligned_le64(&data[33]); - wacom->id[0] = get_unaligned_le16(&data[41]); - pen_frame_len = 8; - pen_frames = 4; - } - - if (wacom->serial[0] >> 52 == 1) { - /* Add back in missing bits of ID for non-USI pens */ - wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF; - } - - for (i = 0; i < pen_frames; i++) { - unsigned char *frame = &data[i*pen_frame_len + 1]; - bool valid = frame[0] & 0x80; - bool prox = frame[0] & 0x40; - bool range = frame[0] & 0x20; - bool invert = frame[0] & 0x10; - - if (!valid) - continue; - - if (!prox) { - wacom->shared->stylus_in_proximity = false; - wacom_exit_report(wacom); - input_sync(pen_input); - - wacom->tool[0] = 0; - wacom->id[0] = 0; - wacom->serial[0] = 0; - return; - } - - if (range) { - if (!wacom->tool[0]) { /* first in range */ - /* Going into range select tool */ - if (invert) - wacom->tool[0] = BTN_TOOL_RUBBER; - else if (wacom->id[0]) - wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0]); - else - wacom->tool[0] = BTN_TOOL_PEN; - } - - input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1])); - input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3])); - - if (wacom->features.type == INTUOSP2_BT || - wacom->features.type == INTUOSP2S_BT) { - /* Fix rotation alignment: userspace expects zero at left */ - int16_t rotation = - (int16_t)get_unaligned_le16(&frame[9]); - rotation += 1800/4; - - if (rotation > 899) - rotation -= 1800; - - input_report_abs(pen_input, ABS_TILT_X, - (char)frame[7]); - input_report_abs(pen_input, ABS_TILT_Y, - (char)frame[8]); - input_report_abs(pen_input, ABS_Z, rotation); - input_report_abs(pen_input, ABS_WHEEL, - get_unaligned_le16(&frame[11])); - } - } - - if (wacom->tool[0]) { - input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5])); - if (wacom->features.type == INTUOSP2_BT || - wacom->features.type == INTUOSP2S_BT) { - input_report_abs(pen_input, ABS_DISTANCE, - range ? frame[13] : wacom->features.distance_max); - } else { - input_report_abs(pen_input, ABS_DISTANCE, - range ? frame[7] : wacom->features.distance_max); - } - - input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x09); - input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02); - input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04); - - input_report_key(pen_input, wacom->tool[0], prox); - input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]); - input_report_abs(pen_input, ABS_MISC, - wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */ - } - - wacom->shared->stylus_in_proximity = prox; - - input_sync(pen_input); - } -} - -static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom) -{ - const int finger_touch_len = 8; - const int finger_frames = 4; - const int finger_frame_len = 43; - - struct input_dev *touch_input = wacom->touch_input; - unsigned char *data = wacom->data; - int num_contacts_left = 5; - int i, j; - - for (i = 0; i < finger_frames; i++) { - unsigned char *frame = &data[i*finger_frame_len + 109]; - int current_num_contacts = frame[0] & 0x7F; - int contacts_to_send; - - if (!(frame[0] & 0x80)) - continue; - - /* - * First packet resets the counter since only the first - * packet in series will have non-zero current_num_contacts. - */ - if (current_num_contacts) - wacom->num_contacts_left = current_num_contacts; - - contacts_to_send = min(num_contacts_left, wacom->num_contacts_left); - - for (j = 0; j < contacts_to_send; j++) { - unsigned char *touch = &frame[j*finger_touch_len + 1]; - int slot = input_mt_get_slot_by_key(touch_input, touch[0]); - int x = get_unaligned_le16(&touch[2]); - int y = get_unaligned_le16(&touch[4]); - int w = touch[6] * input_abs_get_res(touch_input, ABS_MT_POSITION_X); - int h = touch[7] * input_abs_get_res(touch_input, ABS_MT_POSITION_Y); - - if (slot < 0) - continue; - - input_mt_slot(touch_input, slot); - input_mt_report_slot_state(touch_input, MT_TOOL_FINGER, touch[1] & 0x01); - input_report_abs(touch_input, ABS_MT_POSITION_X, x); - input_report_abs(touch_input, ABS_MT_POSITION_Y, y); - input_report_abs(touch_input, ABS_MT_TOUCH_MAJOR, max(w, h)); - input_report_abs(touch_input, ABS_MT_TOUCH_MINOR, min(w, h)); - input_report_abs(touch_input, ABS_MT_ORIENTATION, w > h); - } - - input_mt_sync_frame(touch_input); - - wacom->num_contacts_left -= contacts_to_send; - if (wacom->num_contacts_left <= 0) { - wacom->num_contacts_left = 0; - wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); - input_sync(touch_input); - } - } - - if (wacom->num_contacts_left == 0) { - // Be careful that we don't accidentally call input_sync with - // only a partial set of fingers of processed - input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7)); - input_sync(touch_input); - } - -} - -static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom) -{ - struct input_dev *pad_input = wacom->pad_input; - unsigned char *data = wacom->data; - int nbuttons = wacom->features.numbered_buttons; - - int expresskeys = data[282]; - int center = (data[281] & 0x40) >> 6; - int ring = data[285] & 0x7F; - bool ringstatus = data[285] & 0x80; - bool prox = expresskeys || center || ringstatus; - - /* Fix touchring data: userspace expects 0 at left and increasing clockwise */ - ring = 71 - ring; - ring += 3*72/16; - if (ring > 71) - ring -= 72; - - wacom_report_numbered_buttons(pad_input, nbuttons, - expresskeys | (center << (nbuttons - 1))); - - input_report_abs(pad_input, ABS_WHEEL, ringstatus ? ring : 0); - - input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0); - input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0); - input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff); - - input_sync(pad_input); -} - -static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - - bool chg = data[284] & 0x80; - int battery_status = data[284] & 0x7F; - - wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, - battery_status, chg, 1, chg); -} - -static void wacom_intuos_gen3_bt_pad(struct wacom_wac *wacom) -{ - struct input_dev *pad_input = wacom->pad_input; - unsigned char *data = wacom->data; - - int buttons = data[44]; - - wacom_report_numbered_buttons(pad_input, 4, buttons); - - input_report_key(pad_input, wacom->tool[1], buttons ? 1 : 0); - input_report_abs(pad_input, ABS_MISC, buttons ? PAD_DEVICE_ID : 0); - input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff); - - input_sync(pad_input); -} - -static void wacom_intuos_gen3_bt_battery(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - - bool chg = data[45] & 0x80; - int battery_status = data[45] & 0x7F; - - wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, - battery_status, chg, 1, chg); -} - -static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len) -{ - unsigned char *data = wacom->data; - - if (data[0] != 0x80 && data[0] != 0x81) { - dev_dbg(wacom->pen_input->dev.parent, - "%s: received unknown report #%d\n", __func__, data[0]); - return 0; - } - - wacom_intuos_pro2_bt_pen(wacom); - if (wacom->features.type == INTUOSP2_BT || - wacom->features.type == INTUOSP2S_BT) { - wacom_intuos_pro2_bt_touch(wacom); - wacom_intuos_pro2_bt_pad(wacom); - wacom_intuos_pro2_bt_battery(wacom); - } else { - wacom_intuos_gen3_bt_pad(wacom); - wacom_intuos_gen3_bt_battery(wacom); - } - return 0; -} - -static int wacom_24hdt_irq(struct wacom_wac *wacom) -{ - struct input_dev *input = wacom->touch_input; - unsigned char *data = wacom->data; - int i; - int current_num_contacts = data[61]; - int contacts_to_send = 0; - int num_contacts_left = 4; /* maximum contacts per packet */ - int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET; - int y_offset = 2; - - if (touch_is_muted(wacom) && !wacom->shared->touch_down) - return 0; - - if (wacom->features.type == WACOM_27QHDT) { - current_num_contacts = data[63]; - num_contacts_left = 10; - byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET; - y_offset = 0; - } - - /* - * First packet resets the counter since only the first - * packet in series will have non-zero current_num_contacts. - */ - if (current_num_contacts) - wacom->num_contacts_left = current_num_contacts; - - contacts_to_send = min(num_contacts_left, wacom->num_contacts_left); - - for (i = 0; i < contacts_to_send; i++) { - int offset = (byte_per_packet * i) + 1; - bool touch = (data[offset] & 0x1) && report_touch_events(wacom); - int slot = input_mt_get_slot_by_key(input, data[offset + 1]); - - if (slot < 0) - continue; - input_mt_slot(input, slot); - input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); - - if (touch) { - int t_x = get_unaligned_le16(&data[offset + 2]); - int t_y = get_unaligned_le16(&data[offset + 4 + y_offset]); - - input_report_abs(input, ABS_MT_POSITION_X, t_x); - input_report_abs(input, ABS_MT_POSITION_Y, t_y); - - if (wacom->features.type != WACOM_27QHDT) { - int c_x = get_unaligned_le16(&data[offset + 4]); - int c_y = get_unaligned_le16(&data[offset + 8]); - int w = get_unaligned_le16(&data[offset + 10]); - int h = get_unaligned_le16(&data[offset + 12]); - - input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h)); - input_report_abs(input, ABS_MT_WIDTH_MAJOR, - min(w, h) + int_dist(t_x, t_y, c_x, c_y)); - input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h)); - input_report_abs(input, ABS_MT_ORIENTATION, w > h); - } - } - } - input_mt_sync_frame(input); - - wacom->num_contacts_left -= contacts_to_send; - if (wacom->num_contacts_left <= 0) { - wacom->num_contacts_left = 0; - wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); - } - return 1; -} - -static int wacom_mt_touch(struct wacom_wac *wacom) -{ - struct input_dev *input = wacom->touch_input; - unsigned char *data = wacom->data; - int i; - int current_num_contacts = data[2]; - int contacts_to_send = 0; - int x_offset = 0; - - /* MTTPC does not support Height and Width */ - if (wacom->features.type == MTTPC || wacom->features.type == MTTPC_B) - x_offset = -4; - - /* - * First packet resets the counter since only the first - * packet in series will have non-zero current_num_contacts. - */ - if (current_num_contacts) - wacom->num_contacts_left = current_num_contacts; - - /* There are at most 5 contacts per packet */ - contacts_to_send = min(5, wacom->num_contacts_left); - - for (i = 0; i < contacts_to_send; i++) { - int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3; - bool touch = (data[offset] & 0x1) && report_touch_events(wacom); - int id = get_unaligned_le16(&data[offset + 1]); - int slot = input_mt_get_slot_by_key(input, id); - - if (slot < 0) - continue; - - input_mt_slot(input, slot); - input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); - if (touch) { - int x = get_unaligned_le16(&data[offset + x_offset + 7]); - int y = get_unaligned_le16(&data[offset + x_offset + 9]); - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - } - } - input_mt_sync_frame(input); - - wacom->num_contacts_left -= contacts_to_send; - if (wacom->num_contacts_left <= 0) { - wacom->num_contacts_left = 0; - wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); - } - return 1; -} - -static int wacom_tpc_mt_touch(struct wacom_wac *wacom) -{ - struct input_dev *input = wacom->touch_input; - unsigned char *data = wacom->data; - int i; - - for (i = 0; i < 2; i++) { - int p = data[1] & (1 << i); - bool touch = p && report_touch_events(wacom); - - input_mt_slot(input, i); - input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); - if (touch) { - int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff; - int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff; - - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - } - } - input_mt_sync_frame(input); - - /* keep touch state for pen event */ - wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); - - return 1; -} - -static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->touch_input; - bool prox = report_touch_events(wacom); - int x = 0, y = 0; - - if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG) - return 0; - - if (len == WACOM_PKGLEN_TPC1FG) { - prox = prox && (data[0] & 0x01); - x = get_unaligned_le16(&data[1]); - y = get_unaligned_le16(&data[3]); - } else if (len == WACOM_PKGLEN_TPC1FG_B) { - prox = prox && (data[2] & 0x01); - x = get_unaligned_le16(&data[3]); - y = get_unaligned_le16(&data[5]); - } else { - prox = prox && (data[1] & 0x01); - x = le16_to_cpup((__le16 *)&data[2]); - y = le16_to_cpup((__le16 *)&data[4]); - } - - if (prox) { - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - } - input_report_key(input, BTN_TOUCH, prox); - - /* keep touch state for pen events */ - wacom->shared->touch_down = prox; - - return 1; -} - -static int wacom_tpc_pen(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->pen_input; - bool prox = data[1] & 0x20; - - if (!wacom->shared->stylus_in_proximity) /* first in prox */ - /* Going into proximity select tool */ - wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - - /* keep pen state for touch events */ - wacom->shared->stylus_in_proximity = prox; - - /* send pen events only when touch is up or forced out - * or touch arbitration is off - */ - if (!delay_pen_events(wacom)) { - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x10); - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - input_report_abs(input, ABS_PRESSURE, ((data[7] & 0x07) << 8) | data[6]); - input_report_key(input, BTN_TOUCH, data[1] & 0x05); - input_report_key(input, wacom->tool[0], prox); - return 1; - } - - return 0; -} - -static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) -{ - unsigned char *data = wacom->data; - - if (wacom->pen_input) { - dev_dbg(wacom->pen_input->dev.parent, - "%s: received report #%d\n", __func__, data[0]); - - if (len == WACOM_PKGLEN_PENABLED || - data[0] == WACOM_REPORT_PENABLED) - return wacom_tpc_pen(wacom); - } - else if (wacom->touch_input) { - dev_dbg(wacom->touch_input->dev.parent, - "%s: received report #%d\n", __func__, data[0]); - - switch (len) { - case WACOM_PKGLEN_TPC1FG: - return wacom_tpc_single_touch(wacom, len); - - case WACOM_PKGLEN_TPC2FG: - return wacom_tpc_mt_touch(wacom); - - default: - switch (data[0]) { - case WACOM_REPORT_TPC1FG: - case WACOM_REPORT_TPCHID: - case WACOM_REPORT_TPCST: - case WACOM_REPORT_TPC1FGE: - return wacom_tpc_single_touch(wacom, len); - - case WACOM_REPORT_TPCMT: - case WACOM_REPORT_TPCMT2: - return wacom_mt_touch(wacom); - - } - } - } - - return 0; -} - -static int wacom_offset_rotation(struct input_dev *input, struct hid_usage *usage, - int value, int num, int denom) -{ - struct input_absinfo *abs = &input->absinfo[usage->code]; - int range = (abs->maximum - abs->minimum + 1); - - value += num*range/denom; - if (value > abs->maximum) - value -= range; - else if (value < abs->minimum) - value += range; - return value; -} - -int wacom_equivalent_usage(int usage) -{ - if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) { - int subpage = (usage & 0xFF00) << 8; - int subusage = (usage & 0xFF); - - if (subpage == WACOM_HID_SP_PAD || - subpage == WACOM_HID_SP_BUTTON || - subpage == WACOM_HID_SP_DIGITIZER || - subpage == WACOM_HID_SP_DIGITIZERINFO || - usage == WACOM_HID_WD_SENSE || - usage == WACOM_HID_WD_SERIALHI || - usage == WACOM_HID_WD_TOOLTYPE || - usage == WACOM_HID_WD_DISTANCE || - usage == WACOM_HID_WD_TOUCHSTRIP || - usage == WACOM_HID_WD_TOUCHSTRIP2 || - usage == WACOM_HID_WD_TOUCHRING || - usage == WACOM_HID_WD_TOUCHRINGSTATUS || - usage == WACOM_HID_WD_REPORT_VALID || - usage == WACOM_HID_WD_BARRELSWITCH3 || - usage == WACOM_HID_WD_SEQUENCENUMBER) { - return usage; - } - - if (subpage == HID_UP_UNDEFINED) - subpage = HID_UP_DIGITIZER; - - return subpage | subusage; - } - - if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMTOUCH) { - int subpage = (usage & 0xFF00) << 8; - int subusage = (usage & 0xFF); - - if (usage == WACOM_HID_WT_REPORT_VALID) - return usage; - - if (subpage == HID_UP_UNDEFINED) - subpage = WACOM_HID_SP_DIGITIZER; - - return subpage | subusage; - } - - return usage; -} - -static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage, - struct hid_field *field, __u8 type, __u16 code, int fuzz) -{ - struct wacom *wacom = input_get_drvdata(input); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - int fmin = field->logical_minimum; - int fmax = field->logical_maximum; - unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); - int resolution_code = code; - int resolution = hidinput_calc_abs_res(field, resolution_code); - - if (equivalent_usage == HID_DG_TWIST || - equivalent_usage == WACOM_HID_WD_TOUCHRING) { - resolution_code = ABS_RZ; - } - - if (equivalent_usage == HID_GD_X) { - fmin += features->offset_left; - fmax -= features->offset_right; - } - if (equivalent_usage == HID_GD_Y) { - fmin += features->offset_top; - fmax -= features->offset_bottom; - } - - usage->type = type; - usage->code = code; - - switch (type) { - case EV_ABS: - input_set_abs_params(input, code, fmin, fmax, fuzz, 0); - - /* older tablet may miss physical usage */ - if ((code == ABS_X || code == ABS_Y) && !resolution) { - resolution = WACOM_INTUOS_RES; - hid_warn(input, - "Wacom usage (%d) missing resolution \n", - code); - } - input_abs_set_res(input, code, resolution); - break; - case EV_KEY: - case EV_MSC: - case EV_SW: - input_set_capability(input, type, code); - break; - } -} - -static void wacom_wac_battery_usage_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - return; -} - -static void wacom_wac_battery_event(struct hid_device *hdev, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - - switch (equivalent_usage) { - case HID_DG_BATTERYSTRENGTH: - if (value == 0) { - wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN; - } - else { - value = value * 100 / (field->logical_maximum - field->logical_minimum); - wacom_wac->hid_data.battery_capacity = value; - wacom_wac->hid_data.bat_connected = 1; - wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO; - } - wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY; - break; - case WACOM_HID_WD_BATTERY_LEVEL: - value = value * 100 / (field->logical_maximum - field->logical_minimum); - wacom_wac->hid_data.battery_capacity = value; - wacom_wac->hid_data.bat_connected = 1; - wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO; - wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY; - break; - case WACOM_HID_WD_BATTERY_CHARGING: - wacom_wac->hid_data.bat_charging = value; - wacom_wac->hid_data.ps_connected = value; - wacom_wac->hid_data.bat_connected = 1; - wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO; - wacom_wac->features.quirks |= WACOM_QUIRK_BATTERY; - break; - } -} - -static void wacom_wac_battery_pre_report(struct hid_device *hdev, - struct hid_report *report) -{ - return; -} - -static void wacom_wac_battery_report(struct hid_device *hdev, - struct hid_report *report) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - - int status = wacom_wac->hid_data.bat_status; - int capacity = wacom_wac->hid_data.battery_capacity; - bool charging = wacom_wac->hid_data.bat_charging; - bool connected = wacom_wac->hid_data.bat_connected; - bool powered = wacom_wac->hid_data.ps_connected; - - wacom_notify_battery(wacom_wac, status, capacity, charging, - connected, powered); -} - -static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - struct input_dev *input = wacom_wac->pad_input; - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - - switch (equivalent_usage) { - case WACOM_HID_WD_ACCELEROMETER_X: - __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit); - wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_ACCELEROMETER_Y: - __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit); - wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_ACCELEROMETER_Z: - __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit); - wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_BUTTONCENTER: - case WACOM_HID_WD_BUTTONHOME: - case WACOM_HID_WD_BUTTONUP: - case WACOM_HID_WD_BUTTONDOWN: - case WACOM_HID_WD_BUTTONLEFT: - case WACOM_HID_WD_BUTTONRIGHT: - wacom_map_usage(input, usage, field, EV_KEY, - wacom_numbered_button_to_key(features->numbered_buttons), - 0); - features->numbered_buttons++; - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_MUTE_DEVICE: - /* softkey touch switch */ - wacom_wac->is_soft_touch_switch = true; - fallthrough; - case WACOM_HID_WD_TOUCHONOFF: - /* - * These two usages, which are used to mute touch events, come - * from the pad packet, but are reported on the touch - * interface. Because the touch interface may not have - * been created yet, we cannot call wacom_map_usage(). In - * order to process the usages when we receive them, we set - * the usage type and code directly. - */ - wacom_wac->has_mute_touch_switch = true; - usage->type = EV_SW; - usage->code = SW_MUTE_DEVICE; - break; - case WACOM_HID_WD_TOUCHSTRIP: - wacom_map_usage(input, usage, field, EV_ABS, ABS_RX, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_TOUCHSTRIP2: - wacom_map_usage(input, usage, field, EV_ABS, ABS_RY, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_TOUCHRING: - wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_TOUCHRINGSTATUS: - /* - * Only set up type/code association. Completely mapping - * this usage may overwrite the axis resolution and range. - */ - usage->type = EV_ABS; - usage->code = ABS_WHEEL; - set_bit(EV_ABS, input->evbit); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_BUTTONCONFIG: - wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_ONSCREEN_KEYBOARD: - wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_CONTROLPANEL: - wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0); - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - case WACOM_HID_WD_MODE_CHANGE: - /* do not overwrite previous data */ - if (!wacom_wac->has_mode_change) { - wacom_wac->has_mode_change = true; - wacom_wac->is_direct_mode = true; - } - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - } - - switch (equivalent_usage & 0xfffffff0) { - case WACOM_HID_WD_EXPRESSKEY00: - wacom_map_usage(input, usage, field, EV_KEY, - wacom_numbered_button_to_key(features->numbered_buttons), - 0); - features->numbered_buttons++; - features->device_type |= WACOM_DEVICETYPE_PAD; - break; - } -} - -static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->pad_input; - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - bool do_report = false; - - /* - * Avoid reporting this event and setting inrange_state if this usage - * hasn't been mapped. - */ - if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE) - return; - - if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) { - if (usage->hid != WACOM_HID_WD_TOUCHRING) - wacom_wac->hid_data.inrange_state |= value; - } - - /* Process touch switch state first since it is reported through touch interface, - * which is indepentent of pad interface. In the case when there are no other pad - * events, the pad interface will not even be created. - */ - if ((equivalent_usage == WACOM_HID_WD_MUTE_DEVICE) || - (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)) { - if (wacom_wac->shared->touch_input) { - bool *is_touch_on = &wacom_wac->shared->is_touch_on; - - if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value) - *is_touch_on = !(*is_touch_on); - else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF) - *is_touch_on = value; - - input_report_switch(wacom_wac->shared->touch_input, - SW_MUTE_DEVICE, !(*is_touch_on)); - input_sync(wacom_wac->shared->touch_input); - } - return; - } - - if (!input) - return; - - switch (equivalent_usage) { - case WACOM_HID_WD_TOUCHRING: - /* - * Userspace expects touchrings to increase in value with - * clockwise gestures and have their zero point at the - * tablet's left. HID events "should" be clockwise- - * increasing and zero at top, though the MobileStudio - * Pro and 2nd-gen Intuos Pro don't do this... - */ - if (hdev->vendor == 0x56a && - (hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */ - hdev->product == 0x357 || hdev->product == 0x358 || /* Intuos Pro 2 */ - hdev->product == 0x392 || /* Intuos Pro 2 */ - hdev->product == 0x398 || hdev->product == 0x399 || /* MobileStudio Pro */ - hdev->product == 0x3AA)) { /* MobileStudio Pro */ - value = (field->logical_maximum - value); - - if (hdev->product == 0x357 || hdev->product == 0x358 || - hdev->product == 0x392) - value = wacom_offset_rotation(input, usage, value, 3, 16); - else if (hdev->product == 0x34d || hdev->product == 0x34e || - hdev->product == 0x398 || hdev->product == 0x399 || - hdev->product == 0x3AA) - value = wacom_offset_rotation(input, usage, value, 1, 2); - } - else { - value = wacom_offset_rotation(input, usage, value, 1, 4); - } - do_report = true; - break; - case WACOM_HID_WD_TOUCHRINGSTATUS: - if (!value) - input_event(input, usage->type, usage->code, 0); - break; - - case WACOM_HID_WD_MODE_CHANGE: - if (wacom_wac->is_direct_mode != value) { - wacom_wac->is_direct_mode = value; - wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE); - } - break; - - case WACOM_HID_WD_BUTTONCENTER: - /* - * In kernels before 4.5, changing the LED is - * handled by gnome-settings-daemon. - */ - fallthrough; - default: - do_report = true; - break; - } - - if (do_report) { - input_event(input, usage->type, usage->code, value); - if (value) - wacom_wac->hid_data.pad_input_event_flag = true; - } -} - -static void wacom_wac_pad_pre_report(struct hid_device *hdev, - struct hid_report *report) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - - wacom_wac->hid_data.inrange_state = 0; -} - -static void wacom_wac_pad_report(struct hid_device *hdev, - struct hid_report *report, struct hid_field *field) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->pad_input; - bool active = wacom_wac->hid_data.inrange_state != 0; - - /* report prox for expresskey events */ - if (wacom_wac->hid_data.pad_input_event_flag) { - input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0); - input_sync(input); - if (!active) - wacom_wac->hid_data.pad_input_event_flag = false; - } -} - -static void wacom_set_barrel_switch3_usage(struct wacom_wac *wacom_wac) -{ - struct input_dev *input = wacom_wac->pen_input; - struct wacom_features *features = &wacom_wac->features; - - if (!(features->quirks & WACOM_QUIRK_AESPEN) && - wacom_wac->hid_data.barrelswitch && - wacom_wac->hid_data.barrelswitch2 && - wacom_wac->hid_data.serialhi && - !wacom_wac->hid_data.barrelswitch3) { - input_set_capability(input, EV_KEY, BTN_STYLUS3); - features->quirks |= WACOM_QUIRK_PEN_BUTTON3; - } -} - -static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - struct input_dev *input = wacom_wac->pen_input; - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - - switch (equivalent_usage) { - case HID_GD_X: - wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4); - break; - case HID_GD_Y: - wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4); - break; - case WACOM_HID_WD_DISTANCE: - case HID_GD_Z: - wacom_map_usage(input, usage, field, EV_ABS, ABS_DISTANCE, 0); - break; - case HID_DG_TIPPRESSURE: - wacom_map_usage(input, usage, field, EV_ABS, ABS_PRESSURE, 0); - break; - case HID_DG_INRANGE: - wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0); - break; - case HID_DG_INVERT: - wacom_map_usage(input, usage, field, EV_KEY, - BTN_TOOL_RUBBER, 0); - break; - case HID_DG_TILT_X: - wacom_map_usage(input, usage, field, EV_ABS, ABS_TILT_X, 0); - break; - case HID_DG_TILT_Y: - wacom_map_usage(input, usage, field, EV_ABS, ABS_TILT_Y, 0); - break; - case HID_DG_TWIST: - wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0); - break; - case HID_DG_ERASER: - input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER); - wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); - break; - case HID_DG_TIPSWITCH: - input_set_capability(input, EV_KEY, BTN_TOOL_PEN); - wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); - break; - case HID_DG_BARRELSWITCH: - wacom_wac->hid_data.barrelswitch = true; - wacom_set_barrel_switch3_usage(wacom_wac); - wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS, 0); - break; - case HID_DG_BARRELSWITCH2: - wacom_wac->hid_data.barrelswitch2 = true; - wacom_set_barrel_switch3_usage(wacom_wac); - wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0); - break; - case HID_DG_TOOLSERIALNUMBER: - features->quirks |= WACOM_QUIRK_TOOLSERIAL; - wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0); - break; - case HID_DG_SCANTIME: - wacom_map_usage(input, usage, field, EV_MSC, MSC_TIMESTAMP, 0); - break; - case WACOM_HID_WD_SENSE: - features->quirks |= WACOM_QUIRK_SENSE; - wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0); - break; - case WACOM_HID_WD_SERIALHI: - wacom_wac->hid_data.serialhi = true; - wacom_set_barrel_switch3_usage(wacom_wac); - wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0); - break; - case WACOM_HID_WD_FINGERWHEEL: - input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH); - wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); - break; - case WACOM_HID_WD_BARRELSWITCH3: - wacom_wac->hid_data.barrelswitch3 = true; - wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS3, 0); - features->quirks &= ~WACOM_QUIRK_PEN_BUTTON3; - break; - } -} - -static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - struct input_dev *input = wacom_wac->pen_input; - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - - if (wacom_wac->is_invalid_bt_frame) - return; - - switch (equivalent_usage) { - case HID_GD_Z: - /* - * HID_GD_Z "should increase as the control's position is - * moved from high to low", while ABS_DISTANCE instead - * increases in value as the tool moves from low to high. - */ - value = field->logical_maximum - value; - break; - case HID_DG_INRANGE: - mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100)); - wacom_wac->hid_data.inrange_state = value; - if (!(features->quirks & WACOM_QUIRK_SENSE)) - wacom_wac->hid_data.sense_state = value; - return; - case HID_DG_INVERT: - wacom_wac->hid_data.invert_state = value; - return; - case HID_DG_ERASER: - case HID_DG_TIPSWITCH: - wacom_wac->hid_data.tipswitch |= value; - return; - case HID_DG_BARRELSWITCH: - wacom_wac->hid_data.barrelswitch = value; - return; - case HID_DG_BARRELSWITCH2: - wacom_wac->hid_data.barrelswitch2 = value; - return; - case HID_DG_TOOLSERIALNUMBER: - if (value) { - wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL); - wacom_wac->serial[0] |= wacom_s32tou(value, field->report_size); - } - return; - case HID_DG_TWIST: - /* don't modify the value if the pen doesn't support the feature */ - if (!wacom_is_art_pen(wacom_wac->id[0])) return; - - /* - * Userspace expects pen twist to have its zero point when - * the buttons/finger is on the tablet's left. HID values - * are zero when buttons are toward the top. - */ - value = wacom_offset_rotation(input, usage, value, 1, 4); - break; - case WACOM_HID_WD_SENSE: - wacom_wac->hid_data.sense_state = value; - return; - case WACOM_HID_WD_SERIALHI: - if (value) { - __u32 raw_value = wacom_s32tou(value, field->report_size); - - wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF); - wacom_wac->serial[0] |= ((__u64)raw_value) << 32; - /* - * Non-USI EMR devices may contain additional tool type - * information here. See WACOM_HID_WD_TOOLTYPE case for - * more details. - */ - if (value >> 20 == 1) { - wacom_wac->id[0] |= raw_value & 0xFFFFF; - } - } - return; - case WACOM_HID_WD_TOOLTYPE: - /* - * Some devices (MobileStudio Pro, and possibly later - * devices as well) do not return the complete tool - * type in their WACOM_HID_WD_TOOLTYPE usage. Use a - * bitwise OR so the complete value can be built - * up over time :( - */ - wacom_wac->id[0] |= wacom_s32tou(value, field->report_size); - return; - case WACOM_HID_WD_OFFSETLEFT: - if (features->offset_left && value != features->offset_left) - hid_warn(hdev, "%s: overriding existing left offset " - "%d -> %d\n", __func__, value, - features->offset_left); - features->offset_left = value; - return; - case WACOM_HID_WD_OFFSETRIGHT: - if (features->offset_right && value != features->offset_right) - hid_warn(hdev, "%s: overriding existing right offset " - "%d -> %d\n", __func__, value, - features->offset_right); - features->offset_right = value; - return; - case WACOM_HID_WD_OFFSETTOP: - if (features->offset_top && value != features->offset_top) - hid_warn(hdev, "%s: overriding existing top offset " - "%d -> %d\n", __func__, value, - features->offset_top); - features->offset_top = value; - return; - case WACOM_HID_WD_OFFSETBOTTOM: - if (features->offset_bottom && value != features->offset_bottom) - hid_warn(hdev, "%s: overriding existing bottom offset " - "%d -> %d\n", __func__, value, - features->offset_bottom); - features->offset_bottom = value; - return; - case WACOM_HID_WD_REPORT_VALID: - wacom_wac->is_invalid_bt_frame = !value; - return; - case WACOM_HID_WD_BARRELSWITCH3: - wacom_wac->hid_data.barrelswitch3 = value; - return; - case WACOM_HID_WD_SEQUENCENUMBER: - if (wacom_wac->hid_data.sequence_number != value) - hid_warn(hdev, "Dropped %hu packets", (unsigned short)(value - wacom_wac->hid_data.sequence_number)); - wacom_wac->hid_data.sequence_number = value + 1; - return; - } - - /* send pen events only when touch is up or forced out - * or touch arbitration is off - */ - if (!usage->type || delay_pen_events(wacom_wac)) - return; - - /* send pen events only when the pen is in range */ - if (wacom_wac->hid_data.inrange_state) - input_event(input, usage->type, usage->code, value); - else if (wacom_wac->shared->stylus_in_proximity && !wacom_wac->hid_data.sense_state) - input_event(input, usage->type, usage->code, 0); -} - -static void wacom_wac_pen_pre_report(struct hid_device *hdev, - struct hid_report *report) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - - wacom_wac->is_invalid_bt_frame = false; - return; -} - -static void wacom_wac_pen_report(struct hid_device *hdev, - struct hid_report *report) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->pen_input; - bool range = wacom_wac->hid_data.inrange_state; - bool sense = wacom_wac->hid_data.sense_state; - - if (wacom_wac->is_invalid_bt_frame) - return; - - if (!wacom_wac->tool[0] && range) { /* first in range */ - /* Going into range select tool */ - if (wacom_wac->hid_data.invert_state) - wacom_wac->tool[0] = BTN_TOOL_RUBBER; - else if (wacom_wac->id[0]) - wacom_wac->tool[0] = wacom_intuos_get_tool_type(wacom_wac->id[0]); - else - wacom_wac->tool[0] = BTN_TOOL_PEN; - } - - /* keep pen state for touch events */ - wacom_wac->shared->stylus_in_proximity = sense; - - if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) { - int id = wacom_wac->id[0]; - if (wacom_wac->features.quirks & WACOM_QUIRK_PEN_BUTTON3) { - int sw_state = wacom_wac->hid_data.barrelswitch | - (wacom_wac->hid_data.barrelswitch2 << 1); - wacom_wac->hid_data.barrelswitch = sw_state == 1; - wacom_wac->hid_data.barrelswitch2 = sw_state == 2; - wacom_wac->hid_data.barrelswitch3 = sw_state == 3; - } - input_report_key(input, BTN_STYLUS, wacom_wac->hid_data.barrelswitch); - input_report_key(input, BTN_STYLUS2, wacom_wac->hid_data.barrelswitch2); - input_report_key(input, BTN_STYLUS3, wacom_wac->hid_data.barrelswitch3); - - /* - * Non-USI EMR tools should have their IDs mangled to - * match the legacy behavior of wacom_intuos_general - */ - if (wacom_wac->serial[0] >> 52 == 1) - id = wacom_intuos_id_mangle(id); - - /* - * To ensure compatibility with xf86-input-wacom, we should - * report the BTN_TOOL_* event prior to the ABS_MISC or - * MSC_SERIAL events. - */ - input_report_key(input, BTN_TOUCH, - wacom_wac->hid_data.tipswitch); - input_report_key(input, wacom_wac->tool[0], sense); - if (wacom_wac->serial[0]) { - /* - * xf86-input-wacom does not accept a serial number - * of '0'. Report the low 32 bits if possible, but - * if they are zero, report the upper ones instead. - */ - __u32 serial_lo = wacom_wac->serial[0] & 0xFFFFFFFFu; - __u32 serial_hi = wacom_wac->serial[0] >> 32; - input_event(input, EV_MSC, MSC_SERIAL, (int)(serial_lo ? serial_lo : serial_hi)); - input_report_abs(input, ABS_MISC, sense ? id : 0); - } - - wacom_wac->hid_data.tipswitch = false; - - input_sync(input); - } - - if (!sense) { - wacom_wac->tool[0] = 0; - wacom_wac->id[0] = 0; - wacom_wac->serial[0] = 0; - } -} - -static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->touch_input; - unsigned touch_max = wacom_wac->features.touch_max; - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - - switch (equivalent_usage) { - case HID_GD_X: - if (touch_max == 1) - wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4); - else - wacom_map_usage(input, usage, field, EV_ABS, - ABS_MT_POSITION_X, 4); - break; - case HID_GD_Y: - if (touch_max == 1) - wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4); - else - wacom_map_usage(input, usage, field, EV_ABS, - ABS_MT_POSITION_Y, 4); - break; - case HID_DG_WIDTH: - case HID_DG_HEIGHT: - wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); - wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0); - input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); - break; - case HID_DG_TIPSWITCH: - wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); - break; - case HID_DG_CONTACTCOUNT: - wacom_wac->hid_data.cc_report = field->report->id; - wacom_wac->hid_data.cc_index = field->index; - wacom_wac->hid_data.cc_value_index = usage->usage_index; - break; - case HID_DG_CONTACTID: - if ((field->logical_maximum - field->logical_minimum) < touch_max) { - /* - * The HID descriptor for G11 sensors leaves logical - * maximum set to '1' despite it being a multitouch - * device. Override to a sensible number. - */ - field->logical_maximum = 255; - } - break; - case HID_DG_SCANTIME: - wacom_map_usage(input, usage, field, EV_MSC, MSC_TIMESTAMP, 0); - break; - } -} - -static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, - struct input_dev *input) -{ - struct hid_data *hid_data = &wacom_wac->hid_data; - bool mt = wacom_wac->features.touch_max > 1; - bool touch_down = hid_data->tipswitch && hid_data->confidence; - bool prox = touch_down && report_touch_events(wacom_wac); - - if (touch_is_muted(wacom_wac)) { - if (!wacom_wac->shared->touch_down) - return; - prox = false; - } - - wacom_wac->hid_data.num_received++; - if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected) - return; - - if (mt) { - int slot; - - slot = input_mt_get_slot_by_key(input, hid_data->id); - if (slot < 0) { - return; - } else { - struct input_mt_slot *ps = &input->mt->slots[slot]; - int mt_id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); - - if (!prox && mt_id < 0) { - // No data to send for this slot; short-circuit - return; - } - } - - input_mt_slot(input, slot); - input_mt_report_slot_state(input, MT_TOOL_FINGER, prox); - } - else { - input_report_key(input, BTN_TOUCH, prox); - } - - if (prox) { - input_report_abs(input, mt ? ABS_MT_POSITION_X : ABS_X, - hid_data->x); - input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y, - hid_data->y); - - if (test_bit(ABS_MT_TOUCH_MAJOR, input->absbit)) { - input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(hid_data->width, hid_data->height)); - input_report_abs(input, ABS_MT_TOUCH_MINOR, min(hid_data->width, hid_data->height)); - if (hid_data->width != hid_data->height) - input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1); - } - } -} - -static void wacom_wac_finger_event(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage, __s32 value) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); - struct wacom_features *features = &wacom->wacom_wac.features; - - if (touch_is_muted(wacom_wac) && !wacom_wac->shared->touch_down) - return; - - if (wacom_wac->is_invalid_bt_frame) - return; - - switch (equivalent_usage) { - case HID_DG_CONFIDENCE: - wacom_wac->hid_data.confidence = value; - break; - case HID_GD_X: - wacom_wac->hid_data.x = value; - break; - case HID_GD_Y: - wacom_wac->hid_data.y = value; - break; - case HID_DG_WIDTH: - wacom_wac->hid_data.width = value; - break; - case HID_DG_HEIGHT: - wacom_wac->hid_data.height = value; - break; - case HID_DG_CONTACTID: - wacom_wac->hid_data.id = value; - break; - case HID_DG_TIPSWITCH: - wacom_wac->hid_data.tipswitch = value; - break; - case WACOM_HID_WT_REPORT_VALID: - wacom_wac->is_invalid_bt_frame = !value; - return; - case HID_DG_CONTACTMAX: - if (!features->touch_max) { - features->touch_max = value; - } else { - hid_warn(hdev, "%s: ignoring attempt to overwrite non-zero touch_max " - "%d -> %d\n", __func__, features->touch_max, value); - } - return; - } - - if (usage->usage_index + 1 == field->report_count) { - if (equivalent_usage == wacom_wac->hid_data.last_slot_field) - wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); - } -} - -static void wacom_wac_finger_pre_report(struct hid_device *hdev, - struct hid_report *report) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct hid_data* hid_data = &wacom_wac->hid_data; - int i; - - if (touch_is_muted(wacom_wac) && !wacom_wac->shared->touch_down) - return; - - wacom_wac->is_invalid_bt_frame = false; - - hid_data->confidence = true; - - hid_data->cc_report = 0; - hid_data->cc_index = -1; - hid_data->cc_value_index = -1; - - for (i = 0; i < report->maxfield; i++) { - struct hid_field *field = report->field[i]; - int j; - - for (j = 0; j < field->maxusage; j++) { - struct hid_usage *usage = &field->usage[j]; - unsigned int equivalent_usage = - wacom_equivalent_usage(usage->hid); - - switch (equivalent_usage) { - case HID_GD_X: - case HID_GD_Y: - case HID_DG_WIDTH: - case HID_DG_HEIGHT: - case HID_DG_CONTACTID: - case HID_DG_INRANGE: - case HID_DG_INVERT: - case HID_DG_TIPSWITCH: - hid_data->last_slot_field = equivalent_usage; - break; - case HID_DG_CONTACTCOUNT: - hid_data->cc_report = report->id; - hid_data->cc_index = i; - hid_data->cc_value_index = j; - break; - } - } - } - - if (hid_data->cc_report != 0 && - hid_data->cc_index >= 0) { - struct hid_field *field = report->field[hid_data->cc_index]; - int value = field->value[hid_data->cc_value_index]; - if (value) { - hid_data->num_expected = value; - hid_data->num_received = 0; - } - } - else { - hid_data->num_expected = wacom_wac->features.touch_max; - hid_data->num_received = 0; - } -} - -static void wacom_wac_finger_report(struct hid_device *hdev, - struct hid_report *report) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->touch_input; - unsigned touch_max = wacom_wac->features.touch_max; - - /* if there was nothing to process, don't send an empty sync */ - if (wacom_wac->hid_data.num_expected == 0) - return; - - /* If more packets of data are expected, give us a chance to - * process them rather than immediately syncing a partial - * update. - */ - if (wacom_wac->hid_data.num_received < wacom_wac->hid_data.num_expected) - return; - - if (touch_max > 1) - input_mt_sync_frame(input); - - input_sync(input); - wacom_wac->hid_data.num_received = 0; - wacom_wac->hid_data.num_expected = 0; - - /* keep touch state for pen event */ - wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac); -} - -void wacom_wac_usage_mapping(struct hid_device *hdev, - struct hid_field *field, struct hid_usage *usage) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; - - if (WACOM_DIRECT_DEVICE(field)) - features->device_type |= WACOM_DEVICETYPE_DIRECT; - - /* usage tests must precede field tests */ - if (WACOM_BATTERY_USAGE(usage)) - wacom_wac_battery_usage_mapping(hdev, field, usage); - else if (WACOM_PAD_FIELD(field)) - wacom_wac_pad_usage_mapping(hdev, field, usage); - else if (WACOM_PEN_FIELD(field)) - wacom_wac_pen_usage_mapping(hdev, field, usage); - else if (WACOM_FINGER_FIELD(field)) - wacom_wac_finger_usage_mapping(hdev, field, usage); -} - -void wacom_wac_event(struct hid_device *hdev, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - - if (wacom->wacom_wac.features.type != HID_GENERIC) - return; - - if (value > field->logical_maximum || value < field->logical_minimum) - return; - - /* usage tests must precede field tests */ - if (WACOM_BATTERY_USAGE(usage)) - wacom_wac_battery_event(hdev, field, usage, value); - else if (WACOM_PAD_FIELD(field)) - wacom_wac_pad_event(hdev, field, usage, value); - else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) - wacom_wac_pen_event(hdev, field, usage, value); - else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input) - wacom_wac_finger_event(hdev, field, usage, value); -} - -static void wacom_report_events(struct hid_device *hdev, - struct hid_report *report, int collection_index, - int field_index) -{ - int r; - - for (r = field_index; r < report->maxfield; r++) { - struct hid_field *field; - unsigned count, n; - - field = report->field[r]; - count = field->report_count; - - if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) - continue; - - for (n = 0 ; n < count; n++) { - if (field->usage[n].collection_index == collection_index) - wacom_wac_event(hdev, field, &field->usage[n], - field->value[n]); - else - return; - } - } -} - -static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report, - int collection_index, struct hid_field *field, - int field_index) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - - wacom_report_events(hdev, report, collection_index, field_index); - - /* - * Non-input reports may be sent prior to the device being - * completely initialized. Since only their events need - * to be processed, exit after 'wacom_report_events' has - * been called to prevent potential crashes in the report- - * processing functions. - */ - if (report->type != HID_INPUT_REPORT) - return -1; - - if (WACOM_PAD_FIELD(field)) - return 0; - else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) - wacom_wac_pen_report(hdev, report); - else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input) - wacom_wac_finger_report(hdev, report); - - return 0; -} - -void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) -{ - struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct hid_field *field; - bool pad_in_hid_field = false, pen_in_hid_field = false, - finger_in_hid_field = false, true_pad = false; - int r; - int prev_collection = -1; - - if (wacom_wac->features.type != HID_GENERIC) - return; - - for (r = 0; r < report->maxfield; r++) { - field = report->field[r]; - - if (WACOM_PAD_FIELD(field)) - pad_in_hid_field = true; - if (WACOM_PEN_FIELD(field)) - pen_in_hid_field = true; - if (WACOM_FINGER_FIELD(field)) - finger_in_hid_field = true; - if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) - true_pad = true; - } - - wacom_wac_battery_pre_report(hdev, report); - - if (pad_in_hid_field && wacom_wac->pad_input) - wacom_wac_pad_pre_report(hdev, report); - if (pen_in_hid_field && wacom_wac->pen_input) - wacom_wac_pen_pre_report(hdev, report); - if (finger_in_hid_field && wacom_wac->touch_input) - wacom_wac_finger_pre_report(hdev, report); - - for (r = 0; r < report->maxfield; r++) { - field = report->field[r]; - - if (field->usage[0].collection_index != prev_collection) { - if (wacom_wac_collection(hdev, report, - field->usage[0].collection_index, field, r) < 0) - return; - prev_collection = field->usage[0].collection_index; - } - } - - wacom_wac_battery_report(hdev, report); - - if (true_pad && wacom_wac->pad_input) - wacom_wac_pad_report(hdev, report, field); -} - -static int wacom_bpt_touch(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->touch_input; - struct input_dev *pad_input = wacom->pad_input; - unsigned char *data = wacom->data; - int i; - - if (data[0] != 0x02) - return 0; - - for (i = 0; i < 2; i++) { - int offset = (data[1] & 0x80) ? (8 * i) : (9 * i); - bool touch = report_touch_events(wacom) - && (data[offset + 3] & 0x80); - - input_mt_slot(input, i); - input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); - if (touch) { - int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff; - int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff; - if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) { - x <<= 5; - y <<= 5; - } - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - } - } - - input_mt_sync_frame(input); - - input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0); - input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0); - input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0); - input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0); - wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); - - return 1; -} - -static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) -{ - struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->touch_input; - bool touch = data[1] & 0x80; - int slot = input_mt_get_slot_by_key(input, data[0]); - - if (slot < 0) - return; - - touch = touch && report_touch_events(wacom); - - input_mt_slot(input, slot); - input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); - - if (touch) { - int x = (data[2] << 4) | (data[4] >> 4); - int y = (data[3] << 4) | (data[4] & 0x0f); - int width, height; - - if (features->type >= INTUOSPS && features->type <= INTUOSHT2) { - width = data[5] * 100; - height = data[6] * 100; - } else { - /* - * "a" is a scaled-down area which we assume is - * roughly circular and which can be described as: - * a=(pi*r^2)/C. - */ - int a = data[5]; - int x_res = input_abs_get_res(input, ABS_MT_POSITION_X); - int y_res = input_abs_get_res(input, ABS_MT_POSITION_Y); - width = 2 * int_sqrt(a * WACOM_CONTACT_AREA_SCALE); - height = width * y_res / x_res; - } - - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - input_report_abs(input, ABS_MT_TOUCH_MAJOR, width); - input_report_abs(input, ABS_MT_TOUCH_MINOR, height); - } -} - -static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data) -{ - struct input_dev *input = wacom->pad_input; - struct wacom_features *features = &wacom->features; - - if (features->type == INTUOSHT || features->type == INTUOSHT2) { - input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0); - input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0); - } else { - input_report_key(input, BTN_BACK, (data[1] & 0x02) != 0); - input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0); - } - input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0); - input_report_key(input, BTN_RIGHT, (data[1] & 0x01) != 0); -} - -static int wacom_bpt3_touch(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - int count = data[1] & 0x07; - int touch_changed = 0, i; - - if (data[0] != 0x02) - return 0; - - /* data has up to 7 fixed sized 8-byte messages starting at data[2] */ - for (i = 0; i < count; i++) { - int offset = (8 * i) + 2; - int msg_id = data[offset]; - - if (msg_id >= 2 && msg_id <= 17) { - wacom_bpt3_touch_msg(wacom, data + offset); - touch_changed++; - } else if (msg_id == 128) - wacom_bpt3_button_msg(wacom, data + offset); - - } - - /* only update touch if we actually have a touchpad and touch data changed */ - if (wacom->touch_input && touch_changed) { - input_mt_sync_frame(wacom->touch_input); - wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); - } - - return 1; -} - -static int wacom_bpt_pen(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->pen_input; - unsigned char *data = wacom->data; - int x = 0, y = 0, p = 0, d = 0; - bool pen = false, btn1 = false, btn2 = false; - bool range, prox, rdy; - - if (data[0] != WACOM_REPORT_PENABLED) - return 0; - - range = (data[1] & 0x80) == 0x80; - prox = (data[1] & 0x40) == 0x40; - rdy = (data[1] & 0x20) == 0x20; - - wacom->shared->stylus_in_proximity = range; - if (delay_pen_events(wacom)) - return 0; - - if (rdy) { - p = le16_to_cpup((__le16 *)&data[6]); - pen = data[1] & 0x01; - btn1 = data[1] & 0x02; - btn2 = data[1] & 0x04; - } - if (prox) { - x = le16_to_cpup((__le16 *)&data[2]); - y = le16_to_cpup((__le16 *)&data[4]); - - if (data[1] & 0x08) { - wacom->tool[0] = BTN_TOOL_RUBBER; - wacom->id[0] = ERASER_DEVICE_ID; - } else { - wacom->tool[0] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - } - wacom->reporting_data = true; - } - if (range) { - /* - * Convert distance from out prox to distance from tablet. - * distance will be greater than distance_max once - * touching and applying pressure; do not report negative - * distance. - */ - if (data[8] <= features->distance_max) - d = features->distance_max - data[8]; - } else { - wacom->id[0] = 0; - } - - if (wacom->reporting_data) { - input_report_key(input, BTN_TOUCH, pen); - input_report_key(input, BTN_STYLUS, btn1); - input_report_key(input, BTN_STYLUS2, btn2); - - if (prox || !range) { - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - } - input_report_abs(input, ABS_PRESSURE, p); - input_report_abs(input, ABS_DISTANCE, d); - - input_report_key(input, wacom->tool[0], range); /* PEN or RUBBER */ - input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */ - } - - if (!range) { - wacom->reporting_data = false; - } - - return 1; -} - -static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len) -{ - struct wacom_features *features = &wacom->features; - - if ((features->type == INTUOSHT2) && - (features->device_type & WACOM_DEVICETYPE_PEN)) - return wacom_intuos_irq(wacom); - else if (len == WACOM_PKGLEN_BBTOUCH) - return wacom_bpt_touch(wacom); - else if (len == WACOM_PKGLEN_BBTOUCH3) - return wacom_bpt3_touch(wacom); - else if (len == WACOM_PKGLEN_BBFUN || len == WACOM_PKGLEN_BBPEN) - return wacom_bpt_pen(wacom); - - return 0; -} - -static void wacom_bamboo_pad_pen_event(struct wacom_wac *wacom, - unsigned char *data) -{ - unsigned char prefix; - - /* - * We need to reroute the event from the debug interface to the - * pen interface. - * We need to add the report ID to the actual pen report, so we - * temporary overwrite the first byte to prevent having to kzalloc/kfree - * and memcpy the report. - */ - prefix = data[0]; - data[0] = WACOM_REPORT_BPAD_PEN; - - /* - * actually reroute the event. - * No need to check if wacom->shared->pen is valid, hid_input_report() - * will check for us. - */ - hid_input_report(wacom->shared->pen, HID_INPUT_REPORT, data, - WACOM_PKGLEN_PENABLED, 1); - - data[0] = prefix; -} - -static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom, - unsigned char *data) -{ - struct input_dev *input = wacom->touch_input; - unsigned char *finger_data, prefix; - unsigned id; - int x, y; - bool valid; - - prefix = data[0]; - - for (id = 0; id < wacom->features.touch_max; id++) { - valid = !!(prefix & BIT(id)) && - report_touch_events(wacom); - - input_mt_slot(input, id); - input_mt_report_slot_state(input, MT_TOOL_FINGER, valid); - - if (!valid) - continue; - - finger_data = data + 1 + id * 3; - x = finger_data[0] | ((finger_data[1] & 0x0f) << 8); - y = (finger_data[2] << 4) | (finger_data[1] >> 4); - - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - } - - input_mt_sync_frame(input); - - input_report_key(input, BTN_LEFT, prefix & 0x40); - input_report_key(input, BTN_RIGHT, prefix & 0x80); - - /* keep touch state for pen event */ - wacom->shared->touch_down = !!prefix && report_touch_events(wacom); - - return 1; -} - -static int wacom_bamboo_pad_irq(struct wacom_wac *wacom, size_t len) -{ - unsigned char *data = wacom->data; - - if (!((len == WACOM_PKGLEN_BPAD_TOUCH) || - (len == WACOM_PKGLEN_BPAD_TOUCH_USB)) || - (data[0] != WACOM_REPORT_BPAD_TOUCH)) - return 0; - - if (data[1] & 0x01) - wacom_bamboo_pad_pen_event(wacom, &data[1]); - - if (data[1] & 0x02) - return wacom_bamboo_pad_touch_event(wacom, &data[9]); - - return 0; -} - -static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len) -{ - unsigned char *data = wacom->data; - int connected; - - if (len != WACOM_PKGLEN_WIRELESS || data[0] != WACOM_REPORT_WL) - return 0; - - connected = data[1] & 0x01; - if (connected) { - int pid, battery, charging; - - if ((wacom->shared->type == INTUOSHT || - wacom->shared->type == INTUOSHT2) && - wacom->shared->touch_input && - wacom->shared->touch_max) { - input_report_switch(wacom->shared->touch_input, - SW_MUTE_DEVICE, data[5] & 0x40); - input_sync(wacom->shared->touch_input); - } - - pid = get_unaligned_be16(&data[6]); - battery = (data[5] & 0x3f) * 100 / 31; - charging = !!(data[5] & 0x80); - if (wacom->pid != pid) { - wacom->pid = pid; - wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS); - } - - wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, - battery, charging, 1, 0); - - } else if (wacom->pid != 0) { - /* disconnected while previously connected */ - wacom->pid = 0; - wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS); - wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0); - } - - return 0; -} - -static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len) -{ - struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); - struct wacom_features *features = &wacom_wac->features; - unsigned char *data = wacom_wac->data; - - if (data[0] != WACOM_REPORT_USB) - return 0; - - if ((features->type == INTUOSHT || - features->type == INTUOSHT2) && - wacom_wac->shared->touch_input && - features->touch_max) { - input_report_switch(wacom_wac->shared->touch_input, - SW_MUTE_DEVICE, data[8] & 0x40); - input_sync(wacom_wac->shared->touch_input); - } - - if (data[9] & 0x02) { /* wireless module is attached */ - int battery = (data[8] & 0x3f) * 100 / 31; - bool charging = !!(data[8] & 0x80); - - features->quirks |= WACOM_QUIRK_BATTERY; - wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO, - battery, charging, battery || charging, 1); - } - else if ((features->quirks & WACOM_QUIRK_BATTERY) && - WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery)) { - features->quirks &= ~WACOM_QUIRK_BATTERY; - wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0); - } - return 0; -} - -void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) -{ - bool sync; - - switch (wacom_wac->features.type) { - case PENPARTNER: - sync = wacom_penpartner_irq(wacom_wac); - break; - - case PL: - sync = wacom_pl_irq(wacom_wac); - break; - - case WACOM_G4: - case GRAPHIRE: - case GRAPHIRE_BT: - case WACOM_MO: - sync = wacom_graphire_irq(wacom_wac); - break; - - case PTU: - sync = wacom_ptu_irq(wacom_wac); - break; - - case DTU: - sync = wacom_dtu_irq(wacom_wac); - break; - - case DTUS: - case DTUSX: - sync = wacom_dtus_irq(wacom_wac); - break; - - case INTUOS: - case INTUOS3S: - case INTUOS3: - case INTUOS3L: - case INTUOS4S: - case INTUOS4: - case INTUOS4L: - case CINTIQ: - case WACOM_BEE: - case WACOM_13HD: - case WACOM_21UX2: - case WACOM_22HD: - case WACOM_24HD: - case WACOM_27QHD: - case DTK: - case CINTIQ_HYBRID: - case CINTIQ_COMPANION_2: - sync = wacom_intuos_irq(wacom_wac); - break; - - case INTUOS4WL: - sync = wacom_intuos_bt_irq(wacom_wac, len); - break; - - case WACOM_24HDT: - case WACOM_27QHDT: - sync = wacom_24hdt_irq(wacom_wac); - break; - - case INTUOS5S: - case INTUOS5: - case INTUOS5L: - case INTUOSPS: - case INTUOSPM: - case INTUOSPL: - if (len == WACOM_PKGLEN_BBTOUCH3) - sync = wacom_bpt3_touch(wacom_wac); - else if (wacom_wac->data[0] == WACOM_REPORT_USB) - sync = wacom_status_irq(wacom_wac, len); - else - sync = wacom_intuos_irq(wacom_wac); - break; - - case INTUOSP2_BT: - case INTUOSP2S_BT: - case INTUOSHT3_BT: - sync = wacom_intuos_pro2_bt_irq(wacom_wac, len); - break; - - case TABLETPC: - case TABLETPCE: - case TABLETPC2FG: - case MTSCREEN: - case MTTPC: - case MTTPC_B: - sync = wacom_tpc_irq(wacom_wac, len); - break; - - case BAMBOO_PT: - case BAMBOO_PEN: - case BAMBOO_TOUCH: - case INTUOSHT: - case INTUOSHT2: - if (wacom_wac->data[0] == WACOM_REPORT_USB) - sync = wacom_status_irq(wacom_wac, len); - else - sync = wacom_bpt_irq(wacom_wac, len); - break; - - case BAMBOO_PAD: - sync = wacom_bamboo_pad_irq(wacom_wac, len); - break; - - case WIRELESS: - sync = wacom_wireless_irq(wacom_wac, len); - break; - - case REMOTE: - sync = false; - if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST) - wacom_remote_status_irq(wacom_wac, len); - else - sync = wacom_remote_irq(wacom_wac, len); - break; - - default: - sync = false; - break; - } - - if (sync) { - if (wacom_wac->pen_input) - input_sync(wacom_wac->pen_input); - if (wacom_wac->touch_input) - input_sync(wacom_wac->touch_input); - if (wacom_wac->pad_input) - input_sync(wacom_wac->pad_input); - } -} - -static void wacom_setup_basic_pro_pen(struct wacom_wac *wacom_wac) -{ - struct input_dev *input_dev = wacom_wac->pen_input; - - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); - - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - - input_set_abs_params(input_dev, ABS_DISTANCE, - 0, wacom_wac->features.distance_max, wacom_wac->features.distance_fuzz, 0); -} - -static void wacom_setup_cintiq(struct wacom_wac *wacom_wac) -{ - struct input_dev *input_dev = wacom_wac->pen_input; - struct wacom_features *features = &wacom_wac->features; - - wacom_setup_basic_pro_pen(wacom_wac); - - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_TOOL_BRUSH, input_dev->keybit); - __set_bit(BTN_TOOL_PENCIL, input_dev->keybit); - __set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit); - - input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0); - input_set_abs_params(input_dev, ABS_TILT_X, -64, 63, features->tilt_fuzz, 0); - input_abs_set_res(input_dev, ABS_TILT_X, 57); - input_set_abs_params(input_dev, ABS_TILT_Y, -64, 63, features->tilt_fuzz, 0); - input_abs_set_res(input_dev, ABS_TILT_Y, 57); -} - -static void wacom_setup_intuos(struct wacom_wac *wacom_wac) -{ - struct input_dev *input_dev = wacom_wac->pen_input; - - input_set_capability(input_dev, EV_REL, REL_WHEEL); - - wacom_setup_cintiq(wacom_wac); - - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - __set_bit(BTN_MIDDLE, input_dev->keybit); - __set_bit(BTN_SIDE, input_dev->keybit); - __set_bit(BTN_EXTRA, input_dev->keybit); - __set_bit(BTN_TOOL_MOUSE, input_dev->keybit); - __set_bit(BTN_TOOL_LENS, input_dev->keybit); - - input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_RZ, 287); - input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); - - INIT_WORK(&wacom_wac->intuos_prox_event_worker, - wacom_intuos_schedule_prox_event); -} - -void wacom_setup_device_quirks(struct wacom *wacom) -{ - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom->wacom_wac.features; - - /* The pen and pad share the same interface on most devices */ - if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 || - features->type == DTUS || - (features->type >= INTUOS3S && features->type <= WACOM_MO)) { - if (features->device_type & WACOM_DEVICETYPE_PEN) - features->device_type |= WACOM_DEVICETYPE_PAD; - } - - /* touch device found but size is not defined. use default */ - if (features->device_type & WACOM_DEVICETYPE_TOUCH && !features->x_max) { - features->x_max = 1023; - features->y_max = 1023; - } - - /* - * Intuos5/Pro and Bamboo 3rd gen have no useful data about its - * touch interface in its HID descriptor. If this is the touch - * interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the - * tablet values. - */ - if ((features->type >= INTUOS5S && features->type <= INTUOSPL) || - (features->type >= INTUOSHT && features->type <= BAMBOO_PT)) { - if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - if (features->touch_max) - features->device_type |= WACOM_DEVICETYPE_TOUCH; - if (features->type >= INTUOSHT && features->type <= BAMBOO_PT) - features->device_type |= WACOM_DEVICETYPE_PAD; - - if (features->type == INTUOSHT2) { - features->x_max = features->x_max / 10; - features->y_max = features->y_max / 10; - } - else { - features->x_max = 4096; - features->y_max = 4096; - } - } - else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) { - features->device_type |= WACOM_DEVICETYPE_PAD; - } - } - - /* - * Hack for the Bamboo One: - * the device presents a PAD/Touch interface as most Bamboos and even - * sends ghosts PAD data on it. However, later, we must disable this - * ghost interface, and we can not detect it unless we set it here - * to WACOM_DEVICETYPE_PAD or WACOM_DEVICETYPE_TOUCH. - */ - if (features->type == BAMBOO_PEN && - features->pktlen == WACOM_PKGLEN_BBTOUCH3) - features->device_type |= WACOM_DEVICETYPE_PAD; - - /* - * Raw Wacom-mode pen and touch events both come from interface - * 0, whose HID descriptor has an application usage of 0xFF0D - * (i.e., WACOM_HID_WD_DIGITIZER). We route pen packets back - * out through the HID_GENERIC device created for interface 1, - * so rewrite this one to be of type WACOM_DEVICETYPE_TOUCH. - */ - if (features->type == BAMBOO_PAD) - features->device_type = WACOM_DEVICETYPE_TOUCH; - - if (features->type == REMOTE) - features->device_type = WACOM_DEVICETYPE_PAD; - - if (features->type == INTUOSP2_BT || - features->type == INTUOSP2S_BT) { - features->device_type |= WACOM_DEVICETYPE_PEN | - WACOM_DEVICETYPE_PAD | - WACOM_DEVICETYPE_TOUCH; - features->quirks |= WACOM_QUIRK_BATTERY; - } - - if (features->type == INTUOSHT3_BT) { - features->device_type |= WACOM_DEVICETYPE_PEN | - WACOM_DEVICETYPE_PAD; - features->quirks |= WACOM_QUIRK_BATTERY; - } - - switch (features->type) { - case PL: - case DTU: - case DTUS: - case DTUSX: - case WACOM_21UX2: - case WACOM_22HD: - case DTK: - case WACOM_24HD: - case WACOM_27QHD: - case CINTIQ_HYBRID: - case CINTIQ_COMPANION_2: - case CINTIQ: - case WACOM_BEE: - case WACOM_13HD: - case WACOM_24HDT: - case WACOM_27QHDT: - case TABLETPC: - case TABLETPCE: - case TABLETPC2FG: - case MTSCREEN: - case MTTPC: - case MTTPC_B: - features->device_type |= WACOM_DEVICETYPE_DIRECT; - break; - } - - if (wacom->hdev->bus == BUS_BLUETOOTH) - features->quirks |= WACOM_QUIRK_BATTERY; - - /* quirk for bamboo touch with 2 low res touches */ - if ((features->type == BAMBOO_PT || features->type == BAMBOO_TOUCH) && - features->pktlen == WACOM_PKGLEN_BBTOUCH) { - features->x_max <<= 5; - features->y_max <<= 5; - features->x_fuzz <<= 5; - features->y_fuzz <<= 5; - features->quirks |= WACOM_QUIRK_BBTOUCH_LOWRES; - } - - if (features->type == WIRELESS) { - if (features->device_type == WACOM_DEVICETYPE_WL_MONITOR) { - features->quirks |= WACOM_QUIRK_BATTERY; - } - } - - if (features->type == REMOTE) - features->device_type |= WACOM_DEVICETYPE_WL_MONITOR; - - /* HID descriptor for DTK-2451 / DTH-2452 claims to report lots - * of things it shouldn't. Lets fix up the damage... - */ - if (wacom->hdev->product == 0x382 || wacom->hdev->product == 0x37d) { - features->quirks &= ~WACOM_QUIRK_TOOLSERIAL; - __clear_bit(BTN_TOOL_BRUSH, wacom_wac->pen_input->keybit); - __clear_bit(BTN_TOOL_PENCIL, wacom_wac->pen_input->keybit); - __clear_bit(BTN_TOOL_AIRBRUSH, wacom_wac->pen_input->keybit); - __clear_bit(ABS_Z, wacom_wac->pen_input->absbit); - __clear_bit(ABS_DISTANCE, wacom_wac->pen_input->absbit); - __clear_bit(ABS_TILT_X, wacom_wac->pen_input->absbit); - __clear_bit(ABS_TILT_Y, wacom_wac->pen_input->absbit); - __clear_bit(ABS_WHEEL, wacom_wac->pen_input->absbit); - __clear_bit(ABS_MISC, wacom_wac->pen_input->absbit); - __clear_bit(MSC_SERIAL, wacom_wac->pen_input->mscbit); - __clear_bit(EV_MSC, wacom_wac->pen_input->evbit); - } -} - -int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) -{ - struct wacom_features *features = &wacom_wac->features; - - if (!(features->device_type & WACOM_DEVICETYPE_PEN)) - return -ENODEV; - - if (features->device_type & WACOM_DEVICETYPE_DIRECT) - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - else - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - - if (features->type == HID_GENERIC) - /* setup has already been done */ - return 0; - - input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - __set_bit(BTN_TOUCH, input_dev->keybit); - __set_bit(ABS_MISC, input_dev->absbit); - - input_set_abs_params(input_dev, ABS_X, 0 + features->offset_left, - features->x_max - features->offset_right, - features->x_fuzz, 0); - input_set_abs_params(input_dev, ABS_Y, 0 + features->offset_top, - features->y_max - features->offset_bottom, - features->y_fuzz, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, 0, - features->pressure_max, features->pressure_fuzz, 0); - - /* penabled devices have fixed resolution for each model */ - input_abs_set_res(input_dev, ABS_X, features->x_resolution); - input_abs_set_res(input_dev, ABS_Y, features->y_resolution); - - switch (features->type) { - case GRAPHIRE_BT: - __clear_bit(ABS_MISC, input_dev->absbit); - fallthrough; - - case WACOM_MO: - case WACOM_G4: - input_set_abs_params(input_dev, ABS_DISTANCE, 0, - features->distance_max, - features->distance_fuzz, 0); - fallthrough; - - case GRAPHIRE: - input_set_capability(input_dev, EV_REL, REL_WHEEL); - - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - __set_bit(BTN_MIDDLE, input_dev->keybit); - - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_TOOL_MOUSE, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - break; - - case WACOM_27QHD: - case WACOM_24HD: - case DTK: - case WACOM_22HD: - case WACOM_21UX2: - case WACOM_BEE: - case CINTIQ: - case WACOM_13HD: - case CINTIQ_HYBRID: - case CINTIQ_COMPANION_2: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - wacom_setup_cintiq(wacom_wac); - break; - - case INTUOS3: - case INTUOS3L: - case INTUOS3S: - case INTUOS4: - case INTUOS4WL: - case INTUOS4L: - case INTUOS4S: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - fallthrough; - - case INTUOS: - wacom_setup_intuos(wacom_wac); - break; - - case INTUOS5: - case INTUOS5L: - case INTUOSPM: - case INTUOSPL: - case INTUOS5S: - case INTUOSPS: - case INTUOSP2_BT: - case INTUOSP2S_BT: - input_set_abs_params(input_dev, ABS_DISTANCE, 0, - features->distance_max, - features->distance_fuzz, 0); - - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - - wacom_setup_intuos(wacom_wac); - break; - - case WACOM_24HDT: - case WACOM_27QHDT: - case MTSCREEN: - case MTTPC: - case MTTPC_B: - case TABLETPC2FG: - case TABLETPC: - case TABLETPCE: - __clear_bit(ABS_MISC, input_dev->absbit); - fallthrough; - - case DTUS: - case DTUSX: - case PL: - case DTU: - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - break; - - case PTU: - __set_bit(BTN_STYLUS2, input_dev->keybit); - fallthrough; - - case PENPARTNER: - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - break; - - case INTUOSHT: - case BAMBOO_PT: - case BAMBOO_PEN: - case INTUOSHT2: - case INTUOSHT3_BT: - if (features->type == INTUOSHT2 || - features->type == INTUOSHT3_BT) { - wacom_setup_basic_pro_pen(wacom_wac); - - INIT_WORK(&wacom_wac->intuos_prox_event_worker, - wacom_intuos_schedule_prox_event); - } else { - __clear_bit(ABS_MISC, input_dev->absbit); - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - input_set_abs_params(input_dev, ABS_DISTANCE, 0, - features->distance_max, - features->distance_fuzz, 0); - } - break; - case BAMBOO_PAD: - __clear_bit(ABS_MISC, input_dev->absbit); - break; - } - return 0; -} - -int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) -{ - struct wacom_features *features = &wacom_wac->features; - - if (!(features->device_type & WACOM_DEVICETYPE_TOUCH)) - return -ENODEV; - - if (features->device_type & WACOM_DEVICETYPE_DIRECT) - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - else - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - - if (features->type == HID_GENERIC) - /* setup has already been done */ - return 0; - - input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - __set_bit(BTN_TOUCH, input_dev->keybit); - - if (features->touch_max == 1) { - input_set_abs_params(input_dev, ABS_X, 0, - features->x_max, features->x_fuzz, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - features->y_max, features->y_fuzz, 0); - input_abs_set_res(input_dev, ABS_X, - features->x_resolution); - input_abs_set_res(input_dev, ABS_Y, - features->y_resolution); - } - else if (features->touch_max > 1) { - input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, - features->x_max, features->x_fuzz, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, - features->y_max, features->y_fuzz, 0); - input_abs_set_res(input_dev, ABS_MT_POSITION_X, - features->x_resolution); - input_abs_set_res(input_dev, ABS_MT_POSITION_Y, - features->y_resolution); - } - - switch (features->type) { - case INTUOSP2_BT: - case INTUOSP2S_BT: - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - - if (wacom_wac->shared->touch->product == 0x361) { - input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, 12440, 4, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, 8640, 4, 0); - } - else if (wacom_wac->shared->touch->product == 0x360) { - input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, 8960, 4, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, 5920, 4, 0); - } - else if (wacom_wac->shared->touch->product == 0x393) { - input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, 6400, 4, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, 4000, 4, 0); - } - input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40); - input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40); - - fallthrough; - - case INTUOS5: - case INTUOS5L: - case INTUOSPM: - case INTUOSPL: - case INTUOS5S: - case INTUOSPS: - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, features->y_max, 0, 0); - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); - break; - - case WACOM_24HDT: - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); - fallthrough; - - case WACOM_27QHDT: - if (wacom_wac->shared->touch->product == 0x32C || - wacom_wac->shared->touch->product == 0xF6) { - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - wacom_wac->has_mute_touch_switch = true; - wacom_wac->is_soft_touch_switch = true; - } - fallthrough; - - case MTSCREEN: - case MTTPC: - case MTTPC_B: - case TABLETPC2FG: - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT); - fallthrough; - - case TABLETPC: - case TABLETPCE: - break; - - case INTUOSHT: - case INTUOSHT2: - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - fallthrough; - - case BAMBOO_PT: - case BAMBOO_TOUCH: - if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - input_set_abs_params(input_dev, - ABS_MT_TOUCH_MAJOR, - 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, - ABS_MT_TOUCH_MINOR, - 0, features->y_max, 0, 0); - } - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); - break; - - case BAMBOO_PAD: - input_mt_init_slots(input_dev, features->touch_max, - INPUT_MT_POINTER); - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - break; - } - return 0; -} - -static int wacom_numbered_button_to_key(int n) -{ - if (n < 10) - return BTN_0 + n; - else if (n < 16) - return BTN_A + (n-10); - else if (n < 18) - return BTN_BASE + (n-16); - else - return 0; -} - -static void wacom_setup_numbered_buttons(struct input_dev *input_dev, - int button_count) -{ - int i; - - for (i = 0; i < button_count; i++) { - int key = wacom_numbered_button_to_key(i); - - if (key) - __set_bit(key, input_dev->keybit); - } -} - -static void wacom_report_numbered_buttons(struct input_dev *input_dev, - int button_count, int mask) -{ - int i; - - for (i = 0; i < button_count; i++) { - int key = wacom_numbered_button_to_key(i); - - if (key) - input_report_key(input_dev, key, mask & (1 << i)); - } -} - -int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) -{ - struct wacom_features *features = &wacom_wac->features; - - if ((features->type == HID_GENERIC) && features->numbered_buttons > 0) - features->device_type |= WACOM_DEVICETYPE_PAD; - - if (!(features->device_type & WACOM_DEVICETYPE_PAD)) - return -ENODEV; - - if (features->type == REMOTE && input_dev == wacom_wac->pad_input) - return -ENODEV; - - input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - - /* kept for making legacy xf86-input-wacom working with the wheels */ - __set_bit(ABS_MISC, input_dev->absbit); - - /* kept for making legacy xf86-input-wacom accepting the pad */ - if (!(input_dev->absinfo && (input_dev->absinfo[ABS_X].minimum || - input_dev->absinfo[ABS_X].maximum))) - input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0); - if (!(input_dev->absinfo && (input_dev->absinfo[ABS_Y].minimum || - input_dev->absinfo[ABS_Y].maximum))) - input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0); - - /* kept for making udev and libwacom accepting the pad */ - __set_bit(BTN_STYLUS, input_dev->keybit); - - wacom_setup_numbered_buttons(input_dev, features->numbered_buttons); - - switch (features->type) { - - case CINTIQ_HYBRID: - case CINTIQ_COMPANION_2: - case DTK: - case DTUS: - case GRAPHIRE_BT: - break; - - case WACOM_MO: - __set_bit(BTN_BACK, input_dev->keybit); - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_FORWARD, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - break; - - case WACOM_G4: - __set_bit(BTN_BACK, input_dev->keybit); - __set_bit(BTN_FORWARD, input_dev->keybit); - input_set_capability(input_dev, EV_REL, REL_WHEEL); - break; - - case WACOM_24HD: - __set_bit(KEY_PROG1, input_dev->keybit); - __set_bit(KEY_PROG2, input_dev->keybit); - __set_bit(KEY_PROG3, input_dev->keybit); - - __set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit); - __set_bit(KEY_INFO, input_dev->keybit); - - if (!features->oPid) - __set_bit(KEY_BUTTONCONFIG, input_dev->keybit); - - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); - break; - - case WACOM_27QHD: - __set_bit(KEY_PROG1, input_dev->keybit); - __set_bit(KEY_PROG2, input_dev->keybit); - __set_bit(KEY_PROG3, input_dev->keybit); - - __set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit); - __set_bit(KEY_BUTTONCONFIG, input_dev->keybit); - - if (!features->oPid) - __set_bit(KEY_CONTROLPANEL, input_dev->keybit); - input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0); - input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */ - input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0); - input_abs_set_res(input_dev, ABS_Y, 1024); - input_set_abs_params(input_dev, ABS_Z, -2048, 2048, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 1024); - __set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit); - break; - - case WACOM_22HD: - __set_bit(KEY_PROG1, input_dev->keybit); - __set_bit(KEY_PROG2, input_dev->keybit); - __set_bit(KEY_PROG3, input_dev->keybit); - - __set_bit(KEY_BUTTONCONFIG, input_dev->keybit); - __set_bit(KEY_INFO, input_dev->keybit); - fallthrough; - - case WACOM_21UX2: - case WACOM_BEE: - case CINTIQ: - input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); - input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); - break; - - case WACOM_13HD: - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - break; - - case INTUOS3: - case INTUOS3L: - input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); - fallthrough; - - case INTUOS3S: - input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); - break; - - case INTUOS5: - case INTUOS5L: - case INTUOSPM: - case INTUOSPL: - case INTUOS5S: - case INTUOSPS: - case INTUOSP2_BT: - case INTUOSP2S_BT: - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - break; - - case INTUOS4WL: - /* - * For Bluetooth devices, the udev rule does not work correctly - * for pads unless we add a stylus capability, which forces - * ID_INPUT_TABLET to be set. - */ - __set_bit(BTN_STYLUS, input_dev->keybit); - fallthrough; - - case INTUOS4: - case INTUOS4L: - case INTUOS4S: - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - break; - - case INTUOSHT: - case BAMBOO_PT: - case BAMBOO_TOUCH: - case INTUOSHT2: - __clear_bit(ABS_MISC, input_dev->absbit); - - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_FORWARD, input_dev->keybit); - __set_bit(BTN_BACK, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - - break; - - case REMOTE: - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - break; - - case INTUOSHT3_BT: - case HID_GENERIC: - break; - - default: - /* no pad supported */ - return -ENODEV; - } - return 0; -} - -static const struct wacom_features wacom_features_0x00 = - { "Wacom Penpartner", 5040, 3780, 255, 0, - PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; -static const struct wacom_features wacom_features_0x10 = - { "Wacom Graphire", 10206, 7422, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x81 = - { "Wacom Graphire BT", 16704, 12064, 511, 32, - GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES, 2 }; -static const struct wacom_features wacom_features_0x11 = - { "Wacom Graphire2 4x5", 10206, 7422, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x12 = - { "Wacom Graphire2 5x7", 13918, 10206, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x13 = - { "Wacom Graphire3", 10208, 7424, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x14 = - { "Wacom Graphire3 6x8", 16704, 12064, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x15 = - { "Wacom Graphire4 4x5", 10208, 7424, 511, 63, - WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x16 = - { "Wacom Graphire4 6x8", 16704, 12064, 511, 63, - WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x17 = - { "Wacom BambooFun 4x5", 14760, 9225, 511, 63, - WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x18 = - { "Wacom BambooFun 6x8", 21648, 13530, 511, 63, - WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x19 = - { "Wacom Bamboo1 Medium", 16704, 12064, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x60 = - { "Wacom Volito", 5104, 3712, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x61 = - { "Wacom PenStation2", 3250, 2320, 255, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x62 = - { "Wacom Volito2 4x5", 5104, 3712, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x63 = - { "Wacom Volito2 2x3", 3248, 2320, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x64 = - { "Wacom PenPartner2", 3250, 2320, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x65 = - { "Wacom Bamboo", 14760, 9225, 511, 63, - WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x69 = - { "Wacom Bamboo1", 5104, 3712, 511, 63, - GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; -static const struct wacom_features wacom_features_0x6A = - { "Wacom Bamboo1 4x6", 14760, 9225, 1023, 63, - GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x6B = - { "Wacom Bamboo1 5x8", 21648, 13530, 1023, 63, - GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x20 = - { "Wacom Intuos 4x5", 12700, 10600, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x21 = - { "Wacom Intuos 6x8", 20320, 16240, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x22 = - { "Wacom Intuos 9x12", 30480, 24060, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x23 = - { "Wacom Intuos 12x12", 30480, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x24 = - { "Wacom Intuos 12x18", 45720, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x30 = - { "Wacom PL400", 5408, 4056, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x31 = - { "Wacom PL500", 6144, 4608, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x32 = - { "Wacom PL600", 6126, 4604, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x33 = - { "Wacom PL600SX", 6260, 5016, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x34 = - { "Wacom PL550", 6144, 4608, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x35 = - { "Wacom PL800", 7220, 5780, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x37 = - { "Wacom PL700", 6758, 5406, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x38 = - { "Wacom PL510", 6282, 4762, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x39 = - { "Wacom DTU710", 34080, 27660, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0xC4 = - { "Wacom DTF521", 6282, 4762, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0xC0 = - { "Wacom DTF720", 6858, 5506, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0xC2 = - { "Wacom DTF720a", 6858, 5506, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x03 = - { "Wacom Cintiq Partner", 20480, 15360, 511, 0, - PTU, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x41 = - { "Wacom Intuos2 4x5", 12700, 10600, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x42 = - { "Wacom Intuos2 6x8", 20320, 16240, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x43 = - { "Wacom Intuos2 9x12", 30480, 24060, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x44 = - { "Wacom Intuos2 12x12", 30480, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x45 = - { "Wacom Intuos2 12x18", 45720, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xB0 = - { "Wacom Intuos3 4x5", 25400, 20320, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; -static const struct wacom_features wacom_features_0xB1 = - { "Wacom Intuos3 6x8", 40640, 30480, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB2 = - { "Wacom Intuos3 9x12", 60960, 45720, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB3 = - { "Wacom Intuos3 12x12", 60960, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB4 = - { "Wacom Intuos3 12x19", 97536, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB5 = - { "Wacom Intuos3 6x11", 54204, 31750, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB7 = - { "Wacom Intuos3 4x6", 31496, 19685, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; -static const struct wacom_features wacom_features_0xB8 = - { "Wacom Intuos4 4x6", 31496, 19685, 2047, 63, - INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; -static const struct wacom_features wacom_features_0xB9 = - { "Wacom Intuos4 6x9", 44704, 27940, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0xBA = - { "Wacom Intuos4 8x13", 65024, 40640, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0xBB = - { "Wacom Intuos4 12x19", 97536, 60960, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0xBC = - { "Wacom Intuos4 WL", 40640, 25400, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0xBD = - { "Wacom Intuos4 WL", 40640, 25400, 2047, 63, - INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0x26 = - { "Wacom Intuos5 touch S", 31496, 19685, 2047, 63, - INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x27 = - { "Wacom Intuos5 touch M", 44704, 27940, 2047, 63, - INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x28 = - { "Wacom Intuos5 touch L", 65024, 40640, 2047, 63, - INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x29 = - { "Wacom Intuos5 S", 31496, 19685, 2047, 63, - INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; -static const struct wacom_features wacom_features_0x2A = - { "Wacom Intuos5 M", 44704, 27940, 2047, 63, - INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0x314 = - { "Wacom Intuos Pro S", 31496, 19685, 2047, 63, - INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x315 = - { "Wacom Intuos Pro M", 44704, 27940, 2047, 63, - INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x317 = - { "Wacom Intuos Pro L", 65024, 40640, 2047, 63, - INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0xF4 = - { "Wacom Cintiq 24HD", 104480, 65600, 2047, 63, - WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; -static const struct wacom_features wacom_features_0xF8 = - { "Wacom Cintiq 24HD touch", 104480, 65600, 2047, 63, /* Pen */ - WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 }; -static const struct wacom_features wacom_features_0xF6 = - { "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */ - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x32A = - { "Wacom Cintiq 27QHD", 120140, 67920, 2047, 63, - WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; -static const struct wacom_features wacom_features_0x32B = - { "Wacom Cintiq 27QHD touch", 120140, 67920, 2047, 63, - WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C }; -static const struct wacom_features wacom_features_0x32C = - { "Wacom Cintiq 27QHD touch", .type = WACOM_27QHDT, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 }; -static const struct wacom_features wacom_features_0x3F = - { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63, - CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xC5 = - { "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; -static const struct wacom_features wacom_features_0xC6 = - { "Wacom Cintiq 12WX", 53020, 33440, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; -static const struct wacom_features wacom_features_0x304 = - { "Wacom Cintiq 13HD", 59552, 33848, 1023, 63, - WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; -static const struct wacom_features wacom_features_0x333 = - { "Wacom Cintiq 13HD touch", 59552, 33848, 2047, 63, - WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 }; -static const struct wacom_features wacom_features_0x335 = - { "Wacom Cintiq 13HD touch", .type = WACOM_24HDT, /* Touch */ - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x333, .touch_max = 10, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0xC7 = - { "Wacom DTU1931", 37832, 30305, 511, 0, - PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xCE = - { "Wacom DTU2231", 47864, 27011, 511, 0, - DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBMOUSE }; -static const struct wacom_features wacom_features_0xF0 = - { "Wacom DTU1631", 34623, 19553, 511, 0, - DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xFB = - { "Wacom DTU1031", 22096, 13960, 511, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; -static const struct wacom_features wacom_features_0x32F = - { "Wacom DTU1031X", 22672, 12928, 511, 0, - DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; -static const struct wacom_features wacom_features_0x336 = - { "Wacom DTU1141", 23672, 13403, 1023, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; -static const struct wacom_features wacom_features_0x57 = - { "Wacom DTK2241", 95840, 54260, 2047, 63, - DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; -static const struct wacom_features wacom_features_0x59 = /* Pen */ - { "Wacom DTH2242", 95840, 54260, 2047, 63, - DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D }; -static const struct wacom_features wacom_features_0x5D = /* Touch */ - { "Wacom DTH2242", .type = WACOM_24HDT, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0xCC = - { "Wacom Cintiq 21UX2", 87200, 65600, 2047, 63, - WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; -static const struct wacom_features wacom_features_0xFA = - { "Wacom Cintiq 22HD", 95840, 54260, 2047, 63, - WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; -static const struct wacom_features wacom_features_0x5B = - { "Wacom Cintiq 22HDT", 95840, 54260, 2047, 63, - WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e }; -static const struct wacom_features wacom_features_0x5E = - { "Wacom Cintiq 22HDT", .type = WACOM_24HDT, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x90 = - { "Wacom ISDv4 90", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ -static const struct wacom_features wacom_features_0x93 = - { "Wacom ISDv4 93", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; -static const struct wacom_features wacom_features_0x97 = - { "Wacom ISDv4 97", 26202, 16325, 511, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ -static const struct wacom_features wacom_features_0x9A = - { "Wacom ISDv4 9A", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; -static const struct wacom_features wacom_features_0x9F = - { "Wacom ISDv4 9F", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; -static const struct wacom_features wacom_features_0xE2 = - { "Wacom ISDv4 E2", 26202, 16325, 255, 0, - TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xE3 = - { "Wacom ISDv4 E3", 26202, 16325, 255, 0, - TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xE5 = - { "Wacom ISDv4 E5", 26202, 16325, 255, 0, - MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xE6 = - { "Wacom ISDv4 E6", 27760, 15694, 255, 0, - TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xEC = - { "Wacom ISDv4 EC", 25710, 14500, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ -static const struct wacom_features wacom_features_0xED = - { "Wacom ISDv4 ED", 26202, 16325, 255, 0, - TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; -static const struct wacom_features wacom_features_0xEF = - { "Wacom ISDv4 EF", 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ -static const struct wacom_features wacom_features_0x100 = - { "Wacom ISDv4 100", 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x101 = - { "Wacom ISDv4 101", 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x10D = - { "Wacom ISDv4 10D", 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x10E = - { "Wacom ISDv4 10E", 27760, 15694, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x10F = - { "Wacom ISDv4 10F", 27760, 15694, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x116 = - { "Wacom ISDv4 116", 26202, 16325, 255, 0, - TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 1 }; -static const struct wacom_features wacom_features_0x12C = - { "Wacom ISDv4 12C", 27848, 15752, 2047, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; /* Pen-only */ -static const struct wacom_features wacom_features_0x4001 = - { "Wacom ISDv4 4001", 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x4004 = - { "Wacom ISDv4 4004", 11060, 6220, 255, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5000 = - { "Wacom ISDv4 5000", 27848, 15752, 1023, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5002 = - { "Wacom ISDv4 5002", 29576, 16724, 1023, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x47 = - { "Wacom Intuos2 6x8", 20320, 16240, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x84 = - { "Wacom Wireless Receiver", .type = WIRELESS, .touch_max = 16 }; -static const struct wacom_features wacom_features_0xD0 = - { "Wacom Bamboo 2FG", 14720, 9200, 1023, 31, - BAMBOO_TOUCH, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xD1 = - { "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xD2 = - { "Wacom Bamboo Craft", 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xD3 = - { "Wacom Bamboo 2FG 6x8", 21648, 13700, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xD4 = - { "Wacom Bamboo Pen", 14720, 9200, 1023, 31, - BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xD5 = - { "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31, - BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xD6 = - { "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xD7 = - { "Wacom BambooPT 2FG Small", 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xD8 = - { "Wacom Bamboo Comic 2FG", 21648, 13700, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xDA = - { "Wacom Bamboo 2FG 4x5 SE", 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xDB = - { "Wacom Bamboo 2FG 6x8 SE", 21648, 13700, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xDD = - { "Wacom Bamboo Connect", 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xDE = - { "Wacom Bamboo 16FG 4x5", 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 }; -static const struct wacom_features wacom_features_0xDF = - { "Wacom Bamboo 16FG 6x8", 21648, 13700, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x300 = - { "Wacom Bamboo One S", 14720, 9225, 1023, 31, - BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x301 = - { "Wacom Bamboo One M", 21648, 13530, 1023, 31, - BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x302 = - { "Wacom Intuos PT S", 15200, 9500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x303 = - { "Wacom Intuos PT M", 21600, 13500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x30E = - { "Wacom Intuos S", 15200, 9500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x6004 = - { "ISD-V4", 12800, 8000, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x307 = - { "Wacom ISDv5 307", 59552, 33848, 2047, 63, - CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 }; -static const struct wacom_features wacom_features_0x309 = - { "Wacom ISDv5 309", .type = WACOM_24HDT, /* Touch */ - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x30A = - { "Wacom ISDv5 30A", 59552, 33848, 2047, 63, - CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C }; -static const struct wacom_features wacom_features_0x30C = - { "Wacom ISDv5 30C", .type = WACOM_24HDT, /* Touch */ - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x318 = - { "Wacom USB Bamboo PAD", 4095, 4095, /* Touch */ - .type = BAMBOO_PAD, 35, 48, .touch_max = 4 }; -static const struct wacom_features wacom_features_0x319 = - { "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */ - .type = BAMBOO_PAD, 35, 48, .touch_max = 4 }; -static const struct wacom_features wacom_features_0x325 = - { "Wacom ISDv5 325", 59552, 33848, 2047, 63, - CINTIQ_COMPANION_2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 11, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x326 }; -static const struct wacom_features wacom_features_0x326 = /* Touch */ - { "Wacom ISDv5 326", .type = HID_GENERIC, .oVid = USB_VENDOR_ID_WACOM, - .oPid = 0x325 }; -static const struct wacom_features wacom_features_0x323 = - { "Wacom Intuos P M", 21600, 13500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x331 = - { "Wacom Express Key Remote", .type = REMOTE, - .numbered_buttons = 18, .check_for_hid_type = true, - .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x33B = - { "Wacom Intuos S 2", 15200, 9500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x33C = - { "Wacom Intuos PT S 2", 15200, 9500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x33D = - { "Wacom Intuos P M 2", 21600, 13500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x33E = - { "Wacom Intuos PT M 2", 21600, 13500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16, - .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; -static const struct wacom_features wacom_features_0x343 = - { "Wacom DTK1651", 34816, 19759, 1023, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; -static const struct wacom_features wacom_features_0x360 = - { "Wacom Intuos Pro M", 44800, 29600, 8191, 63, - INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 }; -static const struct wacom_features wacom_features_0x361 = - { "Wacom Intuos Pro L", 62200, 43200, 8191, 63, - INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 }; -static const struct wacom_features wacom_features_0x377 = - { "Wacom Intuos BT S", 15200, 9500, 4095, 63, - INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x379 = - { "Wacom Intuos BT M", 21600, 13500, 4095, 63, - INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x37A = - { "Wacom One by Wacom S", 15200, 9500, 2047, 63, - BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x37B = - { "Wacom One by Wacom M", 21600, 13500, 2047, 63, - BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x393 = - { "Wacom Intuos Pro S", 31920, 19950, 8191, 63, - INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, - .touch_max = 10 }; -static const struct wacom_features wacom_features_0x3c6 = - { "Wacom Intuos BT S", 15200, 9500, 4095, 63, - INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x3c8 = - { "Wacom Intuos BT M", 21600, 13500, 4095, 63, - INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x3dd = - { "Wacom Intuos Pro S", 31920, 19950, 8191, 63, - INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, - .touch_max = 10 }; - -static const struct wacom_features wacom_features_HID_ANY_ID = - { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID }; - -static const struct wacom_features wacom_features_0x94 = - { "Wacom Bootloader", .type = BOOTLOADER }; - -#define USB_DEVICE_WACOM(prod) \ - HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\ - .driver_data = (kernel_ulong_t)&wacom_features_##prod - -#define BT_DEVICE_WACOM(prod) \ - HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\ - .driver_data = (kernel_ulong_t)&wacom_features_##prod - -#define I2C_DEVICE_WACOM(prod) \ - HID_DEVICE(BUS_I2C, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\ - .driver_data = (kernel_ulong_t)&wacom_features_##prod - -#define USB_DEVICE_LENOVO(prod) \ - HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \ - .driver_data = (kernel_ulong_t)&wacom_features_##prod - -const struct hid_device_id wacom_ids[] = { - { USB_DEVICE_WACOM(0x00) }, - { USB_DEVICE_WACOM(0x03) }, - { USB_DEVICE_WACOM(0x10) }, - { USB_DEVICE_WACOM(0x11) }, - { USB_DEVICE_WACOM(0x12) }, - { USB_DEVICE_WACOM(0x13) }, - { USB_DEVICE_WACOM(0x14) }, - { USB_DEVICE_WACOM(0x15) }, - { USB_DEVICE_WACOM(0x16) }, - { USB_DEVICE_WACOM(0x17) }, - { USB_DEVICE_WACOM(0x18) }, - { USB_DEVICE_WACOM(0x19) }, - { USB_DEVICE_WACOM(0x20) }, - { USB_DEVICE_WACOM(0x21) }, - { USB_DEVICE_WACOM(0x22) }, - { USB_DEVICE_WACOM(0x23) }, - { USB_DEVICE_WACOM(0x24) }, - { USB_DEVICE_WACOM(0x26) }, - { USB_DEVICE_WACOM(0x27) }, - { USB_DEVICE_WACOM(0x28) }, - { USB_DEVICE_WACOM(0x29) }, - { USB_DEVICE_WACOM(0x2A) }, - { USB_DEVICE_WACOM(0x30) }, - { USB_DEVICE_WACOM(0x31) }, - { USB_DEVICE_WACOM(0x32) }, - { USB_DEVICE_WACOM(0x33) }, - { USB_DEVICE_WACOM(0x34) }, - { USB_DEVICE_WACOM(0x35) }, - { USB_DEVICE_WACOM(0x37) }, - { USB_DEVICE_WACOM(0x38) }, - { USB_DEVICE_WACOM(0x39) }, - { USB_DEVICE_WACOM(0x3F) }, - { USB_DEVICE_WACOM(0x41) }, - { USB_DEVICE_WACOM(0x42) }, - { USB_DEVICE_WACOM(0x43) }, - { USB_DEVICE_WACOM(0x44) }, - { USB_DEVICE_WACOM(0x45) }, - { USB_DEVICE_WACOM(0x47) }, - { USB_DEVICE_WACOM(0x57) }, - { USB_DEVICE_WACOM(0x59) }, - { USB_DEVICE_WACOM(0x5B) }, - { USB_DEVICE_WACOM(0x5D) }, - { USB_DEVICE_WACOM(0x5E) }, - { USB_DEVICE_WACOM(0x60) }, - { USB_DEVICE_WACOM(0x61) }, - { USB_DEVICE_WACOM(0x62) }, - { USB_DEVICE_WACOM(0x63) }, - { USB_DEVICE_WACOM(0x64) }, - { USB_DEVICE_WACOM(0x65) }, - { USB_DEVICE_WACOM(0x69) }, - { USB_DEVICE_WACOM(0x6A) }, - { USB_DEVICE_WACOM(0x6B) }, - { BT_DEVICE_WACOM(0x81) }, - { USB_DEVICE_WACOM(0x84) }, - { USB_DEVICE_WACOM(0x90) }, - { USB_DEVICE_WACOM(0x93) }, - { USB_DEVICE_WACOM(0x94) }, - { USB_DEVICE_WACOM(0x97) }, - { USB_DEVICE_WACOM(0x9A) }, - { USB_DEVICE_WACOM(0x9F) }, - { USB_DEVICE_WACOM(0xB0) }, - { USB_DEVICE_WACOM(0xB1) }, - { USB_DEVICE_WACOM(0xB2) }, - { USB_DEVICE_WACOM(0xB3) }, - { USB_DEVICE_WACOM(0xB4) }, - { USB_DEVICE_WACOM(0xB5) }, - { USB_DEVICE_WACOM(0xB7) }, - { USB_DEVICE_WACOM(0xB8) }, - { USB_DEVICE_WACOM(0xB9) }, - { USB_DEVICE_WACOM(0xBA) }, - { USB_DEVICE_WACOM(0xBB) }, - { USB_DEVICE_WACOM(0xBC) }, - { BT_DEVICE_WACOM(0xBD) }, - { USB_DEVICE_WACOM(0xC0) }, - { USB_DEVICE_WACOM(0xC2) }, - { USB_DEVICE_WACOM(0xC4) }, - { USB_DEVICE_WACOM(0xC5) }, - { USB_DEVICE_WACOM(0xC6) }, - { USB_DEVICE_WACOM(0xC7) }, - { USB_DEVICE_WACOM(0xCC) }, - { USB_DEVICE_WACOM(0xCE) }, - { USB_DEVICE_WACOM(0xD0) }, - { USB_DEVICE_WACOM(0xD1) }, - { USB_DEVICE_WACOM(0xD2) }, - { USB_DEVICE_WACOM(0xD3) }, - { USB_DEVICE_WACOM(0xD4) }, - { USB_DEVICE_WACOM(0xD5) }, - { USB_DEVICE_WACOM(0xD6) }, - { USB_DEVICE_WACOM(0xD7) }, - { USB_DEVICE_WACOM(0xD8) }, - { USB_DEVICE_WACOM(0xDA) }, - { USB_DEVICE_WACOM(0xDB) }, - { USB_DEVICE_WACOM(0xDD) }, - { USB_DEVICE_WACOM(0xDE) }, - { USB_DEVICE_WACOM(0xDF) }, - { USB_DEVICE_WACOM(0xE2) }, - { USB_DEVICE_WACOM(0xE3) }, - { USB_DEVICE_WACOM(0xE5) }, - { USB_DEVICE_WACOM(0xE6) }, - { USB_DEVICE_WACOM(0xEC) }, - { USB_DEVICE_WACOM(0xED) }, - { USB_DEVICE_WACOM(0xEF) }, - { USB_DEVICE_WACOM(0xF0) }, - { USB_DEVICE_WACOM(0xF4) }, - { USB_DEVICE_WACOM(0xF6) }, - { USB_DEVICE_WACOM(0xF8) }, - { USB_DEVICE_WACOM(0xFA) }, - { USB_DEVICE_WACOM(0xFB) }, - { USB_DEVICE_WACOM(0x100) }, - { USB_DEVICE_WACOM(0x101) }, - { USB_DEVICE_WACOM(0x10D) }, - { USB_DEVICE_WACOM(0x10E) }, - { USB_DEVICE_WACOM(0x10F) }, - { USB_DEVICE_WACOM(0x116) }, - { USB_DEVICE_WACOM(0x12C) }, - { USB_DEVICE_WACOM(0x300) }, - { USB_DEVICE_WACOM(0x301) }, - { USB_DEVICE_WACOM(0x302) }, - { USB_DEVICE_WACOM(0x303) }, - { USB_DEVICE_WACOM(0x304) }, - { USB_DEVICE_WACOM(0x307) }, - { USB_DEVICE_WACOM(0x309) }, - { USB_DEVICE_WACOM(0x30A) }, - { USB_DEVICE_WACOM(0x30C) }, - { USB_DEVICE_WACOM(0x30E) }, - { USB_DEVICE_WACOM(0x314) }, - { USB_DEVICE_WACOM(0x315) }, - { USB_DEVICE_WACOM(0x317) }, - { USB_DEVICE_WACOM(0x318) }, - { USB_DEVICE_WACOM(0x319) }, - { USB_DEVICE_WACOM(0x323) }, - { USB_DEVICE_WACOM(0x325) }, - { USB_DEVICE_WACOM(0x326) }, - { USB_DEVICE_WACOM(0x32A) }, - { USB_DEVICE_WACOM(0x32B) }, - { USB_DEVICE_WACOM(0x32C) }, - { USB_DEVICE_WACOM(0x32F) }, - { USB_DEVICE_WACOM(0x331) }, - { USB_DEVICE_WACOM(0x333) }, - { USB_DEVICE_WACOM(0x335) }, - { USB_DEVICE_WACOM(0x336) }, - { USB_DEVICE_WACOM(0x33B) }, - { USB_DEVICE_WACOM(0x33C) }, - { USB_DEVICE_WACOM(0x33D) }, - { USB_DEVICE_WACOM(0x33E) }, - { USB_DEVICE_WACOM(0x343) }, - { BT_DEVICE_WACOM(0x360) }, - { BT_DEVICE_WACOM(0x361) }, - { BT_DEVICE_WACOM(0x377) }, - { BT_DEVICE_WACOM(0x379) }, - { USB_DEVICE_WACOM(0x37A) }, - { USB_DEVICE_WACOM(0x37B) }, - { BT_DEVICE_WACOM(0x393) }, - { BT_DEVICE_WACOM(0x3c6) }, - { BT_DEVICE_WACOM(0x3c8) }, - { BT_DEVICE_WACOM(0x3dd) }, - { USB_DEVICE_WACOM(0x4001) }, - { USB_DEVICE_WACOM(0x4004) }, - { USB_DEVICE_WACOM(0x5000) }, - { USB_DEVICE_WACOM(0x5002) }, - { USB_DEVICE_LENOVO(0x6004) }, - - { USB_DEVICE_WACOM(HID_ANY_ID) }, - { I2C_DEVICE_WACOM(HID_ANY_ID) }, - { BT_DEVICE_WACOM(HID_ANY_ID) }, - { } -}; -MODULE_DEVICE_TABLE(hid, wacom_ids); diff --git a/3.17/wacom_wac.h b/3.17/wacom_wac.h deleted file mode 100644 index 62d02764..00000000 --- a/3.17/wacom_wac.h +++ /dev/null @@ -1,391 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifndef WACOM_WAC_H -#define WACOM_WAC_H - -#include -#include -#include - -/* maximum packet length for USB/BT devices */ -#define WACOM_PKGLEN_MAX 361 - -#define WACOM_NAME_MAX 64 -#define WACOM_MAX_REMOTES 5 -#define WACOM_STATUS_UNKNOWN 255 - -/* packet length for individual models */ -#define WACOM_PKGLEN_BBFUN 9 -#define WACOM_PKGLEN_TPC1FG 5 -#define WACOM_PKGLEN_TPC1FG_B 10 -#define WACOM_PKGLEN_TPC2FG 14 -#define WACOM_PKGLEN_BBTOUCH 20 -#define WACOM_PKGLEN_BBTOUCH3 64 -#define WACOM_PKGLEN_BBPEN 10 -#define WACOM_PKGLEN_WIRELESS 32 -#define WACOM_PKGLEN_PENABLED 8 -#define WACOM_PKGLEN_BPAD_TOUCH 32 -#define WACOM_PKGLEN_BPAD_TOUCH_USB 64 - -/* wacom data size per MT contact */ -#define WACOM_BYTES_PER_MT_PACKET 11 -#define WACOM_BYTES_PER_24HDT_PACKET 14 -#define WACOM_BYTES_PER_QHDTHID_PACKET 6 - -/* device IDs */ -#define STYLUS_DEVICE_ID 0x02 -#define TOUCH_DEVICE_ID 0x03 -#define CURSOR_DEVICE_ID 0x06 -#define ERASER_DEVICE_ID 0x0A -#define PAD_DEVICE_ID 0x0F - -/* wacom data packet report IDs */ -#define WACOM_REPORT_PENABLED 2 -#define WACOM_REPORT_PENABLED_BT 3 -#define WACOM_REPORT_INTUOS_ID1 5 -#define WACOM_REPORT_INTUOS_ID2 6 -#define WACOM_REPORT_INTUOSPAD 12 -#define WACOM_REPORT_INTUOS5PAD 3 -#define WACOM_REPORT_DTUSPAD 21 -#define WACOM_REPORT_TPC1FG 6 -#define WACOM_REPORT_TPC2FG 13 -#define WACOM_REPORT_TPCMT 13 -#define WACOM_REPORT_TPCMT2 3 -#define WACOM_REPORT_TPCHID 15 -#define WACOM_REPORT_CINTIQ 16 -#define WACOM_REPORT_CINTIQPAD 17 -#define WACOM_REPORT_TPCST 16 -#define WACOM_REPORT_DTUS 17 -#define WACOM_REPORT_TPC1FGE 18 -#define WACOM_REPORT_24HDT 1 -#define WACOM_REPORT_WL 128 -#define WACOM_REPORT_USB 192 -#define WACOM_REPORT_BPAD_PEN 3 -#define WACOM_REPORT_BPAD_TOUCH 16 -#define WACOM_REPORT_DEVICE_LIST 16 -#define WACOM_REPORT_INTUOS_PEN 16 -#define WACOM_REPORT_REMOTE 17 -#define WACOM_REPORT_INTUOSHT2_ID 8 - -/* wacom command report ids */ -#define WAC_CMD_WL_LED_CONTROL 0x03 -#define WAC_CMD_LED_CONTROL 0x20 -#define WAC_CMD_ICON_START 0x21 -#define WAC_CMD_ICON_XFER 0x23 -#define WAC_CMD_ICON_BT_XFER 0x26 -#define WAC_CMD_DELETE_PAIRING 0x20 -#define WAC_CMD_LED_CONTROL_GENERIC 0x32 -#define WAC_CMD_UNPAIR_ALL 0xFF -#define WAC_CMD_WL_INTUOSP2 0x82 - -/* device quirks */ -#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 -#define WACOM_QUIRK_SENSE 0x0002 -#define WACOM_QUIRK_AESPEN 0x0004 -#define WACOM_QUIRK_BATTERY 0x0008 -#define WACOM_QUIRK_TOOLSERIAL 0x0010 -#define WACOM_QUIRK_PEN_BUTTON3 0x0020 - -/* device types */ -#define WACOM_DEVICETYPE_NONE 0x0000 -#define WACOM_DEVICETYPE_PEN 0x0001 -#define WACOM_DEVICETYPE_TOUCH 0x0002 -#define WACOM_DEVICETYPE_PAD 0x0004 -#define WACOM_DEVICETYPE_WL_MONITOR 0x0008 -#define WACOM_DEVICETYPE_DIRECT 0x0010 - -#ifndef HID_DG_BATTERYSTRENGTH -#define HID_DG_BATTERYSTRENGTH (HID_UP_DIGITIZER | 0x3B) -#endif - -#ifndef HID_DG_TILT_X -#define HID_DG_TILT_X (HID_UP_DIGITIZER | 0x3D) -#endif - -#ifndef HID_DG_TILT_Y -#define HID_DG_TILT_Y (HID_UP_DIGITIZER | 0x3E) -#endif - -#ifndef HID_DG_TWIST -#define HID_DG_TWIST (HID_UP_DIGITIZER | 0x41) -#endif - -#ifndef BTN_STYLUS3 -#define BTN_STYLUS3 0x149 -#endif - -#ifndef HID_DG_SCANTIME -#define HID_DG_SCANTIME (HID_UP_DIGITIZER | 0x56) -#endif - -#define WACOM_POWER_SUPPLY_STATUS_AUTO -1 - -#define WACOM_HID_UP_WACOMDIGITIZER 0xff0d0000 -#define WACOM_HID_SP_PAD 0x00040000 -#define WACOM_HID_SP_BUTTON 0x00090000 -#define WACOM_HID_SP_DIGITIZER 0x000d0000 -#define WACOM_HID_SP_DIGITIZERINFO 0x00100000 -#define WACOM_HID_WD_DIGITIZER (WACOM_HID_UP_WACOMDIGITIZER | 0x01) -#define WACOM_HID_WD_PEN (WACOM_HID_UP_WACOMDIGITIZER | 0x02) -#define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36) -#define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39) -#define WACOM_HID_WD_SERIALNUMBER (WACOM_HID_UP_WACOMDIGITIZER | 0x5b) -#define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c) -#define WACOM_HID_WD_BARRELSWITCH3 (WACOM_HID_UP_WACOMDIGITIZER | 0x5d) -#define WACOM_HID_WD_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77) -#define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132) -#define WACOM_HID_WD_TOUCHSTRIP (WACOM_HID_UP_WACOMDIGITIZER | 0x0136) -#define WACOM_HID_WD_TOUCHSTRIP2 (WACOM_HID_UP_WACOMDIGITIZER | 0x0137) -#define WACOM_HID_WD_TOUCHRING (WACOM_HID_UP_WACOMDIGITIZER | 0x0138) -#define WACOM_HID_WD_TOUCHRINGSTATUS (WACOM_HID_UP_WACOMDIGITIZER | 0x0139) -#define WACOM_HID_WD_REPORT_VALID (WACOM_HID_UP_WACOMDIGITIZER | 0x01d0) -#define WACOM_HID_WD_SEQUENCENUMBER (WACOM_HID_UP_WACOMDIGITIZER | 0x0220) -#define WACOM_HID_WD_ACCELEROMETER_X (WACOM_HID_UP_WACOMDIGITIZER | 0x0401) -#define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402) -#define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403) -#define WACOM_HID_WD_BATTERY_CHARGING (WACOM_HID_UP_WACOMDIGITIZER | 0x0404) -#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0454) -#define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b) -#define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910) -#define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0940) -#define WACOM_HID_WD_MODE_CHANGE (WACOM_HID_UP_WACOMDIGITIZER | 0x0980) -#define WACOM_HID_WD_MUTE_DEVICE (WACOM_HID_UP_WACOMDIGITIZER | 0x0981) -#define WACOM_HID_WD_CONTROLPANEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0982) -#define WACOM_HID_WD_ONSCREEN_KEYBOARD (WACOM_HID_UP_WACOMDIGITIZER | 0x0983) -#define WACOM_HID_WD_BUTTONCONFIG (WACOM_HID_UP_WACOMDIGITIZER | 0x0986) -#define WACOM_HID_WD_BUTTONHOME (WACOM_HID_UP_WACOMDIGITIZER | 0x0990) -#define WACOM_HID_WD_BUTTONUP (WACOM_HID_UP_WACOMDIGITIZER | 0x0991) -#define WACOM_HID_WD_BUTTONDOWN (WACOM_HID_UP_WACOMDIGITIZER | 0x0992) -#define WACOM_HID_WD_BUTTONLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0993) -#define WACOM_HID_WD_BUTTONRIGHT (WACOM_HID_UP_WACOMDIGITIZER | 0x0994) -#define WACOM_HID_WD_BUTTONCENTER (WACOM_HID_UP_WACOMDIGITIZER | 0x0995) -#define WACOM_HID_WD_FINGERWHEEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0d03) -#define WACOM_HID_WD_OFFSETLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0d30) -#define WACOM_HID_WD_OFFSETTOP (WACOM_HID_UP_WACOMDIGITIZER | 0x0d31) -#define WACOM_HID_WD_OFFSETRIGHT (WACOM_HID_UP_WACOMDIGITIZER | 0x0d32) -#define WACOM_HID_WD_OFFSETBOTTOM (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33) -#define WACOM_HID_WD_DATAMODE (WACOM_HID_UP_WACOMDIGITIZER | 0x1002) -#define WACOM_HID_WD_DIGITIZERINFO (WACOM_HID_UP_WACOMDIGITIZER | 0x1013) -#define WACOM_HID_WD_TOUCH_RING_SETTING (WACOM_HID_UP_WACOMDIGITIZER | 0x1032) -#define WACOM_HID_UP_G9 0xff090000 -#define WACOM_HID_G9_PEN (WACOM_HID_UP_G9 | 0x02) -#define WACOM_HID_G9_TOUCHSCREEN (WACOM_HID_UP_G9 | 0x11) -#define WACOM_HID_UP_G11 0xff110000 -#define WACOM_HID_G11_PEN (WACOM_HID_UP_G11 | 0x02) -#define WACOM_HID_G11_TOUCHSCREEN (WACOM_HID_UP_G11 | 0x11) -#define WACOM_HID_UP_WACOMTOUCH 0xff000000 -#define WACOM_HID_WT_TOUCHSCREEN (WACOM_HID_UP_WACOMTOUCH | 0x04) -#define WACOM_HID_WT_TOUCHPAD (WACOM_HID_UP_WACOMTOUCH | 0x05) -#define WACOM_HID_WT_CONTACTMAX (WACOM_HID_UP_WACOMTOUCH | 0x55) -#define WACOM_HID_WT_SERIALNUMBER (WACOM_HID_UP_WACOMTOUCH | 0x5b) -#define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130) -#define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131) -#define WACOM_HID_WT_REPORT_VALID (WACOM_HID_UP_WACOMTOUCH | 0x1d0) - -#define WACOM_BATTERY_USAGE(f) (((f)->hid == HID_DG_BATTERYSTRENGTH) || \ - ((f)->hid == WACOM_HID_WD_BATTERY_CHARGING) || \ - ((f)->hid == WACOM_HID_WD_BATTERY_LEVEL)) - -#define WACOM_PAD_FIELD(f) (((f)->physical == HID_DG_TABLETFUNCTIONKEY) || \ - ((f)->physical == WACOM_HID_WD_DIGITIZERFNKEYS) || \ - ((f)->physical == WACOM_HID_WD_DIGITIZERINFO)) - -#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ - ((f)->physical == HID_DG_STYLUS) || \ - ((f)->physical == HID_DG_PEN) || \ - ((f)->application == HID_DG_PEN) || \ - ((f)->application == HID_DG_DIGITIZER) || \ - ((f)->application == WACOM_HID_WD_PEN) || \ - ((f)->application == WACOM_HID_WD_DIGITIZER) || \ - ((f)->application == WACOM_HID_G9_PEN) || \ - ((f)->application == WACOM_HID_G11_PEN)) -#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ - ((f)->physical == HID_DG_FINGER) || \ - ((f)->application == HID_DG_TOUCHSCREEN) || \ - ((f)->application == WACOM_HID_G9_TOUCHSCREEN) || \ - ((f)->application == WACOM_HID_G11_TOUCHSCREEN) || \ - ((f)->application == WACOM_HID_WT_TOUCHPAD) || \ - ((f)->application == HID_DG_TOUCHPAD)) - -#define WACOM_DIRECT_DEVICE(f) (((f)->application == HID_DG_TOUCHSCREEN) || \ - ((f)->application == WACOM_HID_WT_TOUCHSCREEN) || \ - ((f)->application == HID_DG_PEN) || \ - ((f)->application == WACOM_HID_WD_PEN)) - -enum { - PENPARTNER = 0, - GRAPHIRE, - GRAPHIRE_BT, - WACOM_G4, - PTU, - PL, - DTU, - DTUS, - DTUSX, - INTUOS, - INTUOS3S, - INTUOS3, - INTUOS3L, - INTUOS4S, - INTUOS4, - INTUOS4WL, - INTUOS4L, - INTUOS5S, - INTUOS5, - INTUOS5L, - INTUOSPS, - INTUOSPM, - INTUOSPL, - INTUOSP2_BT, - INTUOSP2S_BT, - INTUOSHT3_BT, - WACOM_21UX2, - WACOM_22HD, - DTK, - WACOM_24HD, - WACOM_27QHD, - CINTIQ_HYBRID, - CINTIQ_COMPANION_2, - CINTIQ, - WACOM_BEE, - WACOM_13HD, - WACOM_MO, - BAMBOO_PEN, - INTUOSHT, - INTUOSHT2, - BAMBOO_TOUCH, - BAMBOO_PT, - WACOM_24HDT, - WACOM_27QHDT, - BAMBOO_PAD, - WIRELESS, - REMOTE, - TABLETPC, /* add new TPC below */ - TABLETPCE, - TABLETPC2FG, - MTSCREEN, - MTTPC, - MTTPC_B, - HID_GENERIC, - BOOTLOADER, - MAX_TYPE -}; - -struct wacom_features { - const char *name; - int x_max; - int y_max; - int pressure_max; - int distance_max; - int type; - int x_resolution; - int y_resolution; - int numbered_buttons; - int offset_left; - int offset_right; - int offset_top; - int offset_bottom; - int device_type; - int x_phy; - int y_phy; - unsigned unit; - int unitExpo; - int x_fuzz; - int y_fuzz; - int pressure_fuzz; - int distance_fuzz; - int tilt_fuzz; - unsigned quirks; - unsigned touch_max; - int oVid; - int oPid; - int pktlen; - bool check_for_hid_type; - int hid_type; -}; - -struct wacom_shared { - bool stylus_in_proximity; - bool touch_down; - /* for wireless device to access USB interfaces */ - unsigned touch_max; - int type; - struct input_dev *touch_input; - struct hid_device *pen; - struct hid_device *touch; - bool has_mute_touch_switch; - bool is_touch_on; -}; - -struct hid_data { - __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ - __s16 inputmode_index; /* InputMode HID feature index in the report */ - bool sense_state; - bool inrange_state; - bool invert_state; - bool tipswitch; - bool barrelswitch; - bool barrelswitch2; - bool barrelswitch3; - bool serialhi; - bool confidence; - int x; - int y; - int width; - int height; - int id; - int cc_report; - int cc_index; - int cc_value_index; - int last_slot_field; - int num_expected; - int num_received; - int bat_status; - int battery_capacity; - int bat_charging; - int bat_connected; - int ps_connected; - bool pad_input_event_flag; - unsigned short sequence_number; -}; - -struct wacom_remote_data { - struct { - u32 serial; - bool connected; - } remote[WACOM_MAX_REMOTES]; -}; - -struct wacom_wac { - char name[WACOM_NAME_MAX]; - char pen_name[WACOM_NAME_MAX]; - char touch_name[WACOM_NAME_MAX]; - char pad_name[WACOM_NAME_MAX]; - unsigned char data[WACOM_PKGLEN_MAX]; - int tool[2]; - int id[2]; - __u64 serial[2]; - bool probe_complete; - bool reporting_data; - struct wacom_features features; - struct wacom_shared *shared; - struct input_dev *pen_input; - struct input_dev *touch_input; - struct input_dev *pad_input; - struct kfifo_rec_ptr_2 *pen_fifo; - int pid; - int num_contacts_left; - u8 bt_features; - u8 bt_high_speed; - int mode_report; - int mode_value; - struct work_struct intuos_prox_event_worker; - struct hid_data hid_data; - bool has_mute_touch_switch; - bool is_soft_touch_switch; - bool has_mode_change; - bool is_direct_mode; - bool is_invalid_bt_frame; -}; - -#endif diff --git a/4.5/Makefile.in b/4.18/Makefile.in similarity index 100% rename from 4.5/Makefile.in rename to 4.18/Makefile.in diff --git a/4.5/wacom.h b/4.18/wacom.h similarity index 100% rename from 4.5/wacom.h rename to 4.18/wacom.h diff --git a/4.5/wacom_i2c.c b/4.18/wacom_i2c.c similarity index 100% rename from 4.5/wacom_i2c.c rename to 4.18/wacom_i2c.c diff --git a/4.5/wacom_sys.c b/4.18/wacom_sys.c similarity index 100% rename from 4.5/wacom_sys.c rename to 4.18/wacom_sys.c diff --git a/4.5/wacom_w8001.c b/4.18/wacom_w8001.c similarity index 100% rename from 4.5/wacom_w8001.c rename to 4.18/wacom_w8001.c diff --git a/4.5/wacom_wac.c b/4.18/wacom_wac.c similarity index 100% rename from 4.5/wacom_wac.c rename to 4.18/wacom_wac.c diff --git a/4.5/wacom_wac.h b/4.18/wacom_wac.h similarity index 100% rename from 4.5/wacom_wac.h rename to 4.18/wacom_wac.h diff --git a/Makefile.am b/Makefile.am index ef550533..c1cafc66 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS = @WCM_KERNEL_VER@ -DIST_SUBDIRS = 3.17 4.5 +DIST_SUBDIRS = 4.18 EXTRA_DIST = git-version-gen \ inputattach/inputattach.c inputattach/README \ inputattach/serio-ids.h diff --git a/configure.ac b/configure.ac index aefc1b16..63704950 100644 --- a/configure.ac +++ b/configure.ac @@ -117,17 +117,6 @@ package and try again.]) fi WCM_ENV_KERNEL="yes" -dnl Check for RedHat entreprise Linux >= 7.4 -AC_MSG_CHECKING(RHEL7 minor release) -RHEL7_RELEASE=[$(sed -n 's/^\(Red Hat Enterprise\|Scientific\|CentOS\) Linux .*release 7.\([0-9]*\).*$/\2/gp' "/etc/redhat-release" 2> /dev/null | head -n1)] -dnl RHEL7_RELEASE="" -if test "$RHEL7_RELEASE" = ""; then - RHEL7_RELEASE="0" -elif test "$RHEL7_RELEASE" -gt "3"; then - RHEL7_RELEASE="4" -fi -AC_MSG_RESULT([$RHEL7_RELEASE]) - dnl dnl # code taken from https://github.com/zfsonlinux/spl/blob/master/config/spl-build.m4 dnl # licensed under GPL-v2.0 @@ -188,40 +177,6 @@ AC_DEFUN([WACOM_LINUX_TRY_COMPILE], [$3], [$4]) ]) -dnl -dnl # end of copy from ZFS/spl -dnl - -dnl RedHat entreprise Linux 7.5 backports powersupply functions from 4.1 -AC_MSG_CHECKING(power supply version) -WACOM_LINUX_TRY_COMPILE([ -#include -],[ -struct power_supply_desc test; -],[ - HAVE_POWERSUPPLY_41=yes - AC_MSG_RESULT([v4.1+]) - AC_DEFINE([WACOM_POWERSUPPLY_41], [], [kernel uses powersupply from v4.1+]) -],[ - HAVE_POWERSUPPLY_41=no - AC_MSG_RESULT([pre-v4.1]) -]) - -dnl RedHat enterprise Linux 7.9 backports devm functions from 4.6 -AC_MSG_CHECKING(devm_add_action_or_reset) -WACOM_LINUX_TRY_COMPILE([ -#include -int devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data) { return 0; } -],[ -],[ - HAVE_DEVM_ADD_OR_RESET=no - AC_MSG_RESULT([no]) -],[ - HAVE_DEVM_ADD_OR_RESET=yes - AC_MSG_RESULT([yes]) - AC_DEFINE([WACOM_DEVM_OR_RESET], [], [kernel defines devm_add_action_or_reset from v4.6+]) -]) - dnl Check which API is available for determining bus type AC_MSG_CHECKING(hid_is_using_ll_driver) WACOM_LINUX_TRY_COMPILE([ @@ -290,19 +245,12 @@ bool input_set_timestamp(struct input_dev *dev, ktime_t timestamp) { return true dnl Check which version of the driver we should compile AC_DEFUN([WCM_EXPLODE], [$(echo "$1" | awk '{split($[0],x,"[[^0-9]]"); printf("%03d%03d%03d\n",x[[1]],x[[2]],x[[3]]);}')]) EXPLODED_VER="WCM_EXPLODE($MODUTS)" -if test "$EXPLODED_VER" -lt "WCM_EXPLODE(3.17)"; then - AC_MSG_ERROR(m4_normalize([Kernels older than 3.17 are no longer supported by input-wacom. +if test "$EXPLODED_VER" -lt "WCM_EXPLODE(4.18)"; then + AC_MSG_ERROR(m4_normalize([Kernels older than 4.18 are no longer supported by input-wacom. For newer Wacom models, please upgrade your system to a newer kernel. - For old Wacom models, 'input-wacom-1.0.0' may still support the device])) -elif test "$EXPLODED_VER" -lt "WCM_EXPLODE(4.5)"; then - WCM_KERNEL_VER="3.17" + For old Wacom models, 'input-wacom-1.2.0' may still support the device])) else - WCM_KERNEL_VER="4.5" -fi - -dnl Build both legacy and hid versions -if test "$RHEL7_RELEASE" -ge "4"; then - WCM_KERNEL_VER+=" 3.17" + WCM_KERNEL_VER="4.18" fi dnl ======================================================= @@ -451,16 +399,13 @@ echo WCM_SRC_SUBDIRS=". $WCM_KERNEL_VER" AC_SUBST(WCM_KERNEL_DIR) AC_SUBST(WCM_KERNEL_VER) -AC_SUBST(RHEL6_RELEASE) -AC_SUBST(RHEL7_RELEASE) AC_SUBST(MODUTS) AC_SUBST(MODSIGN_HASHALGO) AC_SUBST(MODSIGN_PRIVFILE) AC_SUBST(MODSIGN_CERTFILE) AC_CONFIG_FILES([Makefile - 3.17/Makefile - 4.5/Makefile]) + 4.18/Makefile]) AC_OUTPUT AC_MSG_NOTICE([ From ce3eb879f291062fe61e6b827e24dd87a3bb08d1 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 26 Jun 2024 18:19:22 -0700 Subject: [PATCH 3/4] Clean up source code for 4.18+ Remove code specific to kernels older than 4.18. Signed-off-by: Ping Cheng --- 4.18/wacom.h | 6 ----- 4.18/wacom_sys.c | 58 +----------------------------------------------- 4.18/wacom_wac.c | 18 ++------------- 3 files changed, 3 insertions(+), 79 deletions(-) diff --git a/4.18/wacom.h b/4.18/wacom.h index ce31055d..792bec17 100644 --- a/4.18/wacom.h +++ b/4.18/wacom.h @@ -166,9 +166,7 @@ struct wacom_remote { struct input_dev *input; bool registered; struct wacom_battery battery; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) ktime_t active_time; -#endif } remotes[WACOM_MAX_REMOTES]; }; @@ -258,9 +256,5 @@ struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group, struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur); int wacom_equivalent_usage(int usage); int wacom_initialize_leds(struct wacom *wacom); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) void wacom_idleprox_timeout(struct timer_list *list); -#else -void wacom_idleprox_timeout(unsigned long data); -#endif #endif diff --git a/4.18/wacom_sys.c b/4.18/wacom_sys.c index 5f9ce313..25c6d354 100644 --- a/4.18/wacom_sys.c +++ b/4.18/wacom_sys.c @@ -18,40 +18,6 @@ #define wacom_is_using_usb_driver(hdev) hid_is_usb(hdev) #elif defined WACOM_USING_LL_DRIVER #define wacom_is_using_usb_driver(hdev) hid_is_using_ll_driver(hdev, &usb_hid_driver) -#else -static int __wacom_is_usb_parent(struct usb_device *usbdev, void *ptr) -{ - struct hid_device *hdev = ptr; - struct device *parent = hdev->dev.parent; - struct usb_host_config *config = usbdev->actconfig; - int i; - - for (i = 0; config && i < config->desc.bNumInterfaces; i++) { - if (&config->interface[i]->dev == parent) - return 1; - } - return 0; -} - -static bool wacom_is_using_usb_driver(struct hid_device *hdev) -{ - return hdev->bus == BUS_USB && - usb_for_each_dev(hdev, __wacom_is_usb_parent); -} -#endif - -#ifndef WACOM_DEVM_OR_RESET -static int devm_add_action_or_reset(struct device *dev, - void (*action)(void *), void *data) -{ - int ret; - - ret = devm_add_action(dev, action, data); - if (ret) - action(data); - - return ret; -} #endif static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf, @@ -1444,9 +1410,7 @@ static int wacom_led_register_one(struct device *dev, struct wacom *wacom, led->hlv = wacom->led.hlv; led->cdev.name = name; led->cdev.max_brightness = LED_FULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0) led->cdev.flags = LED_HW_PLUGGABLE; -#endif led->cdev.brightness_get = __wacom_led_brightness_get; if (!read_only) { led->cdev.brightness_set_blocking = wacom_led_brightness_set; @@ -2615,7 +2579,6 @@ static void wacom_wireless_work(struct work_struct *work) return; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) static void wacom_remote_destroy_battery(struct wacom *wacom, int index) { struct wacom_remote *remote = wacom->remote; @@ -2627,7 +2590,6 @@ static void wacom_remote_destroy_battery(struct wacom *wacom, int index) remote->remotes[index].active_time = 0; } } -#endif static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index) { @@ -2643,13 +2605,7 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index) remote->remotes[i].registered = false; spin_unlock_irqrestore(&remote->remote_lock, flags); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) wacom_remote_destroy_battery(wacom, i); -#else - if (remote->remotes[i].battery.battery) - devres_release_group(&wacom->hdev->dev, - &remote->remotes[i].battery.bat_desc); -#endif if (remote->remotes[i].group.name) devres_release_group(&wacom->hdev->dev, @@ -2657,9 +2613,7 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index) remote->remotes[i].serial = 0; remote->remotes[i].group.name = NULL; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) - remote->remotes[i].battery.battery = NULL; -#endif + wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN; } } @@ -2744,10 +2698,8 @@ static int wacom_remote_attach_battery(struct wacom *wacom, int index) if (remote->remotes[index].battery.battery) return 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) if (!remote->remotes[index].active_time) return 0; -#endif if (wacom->led.groups[index].select == WACOM_STATUS_UNKNOWN) return 0; @@ -2764,9 +2716,7 @@ static void wacom_remote_work(struct work_struct *work) { struct wacom *wacom = container_of(work, struct wacom, remote_work); struct wacom_remote *remote = wacom->remote; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) ktime_t kt = ktime_get(); -#endif struct wacom_remote_work_data remote_work_data; unsigned long flags; unsigned int count; @@ -2794,11 +2744,9 @@ static void wacom_remote_work(struct work_struct *work) work_serial = remote_work_data.remote[i].serial; if (work_serial) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) if (kt - remote->remotes[i].active_time > WACOM_REMOTE_BATTERY_TIMEOUT && remote->remotes[i].active_time != 0) wacom_remote_destroy_battery(wacom, i); -#endif if (remote->remotes[i].serial == work_serial) { wacom_remote_attach_battery(wacom, i); @@ -2908,11 +2856,7 @@ static int wacom_probe(struct hid_device *hdev, INIT_WORK(&wacom->battery_work, wacom_battery_work); INIT_WORK(&wacom->remote_work, wacom_remote_work); INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) timer_setup(&wacom->idleprox_timer, &wacom_idleprox_timeout, TIMER_DEFERRABLE); -#else - setup_timer(&wacom->idleprox_timer, &wacom_idleprox_timeout, (unsigned long) wacom); -#endif /* ask for the report descriptor to be loaded by HID */ error = hid_parse(hdev); diff --git a/4.18/wacom_wac.c b/4.18/wacom_wac.c index 47978073..2416452d 100644 --- a/4.18/wacom_wac.c +++ b/4.18/wacom_wac.c @@ -65,15 +65,9 @@ static void wacom_force_proxout(struct wacom_wac *wacom_wac) input_sync(input); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) void wacom_idleprox_timeout(struct timer_list *list) { - struct wacom *wacom = from_timer(wacom, list, idleprox_timer); -#else -void wacom_idleprox_timeout(unsigned long data) -{ - struct wacom *wacom = (struct wacom *)data; -#endif + struct wacom *wacom = from_timer(wacom, list, idleprox_timer); struct wacom_wac *wacom_wac = &wacom->wacom_wac; if (!wacom_wac->hid_data.sense_state) { @@ -1144,9 +1138,7 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len) if (index < 0 || !remote->remotes[index].registered) goto out; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) remote->remotes[i].active_time = ktime_get(); -#endif input = remote->remotes[index].input; input_report_key(input, BTN_0, (data[9] & 0x01)); @@ -1948,14 +1940,8 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage, int resolution_code = code; int resolution = hidinput_calc_abs_res(field, resolution_code); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) - if (equivalent_usage == HID_DG_TWIST) { -#else - if (equivalent_usage == HID_DG_TWIST || - equivalent_usage == WACOM_HID_WD_TOUCHRING) { -#endif + if (equivalent_usage == HID_DG_TWIST) resolution_code = ABS_RZ; - } if (equivalent_usage == HID_GD_X) { fmin += features->offset_left; From bdf6a034f768415ce381d5f715fa5b7aa1b26fae Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 26 Jun 2024 17:28:35 -0700 Subject: [PATCH 4/4] Update workflow kernel versions Remove kernels older than 4.18 and add newer ones Signed-off-by: Ping Cheng --- .github/workflows/checkpatch.yml | 3 +-- .github/workflows/main.yml | 34 +++++++------------------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml index c9451d70..e7a34d6a 100644 --- a/.github/workflows/checkpatch.yml +++ b/.github/workflows/checkpatch.yml @@ -1,8 +1,7 @@ on: pull_request: paths: - - '3.17/**' - - '4.5/**' + - '4.18/**' permissions: contents: read diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1f67f57..81278458 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,38 +12,18 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - kernel: ["6.3", "5.10", "4.19", "4.14", "4.10", "4.6", "4.5", "4.2", "4.1", "3.19", "3.18", "3.17"] + kernel: ["6.3", "5.15", "5.10", "5.4", "5.0", "4.19"] include: - - kernel: "3.17" - compile_cflags: -fno-pie -Wno-error=format-truncation - prepare_cflags: -fno-pie -no-pie - - kernel: "3.18" - compile_cflags: -fno-pie -Wno-error=format-truncation - prepare_cflags: -fno-pie -no-pie - - kernel: "3.19" - compile_cflags: -fno-pie -Wno-error=format-truncation - prepare_cflags: -fno-pie -no-pie - - kernel: "4.1" - compile_cflags: -fno-pie -Wno-error=format-truncation - prepare_cflags: -fno-pie -no-pie - - kernel: "4.2" - compile_cflags: -fno-pie -Wno-error=format-truncation - prepare_cflags: -fno-pie -no-pie - - kernel: "4.5" - compile_cflags: -fno-pie -Wno-error=format-truncation -Wno-error=pointer-sign - prepare_cflags: -fno-pie -no-pie - - kernel: "4.6" - compile_cflags: -fno-pie -Wno-error=format-truncation -Wno-error=pointer-sign - prepare_cflags: -fno-pie -no-pie - - kernel: "4.10" - compile_cflags: -fno-pie -Wno-error=format-truncation -Wno-error=pointer-sign - prepare_cflags: -fno-pie -no-pie - - kernel: "4.14" - compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign - kernel: "4.19" compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign + - kernel: "5.0" + compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign + - kernel: "5.4" + compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign - kernel: "5.10" compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign + - kernel: "5.15" + compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign - kernel: "6.3" compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign build_makeflags: KBUILD_MODPOST_WARN=1