Commit 8de29a35 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

Pull HID updates from Jiri Kosina:

 - quite a few firmware fixes for RMI driver by Andrew Duggan

 - huion and uclogic drivers have been substantially overlaping in
   functionality laterly.  This redundancy is fixed by hid-huion driver
   being merged into hid-uclogic; work done by Benjamin Tissoires and
   Nikolai Kondrashov

 - i2c-hid now supports ACPI GPIO interrupts; patch from Mika Westerberg

 - Some of the quirks, that got separated into individual drivers, have
   historically had EXPERT dependency.  As HID subsystem matured (as
   well as the individual drivers), this made less and less sense.  This
   dependency is now being removed by patch from Jean Delvare

 - Logitech lg4ff driver received a couple of improvements for mode
   switching, by Michal Malý

 - multitouch driver now supports clickpads, patches by Benjamin
   Tissoires and Seth Forshee

 - hid-sensor framework received a substantial update; namely support
   for Custom and Generic pages is being added; work done by Srinivas
   Pandruvada

 - wacom driver received substantial update; it now supports
   i2c-conntected devices (Mika Westerberg), Bamboo PADs are now
   properly supported (Benjamin Tissoires), much improved battery
   reporting (Jason Gerecke) and pen proximity cleanups (Ping Cheng)

 - small assorted fixes and device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (68 commits)
  HID: sensor: Update document for custom sensor
  HID: sensor: Custom and Generic sensor support
  HID: debug: fix error handling in hid_debug_events_read()
  Input - mt: Fix input_mt_get_slot_by_key
  HID: logitech-hidpp: fix error return code
  HID: wacom: Add support for Cintiq 13HD Touch
  HID: logitech-hidpp: add a module parameter to keep firmware gestures
  HID: usbhid: yet another mouse with ALWAYS_POLL
  HID: usbhid: more mice with ALWAYS_POLL
  HID: wacom: set stylus_in_proximity before checking touch_down
  HID: wacom: use wacom_wac_finger_count_touches to set touch_down
  HID: wacom: remove hardcoded WACOM_QUIRK_MULTI_INPUT
  HID: pidff: effect can't be NULL
  HID: add quirk for PIXART OEM mouse used by HP
  HID: add HP OEM mouse to quirk ALWAYS_POLL
  HID: wacom: ask for a in-prox report when it was missed
  HID: hid-sensor-hub: Fix sparse warning
  HID: hid-sensor-hub: fix attribute read for logical usage id
  HID: plantronics: fix Kconfig default
  HID: pidff: support more than one concurrent effect
  ...
