From 487f619a81f1a24e183c2be3ffa1e27781b3df24 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 16 Aug 2023 14:47:08 -0700 Subject: [PATCH 1/6] Remove 3.7 branch With this patch, the following distros will not be supported: Distro Kernel EOL Debian 8 3.16 2020-07-01 RHEL 7.3- 3.7 2017-07-31 (Kernel changed to 3.17) SuSE Linux Enterprise 12 SP1 3.12 2019-11-13 Ubuntu 14.04.4 3.16 2019-03-06 This patch also removed those old kernels in .github/workflows/main.yml. Signed-off-by: Ping Cheng --- .github/workflows/main.yml | 5 +- 3.7/Makefile.in | 97 - 3.7/wacom.h | 209 -- 3.7/wacom_sys.c | 2168 -------------------- 3.7/wacom_w8001.c | 709 ------- 3.7/wacom_wac.c | 3896 ------------------------------------ 3.7/wacom_wac.h | 229 --- Makefile.am | 2 +- configure.ac | 9 +- 9 files changed, 5 insertions(+), 7319 deletions(-) delete mode 100644 3.7/Makefile.in delete mode 100644 3.7/wacom.h delete mode 100644 3.7/wacom_sys.c delete mode 100644 3.7/wacom_w8001.c delete mode 100644 3.7/wacom_wac.c delete mode 100644 3.7/wacom_wac.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b79cc311..c7d33633 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,11 +9,8 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - kernel: ["6.3", "5.10", "4.14", "4.6", "4.5", "4.1", "3.19", "3.18", "3.17", "3.7"] + kernel: ["6.3", "5.10", "4.14", "4.6", "4.5", "4.1", "3.19", "3.18", "3.17"] include: - - kernel: "3.7" - compile_cflags: -fno-pie -Wno-error=pointer-sign - prepare_cflags: -fno-pie -no-pie - kernel: "3.17" compile_cflags: -fno-pie -Wno-error=format-truncation prepare_cflags: -fno-pie -no-pie diff --git a/3.7/Makefile.in b/3.7/Makefile.in deleted file mode 100644 index 5e56a0fa..00000000 --- a/3.7/Makefile.in +++ /dev/null @@ -1,97 +0,0 @@ -RHEL7_RELEASE := @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_USB_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) -wacom-objs := wacom_wac.o wacom_sys.o -obj-m += wacom.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_USB_WACOM - -LINUXINCLUDE := $(subst -I, -isystem, $(LINUXINCLUDE)) - -else # We were called from command line -PWD := $(shell pwd) -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_VERSION_VER) kernel.' - $(MAKE) -C $(WCM_KERNEL_DIR) M=$(PWD) $(EXTRA_MAKEFLAGS) - -clean: - $(MAKE) -C $(WCM_KERNEL_DIR) M=$(PWD) clean - -signature: all - $(MODSIGN_COMMAND) wacom.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 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 wacom.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 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.7/wacom.h b/3.7/wacom.h deleted file mode 100644 index 3aefca4f..00000000 --- a/3.7/wacom.h +++ /dev/null @@ -1,209 +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 - * - * 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) - */ - -#ifndef WACOM_H -#define WACOM_H - -#include "../config.h" -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#ifndef WACOM_VERSION_SUFFIX -#define WACOM_VERSION_SUFFIX "" -#endif -#define DRIVER_VERSION "v1.53"WACOM_VERSION_SUFFIX -#define DRIVER_AUTHOR "Vojtech Pavlik " -#define DRIVER_DESC "USB Wacom tablet driver" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -#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 - -enum wacom_worker { - WACOM_WORKER_WIRELESS, - WACOM_WORKER_BATTERY, - WACOM_WORKER_REMOTE, -}; - -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 { - dma_addr_t data_dma; - struct usb_device *usbdev; - struct usb_interface *intf; - struct urb *irq; - struct wacom_wac wacom_wac; - struct mutex lock; - struct work_struct wireless_work; - struct work_struct battery_work; - struct work_struct remote_work; - struct wacom_remote *remote; - bool open; - char phys[32]; - struct wacom_led { - u8 select[5]; /* status led selector (0..3) */ - 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; -}; - -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; - } -} - -extern const struct usb_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_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac); -void wacom_battery_work(struct work_struct *work); -#endif diff --git a/3.7/wacom_sys.c b/3.7/wacom_sys.c deleted file mode 100644 index 065d7c9b..00000000 --- a/3.7/wacom_sys.c +++ /dev/null @@ -1,2168 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * USB Wacom tablet support - system specific code - */ - -#include -#include "wacom_wac.h" -#include "wacom.h" - -/* defines to get HID report descriptor */ -#define HID_DEVICET_HID (USB_TYPE_CLASS | 0x01) -#define HID_DEVICET_REPORT (USB_TYPE_CLASS | 0x02) -#define HID_USAGE_UNDEFINED 0x00 -#define HID_USAGE_PAGE 0x04 -#define HID_USAGE_PAGE_DIGITIZER 0x0d -#define HID_USAGE_PAGE_DESKTOP 0x01 -#define HID_USAGE_PAGE_WACOMTOUCH 0xff00 -#define HID_USAGE 0x08 -#define HID_USAGE_X ((HID_USAGE_PAGE_DESKTOP << 16) | 0x30) -#define HID_USAGE_Y ((HID_USAGE_PAGE_DESKTOP << 16) | 0x31) -#define HID_USAGE_PRESSURE ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x30) -#define HID_USAGE_X_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3d) -#define HID_USAGE_Y_TILT ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x3e) -#define HID_USAGE_FINGER ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x22) -#define HID_USAGE_STYLUS ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x20) -#define HID_USAGE_WT_X ((HID_USAGE_PAGE_WACOMTOUCH << 16) | 0x130) -#define HID_USAGE_WT_Y ((HID_USAGE_PAGE_WACOMTOUCH << 16) | 0x131) -#define HID_USAGE_WT_FINGER ((HID_USAGE_PAGE_WACOMTOUCH << 16) | 0x22) -#define HID_USAGE_WT_STYLUS ((HID_USAGE_PAGE_WACOMTOUCH << 16) | 0x20) -#define HID_USAGE_CONTACTMAX ((HID_USAGE_PAGE_DIGITIZER << 16) | 0x55) -#define HID_COLLECTION 0xa0 -#define HID_COLLECTION_LOGICAL 0x02 -#define HID_COLLECTION_END 0xc0 -#define HID_LONGITEM 0xfc - -struct hid_descriptor { - struct usb_descriptor_header header; - __le16 bcdHID; - u8 bCountryCode; - u8 bNumDescriptors; - u8 bDescriptorType; - __le16 wDescriptorLength; -} __attribute__ ((packed)); - -/* defines to get/set USB message */ -#define USB_REQ_GET_REPORT 0x01 -#define USB_REQ_SET_REPORT 0x09 - -#define WAC_HID_FEATURE_REPORT 0x03 -#define WAC_MSG_RETRIES 5 -#define WAC_HID_OUTPUT_REPORT 1 - -#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_RETRIES 10 -#define WAC_CMD_DELETE_PAIRING 0x20 -#define WAC_CMD_UNPAIR_ALL 0xFF -#define WAC_REMOTE_SERIAL_MAX_STRLEN 9 - -#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) - -static int wacom_get_report(struct usb_interface *intf, u8 type, u8 id, - void *buf, size_t size, unsigned int retries) -{ - struct usb_device *dev = interface_to_usbdev(intf); - int retval; - - do { - retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_REPORT, - USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE, - (type << 8) + id, - intf->altsetting[0].desc.bInterfaceNumber, - buf, size, 100); - } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); - - if (retval < 0) - dev_err(&intf->dev, "%s - ran out of retries (last error = %d)\n", - __func__, retval); - return retval; -} - -static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id, - void *buf, size_t size, unsigned int retries) -{ - struct usb_device *dev = interface_to_usbdev(intf); - int retval; - - do { - retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (type << 8) + id, - intf->altsetting[0].desc.bInterfaceNumber, - buf, size, 1000); - } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); - - if (retval < 0) - dev_err(&intf->dev, "%s - ran out of retries (last error = %d)\n", - __func__, retval); - return retval; -} - -static void wacom_sys_irq(struct urb *urb) -{ - struct wacom *wacom = urb->context; - struct device *dev = &wacom->intf->dev; - int retval; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dev_dbg(dev, "%s - urb shutting down with status: %d\n", - __func__, urb->status); - return; - default: - dev_dbg(dev, "%s - nonzero urb status received: %d\n", - __func__, urb->status); - goto exit; - } - - wacom_wac_irq(&wacom->wacom_wac, urb->actual_length); - - exit: - usb_mark_last_busy(wacom->usbdev); - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(dev, "%s - usb_submit_urb failed with result %d\n", - __func__, retval); -} - -static int wacom_open(struct input_dev *dev) -{ - struct wacom *wacom = input_get_drvdata(dev); - int retval = 0; - - if (usb_autopm_get_interface(wacom->intf) < 0) - return -EIO; - - mutex_lock(&wacom->lock); - - if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { - retval = -EIO; - goto out; - } - - wacom->open = true; - wacom->intf->needs_remote_wakeup = 1; - -out: - mutex_unlock(&wacom->lock); - usb_autopm_put_interface(wacom->intf); - return retval; -} - -static void wacom_close(struct input_dev *dev) -{ - struct wacom *wacom = input_get_drvdata(dev); - int autopm_error; - - autopm_error = usb_autopm_get_interface(wacom->intf); - - mutex_lock(&wacom->lock); - usb_kill_urb(wacom->irq); - wacom->open = false; - wacom->intf->needs_remote_wakeup = 0; - mutex_unlock(&wacom->lock); - - if (!autopm_error) - usb_autopm_put_interface(wacom->intf); -} - -/* - * Calculate the resolution of the X or Y axis, given appropriate HID data. - * This function is little more than hidinput_calc_abs_res stripped down. - */ -static int wacom_calc_hid_res(int logical_extents, int physical_extents, - unsigned char unit, unsigned char exponent) -{ - int prev, unit_exponent; - - /* Check if the extents are sane */ - if (logical_extents <= 0 || physical_extents <= 0) - return 0; - - /* Get signed value of nybble-sized twos-compliment exponent */ - unit_exponent = exponent; - if (unit_exponent > 7) - unit_exponent -= 16; - - /* Convert physical_extents to millimeters */ - if (unit == 0x11) { /* If centimeters */ - unit_exponent += 1; - } else if (unit == 0x13) { /* If inches */ - prev = physical_extents; - physical_extents *= 254; - if (physical_extents < prev) - return 0; - unit_exponent -= 1; - } else { - return 0; - } - - /* Apply negative unit exponent */ - for (; unit_exponent < 0; unit_exponent++) { - prev = logical_extents; - logical_extents *= 10; - if (logical_extents < prev) - return 0; - } - /* Apply positive unit exponent */ - for (; unit_exponent > 0; unit_exponent--) { - prev = physical_extents; - physical_extents *= 10; - if (physical_extents < prev) - return 0; - } - - /* Calculate resolution */ - return logical_extents / physical_extents; -} - -static void wacom_retrieve_report_data(struct usb_interface *intf, - struct wacom_features *features) -{ - int result = 0; - unsigned char *rep_data; - - rep_data = kmalloc(2, GFP_KERNEL); - if (rep_data) { - - rep_data[0] = 12; - result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT, - rep_data[0], rep_data, 2, - WAC_MSG_RETRIES); - - if (result >= 0 && rep_data[1] > 2) - features->touch_max = rep_data[1]; - - kfree(rep_data); - } -} - -/* - * 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. - * - * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical - * Collection. Instead they define a Logical Collection with a single - * Logical Maximum for both X and Y. - * - * Intuos5 touch interface does not contain useful data. We deal with - * this after returning from this function. - */ -static int wacom_parse_hid(struct usb_interface *intf, - struct hid_descriptor *hid_desc, - struct wacom_features *features) -{ - struct usb_device *dev = interface_to_usbdev(intf); - char limit = 0; - /* result has to be defined as int for some devices */ - int result = 0, touch_max = 0; - int i = 0, page = 0, finger = 0, pen = 0; - unsigned char *report; - - report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL); - if (!report) - return -ENOMEM; - - /* retrive report descriptors */ - do { - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, - USB_RECIP_INTERFACE | USB_DIR_IN, - HID_DEVICET_REPORT << 8, - intf->altsetting[0].desc.bInterfaceNumber, /* interface */ - report, - hid_desc->wDescriptorLength, - 5000); /* 5 secs */ - } while (result < 0 && limit++ < WAC_MSG_RETRIES); - - /* No need to parse the Descriptor. It isn't an error though */ - if (result < 0) - goto out; - - for (i = 0; i < hid_desc->wDescriptorLength; i++) { - int item = report[i] & 0xFC; - int len = report[i] & 0x03; - int data = 0; - - switch (len) { - case 3: - len = 4; - data |= (report[i+4] << 24); - data |= (report[i+3] << 16); - fallthrough; - case 2: - data |= (report[i+2] << 8); - fallthrough; - case 1: - data |= (report[i+1]); - break; - } - - switch (item) { - case HID_USAGE_PAGE: - page = data; - break; - - case HID_USAGE: - if (len < 4) { - data |= (page << 16); - } - - switch (data) { - case HID_USAGE_WT_X: - if (finger) - features->device_type = BTN_TOOL_FINGER; - if (features->type == INTUOSP2 || - features->type == INTUOSP2S) { - features->touch_max = 10; - features->pktlen = WACOM_PKGLEN_INTUOSP2T; - features->unit = report[i+4]; - features->unitExpo = report[i+6]; - features->x_phy = get_unaligned_le16(&report[i + 10]); - features->x_max = get_unaligned_le16(&report[i + 15]); - } - break; - - case HID_USAGE_WT_Y: - if (features->type == INTUOSP2 || - features->type == INTUOSP2S) { - features->y_phy = get_unaligned_le16(&report[i + 4]); - features->y_max = get_unaligned_le16(&report[i + 7]); - } - break; - - case HID_USAGE_X: - if (finger) { - features->device_type = BTN_TOOL_FINGER; - - /* - * Bamboo Pen only descriptor contains touch - * but it should not... - */ - if (features->type != BAMBOO_PT) - /* - * ISDv4 touch devices at least - * supports one touch point - */ - touch_max = 1; - switch (features->type) { - case TABLETPC2FG: - features->pktlen = WACOM_PKGLEN_TPC2FG; - break; - - case MTSCREEN: - case WACOM_24HDT: - features->pktlen = WACOM_PKGLEN_MTOUCH; - break; - - case DTH1152T: - case WACOM_27QHDT: - features->pktlen = WACOM_PKGLEN_27QHDT; - break; - - case MTTPC: - case MTTPC_B: - case MTTPC_C: - features->pktlen = WACOM_PKGLEN_MTTPC; - break; - - case BAMBOO_PT: - features->pktlen = WACOM_PKGLEN_BBTOUCH; - break; - - case WACOM_MSPROT: - case DTH2452T: - features->pktlen = WACOM_PKGLEN_MSPROT; - break; - - default: - features->pktlen = WACOM_PKGLEN_GRAPHIRE; - break; - } - - switch (features->type) { - case BAMBOO_PT: - features->x_phy = - get_unaligned_le16(&report[i + 5]); - features->x_max = - get_unaligned_le16(&report[i + 8]); - break; - - case DTH1152T: - case WACOM_24HDT: - features->x_max = - get_unaligned_le16(&report[i + 3]); - features->x_phy = - get_unaligned_le16(&report[i + 8]); - features->unit = report[i - 1]; - features->unitExpo = report[i - 3]; - break; - - case WACOM_27QHDT: - if (!features->x_max) { - features->x_max = - get_unaligned_le16(&report[i - 4]); - features->x_phy = - get_unaligned_le16(&report[i - 7]); - features->unit = report[i - 13]; - features->unitExpo = report[i - 11]; - } - break; - - case WACOM_MSPROT: - case MTTPC_B: - case DTH2452T: - features->x_max = - get_unaligned_le16(&report[i + 3]); - features->x_phy = - get_unaligned_le16(&report[i + 6]); - features->unit = report[i - 5]; - features->unitExpo = report[i - 3]; - break; - - case MTTPC_C: - features->x_max = - get_unaligned_le16(&report[i + 3]); - features->x_phy = - get_unaligned_le16(&report[i + 8]); - features->unit = report[i - 1]; - features->unitExpo = report[i - 3]; - break; - - default: - features->x_max = - get_unaligned_le16(&report[i + 3]); - features->x_phy = - get_unaligned_le16(&report[i + 6]); - features->unit = report[i + 9]; - features->unitExpo = report[i + 11]; - break; - } - } else if (pen) { - /* penabled only accepts exact bytes of data */ - if (features->type >= TABLETPC) - features->pktlen = WACOM_PKGLEN_GRAPHIRE; - features->device_type = BTN_TOOL_PEN; - features->x_max = - get_unaligned_le16(&report[i + 3]); - } - break; - - case HID_USAGE_Y: - if (finger) { - switch (features->type) { - case TABLETPC2FG: - case MTSCREEN: - case MTTPC: - features->y_max = - get_unaligned_le16(&report[i + 3]); - features->y_phy = - get_unaligned_le16(&report[i + 6]); - break; - - case DTH1152T: - case WACOM_24HDT: - case MTTPC_C: - features->y_max = - get_unaligned_le16(&report[i + 3]); - features->y_phy = - get_unaligned_le16(&report[i - 2]); - break; - - case WACOM_27QHDT: - if (!features->y_max) { - features->y_max = - get_unaligned_le16(&report[i - 2]); - features->y_phy = - get_unaligned_le16(&report[i - 5]); - } - break; - - case BAMBOO_PT: - features->y_phy = - get_unaligned_le16(&report[i + 3]); - features->y_max = - get_unaligned_le16(&report[i + 6]); - break; - - case WACOM_MSPROT: - case MTTPC_B: - case DTH2452T: - features->y_max = - get_unaligned_le16(&report[i + 3]); - features->y_phy = - get_unaligned_le16(&report[i + 6]); - break; - - default: - features->y_max = - features->x_max; - features->y_phy = - get_unaligned_le16(&report[i + 3]); - break; - } - } else if (pen) { - features->y_max = - get_unaligned_le16(&report[i + 3]); - } - break; - - case HID_USAGE_WT_FINGER: - case HID_USAGE_FINGER: - finger = 1; - break; - - /* - * Requiring Stylus Usage will ignore boot mouse - * X/Y values and some cases of invalid Digitizer X/Y - * values commonly reported. - */ - case HID_USAGE_WT_STYLUS: - case HID_USAGE_STYLUS: - pen = 1; - break; - - case HID_USAGE_CONTACTMAX: - /* leave touch_max as is if predefined */ - if (!features->touch_max) - wacom_retrieve_report_data(intf, features); - break; - - case HID_USAGE_PRESSURE: - if (pen) { - features->pressure_max = - get_unaligned_le16(&report[i + 3]); - } - break; - } - break; - - case HID_COLLECTION_END: - /* reset UsagePage and Finger */ - finger = page = 0; - break; - - case HID_COLLECTION: - switch (report[i]) { - case HID_COLLECTION_LOGICAL: - if (features->type == BAMBOO_PT) { - features->pktlen = WACOM_PKGLEN_BBTOUCH3; - features->device_type = BTN_TOOL_FINGER; - - features->x_max = features->y_max = - get_unaligned_le16(&report[10]); - } - break; - } - break; - - case HID_LONGITEM: - /* - * HID "Long Items" can contain up to 255 bytes - * of data. We don't use long items, so just - * update the length to skip over it entirely. - */ - len += data & 0x00FF; - break; - } - - i += len; - } - - out: - if (!features->touch_max && touch_max) - features->touch_max = touch_max; - result = 0; - kfree(report); - return result; -} - -static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int length, int mode) -{ - unsigned char *rep_data; - int error = -ENOMEM, limit = 0; - - rep_data = kzalloc(length, GFP_KERNEL); - if (!rep_data) - return error; - - do { - rep_data[0] = report_id; - rep_data[1] = mode; - - error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT, - report_id, rep_data, length, 1); - } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); - - kfree(rep_data); - - return error < 0 ? error : 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 usb_interface *intf, struct wacom_features *features) -{ - if (features->device_type == BTN_TOOL_FINGER) { - if (features->type > TABLETPC) { - /* MT Tablet PC touch */ - return wacom_set_device_mode(intf, 3, 4, 4); - } - else if (features->type == WACOM_24HDT) { - return wacom_set_device_mode(intf, 18, 3, 2); - } - else if (features->type == WACOM_27QHDT) { - return wacom_set_device_mode(intf, 131, 3, 2); - } - else if (features->type == WACOM_MSPROT || - features->type == DTH1152T) { - return wacom_set_device_mode(intf, 14, 2, 2); - } - } else if (features->device_type == BTN_TOOL_PEN) { - if (features->type <= BAMBOO_PT) { - return wacom_set_device_mode(intf, 2, 2, 2); - } - } - - return 0; -} - -static int wacom_retrieve_hid_descriptor(struct usb_interface *intf, - struct wacom_features *features) -{ - int error = 0; - struct usb_host_interface *interface = intf->cur_altsetting; - struct hid_descriptor *hid_desc; - - /* default features */ - features->device_type = BTN_TOOL_PEN; - 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) { - if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { - features->device_type = 0; - } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) { - features->device_type = BTN_TOOL_FINGER; - features->pktlen = WACOM_PKGLEN_BBTOUCH3; - } - } - - /* only devices that support touch need to retrieve the info */ - if (features->type < BAMBOO_PT) { - goto out; - } - - error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc); - if (error) { - error = usb_get_extra_descriptor(&interface->endpoint[0], - HID_DEVICET_REPORT, &hid_desc); - if (error) { - dev_err(&intf->dev, - "can not retrieve extra class descriptor\n"); - goto out; - } - } - error = wacom_parse_hid(intf, hid_desc, features); - - out: - return error; -} - -struct wacom_usbdev_data { - struct list_head list; - struct kref kref; - struct usb_device *dev; - struct wacom_shared shared; -}; - -static LIST_HEAD(wacom_udev_list); -static DEFINE_MUTEX(wacom_udev_list_lock); - -static struct usb_device *wacom_get_sibling(struct usb_device *dev, int vendor, int product) -{ - int port1; - struct usb_device *sibling; - - if (vendor == 0 && product == 0) - return dev; - - if (dev->parent == NULL) - return NULL; - - usb_hub_for_each_child(dev->parent, port1, sibling) { - struct usb_device_descriptor *d; - if (sibling == NULL) - continue; - - d = &sibling->descriptor; - if (d->idVendor == vendor && d->idProduct == product) - return sibling; - } - - return NULL; -} - -static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev) -{ - struct wacom_usbdev_data *data; - - list_for_each_entry(data, &wacom_udev_list, list) { - if (data->dev == dev) { - kref_get(&data->kref); - return data; - } - } - - return NULL; -} - -static void wacom_release_shared_data(struct kref *kref) -{ - struct wacom_usbdev_data *data = - container_of(kref, struct wacom_usbdev_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(struct wacom_wac *wacom) -{ - struct wacom_usbdev_data *data; - - if (wacom->shared) { - data = container_of(wacom->shared, struct wacom_usbdev_data, shared); - kref_put(&data->kref, wacom_release_shared_data); - wacom->shared = NULL; - } -} - -static int wacom_add_shared_data(struct wacom_wac *wacom, - struct usb_device *dev) -{ - struct wacom_usbdev_data *data; - int retval = 0; - - mutex_lock(&wacom_udev_list_lock); - - data = wacom_get_usbdev_data(dev); - if (!data) { - data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL); - if (!data) { - retval = -ENOMEM; - goto out; - } - - kref_init(&data->kref); - data->dev = dev; - list_add_tail(&data->list, &wacom_udev_list); - } - - wacom->shared = &data->shared; - -out: - mutex_unlock(&wacom_udev_list_lock); - 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->wacom_wac.pid) { /* wireless connected */ - report_id = WAC_CMD_WL_LED_CONTROL; - buf_size = 13; - } - buf = kzalloc(buf_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (wacom->wacom_wac.features.type == INTUOSP2) { - - buf[0] = WAC_CMD_LED_CONTROL_GENERIC; - buf[1] = wacom->led.llv; - buf[2] = wacom->led.select[0] & 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.select[0] & 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->intf, WAC_HID_FEATURE_REPORT, - buf[0], buf, buf_size, WAC_CMD_RETRIES); - buf[0] = report_id; - buf[4] = led_bits; - } else - buf[1] = led_bits; - } - else { - int led = wacom->led.select[0] | 0x4; - - if (wacom->wacom_wac.features.type == WACOM_21UX2 || - wacom->wacom_wac.features.type == WACOM_24HD) - led |= (wacom->led.select[1] << 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->intf, 0x03, report_id, - buf, buf_size, WAC_CMD_RETRIES); - kfree(buf); - - return retval; -} - -static int wacom_led_putimage(struct wacom *wacom, int button_id, const void *img) -{ - unsigned char *buf; - int i, retval; - - buf = kzalloc(259, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Send 'start' command */ - buf[0] = WAC_CMD_ICON_START; - buf[1] = 1; - retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, - buf, 2, WAC_CMD_RETRIES); - if (retval < 0) - goto out; - - buf[0] = WAC_CMD_ICON_XFER; - buf[1] = button_id & 0x07; - for (i = 0; i < 4; i++) { - buf[2] = i; - memcpy(buf + 3, img + i * 256, 256); - - retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_XFER, - buf, 259, WAC_CMD_RETRIES); - if (retval < 0) - break; - } - - /* Send 'stop' */ - buf[0] = WAC_CMD_ICON_START; - buf[1] = 0; - wacom_set_report(wacom->intf, 0x03, WAC_CMD_ICON_START, - 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 wacom *wacom = dev_get_drvdata(dev); - unsigned int id; - int err; - - err = kstrtouint(buf, 10, &id); - if (err) - return err; - - mutex_lock(&wacom->lock); - - wacom->led.select[set_id] = 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 wacom *wacom = dev_get_drvdata(dev); \ - return snprintf(buf, PAGE_SIZE, "%d\n", \ - wacom->led.select[SET_ID]); \ -} \ -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 wacom *wacom = dev_get_drvdata(dev); \ - \ - 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 wacom *wacom = dev_get_drvdata(dev); - int err; - - if (count != 1024) - return -EINVAL; - - mutex_lock(&wacom->lock); - - err = wacom_led_putimage(wacom, button_id, 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, -}; - -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->intf->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->intf->dev.kobj, - group); -} - -static int wacom_initialize_leds(struct wacom *wacom) -{ - int error; - - if (wacom->wacom_wac.features.device_type != BTN_TOOL_PEN) - return 0; - - /* Initialize default values */ - switch (wacom->wacom_wac.features.type) { - case INTUOS4S: - case INTUOS4: - case INTUOS4L: - wacom->led.select[0] = 0; - wacom->led.select[1] = 0; - wacom->led.llv = 10; - wacom->led.hlv = 20; - wacom->led.img_lum = 10; - - error = wacom_devm_sysfs_create_group(wacom, - &intuos4_led_attr_group); - break; - - case WACOM_24HD: - case WACOM_21UX2: - wacom->led.select[0] = 0; - wacom->led.select[1] = 0; - wacom->led.llv = 0; - wacom->led.hlv = 0; - wacom->led.img_lum = 0; - - error = wacom_devm_sysfs_create_group(wacom, - &cintiq_led_attr_group); - break; - - case INTUOS5S: - case INTUOS5: - case INTUOS5L: - case INTUOSPS: - case INTUOSPM: - case INTUOSPL: - case INTUOSP2: - wacom->led.select[0] = 0; - wacom->led.select[1] = 0; - wacom->led.llv = 32; - wacom->led.hlv = 0; - wacom->led.img_lum = 0; - - error = wacom_devm_sysfs_create_group(wacom, - &intuos5_led_attr_group); - break; - - default: - return 0; - } - - if (error) { - dev_err(&wacom->intf->dev, - "cannot create sysfs group err: %d\n", error); - return error; - } - wacom_led_control(wacom); - - return 0; -} - -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->intf->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->intf->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_0%ld", n); - bat_desc->name = battery->bat_name; - bat_desc->type = POWER_SUPPLY_TYPE_USB; - 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->intf->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->intf->dev, - &wacom->battery.bat_desc); -#else - power_supply_unregister(&wacom->battery.battery); -#endif - WACOM_POWERSUPPLY_DEVICE(wacom->battery.battery) = NULL; - } -} - -static void wacom_destroy_remote_battery(struct wacom_battery *battery) -{ - if (WACOM_POWERSUPPLY_DEVICE(battery->battery)) { - power_supply_unregister(WACOM_POWERSUPPLY_REF(battery->battery)); - WACOM_POWERSUPPLY_DEVICE(battery->battery) = NULL; - } -} - -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 wacom *wacom = dev_get_drvdata(dev); - u8 mode; - - mode = wacom->led.select[index]; - 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 = kasprintf(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; - dev_err(&wacom->intf->dev, - "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->intf, WAC_HID_OUTPUT_REPORT, - WAC_CMD_DELETE_PAIRING, buf, - buf_size, WAC_CMD_RETRIES); - kfree(buf); - - return retval; -} - -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; - - spin_lock_irqsave(&remote->remote_lock, flags); - remote->remotes[index].registered = false; - spin_unlock_irqrestore(&remote->remote_lock, flags); - - if (remote->remotes[index].group.name) - devres_release_group(&wacom->usbdev->dev, - &remote->remotes[index]); - - if (remote->remotes[index].input) - input_unregister_device(remote->remotes[index].input); - - if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[index].battery.battery)) - wacom_destroy_remote_battery(&remote->remotes[index].battery); - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - if (remote->remotes[i].serial == serial) { - remote->remotes[i].serial = 0; - - /* Destroy the attribute group parts not - * covered by devres for this kernel. - */ - kfree((char *)remote->remotes[i].group.name); - remote->remotes[i].group.name = NULL; - remote->remotes[i].registered = false; - WACOM_POWERSUPPLY_DEVICE(remote->remotes[i].battery.battery) = NULL; - wacom->led.select[i] = WACOM_STATUS_UNKNOWN; - } - } -} - -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 wacom *wacom = dev_get_drvdata(dev); - int err; - - if (!strncmp(buf, "*\n", 2)) { - selector = WAC_CMD_UNPAIR_ALL; - } else { - dev_info(&wacom->intf->dev, "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(struct wacom *wacom) -{ - struct wacom_remote *remote = wacom->remote; - int i; - - if (!remote) - return; - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - if (remote->remotes[i].registered) { - wacom_remote_destroy_one(wacom, i); - } - } - 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->usbdev->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) { - dev_err(&wacom->intf->dev, "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->intf->dev.kobj); - - if (!remote->remote_dir) - return -ENOMEM; - - error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs); - - if (error) { - dev_err(&wacom->intf->dev, - "cannot create sysfs group err: %d\n", error); - return error; - } - - for (i = 0; i < WACOM_MAX_REMOTES; i++) { - wacom->led.select[i] = WACOM_STATUS_UNKNOWN; - remote->remotes[i].serial = 0; - } - - return 0; -} - -static void wacom_unregister_inputs(struct wacom *wacom) -{ - if (wacom->wacom_wac.input) - input_unregister_device(wacom->wacom_wac.input); - wacom->wacom_wac.input = NULL; -} - -static int wacom_register_remote_input(struct wacom *wacom, int index) -{ - struct input_dev *input_dev; - struct wacom_remote *remote = wacom->remote; - struct usb_interface *intf = wacom->intf; - struct usb_device *dev = interface_to_usbdev(intf); - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - int error; - - input_dev = input_allocate_device(); - if (!input_dev) { - error = -ENOMEM; - goto fail1; - } - - input_dev->name = wacom_wac->name; - input_dev->dev.parent = &intf->dev; - usb_to_input_id(dev, &input_dev->id); - if (wacom_wac->pid != 0) { - /* copy PID of wireless device */ - input_dev->id.product = wacom_wac->pid; - } - input_set_drvdata(input_dev, wacom); - - remote->remotes[index].input = input_dev; - - return 0; - -fail1: - return error; -} - -static int wacom_register_input(struct wacom *wacom) -{ - struct input_dev *input_dev; - struct usb_interface *intf = wacom->intf; - struct usb_device *dev = interface_to_usbdev(intf); - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - struct wacom_features *features = &wacom_wac->features; - int error; - - if (features->type == REMOTE) - return 0; - - input_dev = input_allocate_device(); - if (!input_dev) { - error = -ENOMEM; - goto fail1; - } - - input_dev->name = wacom_wac->name; - input_dev->dev.parent = &intf->dev; - input_dev->open = wacom_open; - input_dev->close = wacom_close; - usb_to_input_id(dev, &input_dev->id); - if (wacom_wac->pid != 0) { - /* copy PID of wireless device */ - input_dev->id.product = wacom_wac->pid; - } - input_set_drvdata(input_dev, wacom); - - wacom_wac->input = input_dev; - - if (wacom_wac->features.touch_max && wacom_wac->shared) { - if (wacom_wac->features.device_type == BTN_TOOL_FINGER) { - wacom_wac->shared->type = wacom_wac->features.type; - wacom_wac->shared->touch_input = wacom_wac->input; - } - } - - error = wacom_setup_input_capabilities(input_dev, wacom_wac); - if (error) - goto fail1; - - error = input_register_device(input_dev); - if (error) - goto fail2; - - return 0; - -fail2: - if (input_dev) - input_free_device(input_dev); - wacom_wac->input = NULL; -fail1: - return error; -} - -static int wacom_remote_create_one(struct wacom *wacom, u32 serial, - unsigned int index) -{ - struct wacom_remote *remote = wacom->remote; - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct device *dev = &wacom->usbdev->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; - - error = wacom_register_remote_input(wacom, index); - if (error) - goto fail; - - 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_wac->name; - - if (!remote->remotes[index].input->name) { - error = -EINVAL; - goto fail; - } - - error = wacom_setup_input_capabilities(remote->remotes[index].input, - wacom_wac); - if (error) - goto fail; - - remote->remotes[index].serial = serial; - - error = input_register_device(remote->remotes[index].input); - if (error) - goto fail2; - - remote->remotes[index].registered = true; - - devres_close_group(dev, &remote->remotes[index]); - - return 0; -fail2: - if (remote->remotes[index].input) - input_free_device(remote->remotes[index].input); - remote->remotes[index].input = NULL; -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; - - if (!remote->remotes[index].registered) - return 0; - - if (WACOM_POWERSUPPLY_DEVICE(remote->remotes[index].battery.battery)) - return 0; - - return 0; -} - -/* - * 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 = 16-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); -} - -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 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); - - /* Stylus interface */ - wacom1 = usb_get_intfdata(usbdev->config->interface[1]); - wacom_wac1 = &(wacom1->wacom_wac); - wacom_unregister_inputs(wacom1); - - /* Touch interface */ - wacom2 = usb_get_intfdata(usbdev->config->interface[2]); - wacom_wac2 = &(wacom2->wacom_wac); - wacom_unregister_inputs(wacom2); - - if (wacom_wac->pid == 0) { - dev_info(&wacom->intf->dev, "wireless tablet disconnected\n"); - wacom_wac1->shared->type = 0; - } else { - const struct usb_device_id *id = wacom_ids; - - dev_info(&wacom->intf->dev, - "wireless tablet connected with PID %x\n", - wacom_wac->pid); - - while (id->match_flags) { - if (id->idVendor == USB_VENDOR_ID_WACOM && - id->idProduct == wacom_wac->pid) - break; - id++; - } - - if (!id->match_flags) { - dev_info(&wacom->intf->dev, - "ignoring unknown PID.\n"); - return; - } - - /* Stylus interface */ - wacom_wac1->features = - *((struct wacom_features *)id->driver_info); - wacom_wac1->features.device_type = BTN_TOOL_PEN; - snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen", - wacom_wac1->features.name); - wacom_set_default_phy(&wacom_wac1->features); - wacom_calculate_res(&wacom_wac1->features); - wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max; - wacom_wac1->shared->type = wacom_wac1->features.type; - wacom_wac1->pid = wacom_wac->pid; - error = wacom_register_input(wacom1); - 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_info); - wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; - wacom_wac2->features.device_type = BTN_TOOL_FINGER; - wacom_set_default_phy(&wacom_wac1->features); - wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; - wacom_calculate_res(&wacom_wac1->features); - if (wacom_wac1->features.touch_max) - snprintf(wacom_wac2->name, WACOM_NAME_MAX, - "%s (WL) Finger",wacom_wac2->features.name); - else - snprintf(wacom_wac2->name, WACOM_NAME_MAX, - "%s (WL) Pad",wacom_wac2->features.name); - wacom_wac2->pid = wacom_wac->pid; - error = wacom_register_input(wacom2); - if (error) - goto fail; - - if ((wacom_wac1->features.type == INTUOSHT || - wacom_wac1->features.type == INTUOSHT2) && - wacom_wac1->features.touch_max) { - wacom_wac->shared->type = wacom_wac->features.type; - wacom_wac->shared->touch_input = wacom_wac2->input; - } - } - } - - return; - -fail: - wacom_unregister_inputs(wacom1); - wacom_unregister_inputs(wacom2); - return; -} - -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 void wacom_remote_work(struct work_struct *work) -{ - struct wacom *wacom = container_of(work, struct wacom, remote_work); - struct device *dev = &wacom->intf->dev; - 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)) { - dev_err(dev, - "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 int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_endpoint_descriptor *endpoint; - struct wacom *wacom; - struct wacom_wac *wacom_wac; - struct wacom_features *features; - int error; - struct usb_device *other_dev; - - if (!id->driver_info) - return -EINVAL; - - /* Verify that a device really has an endpoint */ - if (intf->cur_altsetting->desc.bNumEndpoints < 1) - return -EINVAL; - - wacom = devm_kzalloc(&dev->dev, sizeof(struct wacom), GFP_KERNEL); - if (!wacom) - return -ENOMEM; - - wacom_wac = &wacom->wacom_wac; - wacom_wac->features = *((struct wacom_features *)id->driver_info); - features = &wacom_wac->features; - if (features->pktlen > WACOM_PKGLEN_MAX) { - error = -EINVAL; - goto fail1; - } - - if ((features->type == WACOM_ONE || features->type == CINTIQ_16) && - intf->cur_altsetting->desc.bInterfaceNumber != 0) { - error = -EINVAL; - goto fail1; - } - - wacom_wac->data = usb_alloc_coherent(dev, WACOM_PKGLEN_MAX, - GFP_KERNEL, &wacom->data_dma); - if (!wacom_wac->data) { - error = -ENOMEM; - goto fail1; - } - - wacom->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!wacom->irq) { - error = -ENOMEM; - goto fail2; - } - - wacom->usbdev = dev; - wacom->intf = intf; - mutex_init(&wacom->lock); - INIT_WORK(&wacom->wireless_work, wacom_wireless_work); - INIT_WORK(&wacom->battery_work, wacom_battery_work); - INIT_WORK(&wacom->remote_work, wacom_remote_work); - - usb_make_path(dev, wacom->phys, sizeof(wacom->phys)); - strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); - - endpoint = &intf->cur_altsetting->endpoint[0].desc; - - /* 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 */ - error = wacom_retrieve_hid_descriptor(intf, features); - if (error) - goto fail3; - - wacom_setup_device_quirks(wacom); - wacom_calculate_res(features); - - strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); - - /* Append the device type to the name */ - if (features->device_type != BTN_TOOL_FINGER) - strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); - else if (features->touch_max) - strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); - else - strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX); - - other_dev = wacom_get_sibling(dev, features->oVid, features->oPid); - if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL) - other_dev = dev; - error = wacom_add_shared_data(wacom_wac, other_dev); - if (error) - goto fail3; - - usb_fill_int_urb(wacom->irq, dev, - usb_rcvintpipe(dev, endpoint->bEndpointAddress), - wacom_wac->data, features->pktlen, - wacom_sys_irq, wacom, endpoint->bInterval); - wacom->irq->transfer_dma = wacom->data_dma; - wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) { - error = wacom_register_input(wacom); - if (error) - goto fail4; - } - - /* Note that if query fails it is not a hard failure */ - wacom_query_tablet_data(intf, features); - - usb_set_intfdata(intf, wacom); - - if (features->quirks & WACOM_QUIRK_MONITOR) { - if (usb_submit_urb(wacom->irq, GFP_KERNEL)) { - error = -EIO; - goto fail4; - } - } - - error = wacom_initialize_leds(wacom); - if (error) - goto fail4; - - if (wacom->wacom_wac.features.type == REMOTE) { - error = wacom_initialize_remotes(wacom); - if (error) - goto fail4; - } - - return 0; - - fail4: wacom_remove_shared_data(wacom_wac); - fail3: usb_free_urb(wacom->irq); - wacom_destroy_battery(wacom); - fail2: usb_free_coherent(dev, WACOM_PKGLEN_MAX, wacom_wac->data, wacom->data_dma); - fail1: - return error; -} - -static void wacom_disconnect(struct usb_interface *intf) -{ - struct wacom *wacom = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - - usb_kill_urb(wacom->irq); - cancel_work_sync(&wacom->wireless_work); - cancel_work_sync(&wacom->battery_work); - cancel_work_sync(&wacom->remote_work); - wacom_remotes_destroy(wacom); - wacom_unregister_inputs(wacom); - wacom_destroy_battery(wacom); - usb_free_urb(wacom->irq); - usb_free_coherent(interface_to_usbdev(intf), WACOM_PKGLEN_MAX, - wacom->wacom_wac.data, wacom->data_dma); - wacom_remove_shared_data(&wacom->wacom_wac); -} - -static int wacom_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct wacom *wacom = usb_get_intfdata(intf); - - mutex_lock(&wacom->lock); - usb_kill_urb(wacom->irq); - mutex_unlock(&wacom->lock); - - return 0; -} - -static int wacom_resume(struct usb_interface *intf) -{ - struct wacom *wacom = usb_get_intfdata(intf); - struct wacom_features *features = &wacom->wacom_wac.features; - int rv = 0; - - mutex_lock(&wacom->lock); - - /* switch to wacom mode first */ - wacom_query_tablet_data(intf, features); - wacom_led_control(wacom); - - if ((wacom->open || (features->quirks & WACOM_QUIRK_MONITOR)) && - usb_submit_urb(wacom->irq, GFP_NOIO) < 0) - rv = -EIO; - - mutex_unlock(&wacom->lock); - - return rv; -} - -static int wacom_reset_resume(struct usb_interface *intf) -{ - return wacom_resume(intf); -} - -static struct usb_driver wacom_driver = { - .name = "wacom", - .id_table = wacom_ids, - .probe = wacom_probe, - .disconnect = wacom_disconnect, - .suspend = wacom_suspend, - .resume = wacom_resume, - .reset_resume = wacom_reset_resume, - .supports_autosuspend = 1, -}; - -module_usb_driver(wacom_driver); - -MODULE_VERSION(DRIVER_VERSION); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/3.7/wacom_w8001.c b/3.7/wacom_w8001.c deleted file mode 100644 index 691285ac..00000000 --- a/3.7/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.7/wacom_wac.c b/3.7/wacom_wac.c deleted file mode 100644 index 2fbc93dc..00000000 --- a/3.7/wacom_wac.c +++ /dev/null @@ -1,3896 +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 SW_MUTE_DEVICE -#define SW_MUTE_DEVICE 0x0e /* set = device disabled */ -#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 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->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->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 (prox) { - wacom->id[0] = ERASER_DEVICE_ID; - 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; - - /* - * if going from out of proximity into proximity select between the eraser - * and the pen based on the state of the stylus2 button, choose eraser if - * pressed else choose pen. if not a proximity change from out to in, send - * an out of proximity for previous tool then a in for new tool. - */ - if (!wacom->tool[0]) { - /* Eraser bit set for DTF */ - if (data[1] & 0x10) - wacom->tool[1] = BTN_TOOL_RUBBER; - else - /* Going into proximity select tool */ - wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - } else { - /* was entered with stylus2 pressed */ - if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { - /* report out proximity for previous tool */ - input_report_key(input, wacom->tool[1], 0); - input_sync(input); - wacom->tool[1] = BTN_TOOL_PEN; - return 0; - } - } - if (wacom->tool[1] != BTN_TOOL_RUBBER) { - /* Unknown tool selected default to pen tool */ - wacom->tool[1] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - } - input_report_key(input, wacom->tool[1], prox); /* report in proximity for tool */ - input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ - 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[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); - } else { - /* report proximity-out of a (valid) tool */ - if (wacom->tool[1] != BTN_TOOL_RUBBER) { - /* Unknown tool selected default to pen tool */ - wacom->tool[1] = BTN_TOOL_PEN; - } - input_report_key(input, wacom->tool[1], prox); - } - - wacom->tool[0] = prox; /* Save proximity state */ - return 1; -} - -static int wacom_ptu_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->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->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->input; - struct wacom_features *features = &wacom->features; - unsigned short prox, pressure = 0; - - if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD - && data[0] != WACOM_REPORT_DTK2451PAD) { - dev_dbg(input->dev.parent, - "%s: received unknown report #%d", __func__, data[0]); - return 0; - } else if (data[0] == WACOM_REPORT_DTUSPAD - || data[0] == WACOM_REPORT_DTK2451PAD) { - 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); - /* - * Serial number is required when expresskeys are - * reported through pen interface. - */ - input_event(input, EV_MSC, MSC_SERIAL, 0xf0); - 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); - if (features->type == DTK2451) { - pressure = get_unaligned_le16(&data[2]); - input_report_abs(input, ABS_X, get_unaligned_le16(&data[4])); - input_report_abs(input, ABS_Y, get_unaligned_le16(&data[6])); - } else { - pressure = ((data[1] & 0x03) << 8) | (data[2] & 0xff); - input_report_abs(input, ABS_X, get_unaligned_be16(&data[3])); - input_report_abs(input, ABS_Y, get_unaligned_be16(&data[5])); - } - 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]); - input_event(input, EV_MSC, MSC_SERIAL, 1); - return 1; - } -} - -static int wacom_dth1152_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; - unsigned short prox, pressure = 0; - - if (data[0] != WACOM_REPORT_DTUS) { - if (data[0] == WACOM_REPORT_DTUSPAD) { - 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); - /* - * Serial number is required when expresskeys are - * reported through pen interface. - */ - input_event(input, EV_MSC, MSC_SERIAL, 0xf0); - return 1; - } - dev_dbg(input->dev.parent, - "%s: received unknown report #%d", __func__, data[0]); - return 0; - } else { - prox = data[1] & 0x80; - if (prox) { - wacom->tool[0] = BTN_TOOL_PEN; - wacom->id[0] = STYLUS_DEVICE_ID; - } - input_report_key(input, BTN_STYLUS, data[1] & 0x20); - input_report_abs(input, ABS_X, get_unaligned_le16(&data[4])); - input_report_abs(input, ABS_Y, get_unaligned_le16(&data[6])); - pressure = data[2] | (data[3] << 8); - input_report_abs(input, ABS_PRESSURE, pressure); - input_report_key(input, BTN_TOUCH, data[1] & 0x10); - - 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_graphire_irq(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; - int prox; - int rw = 0; - int retval = 0; - - 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) { - 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 { - 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_event(input, EV_MSC, MSC_SERIAL, 1); - 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(input, BTN_BACK, (data[7] & 0x40)); - input_report_key(input, BTN_FORWARD, (data[7] & 0x80)); - rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); - input_report_rel(input, REL_WHEEL, rw); - if (!prox) - wacom->id[1] = 0; - input_report_abs(input, ABS_MISC, wacom->id[1]); - input_event(input, EV_MSC, MSC_SERIAL, 0xf0); - 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(input, BTN_BACK, (data[7] & 0x08)); - input_report_key(input, BTN_LEFT, (data[7] & 0x20)); - input_report_key(input, BTN_FORWARD, (data[7] & 0x10)); - input_report_key(input, BTN_RIGHT, (data[7] & 0x40)); - input_report_abs(input, ABS_WHEEL, (data[8] & 0x7f)); - if (!prox) - wacom->id[1] = 0; - input_report_abs(input, ABS_MISC, wacom->id[1]); - input_event(input, EV_MSC, MSC_SERIAL, 0xf0); - retval = 1; - } - break; - } -exit: - return retval; -} - -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->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); - } - } 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 int wacom_intuos_inout(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->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] = ((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; - - /* - * 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; - return 2; - } - - /* don't report other events if we don't know the ID */ - if (!wacom->id[idx]) - return 1; - - return 0; -} - -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->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 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)); - input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f); - } - 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)); - input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f); - 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)); - input_report_abs(input, ABS_TILT_Y, data[8] & 0x7f); - 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->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 wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); - struct wacom_remote *remote = wacom->remote; - struct input_dev *input; - int bat_charging, bat_percent, touch_ring_mode; - __u32 serial; - int i, index = -1; - unsigned long flags; - - if (data[0] != WACOM_REPORT_REMOTE) { - dev_dbg(&wacom->intf->dev, - "%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; - } - } - - input = remote->remotes[index].input; - - if (index < 0 || !remote->remotes[index].registered) - goto out; - - 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.select[i] = 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); - struct device *dev = &wacom->intf->dev; - 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); - dev_err(dev, "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 int wacom_wac_finger_count_touches(struct wacom_wac *wacom) -{ - struct input_dev *input = wacom->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_multitouch_generic_finger(struct wacom_wac *wacom, - int contact_id, bool prox, - int x, int y, int w, int h, - int c_x, int c_y) -{ - struct input_dev *input = wacom->input; - int slot = input_mt_get_slot_by_key(input, contact_id); - - if (wacom->shared->has_mute_touch_switch && - !wacom->shared->is_touch_on) { - if (!wacom->shared->touch_down) - return; - prox = 0; - } - - if (slot < 0) - return; - - prox = prox && report_touch_events(wacom); - - input_mt_slot(input, slot); - input_mt_report_slot_state(input, MT_TOOL_FINGER, prox); - - if (prox) { - input_report_abs(input, ABS_MT_POSITION_X, x); - input_report_abs(input, ABS_MT_POSITION_Y, y); - - if (w >= 0 && h >= 0) { - input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(w, h)); - input_report_abs(input, ABS_MT_TOUCH_MINOR, min(w, h)); - input_report_abs(input, ABS_MT_ORIENTATION, w > h); - - if (c_x >= 0 && c_y >= 0) { - input_report_abs(input, ABS_MT_WIDTH_MAJOR, - min(w, h) + int_dist(x, y, c_x, c_y)); - input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h)); - } - } - } -} - -static int wacom_multitouch_generic(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->input; - unsigned char *data = wacom->data; - int current_num_contacts, contacts_to_send, contacts_per_packet; - int bytes_per_packet, bytes_header; - int i; - - switch (features->type) { - case WACOM_24HDT: - current_num_contacts = data[61]; - contacts_per_packet = 4; - bytes_per_packet = WACOM_BYTES_PER_24HDT_PACKET; - bytes_header = 1; - break; - case WACOM_27QHDT: - if (wacom->shared->has_mute_touch_switch && - !wacom->shared->is_touch_on) { - if (!wacom->shared->touch_down) - return 0; - } - - current_num_contacts = data[63]; - contacts_per_packet = 10; - bytes_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET; - bytes_header = 1; - break; - case WACOM_MSPROT: - case DTH1152T: - case DTH2452T: - current_num_contacts = data[2]; - contacts_per_packet = 5; - bytes_per_packet = WACOM_BYTES_PER_MSPROT_PACKET; - bytes_header = 3; - break; - case INTUOSP2: - case INTUOSP2S: - current_num_contacts = data[1]; - contacts_per_packet = 5; - bytes_per_packet = WACOM_BYTES_PER_INTUOSP2_PACKET; - bytes_header = 2; - break; - default: - return 0; - } - - if (current_num_contacts) - wacom->num_contacts_left = current_num_contacts; - - contacts_to_send = min(contacts_per_packet, wacom->num_contacts_left); - - for (i = 0; i < contacts_to_send; i++) { - int contact_id = -1; - int x = -1; - int y = -1; - int w = -1; - int h = -1; - int c_x = -1; - int c_y = -1; - int prox = -1; - int offset = bytes_per_packet * i + bytes_header; - bool confidence = true; - - switch (features->type) { - case WACOM_24HDT: - prox = data[offset] & 0x01; - contact_id = data[offset + 1]; - x = get_unaligned_le16(&data[offset + 2]); - c_x = get_unaligned_le16(&data[offset + 4]); - y = get_unaligned_le16(&data[offset + 6]); - c_y = get_unaligned_le16(&data[offset + 8]); - w = get_unaligned_le16(&data[offset + 10]); - h = get_unaligned_le16(&data[offset + 12]); - break; - - case WACOM_27QHDT: - prox = data[offset] & 0x01; - contact_id = data[offset + 1]; - x = get_unaligned_le16(&data[offset + 2]); - y = get_unaligned_le16(&data[offset + 4]); - break; - - case WACOM_MSPROT: - case DTH1152T: - case DTH2452T: - prox = data[offset] & 0x1; - confidence = data[offset] & 0x4; - contact_id = get_unaligned_le16(&data[offset + 1]); - x = get_unaligned_le16(&data[offset + 3]); - y = get_unaligned_le16(&data[offset + 5]); - w = data[offset + 7] * 133; - h = data[offset + 8] * 133; - break; - - case INTUOSP2: - case INTUOSP2S: - contact_id = data[offset]; - prox = data[offset + 1] & 0x01; - x = get_unaligned_le16(&data[offset + 2]); - y = get_unaligned_le16(&data[offset + 4]); - w = data[offset + 6]; - h = data[offset + 7]; - break; - - default: - continue; - } - if (!confidence) - continue; - wacom_multitouch_generic_finger(wacom, contact_id, prox, x, y, w, h, c_x, c_y); - } - - 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_mt_sync_frame(input); - return 1; -} - -static int wacom_mt_touch(struct wacom_wac *wacom) -{ - struct input_dev *input = wacom->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 || - wacom->features.type == MTTPC_C) - 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_report_pointer_emulation(input, true); - - 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->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_report_pointer_emulation(input, true); - - /* 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->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->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; - - dev_dbg(wacom->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); - - case WACOM_PKGLEN_PENABLED: - return wacom_tpc_pen(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); - - case WACOM_REPORT_PENABLED: - return wacom_tpc_pen(wacom); - } - } - - return 0; -} - -static int wacom_bpt_touch(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->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_report_pointer_emulation(input, true); - - 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_BACK, (data[1] & 0x02) != 0); - input_report_key(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->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->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) -{ - struct input_dev *input = wacom->input; - 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); - - } - - if (touch_changed) { - input_mt_report_pointer_emulation(input, true); - 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->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 == BTN_TOOL_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 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) { - wacom->shared->is_touch_on = !(data[5] & 0x40); - input_report_switch(wacom->shared->touch_input, - SW_MUTE_DEVICE, !wacom->shared->is_touch_on); - 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) { - wacom_wac->shared->is_touch_on = !(data[8] & 0x40); - input_report_switch(wacom_wac->shared->touch_input, - SW_MUTE_DEVICE, !wacom_wac->shared->is_touch_on); - 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; -} - -static void wacom_mspro_touch_switch(struct wacom_wac *wacom, bool enable_touch) -{ - if (!wacom->shared->touch_input) - return; - - wacom->shared->is_touch_on = enable_touch; - input_report_switch(wacom->shared->touch_input, - SW_MUTE_DEVICE, !enable_touch); - input_sync(wacom->shared->touch_input); -} - -static void wacom_mspro_touch_toggle(struct wacom_wac *wacom) -{ - if (!wacom->shared->touch_input) - return; - - wacom_mspro_touch_switch(wacom, !wacom->shared->is_touch_on); -} - -static int wacom_mspro_device_irq(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - bool bat_charging; - int battery_level; - - battery_level = data[1] & 0x7F; - bat_charging = data[1] & 0x80; - - features->quirks |= WACOM_QUIRK_BATTERY; - wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO, - battery_level, bat_charging, 1, bat_charging); - - wacom_mspro_touch_switch(wacom, (data[2] & 0x80)); - - return 0; -} - -int wacom_mask_with_numbered_buttons(int nbuttons, int buttons) -{ - int mask = 0; - int i; - - for (i = 0; i < nbuttons; i++) - mask |= buttons & (1 << i); - - return mask; -} - -static int wacom_mspro_pad_irq(struct wacom_wac *wacom) -{ - struct wacom_features *features = &wacom->features; - unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; - int nbuttons = features->numbered_buttons; - bool prox; - int buttons, ring, ringvalue, keys; - bool active = false; - - switch (nbuttons) { - case 11: - buttons = (data[1] >> 1) | (data[3] << 6); - ring = le16_to_cpup((__le16 *)&data[4]); - keys = 0; - break; - case 13: - buttons = data[1] | (data[3] << 8); - ring = le16_to_cpup((__le16 *)&data[4]); - keys = 0; - break; - case 4: - buttons = data[1]; - keys = 0; - ring = 0; - break; - case 9: - buttons = (data[1]) | (data[3] << 8); - ring = le16_to_cpup((__le16 *)&data[4]); - keys = 0; - break; - case 7: - buttons = (data[1]) | (data[3] << 6); - ring = le16_to_cpup((__le16 *)&data[4]); - keys = 0; - break; - case 8: /* Cintiq Pro 16 */ - buttons = data[1]; - keys = 0; - ring = WACOM_INTUOSP2_RING_UNTOUCHED; /* No ring */ - break; - case 0: - buttons = 0; - ring = WACOM_INTUOSP2_RING_UNTOUCHED; /* No ring */ - keys = data[1] & 0x0E; /* 0x01 shouldn't make the pad active */ - - if (data[1] & 0x01) - wacom_mspro_touch_toggle(wacom); - - input_report_key(input, KEY_CONTROLPANEL, (data[1] & 0x02) != 0); - input_report_key(input, KEY_ONSCREEN_KEYBOARD, (data[1] & 0x04) != 0); - input_report_key(input, KEY_BUTTONCONFIG, (data[1] & 0x08) != 0); - break; - default: - dev_warn(input->dev.parent, "%s: unsupported device #%d\n", __func__, data[0]); - return 0; - } - - /* Fix touchring data: userspace expects 0 at left and increasing clockwise */ - if (input->id.product == 0x357 || input->id.product == 0x358) { - /* 2nd-gen Intuos Pro */ - ringvalue = 71 - (ring & 0x7F); - ringvalue += 3*72/16; - if (ringvalue > 71) - ringvalue -= 72; - } else if (input->id.product == 0x34d || input->id.product == 0x34e || - input->id.product == 0x398 || input->id.product == 0x399 || - input->id.product == 0x3aa) { - /* MobileStudio Pro */ - ringvalue = 35 - (ring & 0x7F); - ringvalue += 36/2; - if (ringvalue > 35) - ringvalue -= 36; - } - else { - /* "Standard" devices */ - ringvalue = 71 - (ring & 0x7F); - ringvalue += 72/4; - if (ringvalue > 71) - ringvalue -= 72; - } - - /* Mask off buttons greater than nbuttons to avoid having them set prox */ - buttons = wacom_mask_with_numbered_buttons(nbuttons, buttons); - - if (ring != WACOM_INTUOSP2_RING_UNTOUCHED) - prox = buttons || ring; - else - prox = buttons; - - wacom_report_numbered_buttons(input, nbuttons, buttons); - input_report_abs(input, ABS_WHEEL, (ring & 0x80) ? ringvalue : 0); - - input_report_key(input, wacom->tool[1], prox ? 1 : 0); - - active = (ring ^ wacom->previous_ring) || (buttons ^ wacom->previous_buttons) || (keys ^ wacom->previous_keys); - - input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0); - - wacom->previous_buttons = buttons; - wacom->previous_ring = ring; - wacom->previous_keys = keys; - - if (active) - input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff); - else - return 0; - - return 1; -} - -static int wacom_mspro_pen_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; - bool tip, sw1, sw2, range, proximity; - unsigned int x, y; - unsigned int pressure; - int tilt_x, tilt_y; - int rotation; - unsigned int fingerwheel; - unsigned int height; - u64 tool_uid; - unsigned int tool_type; - - if (delay_pen_events(wacom)) - return 1; - - tip = data[1] & 0x01; - sw1 = data[1] & 0x02; - sw2 = data[1] & 0x04; - /* eraser = data[1] & 0x08; */ - /* invert = data[1] & 0x10; */ - range = data[1] & 0x20; - proximity = data[1] & 0x40; - x = le32_to_cpup((__le32 *)&data[2]) & 0xFFFFFF; - y = le32_to_cpup((__le32 *)&data[5]) & 0xFFFFFF; - pressure = le16_to_cpup((__le16 *)&data[8]); - tilt_x = (char)data[10]; - tilt_y = (char)data[11]; - rotation = (int16_t)le16_to_cpup((__le16 *)&data[12]); - fingerwheel = le16_to_cpup((__le16 *)&data[14]); - height = data[16]; - tool_uid = le64_to_cpup((__le64 *)&data[17]); - tool_type = le16_to_cpup((__le16 *)&data[25]); - - if (range) { - wacom->serial[0] = (tool_uid & 0xFFFFFFFF); - wacom->id[0] = ((tool_uid >> 32) & 0xFFFFF) | tool_type; - wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0] & 0xFFFFF); - } - - /* pointer going from fully "in range" to merely "in proximity" */ - if (!range && wacom->tool[0]) { - height = wacom->features.distance_max; - } - - /* - * only report data if there's a tool for userspace to associate - * the events with. - */ - if (wacom->tool[0]) { - unsigned int sw_state = sw1 | (sw2 << 1); - - /* Fix rotation alignment: userspace expects zero at left */ - rotation += 1800/4; - if (rotation > 899) - rotation -= 1800; - - /* Fix tilt zero-point: wacom_setup_cintiq declares 0..127, not -63..+64 */ - tilt_x += 64; - tilt_y += 64; - - input_report_key(input, BTN_TOUCH, proximity ? tip : 0); - input_report_key(input, BTN_STYLUS, proximity ? sw_state == 1 : 0); - input_report_key(input, BTN_STYLUS2, proximity ? sw_state == 2 : 0); - input_report_key(input, BTN_STYLUS3, proximity ? sw_state == 3 : 0); - input_report_abs(input, ABS_X, proximity ? x : 0); - input_report_abs(input, ABS_Y, proximity ? y : 0); - input_report_abs(input, ABS_PRESSURE, proximity ? pressure : 0); - input_report_abs(input, ABS_TILT_X, proximity ? tilt_x : 0); - input_report_abs(input, ABS_TILT_Y, proximity ? tilt_y : 0); - input_report_abs(input, ABS_Z, proximity ? rotation : 0); - input_report_abs(input, ABS_WHEEL, proximity ? fingerwheel : 0); - input_report_abs(input, ABS_DISTANCE, proximity ? height : 0); - - if (wacom->features.type != WACOM_ONE) { - input_event(input, EV_MSC, MSC_SERIAL, - wacom->serial[0]); - input_report_abs(input, ABS_MISC, proximity ? - wacom_intuos_id_mangle(wacom->id[0]) - : 0); - } else { - input_report_abs(input, ABS_MISC, proximity ? - STYLUS_DEVICE_ID : 0); - } - input_report_key(input, wacom->tool[0], proximity ? 1 : 0); - - if (!proximity) - wacom->tool[0] = 0; - } - - wacom->shared->stylus_in_proximity = proximity; - - return 1; -} - -static int wacom_Pro2022_pen_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; - struct wacom_features *features = &wacom->features; - bool tip, sw1, sw2, sw3, range, proximity; - unsigned int x, y; - unsigned int pressure; - int tilt_x, tilt_y; - int rotation; - unsigned int fingerwheel; - unsigned int height; - u64 tool_uid; - unsigned int tool_type; - unsigned int timestamp; - unsigned short sequence_number; - - if (delay_pen_events(wacom)) - return 1; - - tip = data[2] & 0x01; - sw1 = data[2] & 0x02; - sw2 = data[2] & 0x04; - sw3 = data[2] & 0x08; - /* eraser = data[2] & 0x10; */ - /* invert = data[2] & 0x20; */ - range = data[2] & 0x40; - proximity = data[2] & 0x80; - x = le32_to_cpup((__le32 *)&data[3]) & 0xFFFFFF; - y = le32_to_cpup((__le32 *)&data[6]) & 0xFFFFFF; - pressure = le16_to_cpup((__le16 *)&data[9]); - tilt_x = (char)le16_to_cpup((__le16 *)&data[11]); - tilt_y = (char)le16_to_cpup((__le16 *)&data[13]); - rotation = (int16_t)le16_to_cpup((__le16 *)&data[15]); - fingerwheel = le16_to_cpup((__le16 *)&data[17]); - height = data[19]; - tool_uid = le64_to_cpup((__le64 *)&data[20]); - tool_type = le16_to_cpup((__le16 *)&data[28]); - timestamp = le16_to_cpup((__le16 *)&data[30]); - sequence_number = le16_to_cpup((__le16 *)&data[32]); - - if (range) { - wacom->serial[0] = (tool_uid & 0xFFFFFFFF); - wacom->id[0] = ((tool_uid >> 32) & 0xFFFFF) | tool_type; - wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0] & 0xFFFFF); - } - - /* pointer going from fully "in range" to merely "in proximity" */ - if (!range && wacom->tool[0]) - height = wacom->features.distance_max; - - - /* - * only report data if there's a tool for userspace to associate - * the events with. - */ - if (wacom->tool[0]) { - - /* Fix rotation alignment: userspace expects zero at left */ - rotation += 1800/4; - if (rotation > 899) - rotation -= 1800; - - /* Fix tilt zero-point: wacom_setup_cintiq declares 0..127, not -63..+64 */ - tilt_x += 64; - tilt_y += 64; - - input_report_key(input, BTN_TOUCH, proximity ? tip : 0); - input_report_key(input, BTN_STYLUS, proximity ? sw1 : 0); - input_report_key(input, BTN_STYLUS2, proximity ? sw2 : 0); - input_report_key(input, BTN_STYLUS3, proximity ? sw3 : 0); - input_report_abs(input, ABS_X, proximity ? x : 0); - input_report_abs(input, ABS_Y, proximity ? y : 0); - input_report_abs(input, ABS_PRESSURE, proximity ? pressure : 0); - input_report_abs(input, ABS_TILT_X, proximity ? tilt_x : 0); - input_report_abs(input, ABS_TILT_Y, proximity ? tilt_y : 0); - input_report_abs(input, ABS_Z, proximity ? rotation : 0); - input_report_abs(input, ABS_WHEEL, proximity ? fingerwheel : 0); - input_report_abs(input, ABS_DISTANCE, proximity ? height : 0); - input_event(input, EV_MSC, MSC_TIMESTAMP, timestamp); - - if (wacom->features.type != WACOM_ONE) { - input_event(input, EV_MSC, MSC_SERIAL, - wacom->serial[0]); - input_report_abs(input, ABS_MISC, proximity ? - wacom_intuos_id_mangle(wacom->id[0]) - : 0); - } else { - input_report_abs(input, ABS_MISC, proximity ? - STYLUS_DEVICE_ID : 0); - } - input_report_key(input, wacom->tool[0], proximity ? 1 : 0); - - if (features->sequence_number != sequence_number) - hid_warn(wacom->input, "dropped %hu packets", sequence_number - features->sequence_number); - - features->sequence_number = sequence_number + 1; - - if (!proximity) - wacom->tool[0] = 0; - } - - wacom->shared->stylus_in_proximity = proximity; - - return 1; -} - -static int wacom_mspro_irq(struct wacom_wac *wacom) -{ - unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; - switch (data[0]) { - case WACOM_REPORT_MSPRO: - return wacom_mspro_pen_irq(wacom); - case WACOM_REPORT_MSPROPAD: - return wacom_mspro_pad_irq(wacom); - case WACOM_REPORT_MSPRODEVICE: - return wacom_mspro_device_irq(wacom); - case WACOM_REPORT_PRO2022: - return wacom_Pro2022_pen_irq(wacom); - default: - dev_dbg(input->dev.parent, - "%s: received unknown report #%d\n", __func__, data[0]); - break; - } - 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 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: - case DTK2451: - sync = wacom_dtus_irq(wacom_wac); - break; - - case DTUS2: - case DTH1152: - sync = wacom_dth1152_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 WACOM_ONE: - case WACOM_MSPRO: - case INTUOSP2: - case INTUOSP2S: - case WACOM_PRO2022: - case CINTIQ_16: - if (len == WACOM_PKGLEN_INTUOSP2T && - wacom_wac->data[0] == WACOM_REPORT_VENDOR_DEF_TOUCH) - sync = wacom_multitouch_generic(wacom_wac); - else - sync = wacom_mspro_irq(wacom_wac); - break; - - case WACOM_24HDT: - case WACOM_27QHDT: - case DTH1152T: - case DTH2452T: - case WACOM_MSPROT: - sync = wacom_multitouch_generic(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 TABLETPC: - case TABLETPCE: - case TABLETPC2FG: - case MTSCREEN: - case MTTPC: - case MTTPC_B: - case MTTPC_C: - sync = wacom_tpc_irq(wacom_wac, len); - break; - - case BAMBOO_PT: - 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 INTUOSHT3: - sync = wacom_mspro_irq(wacom_wac); - 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) - input_sync(wacom_wac->input); -} - -static void wacom_setup_basic_pro_pen(struct wacom_wac *wacom_wac) -{ - struct input_dev *input_dev = wacom_wac->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->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, 0, 127, features->tilt_fuzz, 0); - input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, features->tilt_fuzz, 0); -} - -static void wacom_setup_intuos(struct wacom_wac *wacom_wac) -{ - struct input_dev *input_dev = wacom_wac->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_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); -} -static void wacom_setup_wacom_one_pen(struct wacom_wac *wacom_wac) - -{ - struct input_dev *input_dev = wacom_wac->input; - struct wacom_features *features = &wacom_wac->features; - - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, - features->tilt_fuzz, 0); - input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, - features->tilt_fuzz, 0); - input_set_abs_params(input_dev, ABS_DISTANCE, - 0, wacom_wac->features.distance_max, - wacom_wac->features.distance_fuzz, 0); -} - -void wacom_setup_device_quirks(struct wacom *wacom) -{ - struct wacom_features *features = &wacom->wacom_wac.features; - struct usb_endpoint_descriptor *endpoint = - &(wacom->intf)->cur_altsetting->endpoint[0].desc; - - /* touch device found but size is not defined. use default */ - if (features->device_type == BTN_TOOL_FINGER && !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 (wMaxPacketSize of WACOM_PKGLEN_BBTOUCH3), override - * the tablet values. - */ - if ((features->type >= INTUOS5S && features->type <= INTUOSPL) || - (features->type >= INTUOSHT && features->type <= BAMBOO_PT)) { - if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) { - features->device_type = BTN_TOOL_FINGER; - features->pktlen = WACOM_PKGLEN_BBTOUCH3; - - 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 { - features->device_type = BTN_TOOL_PEN; - } - } - - /* quirk for bamboo touch with 2 low res touches */ - if (features->type == BAMBOO_PT && - 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 == REMOTE) - features->device_type = BTN_TOOL_FINGER; - - if (features->type == WIRELESS) { - - /* monitor never has input and pen/touch have delayed create */ - features->quirks |= WACOM_QUIRK_NO_INPUT; - - /* must be monitor interface if no device_type set */ - if (!features->device_type) { - features->quirks |= WACOM_QUIRK_MONITOR; - features->quirks |= WACOM_QUIRK_BATTERY; - } - } - - if (features->type == REMOTE) - features->quirks |= WACOM_QUIRK_MONITOR; -} - -static void wacom_abs_set_axis(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) -{ - struct wacom_features *features = &wacom_wac->features; - - if (features->device_type == BTN_TOOL_PEN) { - 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); - } else { - 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); - } - - 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); - } - } -} - -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_input_capabilities(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) -{ - struct wacom_features *features = &wacom_wac->features; - int numbered_buttons = features->numbered_buttons; - if (features->type == REMOTE && input_dev == wacom_wac->input) - return -ENODEV; - - 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); - - wacom_abs_set_axis(input_dev, wacom_wac); - - switch (features->type) { - case REMOTE: - /* kept for making legacy xf86-input-wacom accepting the pad */ - input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0); - 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); - __clear_bit(BTN_TOUCH, input_dev->keybit); - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - break; - - case WACOM_MO: - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); - fallthrough; - - case WACOM_G4: - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); - input_set_abs_params(input_dev, ABS_DISTANCE, 0, - features->distance_max, features->distance_fuzz, 0); - - __set_bit(BTN_BACK, input_dev->keybit); - __set_bit(BTN_FORWARD, input_dev->keybit); - 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); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - break; - - case WACOM_ONE: - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - wacom_setup_wacom_one_pen(wacom_wac); - break; - - case WACOM_MSPRO: - case WACOM_PRO2022: - case CINTIQ_16: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - __set_bit(BTN_STYLUS3, input_dev->keybit); - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - if (features->type == WACOM_MSPRO && - features->numbered_buttons == 0) { /* Cintiq Pro */ - __set_bit(KEY_CONTROLPANEL, input_dev->keybit); - __set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit); - __set_bit(KEY_BUTTONCONFIG, input_dev->keybit); - - wacom_wac->previous_ring = WACOM_INTUOSP2_RING_UNTOUCHED; - } - - if (input_dev->id.product == 0x3B2) { - /* Cintiq Pro 16 refresh */ - wacom_wac->shared->has_mute_touch_switch = true; - } - else if (input_dev->id.product == 0x3B3) { - /* Cintiq Pro 16 refresh touchscreen */ - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - wacom_wac->shared->has_mute_touch_switch = true; - } - - wacom_setup_cintiq(wacom_wac); - 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_THROTTLE, 0, 71, 0, 0); - fallthrough; - - case WACOM_13HD: - case CINTIQ_HYBRID: - case CINTIQ_COMPANION_2: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - fallthrough; - - case DTK: - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - 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); - - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - - wacom_setup_cintiq(wacom_wac); - 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); - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - 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); - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - fallthrough; - - case INTUOS: - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - - wacom_setup_intuos(wacom_wac); - break; - - case INTUOSP2: - case INTUOSP2S: - if (features->device_type == BTN_TOOL_PEN) { - __set_bit(BTN_STYLUS3, input_dev->keybit); - wacom_wac->previous_ring = WACOM_INTUOSP2_RING_UNTOUCHED; - wacom_wac->shared->has_mute_touch_switch = true; - } - else { - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - wacom_wac->shared->has_mute_touch_switch = true; - } - fallthrough; - - case INTUOS5: - case INTUOS5L: - case INTUOSPM: - case INTUOSPL: - case INTUOS5S: - case INTUOSPS: - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - - if (features->device_type == BTN_TOOL_PEN) { - 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); - - wacom_setup_intuos(wacom_wac); - } else if (features->device_type == BTN_TOOL_FINGER) { - __clear_bit(ABS_MISC, input_dev->absbit); - - /* pad is on pen interface */ - numbered_buttons = 0; - 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 INTUOS4: - case INTUOS4L: - case INTUOS4S: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - wacom_setup_intuos(wacom_wac); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - break; - - case WACOM_24HDT: - if (features->device_type == BTN_TOOL_FINGER) { - 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); - } - fallthrough; - - case DTH1152T: - case DTH2452T: - case WACOM_MSPROT: - if (features->device_type == BTN_TOOL_FINGER) { - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); - if (features->type != WACOM_24HDT) - input_set_abs_params(input_dev, ABS_MT_TOUCH_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_input->id.product == 0x32C || - wacom_wac->shared->touch_input->id.product == 0xF6) { - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - wacom_wac->shared->has_mute_touch_switch = true; - } - fallthrough; - - case MTSCREEN: - case MTTPC: - case MTTPC_B: - case MTTPC_C: - case TABLETPC2FG: - if ((features->device_type == BTN_TOOL_FINGER) && features->touch_max > 1) - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT); - fallthrough; - - case TABLETPC: - case TABLETPCE: - __clear_bit(ABS_MISC, input_dev->absbit); - - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - if ((features->device_type == BTN_TOOL_FINGER) && - (input_dev->id.product >= 0x353 && input_dev->id.product <= 0x356)) { - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - wacom_wac->shared->has_mute_touch_switch = true; - wacom_wac->shared->is_touch_on = true; - } - - if (features->device_type != BTN_TOOL_PEN) - break; /* no need to process stylus stuff */ - - fallthrough; - - case DTUS: - case DTUS2: - case DTK2451: - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); - fallthrough; - - case DTUSX: - case PL: - case DTU: - if (features->type != DTUS2) { - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - } - fallthrough; - - case DTH1152: - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - 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); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - break; - - case INTUOSHT: - case INTUOSHT2: - if (features->touch_max && - features->device_type == BTN_TOOL_FINGER) { - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - wacom_wac->shared->has_mute_touch_switch = true; - } - fallthrough; - - case INTUOSHT3: - case BAMBOO_PT: - __clear_bit(ABS_MISC, input_dev->absbit); - - if (features->device_type == BTN_TOOL_FINGER) { - - __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); - - if (features->touch_max) { - 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); - } else { - /* buttons/keys only interface */ - __clear_bit(ABS_X, input_dev->absbit); - __clear_bit(ABS_Y, input_dev->absbit); - __clear_bit(BTN_TOUCH, input_dev->keybit); - - /* For Bamboo, buttons are supported only when touch is supported */ - if (features->type == BAMBOO_PT) { - __clear_bit(BTN_LEFT, input_dev->keybit); - __clear_bit(BTN_FORWARD, input_dev->keybit); - __clear_bit(BTN_BACK, input_dev->keybit); - __clear_bit(BTN_RIGHT, input_dev->keybit); - } - } - } else if (features->device_type == BTN_TOOL_PEN) { - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - if (features->type == INTUOSHT2 || features->type == INTUOSHT3) { - __set_bit(ABS_MISC, input_dev->absbit); - wacom_setup_basic_pro_pen(wacom_wac); - } else { - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __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, - features->distance_max, - features->distance_fuzz, 0); - } - } - break; - } - - /* - * Because all devices with numbered buttons have the pen and pad on - * the same interface we can rely on this check to avoid creating - * extra pads. Future devices may require creating a more involved - * check. - */ - if (features->device_type == BTN_TOOL_PEN || features->type == REMOTE) - wacom_setup_numbered_buttons(input_dev, numbered_buttons); - - return 0; -} - -static const struct wacom_features wacom_features_0x00 = - { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, - PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; -static const struct wacom_features wacom_features_0x10 = - { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x11 = - { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x12 = - { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x13 = - { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x14 = - { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x15 = - { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, - WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x16 = - { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, - WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x17 = - { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, - WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x18 = - { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, - WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x19 = - { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, - GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; -static const struct wacom_features wacom_features_0x60 = - { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x61 = - { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x62 = - { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x63 = - { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x64 = - { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, - GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; -static const struct wacom_features wacom_features_0x65 = - { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, - WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x69 = - { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, - GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; -static const struct wacom_features wacom_features_0x6A = - { "Wacom Bamboo1 4x6", WACOM_PKGLEN_GRAPHIRE, 14760, 9225, 1023, 63, - GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x6B = - { "Wacom Bamboo1 5x8", WACOM_PKGLEN_GRAPHIRE, 21648, 13530, 1023, 63, - GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x20 = - { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x21 = - { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x22 = - { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x23 = - { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x24 = - { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x30 = - { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x31 = - { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x32 = - { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x33 = - { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x34 = - { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x35 = - { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x37 = - { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x38 = - { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x39 = - { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0xC4 = - { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0xC0 = - { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0xC2 = - { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, - PL, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x03 = - { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, - PTU, WACOM_PL_RES, WACOM_PL_RES }; -static const struct wacom_features wacom_features_0x41 = - { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x42 = - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x43 = - { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x44 = - { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x45 = - { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xB0 = - { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; -static const struct wacom_features wacom_features_0xB1 = - { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB2 = - { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB3 = - { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB4 = - { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB5 = - { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xB7 = - { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; -static const struct wacom_features wacom_features_0xB8 = - { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, - INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; -static const struct wacom_features wacom_features_0xB9 = - { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0xBA = - { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0xBB = - { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0xBC = - { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40640, 25400, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0x26 = - { "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, - INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; -static const struct wacom_features wacom_features_0x2A = - { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, - INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; -static const struct wacom_features wacom_features_0x314 = - { "Wacom Intuos Pro S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, - INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x315 = - { "Wacom Intuos Pro M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, - INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x317 = - { "Wacom Intuos Pro L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, - INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; -static const struct wacom_features wacom_features_0xF4 = - { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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 }; -static const struct wacom_features wacom_features_0x32A = - { "Wacom Cintiq 27QHD", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, - CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; -static const struct wacom_features wacom_features_0xC5 = - { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; -static const struct wacom_features wacom_features_0xC6 = - { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; -static const struct wacom_features wacom_features_0x304 = - { "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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 }; -static const struct wacom_features wacom_features_0xC7 = - { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, - PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xCE = - { "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, 0, - DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xF0 = - { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, 0, - DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xFB = - { "Wacom DTU1031", WACOM_PKGLEN_DTUS, 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", WACOM_PKGLEN_DTUS, 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", WACOM_PKGLEN_DTUS, 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", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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 }; -static const struct wacom_features wacom_features_0xCC = - { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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", WACOM_PKGLEN_INTUOS, 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 }; -static const struct wacom_features wacom_features_0x90 = - { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x93 = - { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x97 = - { "Wacom ISDv4 97", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 511, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x9A = - { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x9F = - { "Wacom ISDv4 9F", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xE2 = - { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 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", WACOM_PKGLEN_TPC2FG, 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", WACOM_PKGLEN_MTOUCH, 26202, 16325, 255, 0, - MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xE6 = - { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 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", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xED = - { "Wacom ISDv4 ED", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, - TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xEF = - { "Wacom ISDv4 EF", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x100 = - { "Wacom ISDv4 100", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x101 = - { "Wacom ISDv4 101", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x10D = - { "Wacom ISDv4 10D", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x10E = - { "Wacom ISDv4 10E", WACOM_PKGLEN_MTTPC, 27760, 15694, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x10F = - { "Wacom ISDv4 10F", WACOM_PKGLEN_MTTPC, 27760, 15694, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x116 = - { "Wacom ISDv4 116", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, - TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x12C = - { "Wacom ISDv4 12C", WACOM_PKGLEN_GRAPHIRE, 27848, 15752, 2047, 0, - TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x4001 = - { "Wacom ISDv4 4001", WACOM_PKGLEN_MTTPC, 26202, 16325, 255, 0, - MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x4004 = - { "Wacom ISDv4 4004", WACOM_PKGLEN_MTTPC, 11060, 6220, 255, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5000 = - { "Wacom ISDv4 5000", WACOM_PKGLEN_MTTPC, 27848, 15752, 1023, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5002 = - { "Wacom ISDv4 5002", WACOM_PKGLEN_MTTPC, 29576, 16724, 1023, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5010 = - { "Wacom ISDv4 5010", WACOM_PKGLEN_MTTPC, 13756, 7736, 1023, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5013 = - { "Wacom ISDv4 5013", WACOM_PKGLEN_MTTPC, 11752, 6612, 1023, 0, - MTTPC_B, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5044 = - { "Wacom ISDv4 5044", WACOM_PKGLEN_MTTPC, 27648, 15552, 2047, 0, - MTTPC_C, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5048 = - { "Wacom ISDv4 5048", WACOM_PKGLEN_MTTPC, 27648, 15552, 2047, 0, - MTTPC_C, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x5090 = - { "Wacom ISDv4 5090", WACOM_PKGLEN_MTTPC, 27648, 15552, 2047, 0, - MTTPC_C, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x47 = - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, - INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x84 = - { "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, .type = WIRELESS, .touch_max = 16 }; -static const struct wacom_features wacom_features_0xD0 = - { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 }; -static const struct wacom_features wacom_features_0xD1 = - { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xD5 = - { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xD6 = - { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBFUN, 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", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0xDE = - { "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN, 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", WACOM_PKGLEN_BBPEN, 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", WACOM_PKGLEN_BBPEN, 14720, 9225, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x301 = - { "Wacom Bamboo One M", WACOM_PKGLEN_BBPEN, 21648, 13530, 1023, 31, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x302 = - { "Wacom Intuos PT S", WACOM_PKGLEN_BBPEN, 15200, 9500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x303 = - { "Wacom Intuos PT M", WACOM_PKGLEN_BBPEN, 21600, 13500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x30E = - { "Wacom Intuos S", WACOM_PKGLEN_BBPEN, 15200, 9500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x6004 = - { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, - TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x307 = - { "Wacom ISDv5 307", WACOM_PKGLEN_INTUOS, 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 }; -static const struct wacom_features wacom_features_0x30A = - { "Wacom ISDv5 30A", WACOM_PKGLEN_INTUOS, 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 }; -static const struct wacom_features wacom_features_0x323 = - { "Wacom Intuos P M", WACOM_PKGLEN_BBPEN, 21600, 13500, 1023, 31, - INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x325 = - { "Wacom ISDv5 325", WACOM_PKGLEN_INTUOS, 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 = WACOM_24HDT, .oVid = USB_VENDOR_ID_WACOM, - .oPid = 0x325, .touch_max = 10 }; -static const struct wacom_features wacom_features_0x331 = - { "Wacom Express Key Remote", WACOM_PKGLEN_WIRELESS, .type = REMOTE, - .numbered_buttons = 18 }; -static const struct wacom_features wacom_features_0x33B = - { "Wacom Intuos S 2", WACOM_PKGLEN_INTUOS, 15200, 9500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x33C = - { "Wacom Intuos PT S 2", WACOM_PKGLEN_INTUOS, 15200, 9500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x33D = - { "Wacom Intuos P M 2", WACOM_PKGLEN_INTUOS, 21600, 13500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x33E = - { "Wacom Intuos PT M 2", WACOM_PKGLEN_INTUOS, 21600, 13500, 2047, 63, - INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 }; -static const struct wacom_features wacom_features_0x343 = - { "Wacom DTK1651", WACOM_PKGLEN_DTUS, 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_0x34A = - { "Wacom MobileStudio Pro 13 Touch", WACOM_PKGLEN_MSPROT, .type = WACOM_MSPROT, /* Touch */ - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34D }; -static const struct wacom_features wacom_features_0x34B = - { "Wacom MobileStudio Pro 16 Touch", WACOM_PKGLEN_MSPROT, .type = WACOM_MSPROT, /* Touch */ - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34E }; -static const struct wacom_features wacom_features_0x34D = - { "Wacom MobileStudio Pro 13", WACOM_PKGLEN_MSPRO, 59552, 33848, 8191, 63, - WACOM_MSPRO, 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 = 0x34A }; -static const struct wacom_features wacom_features_0x34E = - { "Wacom MobileStudio Pro 16", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 63, - WACOM_MSPRO, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 13, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34B }; -static const struct wacom_features wacom_features_0x34F = - { "Wacom Cintiq Pro 13 FHD", WACOM_PKGLEN_MSPRO, 59552, 33848, 8191, 63, - WACOM_MSPRO, 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 = 0x353 }; -static const struct wacom_features wacom_features_0x350 = - { "Wacom Cintiq Pro 16UHD", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 63, - WACOM_MSPRO, 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 = 0x354 }; -static const struct wacom_features wacom_features_0x351 = - { "Wacom Cintiq Pro 24", WACOM_PKGLEN_MSPRO, 105286, 59574, 8191, 63, /* Pen & Touch */ - WACOM_MSPRO, 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 = 0x355 }; -static const struct wacom_features wacom_features_0x352 = - { "Wacom Cintiq Pro 32", WACOM_PKGLEN_MSPRO, 140384, 79316, 8191, 63, - WACOM_MSPRO, 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 = 0x356 }; -static const struct wacom_features wacom_features_0x353 = - { "Wacom Cintiq Pro 13FHD Touch", WACOM_PKGLEN_MSPROT, .type = WACOM_MSPROT, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x34f }; /* Touch */ -static const struct wacom_features wacom_features_0x354 = - { "Wacom Cintiq Pro 16UHD Touch", WACOM_PKGLEN_MSPROT, .type = WACOM_MSPROT, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x350 }; /* Touch */ -static const struct wacom_features wacom_features_0x355 = - { "Wacom Cintiq Pro 24 Touch", WACOM_PKGLEN_27QHDT, .type = WACOM_27QHDT, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x351, .touch_max = 10 }; /* Touch */ -static const struct wacom_features wacom_features_0x356 = - { "Wacom Cintiq Pro 32 Touch", WACOM_PKGLEN_27QHDT, .type = WACOM_27QHDT, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x352, .touch_max = 10 }; /* Touch */ -static const struct wacom_features wacom_features_0x357 = - { "Wacom Intuos Pro M", WACOM_PKGLEN_INTUOSP2, 44800, 29600, 8191, 63, - INTUOSP2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 }; -static const struct wacom_features wacom_features_0x358 = - { "Wacom Intuos Pro L", WACOM_PKGLEN_INTUOSP2, 62200, 43200, 8191, 63, - INTUOSP2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 }; -static const struct wacom_features wacom_features_0x359 = - { "Wacom DTU-1141B", WACOM_PKGLEN_DTH1152, 22320, 12555, 1023, 0, - DTUS2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x35A = - { "Wacom DTH-1152", WACOM_PKGLEN_DTH1152, 22320, 12555, 1023, 0, - DTH1152, WACOM_INTUOS_RES, WACOM_INTUOS_RES, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x368 }; -static const struct wacom_features wacom_features_0x368 = - { "Wacom DTH-1152 Touch", WACOM_PKGLEN_27QHDT, - .type = DTH1152T, .touch_max = 10, .oVid = USB_VENDOR_ID_WACOM, - .oPid = 0x35A }; /* Touch */ -static const struct wacom_features wacom_features_0x374 = - { "Intuos S", WACOM_PKGLEN_INTUOSP2, 15200, 9500, 4095, - 63, INTUOSHT3, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x375 = - { "Intuos M", WACOM_PKGLEN_INTUOSP2, 21600, 13500, 4095, - 63, INTUOSHT3, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x376 = - { "Intuos BT S", WACOM_PKGLEN_INTUOSP2, 15200, 9500, 4095, - 63, INTUOSHT3, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x378 = - { "Intuos BT M", WACOM_PKGLEN_INTUOSP2, 21600, 13500, 4095, - 63, INTUOSHT3, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x37A = - { "Wacom One by Wacom S", WACOM_PKGLEN_BBPEN, 15200, 9500, 2047, 63, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x37B = - { "Wacom One by Wacom M", WACOM_PKGLEN_BBPEN, 21600, 13500, 2047, 63, - BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x37C = - { "Wacom Cintiq Pro 24", WACOM_PKGLEN_MSPRO, 105286, 59574, 8191, 63, /* Pen-only */ - WACOM_MSPRO, 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_0x37D = - { "Wacom DTH-2452", WACOM_PKGLEN_DTH1152, 53104, 30046, 2047, - 0, DTK2451, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, - WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x37E }; -static const struct wacom_features wacom_features_0x37E = - { "Wacom DTH-2452 Touch", WACOM_PKGLEN_MSPROT, - .type = DTH2452T, .touch_max = 10, .oVid = USB_VENDOR_ID_WACOM, - .oPid = 0x37D }; /* Touch */ -static const struct wacom_features wacom_features_0x382 = - { "Wacom DTK-2451", WACOM_PKGLEN_DTH1152, 53104, 30046, 2047, - 0, DTK2451, 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_0x390 = - { "Wacom Cintiq 16", WACOM_PKGLEN_MSPRO, 69632, 39518, 8191, 63, - CINTIQ_16, 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_0x391 = - { "Wacom Cintiq 22", WACOM_PKGLEN_MSPRO, 96012, 54358, 8191, 63, - CINTIQ_16, 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_0x392 = - { "Wacom Intuos Pro S", WACOM_PKGLEN_INTUOSP2, 31920, 19950, 8191, 63, - INTUOSP2S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 10 }; -static const struct wacom_features wacom_features_0x396 = - { "Wacom DTK-1660E", WACOM_PKGLEN_MSPRO, 69632, 39518, 8191, 63, - CINTIQ_16, 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_0x398 = - { "Wacom MobileStudio Pro 13", WACOM_PKGLEN_MSPRO, 59552, 33848, 8191, 63, - WACOM_MSPRO, 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 = 0x39A }; -static const struct wacom_features wacom_features_0x399 = - { "Wacom MobileStudio Pro 16", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 63, - WACOM_MSPRO, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 13, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x39B }; -static const struct wacom_features wacom_features_0x39A = - { "Wacom MobileStudio Pro 13 Touch", WACOM_PKGLEN_MSPROT, /* Touch */ - .type = WACOM_MSPROT, .touch_max = 10, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x398 }; -static const struct wacom_features wacom_features_0x39B = - { "Wacom MobileStudio Pro 16 Touch", WACOM_PKGLEN_MSPROT, /* Touch */ - .type = WACOM_MSPROT, .touch_max = 10, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x399 }; -static const struct wacom_features wacom_features_0x3A6 = - { "Wacom One Pen Display 13", WACOM_PKGLEN_MSPRO, 29434, 16556, 4095, 63, - WACOM_ONE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x3BD = - { "Wacom One Pen Display 13", WACOM_PKGLEN_MSPRO, 29376, 16524, 4095, 63, - WACOM_ONE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x3AA = - { "Wacom MobileStudio Pro 16", WACOM_PKGLEN_MSPRO, 69920, 39680, 8191, 63, - WACOM_MSPRO, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 13, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x3AC }; -static const struct wacom_features wacom_features_0x3AC = - { "Wacom MobileStudio Pro 16 Touch", WACOM_PKGLEN_MSPROT, /* Touch */ - .type = WACOM_MSPROT, .touch_max = 10, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x3AA }; -static const struct wacom_features wacom_features_0x3AE = - { "Wacom Cintiq 16", WACOM_PKGLEN_MSPRO, 69632, 39518, 8191, 63, - CINTIQ_16, 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_0x3B0 = - { "Wacom DTK-1660E", WACOM_PKGLEN_MSPRO, 69632, 39518, 8191, 63, - CINTIQ_16, 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_0x3B2 = - { "Wacom Cintiq Pro 16", WACOM_PKGLEN_MSPRO, 69644, 39524, 8191, 63, - CINTIQ_16, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x3B3 }; -static const struct wacom_features wacom_features_0x3B3 = - { "Wacom Cintiq Pro 16 Touch", WACOM_PKGLEN_MSPROT, /* Touch */ - .type = WACOM_MSPROT, .touch_max = 10, - .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x3B2 }; -static const struct wacom_features wacom_features_0x3C0 = - { "Wacom Cintiq Pro 27", WACOM_PKGLEN_MSPRO, 120032, 67868, 8191, 63, - WACOM_PRO2022, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, - WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; -static const struct wacom_features wacom_features_0x3c5 = - { "Intuos BT S", WACOM_PKGLEN_INTUOSP2, 15200, 9500, 4095, - 63, INTUOSHT3, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x3c7 = - { "Intuos BT M", WACOM_PKGLEN_INTUOSP2, 21600, 13500, 4095, - 63, INTUOSHT3, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; -static const struct wacom_features wacom_features_0x3dc = - { "Wacom Intuos Pro S", WACOM_PKGLEN_INTUOSP2, 31920, 19950, 8191, 63, - INTUOSP2S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 10 }; - -#define USB_DEVICE_WACOM(prod) \ - USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ - .driver_info = (kernel_ulong_t)&wacom_features_##prod - -#define USB_DEVICE_DETAILED(prod, class, sub, proto) \ - USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_WACOM, prod, class, \ - sub, proto), \ - .driver_info = (kernel_ulong_t)&wacom_features_##prod - -#define USB_DEVICE_LENOVO(prod) \ - USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \ - .driver_info = (kernel_ulong_t)&wacom_features_##prod - -const struct usb_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_DETAILED(0x5D, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x5E, USB_CLASS_HID, 0, 0) }, - { 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) }, - { USB_DEVICE_WACOM(0x84) }, - { USB_DEVICE_WACOM(0x90) }, - { USB_DEVICE_WACOM(0x93) }, - { 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) }, - { 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) }, - /* - * DTU-2231 has two interfaces on the same configuration, - * only one is used. - */ - { USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID, - USB_INTERFACE_SUBCLASS_BOOT, - USB_INTERFACE_PROTOCOL_MOUSE) }, - { 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_DETAILED(0xF6, USB_CLASS_HID, 0, 0) }, - { 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_DETAILED(0x302, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x303, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_WACOM(0x304) }, - { USB_DEVICE_WACOM(0x307) }, - { USB_DEVICE_DETAILED(0x309, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_WACOM(0x30A) }, - { USB_DEVICE_WACOM(0x30C) }, - { USB_DEVICE_DETAILED(0x30E, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x314, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x315, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x317, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x323, USB_CLASS_HID, 0, 0) }, - { 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_DETAILED(0x331, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_WACOM(0x333) }, - { USB_DEVICE_WACOM(0x335) }, - { USB_DEVICE_WACOM(0x336) }, - { USB_DEVICE_DETAILED(0x33B, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x33C, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x33D, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x33E, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_WACOM(0x343) }, - { USB_DEVICE_WACOM(0x34A) }, - { USB_DEVICE_WACOM(0x34B) }, - { USB_DEVICE_WACOM(0x34D) }, - { USB_DEVICE_WACOM(0x34E) }, - { USB_DEVICE_WACOM(0x34F) }, - { USB_DEVICE_WACOM(0x350) }, - { USB_DEVICE_WACOM(0x351) }, - { USB_DEVICE_WACOM(0x352) }, - { USB_DEVICE_WACOM(0x353) }, - { USB_DEVICE_WACOM(0x354) }, - { USB_DEVICE_WACOM(0x355) }, - { USB_DEVICE_WACOM(0x356) }, - { USB_DEVICE_DETAILED(0x357, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x358, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_WACOM(0x359) }, - { USB_DEVICE_WACOM(0x35A) }, - { USB_DEVICE_WACOM(0x368) }, - { USB_DEVICE_WACOM(0x374) }, - { USB_DEVICE_WACOM(0x375) }, - { USB_DEVICE_WACOM(0x376) }, - { USB_DEVICE_WACOM(0x378) }, - { USB_DEVICE_WACOM(0x37A) }, - { USB_DEVICE_WACOM(0x37B) }, - { USB_DEVICE_WACOM(0x37C) }, - { USB_DEVICE_WACOM(0x37D) }, - { USB_DEVICE_WACOM(0x37E) }, - { USB_DEVICE_WACOM(0x382) }, - { USB_DEVICE_DETAILED(0x390, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x391, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x392, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x396, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_WACOM(0x398) }, - { USB_DEVICE_WACOM(0x399) }, - { USB_DEVICE_WACOM(0x39A) }, - { USB_DEVICE_WACOM(0x39B) }, - { USB_DEVICE_WACOM(0x3A6) }, - { USB_DEVICE_WACOM(0x3AA) }, - { USB_DEVICE_WACOM(0x3AC) }, - { USB_DEVICE_DETAILED(0x3AE, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_DETAILED(0x3B0, USB_CLASS_HID, 0, 0) }, - { USB_DEVICE_WACOM(0x3B2) }, - { USB_DEVICE_WACOM(0x3B3) }, - { USB_DEVICE_WACOM(0x3BD) }, - { USB_DEVICE_WACOM(0x3C0) }, - { USB_DEVICE_WACOM(0x3c5) }, - { USB_DEVICE_WACOM(0x3c7) }, - { USB_DEVICE_WACOM(0x3dc) }, - { USB_DEVICE_WACOM(0x4001) }, - { USB_DEVICE_WACOM(0x4004) }, - { USB_DEVICE_WACOM(0x5000) }, - { USB_DEVICE_WACOM(0x5002) }, - { USB_DEVICE_WACOM(0x5010) }, - { USB_DEVICE_WACOM(0x5013) }, - { USB_DEVICE_WACOM(0x5044) }, - { USB_DEVICE_WACOM(0x5048) }, - { USB_DEVICE_WACOM(0x5090) }, - { USB_DEVICE_LENOVO(0x6004) }, - { } -}; -MODULE_DEVICE_TABLE(usb, wacom_ids); diff --git a/3.7/wacom_wac.h b/3.7/wacom_wac.h deleted file mode 100644 index fc5de948..00000000 --- a/3.7/wacom_wac.h +++ /dev/null @@ -1,229 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifndef WACOM_WAC_H -#define WACOM_WAC_H - -#include - -/* maximum packet length for USB devices */ -#define WACOM_PKGLEN_MAX 192 - -#define WACOM_NAME_MAX 64 -#define WACOM_MAX_REMOTES 5 -#define WACOM_STATUS_UNKNOWN 255 - -/* packet length for individual models */ -#define WACOM_PKGLEN_PENPRTN 7 -#define WACOM_PKGLEN_GRAPHIRE 8 -#define WACOM_PKGLEN_BBFUN 9 -#define WACOM_PKGLEN_INTUOS 10 -#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_MTOUCH 62 -#define WACOM_PKGLEN_MTTPC 40 -#define WACOM_PKGLEN_DTUS 68 -#define WACOM_PKGLEN_PENABLED 8 -#define WACOM_PKGLEN_27QHDT 64 -#define WACOM_PKGLEN_MSPRO 64 -#define WACOM_PKGLEN_MSPROT 50 -#define WACOM_PKGLEN_INTUOSP2 64 -#define WACOM_PKGLEN_INTUOSP2T 44 -#define WACOM_PKGLEN_DTH1152 12 - -/* 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 -#define WACOM_BYTES_PER_MSPROT_PACKET 9 -#define WACOM_BYTES_PER_INTUOSP2_PACKET 8 - -/* 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_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_MSPRO 16 -#define WACOM_REPORT_PRO2022 30 -#define WACOM_REPORT_INTUOS_PEN 16 -#define WACOM_REPORT_CINTIQPAD 17 -#define WACOM_REPORT_TPCST 16 -#define WACOM_REPORT_DTUS 17 -#define WACOM_REPORT_MSPROPAD 17 -#define WACOM_REPORT_TPC1FGE 18 -#define WACOM_REPORT_MSPRODEVICE 19 -#define WACOM_REPORT_DTK2451PAD 21 -#define WACOM_REPORT_24HDT 1 -#define WACOM_REPORT_WL 128 -#define WACOM_REPORT_USB 192 -#define WACOM_REPORT_DEVICE_LIST 16 -#define WACOM_REPORT_REMOTE 17 -#define WACOM_REPORT_VENDOR_DEF_TOUCH 33 -#define WAC_CMD_LED_CONTROL_GENERIC 50 - -/* device quirks */ -#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 -#define WACOM_QUIRK_NO_INPUT 0x0002 -#define WACOM_QUIRK_MONITOR 0x0004 -#define WACOM_QUIRK_BATTERY 0x0008 - -#ifndef BTN_STYLUS3 -#define BTN_STYLUS3 0x149 -#endif - -#ifndef MSC_TIMESTAMP -#define MSC_TIMESTAMP 0x05 -#endif - -#define WACOM_INTUOSP2_RING_UNTOUCHED 0x7f -#define WACOM_POWER_SUPPLY_STATUS_AUTO -1 -enum { - PENPARTNER = 0, - GRAPHIRE, - WACOM_G4, - PTU, - PL, - DTU, - DTUS, - DTUS2, - DTUSX, - DTH1152, - DTK2451, - INTUOS, - INTUOS3S, - INTUOS3, - INTUOS3L, - INTUOS4S, - INTUOS4, - INTUOS4L, - INTUOS5S, - INTUOS5, - INTUOS5L, - INTUOSPS, - INTUOSPM, - INTUOSPL, - WACOM_21UX2, - WACOM_22HD, - DTK, - WACOM_24HD, - WACOM_27QHD, - CINTIQ_HYBRID, - CINTIQ_COMPANION_2, - WACOM_MSPRO, - CINTIQ_16, - WACOM_PRO2022, - WACOM_ONE, - CINTIQ, - WACOM_BEE, - WACOM_13HD, - WACOM_MO, - INTUOSHT, - INTUOSHT2, - BAMBOO_PT, - WACOM_24HDT, - WACOM_27QHDT, - WACOM_MSPROT, - DTH1152T, - INTUOSP2, - INTUOSP2S, - INTUOSHT3, - WIRELESS, - REMOTE, - TABLETPC, /* add new TPC below */ - TABLETPCE, - TABLETPC2FG, - DTH2452T, - MTSCREEN, - MTTPC, - MTTPC_B, - MTTPC_C, - MAX_TYPE -}; - -struct wacom_features { - const char *name; - int pktlen; - 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; - unsigned short sequence_number; -}; - -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; - bool has_mute_touch_switch; - bool is_touch_on; -}; - -struct wacom_remote_data { - struct { - u32 serial; - bool connected; - } remote[WACOM_MAX_REMOTES]; -}; - -struct wacom_wac { - char name[WACOM_NAME_MAX]; - unsigned char *data; - int tool[2]; - int id[2]; - __u32 serial[2]; - bool reporting_data; - struct wacom_features features; - struct wacom_shared *shared; - struct input_dev *input; - int pid; - int num_contacts_left; - int previous_buttons; - int previous_ring; - int previous_keys; -}; - -#endif diff --git a/Makefile.am b/Makefile.am index 95e4fe71..ef550533 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS = @WCM_KERNEL_VER@ -DIST_SUBDIRS = 3.7 3.17 4.5 +DIST_SUBDIRS = 3.17 4.5 EXTRA_DIST = git-version-gen \ inputattach/inputattach.c inputattach/README \ inputattach/serio-ids.h diff --git a/configure.ac b/configure.ac index ea8f8ae0..6f8b4c4e 100644 --- a/configure.ac +++ b/configure.ac @@ -290,12 +290,10 @@ 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.7)"; then - AC_MSG_ERROR(m4_normalize([Kernels older than 3.7 are no longer supported by input-wacom. +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. For newer Wacom models, please upgrade your system to a newer kernel. - For old Wacom models, 'input-wacom-0.47.0' may still support the device])) -elif test "$EXPLODED_VER" -lt "WCM_EXPLODE(3.17)"; then - WCM_KERNEL_VER="3.7" + 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" else @@ -461,7 +459,6 @@ AC_SUBST(MODSIGN_PRIVFILE) AC_SUBST(MODSIGN_CERTFILE) AC_CONFIG_FILES([Makefile - 3.7/Makefile 3.17/Makefile 4.5/Makefile]) AC_OUTPUT From 6f75654b285db1404f1b39ee12646e2e9816fb5a Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 29 Aug 2023 13:10:05 -0700 Subject: [PATCH 2/6] github: Run 'apt-get update' before 'apt-get install' Ensure we have an up-to-date version of the package index before trying to install packages. Otherwise we may try to install an outdated version of something that has been deleted from Ubuntu's servers. Signed-off-by: Jason Gerecke --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b79cc311..78b7c1f9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,6 +42,7 @@ jobs: steps: - name: Install dependencies run: | + sudo apt-get update sudo apt-get install gcc-9-plugin-dev libelf-dev gcc -print-file-name=plugin From ddbd324919394829513ed50f205b1c897dffd95f Mon Sep 17 00:00:00 2001 From: Aaron Armstrong Skomra Date: Tue, 25 Jul 2023 15:20:25 -0700 Subject: [PATCH 3/6] HID: wacom: remove the battery when the EKR is off Currently the EKR battery remains even after we stop getting information from the device. This can lead to a stale battery persisting indefinitely in userspace. The remote sends a heartbeat every 10 seconds. Delete the battery if we miss two heartbeats (after 21 seconds). Restore the battery once we see a heartbeat again. Signed-off-by: Aaron Skomra Signed-off-by: Aaron Armstrong Skomra Reviewed-by: Jason Gerecke Fixes: 9f1015d45f62 ("HID: wacom: EKR: attach the power_supply on first connection") CC: stable@vger.kernel.org Signed-off-by: Jiri Kosina [joshua.dickens@wacom.com: Imported into input-wacom repository (9ac6678b95b0)] Signed-off-by: Joshua Dickens --- .github/workflows/main.yml | 5 ++++- 4.5/wacom.h | 3 +++ 4.5/wacom_sys.c | 34 ++++++++++++++++++++++++++++++++++ 4.5/wacom_wac.c | 3 +++ 4.5/wacom_wac.h | 2 ++ 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5866f8e4..6ae48394 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - kernel: ["6.3", "5.10", "4.14", "4.6", "4.5", "4.1", "3.19", "3.18", "3.17"] + kernel: ["6.3", "5.10", "4.14", "4.10", "4.6", "4.5", "4.1", "3.19", "3.18", "3.17"] include: - kernel: "3.17" compile_cflags: -fno-pie -Wno-error=format-truncation @@ -29,6 +29,9 @@ jobs: - 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: "5.10" diff --git a/4.5/wacom.h b/4.5/wacom.h index ba58f88f..a259469b 100644 --- a/4.5/wacom.h +++ b/4.5/wacom.h @@ -166,6 +166,9 @@ 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]; }; diff --git a/4.5/wacom_sys.c b/4.5/wacom_sys.c index 044f53f9..5e186345 100644 --- a/4.5/wacom_sys.c +++ b/4.5/wacom_sys.c @@ -2585,6 +2585,20 @@ 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; + + if (remote->remotes[index].battery.battery) { + devres_release_group(&wacom->hdev->dev, + &remote->remotes[index].battery.bat_desc); + remote->remotes[index].battery.battery = NULL; + remote->remotes[index].active_time = 0; + } +} +#endif + static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index) { struct wacom_remote *remote = wacom->remote; @@ -2599,9 +2613,13 @@ 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, @@ -2609,7 +2627,9 @@ 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; } } @@ -2694,6 +2714,11 @@ 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; @@ -2709,6 +2734,9 @@ 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_data data; unsigned long flags; unsigned int count; @@ -2735,6 +2763,12 @@ static void wacom_remote_work(struct work_struct *work) serial = data.remote[i].serial; if (data.remote[i].connected) { +#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 == serial) { wacom_remote_attach_battery(wacom, i); continue; diff --git a/4.5/wacom_wac.c b/4.5/wacom_wac.c index 68c2f3ae..792b1329 100644 --- a/4.5/wacom_wac.c +++ b/4.5/wacom_wac.c @@ -1144,6 +1144,9 @@ 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)); diff --git a/4.5/wacom_wac.h b/4.5/wacom_wac.h index 67a6dbe5..6fbb40a9 100644 --- a/4.5/wacom_wac.h +++ b/4.5/wacom_wac.h @@ -8,6 +8,7 @@ #include #include #include +#include /* maximum packet length for USB/BT devices */ #define WACOM_PKGLEN_MAX 361 @@ -15,6 +16,7 @@ #define WACOM_NAME_MAX 64 #define WACOM_MAX_REMOTES 5 #define WACOM_STATUS_UNKNOWN 255 +#define WACOM_REMOTE_BATTERY_TIMEOUT 21000000000ll /* packet length for individual models */ #define WACOM_PKGLEN_BBFUN 9 From 891bf700ea9d91f76af4f4f89248bb8175d228e6 Mon Sep 17 00:00:00 2001 From: Aaron Armstrong Skomra Date: Tue, 25 Jul 2023 15:20:57 -0700 Subject: [PATCH 4/6] HID: wacom: remove unnecessary 'connected' variable from EKR The 'connected' variable was poorly named, and this has led to some confusion. We can get the same information by checking if a serial number exists in the specified EKR slot. Signed-off-by: Aaron Skomra Signed-off-by: Aaron Armstrong Skomra Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina [joshua.dickens@wacom.com: Imported into input-wacom repository (2834e38048f1)] Signed-off-by: Joshua Dickens --- 4.5/wacom_sys.c | 2 +- 4.5/wacom_wac.c | 2 -- 4.5/wacom_wac.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/4.5/wacom_sys.c b/4.5/wacom_sys.c index 5e186345..37f55114 100644 --- a/4.5/wacom_sys.c +++ b/4.5/wacom_sys.c @@ -2761,7 +2761,7 @@ static void wacom_remote_work(struct work_struct *work) for (i = 0; i < WACOM_MAX_REMOTES; i++) { serial = data.remote[i].serial; - if (data.remote[i].connected) { + if (serial) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) if (kt - remote->remotes[i].active_time > WACOM_REMOTE_BATTERY_TIMEOUT diff --git a/4.5/wacom_wac.c b/4.5/wacom_wac.c index 792b1329..37fae55b 100644 --- a/4.5/wacom_wac.c +++ b/4.5/wacom_wac.c @@ -1221,10 +1221,8 @@ static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len) 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); diff --git a/4.5/wacom_wac.h b/4.5/wacom_wac.h index 6fbb40a9..fd46a403 100644 --- a/4.5/wacom_wac.h +++ b/4.5/wacom_wac.h @@ -360,7 +360,6 @@ struct hid_data { struct wacom_remote_data { struct { u32 serial; - bool connected; } remote[WACOM_MAX_REMOTES]; }; From f965820a6161ce12698141ca03f2d0ac6089039e Mon Sep 17 00:00:00 2001 From: Aaron Armstrong Skomra Date: Thu, 31 Aug 2023 12:30:44 -0700 Subject: [PATCH 5/6] HID: wacom: struct name cleanup Help differentiate the two remote related "serial" struct variables by renaming "wacom_remote_data" to "wacom_remote_work_data". Signed-off-by: Aaron Skomra Signed-off-by: Aaron Armstrong Skomra Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina [joshua.dickens@wacom.com: Imported into input-wacom repository (55ab9b2c42f4)] Signed-off-by: Joshua Dickens --- 4.5/wacom_sys.c | 19 ++++++++++--------- 4.5/wacom_wac.c | 4 ++-- 4.5/wacom_wac.h | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/4.5/wacom_sys.c b/4.5/wacom_sys.c index 37f55114..d98375c3 100644 --- a/4.5/wacom_sys.c +++ b/4.5/wacom_sys.c @@ -2059,7 +2059,7 @@ static int wacom_initialize_remotes(struct wacom *wacom) spin_lock_init(&remote->remote_lock); error = kfifo_alloc(&remote->remote_fifo, - 5 * sizeof(struct wacom_remote_data), + 5 * sizeof(struct wacom_remote_work_data), GFP_KERNEL); if (error) { hid_err(wacom->hdev, "failed allocating remote_fifo\n"); @@ -2737,17 +2737,18 @@ static void wacom_remote_work(struct work_struct *work) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) ktime_t kt = ktime_get(); #endif - struct wacom_remote_data data; + struct wacom_remote_work_data remote_work_data; unsigned long flags; unsigned int count; - u32 serial; + u32 work_serial; int i; spin_lock_irqsave(&remote->remote_lock, flags); - count = kfifo_out(&remote->remote_fifo, &data, sizeof(data)); + count = kfifo_out(&remote->remote_fifo, &remote_work_data, + sizeof(remote_work_data)); - if (count != sizeof(data)) { + if (count != sizeof(remote_work_data)) { hid_err(wacom->hdev, "workitem triggered without status available\n"); spin_unlock_irqrestore(&remote->remote_lock, flags); @@ -2760,8 +2761,8 @@ static void wacom_remote_work(struct work_struct *work) spin_unlock_irqrestore(&remote->remote_lock, flags); for (i = 0; i < WACOM_MAX_REMOTES; i++) { - serial = data.remote[i].serial; - if (serial) { + 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 @@ -2769,7 +2770,7 @@ static void wacom_remote_work(struct work_struct *work) wacom_remote_destroy_battery(wacom, i); #endif - if (remote->remotes[i].serial == serial) { + if (remote->remotes[i].serial == work_serial) { wacom_remote_attach_battery(wacom, i); continue; } @@ -2777,7 +2778,7 @@ static void wacom_remote_work(struct work_struct *work) if (remote->remotes[i].serial) wacom_remote_destroy_one(wacom, i); - wacom_remote_create_one(wacom, serial, i); + wacom_remote_create_one(wacom, work_serial, i); } else if (remote->remotes[i].serial) { wacom_remote_destroy_one(wacom, i); diff --git a/4.5/wacom_wac.c b/4.5/wacom_wac.c index 37fae55b..9fb007ac 100644 --- a/4.5/wacom_wac.c +++ b/4.5/wacom_wac.c @@ -1209,14 +1209,14 @@ 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; + struct wacom_remote_work_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)); + memset(&remote_data, 0, sizeof(struct wacom_remote_work_data)); for (i = 0; i < WACOM_MAX_REMOTES; i++) { int j = i * 6; diff --git a/4.5/wacom_wac.h b/4.5/wacom_wac.h index fd46a403..a7c5c75a 100644 --- a/4.5/wacom_wac.h +++ b/4.5/wacom_wac.h @@ -357,7 +357,7 @@ struct hid_data { #endif }; -struct wacom_remote_data { +struct wacom_remote_work_data { struct { u32 serial; } remote[WACOM_MAX_REMOTES]; From 119814e55db8179f88a81b6fef063093f1483466 Mon Sep 17 00:00:00 2001 From: Joshua Dickens Date: Thu, 31 Aug 2023 13:23:54 -0700 Subject: [PATCH 6/6] Updating main.yml with some extra versions to check Adding some versions to check compilation on for any version checks/flags we have setup in the code. 4.19 - For a check in 4.5/wacom_sys.c in wacom_map_usage for the compare_device_paths method. 4.2 - For a method in 3.17/wacom_sys.c hid_field_extract. --- .github/workflows/main.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6ae48394..c049871d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - kernel: ["6.3", "5.10", "4.14", "4.10", "4.6", "4.5", "4.1", "3.19", "3.18", "3.17"] + 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"] include: - kernel: "3.17" compile_cflags: -fno-pie -Wno-error=format-truncation @@ -23,6 +23,9 @@ jobs: - 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 @@ -34,6 +37,8 @@ jobs: 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.10" compile_cflags: -Wno-error=format-truncation -Wno-error=pointer-sign - kernel: "6.3"