mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 05:32:00 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina: - Documentation conversion to ReST, from Mauro Carvalho Chehab - Wacom MobileStudio Pro support, from Ping Cheng - Wacom 2nd Gen Intuos Pro Small support, from Aaron Armstrong Skomra - assorted small fixes and device ID additions * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: HID: Add another Primax PIXART OEM mouse quirk HID: wacom: generic: add touchring adjustment for 2nd Gen Pro Small docs: hid: convert to ReST HID: remove NO_D3 flag when remove driver HID: wacom: add new MobileStudio Pro support HID: wacom: generic: read the number of expected touches on a per collection basis HID: wacom: generic: support the 'report valid' usage for touch HID: wacom: generic: read HID_DG_CONTACTMAX from any feature report HID: wacom: Add 2nd gen Intuos Pro Small support HID: uclogic: Add support for Ugee Rainbow CV720 HID: logitech-dj: fix return value of logi_dj_recv_query_hidpp_devices HID: logitech-hidpp: HID: make const array consumer_rdesc_start static HID: logitech-dj: make const array template static HID: wacom: correct touch resolution x/y typo HID: wacom: generic: Correct pad syncing HID: wacom: generic: only switch the mode on devices with LEDs HID: logitech-dj: Add usb-id for the 27MHz MX3000 receiver
This commit is contained in:
commit
4832a4dada
@ -1,19 +1,26 @@
|
|||||||
|
==========================
|
||||||
ALPS HID Touchpad Protocol
|
ALPS HID Touchpad Protocol
|
||||||
----------------------
|
==========================
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
Currently ALPS HID driver supports U1 Touchpad device.
|
Currently ALPS HID driver supports U1 Touchpad device.
|
||||||
|
|
||||||
U1 devuce basic information.
|
U1 device basic information.
|
||||||
|
|
||||||
|
========== ======
|
||||||
Vender ID 0x044E
|
Vender ID 0x044E
|
||||||
Product ID 0x120B
|
Product ID 0x120B
|
||||||
Version ID 0x0121
|
Version ID 0x0121
|
||||||
|
========== ======
|
||||||
|
|
||||||
|
|
||||||
HID Descriptor
|
HID Descriptor
|
||||||
------------
|
--------------
|
||||||
|
|
||||||
|
======= ==================== ===== =======================================
|
||||||
Byte Field Value Notes
|
Byte Field Value Notes
|
||||||
|
======= ==================== ===== =======================================
|
||||||
0 wHIDDescLength 001E Length of HID Descriptor : 30 bytes
|
0 wHIDDescLength 001E Length of HID Descriptor : 30 bytes
|
||||||
2 bcdVersion 0100 Compliant with Version 1.00
|
2 bcdVersion 0100 Compliant with Version 1.00
|
||||||
4 wReportDescLength 00B2 Report Descriptor is 178 Bytes (0x00B2)
|
4 wReportDescLength 00B2 Report Descriptor is 178 Bytes (0x00B2)
|
||||||
@ -28,10 +35,13 @@ Byte Field Value Notes
|
|||||||
22 wProductID 120B Product ID 0x120B
|
22 wProductID 120B Product ID 0x120B
|
||||||
24 wVersionID 0121 Version 01.21
|
24 wVersionID 0121 Version 01.21
|
||||||
26 RESERVED 0000 RESERVED
|
26 RESERVED 0000 RESERVED
|
||||||
|
======= ==================== ===== =======================================
|
||||||
|
|
||||||
|
|
||||||
Report ID
|
Report ID
|
||||||
------------
|
---------
|
||||||
|
|
||||||
|
========== ================= =========================================
|
||||||
ReportID-1 (Input Reports) (HIDUsage-Mouse) for TP&SP
|
ReportID-1 (Input Reports) (HIDUsage-Mouse) for TP&SP
|
||||||
ReportID-2 (Input Reports) (HIDUsage-keyboard) for TP
|
ReportID-2 (Input Reports) (HIDUsage-keyboard) for TP
|
||||||
ReportID-3 (Input Reports) (Vendor Usage: Max 10 finger data) for TP
|
ReportID-3 (Input Reports) (Vendor Usage: Max 10 finger data) for TP
|
||||||
@ -39,21 +49,28 @@ ReportID-4 (Input Reports) (Vendor Usage: ON bit data) for GP
|
|||||||
ReportID-5 (Feature Reports) Feature Reports
|
ReportID-5 (Feature Reports) Feature Reports
|
||||||
ReportID-6 (Input Reports) (Vendor Usage: StickPointer data) for SP
|
ReportID-6 (Input Reports) (Vendor Usage: StickPointer data) for SP
|
||||||
ReportID-7 (Feature Reports) Flash update (Bootloader)
|
ReportID-7 (Feature Reports) Flash update (Bootloader)
|
||||||
|
========== ================= =========================================
|
||||||
|
|
||||||
|
|
||||||
Data pattern
|
Data pattern
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
===== ========== ===== =================
|
||||||
Case1 ReportID_1 TP/SP Relative/Relative
|
Case1 ReportID_1 TP/SP Relative/Relative
|
||||||
Case2 ReportID_3 TP Absolute
|
Case2 ReportID_3 TP Absolute
|
||||||
ReportID_6 SP Absolute
|
ReportID_6 SP Absolute
|
||||||
|
===== ========== ===== =================
|
||||||
|
|
||||||
|
|
||||||
Command Read/Write
|
Command Read/Write
|
||||||
------------------
|
------------------
|
||||||
To read/write to RAM, need to send a commands to the device.
|
To read/write to RAM, need to send a commands to the device.
|
||||||
|
|
||||||
The command format is as below.
|
The command format is as below.
|
||||||
|
|
||||||
DataByte(SET_REPORT)
|
DataByte(SET_REPORT)
|
||||||
|
|
||||||
|
===== ======================
|
||||||
Byte1 Command Byte
|
Byte1 Command Byte
|
||||||
Byte2 Address - Byte 0 (LSB)
|
Byte2 Address - Byte 0 (LSB)
|
||||||
Byte3 Address - Byte 1
|
Byte3 Address - Byte 1
|
||||||
@ -61,13 +78,19 @@ Byte4 Address - Byte 2
|
|||||||
Byte5 Address - Byte 3 (MSB)
|
Byte5 Address - Byte 3 (MSB)
|
||||||
Byte6 Value Byte
|
Byte6 Value Byte
|
||||||
Byte7 Checksum
|
Byte7 Checksum
|
||||||
|
===== ======================
|
||||||
|
|
||||||
Command Byte is read=0xD1/write=0xD2 .
|
Command Byte is read=0xD1/write=0xD2 .
|
||||||
|
|
||||||
Address is read/write RAM address.
|
Address is read/write RAM address.
|
||||||
|
|
||||||
Value Byte is writing data when you send the write commands.
|
Value Byte is writing data when you send the write commands.
|
||||||
|
|
||||||
When you read RAM, there is no meaning.
|
When you read RAM, there is no meaning.
|
||||||
|
|
||||||
DataByte(GET_REPORT)
|
DataByte(GET_REPORT)
|
||||||
|
|
||||||
|
===== ======================
|
||||||
Byte1 Response Byte
|
Byte1 Response Byte
|
||||||
Byte2 Address - Byte 0 (LSB)
|
Byte2 Address - Byte 0 (LSB)
|
||||||
Byte3 Address - Byte 1
|
Byte3 Address - Byte 1
|
||||||
@ -75,6 +98,7 @@ Byte4 Address - Byte 2
|
|||||||
Byte5 Address - Byte 3 (MSB)
|
Byte5 Address - Byte 3 (MSB)
|
||||||
Byte6 Value Byte
|
Byte6 Value Byte
|
||||||
Byte7 Checksum
|
Byte7 Checksum
|
||||||
|
===== ======================
|
||||||
|
|
||||||
Read value is stored in Value Byte.
|
Read value is stored in Value Byte.
|
||||||
|
|
||||||
@ -82,7 +106,11 @@ Read value is stored in Value Byte.
|
|||||||
Packet Format
|
Packet Format
|
||||||
Touchpad data byte
|
Touchpad data byte
|
||||||
------------------
|
------------------
|
||||||
b7 b6 b5 b4 b3 b2 b1 b0
|
|
||||||
|
|
||||||
|
======= ======= ======= ======= ======= ======= ======= ======= =====
|
||||||
|
- b7 b6 b5 b4 b3 b2 b1 b0
|
||||||
|
======= ======= ======= ======= ======= ======= ======= ======= =====
|
||||||
1 0 0 SW6 SW5 SW4 SW3 SW2 SW1
|
1 0 0 SW6 SW5 SW4 SW3 SW2 SW1
|
||||||
2 0 0 0 Fcv Fn3 Fn2 Fn1 Fn0
|
2 0 0 0 Fcv Fn3 Fn2 Fn1 Fn0
|
||||||
3 Xa0_7 Xa0_6 Xa0_5 Xa0_4 Xa0_3 Xa0_2 Xa0_1 Xa0_0
|
3 Xa0_7 Xa0_6 Xa0_5 Xa0_4 Xa0_3 Xa0_2 Xa0_1 Xa0_0
|
||||||
@ -114,17 +142,25 @@ Touchpad data byte
|
|||||||
25 Ya4_7 Ya4_6 Ya4_5 Ya4_4 Ya4_3 Ya4_2 Ya4_1 Ya4_0
|
25 Ya4_7 Ya4_6 Ya4_5 Ya4_4 Ya4_3 Ya4_2 Ya4_1 Ya4_0
|
||||||
26 Ya4_15 Ya4_14 Ya4_13 Ya4_12 Ya4_11 Ya4_10 Ya4_9 Ya4_8
|
26 Ya4_15 Ya4_14 Ya4_13 Ya4_12 Ya4_11 Ya4_10 Ya4_9 Ya4_8
|
||||||
27 LFB4 Zs4_6 Zs4_5 Zs4_4 Zs4_3 Zs4_2 Zs4_1 Zs4_0
|
27 LFB4 Zs4_6 Zs4_5 Zs4_4 Zs4_3 Zs4_2 Zs4_1 Zs4_0
|
||||||
|
======= ======= ======= ======= ======= ======= ======= ======= =====
|
||||||
|
|
||||||
|
|
||||||
SW1-SW6: SW ON/OFF status
|
SW1-SW6:
|
||||||
Xan_15-0(16bit):X Absolute data of the "n"th finger
|
SW ON/OFF status
|
||||||
Yan_15-0(16bit):Y Absolute data of the "n"th finger
|
Xan_15-0(16bit):
|
||||||
Zsn_6-0(7bit): Operation area of the "n"th finger
|
X Absolute data of the "n"th finger
|
||||||
|
Yan_15-0(16bit):
|
||||||
|
Y Absolute data of the "n"th finger
|
||||||
|
Zsn_6-0(7bit):
|
||||||
|
Operation area of the "n"th finger
|
||||||
|
|
||||||
|
|
||||||
StickPointer data byte
|
StickPointer data byte
|
||||||
------------------
|
----------------------
|
||||||
b7 b6 b5 b4 b3 b2 b1 b0
|
|
||||||
|
======= ======= ======= ======= ======= ======= ======= ======= =====
|
||||||
|
- b7 b6 b5 b4 b3 b2 b1 b0
|
||||||
|
======= ======= ======= ======= ======= ======= ======= ======= =====
|
||||||
Byte1 1 1 1 0 1 SW3 SW2 SW1
|
Byte1 1 1 1 0 1 SW3 SW2 SW1
|
||||||
Byte2 X7 X6 X5 X4 X3 X2 X1 X0
|
Byte2 X7 X6 X5 X4 X3 X2 X1 X0
|
||||||
Byte3 X15 X14 X13 X12 X11 X10 X9 X8
|
Byte3 X15 X14 X13 X12 X11 X10 X9 X8
|
||||||
@ -132,8 +168,13 @@ Byte4 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
|
|||||||
Byte5 Y15 Y14 Y13 Y12 Y11 Y10 Y9 Y8
|
Byte5 Y15 Y14 Y13 Y12 Y11 Y10 Y9 Y8
|
||||||
Byte6 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
|
Byte6 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
|
||||||
Byte7 T&P Z14 Z13 Z12 Z11 Z10 Z9 Z8
|
Byte7 T&P Z14 Z13 Z12 Z11 Z10 Z9 Z8
|
||||||
|
======= ======= ======= ======= ======= ======= ======= ======= =====
|
||||||
|
|
||||||
SW1-SW3: SW ON/OFF status
|
SW1-SW3:
|
||||||
Xn_15-0(16bit):X Absolute data
|
SW ON/OFF status
|
||||||
Yn_15-0(16bit):Y Absolute data
|
Xn_15-0(16bit):
|
||||||
Zn_14-0(15bit):Z
|
X Absolute data
|
||||||
|
Yn_15-0(16bit):
|
||||||
|
Y Absolute data
|
||||||
|
Zn_14-0(15bit):
|
||||||
|
Z
|
@ -1,6 +1,6 @@
|
|||||||
|
=====================
|
||||||
HID Sensors Framework
|
HID Sensors Framework
|
||||||
======================
|
=====================
|
||||||
HID sensor framework provides necessary interfaces to implement sensor drivers,
|
HID sensor framework provides necessary interfaces to implement sensor drivers,
|
||||||
which are connected to a sensor hub. The sensor hub is a HID device and it provides
|
which are connected to a sensor hub. The sensor hub is a HID device and it provides
|
||||||
a report descriptor conforming to HID 1.12 sensor usage tables.
|
a report descriptor conforming to HID 1.12 sensor usage tables.
|
||||||
@ -15,7 +15,7 @@ the drivers themselves."
|
|||||||
This specification describes many usage IDs, which describe the type of sensor
|
This specification describes many usage IDs, which describe the type of sensor
|
||||||
and also the individual data fields. Each sensor can have variable number of
|
and also the individual data fields. Each sensor can have variable number of
|
||||||
data fields. The length and order is specified in the report descriptor. For
|
data fields. The length and order is specified in the report descriptor. For
|
||||||
example a part of report descriptor can look like:
|
example a part of report descriptor can look like::
|
||||||
|
|
||||||
INPUT(1)[INPUT]
|
INPUT(1)[INPUT]
|
||||||
..
|
..
|
||||||
@ -40,13 +40,14 @@ data will use this format.
|
|||||||
|
|
||||||
|
|
||||||
Implementation
|
Implementation
|
||||||
=================
|
==============
|
||||||
|
|
||||||
This specification defines many different types of sensors with different sets of
|
This specification defines many different types of sensors with different sets of
|
||||||
data fields. It is difficult to have a common input event to user space applications,
|
data fields. It is difficult to have a common input event to user space applications,
|
||||||
for different sensors. For example an accelerometer can send X,Y and Z data, whereas
|
for different sensors. For example an accelerometer can send X,Y and Z data, whereas
|
||||||
an ambient light sensor can send illumination data.
|
an ambient light sensor can send illumination data.
|
||||||
So the implementation has two parts:
|
So the implementation has two parts:
|
||||||
|
|
||||||
- Core hid driver
|
- Core hid driver
|
||||||
- Individual sensor processing part (sensor drivers)
|
- Individual sensor processing part (sensor drivers)
|
||||||
|
|
||||||
@ -55,8 +56,11 @@ Core driver
|
|||||||
The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
|
The core driver registers (hid-sensor-hub) registers as a HID driver. It parses
|
||||||
report descriptors and identifies all the sensors present. It adds an MFD device
|
report descriptors and identifies all the sensors present. It adds an MFD device
|
||||||
with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
|
with name HID-SENSOR-xxxx (where xxxx is usage id from the specification).
|
||||||
For example
|
|
||||||
|
For example:
|
||||||
|
|
||||||
HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
|
HID-SENSOR-200073 is registered for an Accelerometer 3D driver.
|
||||||
|
|
||||||
So if any driver with this name is inserted, then the probe routine for that
|
So if any driver with this name is inserted, then the probe routine for that
|
||||||
function will be called. So an accelerometer processing driver can register
|
function will be called. So an accelerometer processing driver can register
|
||||||
with this name and will be probed if there is an accelerometer-3D detected.
|
with this name and will be probed if there is an accelerometer-3D detected.
|
||||||
@ -66,7 +70,8 @@ drivers to register and get events for that usage id. Also it provides parsing
|
|||||||
functions, which get and set each input/feature/output report.
|
functions, which get and set each input/feature/output report.
|
||||||
|
|
||||||
Individual sensor processing part (sensor drivers)
|
Individual sensor processing part (sensor drivers)
|
||||||
-----------
|
--------------------------------------------------
|
||||||
|
|
||||||
The processing driver will use an interface provided by the core driver to parse
|
The processing driver will use an interface provided by the core driver to parse
|
||||||
the report and get the indexes of the fields and also can get events. This driver
|
the report and get the indexes of the fields and also can get events. This driver
|
||||||
can use IIO interface to use the standard ABI defined for a type of sensor.
|
can use IIO interface to use the standard ABI defined for a type of sensor.
|
||||||
@ -75,7 +80,8 @@ can use IIO interface to use the standard ABI defined for a type of sensor.
|
|||||||
Core driver Interface
|
Core driver Interface
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
Callback structure:
|
Callback structure::
|
||||||
|
|
||||||
Each processing driver can use this structure to set some callbacks.
|
Each processing driver can use this structure to set some callbacks.
|
||||||
int (*suspend)(..): Callback when HID suspend is received
|
int (*suspend)(..): Callback when HID suspend is received
|
||||||
int (*resume)(..): Callback when HID resume is received
|
int (*resume)(..): Callback when HID resume is received
|
||||||
@ -83,13 +89,14 @@ Each processing driver can use this structure to set some callbacks.
|
|||||||
int (*send_event)(..): One complete event is received which can have
|
int (*send_event)(..): One complete event is received which can have
|
||||||
multiple data fields.
|
multiple data fields.
|
||||||
|
|
||||||
Registration functions:
|
Registration functions::
|
||||||
|
|
||||||
int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
|
int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
|
||||||
u32 usage_id,
|
u32 usage_id,
|
||||||
struct hid_sensor_hub_callbacks *usage_callback):
|
struct hid_sensor_hub_callbacks *usage_callback):
|
||||||
|
|
||||||
Registers callbacks for an usage id. The callback functions are not allowed
|
Registers callbacks for an usage id. The callback functions are not allowed
|
||||||
to sleep.
|
to sleep::
|
||||||
|
|
||||||
|
|
||||||
int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
|
int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
|
||||||
@ -98,7 +105,8 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
|
|||||||
Removes callbacks for an usage id.
|
Removes callbacks for an usage id.
|
||||||
|
|
||||||
|
|
||||||
Parsing function:
|
Parsing function::
|
||||||
|
|
||||||
int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
|
int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
|
||||||
u8 type,
|
u8 type,
|
||||||
u32 usage_id, u32 attr_usage_id,
|
u32 usage_id, u32 attr_usage_id,
|
||||||
@ -110,14 +118,15 @@ so that fields can be set or get individually.
|
|||||||
These indexes avoid searching every time and getting field index to get or set.
|
These indexes avoid searching every time and getting field index to get or set.
|
||||||
|
|
||||||
|
|
||||||
Set Feature report
|
Set Feature report::
|
||||||
|
|
||||||
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||||
u32 field_index, s32 value);
|
u32 field_index, s32 value);
|
||||||
|
|
||||||
This interface is used to set a value for a field in feature report. For example
|
This interface is used to set a value for a field in feature report. For example
|
||||||
if there is a field report_interval, which is parsed by a call to
|
if there is a field report_interval, which is parsed by a call to
|
||||||
sensor_hub_input_get_attribute_info before, then it can directly set that individual
|
sensor_hub_input_get_attribute_info before, then it can directly set that
|
||||||
field.
|
individual field::
|
||||||
|
|
||||||
|
|
||||||
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||||
@ -125,8 +134,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
|||||||
|
|
||||||
This interface is used to get a value for a field in input report. For example
|
This interface is used to get a value for a field in input report. For example
|
||||||
if there is a field report_interval, which is parsed by a call to
|
if there is a field report_interval, which is parsed by a call to
|
||||||
sensor_hub_input_get_attribute_info before, then it can directly get that individual
|
sensor_hub_input_get_attribute_info before, then it can directly get that
|
||||||
field value.
|
individual field value::
|
||||||
|
|
||||||
|
|
||||||
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
|
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
|
||||||
@ -143,6 +152,8 @@ registered callback function to process the sample.
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
HID Custom and generic Sensors
|
HID Custom and generic Sensors
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
|
||||||
HID Sensor specification defines two special sensor usage types. Since they
|
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
|
don't represent a standard sensor, it is not possible to define using Linux IIO
|
||||||
@ -158,47 +169,50 @@ keyboard attached/detached or lid open/close.
|
|||||||
To allow application to utilize these sensors, here they are exported uses sysfs
|
To allow application to utilize these sensors, here they are exported uses sysfs
|
||||||
attribute groups, attributes and misc device interface.
|
attribute groups, attributes and misc device interface.
|
||||||
|
|
||||||
An example of this representation on sysfs:
|
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
|
/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
|
||||||
.
|
.
|
||||||
????????? enable_sensor
|
│ ├── enable_sensor
|
||||||
????????? feature-0-200316
|
│ │ ├── feature-0-200316
|
||||||
??????? ????????? feature-0-200316-maximum
|
│ │ │ ├── feature-0-200316-maximum
|
||||||
??????? ????????? feature-0-200316-minimum
|
│ │ │ ├── feature-0-200316-minimum
|
||||||
??????? ????????? feature-0-200316-name
|
│ │ │ ├── feature-0-200316-name
|
||||||
??????? ????????? feature-0-200316-size
|
│ │ │ ├── feature-0-200316-size
|
||||||
??????? ????????? feature-0-200316-unit-expo
|
│ │ │ ├── feature-0-200316-unit-expo
|
||||||
??????? ????????? feature-0-200316-units
|
│ │ │ ├── feature-0-200316-units
|
||||||
??????? ????????? feature-0-200316-value
|
│ │ │ ├── feature-0-200316-value
|
||||||
????????? feature-1-200201
|
│ │ ├── feature-1-200201
|
||||||
??????? ????????? feature-1-200201-maximum
|
│ │ │ ├── feature-1-200201-maximum
|
||||||
??????? ????????? feature-1-200201-minimum
|
│ │ │ ├── feature-1-200201-minimum
|
||||||
??????? ????????? feature-1-200201-name
|
│ │ │ ├── feature-1-200201-name
|
||||||
??????? ????????? feature-1-200201-size
|
│ │ │ ├── feature-1-200201-size
|
||||||
??????? ????????? feature-1-200201-unit-expo
|
│ │ │ ├── feature-1-200201-unit-expo
|
||||||
??????? ????????? feature-1-200201-units
|
│ │ │ ├── feature-1-200201-units
|
||||||
??????? ????????? feature-1-200201-value
|
│ │ │ ├── feature-1-200201-value
|
||||||
????????? input-0-200201
|
│ │ ├── input-0-200201
|
||||||
??????? ????????? input-0-200201-maximum
|
│ │ │ ├── input-0-200201-maximum
|
||||||
??????? ????????? input-0-200201-minimum
|
│ │ │ ├── input-0-200201-minimum
|
||||||
??????? ????????? input-0-200201-name
|
│ │ │ ├── input-0-200201-name
|
||||||
??????? ????????? input-0-200201-size
|
│ │ │ ├── input-0-200201-size
|
||||||
??????? ????????? input-0-200201-unit-expo
|
│ │ │ ├── input-0-200201-unit-expo
|
||||||
??????? ????????? input-0-200201-units
|
│ │ │ ├── input-0-200201-units
|
||||||
??????? ????????? input-0-200201-value
|
│ │ │ ├── input-0-200201-value
|
||||||
????????? input-1-200202
|
│ │ ├── input-1-200202
|
||||||
??????? ????????? input-1-200202-maximum
|
│ │ │ ├── input-1-200202-maximum
|
||||||
??????? ????????? input-1-200202-minimum
|
│ │ │ ├── input-1-200202-minimum
|
||||||
??????? ????????? input-1-200202-name
|
│ │ │ ├── input-1-200202-name
|
||||||
??????? ????????? input-1-200202-size
|
│ │ │ ├── input-1-200202-size
|
||||||
??????? ????????? input-1-200202-unit-expo
|
│ │ │ ├── input-1-200202-unit-expo
|
||||||
??????? ????????? input-1-200202-units
|
│ │ │ ├── input-1-200202-units
|
||||||
??????? ????????? input-1-200202-value
|
│ │ │ ├── input-1-200202-value
|
||||||
|
|
||||||
Here there is a custom sensors with four fields, two feature and two inputs.
|
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"
|
Each field is represented by a set of attributes. All fields except the "value"
|
||||||
are read only. The value field is a RW field.
|
are read only. The value field is a RW field.
|
||||||
Example
|
|
||||||
|
Example::
|
||||||
|
|
||||||
/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
|
/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
|
||||||
feature-0-200316-maximum:6
|
feature-0-200316-maximum:6
|
||||||
feature-0-200316-minimum:0
|
feature-0-200316-minimum:0
|
||||||
@ -209,15 +223,19 @@ feature-0-200316-units:25
|
|||||||
feature-0-200316-value:1
|
feature-0-200316-value:1
|
||||||
|
|
||||||
How to enable such sensor?
|
How to enable such sensor?
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
By default sensor can be power gated. To enable sysfs attribute "enable" can be
|
By default sensor can be power gated. To enable sysfs attribute "enable" can be
|
||||||
used.
|
used::
|
||||||
|
|
||||||
$ echo 1 > enable_sensor
|
$ echo 1 > enable_sensor
|
||||||
|
|
||||||
Once enabled and powered on, sensor can report value using HID reports.
|
Once enabled and powered on, sensor can report value using HID reports.
|
||||||
These reports are pushed using misc device interface in a FIFO order.
|
These reports are pushed using misc device interface in a FIFO order::
|
||||||
|
|
||||||
/dev$ tree | grep HID-SENSOR-2000e1.6.auto
|
/dev$ tree | grep HID-SENSOR-2000e1.6.auto
|
||||||
??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto
|
│ │ │ ├── 10:53 -> ../HID-SENSOR-2000e1.6.auto
|
||||||
????????? HID-SENSOR-2000e1.6.auto
|
│ ├── HID-SENSOR-2000e1.6.auto
|
||||||
|
|
||||||
Each reports can be of variable length preceded by a header. This header
|
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
|
consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
|
@ -1,5 +1,6 @@
|
|||||||
|
=========================
|
||||||
HID I/O Transport Drivers
|
HID I/O Transport Drivers
|
||||||
===========================
|
=========================
|
||||||
|
|
||||||
The HID subsystem is independent of the underlying transport driver. Initially,
|
The HID subsystem is independent of the underlying transport driver. Initially,
|
||||||
only USB was supported, but other specifications adopted the HID design and
|
only USB was supported, but other specifications adopted the HID design and
|
||||||
@ -16,6 +17,8 @@ transport and device setup/management. HID core is responsible of
|
|||||||
report-parsing, report interpretation and the user-space API. Device specifics
|
report-parsing, report interpretation and the user-space API. Device specifics
|
||||||
and quirks are handled by all layers depending on the quirk.
|
and quirks are handled by all layers depending on the quirk.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
+-----------+ +-----------+ +-----------+ +-----------+
|
+-----------+ +-----------+ +-----------+ +-----------+
|
||||||
| Device #1 | | Device #i | | Device #j | | Device #k |
|
| Device #1 | | Device #i | | Device #j | | Device #k |
|
||||||
+-----------+ +-----------+ +-----------+ +-----------+
|
+-----------+ +-----------+ +-----------+ +-----------+
|
||||||
@ -42,8 +45,9 @@ and quirks are handled by all layers depending on the quirk.
|
|||||||
+----------------+ +-----------+ +------------------+ +------------------+
|
+----------------+ +-----------+ +------------------+ +------------------+
|
||||||
|
|
||||||
Example Drivers:
|
Example Drivers:
|
||||||
I/O: USB, I2C, Bluetooth-l2cap
|
|
||||||
Transport: USB-HID, I2C-HID, BT-HIDP
|
- I/O: USB, I2C, Bluetooth-l2cap
|
||||||
|
- Transport: USB-HID, I2C-HID, BT-HIDP
|
||||||
|
|
||||||
Everything below "HID Core" is simplified in this graph as it is only of
|
Everything below "HID Core" is simplified in this graph as it is only of
|
||||||
interest to HID device drivers. Transport drivers do not need to know the
|
interest to HID device drivers. Transport drivers do not need to know the
|
||||||
@ -183,7 +187,7 @@ Other ctrl-channel requests are supported by USB-HID but are not available
|
|||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Transport drivers normally use the following procedure to register a new device
|
Transport drivers normally use the following procedure to register a new device
|
||||||
with HID core:
|
with HID core::
|
||||||
|
|
||||||
struct hid_device *hid;
|
struct hid_device *hid;
|
||||||
int ret;
|
int ret;
|
||||||
@ -215,7 +219,7 @@ Once hid_add_device() is entered, HID core might use the callbacks provided in
|
|||||||
"custom_ll_driver". Note that fields like "country" can be ignored by underlying
|
"custom_ll_driver". Note that fields like "country" can be ignored by underlying
|
||||||
transport-drivers if not supported.
|
transport-drivers if not supported.
|
||||||
|
|
||||||
To unregister a device, use:
|
To unregister a device, use::
|
||||||
|
|
||||||
hid_destroy_device(hid);
|
hid_destroy_device(hid);
|
||||||
|
|
||||||
@ -226,73 +230,110 @@ driver callbacks.
|
|||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
The available HID callbacks are:
|
The available HID callbacks are:
|
||||||
- int (*start) (struct hid_device *hdev)
|
|
||||||
|
::
|
||||||
|
|
||||||
|
int (*start) (struct hid_device *hdev)
|
||||||
|
|
||||||
Called from HID device drivers once they want to use the device. Transport
|
Called from HID device drivers once they want to use the device. Transport
|
||||||
drivers can choose to setup their device in this callback. However, normally
|
drivers can choose to setup their device in this callback. However, normally
|
||||||
devices are already set up before transport drivers register them to HID core
|
devices are already set up before transport drivers register them to HID core
|
||||||
so this is mostly only used by USB-HID.
|
so this is mostly only used by USB-HID.
|
||||||
|
|
||||||
- void (*stop) (struct hid_device *hdev)
|
::
|
||||||
|
|
||||||
|
void (*stop) (struct hid_device *hdev)
|
||||||
|
|
||||||
Called from HID device drivers once they are done with a device. Transport
|
Called from HID device drivers once they are done with a device. Transport
|
||||||
drivers can free any buffers and deinitialize the device. But note that
|
drivers can free any buffers and deinitialize the device. But note that
|
||||||
->start() might be called again if another HID device driver is loaded on the
|
->start() might be called again if another HID device driver is loaded on the
|
||||||
device.
|
device.
|
||||||
|
|
||||||
Transport drivers are free to ignore it and deinitialize devices after they
|
Transport drivers are free to ignore it and deinitialize devices after they
|
||||||
destroyed them via hid_destroy_device().
|
destroyed them via hid_destroy_device().
|
||||||
|
|
||||||
- int (*open) (struct hid_device *hdev)
|
::
|
||||||
|
|
||||||
|
int (*open) (struct hid_device *hdev)
|
||||||
|
|
||||||
Called from HID device drivers once they are interested in data reports.
|
Called from HID device drivers once they are interested in data reports.
|
||||||
Usually, while user-space didn't open any input API/etc., device drivers are
|
Usually, while user-space didn't open any input API/etc., device drivers are
|
||||||
not interested in device data and transport drivers can put devices asleep.
|
not interested in device data and transport drivers can put devices asleep.
|
||||||
However, once ->open() is called, transport drivers must be ready for I/O.
|
However, once ->open() is called, transport drivers must be ready for I/O.
|
||||||
->open() calls are nested for each client that opens the HID device.
|
->open() calls are nested for each client that opens the HID device.
|
||||||
|
|
||||||
- void (*close) (struct hid_device *hdev)
|
::
|
||||||
|
|
||||||
|
void (*close) (struct hid_device *hdev)
|
||||||
|
|
||||||
Called from HID device drivers after ->open() was called but they are no
|
Called from HID device drivers after ->open() was called but they are no
|
||||||
longer interested in device reports. (Usually if user-space closed any input
|
longer interested in device reports. (Usually if user-space closed any input
|
||||||
devices of the driver).
|
devices of the driver).
|
||||||
|
|
||||||
Transport drivers can put devices asleep and terminate any I/O of all
|
Transport drivers can put devices asleep and terminate any I/O of all
|
||||||
->open() calls have been followed by a ->close() call. However, ->start() may
|
->open() calls have been followed by a ->close() call. However, ->start() may
|
||||||
be called again if the device driver is interested in input reports again.
|
be called again if the device driver is interested in input reports again.
|
||||||
|
|
||||||
- int (*parse) (struct hid_device *hdev)
|
::
|
||||||
|
|
||||||
|
int (*parse) (struct hid_device *hdev)
|
||||||
|
|
||||||
Called once during device setup after ->start() has been called. Transport
|
Called once during device setup after ->start() has been called. Transport
|
||||||
drivers must read the HID report-descriptor from the device and tell HID core
|
drivers must read the HID report-descriptor from the device and tell HID core
|
||||||
about it via hid_parse_report().
|
about it via hid_parse_report().
|
||||||
|
|
||||||
- int (*power) (struct hid_device *hdev, int level)
|
::
|
||||||
|
|
||||||
|
int (*power) (struct hid_device *hdev, int level)
|
||||||
|
|
||||||
Called by HID core to give PM hints to transport drivers. Usually this is
|
Called by HID core to give PM hints to transport drivers. Usually this is
|
||||||
analogical to the ->open() and ->close() hints and redundant.
|
analogical to the ->open() and ->close() hints and redundant.
|
||||||
|
|
||||||
- void (*request) (struct hid_device *hdev, struct hid_report *report,
|
::
|
||||||
|
|
||||||
|
void (*request) (struct hid_device *hdev, struct hid_report *report,
|
||||||
int reqtype)
|
int reqtype)
|
||||||
|
|
||||||
Send an HID request on the ctrl channel. "report" contains the report that
|
Send an HID request on the ctrl channel. "report" contains the report that
|
||||||
should be sent and "reqtype" the request type. Request-type can be
|
should be sent and "reqtype" the request type. Request-type can be
|
||||||
HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
|
HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
|
||||||
|
|
||||||
This callback is optional. If not provided, HID core will assemble a raw
|
This callback is optional. If not provided, HID core will assemble a raw
|
||||||
report following the HID specs and send it via the ->raw_request() callback.
|
report following the HID specs and send it via the ->raw_request() callback.
|
||||||
The transport driver is free to implement this asynchronously.
|
The transport driver is free to implement this asynchronously.
|
||||||
|
|
||||||
- int (*wait) (struct hid_device *hdev)
|
::
|
||||||
|
|
||||||
|
int (*wait) (struct hid_device *hdev)
|
||||||
|
|
||||||
Used by HID core before calling ->request() again. A transport driver can use
|
Used by HID core before calling ->request() again. A transport driver can use
|
||||||
it to wait for any pending requests to complete if only one request is
|
it to wait for any pending requests to complete if only one request is
|
||||||
allowed at a time.
|
allowed at a time.
|
||||||
|
|
||||||
- int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
|
::
|
||||||
|
|
||||||
|
int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
|
||||||
__u8 *buf, size_t count, unsigned char rtype,
|
__u8 *buf, size_t count, unsigned char rtype,
|
||||||
int reqtype)
|
int reqtype)
|
||||||
|
|
||||||
Same as ->request() but provides the report as raw buffer. This request shall
|
Same as ->request() but provides the report as raw buffer. This request shall
|
||||||
be synchronous. A transport driver must not use ->wait() to complete such
|
be synchronous. A transport driver must not use ->wait() to complete such
|
||||||
requests. This request is mandatory and hid core will reject the device if
|
requests. This request is mandatory and hid core will reject the device if
|
||||||
it is missing.
|
it is missing.
|
||||||
|
|
||||||
- int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
|
::
|
||||||
|
|
||||||
|
int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
|
||||||
|
|
||||||
Send raw output report via intr channel. Used by some HID device drivers
|
Send raw output report via intr channel. Used by some HID device drivers
|
||||||
which require high throughput for outgoing requests on the intr channel. This
|
which require high throughput for outgoing requests on the intr channel. This
|
||||||
must not cause SET_REPORT calls! This must be implemented as asynchronous
|
must not cause SET_REPORT calls! This must be implemented as asynchronous
|
||||||
output report on the intr channel!
|
output report on the intr channel!
|
||||||
|
|
||||||
- int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
|
::
|
||||||
|
|
||||||
|
int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
|
||||||
|
|
||||||
Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
|
Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
|
||||||
|
|
||||||
2.3) Data Path
|
2.3) Data Path
|
||||||
@ -314,4 +355,5 @@ transport driver and not passed to hid_input_report().
|
|||||||
Acknowledgements to SET_REPORT requests are not of interest to HID core.
|
Acknowledgements to SET_REPORT requests are not of interest to HID core.
|
||||||
|
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
Written 2013, David Herrmann <dh.herrmann@gmail.com>
|
Written 2013, David Herrmann <dh.herrmann@gmail.com>
|
@ -1,6 +1,9 @@
|
|||||||
|
================================================
|
||||||
Care and feeding of your Human Interface Devices
|
Care and feeding of your Human Interface Devices
|
||||||
|
================================================
|
||||||
|
|
||||||
INTRODUCTION
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
In addition to the normal input type HID devices, USB also uses the
|
In addition to the normal input type HID devices, USB also uses the
|
||||||
human interface device protocols for things that are not really human
|
human interface device protocols for things that are not really human
|
||||||
@ -16,7 +19,7 @@ normalised event interface - see Documentation/input/input.rst
|
|||||||
* the hiddev interface, which provides fairly raw HID events
|
* the hiddev interface, which provides fairly raw HID events
|
||||||
|
|
||||||
The data flow for a HID event produced by a device is something like
|
The data flow for a HID event produced by a device is something like
|
||||||
the following :
|
the following::
|
||||||
|
|
||||||
usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event]
|
usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event]
|
||||||
|
|
|
|
||||||
@ -27,11 +30,13 @@ In addition, other subsystems (apart from USB) can potentially feed
|
|||||||
events into the input subsystem, but these have no effect on the hid
|
events into the input subsystem, but these have no effect on the hid
|
||||||
device interface.
|
device interface.
|
||||||
|
|
||||||
USING THE HID DEVICE INTERFACE
|
Using the HID Device Interface
|
||||||
|
==============================
|
||||||
|
|
||||||
The hiddev interface is a char interface using the normal USB major,
|
The hiddev interface is a char interface using the normal USB major,
|
||||||
with the minor numbers starting at 96 and finishing at 111. Therefore,
|
with the minor numbers starting at 96 and finishing at 111. Therefore,
|
||||||
you need the following commands:
|
you need the following commands::
|
||||||
|
|
||||||
mknod /dev/usb/hiddev0 c 180 96
|
mknod /dev/usb/hiddev0 c 180 96
|
||||||
mknod /dev/usb/hiddev1 c 180 97
|
mknod /dev/usb/hiddev1 c 180 97
|
||||||
mknod /dev/usb/hiddev2 c 180 98
|
mknod /dev/usb/hiddev2 c 180 98
|
||||||
@ -56,7 +61,9 @@ Assuming that you have a hiddev compliant user-space program, of
|
|||||||
course. If you need to write one, read on.
|
course. If you need to write one, read on.
|
||||||
|
|
||||||
|
|
||||||
THE HIDDEV API
|
The HIDDEV API
|
||||||
|
==============
|
||||||
|
|
||||||
This description should be read in conjunction with the HID
|
This description should be read in conjunction with the HID
|
||||||
specification, freely available from http://www.usb.org, and
|
specification, freely available from http://www.usb.org, and
|
||||||
conveniently linked of http://www.linux-usb.org.
|
conveniently linked of http://www.linux-usb.org.
|
||||||
@ -69,12 +76,14 @@ each of which can have one or more "usages". In the hid-core,
|
|||||||
each one of these usages has a single signed 32 bit value.
|
each one of these usages has a single signed 32 bit value.
|
||||||
|
|
||||||
read():
|
read():
|
||||||
|
-------
|
||||||
|
|
||||||
This is the event interface. When the HID device's state changes,
|
This is the event interface. When the HID device's state changes,
|
||||||
it performs an interrupt transfer containing a report which contains
|
it performs an interrupt transfer containing a report which contains
|
||||||
the changed value. The hid-core.c module parses the report, and
|
the changed value. The hid-core.c module parses the report, and
|
||||||
returns to hiddev.c the individual usages that have changed within
|
returns to hiddev.c the individual usages that have changed within
|
||||||
the report. In its basic mode, the hiddev will make these individual
|
the report. In its basic mode, the hiddev will make these individual
|
||||||
usage changes available to the reader using a struct hiddev_event:
|
usage changes available to the reader using a struct hiddev_event::
|
||||||
|
|
||||||
struct hiddev_event {
|
struct hiddev_event {
|
||||||
unsigned hid;
|
unsigned hid;
|
||||||
@ -91,12 +100,18 @@ ioctl() described below.
|
|||||||
|
|
||||||
|
|
||||||
ioctl():
|
ioctl():
|
||||||
|
--------
|
||||||
|
|
||||||
This is the control interface. There are a number of controls:
|
This is the control interface. There are a number of controls:
|
||||||
|
|
||||||
HIDIOCGVERSION - int (read)
|
HIDIOCGVERSION
|
||||||
|
- int (read)
|
||||||
|
|
||||||
Gets the version code out of the hiddev driver.
|
Gets the version code out of the hiddev driver.
|
||||||
|
|
||||||
HIDIOCAPPLICATION - (none)
|
HIDIOCAPPLICATION
|
||||||
|
- (none)
|
||||||
|
|
||||||
This ioctl call returns the HID application usage associated with the
|
This ioctl call returns the HID application usage associated with the
|
||||||
hid device. The third argument to ioctl() specifies which application
|
hid device. The third argument to ioctl() specifies which application
|
||||||
index to get. This is useful when the device has more than one
|
index to get. This is useful when the device has more than one
|
||||||
@ -106,7 +121,9 @@ returns -1. You can find out beforehand how many application
|
|||||||
collections the device has from the num_applications field from the
|
collections the device has from the num_applications field from the
|
||||||
hiddev_devinfo structure.
|
hiddev_devinfo structure.
|
||||||
|
|
||||||
HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write)
|
HIDIOCGCOLLECTIONINFO
|
||||||
|
- struct hiddev_collection_info (read/write)
|
||||||
|
|
||||||
This returns a superset of the information above, providing not only
|
This returns a superset of the information above, providing not only
|
||||||
application collections, but all the collections the device has. It
|
application collections, but all the collections the device has. It
|
||||||
also returns the level the collection lives in the hierarchy.
|
also returns the level the collection lives in the hierarchy.
|
||||||
@ -115,14 +132,20 @@ field set to the index that should be returned. The ioctl fills in
|
|||||||
the other fields. If the index is larger than the last collection
|
the other fields. If the index is larger than the last collection
|
||||||
index, the ioctl returns -1 and sets errno to -EINVAL.
|
index, the ioctl returns -1 and sets errno to -EINVAL.
|
||||||
|
|
||||||
HIDIOCGDEVINFO - struct hiddev_devinfo (read)
|
HIDIOCGDEVINFO
|
||||||
|
- struct hiddev_devinfo (read)
|
||||||
|
|
||||||
Gets a hiddev_devinfo structure which describes the device.
|
Gets a hiddev_devinfo structure which describes the device.
|
||||||
|
|
||||||
HIDIOCGSTRING - struct hiddev_string_descriptor (read/write)
|
HIDIOCGSTRING
|
||||||
|
- struct hiddev_string_descriptor (read/write)
|
||||||
|
|
||||||
Gets a string descriptor from the device. The caller must fill in the
|
Gets a string descriptor from the device. The caller must fill in the
|
||||||
"index" field to indicate which descriptor should be returned.
|
"index" field to indicate which descriptor should be returned.
|
||||||
|
|
||||||
HIDIOCINITREPORT - (none)
|
HIDIOCINITREPORT
|
||||||
|
- (none)
|
||||||
|
|
||||||
Instructs the kernel to retrieve all input and feature report values
|
Instructs the kernel to retrieve all input and feature report values
|
||||||
from the device. At this point, all the usage structures will contain
|
from the device. At this point, all the usage structures will contain
|
||||||
current values for the device, and will maintain it as the device
|
current values for the device, and will maintain it as the device
|
||||||
@ -130,21 +153,29 @@ changes. Note that the use of this ioctl is unnecessary in general,
|
|||||||
since later kernels automatically initialize the reports from the
|
since later kernels automatically initialize the reports from the
|
||||||
device at attach time.
|
device at attach time.
|
||||||
|
|
||||||
HIDIOCGNAME - string (variable length)
|
HIDIOCGNAME
|
||||||
|
- string (variable length)
|
||||||
|
|
||||||
Gets the device name
|
Gets the device name
|
||||||
|
|
||||||
HIDIOCGREPORT - struct hiddev_report_info (write)
|
HIDIOCGREPORT
|
||||||
|
- struct hiddev_report_info (write)
|
||||||
|
|
||||||
Instructs the kernel to get a feature or input report from the device,
|
Instructs the kernel to get a feature or input report from the device,
|
||||||
in order to selectively update the usage structures (in contrast to
|
in order to selectively update the usage structures (in contrast to
|
||||||
INITREPORT).
|
INITREPORT).
|
||||||
|
|
||||||
HIDIOCSREPORT - struct hiddev_report_info (write)
|
HIDIOCSREPORT
|
||||||
|
- struct hiddev_report_info (write)
|
||||||
|
|
||||||
Instructs the kernel to send a report to the device. This report can
|
Instructs the kernel to send a report to the device. This report can
|
||||||
be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
|
be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
|
||||||
individual usage values in the report before sending the report in full
|
individual usage values in the report before sending the report in full
|
||||||
to the device.
|
to the device.
|
||||||
|
|
||||||
HIDIOCGREPORTINFO - struct hiddev_report_info (read/write)
|
HIDIOCGREPORTINFO
|
||||||
|
- struct hiddev_report_info (read/write)
|
||||||
|
|
||||||
Fills in a hiddev_report_info structure for the user. The report is
|
Fills in a hiddev_report_info structure for the user. The report is
|
||||||
looked up by type (input, output or feature) and id, so these fields
|
looked up by type (input, output or feature) and id, so these fields
|
||||||
must be filled in by the user. The ID can be absolute -- the actual
|
must be filled in by the user. The ID can be absolute -- the actual
|
||||||
@ -156,19 +187,25 @@ use the relative IDs above to enumerate the valid IDs. The ioctl
|
|||||||
returns non-zero when there is no more next ID. The real report ID is
|
returns non-zero when there is no more next ID. The real report ID is
|
||||||
filled into the returned hiddev_report_info structure.
|
filled into the returned hiddev_report_info structure.
|
||||||
|
|
||||||
HIDIOCGFIELDINFO - struct hiddev_field_info (read/write)
|
HIDIOCGFIELDINFO
|
||||||
|
- struct hiddev_field_info (read/write)
|
||||||
|
|
||||||
Returns the field information associated with a report in a
|
Returns the field information associated with a report in a
|
||||||
hiddev_field_info structure. The user must fill in report_id and
|
hiddev_field_info structure. The user must fill in report_id and
|
||||||
report_type in this structure, as above. The field_index should also
|
report_type in this structure, as above. The field_index should also
|
||||||
be filled in, which should be a number from 0 and maxfield-1, as
|
be filled in, which should be a number from 0 and maxfield-1, as
|
||||||
returned from a previous HIDIOCGREPORTINFO call.
|
returned from a previous HIDIOCGREPORTINFO call.
|
||||||
|
|
||||||
HIDIOCGUCODE - struct hiddev_usage_ref (read/write)
|
HIDIOCGUCODE
|
||||||
|
- struct hiddev_usage_ref (read/write)
|
||||||
|
|
||||||
Returns the usage_code in a hiddev_usage_ref structure, given that
|
Returns the usage_code in a hiddev_usage_ref structure, given that
|
||||||
given its report type, report id, field index, and index within the
|
given its report type, report id, field index, and index within the
|
||||||
field have already been filled into the structure.
|
field have already been filled into the structure.
|
||||||
|
|
||||||
HIDIOCGUSAGE - struct hiddev_usage_ref (read/write)
|
HIDIOCGUSAGE
|
||||||
|
- struct hiddev_usage_ref (read/write)
|
||||||
|
|
||||||
Returns the value of a usage in a hiddev_usage_ref structure. The
|
Returns the value of a usage in a hiddev_usage_ref structure. The
|
||||||
usage to be retrieved can be specified as above, or the user can
|
usage to be retrieved can be specified as above, or the user can
|
||||||
choose to fill in the report_type field and specify the report_id as
|
choose to fill in the report_type field and specify the report_id as
|
||||||
@ -176,28 +213,37 @@ HID_REPORT_ID_UNKNOWN. In this case, the hiddev_usage_ref will be
|
|||||||
filled in with the report and field information associated with this
|
filled in with the report and field information associated with this
|
||||||
usage if it is found.
|
usage if it is found.
|
||||||
|
|
||||||
HIDIOCSUSAGE - struct hiddev_usage_ref (write)
|
HIDIOCSUSAGE
|
||||||
|
- struct hiddev_usage_ref (write)
|
||||||
|
|
||||||
Sets the value of a usage in an output report. The user fills in
|
Sets the value of a usage in an output report. The user fills in
|
||||||
the hiddev_usage_ref structure as above, but additionally fills in
|
the hiddev_usage_ref structure as above, but additionally fills in
|
||||||
the value field.
|
the value field.
|
||||||
|
|
||||||
HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write)
|
HIDIOGCOLLECTIONINDEX
|
||||||
|
- struct hiddev_usage_ref (write)
|
||||||
|
|
||||||
Returns the collection index associated with this usage. This
|
Returns the collection index associated with this usage. This
|
||||||
indicates where in the collection hierarchy this usage sits.
|
indicates where in the collection hierarchy this usage sits.
|
||||||
|
|
||||||
HIDIOCGFLAG - int (read)
|
HIDIOCGFLAG
|
||||||
HIDIOCSFLAG - int (write)
|
- int (read)
|
||||||
|
HIDIOCSFLAG
|
||||||
|
- int (write)
|
||||||
|
|
||||||
These operations respectively inspect and replace the mode flags
|
These operations respectively inspect and replace the mode flags
|
||||||
that influence the read() call above. The flags are as follows:
|
that influence the read() call above. The flags are as follows:
|
||||||
|
|
||||||
HIDDEV_FLAG_UREF - read() calls will now return
|
HIDDEV_FLAG_UREF
|
||||||
|
- read() calls will now return
|
||||||
struct hiddev_usage_ref instead of struct hiddev_event.
|
struct hiddev_usage_ref instead of struct hiddev_event.
|
||||||
This is a larger structure, but in situations where the
|
This is a larger structure, but in situations where the
|
||||||
device has more than one usage in its reports with the
|
device has more than one usage in its reports with the
|
||||||
same usage code, this mode serves to resolve such
|
same usage code, this mode serves to resolve such
|
||||||
ambiguity.
|
ambiguity.
|
||||||
|
|
||||||
HIDDEV_FLAG_REPORT - This flag can only be used in conjunction
|
HIDDEV_FLAG_REPORT
|
||||||
|
- This flag can only be used in conjunction
|
||||||
with HIDDEV_FLAG_UREF. With this flag set, when the device
|
with HIDDEV_FLAG_UREF. With this flag set, when the device
|
||||||
sends a report, a struct hiddev_usage_ref will be returned
|
sends a report, a struct hiddev_usage_ref will be returned
|
||||||
to read() filled in with the report_type and report_id, but
|
to read() filled in with the report_type and report_id, but
|
@ -1,5 +1,6 @@
|
|||||||
|
================================================================
|
||||||
HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
|
HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
|
||||||
==================================================================
|
================================================================
|
||||||
|
|
||||||
The hidraw driver provides a raw interface to USB and Bluetooth Human
|
The hidraw driver provides a raw interface to USB and Bluetooth Human
|
||||||
Interface Devices (HIDs). It differs from hiddev in that reports sent and
|
Interface Devices (HIDs). It differs from hiddev in that reports sent and
|
||||||
@ -31,6 +32,7 @@ directly under /dev (eg: /dev/hidraw0). As this location is distribution-
|
|||||||
and udev rule-dependent, applications should use libudev to locate hidraw
|
and udev rule-dependent, applications should use libudev to locate hidraw
|
||||||
devices attached to the system. There is a tutorial on libudev with a
|
devices attached to the system. There is a tutorial on libudev with a
|
||||||
working example at:
|
working example at:
|
||||||
|
|
||||||
http://www.signal11.us/oss/udev/
|
http://www.signal11.us/oss/udev/
|
||||||
|
|
||||||
The HIDRAW API
|
The HIDRAW API
|
||||||
@ -51,7 +53,7 @@ byte. For devices which do not use numbered reports, the report data
|
|||||||
will begin at the first byte.
|
will begin at the first byte.
|
||||||
|
|
||||||
write()
|
write()
|
||||||
--------
|
-------
|
||||||
The write() function will write a report to the device. For USB devices, if
|
The write() function will write a report to the device. For USB devices, if
|
||||||
the device has an INTERRUPT OUT endpoint, the report will be sent on that
|
the device has an INTERRUPT OUT endpoint, the report will be sent on that
|
||||||
endpoint. If it does not, the report will be sent over the control endpoint,
|
endpoint. If it does not, the report will be sent over the control endpoint,
|
||||||
@ -62,38 +64,52 @@ number. If the device does not use numbered reports, the first byte should
|
|||||||
be set to 0. The report data itself should begin at the second byte.
|
be set to 0. The report data itself should begin at the second byte.
|
||||||
|
|
||||||
ioctl()
|
ioctl()
|
||||||
--------
|
-------
|
||||||
Hidraw supports the following ioctls:
|
Hidraw supports the following ioctls:
|
||||||
|
|
||||||
HIDIOCGRDESCSIZE: Get Report Descriptor Size
|
HIDIOCGRDESCSIZE:
|
||||||
|
Get Report Descriptor Size
|
||||||
|
|
||||||
This ioctl will get the size of the device's report descriptor.
|
This ioctl will get the size of the device's report descriptor.
|
||||||
|
|
||||||
HIDIOCGRDESC: Get Report Descriptor
|
HIDIOCGRDESC:
|
||||||
|
Get Report Descriptor
|
||||||
|
|
||||||
This ioctl returns the device's report descriptor using a
|
This ioctl returns the device's report descriptor using a
|
||||||
hidraw_report_descriptor struct. Make sure to set the size field of the
|
hidraw_report_descriptor struct. Make sure to set the size field of the
|
||||||
hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
|
hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
|
||||||
|
|
||||||
HIDIOCGRAWINFO: Get Raw Info
|
HIDIOCGRAWINFO:
|
||||||
|
Get Raw Info
|
||||||
|
|
||||||
This ioctl will return a hidraw_devinfo struct containing the bus type, the
|
This ioctl will return a hidraw_devinfo struct containing the bus type, the
|
||||||
vendor ID (VID), and product ID (PID) of the device. The bus type can be one
|
vendor ID (VID), and product ID (PID) of the device. The bus type can be one
|
||||||
of:
|
of::
|
||||||
BUS_USB
|
|
||||||
BUS_HIL
|
- BUS_USB
|
||||||
BUS_BLUETOOTH
|
- BUS_HIL
|
||||||
BUS_VIRTUAL
|
- BUS_BLUETOOTH
|
||||||
|
- BUS_VIRTUAL
|
||||||
|
|
||||||
which are defined in uapi/linux/input.h.
|
which are defined in uapi/linux/input.h.
|
||||||
|
|
||||||
HIDIOCGRAWNAME(len): Get Raw Name
|
HIDIOCGRAWNAME(len):
|
||||||
|
Get Raw Name
|
||||||
|
|
||||||
This ioctl returns a string containing the vendor and product strings of
|
This ioctl returns a string containing the vendor and product strings of
|
||||||
the device. The returned string is Unicode, UTF-8 encoded.
|
the device. The returned string is Unicode, UTF-8 encoded.
|
||||||
|
|
||||||
HIDIOCGRAWPHYS(len): Get Physical Address
|
HIDIOCGRAWPHYS(len):
|
||||||
|
Get Physical Address
|
||||||
|
|
||||||
This ioctl returns a string representing the physical address of the device.
|
This ioctl returns a string representing the physical address of the device.
|
||||||
For USB devices, the string contains the physical path to the device (the
|
For USB devices, the string contains the physical path to the device (the
|
||||||
USB controller, hubs, ports, etc). For Bluetooth devices, the string
|
USB controller, hubs, ports, etc). For Bluetooth devices, the string
|
||||||
contains the hardware (MAC) address of the device.
|
contains the hardware (MAC) address of the device.
|
||||||
|
|
||||||
HIDIOCSFEATURE(len): Send a Feature Report
|
HIDIOCSFEATURE(len):
|
||||||
|
Send a Feature Report
|
||||||
|
|
||||||
This ioctl will send a feature report to the device. Per the HID
|
This ioctl will send a feature report to the device. Per the HID
|
||||||
specification, feature reports are always sent using the control endpoint.
|
specification, feature reports are always sent using the control endpoint.
|
||||||
Set the first byte of the supplied buffer to the report number. For devices
|
Set the first byte of the supplied buffer to the report number. For devices
|
||||||
@ -101,7 +117,9 @@ which do not use numbered reports, set the first byte to 0. The report data
|
|||||||
begins in the second byte. Make sure to set len accordingly, to one more
|
begins in the second byte. Make sure to set len accordingly, to one more
|
||||||
than the length of the report (to account for the report number).
|
than the length of the report (to account for the report number).
|
||||||
|
|
||||||
HIDIOCGFEATURE(len): Get a Feature Report
|
HIDIOCGFEATURE(len):
|
||||||
|
Get a Feature Report
|
||||||
|
|
||||||
This ioctl will request a feature report from the device using the control
|
This ioctl will request a feature report from the device using the control
|
||||||
endpoint. The first byte of the supplied buffer should be set to the report
|
endpoint. The first byte of the supplied buffer should be set to the report
|
||||||
number of the requested report. For devices which do not use numbered
|
number of the requested report. For devices which do not use numbered
|
||||||
@ -109,11 +127,12 @@ reports, set the first byte to 0. The report will be returned starting at
|
|||||||
the first byte of the buffer (ie: the report number is not returned).
|
the first byte of the buffer (ie: the report number is not returned).
|
||||||
|
|
||||||
Example
|
Example
|
||||||
---------
|
-------
|
||||||
In samples/, find hid-example.c, which shows examples of read(), write(),
|
In samples/, find hid-example.c, which shows examples of read(), write(),
|
||||||
and all the ioctls for hidraw. The code may be used by anyone for any
|
and all the ioctls for hidraw. The code may be used by anyone for any
|
||||||
purpose, and can serve as a starting point for developing applications using
|
purpose, and can serve as a starting point for developing applications using
|
||||||
hidraw.
|
hidraw.
|
||||||
|
|
||||||
Document by:
|
Document by:
|
||||||
|
|
||||||
Alan Ott <alan@signal11.us>, Signal 11 Software
|
Alan Ott <alan@signal11.us>, Signal 11 Software
|
18
Documentation/hid/index.rst
Normal file
18
Documentation/hid/index.rst
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
:orphan:
|
||||||
|
|
||||||
|
=============================
|
||||||
|
Human Interface Devices (HID)
|
||||||
|
=============================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
hiddev
|
||||||
|
hidraw
|
||||||
|
hid-sensor
|
||||||
|
hid-transport
|
||||||
|
|
||||||
|
uhid
|
||||||
|
|
||||||
|
hid-alps
|
||||||
|
intel-ish-hid
|
485
Documentation/hid/intel-ish-hid.rst
Normal file
485
Documentation/hid/intel-ish-hid.rst
Normal file
@ -0,0 +1,485 @@
|
|||||||
|
=================================
|
||||||
|
Intel Integrated Sensor Hub (ISH)
|
||||||
|
=================================
|
||||||
|
|
||||||
|
A sensor hub enables the ability to offload sensor polling and algorithm
|
||||||
|
processing to a dedicated low power co-processor. This allows the core
|
||||||
|
processor to go into low power modes more often, resulting in the increased
|
||||||
|
battery life.
|
||||||
|
|
||||||
|
There are many vendors providing external sensor hubs confirming to HID
|
||||||
|
Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
|
||||||
|
and embedded products. Linux had this support since Linux 3.9.
|
||||||
|
|
||||||
|
Intel® introduced integrated sensor hubs as a part of the SoC starting from
|
||||||
|
Cherry Trail and now supported on multiple generations of CPU packages. There
|
||||||
|
are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
|
||||||
|
These ISH also comply to HID sensor specification, but the difference is the
|
||||||
|
transport protocol used for communication. The current external sensor hubs
|
||||||
|
mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
|
||||||
|
|
||||||
|
1. Overview
|
||||||
|
===========
|
||||||
|
|
||||||
|
Using a analogy with a usbhid implementation, the ISH follows a similar model
|
||||||
|
for a very high speed communication::
|
||||||
|
|
||||||
|
----------------- ----------------------
|
||||||
|
| USB HID | --> | ISH HID |
|
||||||
|
----------------- ----------------------
|
||||||
|
----------------- ----------------------
|
||||||
|
| USB protocol | --> | ISH Transport |
|
||||||
|
----------------- ----------------------
|
||||||
|
----------------- ----------------------
|
||||||
|
| EHCI/XHCI | --> | ISH IPC |
|
||||||
|
----------------- ----------------------
|
||||||
|
PCI PCI
|
||||||
|
----------------- ----------------------
|
||||||
|
|Host controller| --> | ISH processor |
|
||||||
|
----------------- ----------------------
|
||||||
|
USB Link
|
||||||
|
----------------- ----------------------
|
||||||
|
| USB End points| --> | ISH Clients |
|
||||||
|
----------------- ----------------------
|
||||||
|
|
||||||
|
Like USB protocol provides a method for device enumeration, link management
|
||||||
|
and user data encapsulation, the ISH also provides similar services. But it is
|
||||||
|
very light weight tailored to manage and communicate with ISH client
|
||||||
|
applications implemented in the firmware.
|
||||||
|
|
||||||
|
The ISH allows multiple sensor management applications executing in the
|
||||||
|
firmware. Like USB endpoints the messaging can be to/from a client. As part of
|
||||||
|
enumeration process, these clients are identified. These clients can be simple
|
||||||
|
HID sensor applications, sensor calibration application or senor firmware
|
||||||
|
update application.
|
||||||
|
|
||||||
|
The implementation model is similar, like USB bus, ISH transport is also
|
||||||
|
implemented as a bus. Each client application executing in the ISH processor
|
||||||
|
is registered as a device on this bus. The driver, which binds each device
|
||||||
|
(ISH HID driver) identifies the device type and registers with the hid core.
|
||||||
|
|
||||||
|
2. ISH Implementation: Block Diagram
|
||||||
|
====================================
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
| User Space Applications |
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
----------------IIO ABI----------------
|
||||||
|
--------------------------
|
||||||
|
| IIO Sensor Drivers |
|
||||||
|
--------------------------
|
||||||
|
--------------------------
|
||||||
|
| IIO core |
|
||||||
|
--------------------------
|
||||||
|
--------------------------
|
||||||
|
| HID Sensor Hub MFD |
|
||||||
|
--------------------------
|
||||||
|
--------------------------
|
||||||
|
| HID Core |
|
||||||
|
--------------------------
|
||||||
|
--------------------------
|
||||||
|
| HID over ISH Client |
|
||||||
|
--------------------------
|
||||||
|
--------------------------
|
||||||
|
| ISH Transport (ISHTP) |
|
||||||
|
--------------------------
|
||||||
|
--------------------------
|
||||||
|
| IPC Drivers |
|
||||||
|
--------------------------
|
||||||
|
OS
|
||||||
|
---------------- PCI -----------------
|
||||||
|
Hardware + Firmware
|
||||||
|
----------------------------
|
||||||
|
| ISH Hardware/Firmware(FW) |
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
3. High level processing in above blocks
|
||||||
|
========================================
|
||||||
|
|
||||||
|
3.1 Hardware Interface
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
|
||||||
|
product and vendor IDs are changed from different generations of processors. So
|
||||||
|
the source code which enumerate drivers needs to update from generation to
|
||||||
|
generation.
|
||||||
|
|
||||||
|
3.2 Inter Processor Communication (IPC) driver
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
Location: drivers/hid/intel-ish-hid/ipc
|
||||||
|
|
||||||
|
The IPC message used memory mapped I/O. The registers are defined in
|
||||||
|
hw-ish-regs.h.
|
||||||
|
|
||||||
|
3.2.1 IPC/FW message types
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
There are two types of messages, one for management of link and other messages
|
||||||
|
are to and from transport layers.
|
||||||
|
|
||||||
|
TX and RX of Transport messages
|
||||||
|
...............................
|
||||||
|
|
||||||
|
A set of memory mapped register offers support of multi byte messages TX and
|
||||||
|
RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
|
||||||
|
internal queues to sequence messages and send them in order to the FW.
|
||||||
|
Optionally the caller can register handler to get notification of completion.
|
||||||
|
A door bell mechanism is used in messaging to trigger processing in host and
|
||||||
|
client firmware side. When ISH interrupt handler is called, the ISH2HOST
|
||||||
|
doorbell register is used by host drivers to determine that the interrupt
|
||||||
|
is for ISH.
|
||||||
|
|
||||||
|
Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
|
||||||
|
register has the following format:
|
||||||
|
Bits 0..6: fragment length (7 bits are used)
|
||||||
|
Bits 10..13: encapsulated protocol
|
||||||
|
Bits 16..19: management command (for IPC management protocol)
|
||||||
|
Bit 31: doorbell trigger (signal H/W interrupt to the other side)
|
||||||
|
Other bits are reserved, should be 0.
|
||||||
|
|
||||||
|
3.2.2 Transport layer interface
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
To abstract HW level IPC communication, a set of callbacks are registered.
|
||||||
|
The transport layer uses them to send and receive messages.
|
||||||
|
Refer to struct ishtp_hw_ops for callbacks.
|
||||||
|
|
||||||
|
3.3 ISH Transport layer
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Location: drivers/hid/intel-ish-hid/ishtp/
|
||||||
|
|
||||||
|
3.3.1 A Generic Transport Layer
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The transport layer is a bi-directional protocol, which defines:
|
||||||
|
- Set of commands to start, stop, connect, disconnect and flow control
|
||||||
|
(ishtp/hbm.h) for details
|
||||||
|
- A flow control mechanism to avoid buffer overflows
|
||||||
|
|
||||||
|
This protocol resembles bus messages described in the following document:
|
||||||
|
http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
|
||||||
|
specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
|
||||||
|
|
||||||
|
3.3.2 Connection and Flow Control Mechanism
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Each FW client and a protocol is identified by an UUID. In order to communicate
|
||||||
|
to a FW client, a connection must be established using connect request and
|
||||||
|
response bus messages. If successful, a pair (host_client_id and fw_client_id)
|
||||||
|
will identify the connection.
|
||||||
|
|
||||||
|
Once connection is established, peers send each other flow control bus messages
|
||||||
|
independently. Every peer may send a message only if it has received a
|
||||||
|
flow-control credit before. Once it sent a message, it may not send another one
|
||||||
|
before receiving the next flow control credit.
|
||||||
|
Either side can send disconnect request bus message to end communication. Also
|
||||||
|
the link will be dropped if major FW reset occurs.
|
||||||
|
|
||||||
|
3.3.3 Peer to Peer data transfer
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Peer to Peer data transfer can happen with or without using DMA. Depending on
|
||||||
|
the sensor bandwidth requirement DMA can be enabled by using module parameter
|
||||||
|
ishtp_use_dma under intel_ishtp.
|
||||||
|
|
||||||
|
Each side (host and FW) manages its DMA transfer memory independently. When an
|
||||||
|
ISHTP client from either host or FW side wants to send something, it decides
|
||||||
|
whether to send over IPC or over DMA; for each transfer the decision is
|
||||||
|
independent. The sending side sends DMA_XFER message when the message is in
|
||||||
|
the respective host buffer (TX when host client sends, RX when FW client
|
||||||
|
sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
|
||||||
|
the sender that the memory region for that message may be reused.
|
||||||
|
|
||||||
|
DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
|
||||||
|
(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
|
||||||
|
Additionally to DMA address communication, this sequence checks capabilities:
|
||||||
|
if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
|
||||||
|
send DMA; if FW doesn't support DMA then it won't respond with
|
||||||
|
DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
|
||||||
|
Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
|
||||||
|
it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
|
||||||
|
that it already did DMA and the message resides at host. Thus, DMA_XFER
|
||||||
|
and DMA_XFER_ACK act as ownership indicators.
|
||||||
|
|
||||||
|
At initial state all outgoing memory belongs to the sender (TX to host, RX to
|
||||||
|
FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
|
||||||
|
the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
|
||||||
|
needs not wait for previous DMA_XFER to be ack'ed, and may send another message
|
||||||
|
as long as remaining continuous memory in its ownership is enough.
|
||||||
|
In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
|
||||||
|
(up to IPC MTU), thus allowing for interrupt throttling.
|
||||||
|
Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
|
||||||
|
fragments and via IPC otherwise.
|
||||||
|
|
||||||
|
3.3.4 Ring Buffers
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
When a client initiate a connection, a ring or RX and TX buffers are allocated.
|
||||||
|
The size of ring can be specified by the client. HID client set 16 and 32 for
|
||||||
|
TX and RX buffers respectively. On send request from client, the data to be
|
||||||
|
sent is copied to one of the send ring buffer and scheduled to be sent using
|
||||||
|
bus message protocol. These buffers are required because the FW may have not
|
||||||
|
have processed the last message and may not have enough flow control credits
|
||||||
|
to send. Same thing holds true on receive side and flow control is required.
|
||||||
|
|
||||||
|
3.3.5 Host Enumeration
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The host enumeration bus command allow discovery of clients present in the FW.
|
||||||
|
There can be multiple sensor clients and clients for calibration function.
|
||||||
|
|
||||||
|
To ease in implantation and allow independent driver handle each client
|
||||||
|
this transport layer takes advantage of Linux Bus driver model. Each
|
||||||
|
client is registered as device on the the transport bus (ishtp bus).
|
||||||
|
|
||||||
|
Enumeration sequence of messages:
|
||||||
|
|
||||||
|
- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
|
||||||
|
- FW responds with HOST_START_RES_CMD
|
||||||
|
- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
|
||||||
|
- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
|
||||||
|
client IDs
|
||||||
|
- For each FW ID found in that bitmap host sends
|
||||||
|
HOST_CLIENT_PROPERTIES_REQ_CMD
|
||||||
|
- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
|
||||||
|
max ISHTP message size, etc.
|
||||||
|
- Once host received properties for that last discovered client, it considers
|
||||||
|
ISHTP device fully functional (and allocates DMA buffers)
|
||||||
|
|
||||||
|
3.4 HID over ISH Client
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Location: drivers/hid/intel-ish-hid
|
||||||
|
|
||||||
|
The ISHTP client driver is responsible for:
|
||||||
|
|
||||||
|
- enumerate HID devices under FW ISH client
|
||||||
|
- Get Report descriptor
|
||||||
|
- Register with HID core as a LL driver
|
||||||
|
- Process Get/Set feature request
|
||||||
|
- Get input reports
|
||||||
|
|
||||||
|
3.5 HID Sensor Hub MFD and IIO sensor drivers
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
The functionality in these drivers is the same as an external sensor hub.
|
||||||
|
Refer to
|
||||||
|
Documentation/hid/hid-sensor.rst for HID sensor
|
||||||
|
Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
|
||||||
|
|
||||||
|
3.6 End to End HID transport Sequence Diagram
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
HID-ISH-CLN ISHTP IPC HW
|
||||||
|
| | | |
|
||||||
|
| | |-----WAKE UP------------------>|
|
||||||
|
| | | |
|
||||||
|
| | |-----HOST READY--------------->|
|
||||||
|
| | | |
|
||||||
|
| | |<----MNG_RESET_NOTIFY_ACK----- |
|
||||||
|
| | | |
|
||||||
|
| |<----ISHTP_START------ | |
|
||||||
|
| | | |
|
||||||
|
| |<-----------------HOST_START_RES_CMD-------------------|
|
||||||
|
| | | |
|
||||||
|
| |------------------QUERY_SUBSCRIBER-------------------->|
|
||||||
|
| | | |
|
||||||
|
| |------------------HOST_ENUM_REQ_CMD------------------->|
|
||||||
|
| | | |
|
||||||
|
| |<-----------------HOST_ENUM_RES_CMD--------------------|
|
||||||
|
| | | |
|
||||||
|
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
|
||||||
|
| | | |
|
||||||
|
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
|
||||||
|
| Create new device on in ishtp bus | |
|
||||||
|
| | | |
|
||||||
|
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
|
||||||
|
| | | |
|
||||||
|
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
|
||||||
|
| Create new device on in ishtp bus | |
|
||||||
|
| | | |
|
||||||
|
| |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
|
||||||
|
| | | |
|
||||||
|
probed()
|
||||||
|
|----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
|
||||||
|
| | | |
|
||||||
|
| |<----------------CLIENT_CONNECT_RES_CMD----------------|
|
||||||
|
| | | |
|
||||||
|
|register event callback | | |
|
||||||
|
| | | |
|
||||||
|
|ishtp_cl_send(
|
||||||
|
HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
|
||||||
|
| | | |
|
||||||
|
| | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
|
||||||
|
| | | |
|
||||||
|
|<--ENUM_DEVICE RSP------| | |
|
||||||
|
| | | |
|
||||||
|
for each enumerated device
|
||||||
|
|ishtp_cl_send(
|
||||||
|
HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW----- >|
|
||||||
|
| | | |
|
||||||
|
...Response
|
||||||
|
| | | |
|
||||||
|
for each enumerated device
|
||||||
|
|ishtp_cl_send(
|
||||||
|
HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
hid_allocate_device
|
||||||
|
| | | |
|
||||||
|
hid_add_device | | |
|
||||||
|
| | | |
|
||||||
|
|
||||||
|
|
||||||
|
3.7 ISH Debugging
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
To debug ISH, event tracing mechanism is used. To enable debug logs
|
||||||
|
echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
|
||||||
|
cat sys/kernel/debug/tracing/trace
|
||||||
|
|
||||||
|
3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
|
||||||
|
/sys/bus/iio/devices/
|
||||||
|
├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
|
||||||
|
│ ├── buffer
|
||||||
|
│ │ ├── enable
|
||||||
|
│ │ ├── length
|
||||||
|
│ │ └── watermark
|
||||||
|
...
|
||||||
|
│ ├── in_accel_hysteresis
|
||||||
|
│ ├── in_accel_offset
|
||||||
|
│ ├── in_accel_sampling_frequency
|
||||||
|
│ ├── in_accel_scale
|
||||||
|
│ ├── in_accel_x_raw
|
||||||
|
│ ├── in_accel_y_raw
|
||||||
|
│ ├── in_accel_z_raw
|
||||||
|
│ ├── name
|
||||||
|
│ ├── scan_elements
|
||||||
|
│ │ ├── in_accel_x_en
|
||||||
|
│ │ ├── in_accel_x_index
|
||||||
|
│ │ ├── in_accel_x_type
|
||||||
|
│ │ ├── in_accel_y_en
|
||||||
|
│ │ ├── in_accel_y_index
|
||||||
|
│ │ ├── in_accel_y_type
|
||||||
|
│ │ ├── in_accel_z_en
|
||||||
|
│ │ ├── in_accel_z_index
|
||||||
|
│ │ └── in_accel_z_type
|
||||||
|
...
|
||||||
|
│ │ ├── devices
|
||||||
|
│ │ │ │ ├── buffer
|
||||||
|
│ │ │ │ │ ├── enable
|
||||||
|
│ │ │ │ │ ├── length
|
||||||
|
│ │ │ │ │ └── watermark
|
||||||
|
│ │ │ │ ├── dev
|
||||||
|
│ │ │ │ ├── in_intensity_both_raw
|
||||||
|
│ │ │ │ ├── in_intensity_hysteresis
|
||||||
|
│ │ │ │ ├── in_intensity_offset
|
||||||
|
│ │ │ │ ├── in_intensity_sampling_frequency
|
||||||
|
│ │ │ │ ├── in_intensity_scale
|
||||||
|
│ │ │ │ ├── name
|
||||||
|
│ │ │ │ ├── scan_elements
|
||||||
|
│ │ │ │ │ ├── in_intensity_both_en
|
||||||
|
│ │ │ │ │ ├── in_intensity_both_index
|
||||||
|
│ │ │ │ │ └── in_intensity_both_type
|
||||||
|
│ │ │ │ ├── trigger
|
||||||
|
│ │ │ │ │ └── current_trigger
|
||||||
|
...
|
||||||
|
│ │ │ │ ├── buffer
|
||||||
|
│ │ │ │ │ ├── enable
|
||||||
|
│ │ │ │ │ ├── length
|
||||||
|
│ │ │ │ │ └── watermark
|
||||||
|
│ │ │ │ ├── dev
|
||||||
|
│ │ │ │ ├── in_magn_hysteresis
|
||||||
|
│ │ │ │ ├── in_magn_offset
|
||||||
|
│ │ │ │ ├── in_magn_sampling_frequency
|
||||||
|
│ │ │ │ ├── in_magn_scale
|
||||||
|
│ │ │ │ ├── in_magn_x_raw
|
||||||
|
│ │ │ │ ├── in_magn_y_raw
|
||||||
|
│ │ │ │ ├── in_magn_z_raw
|
||||||
|
│ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
|
||||||
|
│ │ │ │ ├── in_rot_hysteresis
|
||||||
|
│ │ │ │ ├── in_rot_offset
|
||||||
|
│ │ │ │ ├── in_rot_sampling_frequency
|
||||||
|
│ │ │ │ ├── in_rot_scale
|
||||||
|
│ │ │ │ ├── name
|
||||||
|
...
|
||||||
|
│ │ │ │ ├── scan_elements
|
||||||
|
│ │ │ │ │ ├── in_magn_x_en
|
||||||
|
│ │ │ │ │ ├── in_magn_x_index
|
||||||
|
│ │ │ │ │ ├── in_magn_x_type
|
||||||
|
│ │ │ │ │ ├── in_magn_y_en
|
||||||
|
│ │ │ │ │ ├── in_magn_y_index
|
||||||
|
│ │ │ │ │ ├── in_magn_y_type
|
||||||
|
│ │ │ │ │ ├── in_magn_z_en
|
||||||
|
│ │ │ │ │ ├── in_magn_z_index
|
||||||
|
│ │ │ │ │ ├── in_magn_z_type
|
||||||
|
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
|
||||||
|
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
|
||||||
|
│ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
|
||||||
|
│ │ │ │ ├── trigger
|
||||||
|
│ │ │ │ │ └── current_trigger
|
||||||
|
...
|
||||||
|
│ │ │ │ ├── buffer
|
||||||
|
│ │ │ │ │ ├── enable
|
||||||
|
│ │ │ │ │ ├── length
|
||||||
|
│ │ │ │ │ └── watermark
|
||||||
|
│ │ │ │ ├── dev
|
||||||
|
│ │ │ │ ├── in_anglvel_hysteresis
|
||||||
|
│ │ │ │ ├── in_anglvel_offset
|
||||||
|
│ │ │ │ ├── in_anglvel_sampling_frequency
|
||||||
|
│ │ │ │ ├── in_anglvel_scale
|
||||||
|
│ │ │ │ ├── in_anglvel_x_raw
|
||||||
|
│ │ │ │ ├── in_anglvel_y_raw
|
||||||
|
│ │ │ │ ├── in_anglvel_z_raw
|
||||||
|
│ │ │ │ ├── name
|
||||||
|
│ │ │ │ ├── scan_elements
|
||||||
|
│ │ │ │ │ ├── in_anglvel_x_en
|
||||||
|
│ │ │ │ │ ├── in_anglvel_x_index
|
||||||
|
│ │ │ │ │ ├── in_anglvel_x_type
|
||||||
|
│ │ │ │ │ ├── in_anglvel_y_en
|
||||||
|
│ │ │ │ │ ├── in_anglvel_y_index
|
||||||
|
│ │ │ │ │ ├── in_anglvel_y_type
|
||||||
|
│ │ │ │ │ ├── in_anglvel_z_en
|
||||||
|
│ │ │ │ │ ├── in_anglvel_z_index
|
||||||
|
│ │ │ │ │ └── in_anglvel_z_type
|
||||||
|
│ │ │ │ ├── trigger
|
||||||
|
│ │ │ │ │ └── current_trigger
|
||||||
|
...
|
||||||
|
│ │ │ │ ├── buffer
|
||||||
|
│ │ │ │ │ ├── enable
|
||||||
|
│ │ │ │ │ ├── length
|
||||||
|
│ │ │ │ │ └── watermark
|
||||||
|
│ │ │ │ ├── dev
|
||||||
|
│ │ │ │ ├── in_anglvel_hysteresis
|
||||||
|
│ │ │ │ ├── in_anglvel_offset
|
||||||
|
│ │ │ │ ├── in_anglvel_sampling_frequency
|
||||||
|
│ │ │ │ ├── in_anglvel_scale
|
||||||
|
│ │ │ │ ├── in_anglvel_x_raw
|
||||||
|
│ │ │ │ ├── in_anglvel_y_raw
|
||||||
|
│ │ │ │ ├── in_anglvel_z_raw
|
||||||
|
│ │ │ │ ├── name
|
||||||
|
│ │ │ │ ├── scan_elements
|
||||||
|
│ │ │ │ │ ├── in_anglvel_x_en
|
||||||
|
│ │ │ │ │ ├── in_anglvel_x_index
|
||||||
|
│ │ │ │ │ ├── in_anglvel_x_type
|
||||||
|
│ │ │ │ │ ├── in_anglvel_y_en
|
||||||
|
│ │ │ │ │ ├── in_anglvel_y_index
|
||||||
|
│ │ │ │ │ ├── in_anglvel_y_type
|
||||||
|
│ │ │ │ │ ├── in_anglvel_z_en
|
||||||
|
│ │ │ │ │ ├── in_anglvel_z_index
|
||||||
|
│ │ │ │ │ └── in_anglvel_z_type
|
||||||
|
│ │ │ │ ├── trigger
|
||||||
|
│ │ │ │ │ └── current_trigger
|
||||||
|
...
|
@ -1,454 +0,0 @@
|
|||||||
Intel Integrated Sensor Hub (ISH)
|
|
||||||
===============================
|
|
||||||
|
|
||||||
A sensor hub enables the ability to offload sensor polling and algorithm
|
|
||||||
processing to a dedicated low power co-processor. This allows the core
|
|
||||||
processor to go into low power modes more often, resulting in the increased
|
|
||||||
battery life.
|
|
||||||
|
|
||||||
There are many vendors providing external sensor hubs confirming to HID
|
|
||||||
Sensor usage tables, and used in several tablets, 2 in 1 convertible laptops
|
|
||||||
and embedded products. Linux had this support since Linux 3.9.
|
|
||||||
|
|
||||||
Intel® introduced integrated sensor hubs as a part of the SoC starting from
|
|
||||||
Cherry Trail and now supported on multiple generations of CPU packages. There
|
|
||||||
are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
|
|
||||||
These ISH also comply to HID sensor specification, but the difference is the
|
|
||||||
transport protocol used for communication. The current external sensor hubs
|
|
||||||
mainly use HID over i2C or USB. But ISH doesn't use either i2c or USB.
|
|
||||||
|
|
||||||
1. Overview
|
|
||||||
|
|
||||||
Using a analogy with a usbhid implementation, the ISH follows a similar model
|
|
||||||
for a very high speed communication:
|
|
||||||
|
|
||||||
----------------- ----------------------
|
|
||||||
| USB HID | --> | ISH HID |
|
|
||||||
----------------- ----------------------
|
|
||||||
----------------- ----------------------
|
|
||||||
| USB protocol | --> | ISH Transport |
|
|
||||||
----------------- ----------------------
|
|
||||||
----------------- ----------------------
|
|
||||||
| EHCI/XHCI | --> | ISH IPC |
|
|
||||||
----------------- ----------------------
|
|
||||||
PCI PCI
|
|
||||||
----------------- ----------------------
|
|
||||||
|Host controller| --> | ISH processor |
|
|
||||||
----------------- ----------------------
|
|
||||||
USB Link
|
|
||||||
----------------- ----------------------
|
|
||||||
| USB End points| --> | ISH Clients |
|
|
||||||
----------------- ----------------------
|
|
||||||
|
|
||||||
Like USB protocol provides a method for device enumeration, link management
|
|
||||||
and user data encapsulation, the ISH also provides similar services. But it is
|
|
||||||
very light weight tailored to manage and communicate with ISH client
|
|
||||||
applications implemented in the firmware.
|
|
||||||
|
|
||||||
The ISH allows multiple sensor management applications executing in the
|
|
||||||
firmware. Like USB endpoints the messaging can be to/from a client. As part of
|
|
||||||
enumeration process, these clients are identified. These clients can be simple
|
|
||||||
HID sensor applications, sensor calibration application or senor firmware
|
|
||||||
update application.
|
|
||||||
|
|
||||||
The implementation model is similar, like USB bus, ISH transport is also
|
|
||||||
implemented as a bus. Each client application executing in the ISH processor
|
|
||||||
is registered as a device on this bus. The driver, which binds each device
|
|
||||||
(ISH HID driver) identifies the device type and registers with the hid core.
|
|
||||||
|
|
||||||
2. ISH Implementation: Block Diagram
|
|
||||||
|
|
||||||
---------------------------
|
|
||||||
| User Space Applications |
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
----------------IIO ABI----------------
|
|
||||||
--------------------------
|
|
||||||
| IIO Sensor Drivers |
|
|
||||||
--------------------------
|
|
||||||
--------------------------
|
|
||||||
| IIO core |
|
|
||||||
--------------------------
|
|
||||||
--------------------------
|
|
||||||
| HID Sensor Hub MFD |
|
|
||||||
--------------------------
|
|
||||||
--------------------------
|
|
||||||
| HID Core |
|
|
||||||
--------------------------
|
|
||||||
--------------------------
|
|
||||||
| HID over ISH Client |
|
|
||||||
--------------------------
|
|
||||||
--------------------------
|
|
||||||
| ISH Transport (ISHTP) |
|
|
||||||
--------------------------
|
|
||||||
--------------------------
|
|
||||||
| IPC Drivers |
|
|
||||||
--------------------------
|
|
||||||
OS
|
|
||||||
---------------- PCI -----------------
|
|
||||||
Hardware + Firmware
|
|
||||||
----------------------------
|
|
||||||
| ISH Hardware/Firmware(FW) |
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
3. High level processing in above blocks
|
|
||||||
|
|
||||||
3.1 Hardware Interface
|
|
||||||
|
|
||||||
The ISH is exposed as "Non-VGA unclassified PCI device" to the host. The PCI
|
|
||||||
product and vendor IDs are changed from different generations of processors. So
|
|
||||||
the source code which enumerate drivers needs to update from generation to
|
|
||||||
generation.
|
|
||||||
|
|
||||||
3.2 Inter Processor Communication (IPC) driver
|
|
||||||
Location: drivers/hid/intel-ish-hid/ipc
|
|
||||||
|
|
||||||
The IPC message used memory mapped I/O. The registers are defined in
|
|
||||||
hw-ish-regs.h.
|
|
||||||
|
|
||||||
3.2.1 IPC/FW message types
|
|
||||||
|
|
||||||
There are two types of messages, one for management of link and other messages
|
|
||||||
are to and from transport layers.
|
|
||||||
|
|
||||||
TX and RX of Transport messages
|
|
||||||
|
|
||||||
A set of memory mapped register offers support of multi byte messages TX and
|
|
||||||
RX (E.g.IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
|
|
||||||
internal queues to sequence messages and send them in order to the FW.
|
|
||||||
Optionally the caller can register handler to get notification of completion.
|
|
||||||
A door bell mechanism is used in messaging to trigger processing in host and
|
|
||||||
client firmware side. When ISH interrupt handler is called, the ISH2HOST
|
|
||||||
doorbell register is used by host drivers to determine that the interrupt
|
|
||||||
is for ISH.
|
|
||||||
|
|
||||||
Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
|
|
||||||
register has the following format:
|
|
||||||
Bits 0..6: fragment length (7 bits are used)
|
|
||||||
Bits 10..13: encapsulated protocol
|
|
||||||
Bits 16..19: management command (for IPC management protocol)
|
|
||||||
Bit 31: doorbell trigger (signal H/W interrupt to the other side)
|
|
||||||
Other bits are reserved, should be 0.
|
|
||||||
|
|
||||||
3.2.2 Transport layer interface
|
|
||||||
|
|
||||||
To abstract HW level IPC communication, a set of callbacks are registered.
|
|
||||||
The transport layer uses them to send and receive messages.
|
|
||||||
Refer to struct ishtp_hw_ops for callbacks.
|
|
||||||
|
|
||||||
3.3 ISH Transport layer
|
|
||||||
Location: drivers/hid/intel-ish-hid/ishtp/
|
|
||||||
|
|
||||||
3.3.1 A Generic Transport Layer
|
|
||||||
|
|
||||||
The transport layer is a bi-directional protocol, which defines:
|
|
||||||
- Set of commands to start, stop, connect, disconnect and flow control
|
|
||||||
(ishtp/hbm.h) for details
|
|
||||||
- A flow control mechanism to avoid buffer overflows
|
|
||||||
|
|
||||||
This protocol resembles bus messages described in the following document:
|
|
||||||
http://www.intel.com/content/dam/www/public/us/en/documents/technical-\
|
|
||||||
specifications/dcmi-hi-1-0-spec.pdf "Chapter 7: Bus Message Layer"
|
|
||||||
|
|
||||||
3.3.2 Connection and Flow Control Mechanism
|
|
||||||
|
|
||||||
Each FW client and a protocol is identified by an UUID. In order to communicate
|
|
||||||
to a FW client, a connection must be established using connect request and
|
|
||||||
response bus messages. If successful, a pair (host_client_id and fw_client_id)
|
|
||||||
will identify the connection.
|
|
||||||
|
|
||||||
Once connection is established, peers send each other flow control bus messages
|
|
||||||
independently. Every peer may send a message only if it has received a
|
|
||||||
flow-control credit before. Once it sent a message, it may not send another one
|
|
||||||
before receiving the next flow control credit.
|
|
||||||
Either side can send disconnect request bus message to end communication. Also
|
|
||||||
the link will be dropped if major FW reset occurs.
|
|
||||||
|
|
||||||
3.3.3 Peer to Peer data transfer
|
|
||||||
|
|
||||||
Peer to Peer data transfer can happen with or without using DMA. Depending on
|
|
||||||
the sensor bandwidth requirement DMA can be enabled by using module parameter
|
|
||||||
ishtp_use_dma under intel_ishtp.
|
|
||||||
|
|
||||||
Each side (host and FW) manages its DMA transfer memory independently. When an
|
|
||||||
ISHTP client from either host or FW side wants to send something, it decides
|
|
||||||
whether to send over IPC or over DMA; for each transfer the decision is
|
|
||||||
independent. The sending side sends DMA_XFER message when the message is in
|
|
||||||
the respective host buffer (TX when host client sends, RX when FW client
|
|
||||||
sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
|
|
||||||
the sender that the memory region for that message may be reused.
|
|
||||||
|
|
||||||
DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message
|
|
||||||
(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.
|
|
||||||
Additionally to DMA address communication, this sequence checks capabilities:
|
|
||||||
if thw host doesn't support DMA, then it won't send DMA allocation, so FW can't
|
|
||||||
send DMA; if FW doesn't support DMA then it won't respond with
|
|
||||||
DMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.
|
|
||||||
Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,
|
|
||||||
it's request to do host->ISH DMA transfer; when FW sends DMA_XFER, it means
|
|
||||||
that it already did DMA and the message resides at host. Thus, DMA_XFER
|
|
||||||
and DMA_XFER_ACK act as ownership indicators.
|
|
||||||
|
|
||||||
At initial state all outgoing memory belongs to the sender (TX to host, RX to
|
|
||||||
FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
|
|
||||||
the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
|
|
||||||
needs not wait for previous DMA_XFER to be ack'ed, and may send another message
|
|
||||||
as long as remaining continuous memory in its ownership is enough.
|
|
||||||
In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once
|
|
||||||
(up to IPC MTU), thus allowing for interrupt throttling.
|
|
||||||
Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPC
|
|
||||||
fragments and via IPC otherwise.
|
|
||||||
|
|
||||||
3.3.4 Ring Buffers
|
|
||||||
|
|
||||||
When a client initiate a connection, a ring or RX and TX buffers are allocated.
|
|
||||||
The size of ring can be specified by the client. HID client set 16 and 32 for
|
|
||||||
TX and RX buffers respectively. On send request from client, the data to be
|
|
||||||
sent is copied to one of the send ring buffer and scheduled to be sent using
|
|
||||||
bus message protocol. These buffers are required because the FW may have not
|
|
||||||
have processed the last message and may not have enough flow control credits
|
|
||||||
to send. Same thing holds true on receive side and flow control is required.
|
|
||||||
|
|
||||||
3.3.5 Host Enumeration
|
|
||||||
|
|
||||||
The host enumeration bus command allow discovery of clients present in the FW.
|
|
||||||
There can be multiple sensor clients and clients for calibration function.
|
|
||||||
|
|
||||||
To ease in implantation and allow independent driver handle each client
|
|
||||||
this transport layer takes advantage of Linux Bus driver model. Each
|
|
||||||
client is registered as device on the the transport bus (ishtp bus).
|
|
||||||
|
|
||||||
Enumeration sequence of messages:
|
|
||||||
- Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.
|
|
||||||
- FW responds with HOST_START_RES_CMD
|
|
||||||
- Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)
|
|
||||||
- FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FW
|
|
||||||
client IDs
|
|
||||||
- For each FW ID found in that bitmap host sends
|
|
||||||
HOST_CLIENT_PROPERTIES_REQ_CMD
|
|
||||||
- FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,
|
|
||||||
max ISHTP message size, etc.
|
|
||||||
- Once host received properties for that last discovered client, it considers
|
|
||||||
ISHTP device fully functional (and allocates DMA buffers)
|
|
||||||
|
|
||||||
3.4 HID over ISH Client
|
|
||||||
Location: drivers/hid/intel-ish-hid
|
|
||||||
|
|
||||||
The ISHTP client driver is responsible for:
|
|
||||||
- enumerate HID devices under FW ISH client
|
|
||||||
- Get Report descriptor
|
|
||||||
- Register with HID core as a LL driver
|
|
||||||
- Process Get/Set feature request
|
|
||||||
- Get input reports
|
|
||||||
|
|
||||||
3.5 HID Sensor Hub MFD and IIO sensor drivers
|
|
||||||
|
|
||||||
The functionality in these drivers is the same as an external sensor hub.
|
|
||||||
Refer to
|
|
||||||
Documentation/hid/hid-sensor.txt for HID sensor
|
|
||||||
Documentation/ABI/testing/sysfs-bus-iio for IIO ABIs to user space
|
|
||||||
|
|
||||||
3.6 End to End HID transport Sequence Diagram
|
|
||||||
|
|
||||||
HID-ISH-CLN ISHTP IPC HW
|
|
||||||
| | | |
|
|
||||||
| | |-----WAKE UP------------------>|
|
|
||||||
| | | |
|
|
||||||
| | |-----HOST READY--------------->|
|
|
||||||
| | | |
|
|
||||||
| | |<----MNG_RESET_NOTIFY_ACK----- |
|
|
||||||
| | | |
|
|
||||||
| |<----ISHTP_START------ | |
|
|
||||||
| | | |
|
|
||||||
| |<-----------------HOST_START_RES_CMD-------------------|
|
|
||||||
| | | |
|
|
||||||
| |------------------QUERY_SUBSCRIBER-------------------->|
|
|
||||||
| | | |
|
|
||||||
| |------------------HOST_ENUM_REQ_CMD------------------->|
|
|
||||||
| | | |
|
|
||||||
| |<-----------------HOST_ENUM_RES_CMD--------------------|
|
|
||||||
| | | |
|
|
||||||
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
|
|
||||||
| | | |
|
|
||||||
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
|
|
||||||
| Create new device on in ishtp bus | |
|
|
||||||
| | | |
|
|
||||||
| |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|
|
|
||||||
| | | |
|
|
||||||
| |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|
|
|
||||||
| Create new device on in ishtp bus | |
|
|
||||||
| | | |
|
|
||||||
| |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|
|
|
||||||
| | | |
|
|
||||||
probed()
|
|
||||||
|----ishtp_cl_connect-->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|
|
|
||||||
| | | |
|
|
||||||
| |<----------------CLIENT_CONNECT_RES_CMD----------------|
|
|
||||||
| | | |
|
|
||||||
|register event callback| | |
|
|
||||||
| | | |
|
|
||||||
|ishtp_cl_send(
|
|
||||||
HOSTIF_DM_ENUM_DEVICES) |----------fill ishtp_msg_hdr struct write to HW----- >|
|
|
||||||
| | | |
|
|
||||||
| | |<-----IRQ(IPC_PROTOCOL_ISHTP---|
|
|
||||||
| | | |
|
|
||||||
|<--ENUM_DEVICE RSP-----| | |
|
|
||||||
| | | |
|
|
||||||
for each enumerated device
|
|
||||||
|ishtp_cl_send(
|
|
||||||
HOSTIF_GET_HID_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW--- >|
|
|
||||||
| | | |
|
|
||||||
...Response
|
|
||||||
| | | |
|
|
||||||
for each enumerated device
|
|
||||||
|ishtp_cl_send(
|
|
||||||
HOSTIF_GET_REPORT_DESCRIPTOR |----------fill ishtp_msg_hdr struct write to HW- >|
|
|
||||||
| | | |
|
|
||||||
| | | |
|
|
||||||
hid_allocate_device
|
|
||||||
| | | |
|
|
||||||
hid_add_device | | |
|
|
||||||
| | | |
|
|
||||||
|
|
||||||
|
|
||||||
3.7 ISH Debugging
|
|
||||||
|
|
||||||
To debug ISH, event tracing mechanism is used. To enable debug logs
|
|
||||||
echo 1 > /sys/kernel/debug/tracing/events/intel_ish/enable
|
|
||||||
cat sys/kernel/debug/tracing/trace
|
|
||||||
|
|
||||||
3.8 ISH IIO sysfs Example on Lenovo thinkpad Yoga 260
|
|
||||||
|
|
||||||
root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices/
|
|
||||||
/sys/bus/iio/devices/
|
|
||||||
├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0
|
|
||||||
│ ├── buffer
|
|
||||||
│ │ ├── enable
|
|
||||||
│ │ ├── length
|
|
||||||
│ │ └── watermark
|
|
||||||
...
|
|
||||||
│ ├── in_accel_hysteresis
|
|
||||||
│ ├── in_accel_offset
|
|
||||||
│ ├── in_accel_sampling_frequency
|
|
||||||
│ ├── in_accel_scale
|
|
||||||
│ ├── in_accel_x_raw
|
|
||||||
│ ├── in_accel_y_raw
|
|
||||||
│ ├── in_accel_z_raw
|
|
||||||
│ ├── name
|
|
||||||
│ ├── scan_elements
|
|
||||||
│ │ ├── in_accel_x_en
|
|
||||||
│ │ ├── in_accel_x_index
|
|
||||||
│ │ ├── in_accel_x_type
|
|
||||||
│ │ ├── in_accel_y_en
|
|
||||||
│ │ ├── in_accel_y_index
|
|
||||||
│ │ ├── in_accel_y_type
|
|
||||||
│ │ ├── in_accel_z_en
|
|
||||||
│ │ ├── in_accel_z_index
|
|
||||||
│ │ └── in_accel_z_type
|
|
||||||
...
|
|
||||||
│ │ ├── devices
|
|
||||||
│ │ │ │ ├── buffer
|
|
||||||
│ │ │ │ │ ├── enable
|
|
||||||
│ │ │ │ │ ├── length
|
|
||||||
│ │ │ │ │ └── watermark
|
|
||||||
│ │ │ │ ├── dev
|
|
||||||
│ │ │ │ ├── in_intensity_both_raw
|
|
||||||
│ │ │ │ ├── in_intensity_hysteresis
|
|
||||||
│ │ │ │ ├── in_intensity_offset
|
|
||||||
│ │ │ │ ├── in_intensity_sampling_frequency
|
|
||||||
│ │ │ │ ├── in_intensity_scale
|
|
||||||
│ │ │ │ ├── name
|
|
||||||
│ │ │ │ ├── scan_elements
|
|
||||||
│ │ │ │ │ ├── in_intensity_both_en
|
|
||||||
│ │ │ │ │ ├── in_intensity_both_index
|
|
||||||
│ │ │ │ │ └── in_intensity_both_type
|
|
||||||
│ │ │ │ ├── trigger
|
|
||||||
│ │ │ │ │ └── current_trigger
|
|
||||||
...
|
|
||||||
│ │ │ │ ├── buffer
|
|
||||||
│ │ │ │ │ ├── enable
|
|
||||||
│ │ │ │ │ ├── length
|
|
||||||
│ │ │ │ │ └── watermark
|
|
||||||
│ │ │ │ ├── dev
|
|
||||||
│ │ │ │ ├── in_magn_hysteresis
|
|
||||||
│ │ │ │ ├── in_magn_offset
|
|
||||||
│ │ │ │ ├── in_magn_sampling_frequency
|
|
||||||
│ │ │ │ ├── in_magn_scale
|
|
||||||
│ │ │ │ ├── in_magn_x_raw
|
|
||||||
│ │ │ │ ├── in_magn_y_raw
|
|
||||||
│ │ │ │ ├── in_magn_z_raw
|
|
||||||
│ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_raw
|
|
||||||
│ │ │ │ ├── in_rot_hysteresis
|
|
||||||
│ │ │ │ ├── in_rot_offset
|
|
||||||
│ │ │ │ ├── in_rot_sampling_frequency
|
|
||||||
│ │ │ │ ├── in_rot_scale
|
|
||||||
│ │ │ │ ├── name
|
|
||||||
...
|
|
||||||
│ │ │ │ ├── scan_elements
|
|
||||||
│ │ │ │ │ ├── in_magn_x_en
|
|
||||||
│ │ │ │ │ ├── in_magn_x_index
|
|
||||||
│ │ │ │ │ ├── in_magn_x_type
|
|
||||||
│ │ │ │ │ ├── in_magn_y_en
|
|
||||||
│ │ │ │ │ ├── in_magn_y_index
|
|
||||||
│ │ │ │ │ ├── in_magn_y_type
|
|
||||||
│ │ │ │ │ ├── in_magn_z_en
|
|
||||||
│ │ │ │ │ ├── in_magn_z_index
|
|
||||||
│ │ │ │ │ ├── in_magn_z_type
|
|
||||||
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_en
|
|
||||||
│ │ │ │ │ ├── in_rot_from_north_magnetic_tilt_comp_index
|
|
||||||
│ │ │ │ │ └── in_rot_from_north_magnetic_tilt_comp_type
|
|
||||||
│ │ │ │ ├── trigger
|
|
||||||
│ │ │ │ │ └── current_trigger
|
|
||||||
...
|
|
||||||
│ │ │ │ ├── buffer
|
|
||||||
│ │ │ │ │ ├── enable
|
|
||||||
│ │ │ │ │ ├── length
|
|
||||||
│ │ │ │ │ └── watermark
|
|
||||||
│ │ │ │ ├── dev
|
|
||||||
│ │ │ │ ├── in_anglvel_hysteresis
|
|
||||||
│ │ │ │ ├── in_anglvel_offset
|
|
||||||
│ │ │ │ ├── in_anglvel_sampling_frequency
|
|
||||||
│ │ │ │ ├── in_anglvel_scale
|
|
||||||
│ │ │ │ ├── in_anglvel_x_raw
|
|
||||||
│ │ │ │ ├── in_anglvel_y_raw
|
|
||||||
│ │ │ │ ├── in_anglvel_z_raw
|
|
||||||
│ │ │ │ ├── name
|
|
||||||
│ │ │ │ ├── scan_elements
|
|
||||||
│ │ │ │ │ ├── in_anglvel_x_en
|
|
||||||
│ │ │ │ │ ├── in_anglvel_x_index
|
|
||||||
│ │ │ │ │ ├── in_anglvel_x_type
|
|
||||||
│ │ │ │ │ ├── in_anglvel_y_en
|
|
||||||
│ │ │ │ │ ├── in_anglvel_y_index
|
|
||||||
│ │ │ │ │ ├── in_anglvel_y_type
|
|
||||||
│ │ │ │ │ ├── in_anglvel_z_en
|
|
||||||
│ │ │ │ │ ├── in_anglvel_z_index
|
|
||||||
│ │ │ │ │ └── in_anglvel_z_type
|
|
||||||
│ │ │ │ ├── trigger
|
|
||||||
│ │ │ │ │ └── current_trigger
|
|
||||||
...
|
|
||||||
│ │ │ │ ├── buffer
|
|
||||||
│ │ │ │ │ ├── enable
|
|
||||||
│ │ │ │ │ ├── length
|
|
||||||
│ │ │ │ │ └── watermark
|
|
||||||
│ │ │ │ ├── dev
|
|
||||||
│ │ │ │ ├── in_anglvel_hysteresis
|
|
||||||
│ │ │ │ ├── in_anglvel_offset
|
|
||||||
│ │ │ │ ├── in_anglvel_sampling_frequency
|
|
||||||
│ │ │ │ ├── in_anglvel_scale
|
|
||||||
│ │ │ │ ├── in_anglvel_x_raw
|
|
||||||
│ │ │ │ ├── in_anglvel_y_raw
|
|
||||||
│ │ │ │ ├── in_anglvel_z_raw
|
|
||||||
│ │ │ │ ├── name
|
|
||||||
│ │ │ │ ├── scan_elements
|
|
||||||
│ │ │ │ │ ├── in_anglvel_x_en
|
|
||||||
│ │ │ │ │ ├── in_anglvel_x_index
|
|
||||||
│ │ │ │ │ ├── in_anglvel_x_type
|
|
||||||
│ │ │ │ │ ├── in_anglvel_y_en
|
|
||||||
│ │ │ │ │ ├── in_anglvel_y_index
|
|
||||||
│ │ │ │ │ ├── in_anglvel_y_type
|
|
||||||
│ │ │ │ │ ├── in_anglvel_z_en
|
|
||||||
│ │ │ │ │ ├── in_anglvel_z_index
|
|
||||||
│ │ │ │ │ └── in_anglvel_z_type
|
|
||||||
│ │ │ │ ├── trigger
|
|
||||||
│ │ │ │ │ └── current_trigger
|
|
||||||
...
|
|
@ -1,5 +1,6 @@
|
|||||||
|
======================================================
|
||||||
UHID - User-space I/O driver support for HID subsystem
|
UHID - User-space I/O driver support for HID subsystem
|
||||||
========================================================
|
======================================================
|
||||||
|
|
||||||
UHID allows user-space to implement HID transport drivers. Please see
|
UHID allows user-space to implement HID transport drivers. Please see
|
||||||
hid-transport.txt for an introduction into HID transport drivers. This document
|
hid-transport.txt for an introduction into HID transport drivers. This document
|
||||||
@ -22,7 +23,7 @@ If a new device is detected by your HID I/O Driver and you want to register this
|
|||||||
device with the HID subsystem, then you need to open /dev/uhid once for each
|
device with the HID subsystem, then you need to open /dev/uhid once for each
|
||||||
device you want to register. All further communication is done by read()'ing or
|
device you want to register. All further communication is done by read()'ing or
|
||||||
write()'ing "struct uhid_event" objects. Non-blocking operations are supported
|
write()'ing "struct uhid_event" objects. Non-blocking operations are supported
|
||||||
by setting O_NONBLOCK.
|
by setting O_NONBLOCK::
|
||||||
|
|
||||||
struct uhid_event {
|
struct uhid_event {
|
||||||
__u32 type;
|
__u32 type;
|
||||||
@ -127,9 +128,11 @@ them but you should handle them according to your needs.
|
|||||||
Device drivers might required delayed setups.
|
Device drivers might required delayed setups.
|
||||||
This event contains a payload of type uhid_start_req. The "dev_flags" field
|
This event contains a payload of type uhid_start_req. The "dev_flags" field
|
||||||
describes special behaviors of a device. The following flags are defined:
|
describes special behaviors of a device. The following flags are defined:
|
||||||
UHID_DEV_NUMBERED_FEATURE_REPORTS:
|
|
||||||
UHID_DEV_NUMBERED_OUTPUT_REPORTS:
|
- UHID_DEV_NUMBERED_FEATURE_REPORTS
|
||||||
UHID_DEV_NUMBERED_INPUT_REPORTS:
|
- UHID_DEV_NUMBERED_OUTPUT_REPORTS
|
||||||
|
- UHID_DEV_NUMBERED_INPUT_REPORTS
|
||||||
|
|
||||||
Each of these flags defines whether a given report-type uses numbered
|
Each of these flags defines whether a given report-type uses numbered
|
||||||
reports. If numbered reports are used for a type, all messages from
|
reports. If numbered reports are used for a type, all messages from
|
||||||
the kernel already have the report-number as prefix. Otherwise, no
|
the kernel already have the report-number as prefix. Otherwise, no
|
||||||
@ -140,10 +143,12 @@ them but you should handle them according to your needs.
|
|||||||
UHID_STOP:
|
UHID_STOP:
|
||||||
This is sent when the HID device is stopped. Consider this as an answer to
|
This is sent when the HID device is stopped. Consider this as an answer to
|
||||||
UHID_DESTROY.
|
UHID_DESTROY.
|
||||||
|
|
||||||
If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
|
If you didn't destroy your device via UHID_DESTROY, but the kernel sends an
|
||||||
UHID_STOP event, this should usually be ignored. It means that the kernel
|
UHID_STOP event, this should usually be ignored. It means that the kernel
|
||||||
reloaded/changed the device driver loaded on your HID device (or some other
|
reloaded/changed the device driver loaded on your HID device (or some other
|
||||||
maintenance actions happened).
|
maintenance actions happened).
|
||||||
|
|
||||||
You can usually ignored any UHID_STOP events safely.
|
You can usually ignored any UHID_STOP events safely.
|
||||||
|
|
||||||
UHID_OPEN:
|
UHID_OPEN:
|
||||||
@ -184,4 +189,5 @@ them but you should handle them according to your needs.
|
|||||||
The same restrictions as for UHID_GET_REPORT apply.
|
The same restrictions as for UHID_GET_REPORT apply.
|
||||||
|
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
Written 2012, David Herrmann <dh.herrmann@gmail.com>
|
Written 2012, David Herrmann <dh.herrmann@gmail.com>
|
@ -188,7 +188,7 @@ LCDs and many other purposes.
|
|||||||
|
|
||||||
The monitor and speaker controls should be easy to add to the hid/input
|
The monitor and speaker controls should be easy to add to the hid/input
|
||||||
interface, but for the UPSs and LCDs it doesn't make much sense. For this,
|
interface, but for the UPSs and LCDs it doesn't make much sense. For this,
|
||||||
the hiddev interface was designed. See Documentation/hid/hiddev.txt
|
the hiddev interface was designed. See Documentation/hid/hiddev.rst
|
||||||
for more information about it.
|
for more information about it.
|
||||||
|
|
||||||
The usage of the usbhid module is very simple, it takes no parameters,
|
The usage of the usbhid module is very simple, it takes no parameters,
|
||||||
|
@ -16432,7 +16432,7 @@ M: Benjamin Tissoires <benjamin.tissoires@redhat.com>
|
|||||||
L: linux-usb@vger.kernel.org
|
L: linux-usb@vger.kernel.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/hid/hiddev.txt
|
F: Documentation/hid/hiddev.rst
|
||||||
F: drivers/hid/usbhid/
|
F: drivers/hid/usbhid/
|
||||||
|
|
||||||
USB INTEL XHCI ROLE MUX DRIVER
|
USB INTEL XHCI ROLE MUX DRIVER
|
||||||
|
@ -1157,6 +1157,7 @@
|
|||||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
|
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
||||||
|
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
|
||||||
|
|
||||||
#define USB_VENDOR_ID_UNITEC 0x227d
|
#define USB_VENDOR_ID_UNITEC 0x227d
|
||||||
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
|
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
|
||||||
@ -1241,6 +1242,7 @@
|
|||||||
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
|
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
|
||||||
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
|
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
|
||||||
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F 0x4d0f
|
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F 0x4d0f
|
||||||
|
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65 0x4d65
|
||||||
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22 0x4e22
|
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22 0x4e22
|
||||||
|
|
||||||
|
|
||||||
|
@ -869,8 +869,6 @@ static void lg_remove(struct hid_device *hdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct hid_device_id lg_devices[] = {
|
static const struct hid_device_id lg_devices[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
|
|
||||||
.driver_data = LG_RDESC | LG_WIRELESS },
|
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
|
||||||
.driver_data = LG_RDESC | LG_WIRELESS },
|
.driver_data = LG_RDESC | LG_WIRELESS },
|
||||||
|
|
||||||
|
@ -1103,12 +1103,14 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
|
|||||||
|
|
||||||
static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
|
static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
|
||||||
{
|
{
|
||||||
const u8 template[] = {REPORT_ID_HIDPP_SHORT,
|
static const u8 template[] = {
|
||||||
|
REPORT_ID_HIDPP_SHORT,
|
||||||
HIDPP_RECEIVER_INDEX,
|
HIDPP_RECEIVER_INDEX,
|
||||||
HIDPP_SET_REGISTER,
|
HIDPP_SET_REGISTER,
|
||||||
HIDPP_REG_CONNECTION_STATE,
|
HIDPP_REG_CONNECTION_STATE,
|
||||||
HIDPP_FAKE_DEVICE_ARRIVAL,
|
HIDPP_FAKE_DEVICE_ARRIVAL,
|
||||||
0x00, 0x00};
|
0x00, 0x00
|
||||||
|
};
|
||||||
u8 *hidpp_report;
|
u8 *hidpp_report;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@ -1123,7 +1125,7 @@ static int logi_dj_recv_query_hidpp_devices(struct dj_receiver_dev *djrcv_dev)
|
|||||||
HID_REQ_SET_REPORT);
|
HID_REQ_SET_REPORT);
|
||||||
|
|
||||||
kfree(hidpp_report);
|
kfree(hidpp_report);
|
||||||
return 0;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
||||||
@ -1834,6 +1836,9 @@ static const struct hid_device_id logi_dj_receivers[] = {
|
|||||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||||
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING),
|
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING),
|
||||||
.driver_data = recvr_type_gaming_hidpp},
|
.driver_data = recvr_type_gaming_hidpp},
|
||||||
|
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
|
||||||
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
|
||||||
|
.driver_data = recvr_type_27mhz},
|
||||||
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */
|
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */
|
||||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||||
USB_DEVICE_ID_S510_RECEIVER_2),
|
USB_DEVICE_ID_S510_RECEIVER_2),
|
||||||
|
@ -2858,7 +2858,7 @@ static u8 *hidpp10_consumer_keys_report_fixup(struct hidpp_device *hidpp,
|
|||||||
u8 *_rdesc, unsigned int *rsize)
|
u8 *_rdesc, unsigned int *rsize)
|
||||||
{
|
{
|
||||||
/* Note 0 terminated so we can use strnstr to search for this. */
|
/* Note 0 terminated so we can use strnstr to search for this. */
|
||||||
const char consumer_rdesc_start[] = {
|
static const char consumer_rdesc_start[] = {
|
||||||
0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
|
0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
|
||||||
0x09, 0x01, /* USAGE (Consumer Control) */
|
0x09, 0x01, /* USAGE (Consumer Control) */
|
||||||
0xA1, 0x01, /* COLLECTION (Application) */
|
0xA1, 0x01, /* COLLECTION (Application) */
|
||||||
|
@ -130,6 +130,7 @@ static const struct hid_device_id hid_quirks[] = {
|
|||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
|
||||||
|
@ -389,6 +389,8 @@ static const struct hid_device_id uclogic_devices[] = {
|
|||||||
USB_DEVICE_ID_UGEE_TABLET_G5) },
|
USB_DEVICE_ID_UGEE_TABLET_G5) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_TABLET_EX07S) },
|
USB_DEVICE_ID_UGEE_TABLET_EX07S) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
|
USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
|
@ -1001,6 +1001,8 @@ int uclogic_params_init(struct uclogic_params *params,
|
|||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
|
||||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
|
||||||
|
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||||
|
USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
|
||||||
/* If this is the pen interface */
|
/* If this is the pen interface */
|
||||||
if (bInterfaceNumber == 1) {
|
if (bInterfaceNumber == 1) {
|
||||||
/* Probe v1 pen parameters */
|
/* Probe v1 pen parameters */
|
||||||
|
@ -184,6 +184,7 @@ static void ish_remove(struct pci_dev *pdev)
|
|||||||
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
|
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
|
||||||
|
|
||||||
ishtp_bus_remove_all_clients(ishtp_dev, false);
|
ishtp_bus_remove_all_clients(ishtp_dev, false);
|
||||||
|
pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
|
||||||
ish_device_disable(ishtp_dev);
|
ish_device_disable(ishtp_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,18 +304,23 @@ static void wacom_feature_mapping(struct hid_device *hdev,
|
|||||||
wacom_hid_usage_quirk(hdev, field, usage);
|
wacom_hid_usage_quirk(hdev, field, usage);
|
||||||
|
|
||||||
switch (equivalent_usage) {
|
switch (equivalent_usage) {
|
||||||
|
case WACOM_HID_WD_TOUCH_RING_SETTING:
|
||||||
|
wacom->generic_has_leds = true;
|
||||||
|
break;
|
||||||
case HID_DG_CONTACTMAX:
|
case HID_DG_CONTACTMAX:
|
||||||
/* leave touch_max as is if predefined */
|
/* leave touch_max as is if predefined */
|
||||||
if (!features->touch_max) {
|
if (!features->touch_max) {
|
||||||
/* read manually */
|
/* read manually */
|
||||||
data = kzalloc(2, GFP_KERNEL);
|
n = hid_report_len(field->report);
|
||||||
|
data = hid_alloc_report_buf(field->report, GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
break;
|
break;
|
||||||
data[0] = field->report->id;
|
data[0] = field->report->id;
|
||||||
ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
|
ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
|
||||||
data, 2, WAC_CMD_RETRIES);
|
data, n, WAC_CMD_RETRIES);
|
||||||
if (ret == 2) {
|
if (ret == n) {
|
||||||
features->touch_max = data[1];
|
ret = hid_report_raw_event(hdev,
|
||||||
|
HID_FEATURE_REPORT, data, n, 0);
|
||||||
} else {
|
} else {
|
||||||
features->touch_max = 16;
|
features->touch_max = 16;
|
||||||
hid_warn(hdev, "wacom_feature_mapping: "
|
hid_warn(hdev, "wacom_feature_mapping: "
|
||||||
|
@ -1216,7 +1216,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
|
|||||||
unsigned char *data = wacom->data;
|
unsigned char *data = wacom->data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (wacom->features.type == INTUOSP2_BT) {
|
if (wacom->features.type == INTUOSP2_BT ||
|
||||||
|
wacom->features.type == INTUOSP2S_BT) {
|
||||||
wacom->serial[0] = get_unaligned_le64(&data[99]);
|
wacom->serial[0] = get_unaligned_le64(&data[99]);
|
||||||
wacom->id[0] = get_unaligned_le16(&data[107]);
|
wacom->id[0] = get_unaligned_le16(&data[107]);
|
||||||
pen_frame_len = 14;
|
pen_frame_len = 14;
|
||||||
@ -1268,7 +1269,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
|
|||||||
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
|
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
|
||||||
input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
|
input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
|
||||||
|
|
||||||
if (wacom->features.type == INTUOSP2_BT) {
|
if (wacom->features.type == INTUOSP2_BT ||
|
||||||
|
wacom->features.type == INTUOSP2S_BT) {
|
||||||
/* Fix rotation alignment: userspace expects zero at left */
|
/* Fix rotation alignment: userspace expects zero at left */
|
||||||
int16_t rotation =
|
int16_t rotation =
|
||||||
(int16_t)get_unaligned_le16(&frame[9]);
|
(int16_t)get_unaligned_le16(&frame[9]);
|
||||||
@ -1286,7 +1288,6 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
|
|||||||
get_unaligned_le16(&frame[11]));
|
get_unaligned_le16(&frame[11]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wacom->tool[0]) {
|
if (wacom->tool[0]) {
|
||||||
input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
|
input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
|
||||||
if (wacom->features.type == INTUOSP2_BT) {
|
if (wacom->features.type == INTUOSP2_BT) {
|
||||||
@ -1456,7 +1457,8 @@ static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wacom_intuos_pro2_bt_pen(wacom);
|
wacom_intuos_pro2_bt_pen(wacom);
|
||||||
if (wacom->features.type == INTUOSP2_BT) {
|
if (wacom->features.type == INTUOSP2_BT ||
|
||||||
|
wacom->features.type == INTUOSP2S_BT) {
|
||||||
wacom_intuos_pro2_bt_touch(wacom);
|
wacom_intuos_pro2_bt_touch(wacom);
|
||||||
wacom_intuos_pro2_bt_pad(wacom);
|
wacom_intuos_pro2_bt_pad(wacom);
|
||||||
wacom_intuos_pro2_bt_battery(wacom);
|
wacom_intuos_pro2_bt_battery(wacom);
|
||||||
@ -1768,6 +1770,9 @@ int wacom_equivalent_usage(int usage)
|
|||||||
int subpage = (usage & 0xFF00) << 8;
|
int subpage = (usage & 0xFF00) << 8;
|
||||||
int subusage = (usage & 0xFF);
|
int subusage = (usage & 0xFF);
|
||||||
|
|
||||||
|
if (usage == WACOM_HID_WT_REPORT_VALID)
|
||||||
|
return usage;
|
||||||
|
|
||||||
if (subpage == HID_UP_UNDEFINED)
|
if (subpage == HID_UP_UNDEFINED)
|
||||||
subpage = WACOM_HID_SP_DIGITIZER;
|
subpage = WACOM_HID_SP_DIGITIZER;
|
||||||
|
|
||||||
@ -1926,8 +1931,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
|
|||||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||||
break;
|
break;
|
||||||
case WACOM_HID_WD_BUTTONCENTER:
|
case WACOM_HID_WD_BUTTONCENTER:
|
||||||
wacom->generic_has_leds = true;
|
|
||||||
/* fall through */
|
|
||||||
case WACOM_HID_WD_BUTTONHOME:
|
case WACOM_HID_WD_BUTTONHOME:
|
||||||
case WACOM_HID_WD_BUTTONUP:
|
case WACOM_HID_WD_BUTTONUP:
|
||||||
case WACOM_HID_WD_BUTTONDOWN:
|
case WACOM_HID_WD_BUTTONDOWN:
|
||||||
@ -2043,12 +2046,16 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
|||||||
*/
|
*/
|
||||||
if (hdev->vendor == 0x56a &&
|
if (hdev->vendor == 0x56a &&
|
||||||
(hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */
|
(hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */
|
||||||
hdev->product == 0x357 || hdev->product == 0x358)) { /* Intuos Pro 2 */
|
hdev->product == 0x357 || hdev->product == 0x358 || /* Intuos Pro 2 */
|
||||||
|
hdev->product == 0x392 || /* Intuos Pro 2 */
|
||||||
|
hdev->product == 0x399)) { /* MobileStudio Pro */
|
||||||
value = (field->logical_maximum - value);
|
value = (field->logical_maximum - value);
|
||||||
|
|
||||||
if (hdev->product == 0x357 || hdev->product == 0x358)
|
if (hdev->product == 0x357 || hdev->product == 0x358 ||
|
||||||
|
hdev->product == 0x392)
|
||||||
value = wacom_offset_rotation(input, usage, value, 3, 16);
|
value = wacom_offset_rotation(input, usage, value, 3, 16);
|
||||||
else if (hdev->product == 0x34d || hdev->product == 0x34e)
|
else if (hdev->product == 0x34d || hdev->product == 0x34e ||
|
||||||
|
hdev->product == 0x399)
|
||||||
value = wacom_offset_rotation(input, usage, value, 1, 2);
|
value = wacom_offset_rotation(input, usage, value, 1, 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -2119,14 +2126,12 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
|
|||||||
bool active = wacom_wac->hid_data.inrange_state != 0;
|
bool active = wacom_wac->hid_data.inrange_state != 0;
|
||||||
|
|
||||||
/* report prox for expresskey events */
|
/* report prox for expresskey events */
|
||||||
if ((wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) &&
|
if (wacom_wac->hid_data.pad_input_event_flag) {
|
||||||
wacom_wac->hid_data.pad_input_event_flag) {
|
|
||||||
input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
|
input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
|
||||||
input_sync(input);
|
input_sync(input);
|
||||||
if (!active)
|
if (!active)
|
||||||
wacom_wac->hid_data.pad_input_event_flag = false;
|
wacom_wac->hid_data.pad_input_event_flag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
||||||
@ -2512,6 +2517,10 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
|
|||||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||||
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
|
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
|
||||||
|
struct wacom_features *features = &wacom->wacom_wac.features;
|
||||||
|
|
||||||
|
if (wacom_wac->is_invalid_bt_frame)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (equivalent_usage) {
|
switch (equivalent_usage) {
|
||||||
case HID_GD_X:
|
case HID_GD_X:
|
||||||
@ -2532,9 +2541,14 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
|
|||||||
case HID_DG_TIPSWITCH:
|
case HID_DG_TIPSWITCH:
|
||||||
wacom_wac->hid_data.tipswitch = value;
|
wacom_wac->hid_data.tipswitch = value;
|
||||||
break;
|
break;
|
||||||
|
case WACOM_HID_WT_REPORT_VALID:
|
||||||
|
wacom_wac->is_invalid_bt_frame = !value;
|
||||||
|
return;
|
||||||
|
case HID_DG_CONTACTMAX:
|
||||||
|
features->touch_max = value;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (usage->usage_index + 1 == field->report_count) {
|
if (usage->usage_index + 1 == field->report_count) {
|
||||||
if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
|
if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
|
||||||
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
|
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
|
||||||
@ -2549,6 +2563,8 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
|
|||||||
struct hid_data* hid_data = &wacom_wac->hid_data;
|
struct hid_data* hid_data = &wacom_wac->hid_data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
wacom_wac->is_invalid_bt_frame = false;
|
||||||
|
|
||||||
for (i = 0; i < report->maxfield; i++) {
|
for (i = 0; i < report->maxfield; i++) {
|
||||||
struct hid_field *field = report->field[i];
|
struct hid_field *field = report->field[i];
|
||||||
int j;
|
int j;
|
||||||
@ -2569,25 +2585,9 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
|
|||||||
case HID_DG_TIPSWITCH:
|
case HID_DG_TIPSWITCH:
|
||||||
hid_data->last_slot_field = equivalent_usage;
|
hid_data->last_slot_field = equivalent_usage;
|
||||||
break;
|
break;
|
||||||
case HID_DG_CONTACTCOUNT:
|
|
||||||
hid_data->cc_report = report->id;
|
|
||||||
hid_data->cc_index = i;
|
|
||||||
hid_data->cc_value_index = j;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hid_data->cc_report != 0 &&
|
|
||||||
hid_data->cc_index >= 0) {
|
|
||||||
struct hid_field *field = report->field[hid_data->cc_index];
|
|
||||||
int value = field->value[hid_data->cc_value_index];
|
|
||||||
if (value)
|
|
||||||
hid_data->num_expected = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hid_data->num_expected = wacom_wac->features.touch_max;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wacom_wac_finger_report(struct hid_device *hdev,
|
static void wacom_wac_finger_report(struct hid_device *hdev,
|
||||||
@ -2597,6 +2597,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
|
|||||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||||
struct input_dev *input = wacom_wac->touch_input;
|
struct input_dev *input = wacom_wac->touch_input;
|
||||||
unsigned touch_max = wacom_wac->features.touch_max;
|
unsigned touch_max = wacom_wac->features.touch_max;
|
||||||
|
struct hid_data *hid_data = &wacom_wac->hid_data;
|
||||||
|
|
||||||
/* If more packets of data are expected, give us a chance to
|
/* If more packets of data are expected, give us a chance to
|
||||||
* process them rather than immediately syncing a partial
|
* process them rather than immediately syncing a partial
|
||||||
@ -2610,6 +2611,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
|
|||||||
|
|
||||||
input_sync(input);
|
input_sync(input);
|
||||||
wacom_wac->hid_data.num_received = 0;
|
wacom_wac->hid_data.num_received = 0;
|
||||||
|
hid_data->num_expected = 0;
|
||||||
|
|
||||||
/* keep touch state for pen event */
|
/* keep touch state for pen event */
|
||||||
wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
|
wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac);
|
||||||
@ -2684,12 +2686,73 @@ static void wacom_report_events(struct hid_device *hdev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void wacom_set_num_expected(struct hid_device *hdev,
|
||||||
|
struct hid_report *report,
|
||||||
|
int collection_index,
|
||||||
|
struct hid_field *field,
|
||||||
|
int field_index)
|
||||||
|
{
|
||||||
|
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||||
|
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||||
|
struct hid_data *hid_data = &wacom_wac->hid_data;
|
||||||
|
unsigned int original_collection_level =
|
||||||
|
hdev->collection[collection_index].level;
|
||||||
|
bool end_collection = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (hid_data->num_expected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// find the contact count value for this segment
|
||||||
|
for (i = field_index; i < report->maxfield && !end_collection; i++) {
|
||||||
|
struct hid_field *field = report->field[i];
|
||||||
|
unsigned int field_level =
|
||||||
|
hdev->collection[field->usage[0].collection_index].level;
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
if (field_level != original_collection_level)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; j < field->maxusage; j++) {
|
||||||
|
struct hid_usage *usage = &field->usage[j];
|
||||||
|
|
||||||
|
if (usage->collection_index != collection_index) {
|
||||||
|
end_collection = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (wacom_equivalent_usage(usage->hid) == HID_DG_CONTACTCOUNT) {
|
||||||
|
hid_data->cc_report = report->id;
|
||||||
|
hid_data->cc_index = i;
|
||||||
|
hid_data->cc_value_index = j;
|
||||||
|
|
||||||
|
if (hid_data->cc_report != 0 &&
|
||||||
|
hid_data->cc_index >= 0) {
|
||||||
|
|
||||||
|
struct hid_field *field =
|
||||||
|
report->field[hid_data->cc_index];
|
||||||
|
int value =
|
||||||
|
field->value[hid_data->cc_value_index];
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
hid_data->num_expected = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hid_data->cc_report == 0 || hid_data->cc_index < 0)
|
||||||
|
hid_data->num_expected = wacom_wac->features.touch_max;
|
||||||
|
}
|
||||||
|
|
||||||
static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
|
static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
|
||||||
int collection_index, struct hid_field *field,
|
int collection_index, struct hid_field *field,
|
||||||
int field_index)
|
int field_index)
|
||||||
{
|
{
|
||||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||||
|
|
||||||
|
if (WACOM_FINGER_FIELD(field))
|
||||||
|
wacom_set_num_expected(hdev, report, collection_index, field,
|
||||||
|
field_index);
|
||||||
wacom_report_events(hdev, report, collection_index, field_index);
|
wacom_report_events(hdev, report, collection_index, field_index);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2702,9 +2765,7 @@ static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *repo
|
|||||||
if (report->type != HID_INPUT_REPORT)
|
if (report->type != HID_INPUT_REPORT)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
|
if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
|
||||||
wacom_wac_pad_report(hdev, report, field);
|
|
||||||
else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
|
|
||||||
wacom_wac_pen_report(hdev, report);
|
wacom_wac_pen_report(hdev, report);
|
||||||
else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
|
else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
|
||||||
wacom_wac_finger_report(hdev, report);
|
wacom_wac_finger_report(hdev, report);
|
||||||
@ -2718,7 +2779,7 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
|
|||||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||||
struct hid_field *field;
|
struct hid_field *field;
|
||||||
bool pad_in_hid_field = false, pen_in_hid_field = false,
|
bool pad_in_hid_field = false, pen_in_hid_field = false,
|
||||||
finger_in_hid_field = false;
|
finger_in_hid_field = false, true_pad = false;
|
||||||
int r;
|
int r;
|
||||||
int prev_collection = -1;
|
int prev_collection = -1;
|
||||||
|
|
||||||
@ -2734,6 +2795,8 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
|
|||||||
pen_in_hid_field = true;
|
pen_in_hid_field = true;
|
||||||
if (WACOM_FINGER_FIELD(field))
|
if (WACOM_FINGER_FIELD(field))
|
||||||
finger_in_hid_field = true;
|
finger_in_hid_field = true;
|
||||||
|
if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY)
|
||||||
|
true_pad = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
wacom_wac_battery_pre_report(hdev, report);
|
wacom_wac_battery_pre_report(hdev, report);
|
||||||
@ -2757,6 +2820,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wacom_wac_battery_report(hdev, report);
|
wacom_wac_battery_report(hdev, report);
|
||||||
|
|
||||||
|
if (true_pad && wacom->wacom_wac.pad_input)
|
||||||
|
wacom_wac_pad_report(hdev, report, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wacom_bpt_touch(struct wacom_wac *wacom)
|
static int wacom_bpt_touch(struct wacom_wac *wacom)
|
||||||
@ -3225,6 +3291,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INTUOSP2_BT:
|
case INTUOSP2_BT:
|
||||||
|
case INTUOSP2S_BT:
|
||||||
case INTUOSHT3_BT:
|
case INTUOSHT3_BT:
|
||||||
sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
|
sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
|
||||||
break;
|
break;
|
||||||
@ -3405,7 +3472,8 @@ void wacom_setup_device_quirks(struct wacom *wacom)
|
|||||||
if (features->type == REMOTE)
|
if (features->type == REMOTE)
|
||||||
features->device_type = WACOM_DEVICETYPE_PAD;
|
features->device_type = WACOM_DEVICETYPE_PAD;
|
||||||
|
|
||||||
if (features->type == INTUOSP2_BT) {
|
if (features->type == INTUOSP2_BT ||
|
||||||
|
features->type == INTUOSP2S_BT) {
|
||||||
features->device_type |= WACOM_DEVICETYPE_PEN |
|
features->device_type |= WACOM_DEVICETYPE_PEN |
|
||||||
WACOM_DEVICETYPE_PAD |
|
WACOM_DEVICETYPE_PAD |
|
||||||
WACOM_DEVICETYPE_TOUCH;
|
WACOM_DEVICETYPE_TOUCH;
|
||||||
@ -3586,6 +3654,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
|
|||||||
case INTUOS5S:
|
case INTUOS5S:
|
||||||
case INTUOSPS:
|
case INTUOSPS:
|
||||||
case INTUOSP2_BT:
|
case INTUOSP2_BT:
|
||||||
|
case INTUOSP2S_BT:
|
||||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
||||||
features->distance_max,
|
features->distance_max,
|
||||||
features->distance_fuzz, 0);
|
features->distance_fuzz, 0);
|
||||||
@ -3697,6 +3766,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
|
|||||||
|
|
||||||
switch (features->type) {
|
switch (features->type) {
|
||||||
case INTUOSP2_BT:
|
case INTUOSP2_BT:
|
||||||
|
case INTUOSP2S_BT:
|
||||||
input_dev->evbit[0] |= BIT_MASK(EV_SW);
|
input_dev->evbit[0] |= BIT_MASK(EV_SW);
|
||||||
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
|
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
|
||||||
|
|
||||||
@ -3712,8 +3782,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
|
|||||||
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
|
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
|
||||||
0, 5920, 4, 0);
|
0, 5920, 4, 0);
|
||||||
}
|
}
|
||||||
|
else if (wacom_wac->shared->touch->product == 0x393) {
|
||||||
|
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
|
||||||
|
0, 6400, 4, 0);
|
||||||
|
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
|
||||||
|
0, 4000, 4, 0);
|
||||||
|
}
|
||||||
input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
|
input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
|
||||||
input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
|
input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40);
|
||||||
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
@ -4021,6 +4097,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
|
|||||||
case INTUOS5S:
|
case INTUOS5S:
|
||||||
case INTUOSPS:
|
case INTUOSPS:
|
||||||
case INTUOSP2_BT:
|
case INTUOSP2_BT:
|
||||||
|
case INTUOSP2S_BT:
|
||||||
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
|
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -4598,6 +4675,10 @@ static const struct wacom_features wacom_features_0x37A =
|
|||||||
static const struct wacom_features wacom_features_0x37B =
|
static const struct wacom_features wacom_features_0x37B =
|
||||||
{ "Wacom One by Wacom M", 21600, 13500, 2047, 63,
|
{ "Wacom One by Wacom M", 21600, 13500, 2047, 63,
|
||||||
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||||
|
static const struct wacom_features wacom_features_0x393 =
|
||||||
|
{ "Wacom Intuos Pro S", 31920, 19950, 8191, 63,
|
||||||
|
INTUOSP2S_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7,
|
||||||
|
.touch_max = 10 };
|
||||||
|
|
||||||
static const struct wacom_features wacom_features_HID_ANY_ID =
|
static const struct wacom_features wacom_features_HID_ANY_ID =
|
||||||
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
|
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
|
||||||
@ -4770,6 +4851,7 @@ const struct hid_device_id wacom_ids[] = {
|
|||||||
{ BT_DEVICE_WACOM(0x379) },
|
{ BT_DEVICE_WACOM(0x379) },
|
||||||
{ USB_DEVICE_WACOM(0x37A) },
|
{ USB_DEVICE_WACOM(0x37A) },
|
||||||
{ USB_DEVICE_WACOM(0x37B) },
|
{ USB_DEVICE_WACOM(0x37B) },
|
||||||
|
{ BT_DEVICE_WACOM(0x393) },
|
||||||
{ USB_DEVICE_WACOM(0x4001) },
|
{ USB_DEVICE_WACOM(0x4001) },
|
||||||
{ USB_DEVICE_WACOM(0x4004) },
|
{ USB_DEVICE_WACOM(0x4004) },
|
||||||
{ USB_DEVICE_WACOM(0x5000) },
|
{ USB_DEVICE_WACOM(0x5000) },
|
||||||
|
@ -141,6 +141,7 @@
|
|||||||
#define WACOM_HID_WD_OFFSETBOTTOM (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33)
|
#define WACOM_HID_WD_OFFSETBOTTOM (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33)
|
||||||
#define WACOM_HID_WD_DATAMODE (WACOM_HID_UP_WACOMDIGITIZER | 0x1002)
|
#define WACOM_HID_WD_DATAMODE (WACOM_HID_UP_WACOMDIGITIZER | 0x1002)
|
||||||
#define WACOM_HID_WD_DIGITIZERINFO (WACOM_HID_UP_WACOMDIGITIZER | 0x1013)
|
#define WACOM_HID_WD_DIGITIZERINFO (WACOM_HID_UP_WACOMDIGITIZER | 0x1013)
|
||||||
|
#define WACOM_HID_WD_TOUCH_RING_SETTING (WACOM_HID_UP_WACOMDIGITIZER | 0x1032)
|
||||||
#define WACOM_HID_UP_G9 0xff090000
|
#define WACOM_HID_UP_G9 0xff090000
|
||||||
#define WACOM_HID_G9_PEN (WACOM_HID_UP_G9 | 0x02)
|
#define WACOM_HID_G9_PEN (WACOM_HID_UP_G9 | 0x02)
|
||||||
#define WACOM_HID_G9_TOUCHSCREEN (WACOM_HID_UP_G9 | 0x11)
|
#define WACOM_HID_G9_TOUCHSCREEN (WACOM_HID_UP_G9 | 0x11)
|
||||||
@ -154,6 +155,7 @@
|
|||||||
#define WACOM_HID_WT_SERIALNUMBER (WACOM_HID_UP_WACOMTOUCH | 0x5b)
|
#define WACOM_HID_WT_SERIALNUMBER (WACOM_HID_UP_WACOMTOUCH | 0x5b)
|
||||||
#define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130)
|
#define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130)
|
||||||
#define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)
|
#define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)
|
||||||
|
#define WACOM_HID_WT_REPORT_VALID (WACOM_HID_UP_WACOMTOUCH | 0x1d0)
|
||||||
|
|
||||||
#define WACOM_BATTERY_USAGE(f) (((f)->hid == HID_DG_BATTERYSTRENGTH) || \
|
#define WACOM_BATTERY_USAGE(f) (((f)->hid == HID_DG_BATTERYSTRENGTH) || \
|
||||||
((f)->hid == WACOM_HID_WD_BATTERY_CHARGING) || \
|
((f)->hid == WACOM_HID_WD_BATTERY_CHARGING) || \
|
||||||
@ -210,6 +212,7 @@ enum {
|
|||||||
INTUOSPM,
|
INTUOSPM,
|
||||||
INTUOSPL,
|
INTUOSPL,
|
||||||
INTUOSP2_BT,
|
INTUOSP2_BT,
|
||||||
|
INTUOSP2S_BT,
|
||||||
INTUOSHT3_BT,
|
INTUOSHT3_BT,
|
||||||
WACOM_21UX2,
|
WACOM_21UX2,
|
||||||
WACOM_22HD,
|
WACOM_22HD,
|
||||||
|
Loading…
Reference in New Issue
Block a user