parents 31f7dc79 2e455c27
...@@ -8,3 +8,13 @@ Description: When read, this file returns the device's raw binary HID ...@@ -8,3 +8,13 @@ Description: When read, this file returns the device's raw binary HID
report descriptor. report descriptor.
This file cannot be written. This file cannot be written.
Users: HIDAPI library (http://www.signal11.us/oss/hidapi) Users: HIDAPI library (http://www.signal11.us/oss/hidapi)
What: For USB devices : /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
For BT devices : /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
Symlink : /sys/class/hidraw/hidraw<num>/device/country
Date: February 2015
KernelVersion: 3.19
Contact: Olivier Gay <ogay@logitech.com>
Description: When read, this file returns the hex integer value in ASCII
of the device's HID country code (e.g. 21 for US).
This file cannot be written.
...@@ -5,3 +5,48 @@ Contact: Michal Malý <madcatxster@gmail.com> ...@@ -5,3 +5,48 @@ Contact: Michal Malý <madcatxster@gmail.com>
Description: Display minimum, maximum and current range of the steering Description: Display minimum, maximum and current range of the steering
wheel. Writing a value within min and max boundaries sets the wheel. Writing a value within min and max boundaries sets the
range of the wheel. range of the wheel.
What: /sys/bus/hid/drivers/logitech/<dev>/alternate_modes
Date: Feb 2015
KernelVersion: 4.1
Contact: Michal Malý <madcatxster@gmail.com>
Description: Displays a set of alternate modes supported by a wheel. Each
mode is listed as follows:
Tag: Mode Name
Currently active mode is marked with an asterisk. List also
contains an abstract item "native" which always denotes the
native mode of the wheel. Echoing the mode tag switches the
wheel into the corresponding mode. Depending on the exact model
of the wheel not all listed modes might always be selectable.
If a wheel cannot be switched into the desired mode, -EINVAL
is returned accompanied with an explanatory message in the
kernel log.
This entry is not created for devices that have only one mode.
Currently supported mode switches:
Driving Force Pro:
DF-EX --> DFP
G25:
DF-EX --> DFP --> G25
G27:
DF-EX <*> DFP <-> G25 <-> G27
DF-EX <*--------> G25 <-> G27
DF-EX <*----------------> G27
DFGT:
DF-EX <*> DFP <-> DFGT
DF-EX <*--------> DFGT
* hid_logitech module must be loaded with lg4ff_no_autoswitch=1
parameter set in order for the switch to DF-EX mode to work.
What: /sys/bus/hid/drivers/logitech/<dev>/real_id
Date: Feb 2015
KernelVersion: 4.1
Contact: Michal Malý <madcatxster@gmail.com>
Description: Displays the real model of the wheel regardless of any
alternate mode the wheel might be switched to.
It is a read-only value.
This entry is not created for devices that have only one mode.
...@@ -138,3 +138,87 @@ accelerometer wants to poll X axis value, then it can call this function with ...@@ -138,3 +138,87 @@ accelerometer wants to poll X axis value, then it can call this function with
the usage id of X axis. HID sensors can provide events, so this is not necessary the usage id of X axis. HID sensors can provide events, so this is not necessary
to poll for any field. If there is some new sample, the core driver will call to poll for any field. If there is some new sample, the core driver will call
registered callback function to process the sample. registered callback function to process the sample.
----------
HID Custom and generic Sensors
HID Sensor specification defines two special sensor usage types. Since they
don't represent a standard sensor, it is not possible to define using Linux IIO
type interfaces.
The purpose of these sensors is to extend the functionality or provide a
way to obfuscate the data being communicated by a sensor. Without knowing the
mapping between the data and its encapsulated form, it is difficult for
an application/driver to determine what data is being communicated by the sensor.
This allows some differentiating use cases, where vendor can provide applications.
Some common use cases are debug other sensors or to provide some events like
keyboard attached/detached or lid open/close.
To allow application to utilize these sensors, here they are exported uses sysfs
attribute groups, attributes and misc device interface.
An example of this representation on sysfs:
/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
.
????????? enable_sensor
????????? feature-0-200316
??????? ????????? feature-0-200316-maximum
??????? ????????? feature-0-200316-minimum
??????? ????????? feature-0-200316-name
??????? ????????? feature-0-200316-size
??????? ????????? feature-0-200316-unit-expo
??????? ????????? feature-0-200316-units
??????? ????????? feature-0-200316-value
????????? feature-1-200201
??????? ????????? feature-1-200201-maximum
??????? ????????? feature-1-200201-minimum
??????? ????????? feature-1-200201-name
??????? ????????? feature-1-200201-size
??????? ????????? feature-1-200201-unit-expo
??????? ????????? feature-1-200201-units
??????? ????????? feature-1-200201-value
????????? input-0-200201
??????? ????????? input-0-200201-maximum
??????? ????????? input-0-200201-minimum
??????? ????????? input-0-200201-name
??????? ????????? input-0-200201-size
??????? ????????? input-0-200201-unit-expo
??????? ????????? input-0-200201-units
??????? ????????? input-0-200201-value
????????? input-1-200202
??????? ????????? input-1-200202-maximum
??????? ????????? input-1-200202-minimum
??????? ????????? input-1-200202-name
??????? ????????? input-1-200202-size
??????? ????????? input-1-200202-unit-expo
??????? ????????? input-1-200202-units
??????? ????????? input-1-200202-value
Here there is a custom sensors with four fields, two feature and two inputs.
Each field is represented by a set of attributes. All fields except the "value"
are read only. The value field is a RW field.
Example
/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
feature-0-200316-maximum:6
feature-0-200316-minimum:0
feature-0-200316-name:property-reporting-state
feature-0-200316-size:1
feature-0-200316-unit-expo:0
feature-0-200316-units:25
feature-0-200316-value:1
How to enable such sensor?
By default sensor can be power gated. To enable sysfs attribute "enable" can be
used.
$ echo 1 > enable_sensor
Once enabled and powered on, sensor can report value using HID reports.
These reports are pushed using misc device interface in a FIFO order.
/dev$ tree | grep HID-SENSOR-2000e1.6.auto
??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto
????????? HID-SENSOR-2000e1.6.auto
Each reports can be of variable length preceded by a header. This header
consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
data.
...@@ -92,7 +92,7 @@ menu "Special HID drivers" ...@@ -92,7 +92,7 @@ menu "Special HID drivers"
depends on HID depends on HID
config HID_A4TECH config HID_A4TECH
tristate "A4 tech mice" if EXPERT tristate "A4 tech mice"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -113,7 +113,7 @@ config HID_ACRUX_FF ...@@ -113,7 +113,7 @@ config HID_ACRUX_FF
game controllers. game controllers.
config HID_APPLE config HID_APPLE
tristate "Apple {i,Power,Mac}Books" if EXPERT tristate "Apple {i,Power,Mac}Books"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -141,7 +141,7 @@ config HID_AUREAL ...@@ -141,7 +141,7 @@ config HID_AUREAL
Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes. Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
config HID_BELKIN config HID_BELKIN
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT tristate "Belkin Flip KVM and Wireless keyboard"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -158,14 +158,14 @@ config HID_BETOP_FF ...@@ -158,14 +158,14 @@ config HID_BETOP_FF
- BETOP 2185 PC & BFM MODE - BETOP 2185 PC & BFM MODE
config HID_CHERRY config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT tristate "Cherry Cymotion keyboard"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Cherry Cymotion keyboard. Support for Cherry Cymotion keyboard.
config HID_CHICONY config HID_CHICONY
tristate "Chicony Tactical pad" if EXPERT tristate "Chicony Tactical pad"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -196,7 +196,7 @@ config HID_CP2112 ...@@ -196,7 +196,7 @@ config HID_CP2112
customizable USB descriptor fields are exposed as sysfs attributes. customizable USB descriptor fields are exposed as sysfs attributes.
config HID_CYPRESS config HID_CYPRESS
tristate "Cypress mouse and barcode readers" if EXPERT tristate "Cypress mouse and barcode readers"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -245,7 +245,7 @@ config HID_ELO ...@@ -245,7 +245,7 @@ config HID_ELO
different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO. different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO.
config HID_EZKEY config HID_EZKEY
tristate "Ezkey BTC 8193 keyboard" if EXPERT tristate "Ezkey BTC 8193 keyboard"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -286,12 +286,6 @@ config HID_GT683R ...@@ -286,12 +286,6 @@ config HID_GT683R
Currently the following devices are know to be supported: Currently the following devices are know to be supported:
- MSI GT683R - MSI GT683R
config HID_HUION
tristate "Huion tablets"
depends on USB_HID
---help---
Support for Huion 580 tablet.
config HID_KEYTOUCH config HID_KEYTOUCH
tristate "Keytouch HID devices" tristate "Keytouch HID devices"
depends on HID depends on HID
...@@ -312,9 +306,9 @@ config HID_KYE ...@@ -312,9 +306,9 @@ config HID_KYE
config HID_UCLOGIC config HID_UCLOGIC
tristate "UC-Logic" tristate "UC-Logic"
depends on HID depends on USB_HID
---help--- ---help---
Support for UC-Logic tablets. Support for UC-Logic and Huion tablets.
config HID_WALTOP config HID_WALTOP
tristate "Waltop" tristate "Waltop"
...@@ -344,7 +338,7 @@ config HID_TWINHAN ...@@ -344,7 +338,7 @@ config HID_TWINHAN
Support for Twinhan IR remote control. Support for Twinhan IR remote control.
config HID_KENSINGTON config HID_KENSINGTON
tristate "Kensington Slimblade Trackball" if EXPERT tristate "Kensington Slimblade Trackball"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -372,7 +366,7 @@ config HID_LENOVO ...@@ -372,7 +366,7 @@ config HID_LENOVO
- ThinkPad Compact USB Keyboard with TrackPoint (supports Fn keys) - ThinkPad Compact USB Keyboard with TrackPoint (supports Fn keys)
config HID_LOGITECH config HID_LOGITECH
tristate "Logitech devices" if EXPERT tristate "Logitech devices"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -461,14 +455,14 @@ config HID_MAGICMOUSE ...@@ -461,14 +455,14 @@ config HID_MAGICMOUSE
Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad. Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad.
config HID_MICROSOFT config HID_MICROSOFT
tristate "Microsoft non-fully HID-compliant devices" if EXPERT tristate "Microsoft non-fully HID-compliant devices"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Microsoft devices that are not fully compliant with HID standard. Support for Microsoft devices that are not fully compliant with HID standard.
config HID_MONTEREY config HID_MONTEREY
tristate "Monterey Genius KB29E keyboard" if EXPERT tristate "Monterey Genius KB29E keyboard"
depends on HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
...@@ -638,7 +632,6 @@ config HID_PICOLCD_CIR ...@@ -638,7 +632,6 @@ config HID_PICOLCD_CIR
config HID_PLANTRONICS config HID_PLANTRONICS
tristate "Plantronics USB HID Driver" tristate "Plantronics USB HID Driver"
default !EXPERT
depends on HID depends on HID
---help--- ---help---
Provides HID support for Plantronics telephony devices. Provides HID support for Plantronics telephony devices.
...@@ -885,6 +878,21 @@ config HID_SENSOR_HUB ...@@ -885,6 +878,21 @@ config HID_SENSOR_HUB
for events and handle data streams. Each sensor driver can format for events and handle data streams. Each sensor driver can format
data and present to user mode using input or IIO interface. data and present to user mode using input or IIO interface.
config HID_SENSOR_CUSTOM_SENSOR
tristate "HID Sensors hub custom sensor support"
depends on HID_SENSOR_HUB
default n
---help---
HID Sensor hub specification allows definition of some custom and
generic sensors. Unlike other HID sensors, they can't be exported
via Linux IIO because of custom fields. This is up to the manufacturer
to decide how to interpret these special sensor ids and process in
the user space. Currently some manufacturers are using these ids for
sensor calibration and debugging other sensors. Manufacturers
should't use these special custom sensor ids to export any of the
standard sensors.
Select this config option for custom/generic sensor support.
endmenu endmenu
endif # HID endif # HID
......
...@@ -41,7 +41,6 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o ...@@ -41,7 +41,6 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
obj-$(CONFIG_HID_HUION) += hid-huion.o
obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
obj-$(CONFIG_HID_ICADE) += hid-icade.o obj-$(CONFIG_HID_ICADE) += hid-icade.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
...@@ -101,6 +100,7 @@ obj-$(CONFIG_HID_WACOM) += wacom.o ...@@ -101,6 +100,7 @@ obj-$(CONFIG_HID_WACOM) += wacom.o
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o
obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/
......
...@@ -1562,12 +1562,26 @@ read_report_descriptor(struct file *filp, struct kobject *kobj, ...@@ -1562,12 +1562,26 @@ read_report_descriptor(struct file *filp, struct kobject *kobj,
return count; return count;
} }
static ssize_t
show_country(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
return sprintf(buf, "%02x\n", hdev->country & 0xff);
}
static struct bin_attribute dev_bin_attr_report_desc = { static struct bin_attribute dev_bin_attr_report_desc = {
.attr = { .name = "report_descriptor", .mode = 0444 }, .attr = { .name = "report_descriptor", .mode = 0444 },
.read = read_report_descriptor, .read = read_report_descriptor,
.size = HID_MAX_DESCRIPTOR_SIZE, .size = HID_MAX_DESCRIPTOR_SIZE,
}; };
static struct device_attribute dev_attr_country = {
.attr = { .name = "country", .mode = 0444 },
.show = show_country,
};
int hid_connect(struct hid_device *hdev, unsigned int connect_mask) int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
{ {
static const char *types[] = { "Device", "Pointer", "Mouse", "Device", static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
...@@ -1646,6 +1660,11 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) ...@@ -1646,6 +1660,11 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
bus = "<UNKNOWN>"; bus = "<UNKNOWN>";
} }
ret = device_create_file(&hdev->dev, &dev_attr_country);
if (ret)
hid_warn(hdev,
"can't create sysfs country code attribute err: %d\n", ret);
ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc); ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (ret) if (ret)
hid_warn(hdev, hid_warn(hdev,
...@@ -1661,6 +1680,7 @@ EXPORT_SYMBOL_GPL(hid_connect); ...@@ -1661,6 +1680,7 @@ EXPORT_SYMBOL_GPL(hid_connect);
void hid_disconnect(struct hid_device *hdev) void hid_disconnect(struct hid_device *hdev)
{ {
device_remove_file(&hdev->dev, &dev_attr_country);
device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc); device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (hdev->claimed & HID_CLAIMED_INPUT) if (hdev->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hdev); hidinput_disconnect(hdev);
...@@ -1824,6 +1844,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1824,6 +1844,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
#if IS_ENABLED(CONFIG_HID_LENOVO) #if IS_ENABLED(CONFIG_HID_LENOVO)
......
...@@ -165,6 +165,7 @@ static const struct hid_usage_entry hid_usage_table[] = { ...@@ -165,6 +165,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x53, "DeviceIndex"}, {0, 0x53, "DeviceIndex"},
{0, 0x54, "ContactCount"}, {0, 0x54, "ContactCount"},
{0, 0x55, "ContactMaximumNumber"}, {0, 0x55, "ContactMaximumNumber"},
{0, 0x59, "ButtonType"},
{0, 0x5A, "SecondaryBarrelSwitch"}, {0, 0x5A, "SecondaryBarrelSwitch"},
{0, 0x5B, "TransducerSerialNumber"}, {0, 0x5B, "TransducerSerialNumber"},
{ 15, 0, "PhysicalInterfaceDevice" }, { 15, 0, "PhysicalInterfaceDevice" },
...@@ -1127,7 +1128,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, ...@@ -1127,7 +1128,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
if (!list->hdev || !list->hdev->debug) { if (!list->hdev || !list->hdev->debug) {
ret = -EIO; ret = -EIO;
break; set_current_state(TASK_RUNNING);
goto out;
} }
/* allow O_NONBLOCK from other threads */ /* allow O_NONBLOCK from other threads */
......
/*
* HID driver for Huion devices not fully compliant with HID standard
*
* Copyright (c) 2013 Martin Rusko
* Copyright (c) 2014 Nikolai Kondrashov
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <asm/unaligned.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
/* Report descriptor template placeholder head */
#define HUION_PH_HEAD 0xFE, 0xED, 0x1D
/* Report descriptor template placeholder IDs */
enum huion_ph_id {
HUION_PH_ID_X_LM,
HUION_PH_ID_X_PM,
HUION_PH_ID_Y_LM,
HUION_PH_ID_Y_PM,
HUION_PH_ID_PRESSURE_LM,
HUION_PH_ID_NUM
};
/* Report descriptor template placeholder */
#define HUION_PH(_ID) HUION_PH_HEAD, HUION_PH_ID_##_ID
/* Fixed report descriptor template */
static const __u8 huion_tablet_rdesc_template[] = {
0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x07, /* Report ID (7), */
0x09, 0x20, /* Usage (Stylus), */
0xA0, /* Collection (Physical), */
0x14, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x09, 0x42, /* Usage (Tip Switch), */
0x09, 0x44, /* Usage (Barrel Switch), */
0x09, 0x46, /* Usage (Tablet Pick), */
0x95, 0x03, /* Report Count (3), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x03, /* Report Count (3), */
0x81, 0x03, /* Input (Constant, Variable), */
0x09, 0x32, /* Usage (In Range), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x03, /* Input (Constant, Variable), */
0x75, 0x10, /* Report Size (16), */
0x95, 0x01, /* Report Count (1), */
0xA4, /* Push, */
0x05, 0x01, /* Usage Page (Desktop), */
0x65, 0x13, /* Unit (Inch), */
0x55, 0xFD, /* Unit Exponent (-3), */
0x34, /* Physical Minimum (0), */
0x09, 0x30, /* Usage (X), */
0x27, HUION_PH(X_LM), /* Logical Maximum (PLACEHOLDER), */
0x47, HUION_PH(X_PM), /* Physical Maximum (PLACEHOLDER), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x31, /* Usage (Y), */
0x27, HUION_PH(Y_LM), /* Logical Maximum (PLACEHOLDER), */
0x47, HUION_PH(Y_PM), /* Physical Maximum (PLACEHOLDER), */
0x81, 0x02, /* Input (Variable), */
0xB4, /* Pop, */
0x09, 0x30, /* Usage (Tip Pressure), */
0x27,
HUION_PH(PRESSURE_LM), /* Logical Maximum (PLACEHOLDER), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
/* Parameter indices */
enum huion_prm {
HUION_PRM_X_LM = 1,
HUION_PRM_Y_LM = 2,
HUION_PRM_PRESSURE_LM = 4,
HUION_PRM_RESOLUTION = 5,
HUION_PRM_NUM
};
/* Driver data */
struct huion_drvdata {
__u8 *rdesc;
unsigned int rsize;
};
static __u8 *huion_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
switch (hdev->product) {
case USB_DEVICE_ID_HUION_TABLET:
if (drvdata->rdesc != NULL) {
rdesc = drvdata->rdesc;
*rsize = drvdata->rsize;
}
break;
}
return rdesc;
}
/**
* Enable fully-functional tablet mode and determine device parameters.
*
* @hdev: HID device
*/
static int huion_tablet_enable(struct hid_device *hdev)
{
int rc;
struct usb_device *usb_dev = hid_to_usb_dev(hdev);
struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
__le16 *buf = NULL;
size_t len;
s32 params[HUION_PH_ID_NUM];
s32 resolution;
__u8 *p;
s32 v;
/*
* Read string descriptor containing tablet parameters. The specific
* string descriptor and data were discovered by sniffing the Windows
* driver traffic.
* NOTE: This enables fully-functional tablet mode.
*/
len = HUION_PRM_NUM * sizeof(*buf);
buf = kmalloc(len, GFP_KERNEL);
if (buf == NULL) {
hid_err(hdev, "failed to allocate parameter buffer\n");
rc = -ENOMEM;
goto cleanup;
}
rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
(USB_DT_STRING << 8) + 0x64,
0x0409, buf, len,
USB_CTRL_GET_TIMEOUT);
if (rc == -EPIPE) {
hid_err(hdev, "device parameters not found\n");
rc = -ENODEV;
goto cleanup;
} else if (rc < 0) {
hid_err(hdev, "failed to get device parameters: %d\n", rc);
rc = -ENODEV;
goto cleanup;
} else if (rc != len) {
hid_err(hdev, "invalid device parameters\n");
rc = -ENODEV;
goto cleanup;
}
/* Extract device parameters */
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
params[HUION_PH_ID_PRESSURE_LM] =
le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
if (resolution == 0) {
params[HUION_PH_ID_X_PM] = 0;
params[HUION_PH_ID_Y_PM] = 0;
} else {
params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
1000 / resolution;
params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
1000 / resolution;
}
/* Allocate fixed report descriptor */
drvdata->rdesc = devm_kmalloc(&hdev->dev,
sizeof(huion_tablet_rdesc_template),
GFP_KERNEL);
if (drvdata->rdesc == NULL) {
hid_err(hdev, "failed to allocate fixed rdesc\n");
rc = -ENOMEM;
goto cleanup;
}
drvdata->rsize = sizeof(huion_tablet_rdesc_template);
/* Format fixed report descriptor */
memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
drvdata->rsize);
for (p = drvdata->rdesc;
p <= drvdata->rdesc + drvdata->rsize - 4;) {
if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
p[3] < sizeof(params)) {
v = params[p[3]];
put_unaligned(cpu_to_le32(v), (s32 *)p);
p += 4;
} else {
p++;
}
}
rc = 0;
cleanup:
kfree(buf);
return rc;
}
static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int rc;
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct huion_drvdata *drvdata;
/* Allocate and assign driver data */
drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (drvdata == NULL) {
hid_err(hdev, "failed to allocate driver data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, drvdata);
switch (id->product) {
case USB_DEVICE_ID_HUION_TABLET:
/* If this is the pen interface */
if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
rc = huion_tablet_enable(hdev);
if (rc) {
hid_err(hdev, "tablet enabling failed\n");
return rc;
}
}
break;
}
rc = hid_parse(hdev);
if (rc) {
hid_err(hdev, "parse failed\n");
return rc;
}
rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (rc) {
hid_err(hdev, "hw start failed\n");
return rc;
}
return 0;
}
static int huion_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
/* If this is a pen input report */
if (intf->cur_altsetting->desc.bInterfaceNumber == 0 &&
report->type == HID_INPUT_REPORT &&
report->id == 0x07 && size >= 2)
/* Invert the in-range bit */
data[1] ^= 0x40;
return 0;
}
static const struct hid_device_id huion_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
{ }
};
MODULE_DEVICE_TABLE(hid, huion_devices);
static struct hid_driver huion_driver = {
.name = "huion",
.id_table = huion_devices,
.probe = huion_probe,
.report_fixup = huion_report_fixup,
.raw_event = huion_raw_event,
};
module_hid_driver(huion_driver);
MODULE_AUTHOR("Martin Rusko");
MODULE_DESCRIPTION("Huion HID driver");
MODULE_LICENSE("GPL");
...@@ -459,6 +459,11 @@ ...@@ -459,6 +459,11 @@
#define USB_DEVICE_ID_UGCI_FLYING 0x0020 #define USB_DEVICE_ID_UGCI_FLYING 0x0020
#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 #define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
#define USB_VENDOR_ID_HP 0x03f0
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A 0x0a4a
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_VENDOR_ID_HUION 0x256c #define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e #define USB_DEVICE_ID_HUION_TABLET 0x006e
...@@ -533,6 +538,7 @@ ...@@ -533,6 +538,7 @@
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2 0x501a #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2 0x501a
#define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013 #define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013
#define USB_DEVICE_ID_KYE_PENSKETCH_M912 0x5015
#define USB_VENDOR_ID_LABTEC 0x1020 #define USB_VENDOR_ID_LABTEC 0x1020
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
...@@ -591,6 +597,9 @@ ...@@ -591,6 +597,9 @@
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306 #define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
#define USB_DEVICE_ID_LOGITECH_MOUSE_C01A 0xc01a
#define USB_DEVICE_ID_LOGITECH_MOUSE_C05A 0xc05a
#define USB_DEVICE_ID_LOGITECH_MOUSE_C06A 0xc06a
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 #define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
...@@ -1022,6 +1031,7 @@ ...@@ -1022,6 +1031,7 @@
#define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 #define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005
#define USB_VENDOR_ID_PRIMAX 0x0461 #define USB_VENDOR_ID_PRIMAX 0x0461
#define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
......
...@@ -720,6 +720,29 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -720,6 +720,29 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
} }
break; break;
case HID_UP_TELEPHONY:
switch (usage->hid & HID_USAGE) {
case 0x2f: map_key_clear(KEY_MICMUTE); break;
case 0xb0: map_key_clear(KEY_NUMERIC_0); break;
case 0xb1: map_key_clear(KEY_NUMERIC_1); break;
case 0xb2: map_key_clear(KEY_NUMERIC_2); break;
case 0xb3: map_key_clear(KEY_NUMERIC_3); break;
case 0xb4: map_key_clear(KEY_NUMERIC_4); break;
case 0xb5: map_key_clear(KEY_NUMERIC_5); break;
case 0xb6: map_key_clear(KEY_NUMERIC_6); break;
case 0xb7: map_key_clear(KEY_NUMERIC_7); break;
case 0xb8: map_key_clear(KEY_NUMERIC_8); break;
case 0xb9: map_key_clear(KEY_NUMERIC_9); break;
case 0xba: map_key_clear(KEY_NUMERIC_STAR); break;
case 0xbb: map_key_clear(KEY_NUMERIC_POUND); break;
case 0xbc: map_key_clear(KEY_NUMERIC_A); break;
case 0xbd: map_key_clear(KEY_NUMERIC_B); break;
case 0xbe: map_key_clear(KEY_NUMERIC_C); break;
case 0xbf: map_key_clear(KEY_NUMERIC_D); break;
default: goto ignore;
}
break;
case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */ case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */
switch (usage->hid & HID_USAGE) { switch (usage->hid & HID_USAGE) {
case 0x000: goto ignore; case 0x000: goto ignore;
......
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "usbhid/usbhid.h" #include "usbhid/usbhid.h"
#include "hid-ids.h" #include "hid-ids.h"
#include "hid-lg.h" #include "hid-lg.h"
#include "hid-lg4ff.h"
#define LG_RDESC 0x001 #define LG_RDESC 0x001
#define LG_BAD_RELATIVE_KEYS 0x002 #define LG_BAD_RELATIVE_KEYS 0x002
...@@ -818,4 +819,10 @@ static struct hid_driver lg_driver = { ...@@ -818,4 +819,10 @@ static struct hid_driver lg_driver = {
}; };
module_hid_driver(lg_driver); module_hid_driver(lg_driver);
#ifdef CONFIG_LOGIWHEELS_FF
int lg4ff_no_autoswitch = 0;
module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -24,16 +24,4 @@ int lg3ff_init(struct hid_device *hdev); ...@@ -24,16 +24,4 @@ int lg3ff_init(struct hid_device *hdev);
static inline int lg3ff_init(struct hid_device *hdev) { return -1; } static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
#endif #endif
#ifdef CONFIG_LOGIWHEELS_FF
int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data);
int lg4ff_init(struct hid_device *hdev);
int lg4ff_deinit(struct hid_device *hdev);
#else
static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) { return 0; }
static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
#endif
#endif #endif
This diff is collapsed.
#ifndef __HID_LG4FF_H
#define __HID_LG4FF_H
#ifdef CONFIG_LOGIWHEELS_FF
extern int lg4ff_no_autoswitch; /* From hid-lg.c */
int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data);
int lg4ff_init(struct hid_device *hdev);
int lg4ff_deinit(struct hid_device *hdev);
#else
static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) { return 0; }
static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; }
#endif
#endif
...@@ -28,6 +28,11 @@ MODULE_LICENSE("GPL"); ...@@ -28,6 +28,11 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>"); MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>");
static bool disable_raw_mode;
module_param(disable_raw_mode, bool, 0644);
MODULE_PARM_DESC(disable_raw_mode,
"Disable Raw mode reporting for touchpads and keep firmware gestures.");
#define REPORT_ID_HIDPP_SHORT 0x10 #define REPORT_ID_HIDPP_SHORT 0x10
#define REPORT_ID_HIDPP_LONG 0x11 #define REPORT_ID_HIDPP_LONG 0x11
...@@ -1188,6 +1193,11 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1188,6 +1193,11 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hidpp->quirks = id->driver_data; hidpp->quirks = id->driver_data;
if (disable_raw_mode) {
hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
hidpp->quirks &= ~HIDPP_QUIRK_DELAYED_INIT;
}
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
ret = wtp_allocate(hdev, id); ret = wtp_allocate(hdev, id);
if (ret) if (ret)
...@@ -1210,6 +1220,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1210,6 +1220,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
connected = hidpp_is_connected(hidpp); connected = hidpp_is_connected(hidpp);
if (id->group != HID_GROUP_LOGITECH_DJ_DEVICE) { if (id->group != HID_GROUP_LOGITECH_DJ_DEVICE) {
if (!connected) { if (!connected) {
ret = -ENODEV;
hid_err(hdev, "Device not connected"); hid_err(hdev, "Device not connected");
hid_device_io_stop(hdev); hid_device_io_stop(hdev);
goto hid_parse_fail; goto hid_parse_fail;
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -72,6 +71,8 @@ MODULE_LICENSE("GPL"); ...@@ -72,6 +71,8 @@ MODULE_LICENSE("GPL");
#define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03 #define MT_INPUTMODE_TOUCHPAD 0x03
#define MT_BUTTONTYPE_CLICKPAD 0
struct mt_slot { struct mt_slot {
__s32 x, y, cx, cy, p, w, h; __s32 x, y, cx, cy, p, w, h;
__s32 contactid; /* the device ContactID assigned to this slot */ __s32 contactid; /* the device ContactID assigned to this slot */
...@@ -116,6 +117,8 @@ struct mt_device { ...@@ -116,6 +117,8 @@ struct mt_device {
__u8 touches_by_report; /* how many touches are present in one report: __u8 touches_by_report; /* how many touches are present in one report:
* 1 means we should use a serial protocol * 1 means we should use a serial protocol
* > 1 means hybrid (multitouch) protocol */ * > 1 means hybrid (multitouch) protocol */
__u8 buttons_count; /* number of physical buttons per touchpad */
bool is_buttonpad; /* is this device a button pad? */
bool serial_maybe; /* need to check for serial protocol */ bool serial_maybe; /* need to check for serial protocol */
bool curvalid; /* is the current contact valid? */ bool curvalid; /* is the current contact valid? */
unsigned mt_flags; /* flags to pass to input-mt */ unsigned mt_flags; /* flags to pass to input-mt */
...@@ -333,6 +336,16 @@ static void mt_feature_mapping(struct hid_device *hdev, ...@@ -333,6 +336,16 @@ static void mt_feature_mapping(struct hid_device *hdev,
/* check if the maxcontacts is given by the class */ /* check if the maxcontacts is given by the class */
td->maxcontacts = td->mtclass.maxcontacts; td->maxcontacts = td->mtclass.maxcontacts;
break;
case HID_DG_BUTTONTYPE:
if (usage->usage_index >= field->report_count) {
dev_err(&hdev->dev, "HID_DG_BUTTONTYPE out of range\n");
break;
}
if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD)
td->is_buttonpad = true;
break; break;
} }
} }
...@@ -379,6 +392,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -379,6 +392,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->inputmode_value = MT_INPUTMODE_TOUCHPAD; td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
} }
/* count the buttons on touchpads */
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
td->buttons_count++;
if (usage->usage_index) if (usage->usage_index)
prev_usage = &field->usage[usage->usage_index - 1]; prev_usage = &field->usage[usage->usage_index - 1];
...@@ -728,6 +745,13 @@ static void mt_touch_input_configured(struct hid_device *hdev, ...@@ -728,6 +745,13 @@ static void mt_touch_input_configured(struct hid_device *hdev,
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
td->mt_flags |= INPUT_MT_DROP_UNUSED; td->mt_flags |= INPUT_MT_DROP_UNUSED;
/* check for clickpads */
if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1))
td->is_buttonpad = true;
if (td->is_buttonpad)
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
input_mt_init_slots(input, td->maxcontacts, td->mt_flags); input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
td->mt_flags = 0; td->mt_flags = 0;
......
...@@ -104,6 +104,7 @@ struct rmi_data { ...@@ -104,6 +104,7 @@ struct rmi_data {
unsigned long flags; unsigned long flags;
struct rmi_function f01;
struct rmi_function f11; struct rmi_function f11;
struct rmi_function f30; struct rmi_function f30;
...@@ -124,6 +125,7 @@ struct rmi_data { ...@@ -124,6 +125,7 @@ struct rmi_data {
struct hid_device *hdev; struct hid_device *hdev;
unsigned long device_flags; unsigned long device_flags;
unsigned long firmware_id;
}; };
#define RMI_PAGE(addr) (((addr) >> 8) & 0xff) #define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
...@@ -272,6 +274,46 @@ static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf) ...@@ -272,6 +274,46 @@ static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf)
return rmi_read_block(hdev, addr, buf, 1); return rmi_read_block(hdev, addr, buf, 1);
} }
static int rmi_write_block(struct hid_device *hdev, u16 addr, void *buf,
const int len)
{
struct rmi_data *data = hid_get_drvdata(hdev);
int ret;
mutex_lock(&data->page_mutex);
if (RMI_PAGE(addr) != data->page) {
ret = rmi_set_page(hdev, RMI_PAGE(addr));
if (ret < 0)
goto exit;
}
data->writeReport[0] = RMI_WRITE_REPORT_ID;
data->writeReport[1] = len;
data->writeReport[2] = addr & 0xFF;
data->writeReport[3] = (addr >> 8) & 0xFF;
memcpy(&data->writeReport[4], buf, len);
ret = rmi_write_report(hdev, data->writeReport,
data->output_report_size);
if (ret < 0) {
dev_err(&hdev->dev,
"failed to write request output report (%d)\n",
ret);
goto exit;
}
ret = 0;
exit:
mutex_unlock(&data->page_mutex);
return ret;
}
static inline int rmi_write(struct hid_device *hdev, u16 addr, void *buf)
{
return rmi_write_block(hdev, addr, buf, 1);
}
static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, static void rmi_f11_process_touch(struct rmi_data *hdata, int slot,
u8 finger_state, u8 *touch_data) u8 finger_state, u8 *touch_data)
{ {
...@@ -532,6 +574,9 @@ static void rmi_register_function(struct rmi_data *data, ...@@ -532,6 +574,9 @@ static void rmi_register_function(struct rmi_data *data,
u16 page_base = page << 8; u16 page_base = page << 8;
switch (pdt_entry->function_number) { switch (pdt_entry->function_number) {
case 0x01:
f = &data->f01;
break;
case 0x11: case 0x11:
f = &data->f11; f = &data->f11;
break; break;
...@@ -604,6 +649,92 @@ static int rmi_scan_pdt(struct hid_device *hdev) ...@@ -604,6 +649,92 @@ static int rmi_scan_pdt(struct hid_device *hdev)
return retval; return retval;
} }
#define RMI_DEVICE_F01_BASIC_QUERY_LEN 11
static int rmi_populate_f01(struct hid_device *hdev)
{
struct rmi_data *data = hid_get_drvdata(hdev);
u8 basic_queries[RMI_DEVICE_F01_BASIC_QUERY_LEN];
u8 info[3];
int ret;
bool has_query42;
bool has_lts;
bool has_sensor_id;
bool has_ds4_queries = false;
bool has_build_id_query = false;
bool has_package_id_query = false;
u16 query_offset = data->f01.query_base_addr;
u16 prod_info_addr;
u8 ds4_query_len;
ret = rmi_read_block(hdev, query_offset, basic_queries,
RMI_DEVICE_F01_BASIC_QUERY_LEN);
if (ret) {
hid_err(hdev, "Can not read basic queries from Function 0x1.\n");
return ret;
}
has_lts = !!(basic_queries[0] & BIT(2));
has_sensor_id = !!(basic_queries[1] & BIT(3));
has_query42 = !!(basic_queries[1] & BIT(7));
query_offset += 11;
prod_info_addr = query_offset + 6;
query_offset += 10;
if (has_lts)
query_offset += 20;
if (has_sensor_id)
query_offset++;
if (has_query42) {
ret = rmi_read(hdev, query_offset, info);
if (ret) {
hid_err(hdev, "Can not read query42.\n");
return ret;
}
has_ds4_queries = !!(info[0] & BIT(0));
query_offset++;
}
if (has_ds4_queries) {
ret = rmi_read(hdev, query_offset, &ds4_query_len);
if (ret) {
hid_err(hdev, "Can not read DS4 Query length.\n");
return ret;
}
query_offset++;
if (ds4_query_len > 0) {
ret = rmi_read(hdev, query_offset, info);
if (ret) {
hid_err(hdev, "Can not read DS4 query.\n");
return ret;
}
has_package_id_query = !!(info[0] & BIT(0));
has_build_id_query = !!(info[0] & BIT(1));
}
}
if (has_package_id_query)
prod_info_addr++;
if (has_build_id_query) {
ret = rmi_read_block(hdev, prod_info_addr, info, 3);
if (ret) {
hid_err(hdev, "Can not read product info.\n");
return ret;
}
data->firmware_id = info[1] << 8 | info[0];
data->firmware_id += info[2] * 65536;
}
return 0;
}
static int rmi_populate_f11(struct hid_device *hdev) static int rmi_populate_f11(struct hid_device *hdev)
{ {
struct rmi_data *data = hid_get_drvdata(hdev); struct rmi_data *data = hid_get_drvdata(hdev);
...@@ -620,6 +751,8 @@ static int rmi_populate_f11(struct hid_device *hdev) ...@@ -620,6 +751,8 @@ static int rmi_populate_f11(struct hid_device *hdev)
bool has_gestures; bool has_gestures;
bool has_rel; bool has_rel;
bool has_data40 = false; bool has_data40 = false;
bool has_dribble = false;
bool has_palm_detect = false;
unsigned x_size, y_size; unsigned x_size, y_size;
u16 query_offset; u16 query_offset;
...@@ -661,6 +794,14 @@ static int rmi_populate_f11(struct hid_device *hdev) ...@@ -661,6 +794,14 @@ static int rmi_populate_f11(struct hid_device *hdev)
has_rel = !!(buf[0] & BIT(3)); has_rel = !!(buf[0] & BIT(3));
has_gestures = !!(buf[0] & BIT(5)); has_gestures = !!(buf[0] & BIT(5));
ret = rmi_read(hdev, data->f11.query_base_addr + 5, buf);
if (ret) {
hid_err(hdev, "can not get absolute data sources: %d.\n", ret);
return ret;
}
has_dribble = !!(buf[0] & BIT(4));
/* /*
* At least 4 queries are guaranteed to be present in F11 * At least 4 queries are guaranteed to be present in F11
* +1 for query 5 which is present since absolute events are * +1 for query 5 which is present since absolute events are
...@@ -680,6 +821,7 @@ static int rmi_populate_f11(struct hid_device *hdev) ...@@ -680,6 +821,7 @@ static int rmi_populate_f11(struct hid_device *hdev)
ret); ret);
return ret; return ret;
} }
has_palm_detect = !!(buf[0] & BIT(0));
has_query10 = !!(buf[0] & BIT(2)); has_query10 = !!(buf[0] & BIT(2));
query_offset += 2; /* query 7 and 8 are present */ query_offset += 2; /* query 7 and 8 are present */
...@@ -766,17 +908,38 @@ static int rmi_populate_f11(struct hid_device *hdev) ...@@ -766,17 +908,38 @@ static int rmi_populate_f11(struct hid_device *hdev)
* retrieve the ctrl registers * retrieve the ctrl registers
* the ctrl register has a size of 20 but a fw bug split it into 16 + 4, * the ctrl register has a size of 20 but a fw bug split it into 16 + 4,
* and there is no way to know if the first 20 bytes are here or not. * and there is no way to know if the first 20 bytes are here or not.
* We use only the first 10 bytes, so get only them. * We use only the first 12 bytes, so get only them.
*/ */
ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 10); ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 12);
if (ret) { if (ret) {
hid_err(hdev, "can not read ctrl block of size 10: %d.\n", ret); hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret);
return ret; return ret;
} }
data->max_x = buf[6] | (buf[7] << 8); data->max_x = buf[6] | (buf[7] << 8);
data->max_y = buf[8] | (buf[9] << 8); data->max_y = buf[8] | (buf[9] << 8);
if (has_dribble) {
buf[0] = buf[0] & ~BIT(6);
ret = rmi_write(hdev, data->f11.control_base_addr, buf);
if (ret) {
hid_err(hdev, "can not write to control reg 0: %d.\n",
ret);
return ret;
}
}
if (has_palm_detect) {
buf[11] = buf[11] & ~BIT(0);
ret = rmi_write(hdev, data->f11.control_base_addr + 11,
&buf[11]);
if (ret) {
hid_err(hdev, "can not write to control reg 11: %d.\n",
ret);
return ret;
}
}
return 0; return 0;
} }
...@@ -858,6 +1021,12 @@ static int rmi_populate(struct hid_device *hdev) ...@@ -858,6 +1021,12 @@ static int rmi_populate(struct hid_device *hdev)
return ret; return ret;
} }
ret = rmi_populate_f01(hdev);
if (ret) {
hid_err(hdev, "Error while initializing F01 (%d).\n", ret);
return ret;
}
ret = rmi_populate_f11(hdev); ret = rmi_populate_f11(hdev);
if (ret) { if (ret) {
hid_err(hdev, "Error while initializing F11 (%d).\n", ret); hid_err(hdev, "Error while initializing F11 (%d).\n", ret);
...@@ -907,6 +1076,8 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -907,6 +1076,8 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (ret) if (ret)
goto exit; goto exit;
hid_info(hdev, "firmware id: %ld\n", data->firmware_id);
__set_bit(EV_ABS, input->evbit); __set_bit(EV_ABS, input->evbit);
input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0);
......
This diff is collapsed.
This diff is collapsed.
...@@ -802,7 +802,8 @@ union sixaxis_output_report_01 { ...@@ -802,7 +802,8 @@ union sixaxis_output_report_01 {
#define DS4_REPORT_0x05_SIZE 32 #define DS4_REPORT_0x05_SIZE 32
#define DS4_REPORT_0x11_SIZE 78 #define DS4_REPORT_0x11_SIZE 78
#define DS4_REPORT_0x81_SIZE 7 #define DS4_REPORT_0x81_SIZE 7
#define SIXAXIS_REPORT_0xF2_SIZE 18 #define SIXAXIS_REPORT_0xF2_SIZE 17
#define SIXAXIS_REPORT_0xF5_SIZE 8
static DEFINE_SPINLOCK(sony_dev_list_lock); static DEFINE_SPINLOCK(sony_dev_list_lock);
static LIST_HEAD(sony_device_list); static LIST_HEAD(sony_device_list);
...@@ -1131,18 +1132,38 @@ static void sony_input_configured(struct hid_device *hdev, ...@@ -1131,18 +1132,38 @@ static void sony_input_configured(struct hid_device *hdev,
*/ */
static int sixaxis_set_operational_usb(struct hid_device *hdev) static int sixaxis_set_operational_usb(struct hid_device *hdev)
{ {
const int buf_size =
max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE);
__u8 *buf;
int ret; int ret;
char *buf = kmalloc(18, GFP_KERNEL);
buf = kmalloc(buf_size, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
ret = hid_hw_raw_request(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT, ret = hid_hw_raw_request(hdev, 0xf2, buf, SIXAXIS_REPORT_0xF2_SIZE,
HID_REQ_GET_REPORT); HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0) {
hid_err(hdev, "can't set operational mode: step 1\n");
goto out;
}
/*
* Some compatible controllers like the Speedlink Strike FX and
* Gasia need another query plus an USB interrupt to get operational.
*/
ret = hid_hw_raw_request(hdev, 0xf5, buf, SIXAXIS_REPORT_0xF5_SIZE,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0) {
hid_err(hdev, "can't set operational mode: step 2\n");
goto out;
}
ret = hid_hw_output_report(hdev, buf, 1);
if (ret < 0) if (ret < 0)
hid_err(hdev, "can't set operational mode\n"); hid_err(hdev, "can't set operational mode: step 3\n");
out:
kfree(buf); kfree(buf);
return ret; return ret;
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
*/ */
#include <linux/device.h> #include <linux/device.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
......
This diff is collapsed.
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c/i2c-hid.h> #include <linux/i2c/i2c-hid.h>
...@@ -144,6 +145,8 @@ struct i2c_hid { ...@@ -144,6 +145,8 @@ struct i2c_hid {
unsigned long flags; /* device flags */ unsigned long flags; /* device flags */
wait_queue_head_t wait; /* For waiting the interrupt */ wait_queue_head_t wait; /* For waiting the interrupt */
struct gpio_desc *desc;
int irq;
struct i2c_hid_platform_data pdata; struct i2c_hid_platform_data pdata;
}; };
...@@ -785,16 +788,16 @@ static int i2c_hid_init_irq(struct i2c_client *client) ...@@ -785,16 +788,16 @@ static int i2c_hid_init_irq(struct i2c_client *client)
struct i2c_hid *ihid = i2c_get_clientdata(client); struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret; int ret;
dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq); dev_dbg(&client->dev, "Requesting IRQ: %d\n", ihid->irq);
ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq, ret = request_threaded_irq(ihid->irq, NULL, i2c_hid_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, ihid); client->name, ihid);
if (ret < 0) { if (ret < 0) {
dev_warn(&client->dev, dev_warn(&client->dev,
"Could not register for %s interrupt, irq = %d," "Could not register for %s interrupt, irq = %d,"
" ret = %d\n", " ret = %d\n",
client->name, client->irq, ret); client->name, ihid->irq, ret);
return ret; return ret;
} }
...@@ -841,6 +844,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) ...@@ -841,6 +844,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
/* Default GPIO mapping */
static const struct acpi_gpio_params i2c_hid_irq_gpio = { 0, 0, true };
static const struct acpi_gpio_mapping i2c_hid_acpi_gpios[] = {
{ "gpios", &i2c_hid_irq_gpio, 1 },
{ },
};
static int i2c_hid_acpi_pdata(struct i2c_client *client, static int i2c_hid_acpi_pdata(struct i2c_client *client,
struct i2c_hid_platform_data *pdata) struct i2c_hid_platform_data *pdata)
{ {
...@@ -866,7 +877,7 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, ...@@ -866,7 +877,7 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
pdata->hid_descriptor_address = obj->integer.value; pdata->hid_descriptor_address = obj->integer.value;
ACPI_FREE(obj); ACPI_FREE(obj);
return 0; return acpi_dev_add_driver_gpios(adev, i2c_hid_acpi_gpios);
} }
static const struct acpi_device_id i2c_hid_acpi_match[] = { static const struct acpi_device_id i2c_hid_acpi_match[] = {
...@@ -930,12 +941,6 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -930,12 +941,6 @@ static int i2c_hid_probe(struct i2c_client *client,
dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); dbg_hid("HID probe called for i2c 0x%02x\n", client->addr);
if (!client->irq) {
dev_err(&client->dev,
"HID over i2c has not been provided an Int IRQ\n");
return -EINVAL;
}
ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL); ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL);
if (!ihid) if (!ihid)
return -ENOMEM; return -ENOMEM;
...@@ -955,6 +960,23 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -955,6 +960,23 @@ static int i2c_hid_probe(struct i2c_client *client,
ihid->pdata = *platform_data; ihid->pdata = *platform_data;
} }
if (client->irq > 0) {
ihid->irq = client->irq;
} else if (ACPI_COMPANION(&client->dev)) {
ihid->desc = gpiod_get(&client->dev, NULL, GPIOD_IN);
if (IS_ERR(ihid->desc)) {
dev_err(&client->dev, "Failed to get GPIO interrupt\n");
return PTR_ERR(ihid->desc);
}
ihid->irq = gpiod_to_irq(ihid->desc);
if (ihid->irq < 0) {
gpiod_put(ihid->desc);
dev_err(&client->dev, "Failed to convert GPIO to IRQ\n");
return ihid->irq;
}
}
i2c_set_clientdata(client, ihid); i2c_set_clientdata(client, ihid);
ihid->client = client; ihid->client = client;
...@@ -1017,13 +1039,16 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1017,13 +1039,16 @@ static int i2c_hid_probe(struct i2c_client *client,
hid_destroy_device(hid); hid_destroy_device(hid);
err_irq: err_irq:
free_irq(client->irq, ihid); free_irq(ihid->irq, ihid);
err_pm: err_pm:
pm_runtime_put_noidle(&client->dev); pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev); pm_runtime_disable(&client->dev);
err: err:
if (ihid->desc)
gpiod_put(ihid->desc);
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
kfree(ihid); kfree(ihid);
return ret; return ret;
...@@ -1042,13 +1067,18 @@ static int i2c_hid_remove(struct i2c_client *client) ...@@ -1042,13 +1067,18 @@ static int i2c_hid_remove(struct i2c_client *client)
hid = ihid->hid; hid = ihid->hid;
hid_destroy_device(hid); hid_destroy_device(hid);
free_irq(client->irq, ihid); free_irq(ihid->irq, ihid);
if (ihid->bufsize) if (ihid->bufsize)
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
if (ihid->desc)
gpiod_put(ihid->desc);
kfree(ihid); kfree(ihid);
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev));
return 0; return 0;
} }
...@@ -1060,9 +1090,9 @@ static int i2c_hid_suspend(struct device *dev) ...@@ -1060,9 +1090,9 @@ static int i2c_hid_suspend(struct device *dev)
struct hid_device *hid = ihid->hid; struct hid_device *hid = ihid->hid;
int ret = 0; int ret = 0;
disable_irq(client->irq); disable_irq(ihid->irq);
if (device_may_wakeup(&client->dev)) if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq); enable_irq_wake(ihid->irq);
if (hid->driver && hid->driver->suspend) if (hid->driver && hid->driver->suspend)
ret = hid->driver->suspend(hid, PMSG_SUSPEND); ret = hid->driver->suspend(hid, PMSG_SUSPEND);
...@@ -1080,13 +1110,13 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1080,13 +1110,13 @@ static int i2c_hid_resume(struct device *dev)
struct i2c_hid *ihid = i2c_get_clientdata(client); struct i2c_hid *ihid = i2c_get_clientdata(client);
struct hid_device *hid = ihid->hid; struct hid_device *hid = ihid->hid;
enable_irq(client->irq); enable_irq(ihid->irq);
ret = i2c_hid_hwreset(client); ret = i2c_hid_hwreset(client);
if (ret) if (ret)
return ret; return ret;
if (device_may_wakeup(&client->dev)) if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq); disable_irq_wake(ihid->irq);
if (hid->driver && hid->driver->reset_resume) { if (hid->driver && hid->driver->reset_resume) {
ret = hid->driver->reset_resume(hid); ret = hid->driver->reset_resume(hid);
...@@ -1101,17 +1131,19 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1101,17 +1131,19 @@ static int i2c_hid_resume(struct device *dev)
static int i2c_hid_runtime_suspend(struct device *dev) static int i2c_hid_runtime_suspend(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct i2c_hid *ihid = i2c_get_clientdata(client);
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
disable_irq(client->irq); disable_irq(ihid->irq);
return 0; return 0;
} }
static int i2c_hid_runtime_resume(struct device *dev) static int i2c_hid_runtime_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct i2c_hid *ihid = i2c_get_clientdata(client);
enable_irq(client->irq); enable_irq(ihid->irq);
i2c_hid_set_power(client, I2C_HID_PWR_ON); i2c_hid_set_power(client, I2C_HID_PWR_ON);
return 0; return 0;
} }
......
...@@ -568,6 +568,12 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, ...@@ -568,6 +568,12 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
int type_id; int type_id;
int error; int error;
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
if (old) {
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] =
pidff->pid_id[effect->id];
}
switch (effect->type) { switch (effect->type) {
case FF_CONSTANT: case FF_CONSTANT:
if (!old) { if (!old) {
......
...@@ -78,7 +78,13 @@ static const struct hid_blacklist { ...@@ -78,7 +78,13 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
...@@ -92,6 +98,7 @@ static const struct hid_blacklist { ...@@ -92,6 +98,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
...@@ -107,12 +114,8 @@ static const struct hid_blacklist { ...@@ -107,12 +114,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
...@@ -128,6 +131,7 @@ static const struct hid_blacklist { ...@@ -128,6 +131,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
......
...@@ -131,13 +131,6 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) ...@@ -131,13 +131,6 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac)
schedule_work(&wacom->work); schedule_work(&wacom->work);
} }
static inline void wacom_notify_battery(struct wacom_wac *wacom_wac)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
power_supply_changed(wacom->battery);
}
extern const struct hid_device_id wacom_ids[]; extern const struct hid_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
...@@ -151,4 +144,5 @@ void wacom_wac_usage_mapping(struct hid_device *hdev, ...@@ -151,4 +144,5 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value); struct hid_usage *usage, __s32 value);
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
void wacom_battery_work(struct work_struct *work);
#endif #endif
...@@ -406,6 +406,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev, ...@@ -406,6 +406,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
else if (features->type == WACOM_27QHDT) { else if (features->type == WACOM_27QHDT) {
return wacom_set_device_mode(hdev, 131, 3, 2); return wacom_set_device_mode(hdev, 131, 3, 2);
} }
else if (features->type == BAMBOO_PAD) {
return wacom_set_device_mode(hdev, 2, 2, 2);
}
} else if (features->device_type == BTN_TOOL_PEN) { } else if (features->device_type == BTN_TOOL_PEN) {
if (features->type <= BAMBOO_PT && features->type != WIRELESS) { if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
return wacom_set_device_mode(hdev, 2, 2, 2); return wacom_set_device_mode(hdev, 2, 2, 2);
...@@ -524,6 +527,11 @@ static int wacom_add_shared_data(struct hid_device *hdev) ...@@ -524,6 +527,11 @@ static int wacom_add_shared_data(struct hid_device *hdev)
wacom_wac->shared = &data->shared; wacom_wac->shared = &data->shared;
if (wacom_wac->features.device_type == BTN_TOOL_FINGER)
wacom_wac->shared->touch = hdev;
else if (wacom_wac->features.device_type == BTN_TOOL_PEN)
wacom_wac->shared->pen = hdev;
out: out:
mutex_unlock(&wacom_udev_list_lock); mutex_unlock(&wacom_udev_list_lock);
return retval; return retval;
...@@ -541,14 +549,22 @@ static void wacom_release_shared_data(struct kref *kref) ...@@ -541,14 +549,22 @@ static void wacom_release_shared_data(struct kref *kref)
kfree(data); kfree(data);
} }
static void wacom_remove_shared_data(struct wacom_wac *wacom) static void wacom_remove_shared_data(struct wacom *wacom)
{ {
struct wacom_hdev_data *data; struct wacom_hdev_data *data;
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
if (wacom_wac->shared) {
data = container_of(wacom_wac->shared, struct wacom_hdev_data,
shared);
if (wacom_wac->shared->touch == wacom->hdev)
wacom_wac->shared->touch = NULL;
else if (wacom_wac->shared->pen == wacom->hdev)
wacom_wac->shared->pen = NULL;
if (wacom->shared) {
data = container_of(wacom->shared, struct wacom_hdev_data, shared);
kref_put(&data->kref, wacom_release_shared_data); kref_put(&data->kref, wacom_release_shared_data);
wacom->shared = NULL; wacom_wac->shared = NULL;
} }
} }
...@@ -929,6 +945,7 @@ static void wacom_destroy_leds(struct wacom *wacom) ...@@ -929,6 +945,7 @@ static void wacom_destroy_leds(struct wacom *wacom)
} }
static enum power_supply_property wacom_battery_props[] = { static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_CAPACITY POWER_SUPPLY_PROP_CAPACITY
...@@ -948,6 +965,9 @@ static int wacom_battery_get_property(struct power_supply *psy, ...@@ -948,6 +965,9 @@ static int wacom_battery_get_property(struct power_supply *psy,
int ret = 0; int ret = 0;
switch (psp) { switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
val->intval = wacom->wacom_wac.bat_connected;
break;
case POWER_SUPPLY_PROP_SCOPE: case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE; val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break; break;
...@@ -961,6 +981,8 @@ static int wacom_battery_get_property(struct power_supply *psy, ...@@ -961,6 +981,8 @@ static int wacom_battery_get_property(struct power_supply *psy,
else if (wacom->wacom_wac.battery_capacity == 100 && else if (wacom->wacom_wac.battery_capacity == 100 &&
wacom->wacom_wac.ps_connected) wacom->wacom_wac.ps_connected)
val->intval = POWER_SUPPLY_STATUS_FULL; val->intval = POWER_SUPPLY_STATUS_FULL;
else if (wacom->wacom_wac.ps_connected)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING; val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break; break;
...@@ -1045,8 +1067,7 @@ static int wacom_initialize_battery(struct wacom *wacom) ...@@ -1045,8 +1067,7 @@ static int wacom_initialize_battery(struct wacom *wacom)
static void wacom_destroy_battery(struct wacom *wacom) static void wacom_destroy_battery(struct wacom *wacom)
{ {
if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) && if (wacom->battery) {
wacom->battery) {
power_supply_unregister(wacom->battery); power_supply_unregister(wacom->battery);
wacom->battery = NULL; wacom->battery = NULL;
power_supply_unregister(wacom->ac); power_supply_unregister(wacom->ac);
...@@ -1317,6 +1338,20 @@ static void wacom_wireless_work(struct work_struct *work) ...@@ -1317,6 +1338,20 @@ static void wacom_wireless_work(struct work_struct *work)
return; return;
} }
void wacom_battery_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, work);
if ((wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
!wacom->battery) {
wacom_initialize_battery(wacom);
}
else if (!(wacom->wacom_wac.features.quirks & WACOM_QUIRK_BATTERY) &&
wacom->battery) {
wacom_destroy_battery(wacom);
}
}
/* /*
* Not all devices report physical dimensions from HID. * Not all devices report physical dimensions from HID.
* Compute the default from hardcoded logical dimension * Compute the default from hardcoded logical dimension
...@@ -1377,6 +1412,9 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -1377,6 +1412,9 @@ static int wacom_probe(struct hid_device *hdev,
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
/* hid-core sets this quirk for the boot interface */
hdev->quirks &= ~HID_QUIRK_NOGET;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
if (!wacom) if (!wacom)
return -ENOMEM; return -ENOMEM;
...@@ -1416,6 +1454,21 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -1416,6 +1454,21 @@ static int wacom_probe(struct hid_device *hdev,
goto fail_allocate_inputs; goto fail_allocate_inputs;
} }
/*
* Bamboo Pad has a generic hid handling for the Pen, and we switch it
* into debug mode for the touch part.
* We ignore the other interfaces.
*/
if (features->type == BAMBOO_PAD) {
if (features->pktlen == WACOM_PKGLEN_PENABLED) {
features->type = HID_GENERIC;
} else if ((features->pktlen != WACOM_PKGLEN_BPAD_TOUCH) &&
(features->pktlen != WACOM_PKGLEN_BPAD_TOUCH_USB)) {
error = -ENODEV;
goto fail_shared_data;
}
}
/* set the default size in case we do not get them from hid */ /* set the default size in case we do not get them from hid */
wacom_set_default_phy(features); wacom_set_default_phy(features);
...@@ -1450,6 +1503,12 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -1450,6 +1503,12 @@ static int wacom_probe(struct hid_device *hdev,
features->y_max = 4096; features->y_max = 4096;
} }
/*
* Same thing for Bamboo PAD
*/
if (features->type == BAMBOO_PAD)
features->device_type = BTN_TOOL_FINGER;
if (hdev->bus == BUS_BLUETOOTH) if (hdev->bus == BUS_BLUETOOTH)
features->quirks |= WACOM_QUIRK_BATTERY; features->quirks |= WACOM_QUIRK_BATTERY;
...@@ -1466,19 +1525,17 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -1466,19 +1525,17 @@ static int wacom_probe(struct hid_device *hdev,
snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
"%s Pad", features->name); "%s Pad", features->name);
if (features->quirks & WACOM_QUIRK_MULTI_INPUT) { /* Append the device type to the name */
/* Append the device type to the name */ if (features->device_type != BTN_TOOL_FINGER)
if (features->device_type != BTN_TOOL_FINGER) strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); else if (features->touch_max)
else if (features->touch_max) strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX);
strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); else
else strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
error = wacom_add_shared_data(hdev); error = wacom_add_shared_data(hdev);
if (error) if (error)
goto fail_shared_data; goto fail_shared_data;
}
if (!(features->quirks & WACOM_QUIRK_MONITOR) && if (!(features->quirks & WACOM_QUIRK_MONITOR) &&
(features->quirks & WACOM_QUIRK_BATTERY)) { (features->quirks & WACOM_QUIRK_BATTERY)) {
...@@ -1531,7 +1588,7 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -1531,7 +1588,7 @@ static int wacom_probe(struct hid_device *hdev,
wacom_clean_inputs(wacom); wacom_clean_inputs(wacom);
wacom_destroy_battery(wacom); wacom_destroy_battery(wacom);
fail_battery: fail_battery:
wacom_remove_shared_data(wacom_wac); wacom_remove_shared_data(wacom);
fail_shared_data: fail_shared_data:
wacom_clean_inputs(wacom); wacom_clean_inputs(wacom);
fail_allocate_inputs: fail_allocate_inputs:
...@@ -1554,7 +1611,7 @@ static void wacom_remove(struct hid_device *hdev) ...@@ -1554,7 +1611,7 @@ static void wacom_remove(struct hid_device *hdev)
if (hdev->bus == BUS_BLUETOOTH) if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed); device_remove_file(&hdev->dev, &dev_attr_speed);
wacom_destroy_battery(wacom); wacom_destroy_battery(wacom);
wacom_remove_shared_data(&wacom->wacom_wac); wacom_remove_shared_data(wacom);
hid_set_drvdata(hdev, NULL); hid_set_drvdata(hdev, NULL);
kfree(wacom); kfree(wacom);
......
This diff is collapsed.
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#define WACOM_PKGLEN_MTTPC 40 #define WACOM_PKGLEN_MTTPC 40
#define WACOM_PKGLEN_DTUS 68 #define WACOM_PKGLEN_DTUS 68
#define WACOM_PKGLEN_PENABLED 8 #define WACOM_PKGLEN_PENABLED 8
#define WACOM_PKGLEN_BPAD_TOUCH 32
#define WACOM_PKGLEN_BPAD_TOUCH_USB 64
/* wacom data size per MT contact */ /* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11 #define WACOM_BYTES_PER_MT_PACKET 11
...@@ -67,13 +69,14 @@ ...@@ -67,13 +69,14 @@
#define WACOM_REPORT_24HDT 1 #define WACOM_REPORT_24HDT 1
#define WACOM_REPORT_WL 128 #define WACOM_REPORT_WL 128
#define WACOM_REPORT_USB 192 #define WACOM_REPORT_USB 192
#define WACOM_REPORT_BPAD_PEN 3
#define WACOM_REPORT_BPAD_TOUCH 16
/* device quirks */ /* device quirks */
#define WACOM_QUIRK_MULTI_INPUT 0x0001 #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002 #define WACOM_QUIRK_NO_INPUT 0x0002
#define WACOM_QUIRK_NO_INPUT 0x0004 #define WACOM_QUIRK_MONITOR 0x0004
#define WACOM_QUIRK_MONITOR 0x0008 #define WACOM_QUIRK_BATTERY 0x0008
#define WACOM_QUIRK_BATTERY 0x0010
#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
((f)->physical == HID_DG_STYLUS) || \ ((f)->physical == HID_DG_STYLUS) || \
...@@ -122,6 +125,7 @@ enum { ...@@ -122,6 +125,7 @@ enum {
BAMBOO_PT, BAMBOO_PT,
WACOM_24HDT, WACOM_24HDT,
WACOM_27QHDT, WACOM_27QHDT,
BAMBOO_PAD,
TABLETPC, /* add new TPC below */ TABLETPC, /* add new TPC below */
TABLETPCE, TABLETPCE,
TABLETPC2FG, TABLETPC2FG,
...@@ -169,6 +173,8 @@ struct wacom_shared { ...@@ -169,6 +173,8 @@ struct wacom_shared {
unsigned touch_max; unsigned touch_max;
int type; int type;
struct input_dev *touch_input; struct input_dev *touch_input;
struct hid_device *pen;
struct hid_device *touch;
}; };
struct hid_data { struct hid_data {
...@@ -205,6 +211,7 @@ struct wacom_wac { ...@@ -205,6 +211,7 @@ struct wacom_wac {
int battery_capacity; int battery_capacity;
int num_contacts_left; int num_contacts_left;
int bat_charging; int bat_charging;
int bat_connected;
int ps_connected; int ps_connected;
u8 bt_features; u8 bt_features;
u8 bt_high_speed; u8 bt_high_speed;
......
...@@ -123,7 +123,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, ...@@ -123,7 +123,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
accel_state->common_attributes.hsdev, accel_state->common_attributes.hsdev,
HID_USAGE_SENSOR_ACCEL_3D, address, HID_USAGE_SENSOR_ACCEL_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
*val = 0; *val = 0;
hid_sensor_power_state(&accel_state->common_attributes, hid_sensor_power_state(&accel_state->common_attributes,
......
...@@ -153,8 +153,8 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) ...@@ -153,8 +153,8 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
int ret; int ret;
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id, st->poll.report_id,
st->poll.index, &value); st->poll.index, sizeof(value), &value);
if (ret < 0 || value < 0) { if (ret < 0 || value < 0) {
return -EINVAL; return -EINVAL;
...@@ -174,8 +174,8 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, ...@@ -174,8 +174,8 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
int ret; int ret;
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->poll.report_id, st->poll.report_id,
st->poll.index, &value); st->poll.index, sizeof(value), &value);
if (ret < 0 || value < 0) { if (ret < 0 || value < 0) {
*val1 = *val2 = 0; *val1 = *val2 = 0;
return -EINVAL; return -EINVAL;
...@@ -212,9 +212,8 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, ...@@ -212,9 +212,8 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
else else
value = 0; value = 0;
} }
ret = sensor_hub_set_feature(st->hsdev, ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id,
st->poll.report_id, st->poll.index, sizeof(value), &value);
st->poll.index, value);
if (ret < 0 || value < 0) if (ret < 0 || value < 0)
ret = -EINVAL; ret = -EINVAL;
...@@ -229,8 +228,9 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, ...@@ -229,8 +228,9 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
int ret; int ret;
ret = sensor_hub_get_feature(st->hsdev, ret = sensor_hub_get_feature(st->hsdev,
st->sensitivity.report_id, st->sensitivity.report_id,
st->sensitivity.index, &value); st->sensitivity.index, sizeof(value),
&value);
if (ret < 0 || value < 0) { if (ret < 0 || value < 0) {
*val1 = *val2 = 0; *val1 = *val2 = 0;
return -EINVAL; return -EINVAL;
...@@ -253,9 +253,9 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, ...@@ -253,9 +253,9 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
value = convert_to_vtf_format(st->sensitivity.size, value = convert_to_vtf_format(st->sensitivity.size,
st->sensitivity.unit_expo, st->sensitivity.unit_expo,
val1, val2); val1, val2);
ret = sensor_hub_set_feature(st->hsdev, ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id,
st->sensitivity.report_id, st->sensitivity.index, sizeof(value),
st->sensitivity.index, value); &value);
if (ret < 0 || value < 0) if (ret < 0 || value < 0)
ret = -EINVAL; ret = -EINVAL;
......
...@@ -68,20 +68,21 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state) ...@@ -68,20 +68,21 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
if (state_val >= 0) { if (state_val >= 0) {
state_val += st->power_state.logical_minimum; state_val += st->power_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id, sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index, st->power_state.index, sizeof(state_val),
(s32)state_val); &state_val);
} }
if (report_val >= 0) { if (report_val >= 0) {
report_val += st->report_state.logical_minimum; report_val += st->report_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->report_state.report_id, sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
st->report_state.index, st->report_state.index,
(s32)report_val); sizeof(report_val),
&report_val);
} }
sensor_hub_get_feature(st->hsdev, st->power_state.report_id, sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
st->power_state.index, st->power_state.index,
&state_val); sizeof(state_val), &state_val);
if (state && poll_value) if (state && poll_value)
msleep_interruptible(poll_value * 2); msleep_interruptible(poll_value * 2);
......
...@@ -123,7 +123,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, ...@@ -123,7 +123,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
gyro_state->common_attributes.hsdev, gyro_state->common_attributes.hsdev,
HID_USAGE_SENSOR_GYRO_3D, address, HID_USAGE_SENSOR_GYRO_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
*val = 0; *val = 0;
hid_sensor_power_state(&gyro_state->common_attributes, hid_sensor_power_state(&gyro_state->common_attributes,
......
...@@ -101,7 +101,8 @@ static int als_read_raw(struct iio_dev *indio_dev, ...@@ -101,7 +101,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
als_state->common_attributes.hsdev, als_state->common_attributes.hsdev,
HID_USAGE_SENSOR_ALS, address, HID_USAGE_SENSOR_ALS, address,
report_id); report_id,
SENSOR_HUB_SYNC);
hid_sensor_power_state(&als_state->common_attributes, hid_sensor_power_state(&als_state->common_attributes,
false); false);
} else { } else {
......
...@@ -96,7 +96,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, ...@@ -96,7 +96,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
prox_state->common_attributes.hsdev, prox_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PROX, address, HID_USAGE_SENSOR_PROX, address,
report_id); report_id,
SENSOR_HUB_SYNC);
hid_sensor_power_state(&prox_state->common_attributes, hid_sensor_power_state(&prox_state->common_attributes,
false); false);
} else { } else {
......
...@@ -170,7 +170,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, ...@@ -170,7 +170,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
magn_state->common_attributes.hsdev, magn_state->common_attributes.hsdev,
HID_USAGE_SENSOR_COMPASS_3D, address, HID_USAGE_SENSOR_COMPASS_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
*val = 0; *val = 0;
hid_sensor_power_state(&magn_state->common_attributes, hid_sensor_power_state(&magn_state->common_attributes,
......
...@@ -124,7 +124,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev, ...@@ -124,7 +124,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
incl_state->common_attributes.hsdev, incl_state->common_attributes.hsdev,
HID_USAGE_SENSOR_INCLINOMETER_3D, address, HID_USAGE_SENSOR_INCLINOMETER_3D, address,
report_id); report_id,
SENSOR_HUB_SYNC);
else { else {
hid_sensor_power_state(&incl_state->common_attributes, hid_sensor_power_state(&incl_state->common_attributes,
false); false);
......
...@@ -100,7 +100,8 @@ static int press_read_raw(struct iio_dev *indio_dev, ...@@ -100,7 +100,8 @@ static int press_read_raw(struct iio_dev *indio_dev,
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
press_state->common_attributes.hsdev, press_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PRESSURE, address, HID_USAGE_SENSOR_PRESSURE, address,
report_id); report_id,
SENSOR_HUB_SYNC);
hid_sensor_power_state(&press_state->common_attributes, hid_sensor_power_state(&press_state->common_attributes,
false); false);
} else { } else {
......
...@@ -88,10 +88,13 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, ...@@ -88,10 +88,13 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
goto err_mem; goto err_mem;
} }
/* Mark slots as 'unused' */ /* Mark slots as 'inactive' */
for (i = 0; i < num_slots; i++) for (i = 0; i < num_slots; i++)
input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1); input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
/* Mark slots as 'unused' */
mt->frame = 1;
dev->mt = mt; dev->mt = mt;
return 0; return 0;
err_mem: err_mem:
...@@ -439,6 +442,8 @@ EXPORT_SYMBOL(input_mt_assign_slots); ...@@ -439,6 +442,8 @@ EXPORT_SYMBOL(input_mt_assign_slots);
* set the key on the first unused slot and return. * set the key on the first unused slot and return.
* *
* If no available slot can be found, -1 is returned. * If no available slot can be found, -1 is returned.
* Note that for this function to work properly, input_mt_sync_frame() has
* to be called at each frame.
*/ */
int input_mt_get_slot_by_key(struct input_dev *dev, int key) int input_mt_get_slot_by_key(struct input_dev *dev, int key)
{ {
...@@ -453,7 +458,7 @@ int input_mt_get_slot_by_key(struct input_dev *dev, int key) ...@@ -453,7 +458,7 @@ int input_mt_get_slot_by_key(struct input_dev *dev, int key)
return s - mt->slots; return s - mt->slots;
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
if (!input_mt_is_active(s)) { if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) {
s->key = key; s->key = key;
return s - mt->slots; return s - mt->slots;
} }
......
...@@ -213,7 +213,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -213,7 +213,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* get a report with all values through requesting one value */ /* get a report with all values through requesting one value */
sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev, sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev,
HID_USAGE_SENSOR_TIME, hid_time_addresses[0], HID_USAGE_SENSOR_TIME, hid_time_addresses[0],
time_state->info[0].report_id); time_state->info[0].report_id, SENSOR_HUB_SYNC);
/* wait for all values (event) */ /* wait for all values (event) */
ret = wait_for_completion_killable_timeout( ret = wait_for_completion_killable_timeout(
&time_state->comp_last_time, HZ*6); &time_state->comp_last_time, HZ*6);
......
This diff is collapsed.
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#define HID_MAX_PHY_DEVICES 0xFF #define HID_MAX_PHY_DEVICES 0xFF
#define HID_USAGE_SENSOR_COLLECTION 0x200001
/* Accel 3D (200073) */ /* Accel 3D (200073) */
#define HID_USAGE_SENSOR_ACCEL_3D 0x200073 #define HID_USAGE_SENSOR_ACCEL_3D 0x200073
#define HID_USAGE_SENSOR_DATA_ACCELERATION 0x200452 #define HID_USAGE_SENSOR_DATA_ACCELERATION 0x200452
......
...@@ -159,6 +159,7 @@ struct hid_item { ...@@ -159,6 +159,7 @@ struct hid_item {
#define HID_UP_LED 0x00080000 #define HID_UP_LED 0x00080000
#define HID_UP_BUTTON 0x00090000 #define HID_UP_BUTTON 0x00090000
#define HID_UP_ORDINAL 0x000a0000 #define HID_UP_ORDINAL 0x000a0000
#define HID_UP_TELEPHONY 0x000b0000
#define HID_UP_CONSUMER 0x000c0000 #define HID_UP_CONSUMER 0x000c0000
#define HID_UP_DIGITIZER 0x000d0000 #define HID_UP_DIGITIZER 0x000d0000
#define HID_UP_PID 0x000f0000 #define HID_UP_PID 0x000f0000
...@@ -269,6 +270,7 @@ struct hid_item { ...@@ -269,6 +270,7 @@ struct hid_item {
#define HID_DG_DEVICEINDEX 0x000d0053 #define HID_DG_DEVICEINDEX 0x000d0053
#define HID_DG_CONTACTCOUNT 0x000d0054 #define HID_DG_CONTACTCOUNT 0x000d0054
#define HID_DG_CONTACTMAX 0x000d0055 #define HID_DG_CONTACTMAX 0x000d0055
#define HID_DG_BUTTONTYPE 0x000d0059
#define HID_DG_BARRELSWITCH2 0x000d005a #define HID_DG_BARRELSWITCH2 0x000d005a
#define HID_DG_TOOLSERIALNUMBER 0x000d005b #define HID_DG_TOOLSERIALNUMBER 0x000d005b
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment