forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina: - AMD SFH (Sensor Fusion Hub) support (Sandeep Singh) - increase of maximum HID report size to 16KB in order to support some of the modern devices (Dean Camera) - control interface support for hidraw (Dean Camera) - Sony DS4 power and firmware reporting fixes (Roderick Colenbrander) - support for ghlive PS3/WII U dongles (Pascal Giard) * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (27 commits) HID: i2c-hid: add Vero K147 to descriptor override HID: ite: Add support for Acer S1002 keyboard-dock HID: sony: support for ghlive ps3/wii u dongles HID: hidraw: Add additional hidraw input/output report ioctls. HID: Increase HID maximum report size to 16KB HID: elecom: drop stray comment HID: mf: add support for 0079:1846 Mayflash/Dragonrise USB Gamecube Adapter HID: elecom: add support for EX-G M-XGL20DLBK wireless mouse HID: elecom: rewrite report based on model specific parameters HID: wacom: Constify attribute_groups HID: input: Fix fall-through warnings for Clang HID: usbhid: Fix fall-through warnings for Clang HID: logitech-hidpp: Add hid_device_id for V470 bluetooth mouse HID: intel-ish-hid: Remove unnecessary assignment to variable rv HID: sony: Workaround for DS4 dongle hotplug kernel crash. HID: sony: Don't use fw_version/hw_version for sysfs cleanup. HID: sony: Report more accurate DS4 power status. SFH: fix error return check for -ERESTARTSYS HID: SFH: Add documentation HID: hid-input: occasionally report stylus battery even if not changed ...
This commit is contained in:
commit
de925e2fbb
145
Documentation/hid/amd-sfh-hid.rst
Normal file
145
Documentation/hid/amd-sfh-hid.rst
Normal file
@ -0,0 +1,145 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
|
||||
AMD Sensor Fusion Hub
|
||||
=====================
|
||||
AMD Sensor Fusion Hub (SFH) is part of an SOC starting from Ryzen based platforms.
|
||||
The solution is working well on several OEM products. AMD SFH uses HID over PCIe bus.
|
||||
In terms of architecture it resembles ISH, however the major difference is all
|
||||
the HID reports are generated as part of the kernel driver.
|
||||
|
||||
1. Block Diagram
|
||||
================
|
||||
|
||||
::
|
||||
|
||||
---------------------------------
|
||||
| HID User Space Applications |
|
||||
- -------------------------------
|
||||
|
||||
---------------------------------------------
|
||||
---------------------------------
|
||||
| HID Core |
|
||||
---------------------------------
|
||||
|
||||
---------------------------------
|
||||
| AMD HID Transport |
|
||||
---------------------------------
|
||||
|
||||
--------------------------------
|
||||
| AMD HID Client |
|
||||
| with HID Report Generator|
|
||||
--------------------------------
|
||||
|
||||
--------------------------------
|
||||
| AMD MP2 PCIe Driver |
|
||||
--------------------------------
|
||||
OS
|
||||
---------------------------------------------
|
||||
Hardware + Firmware
|
||||
--------------------------------
|
||||
| SFH MP2 Processor |
|
||||
--------------------------------
|
||||
|
||||
|
||||
AMD HID Transport Layer
|
||||
-----------------------
|
||||
AMD SFH transport is also implemented as a bus. Each client application executing in the AMD MP2 is
|
||||
registered as a device on this bus. Here: MP2 which is an ARM core connected to x86 for processing
|
||||
sensor data. The layer, which binds each device (AMD SFH HID driver) identifies the device type and
|
||||
registers with the hid core. Transport layer attach a constant "struct hid_ll_driver" object with
|
||||
each device. Once a device is registered with HID core, the callbacks provided via this struct are
|
||||
used by HID core to communicate with the device. AMD HID Transport layer implements the synchronous calls.
|
||||
|
||||
AMD HID Client Layer
|
||||
--------------------
|
||||
This layer is responsible to implement HID request and descriptors. As firmware is OS agnostic, HID
|
||||
client layer fills the HID request structure and descriptors. HID client layer is complex as it is
|
||||
interface between MP2 PCIe layer and HID. HID client layer initialized the MP2 PCIe layer and holds
|
||||
the instance of MP2 layer. It identifies the number of sensors connected using MP2-PCIe layer. Base
|
||||
on that allocates the DRAM address for each and every sensor and pass it to MP2-PCIe driver.On
|
||||
enumeration of each the sensor, client layer fills the HID Descriptor structure and HID input repor
|
||||
structure. HID Feature report structure is optional. The report descriptor structure varies from
|
||||
sensor to sensor.
|
||||
|
||||
AMD MP2 PCIe layer
|
||||
------------------
|
||||
MP2 PCIe Layer is responsible for making all transactions with the firmware over PCIe.
|
||||
The connection establishment between firmware and PCIe happens here.
|
||||
|
||||
The communication between X86 and MP2 is split into three parts.
|
||||
1. Command transfer via the C2P mailbox registers.
|
||||
2. Data transfer via DRAM.
|
||||
3. Supported sensor info via P2C registers.
|
||||
|
||||
Commands are sent to MP2 using C2P Mailbox registers. Writing into C2P Message registers generate
|
||||
interrupt to MP2. The client layer allocates the physical memory and the same is sent to MP2 via
|
||||
the PCI layer. MP2 firmware writes the command output to the access DRAM memory which the client
|
||||
layer has allocated. Firmware always writes minimum of 32 bytes into DRAM. So as a protocol driver
|
||||
shall allocate minimum of 32 bytes DRAM space.
|
||||
|
||||
Enumeration and Probing flow
|
||||
----------------------------
|
||||
::
|
||||
|
||||
HID AMD AMD AMD -PCIe MP2
|
||||
Core Transport Client layer layer FW
|
||||
| | | | |
|
||||
| | | on Boot Driver Loaded |
|
||||
| | | | |
|
||||
| | | MP2-PCIe Int |
|
||||
| | | | |
|
||||
| | |---Get Number of sensors-> | |
|
||||
| | | Read P2C |
|
||||
| | | Register |
|
||||
| | | | |
|
||||
| | | Loop(for No of Sensors) | |
|
||||
| | |----------------------| | |
|
||||
| | | Create HID Descriptor| | |
|
||||
| | | Create Input report | | |
|
||||
| | | Descriptor Map | | |
|
||||
| | | the MP2 FW Index to | | |
|
||||
| | | HID Index | | |
|
||||
| | | Allocate the DRAM | Enable |
|
||||
| | | address | Sensors |
|
||||
| | |----------------------| | |
|
||||
| | HID transport| | Enable |
|
||||
| |<--Probe------| |---Sensor CMD--> |
|
||||
| | Create the | | |
|
||||
| | HID device | | |
|
||||
| | (MFD) | | |
|
||||
| | by Populating| | |
|
||||
| | the HID | | |
|
||||
| | ll_driver | | |
|
||||
| HID | | | |
|
||||
| add | | | |
|
||||
|Device | | | |
|
||||
|<------------- | | | |
|
||||
|
||||
|
||||
Data Flow from Application to the AMD SFH Driver
|
||||
------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
|HID_req | | | |
|
||||
|get_report | | | |
|
||||
|------------->| | | |
|
||||
| | HID_get_input| | |
|
||||
| | report | | |
|
||||
| |------------->|------------------------| | |
|
||||
| | | Read the DRAM data for| | |
|
||||
| | | requested sensor and | | |
|
||||
| | | create the HID input | | |
|
||||
| | | report | | |
|
||||
| | |------------------------| | |
|
||||
| |Data received | | |
|
||||
| | in HID report| | |
|
||||
To |<-------------|<-------------| | |
|
||||
Applications| | | | |
|
||||
<-------| | | | |
|
@ -123,8 +123,49 @@ HIDIOCGFEATURE(len):
|
||||
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
|
||||
number of the requested report. For devices which do not use numbered
|
||||
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).
|
||||
reports, set the first byte to 0. The returned report buffer will contain the
|
||||
report number in the first byte, followed by the report data read from the
|
||||
device. For devices which do not use numbered reports, the report data will
|
||||
begin at the first byte of the returned buffer.
|
||||
|
||||
HIDIOCSINPUT(len):
|
||||
Send an Input Report
|
||||
|
||||
This ioctl will send an input report to the device, using the control endpoint.
|
||||
In most cases, setting an input HID report on a device is meaningless and has
|
||||
no effect, but some devices may choose to use this to set or reset an initial
|
||||
state of a report. The format of the buffer issued with this report is identical
|
||||
to that of HIDIOCSFEATURE.
|
||||
|
||||
HIDIOCGINPUT(len):
|
||||
Get an Input Report
|
||||
|
||||
This ioctl will request an input report from the device using the control
|
||||
endpoint. This is slower on most devices where a dedicated In endpoint exists
|
||||
for regular input reports, but allows the host to request the value of a
|
||||
specific report number. Typically, this is used to request the initial states of
|
||||
an input report of a device, before an application listens for normal reports via
|
||||
the regular device read() interface. The format of the buffer issued with this report
|
||||
is identical to that of HIDIOCGFEATURE.
|
||||
|
||||
HIDIOCSOUTPUT(len):
|
||||
Send an Output Report
|
||||
|
||||
This ioctl will send an output report to the device, using the control endpoint.
|
||||
This is slower on most devices where a dedicated Out endpoint exists for regular
|
||||
output reports, but is added for completeness. Typically, this is used to set
|
||||
the initial states of an output report of a device, before an application sends
|
||||
updates via the regular device write() interface. The format of the buffer issued
|
||||
with this report is identical to that of HIDIOCSFEATURE.
|
||||
|
||||
HIDIOCGOUTPUT(len):
|
||||
Get an Output Report
|
||||
|
||||
This ioctl will request an output report from the device using the control
|
||||
endpoint. Typically, this is used to retrive the initial state of
|
||||
an output report of a device, before an application updates it as necessary either
|
||||
via a HIDIOCSOUTPUT request, or the regular device write() interface. The format
|
||||
of the buffer issued with this report is identical to that of HIDIOCGFEATURE.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
@ -16,3 +16,4 @@ Human Interface Devices (HID)
|
||||
|
||||
hid-alps
|
||||
intel-ish-hid
|
||||
amd-sfh-hid
|
||||
|
@ -956,6 +956,14 @@ S: Supported
|
||||
F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
|
||||
F: drivers/net/ethernet/amd/xgbe/
|
||||
|
||||
AMD SENSOR FUSION HUB DRIVER
|
||||
M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
|
||||
M: Sandeep Singh <sandeep.singh@amd.com>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hid/amd-sfh*
|
||||
F: drivers/hid/amd-sfh-hid/
|
||||
|
||||
AMS AS73211 DRIVER
|
||||
M: Christian Eggers <ceggers@arri.de>
|
||||
L: linux-iio@vger.kernel.org
|
||||
|
@ -907,6 +907,7 @@ config HID_SONY
|
||||
* Buzz controllers
|
||||
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
|
||||
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
|
||||
* Guitar Hero Live PS3 and Wii U guitar dongles
|
||||
|
||||
config SONY_FF
|
||||
bool "Sony PS2/3/4 accessories force feedback support"
|
||||
@ -1183,4 +1184,6 @@ source "drivers/hid/i2c-hid/Kconfig"
|
||||
|
||||
source "drivers/hid/intel-ish-hid/Kconfig"
|
||||
|
||||
source "drivers/hid/amd-sfh-hid/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -142,3 +142,5 @@ obj-$(CONFIG_I2C_HID) += i2c-hid/
|
||||
|
||||
obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
|
||||
obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
|
||||
|
||||
obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
|
||||
|
18
drivers/hid/amd-sfh-hid/Kconfig
Normal file
18
drivers/hid/amd-sfh-hid/Kconfig
Normal file
@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
menu "AMD SFH HID Support"
|
||||
depends on X86_64 || COMPILE_TEST
|
||||
depends on PCI
|
||||
depends on HID
|
||||
|
||||
config AMD_SFH_HID
|
||||
tristate "AMD Sensor Fusion Hub"
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
AMD Sensor Fusion Hub.
|
||||
This driver will enable sensors functionality on AMD platforms
|
||||
starting from 17h family of RYZEN parts.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called amd-sfh.
|
||||
Say Y or M here if you want to support AMD SFH. If unsure, say N.
|
||||
endmenu
|
13
drivers/hid/amd-sfh-hid/Makefile
Normal file
13
drivers/hid/amd-sfh-hid/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Makefile - AMD SFH HID drivers
|
||||
# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
|
||||
#
|
||||
#
|
||||
obj-$(CONFIG_AMD_SFH_HID) += amd_sfh.o
|
||||
amd_sfh-objs := amd_sfh_hid.o
|
||||
amd_sfh-objs += amd_sfh_client.o
|
||||
amd_sfh-objs += amd_sfh_pcie.o
|
||||
amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o
|
||||
|
||||
ccflags-y += -I $(srctree)/$(src)/
|
246
drivers/hid/amd-sfh-hid/amd_sfh_client.c
Normal file
246
drivers/hid/amd-sfh-hid/amd_sfh_client.c
Normal file
@ -0,0 +1,246 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* AMD SFH Client Layer
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
* Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>
|
||||
* Sandeep Singh <Sandeep.singh@amd.com>
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "hid_descriptor/amd_sfh_hid_desc.h"
|
||||
#include "amd_sfh_pcie.h"
|
||||
#include "amd_sfh_hid.h"
|
||||
|
||||
#define AMD_SFH_IDLE_LOOP 200
|
||||
|
||||
struct request_list {
|
||||
struct hid_device *hid;
|
||||
struct list_head list;
|
||||
u8 report_id;
|
||||
u8 sensor_idx;
|
||||
u8 report_type;
|
||||
u8 current_index;
|
||||
};
|
||||
|
||||
static struct request_list req_list;
|
||||
|
||||
void amd_sfh_set_report(struct hid_device *hid, int report_id,
|
||||
int report_type)
|
||||
{
|
||||
struct amdtp_hid_data *hid_data = hid->driver_data;
|
||||
struct amdtp_cl_data *cli_data = hid_data->cli_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cli_data->num_hid_devices; i++) {
|
||||
if (cli_data->hid_sensor_hubs[i] == hid) {
|
||||
cli_data->cur_hid_dev = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
amdtp_hid_wakeup(hid);
|
||||
}
|
||||
|
||||
int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)
|
||||
{
|
||||
struct amdtp_hid_data *hid_data = hid->driver_data;
|
||||
struct amdtp_cl_data *cli_data = hid_data->cli_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cli_data->num_hid_devices; i++) {
|
||||
if (cli_data->hid_sensor_hubs[i] == hid) {
|
||||
struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL);
|
||||
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
new->current_index = i;
|
||||
new->sensor_idx = cli_data->sensor_idx[i];
|
||||
new->hid = hid;
|
||||
new->report_type = report_type;
|
||||
new->report_id = report_id;
|
||||
cli_data->report_id[i] = report_id;
|
||||
cli_data->request_done[i] = false;
|
||||
list_add(&new->list, &req_list.list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
schedule_delayed_work(&cli_data->work, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amd_sfh_work(struct work_struct *work)
|
||||
{
|
||||
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);
|
||||
struct request_list *req_node;
|
||||
u8 current_index, sensor_index;
|
||||
u8 report_id, node_type;
|
||||
u8 report_size = 0;
|
||||
|
||||
req_node = list_last_entry(&req_list.list, struct request_list, list);
|
||||
list_del(&req_node->list);
|
||||
current_index = req_node->current_index;
|
||||
sensor_index = req_node->sensor_idx;
|
||||
report_id = req_node->report_id;
|
||||
node_type = req_node->report_type;
|
||||
|
||||
if (node_type == HID_FEATURE_REPORT) {
|
||||
report_size = get_feature_report(sensor_index, report_id,
|
||||
cli_data->feature_report[current_index]);
|
||||
if (report_size)
|
||||
hid_input_report(cli_data->hid_sensor_hubs[current_index],
|
||||
cli_data->report_type[current_index],
|
||||
cli_data->feature_report[current_index], report_size, 0);
|
||||
else
|
||||
pr_err("AMDSFH: Invalid report size\n");
|
||||
|
||||
} else if (node_type == HID_INPUT_REPORT) {
|
||||
report_size = get_input_report(sensor_index, report_id,
|
||||
cli_data->input_report[current_index],
|
||||
cli_data->sensor_virt_addr[current_index]);
|
||||
if (report_size)
|
||||
hid_input_report(cli_data->hid_sensor_hubs[current_index],
|
||||
cli_data->report_type[current_index],
|
||||
cli_data->input_report[current_index], report_size, 0);
|
||||
else
|
||||
pr_err("AMDSFH: Invalid report size\n");
|
||||
}
|
||||
cli_data->cur_hid_dev = current_index;
|
||||
cli_data->sensor_requested_cnt[current_index] = 0;
|
||||
amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]);
|
||||
}
|
||||
|
||||
static void amd_sfh_work_buffer(struct work_struct *work)
|
||||
{
|
||||
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);
|
||||
u8 report_size;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cli_data->num_hid_devices; i++) {
|
||||
report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i],
|
||||
cli_data->input_report[i],
|
||||
cli_data->sensor_virt_addr[i]);
|
||||
hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
|
||||
cli_data->input_report[i], report_size, 0);
|
||||
}
|
||||
schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
|
||||
}
|
||||
|
||||
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||
{
|
||||
struct amdtp_cl_data *cl_data = privdata->cl_data;
|
||||
struct amd_mp2_sensor_info info;
|
||||
struct device *dev;
|
||||
u32 feature_report_size;
|
||||
u32 input_report_size;
|
||||
u8 cl_idx;
|
||||
int rc, i;
|
||||
|
||||
dev = &privdata->pdev->dev;
|
||||
cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL);
|
||||
if (!cl_data)
|
||||
return -ENOMEM;
|
||||
|
||||
cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
|
||||
|
||||
INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
|
||||
INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
|
||||
INIT_LIST_HEAD(&req_list.list);
|
||||
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||
cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
|
||||
&cl_data->sensor_phys_addr[i],
|
||||
GFP_KERNEL);
|
||||
cl_data->sensor_sts[i] = 0;
|
||||
cl_data->sensor_requested_cnt[i] = 0;
|
||||
cl_data->cur_hid_dev = i;
|
||||
cl_idx = cl_data->sensor_idx[i];
|
||||
cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size);
|
||||
if (!cl_data->report_descr_sz[i]) {
|
||||
rc = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
feature_report_size = get_descr_sz(cl_idx, feature_size);
|
||||
if (!feature_report_size) {
|
||||
rc = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
input_report_size = get_descr_sz(cl_idx, input_size);
|
||||
if (!input_report_size) {
|
||||
rc = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
cl_data->feature_report[i] = kzalloc(feature_report_size, GFP_KERNEL);
|
||||
if (!cl_data->feature_report[i]) {
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
cl_data->input_report[i] = kzalloc(input_report_size, GFP_KERNEL);
|
||||
if (!cl_data->input_report[i]) {
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
info.period = msecs_to_jiffies(AMD_SFH_IDLE_LOOP);
|
||||
info.sensor_idx = cl_idx;
|
||||
info.phys_address = cl_data->sensor_phys_addr[i];
|
||||
|
||||
cl_data->report_descr[i] = kzalloc(cl_data->report_descr_sz[i], GFP_KERNEL);
|
||||
if (!cl_data->report_descr[i]) {
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
amd_start_sensor(privdata, info);
|
||||
cl_data->sensor_sts[i] = 1;
|
||||
}
|
||||
privdata->cl_data = cl_data;
|
||||
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||
if (cl_data->sensor_virt_addr[i]) {
|
||||
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
|
||||
cl_data->sensor_virt_addr[i],
|
||||
cl_data->sensor_phys_addr[i]);
|
||||
}
|
||||
kfree(cl_data->feature_report[i]);
|
||||
kfree(cl_data->input_report[i]);
|
||||
kfree(cl_data->report_descr[i]);
|
||||
}
|
||||
kfree(cl_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
|
||||
{
|
||||
struct amdtp_cl_data *cl_data = privdata->cl_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++)
|
||||
amd_stop_sensor(privdata, i);
|
||||
|
||||
cancel_delayed_work_sync(&cl_data->work);
|
||||
cancel_delayed_work_sync(&cl_data->work_buffer);
|
||||
amdtp_hid_remove(cl_data);
|
||||
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||
if (cl_data->sensor_virt_addr[i]) {
|
||||
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
|
||||
cl_data->sensor_virt_addr[i],
|
||||
cl_data->sensor_phys_addr[i]);
|
||||
}
|
||||
}
|
||||
kfree(cl_data);
|
||||
return 0;
|
||||
}
|
174
drivers/hid/amd-sfh-hid/amd_sfh_hid.c
Normal file
174
drivers/hid/amd-sfh-hid/amd_sfh_hid.c
Normal file
@ -0,0 +1,174 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* AMD MP2 Sensors transport driver
|
||||
*
|
||||
* Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
|
||||
* Sandeep Singh <sandeep.singh@amd.com>
|
||||
*/
|
||||
#include <linux/hid.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "amd_sfh_hid.h"
|
||||
|
||||
#define AMD_SFH_RESPONSE_TIMEOUT 1500
|
||||
|
||||
/**
|
||||
* amdtp_hid_parse() - hid-core .parse() callback
|
||||
* @hid: hid device instance
|
||||
*
|
||||
* This function gets called during call to hid_add_device
|
||||
*
|
||||
* Return: 0 on success and non zero on error
|
||||
*/
|
||||
static int amdtp_hid_parse(struct hid_device *hid)
|
||||
{
|
||||
struct amdtp_hid_data *hid_data = hid->driver_data;
|
||||
struct amdtp_cl_data *cli_data = hid_data->cli_data;
|
||||
|
||||
return hid_parse_report(hid, cli_data->report_descr[hid_data->index],
|
||||
cli_data->report_descr_sz[hid_data->index]);
|
||||
}
|
||||
|
||||
/* Empty callbacks with success return code */
|
||||
static int amdtp_hid_start(struct hid_device *hid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdtp_hid_stop(struct hid_device *hid)
|
||||
{
|
||||
}
|
||||
|
||||
static int amdtp_hid_open(struct hid_device *hid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdtp_hid_close(struct hid_device *hid)
|
||||
{
|
||||
}
|
||||
|
||||
static int amdtp_raw_request(struct hid_device *hdev, u8 reportnum,
|
||||
u8 *buf, size_t len, u8 rtype, int reqtype)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (reqtype) {
|
||||
case HID_REQ_GET_REPORT:
|
||||
rc = amd_sfh_get_report(hid, rep->id, rep->type);
|
||||
if (rc)
|
||||
dev_err(&hid->dev, "AMDSFH get report error\n");
|
||||
break;
|
||||
case HID_REQ_SET_REPORT:
|
||||
amd_sfh_set_report(hid, rep->id, reqtype);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int amdtp_wait_for_response(struct hid_device *hid)
|
||||
{
|
||||
struct amdtp_hid_data *hid_data = hid->driver_data;
|
||||
struct amdtp_cl_data *cli_data = hid_data->cli_data;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < cli_data->num_hid_devices; i++) {
|
||||
if (cli_data->hid_sensor_hubs[i] == hid)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cli_data->request_done[i])
|
||||
ret = wait_event_interruptible_timeout(hid_data->hid_wait,
|
||||
cli_data->request_done[i],
|
||||
msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT));
|
||||
if (ret == -ERESTARTSYS)
|
||||
return -ERESTARTSYS;
|
||||
else if (ret < 0)
|
||||
return -ETIMEDOUT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amdtp_hid_wakeup(struct hid_device *hid)
|
||||
{
|
||||
struct amdtp_hid_data *hid_data = hid->driver_data;
|
||||
struct amdtp_cl_data *cli_data = hid_data->cli_data;
|
||||
|
||||
cli_data->request_done[cli_data->cur_hid_dev] = true;
|
||||
wake_up_interruptible(&hid_data->hid_wait);
|
||||
}
|
||||
|
||||
static struct hid_ll_driver amdtp_hid_ll_driver = {
|
||||
.parse = amdtp_hid_parse,
|
||||
.start = amdtp_hid_start,
|
||||
.stop = amdtp_hid_stop,
|
||||
.open = amdtp_hid_open,
|
||||
.close = amdtp_hid_close,
|
||||
.request = amdtp_hid_request,
|
||||
.wait = amdtp_wait_for_response,
|
||||
.raw_request = amdtp_raw_request,
|
||||
};
|
||||
|
||||
int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
|
||||
{
|
||||
struct hid_device *hid;
|
||||
struct amdtp_hid_data *hid_data;
|
||||
int rc;
|
||||
|
||||
hid = hid_allocate_device();
|
||||
if (IS_ERR(hid))
|
||||
return PTR_ERR(hid);
|
||||
|
||||
hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
|
||||
if (!hid_data) {
|
||||
rc = -ENOMEM;
|
||||
goto err_hid_data;
|
||||
}
|
||||
|
||||
hid->ll_driver = &amdtp_hid_ll_driver;
|
||||
hid_data->index = cur_hid_dev;
|
||||
hid_data->cli_data = cli_data;
|
||||
init_waitqueue_head(&hid_data->hid_wait);
|
||||
|
||||
hid->driver_data = hid_data;
|
||||
cli_data->hid_sensor_hubs[cur_hid_dev] = hid;
|
||||
hid->bus = BUS_AMD_AMDTP;
|
||||
hid->vendor = AMD_SFH_HID_VENDOR;
|
||||
hid->product = AMD_SFH_HID_PRODUCT;
|
||||
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp",
|
||||
hid->vendor, hid->product);
|
||||
|
||||
rc = hid_add_device(hid);
|
||||
if (rc)
|
||||
goto err_hid_device;
|
||||
return 0;
|
||||
|
||||
err_hid_device:
|
||||
kfree(hid_data);
|
||||
err_hid_data:
|
||||
hid_destroy_device(hid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void amdtp_hid_remove(struct amdtp_cl_data *cli_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cli_data->num_hid_devices; ++i) {
|
||||
kfree(cli_data->feature_report[i]);
|
||||
kfree(cli_data->input_report[i]);
|
||||
kfree(cli_data->report_descr[i]);
|
||||
if (cli_data->hid_sensor_hubs[i]) {
|
||||
kfree(cli_data->hid_sensor_hubs[i]->driver_data);
|
||||
hid_destroy_device(cli_data->hid_sensor_hubs[i]);
|
||||
cli_data->hid_sensor_hubs[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
67
drivers/hid/amd-sfh-hid/amd_sfh_hid.h
Normal file
67
drivers/hid/amd-sfh-hid/amd_sfh_hid.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* AMD MP2 Sensors transport driver
|
||||
*
|
||||
* Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
|
||||
* Sandeep Singh <sandeep.singh@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef AMDSFH_HID_H
|
||||
#define AMDSFH_HID_H
|
||||
|
||||
#define MAX_HID_DEVICES 4
|
||||
#define BUS_AMD_AMDTP 0x20
|
||||
#define AMD_SFH_HID_VENDOR 0x1022
|
||||
#define AMD_SFH_HID_PRODUCT 0x0001
|
||||
|
||||
struct amdtp_cl_data {
|
||||
u8 init_done;
|
||||
u32 cur_hid_dev;
|
||||
u32 hid_dev_count;
|
||||
u32 num_hid_devices;
|
||||
struct device_info *hid_devices;
|
||||
u8 *report_descr[MAX_HID_DEVICES];
|
||||
int report_descr_sz[MAX_HID_DEVICES];
|
||||
struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES];
|
||||
u8 *hid_descr[MAX_HID_DEVICES];
|
||||
int hid_descr_size[MAX_HID_DEVICES];
|
||||
phys_addr_t phys_addr_base;
|
||||
u32 *sensor_virt_addr[MAX_HID_DEVICES];
|
||||
phys_addr_t sensor_phys_addr[MAX_HID_DEVICES];
|
||||
u32 sensor_sts[MAX_HID_DEVICES];
|
||||
u32 sensor_requested_cnt[MAX_HID_DEVICES];
|
||||
u8 report_type[MAX_HID_DEVICES];
|
||||
u8 report_id[MAX_HID_DEVICES];
|
||||
u8 sensor_idx[MAX_HID_DEVICES];
|
||||
u8 *feature_report[MAX_HID_DEVICES];
|
||||
u8 *input_report[MAX_HID_DEVICES];
|
||||
u8 request_done[MAX_HID_DEVICES];
|
||||
struct delayed_work work;
|
||||
struct delayed_work work_buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amdtp_hid_data - Per instance HID data
|
||||
* @index: Device index in the order of enumeration
|
||||
* @request_done: Get Feature/Input report complete flag
|
||||
* used during get/set request from hid core
|
||||
* @cli_data: Link to the client instance
|
||||
* @hid_wait: Completion waitq
|
||||
*
|
||||
* Used to tie hid->driver data to driver client instance
|
||||
*/
|
||||
struct amdtp_hid_data {
|
||||
int index;
|
||||
struct amdtp_cl_data *cli_data;
|
||||
wait_queue_head_t hid_wait;
|
||||
};
|
||||
|
||||
/* Interface functions between HID LL driver and AMD SFH client */
|
||||
void hid_amdtp_set_feature(struct hid_device *hid, char *buf, u32 len, int report_id);
|
||||
void hid_amdtp_get_report(struct hid_device *hid, int report_id, int report_type);
|
||||
int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data);
|
||||
void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
|
||||
int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type);
|
||||
void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type);
|
||||
void amdtp_hid_wakeup(struct hid_device *hid);
|
||||
#endif
|
152
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
Normal file
152
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
Normal file
@ -0,0 +1,152 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* AMD MP2 PCIe communication driver
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
|
||||
* Sandeep Singh <Sandeep.singh@amd.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "amd_sfh_pcie.h"
|
||||
|
||||
#define DRIVER_NAME "pcie_mp2_amd"
|
||||
#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
|
||||
|
||||
#define ACEL_EN BIT(0)
|
||||
#define GYRO_EN BIT(1)
|
||||
#define MAGNO_EN BIT(2)
|
||||
#define ALS_EN BIT(19)
|
||||
|
||||
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
|
||||
{
|
||||
union sfh_cmd_param cmd_param;
|
||||
union sfh_cmd_base cmd_base;
|
||||
|
||||
/* fill up command register */
|
||||
memset(&cmd_base, 0, sizeof(cmd_base));
|
||||
cmd_base.s.cmd_id = ENABLE_SENSOR;
|
||||
cmd_base.s.period = info.period;
|
||||
cmd_base.s.sensor_id = info.sensor_idx;
|
||||
|
||||
/* fill up command param register */
|
||||
memset(&cmd_param, 0, sizeof(cmd_param));
|
||||
cmd_param.s.buf_layout = 1;
|
||||
cmd_param.s.buf_length = 16;
|
||||
|
||||
writeq(info.phys_address, privdata->mmio + AMD_C2P_MSG2);
|
||||
writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
|
||||
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
|
||||
}
|
||||
|
||||
void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
|
||||
{
|
||||
union sfh_cmd_base cmd_base;
|
||||
|
||||
/* fill up command register */
|
||||
memset(&cmd_base, 0, sizeof(cmd_base));
|
||||
cmd_base.s.cmd_id = DISABLE_SENSOR;
|
||||
cmd_base.s.period = 0;
|
||||
cmd_base.s.sensor_id = sensor_idx;
|
||||
|
||||
writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
|
||||
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
|
||||
}
|
||||
|
||||
void amd_stop_all_sensors(struct amd_mp2_dev *privdata)
|
||||
{
|
||||
union sfh_cmd_base cmd_base;
|
||||
|
||||
/* fill up command register */
|
||||
memset(&cmd_base, 0, sizeof(cmd_base));
|
||||
cmd_base.s.cmd_id = STOP_ALL_SENSORS;
|
||||
cmd_base.s.period = 0;
|
||||
cmd_base.s.sensor_id = 0;
|
||||
|
||||
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
|
||||
}
|
||||
|
||||
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
|
||||
{
|
||||
int activestatus, num_of_sensors = 0;
|
||||
|
||||
privdata->activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3);
|
||||
activestatus = privdata->activecontrolstatus >> 4;
|
||||
if (ACEL_EN & activestatus)
|
||||
sensor_id[num_of_sensors++] = accel_idx;
|
||||
|
||||
if (GYRO_EN & activestatus)
|
||||
sensor_id[num_of_sensors++] = gyro_idx;
|
||||
|
||||
if (MAGNO_EN & activestatus)
|
||||
sensor_id[num_of_sensors++] = mag_idx;
|
||||
|
||||
if (ALS_EN & activestatus)
|
||||
sensor_id[num_of_sensors++] = als_idx;
|
||||
|
||||
return num_of_sensors;
|
||||
}
|
||||
|
||||
static void amd_mp2_pci_remove(void *privdata)
|
||||
{
|
||||
amd_sfh_hid_client_deinit(privdata);
|
||||
amd_stop_all_sensors(privdata);
|
||||
}
|
||||
|
||||
static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct amd_mp2_dev *privdata;
|
||||
int rc;
|
||||
|
||||
privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
|
||||
if (!privdata)
|
||||
return -ENOMEM;
|
||||
|
||||
privdata->pdev = pdev;
|
||||
pci_set_drvdata(pdev, privdata);
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
privdata->mmio = pcim_iomap_table(pdev)[2];
|
||||
pci_set_master(pdev);
|
||||
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
|
||||
if (rc) {
|
||||
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
return rc;
|
||||
}
|
||||
rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return amd_sfh_hid_client_init(privdata);
|
||||
}
|
||||
|
||||
static const struct pci_device_id amd_mp2_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
|
||||
|
||||
static struct pci_driver amd_mp2_pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = amd_mp2_pci_tbl,
|
||||
.probe = amd_mp2_pci_probe,
|
||||
};
|
||||
module_pci_driver(amd_mp2_pci_driver);
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
|
||||
MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");
|
79
drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
Normal file
79
drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* AMD MP2 PCIe communication driver
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
* Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
|
||||
* Sandeep Singh <Sandeep.singh@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef PCIE_MP2_AMD_H
|
||||
#define PCIE_MP2_AMD_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define PCI_DEVICE_ID_AMD_MP2 0x15E4
|
||||
|
||||
#define ENABLE_SENSOR 1
|
||||
#define DISABLE_SENSOR 2
|
||||
#define STOP_ALL_SENSORS 8
|
||||
|
||||
/* MP2 C2P Message Registers */
|
||||
#define AMD_C2P_MSG0 0x10500
|
||||
#define AMD_C2P_MSG1 0x10504
|
||||
#define AMD_C2P_MSG2 0x10508
|
||||
|
||||
/* MP2 P2C Message Registers */
|
||||
#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */
|
||||
|
||||
/* SFH Command register */
|
||||
union sfh_cmd_base {
|
||||
u32 ul;
|
||||
struct {
|
||||
u32 cmd_id : 8;
|
||||
u32 sensor_id : 8;
|
||||
u32 period : 16;
|
||||
} s;
|
||||
};
|
||||
|
||||
union sfh_cmd_param {
|
||||
u32 ul;
|
||||
struct {
|
||||
u32 buf_layout : 2;
|
||||
u32 buf_length : 6;
|
||||
u32 rsvd : 24;
|
||||
} s;
|
||||
};
|
||||
|
||||
struct sfh_cmd_reg {
|
||||
union sfh_cmd_base cmd_base;
|
||||
union sfh_cmd_param cmd_param;
|
||||
phys_addr_t phys_addr;
|
||||
};
|
||||
|
||||
enum sensor_idx {
|
||||
accel_idx = 0,
|
||||
gyro_idx = 1,
|
||||
mag_idx = 2,
|
||||
als_idx = 19
|
||||
};
|
||||
|
||||
struct amd_mp2_dev {
|
||||
struct pci_dev *pdev;
|
||||
struct amdtp_cl_data *cl_data;
|
||||
void __iomem *mmio;
|
||||
u32 activecontrolstatus;
|
||||
};
|
||||
|
||||
struct amd_mp2_sensor_info {
|
||||
u8 sensor_idx;
|
||||
u32 period;
|
||||
phys_addr_t phys_address;
|
||||
};
|
||||
|
||||
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
|
||||
void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx);
|
||||
void amd_stop_all_sensors(struct amd_mp2_dev *privdata);
|
||||
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id);
|
||||
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata);
|
||||
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);
|
||||
#endif
|
224
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
Normal file
224
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
Normal file
@ -0,0 +1,224 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* AMD SFH Report Descriptor generator
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
* Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com>
|
||||
* Sandeep Singh <sandeep.singh@amd.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include "amd_sfh_pcie.h"
|
||||
#include "amd_sfh_hid_desc.h"
|
||||
#include "amd_sfh_hid_report_desc.h"
|
||||
|
||||
#define AMD_SFH_FW_MULTIPLIER (1000)
|
||||
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51
|
||||
#define HID_DEFAULT_REPORT_INTERVAL 0x50
|
||||
#define HID_DEFAULT_MIN_VALUE 0X7F
|
||||
#define HID_DEFAULT_MAX_VALUE 0x80
|
||||
#define HID_DEFAULT_SENSITIVITY 0x7F
|
||||
#define HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM 0x01
|
||||
/* state enums */
|
||||
#define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02
|
||||
#define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05
|
||||
#define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04
|
||||
|
||||
int get_report_descriptor(int sensor_idx, u8 *rep_desc)
|
||||
{
|
||||
switch (sensor_idx) {
|
||||
case accel_idx: /* accel */
|
||||
memset(rep_desc, 0, sizeof(accel3_report_descriptor));
|
||||
memcpy(rep_desc, accel3_report_descriptor,
|
||||
sizeof(accel3_report_descriptor));
|
||||
break;
|
||||
case gyro_idx: /* gyro */
|
||||
memset(rep_desc, 0, sizeof(gyro3_report_descriptor));
|
||||
memcpy(rep_desc, gyro3_report_descriptor,
|
||||
sizeof(gyro3_report_descriptor));
|
||||
break;
|
||||
case mag_idx: /* Magnetometer */
|
||||
memset(rep_desc, 0, sizeof(comp3_report_descriptor));
|
||||
memcpy(rep_desc, comp3_report_descriptor,
|
||||
sizeof(comp3_report_descriptor));
|
||||
break;
|
||||
case als_idx: /* ambient light sensor */
|
||||
memset(rep_desc, 0, sizeof(als_report_descriptor));
|
||||
memcpy(rep_desc, als_report_descriptor,
|
||||
sizeof(als_report_descriptor));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 get_descr_sz(int sensor_idx, int descriptor_name)
|
||||
{
|
||||
switch (sensor_idx) {
|
||||
case accel_idx:
|
||||
switch (descriptor_name) {
|
||||
case descr_size:
|
||||
return sizeof(accel3_report_descriptor);
|
||||
case input_size:
|
||||
return sizeof(struct accel3_input_report);
|
||||
case feature_size:
|
||||
return sizeof(struct accel3_feature_report);
|
||||
}
|
||||
break;
|
||||
case gyro_idx:
|
||||
switch (descriptor_name) {
|
||||
case descr_size:
|
||||
return sizeof(gyro3_report_descriptor);
|
||||
case input_size:
|
||||
return sizeof(struct gyro_input_report);
|
||||
case feature_size:
|
||||
return sizeof(struct gyro_feature_report);
|
||||
}
|
||||
break;
|
||||
case mag_idx:
|
||||
switch (descriptor_name) {
|
||||
case descr_size:
|
||||
return sizeof(comp3_report_descriptor);
|
||||
case input_size:
|
||||
return sizeof(struct magno_input_report);
|
||||
case feature_size:
|
||||
return sizeof(struct magno_feature_report);
|
||||
}
|
||||
break;
|
||||
case als_idx:
|
||||
switch (descriptor_name) {
|
||||
case descr_size:
|
||||
return sizeof(als_report_descriptor);
|
||||
case input_size:
|
||||
return sizeof(struct als_input_report);
|
||||
case feature_size:
|
||||
return sizeof(struct als_feature_report);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_common_features(struct common_feature_property *common, int report_id)
|
||||
{
|
||||
common->report_id = report_id;
|
||||
common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM;
|
||||
common->report_state = HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
|
||||
common->power_state = HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
|
||||
common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM;
|
||||
common->report_interval = HID_DEFAULT_REPORT_INTERVAL;
|
||||
}
|
||||
|
||||
u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
|
||||
{
|
||||
struct accel3_feature_report acc_feature;
|
||||
struct gyro_feature_report gyro_feature;
|
||||
struct magno_feature_report magno_feature;
|
||||
struct als_feature_report als_feature;
|
||||
u8 report_size = 0;
|
||||
|
||||
if (!feature_report)
|
||||
return report_size;
|
||||
|
||||
switch (sensor_idx) {
|
||||
case accel_idx: /* accel */
|
||||
get_common_features(&acc_feature.common_property, report_id);
|
||||
acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
|
||||
acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE;
|
||||
acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE;
|
||||
memcpy(feature_report, &acc_feature, sizeof(acc_feature));
|
||||
report_size = sizeof(acc_feature);
|
||||
break;
|
||||
case gyro_idx: /* gyro */
|
||||
get_common_features(&gyro_feature.common_property, report_id);
|
||||
gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
|
||||
gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE;
|
||||
gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE;
|
||||
memcpy(feature_report, &gyro_feature, sizeof(gyro_feature));
|
||||
report_size = sizeof(gyro_feature);
|
||||
break;
|
||||
case mag_idx: /* Magnetometer */
|
||||
get_common_features(&magno_feature.common_property, report_id);
|
||||
magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY;
|
||||
magno_feature.heading_min = HID_DEFAULT_MIN_VALUE;
|
||||
magno_feature.heading_max = HID_DEFAULT_MAX_VALUE;
|
||||
magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE;
|
||||
magno_feature.flux_min = HID_DEFAULT_MIN_VALUE;
|
||||
magno_feature.flux_max = HID_DEFAULT_MAX_VALUE;
|
||||
memcpy(feature_report, &magno_feature, sizeof(magno_feature));
|
||||
report_size = sizeof(magno_feature);
|
||||
break;
|
||||
case als_idx: /* ambient light sensor */
|
||||
get_common_features(&als_feature.common_property, report_id);
|
||||
als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY;
|
||||
als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE;
|
||||
als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE;
|
||||
memcpy(feature_report, &als_feature, sizeof(als_feature));
|
||||
report_size = sizeof(als_feature);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return report_size;
|
||||
}
|
||||
|
||||
static void get_common_inputs(struct common_input_property *common, int report_id)
|
||||
{
|
||||
common->report_id = report_id;
|
||||
common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM;
|
||||
common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
|
||||
}
|
||||
|
||||
u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr)
|
||||
{
|
||||
struct accel3_input_report acc_input;
|
||||
struct gyro_input_report gyro_input;
|
||||
struct magno_input_report magno_input;
|
||||
struct als_input_report als_input;
|
||||
u8 report_size = 0;
|
||||
|
||||
if (!sensor_virt_addr || !input_report)
|
||||
return report_size;
|
||||
|
||||
switch (sensor_idx) {
|
||||
case accel_idx: /* accel */
|
||||
get_common_inputs(&acc_input.common_property, report_id);
|
||||
acc_input.in_accel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
|
||||
acc_input.in_accel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER;
|
||||
acc_input.in_accel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER;
|
||||
memcpy(input_report, &acc_input, sizeof(acc_input));
|
||||
report_size = sizeof(acc_input);
|
||||
break;
|
||||
case gyro_idx: /* gyro */
|
||||
get_common_inputs(&gyro_input.common_property, report_id);
|
||||
gyro_input.in_angel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
|
||||
gyro_input.in_angel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER;
|
||||
gyro_input.in_angel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER;
|
||||
memcpy(input_report, &gyro_input, sizeof(gyro_input));
|
||||
report_size = sizeof(gyro_input);
|
||||
break;
|
||||
case mag_idx: /* Magnetometer */
|
||||
get_common_inputs(&magno_input.common_property, report_id);
|
||||
magno_input.in_magno_x = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
|
||||
magno_input.in_magno_y = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER;
|
||||
magno_input.in_magno_z = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER;
|
||||
magno_input.in_magno_accuracy = (u16)sensor_virt_addr[3] / AMD_SFH_FW_MULTIPLIER;
|
||||
memcpy(input_report, &magno_input, sizeof(magno_input));
|
||||
report_size = sizeof(magno_input);
|
||||
break;
|
||||
case als_idx: /* Als */
|
||||
get_common_inputs(&als_input.common_property, report_id);
|
||||
als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
|
||||
report_size = sizeof(als_input);
|
||||
memcpy(input_report, &als_input, sizeof(als_input));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return report_size;
|
||||
}
|
107
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
Normal file
107
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
Normal file
@ -0,0 +1,107 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* HID report descriptors, structures and routines
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
* Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
|
||||
* Sandeep Singh <Sandeep.singh@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef AMD_SFH_HID_DESCRIPTOR_H
|
||||
#define AMD_SFH_HID_DESCRIPTOR_H
|
||||
|
||||
enum desc_type {
|
||||
/* Report descriptor name */
|
||||
descr_size = 1,
|
||||
input_size,
|
||||
feature_size,
|
||||
};
|
||||
|
||||
struct common_feature_property {
|
||||
/* common properties */
|
||||
u8 report_id;
|
||||
u8 connection_type;
|
||||
u8 report_state;
|
||||
u8 power_state;
|
||||
u8 sensor_state;
|
||||
u32 report_interval;
|
||||
} __packed;
|
||||
|
||||
struct common_input_property {
|
||||
/* common properties */
|
||||
u8 report_id;
|
||||
u8 sensor_state;
|
||||
u8 event_type;
|
||||
} __packed;
|
||||
|
||||
struct accel3_feature_report {
|
||||
struct common_feature_property common_property;
|
||||
/* properties specific to this sensor */
|
||||
u16 accel_change_sesnitivity;
|
||||
s16 accel_sensitivity_max;
|
||||
s16 accel_sensitivity_min;
|
||||
} __packed;
|
||||
|
||||
struct accel3_input_report {
|
||||
struct common_input_property common_property;
|
||||
/* values specific to this sensor */
|
||||
int in_accel_x_value;
|
||||
int in_accel_y_value;
|
||||
int in_accel_z_value;
|
||||
/* include if required to support the "shake" event */
|
||||
u8 in_accel_shake_detection;
|
||||
} __packed;
|
||||
|
||||
struct gyro_feature_report {
|
||||
struct common_feature_property common_property;
|
||||
/* properties specific to this sensor */
|
||||
u16 gyro_change_sesnitivity;
|
||||
s16 gyro_sensitivity_max;
|
||||
s16 gyro_sensitivity_min;
|
||||
} __packed;
|
||||
|
||||
struct gyro_input_report {
|
||||
struct common_input_property common_property;
|
||||
/* values specific to this sensor */
|
||||
int in_angel_x_value;
|
||||
int in_angel_y_value;
|
||||
int in_angel_z_value;
|
||||
} __packed;
|
||||
|
||||
struct magno_feature_report {
|
||||
struct common_feature_property common_property;
|
||||
/*properties specific to this sensor */
|
||||
u16 magno_headingchange_sensitivity;
|
||||
s16 heading_min;
|
||||
s16 heading_max;
|
||||
u16 flux_change_sensitivity;
|
||||
s16 flux_min;
|
||||
s16 flux_max;
|
||||
} __packed;
|
||||
|
||||
struct magno_input_report {
|
||||
struct common_input_property common_property;
|
||||
int in_magno_x;
|
||||
int in_magno_y;
|
||||
int in_magno_z;
|
||||
int in_magno_accuracy;
|
||||
} __packed;
|
||||
|
||||
struct als_feature_report {
|
||||
struct common_feature_property common_property;
|
||||
/* properties specific to this sensor */
|
||||
u16 als_change_sesnitivity;
|
||||
s16 als_sensitivity_max;
|
||||
s16 als_sensitivity_min;
|
||||
} __packed;
|
||||
|
||||
struct als_input_report {
|
||||
struct common_input_property common_property;
|
||||
/* values specific to this sensor */
|
||||
int illuminance_value;
|
||||
} __packed;
|
||||
|
||||
int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
|
||||
u32 get_descr_sz(int sensor_idx, int descriptor_name);
|
||||
u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report);
|
||||
u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr);
|
||||
#endif
|
645
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
Normal file
645
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
Normal file
@ -0,0 +1,645 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* HID descriptor stuructures
|
||||
* Copyright 2020 Advanced Micro Devices, Inc.
|
||||
* Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com>
|
||||
* Sandeep Singh <Sandeep.singh@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef AMD_SFH_HID_REPORT_DESCRIPTOR_H
|
||||
#define AMD_SFH_HID_REPORT_DESCRIPTOR_H
|
||||
|
||||
// Accelerometer 3D Sensor
|
||||
static const u8 accel3_report_descriptor[] = {
|
||||
0x05, 0x20, /* Usage page */
|
||||
0x09, 0x73, /* Motion type Accel 3D */
|
||||
0xA1, 0x00, /* HID Collection (Physical) */
|
||||
|
||||
//feature reports(xmit/receive)
|
||||
0x85, 1, /* HID Report ID */
|
||||
0x05, 0x20, /* HID usage page sensor */
|
||||
0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
|
||||
0x15, 0, /* HID logical MIN_8(0) */
|
||||
0x25, 2, /* HID logical MAX_8(2) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection (logical) */
|
||||
0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel*/
|
||||
0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
|
||||
0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x40, 0x08, /* Sensor property report state no events sel */
|
||||
0x0A, 0x41, 0x08, /* Sensor property report state all events sel */
|
||||
0x0A, 0x42, 0x08, /* Sensor property report state threshold events sel */
|
||||
0x0A, 0x43, 0x08, /* Sensor property report state no events wake sel */
|
||||
0x0A, 0x44, 0x08, /* Sensor property report state all events wake sel */
|
||||
0x0A, 0x45, 0x08, /* Sensor property report state threshold events wake sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x19, 0x03, /* HID usage sensor property power state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x50, 0x08, /* Sensor property power state undefined sel */
|
||||
0x0A, 0x51, 0x08, /* Sensor property power state D0 full power sel */
|
||||
0x0A, 0x52, 0x08, /* Sensor property power state D1 low power sel */
|
||||
0x0A, 0x53, 0x08, /* Sensor property power state D2 standby with wake sel */
|
||||
0x0A, 0x54, 0x08, /* Sensor property power state D3 sleep with wake sel */
|
||||
0x0A, 0x55, 0x08, /* Sensor property power state D4 power off sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0, /* HID unit exponent(0) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x52, 0x14, /* Sensor data motion accel and mod change sensitivity ABS) */
|
||||
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
|
||||
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x52, 0x24, /* HID usage sensor data (motion accel and mod max) */
|
||||
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x52, 0x34, /* HID usage sensor data (motion accel and mod min) */
|
||||
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
|
||||
//input report (transmit)
|
||||
0x05, 0x20, /* HID usage page sensors */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x02, 0x02, /* HID usage sensor event */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
|
||||
0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
|
||||
0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
|
||||
0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
|
||||
0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
|
||||
0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x53, 0x04, /* HID usage sensor data motion Acceleration X axis */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
|
||||
0x27, 0xFF, 0xff, 0XFF, 0XFF, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0x0A, 0x54, 0x04, /* HID usage sensor data motion Acceleration Y axis */
|
||||
0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
|
||||
0x27, 0xFF, 0xFF, 0XFF, 0XFF, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0x0A, 0x55, 0x04, /* HID usage sensor data motion Acceleration Z axis */
|
||||
0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
|
||||
0x27, 0XFF, 0XFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
|
||||
0x0A, 0x51, 0x04, /* HID usage sensor data motion state */
|
||||
0x15, 0, /* HID logical Min_8(0) False = Still*/
|
||||
0x25, 1, /* HID logical Min_8(1) True = In motion */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0 /* HID end collection */
|
||||
};
|
||||
|
||||
const u8 gyro3_report_descriptor[] = {
|
||||
0x05, 0x20, /* Usage page */
|
||||
0x09, 0x76, /* Motion type Gyro3D */
|
||||
0xA1, 0x00, /* HID Collection (Physical) */
|
||||
|
||||
0x85, 2, /* HID Report ID */
|
||||
0x05, 0x20, /* HID usage page sensor */
|
||||
0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
|
||||
0x15, 0, /* HID logical MIN_8(0) */
|
||||
0x25, 2, /* HID logical MAX_8(2) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection (logical) */
|
||||
0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */
|
||||
0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
|
||||
0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */
|
||||
0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */
|
||||
0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */
|
||||
0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */
|
||||
0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */
|
||||
0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x19, 0x03, /* HID usage sensor property power state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x50, 0x08, /* Sensor power state undefined sel */
|
||||
0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */
|
||||
0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */
|
||||
0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */
|
||||
0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */
|
||||
0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0, /* HID unit exponent(0) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x56, 0x14, /* Angular velocity and mod change sensitivity ABS)*/
|
||||
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
|
||||
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x56, 0x24, /* Sensor data (motion angular velocity and mod max) */
|
||||
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x56, 0x34, /* HID usage sensor data (motion accel and mod min) */
|
||||
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
|
||||
//Input reports(transmit)
|
||||
0x05, 0x20, /* HID usage page sensors */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x02, 0x02, /* HID usage sensor event */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
|
||||
0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
|
||||
0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
|
||||
0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
|
||||
0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
|
||||
0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x57, 0x04, /* Sensor data motion Angular velocity X axis */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0x0A, 0x58, 0x04, /* Sensor data motion Angular velocity Y axis */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0x0A, 0x59, 0x04, /* Sensor data motion Angular velocity Z axis */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
|
||||
0xC0, /* HID end collection */
|
||||
};
|
||||
|
||||
const u8 comp3_report_descriptor[] = {
|
||||
0x05, 0x20, /* Usage page */
|
||||
0x09, 0x83, /* Motion type Orientation compass 3D */
|
||||
0xA1, 0x00, /* HID Collection (Physical) */
|
||||
|
||||
0x85, 3, /* HID Report ID */
|
||||
0x05, 0x20, /* HID usage page sensor */
|
||||
0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
|
||||
0x15, 0, /* HID logical MIN_8(0) */
|
||||
0x25, 2, /* HID logical MAX_8(2) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection (logical) */
|
||||
0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */
|
||||
0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
|
||||
0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */
|
||||
0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */
|
||||
0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */
|
||||
0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */
|
||||
0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */
|
||||
0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x19, 0x03, /* HID usage sensor property power state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x50, 0x08, /* Sensor power state undefined sel */
|
||||
0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */
|
||||
0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */
|
||||
0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */
|
||||
0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */
|
||||
0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0, /* HID unit exponent(0) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x71, 0x14, /* Orientation and mod change sensitivity ABS)*/
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x71, 0x24, /* Sensor data (motion orientation and mod max) */
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0F, /* HID unit exponent(0x0F) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x71, 0x34, /* Sensor data (motion orientation and mod min) */
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0F, /* HID unit exponent(0x0F) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x84, 0x14, /* Maganetic flux and change sensitivity ABS) */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x84, 0x24, /* Maganetic flux and mod change sensitivity Max) */
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0F, /* HID unit exponent(0x0F) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0x84, 0x34, /* Maganetic flux and mod change sensitivity Min */
|
||||
0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */
|
||||
0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0F, /* HID unit exponent(0x0F) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
|
||||
//Input reports(transmit)
|
||||
0x05, 0x20, /* HID usage page sensors */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x02, 0x02, /* HID usage sensor event */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
|
||||
0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
|
||||
0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
|
||||
0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
|
||||
0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
|
||||
0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x85, 0x04, /* Sensor data orientation magnetic flux X axis */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0D, /* HID unit exponent(0x0D) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0x0A, 0x86, 0x04, /* Sensor data orientation magnetic flux Y axis */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0D, /* HID unit exponent(0x0D) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0x0A, 0x87, 0x04, /* Sensor data orientation magnetic flux Z axis */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0x55, 0x0D, /* HID unit exponent(0x0D) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0x0A, 0x88, 0x04, /* Sensor data orientation magnetometer accuracy */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0 /* HID end collection */
|
||||
};
|
||||
|
||||
const u8 als_report_descriptor[] = {
|
||||
0x05, 0x20, /* HID usage page sensor */
|
||||
0x09, 0x41, /* HID usage sensor type Ambientlight */
|
||||
0xA1, 0x00, /* HID Collection (Physical) */
|
||||
|
||||
//feature reports(xmit/receive)//
|
||||
0x85, 4, /* HID Report ID */
|
||||
0x05, 0x20, /* HID usage page sensor */
|
||||
0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
|
||||
0x15, 0, /* HID logical MIN_8(0) */
|
||||
0x25, 2, /* HID logical MAX_8(2) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection (logical) */
|
||||
0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */
|
||||
0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
|
||||
0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */
|
||||
0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */
|
||||
0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */
|
||||
0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */
|
||||
0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */
|
||||
0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x19, 0x03, /* HID usage sensor property power state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x50, 0x08, /* Sensor power state undefined sel */
|
||||
0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */
|
||||
0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */
|
||||
0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */
|
||||
0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */
|
||||
0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0xA1, 0x02, /* HID collection(logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0, /* HID unit exponent(0) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0xD1, 0xE4, /* Light illuminance and sensitivity REL PCT) */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x26, 0x10, 0x27, /* HID logical Max_16(0x10,0x27) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0E, /* HID unit exponent(0x0E) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0xD1, 0x24, /* Sensor data (Light illuminance and mod max) */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0F, /* HID unit exponent(0x0F) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
0x0A, 0xD1, 0x34, /* Sensor data (Light illuminance and mod min) */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */
|
||||
0x75, 16, /* HID report size(16) */
|
||||
0x95, 1, /* HID report count(1) */
|
||||
0x55, 0x0F, /* HID unit exponent(0x0F) */
|
||||
0xB1, 0x02, /* HID feature (Data_Arr_Abs) */
|
||||
|
||||
//Input reports (transmit)
|
||||
0x05, 0x20, /* HID usage page sensors */
|
||||
0x0A, 0x01, 0x02, /* HID usage sensor state */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 6, /* HID logical Max_8(6) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
|
||||
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
|
||||
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
|
||||
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
|
||||
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
|
||||
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
|
||||
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0x02, 0x02, /* HID usage sensor event */
|
||||
0x15, 0, /* HID logical Min_8(0) */
|
||||
0x25, 5, /* HID logical Max_8(5) */
|
||||
0x75, 8, /* HID report size(8) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0xA1, 0x02, /* HID end collection (logical) */
|
||||
0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
|
||||
0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
|
||||
0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
|
||||
0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
|
||||
0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
|
||||
0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
|
||||
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0, /* HID end collection */
|
||||
0x0A, 0xD1, 0x04, /* HID usage sensor data light illuminance */
|
||||
0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */
|
||||
0x55, 0x0F, /* HID unit exponent(0x0F) */
|
||||
0x75, 32, /* HID report size(32) */
|
||||
0x95, 1, /* HID report count (1) */
|
||||
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
|
||||
0xC0 /* HID end collection */
|
||||
};
|
||||
#endif
|
@ -48,6 +48,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define INPUT_REPORT_ID 0x5d
|
||||
#define FEATURE_KBD_REPORT_ID 0x5a
|
||||
#define FEATURE_KBD_REPORT_SIZE 16
|
||||
#define FEATURE_KBD_LED_REPORT_ID1 0x5d
|
||||
#define FEATURE_KBD_LED_REPORT_ID2 0x5e
|
||||
|
||||
#define SUPPORT_KBD_BACKLIGHT BIT(0)
|
||||
|
||||
@ -80,6 +82,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define QUIRK_T101HA_DOCK BIT(9)
|
||||
#define QUIRK_T90CHI BIT(10)
|
||||
#define QUIRK_MEDION_E1239T BIT(11)
|
||||
#define QUIRK_ROG_NKEY_KEYBOARD BIT(12)
|
||||
|
||||
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
|
||||
QUIRK_NO_INIT_REPORTS | \
|
||||
@ -332,6 +335,28 @@ static int asus_raw_event(struct hid_device *hdev,
|
||||
if (drvdata->quirks & QUIRK_MEDION_E1239T)
|
||||
return asus_e1239t_event(drvdata, data, size);
|
||||
|
||||
if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
||||
/*
|
||||
* Skip these report ID, the device emits a continuous stream associated
|
||||
* with the AURA mode it is in which looks like an 'echo'.
|
||||
*/
|
||||
if (report->id == FEATURE_KBD_LED_REPORT_ID1 ||
|
||||
report->id == FEATURE_KBD_LED_REPORT_ID2) {
|
||||
return -1;
|
||||
/* Additional report filtering */
|
||||
} else if (report->id == FEATURE_KBD_REPORT_ID) {
|
||||
/*
|
||||
* G14 and G15 send these codes on some keypresses with no
|
||||
* discernable reason for doing so. We'll filter them out to avoid
|
||||
* unmapped warning messages later.
|
||||
*/
|
||||
if (data[1] == 0xea || data[1] == 0xec || data[1] == 0x02 ||
|
||||
data[1] == 0x8a || data[1] == 0x9e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -344,7 +369,11 @@ static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size
|
||||
if (!dmabuf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf,
|
||||
/*
|
||||
* The report ID should be set from the incoming buffer due to LED and key
|
||||
* interfaces having different pages
|
||||
*/
|
||||
ret = hid_hw_raw_request(hdev, buf[0], dmabuf,
|
||||
buf_size, HID_FEATURE_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
kfree(dmabuf);
|
||||
@ -397,6 +426,51 @@ static int asus_kbd_get_functions(struct hid_device *hdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rog_nkey_led_init(struct hid_device *hdev)
|
||||
{
|
||||
u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 };
|
||||
u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20,
|
||||
0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
|
||||
u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1,
|
||||
0x05, 0x20, 0x31, 0x00, 0x08 };
|
||||
int ret;
|
||||
|
||||
hid_info(hdev, "Asus initialise N-KEY Device");
|
||||
/* The first message is an init start */
|
||||
ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start));
|
||||
if (ret < 0) {
|
||||
hid_warn(hdev, "Asus failed to send init start command: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/* Followed by a string */
|
||||
ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
|
||||
if (ret < 0) {
|
||||
hid_warn(hdev, "Asus failed to send init command 1.0: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/* Followed by a string */
|
||||
ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
|
||||
if (ret < 0) {
|
||||
hid_warn(hdev, "Asus failed to send init command 1.1: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* begin second report ID with same data */
|
||||
buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2;
|
||||
buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2;
|
||||
|
||||
ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
|
||||
if (ret < 0) {
|
||||
hid_warn(hdev, "Asus failed to send init command 2.0: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
|
||||
if (ret < 0)
|
||||
hid_warn(hdev, "Asus failed to send init command 2.1: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
@ -460,19 +534,25 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
|
||||
unsigned char kbd_func;
|
||||
int ret;
|
||||
|
||||
/* Initialize keyboard */
|
||||
ret = asus_kbd_init(hdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
||||
ret = rog_nkey_led_init(hdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
/* Initialize keyboard */
|
||||
ret = asus_kbd_init(hdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Get keyboard functions */
|
||||
ret = asus_kbd_get_functions(hdev, &kbd_func);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Get keyboard functions */
|
||||
ret = asus_kbd_get_functions(hdev, &kbd_func);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Check for backlight support */
|
||||
if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
|
||||
return -ENODEV;
|
||||
/* Check for backlight support */
|
||||
if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
|
||||
sizeof(struct asus_kbd_leds),
|
||||
@ -751,8 +831,8 @@ static int asus_input_mapping(struct hid_device *hdev,
|
||||
usage->hid == (HID_UP_GENDEVCTRLS | 0x0026)))
|
||||
return -1;
|
||||
|
||||
/* ASUS-specific keyboard hotkeys */
|
||||
if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
|
||||
/* ASUS-specific keyboard hotkeys and led backlight */
|
||||
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) {
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
|
||||
case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
|
||||
@ -780,6 +860,18 @@ static int asus_input_mapping(struct hid_device *hdev,
|
||||
/* Fn+F5 "fan" symbol on FX503VD */
|
||||
case 0x99: asus_map_key_clear(KEY_PROG4); break;
|
||||
|
||||
/* Fn+F5 "fan" symbol on N-Key keyboard */
|
||||
case 0xae: asus_map_key_clear(KEY_PROG4); break;
|
||||
|
||||
/* Fn+Ret "Calc" symbol on N-Key keyboard */
|
||||
case 0x92: asus_map_key_clear(KEY_CALC); break;
|
||||
|
||||
/* Fn+Left Aura mode previous on N-Key keyboard */
|
||||
case 0xb2: asus_map_key_clear(KEY_PROG2); break;
|
||||
|
||||
/* Fn+Right Aura mode next on N-Key keyboard */
|
||||
case 0xb3: asus_map_key_clear(KEY_PROG3); break;
|
||||
|
||||
default:
|
||||
/* ASUS lazily declares 256 usages, ignore the rest,
|
||||
* as some make the keyboard appear as a pointer device. */
|
||||
@ -1126,6 +1218,9 @@ static const struct hid_device_id asus_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD),
|
||||
QUIRK_USE_KBD_BACKLIGHT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD),
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
|
||||
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
|
||||
|
@ -11,6 +11,7 @@
|
||||
* Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu>
|
||||
* Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org>
|
||||
* Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com>
|
||||
* Copyright (c) 2020 YOSHIOKA Takuma <lo48576@hard-wi.red>
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -29,25 +30,26 @@
|
||||
* report descriptor but it does not appear that these enable software to
|
||||
* control what the extra buttons map to. The only simple and straightforward
|
||||
* solution seems to involve fixing up the report descriptor.
|
||||
*
|
||||
* Report descriptor format:
|
||||
* Positions 13, 15, 21 and 31 store the button bit count, button usage minimum,
|
||||
* button usage maximum and padding bit count respectively.
|
||||
*/
|
||||
#define MOUSE_BUTTONS_MAX 8
|
||||
static void mouse_button_fixup(struct hid_device *hdev,
|
||||
__u8 *rdesc, unsigned int rsize,
|
||||
unsigned int button_bit_count,
|
||||
unsigned int padding_bit,
|
||||
unsigned int button_report_size,
|
||||
unsigned int button_usage_maximum,
|
||||
int nbuttons)
|
||||
{
|
||||
if (rsize < 32 || rdesc[12] != 0x95 ||
|
||||
rdesc[14] != 0x75 || rdesc[15] != 0x01 ||
|
||||
rdesc[20] != 0x29 || rdesc[30] != 0x75)
|
||||
if (rsize < 32 || rdesc[button_bit_count] != 0x95 ||
|
||||
rdesc[button_report_size] != 0x75 ||
|
||||
rdesc[button_report_size + 1] != 0x01 ||
|
||||
rdesc[button_usage_maximum] != 0x29 || rdesc[padding_bit] != 0x75)
|
||||
return;
|
||||
hid_info(hdev, "Fixing up Elecom mouse button count\n");
|
||||
nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX);
|
||||
rdesc[13] = nbuttons;
|
||||
rdesc[21] = nbuttons;
|
||||
rdesc[31] = MOUSE_BUTTONS_MAX - nbuttons;
|
||||
rdesc[button_bit_count + 1] = nbuttons;
|
||||
rdesc[button_usage_maximum + 1] = nbuttons;
|
||||
rdesc[padding_bit + 1] = MOUSE_BUTTONS_MAX - nbuttons;
|
||||
}
|
||||
|
||||
static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
@ -62,16 +64,40 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
rdesc[47] = 0x00;
|
||||
}
|
||||
break;
|
||||
case USB_DEVICE_ID_ELECOM_M_XGL20DLBK:
|
||||
/*
|
||||
* Report descriptor format:
|
||||
* 20: button bit count
|
||||
* 28: padding bit count
|
||||
* 22: button report size
|
||||
* 14: button usage maximum
|
||||
*/
|
||||
mouse_button_fixup(hdev, rdesc, *rsize, 20, 28, 22, 14, 8);
|
||||
break;
|
||||
case USB_DEVICE_ID_ELECOM_M_XT3URBK:
|
||||
case USB_DEVICE_ID_ELECOM_M_XT3DRBK:
|
||||
case USB_DEVICE_ID_ELECOM_M_XT4DRBK:
|
||||
mouse_button_fixup(hdev, rdesc, *rsize, 6);
|
||||
/*
|
||||
* Report descriptor format:
|
||||
* 12: button bit count
|
||||
* 30: padding bit count
|
||||
* 14: button report size
|
||||
* 20: button usage maximum
|
||||
*/
|
||||
mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 6);
|
||||
break;
|
||||
case USB_DEVICE_ID_ELECOM_M_DT1URBK:
|
||||
case USB_DEVICE_ID_ELECOM_M_DT1DRBK:
|
||||
case USB_DEVICE_ID_ELECOM_M_HT1URBK:
|
||||
case USB_DEVICE_ID_ELECOM_M_HT1DRBK:
|
||||
mouse_button_fixup(hdev, rdesc, *rsize, 8);
|
||||
/*
|
||||
* Report descriptor format:
|
||||
* 12: button bit count
|
||||
* 30: padding bit count
|
||||
* 14: button report size
|
||||
* 20: button usage maximum
|
||||
*/
|
||||
mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8);
|
||||
break;
|
||||
}
|
||||
return rdesc;
|
||||
@ -79,6 +105,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
|
||||
static const struct hid_device_id elecom_devices[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) },
|
||||
|
@ -190,6 +190,7 @@
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866
|
||||
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
|
||||
|
||||
#define USB_VENDOR_ID_ATEN 0x0557
|
||||
@ -359,6 +360,7 @@
|
||||
#define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803
|
||||
#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1 0x1843
|
||||
#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2 0x1844
|
||||
#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE3 0x1846
|
||||
|
||||
#define USB_VENDOR_ID_DWAV 0x0eef
|
||||
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
|
||||
@ -390,6 +392,7 @@
|
||||
|
||||
#define USB_VENDOR_ID_ELECOM 0x056e
|
||||
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
|
||||
#define USB_DEVICE_ID_ELECOM_M_XGL20DLBK 0x00e6
|
||||
#define USB_DEVICE_ID_ELECOM_M_XT3URBK 0x00fb
|
||||
#define USB_DEVICE_ID_ELECOM_M_XT3DRBK 0x00fc
|
||||
#define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd
|
||||
@ -1074,6 +1077,9 @@
|
||||
#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
|
||||
#define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000
|
||||
|
||||
#define USB_VENDOR_ID_SONY_GHLIVE 0x12ba
|
||||
#define USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE 0x074b
|
||||
|
||||
#define USB_VENDOR_ID_SINO_LITE 0x1345
|
||||
#define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008
|
||||
|
||||
@ -1133,6 +1139,7 @@
|
||||
#define USB_DEVICE_ID_SYNAPTICS_DELL_K12A 0x2819
|
||||
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968
|
||||
#define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710
|
||||
#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002 0x73f4
|
||||
#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003 0x73f5
|
||||
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7
|
||||
|
||||
|
@ -537,9 +537,12 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
|
||||
capacity = hidinput_scale_battery_capacity(dev, value);
|
||||
|
||||
if (dev->battery_status != HID_BATTERY_REPORTED ||
|
||||
capacity != dev->battery_capacity) {
|
||||
capacity != dev->battery_capacity ||
|
||||
ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) {
|
||||
dev->battery_capacity = capacity;
|
||||
dev->battery_status = HID_BATTERY_REPORTED;
|
||||
dev->battery_ratelimit_time =
|
||||
ktime_add_ms(ktime_get_coarse(), 30 * 1000);
|
||||
power_supply_changed(dev->battery);
|
||||
}
|
||||
}
|
||||
@ -746,6 +749,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
field->flags |= HID_MAIN_ITEM_RELATIVE;
|
||||
break;
|
||||
}
|
||||
goto unknown;
|
||||
|
||||
default: goto unknown;
|
||||
}
|
||||
|
@ -18,10 +18,16 @@ static __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
|
||||
if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) {
|
||||
/* For Acer Aspire Switch 10 SW5-012 keyboard-dock */
|
||||
if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) {
|
||||
hid_info(hdev, "Fixing up ITE keyboard report descriptor\n");
|
||||
hid_info(hdev, "Fixing up Acer Sw5-012 ITE keyboard report descriptor\n");
|
||||
rdesc[163] = HID_MAIN_ITEM_RELATIVE;
|
||||
}
|
||||
/* For Acer One S1002 keyboard-dock */
|
||||
if (*rsize == 188 && rdesc[185] == 0x81 && rdesc[186] == 0x02) {
|
||||
hid_info(hdev, "Fixing up Acer S1002 ITE keyboard report descriptor\n");
|
||||
rdesc[186] = HID_MAIN_ITEM_RELATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
return rdesc;
|
||||
@ -101,6 +107,11 @@ static const struct hid_device_id ite_devices[] = {
|
||||
USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012),
|
||||
.driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
|
||||
/* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_SYNAPTICS,
|
||||
USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002),
|
||||
.driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT },
|
||||
/* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_SYNAPTICS,
|
||||
USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003) },
|
||||
|
@ -4048,6 +4048,8 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||
{ /* MX5500 keyboard over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b),
|
||||
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
|
||||
{ /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) },
|
||||
{ /* MX Master mouse over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012),
|
||||
.driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
|
@ -153,6 +153,8 @@ static const struct hid_device_id mf_devices[] = {
|
||||
.driver_data = HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2),
|
||||
.driver_data = 0 }, /* No quirk required */
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3),
|
||||
.driver_data = HID_QUIRK_MULTI_INPUT },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, mf_devices);
|
||||
|
@ -72,6 +72,7 @@ static const struct hid_device_id hid_quirks[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
|
||||
@ -366,6 +367,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_HID_ELECOM)
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) },
|
||||
@ -484,6 +486,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3) },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_HID_MICROSOFT)
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
|
||||
|
@ -11,6 +11,7 @@
|
||||
* Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
|
||||
* Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com>
|
||||
* Copyright (c) 2018 Todd Kelner
|
||||
* Copyright (c) 2020 Pascal Giard <pascal.giard@etsmtl.ca>
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -35,6 +36,8 @@
|
||||
#include <linux/idr.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
@ -56,6 +59,7 @@
|
||||
#define NSG_MR5U_REMOTE_BT BIT(14)
|
||||
#define NSG_MR7U_REMOTE_BT BIT(15)
|
||||
#define SHANWAN_GAMEPAD BIT(16)
|
||||
#define GHL_GUITAR_PS3WIIU BIT(17)
|
||||
|
||||
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
|
||||
#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
|
||||
@ -79,6 +83,17 @@
|
||||
#define NSG_MRXU_MAX_X 1667
|
||||
#define NSG_MRXU_MAX_Y 1868
|
||||
|
||||
#define GHL_GUITAR_POKE_INTERVAL 10 /* In seconds */
|
||||
#define GHL_GUITAR_TILT_USAGE 44
|
||||
|
||||
/* Magic value and data taken from GHLtarUtility:
|
||||
* https://github.com/ghlre/GHLtarUtility/blob/master/PS3Guitar.cs
|
||||
* Note: The Wii U and PS3 dongles happen to share the same!
|
||||
*/
|
||||
static const u16 ghl_ps3wiiu_magic_value = 0x201;
|
||||
static const char ghl_ps3wiiu_magic_data[] = {
|
||||
0x02, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* PS/3 Motion controller */
|
||||
static u8 motion_rdesc[] = {
|
||||
@ -550,7 +565,9 @@ struct sony_sc {
|
||||
struct power_supply_desc battery_desc;
|
||||
int device_id;
|
||||
unsigned fw_version;
|
||||
bool fw_version_created;
|
||||
unsigned hw_version;
|
||||
bool hw_version_created;
|
||||
u8 *output_report_dmabuf;
|
||||
|
||||
#ifdef CONFIG_SONY_FF
|
||||
@ -562,9 +579,8 @@ struct sony_sc {
|
||||
u8 hotplug_worker_initialized;
|
||||
u8 state_worker_initialized;
|
||||
u8 defer_initialization;
|
||||
u8 cable_state;
|
||||
u8 battery_charging;
|
||||
u8 battery_capacity;
|
||||
int battery_status;
|
||||
u8 led_state[MAX_LEDS];
|
||||
u8 led_delay_on[MAX_LEDS];
|
||||
u8 led_delay_off[MAX_LEDS];
|
||||
@ -578,6 +594,10 @@ struct sony_sc {
|
||||
enum ds4_dongle_state ds4_dongle_state;
|
||||
/* DS4 calibration data */
|
||||
struct ds4_calibration_data ds4_calib_data[6];
|
||||
/* GH Live */
|
||||
struct timer_list ghl_poke_timer;
|
||||
struct usb_ctrlrequest *ghl_cr;
|
||||
u8 *ghl_databuf;
|
||||
};
|
||||
|
||||
static void sony_set_leds(struct sony_sc *sc);
|
||||
@ -601,6 +621,85 @@ static inline void sony_schedule_work(struct sony_sc *sc,
|
||||
}
|
||||
}
|
||||
|
||||
static void ghl_magic_poke_cb(struct urb *urb)
|
||||
{
|
||||
if (urb) {
|
||||
/* Free sc->ghl_cr and sc->ghl_databuf allocated in
|
||||
* ghl_magic_poke()
|
||||
*/
|
||||
kfree(urb->setup_packet);
|
||||
kfree(urb->transfer_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void ghl_magic_poke(struct timer_list *t)
|
||||
{
|
||||
struct sony_sc *sc = from_timer(sc, t, ghl_poke_timer);
|
||||
|
||||
int ret;
|
||||
unsigned int pipe;
|
||||
struct urb *urb;
|
||||
struct usb_device *usbdev = to_usb_device(sc->hdev->dev.parent->parent);
|
||||
const u16 poke_size =
|
||||
ARRAY_SIZE(ghl_ps3wiiu_magic_data);
|
||||
|
||||
pipe = usb_sndctrlpipe(usbdev, 0);
|
||||
|
||||
if (!sc->ghl_cr) {
|
||||
sc->ghl_cr = kzalloc(sizeof(*sc->ghl_cr), GFP_ATOMIC);
|
||||
if (!sc->ghl_cr)
|
||||
goto resched;
|
||||
}
|
||||
|
||||
if (!sc->ghl_databuf) {
|
||||
sc->ghl_databuf = kzalloc(poke_size, GFP_ATOMIC);
|
||||
if (!sc->ghl_databuf)
|
||||
goto resched;
|
||||
}
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
goto resched;
|
||||
|
||||
sc->ghl_cr->bRequestType =
|
||||
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT;
|
||||
sc->ghl_cr->bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
sc->ghl_cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
|
||||
sc->ghl_cr->wIndex = 0;
|
||||
sc->ghl_cr->wLength = cpu_to_le16(poke_size);
|
||||
memcpy(sc->ghl_databuf, ghl_ps3wiiu_magic_data, poke_size);
|
||||
|
||||
usb_fill_control_urb(
|
||||
urb, usbdev, pipe,
|
||||
(unsigned char *) sc->ghl_cr, sc->ghl_databuf,
|
||||
poke_size, ghl_magic_poke_cb, NULL);
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
kfree(sc->ghl_databuf);
|
||||
kfree(sc->ghl_cr);
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
|
||||
resched:
|
||||
/* Reschedule for next time */
|
||||
mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
|
||||
}
|
||||
|
||||
static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
|
||||
unsigned int abs = usage->hid & HID_USAGE;
|
||||
|
||||
if (abs == GHL_GUITAR_TILT_USAGE) {
|
||||
hid_map_usage_clear(hi, usage, bit, max, EV_ABS, ABS_RY);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ds4_show_poll_interval(struct device *dev,
|
||||
struct device_attribute
|
||||
*attr, char *buf)
|
||||
@ -892,7 +991,8 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size)
|
||||
static const u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 };
|
||||
unsigned long flags;
|
||||
int offset;
|
||||
u8 cable_state, battery_capacity, battery_charging;
|
||||
u8 battery_capacity;
|
||||
int battery_status;
|
||||
|
||||
/*
|
||||
* The sixaxis is charging if the battery value is 0xee
|
||||
@ -904,19 +1004,16 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size)
|
||||
|
||||
if (rd[offset] >= 0xee) {
|
||||
battery_capacity = 100;
|
||||
battery_charging = !(rd[offset] & 0x01);
|
||||
cable_state = 1;
|
||||
battery_status = (rd[offset] & 0x01) ? POWER_SUPPLY_STATUS_FULL : POWER_SUPPLY_STATUS_CHARGING;
|
||||
} else {
|
||||
u8 index = rd[offset] <= 5 ? rd[offset] : 5;
|
||||
battery_capacity = sixaxis_battery_capacity[index];
|
||||
battery_charging = 0;
|
||||
cable_state = 0;
|
||||
battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->lock, flags);
|
||||
sc->cable_state = cable_state;
|
||||
sc->battery_capacity = battery_capacity;
|
||||
sc->battery_charging = battery_charging;
|
||||
sc->battery_status = battery_status;
|
||||
spin_unlock_irqrestore(&sc->lock, flags);
|
||||
|
||||
if (sc->quirks & SIXAXIS_CONTROLLER) {
|
||||
@ -944,7 +1041,8 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
|
||||
struct input_dev *input_dev = hidinput->input;
|
||||
unsigned long flags;
|
||||
int n, m, offset, num_touch_data, max_touch_data;
|
||||
u8 cable_state, battery_capacity, battery_charging;
|
||||
u8 cable_state, battery_capacity;
|
||||
int battery_status;
|
||||
u16 timestamp;
|
||||
|
||||
/* When using Bluetooth the header is 2 bytes longer, so skip these. */
|
||||
@ -1049,29 +1147,52 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size)
|
||||
*/
|
||||
offset = data_offset + DS4_INPUT_REPORT_BATTERY_OFFSET;
|
||||
cable_state = (rd[offset] >> 4) & 0x01;
|
||||
battery_capacity = rd[offset] & 0x0F;
|
||||
|
||||
/*
|
||||
* When a USB power source is connected the battery level ranges from
|
||||
* 0 to 10, and when running on battery power it ranges from 0 to 9.
|
||||
* A battery level above 10 when plugged in means charge completed.
|
||||
* Interpretation of the battery_capacity data depends on the cable state.
|
||||
* When no cable is connected (bit4 is 0):
|
||||
* - 0:10: percentage in units of 10%.
|
||||
* When a cable is plugged in:
|
||||
* - 0-10: percentage in units of 10%.
|
||||
* - 11: battery is full
|
||||
* - 14: not charging due to Voltage or temperature error
|
||||
* - 15: charge error
|
||||
*/
|
||||
if (!cable_state || battery_capacity > 10)
|
||||
battery_charging = 0;
|
||||
else
|
||||
battery_charging = 1;
|
||||
if (cable_state) {
|
||||
u8 battery_data = rd[offset] & 0xf;
|
||||
|
||||
if (!cable_state)
|
||||
battery_capacity++;
|
||||
if (battery_capacity > 10)
|
||||
battery_capacity = 10;
|
||||
if (battery_data < 10) {
|
||||
/* Take the mid-point for each battery capacity value,
|
||||
* because on the hardware side 0 = 0-9%, 1=10-19%, etc.
|
||||
* This matches official platform behavior, which does
|
||||
* the same.
|
||||
*/
|
||||
battery_capacity = battery_data * 10 + 5;
|
||||
battery_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
} else if (battery_data == 10) {
|
||||
battery_capacity = 100;
|
||||
battery_status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
} else if (battery_data == 11) {
|
||||
battery_capacity = 100;
|
||||
battery_status = POWER_SUPPLY_STATUS_FULL;
|
||||
} else { /* 14, 15 and undefined values */
|
||||
battery_capacity = 0;
|
||||
battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
u8 battery_data = rd[offset] & 0xf;
|
||||
|
||||
battery_capacity *= 10;
|
||||
if (battery_data < 10)
|
||||
battery_capacity = battery_data * 10 + 5;
|
||||
else /* 10 */
|
||||
battery_capacity = 100;
|
||||
|
||||
battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->lock, flags);
|
||||
sc->cable_state = cable_state;
|
||||
sc->battery_capacity = battery_capacity;
|
||||
sc->battery_charging = battery_charging;
|
||||
sc->battery_status = battery_status;
|
||||
spin_unlock_irqrestore(&sc->lock, flags);
|
||||
|
||||
/*
|
||||
@ -1360,6 +1481,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
if (sc->quirks & DUALSHOCK4_CONTROLLER)
|
||||
return ds4_mapping(hdev, hi, field, usage, bit, max);
|
||||
|
||||
if (sc->quirks & GHL_GUITAR_PS3WIIU)
|
||||
return guitar_mapping(hdev, hi, field, usage, bit, max);
|
||||
|
||||
/* Let hid-core decide for the others */
|
||||
return 0;
|
||||
@ -1597,16 +1720,38 @@ static int dualshock4_get_calibration_data(struct sony_sc *sc)
|
||||
* of the controller, so that it sends input reports of type 0x11.
|
||||
*/
|
||||
if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) {
|
||||
int retries;
|
||||
|
||||
buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_hw_raw_request(sc->hdev, 0x02, buf,
|
||||
DS4_FEATURE_REPORT_0x02_SIZE,
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
if (ret < 0)
|
||||
goto err_stop;
|
||||
/* We should normally receive the feature report data we asked
|
||||
* for, but hidraw applications such as Steam can issue feature
|
||||
* reports as well. In particular for Dongle reconnects, Steam
|
||||
* and this function are competing resulting in often receiving
|
||||
* data for a different HID report, so retry a few times.
|
||||
*/
|
||||
for (retries = 0; retries < 3; retries++) {
|
||||
ret = hid_hw_raw_request(sc->hdev, 0x02, buf,
|
||||
DS4_FEATURE_REPORT_0x02_SIZE,
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
if (ret < 0)
|
||||
goto err_stop;
|
||||
|
||||
if (buf[0] != 0x02) {
|
||||
if (retries < 2) {
|
||||
hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report (0x02) request\n");
|
||||
continue;
|
||||
} else {
|
||||
ret = -EILSEQ;
|
||||
goto err_stop;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u8 bthdr = 0xA3;
|
||||
u32 crc;
|
||||
@ -2300,12 +2445,12 @@ static int sony_battery_get_property(struct power_supply *psy,
|
||||
struct sony_sc *sc = power_supply_get_drvdata(psy);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
u8 battery_charging, battery_capacity, cable_state;
|
||||
u8 battery_capacity;
|
||||
int battery_status;
|
||||
|
||||
spin_lock_irqsave(&sc->lock, flags);
|
||||
battery_charging = sc->battery_charging;
|
||||
battery_capacity = sc->battery_capacity;
|
||||
cable_state = sc->cable_state;
|
||||
battery_status = sc->battery_status;
|
||||
spin_unlock_irqrestore(&sc->lock, flags);
|
||||
|
||||
switch (psp) {
|
||||
@ -2319,13 +2464,7 @@ static int sony_battery_get_property(struct power_supply *psy,
|
||||
val->intval = battery_capacity;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (battery_charging)
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else
|
||||
if (battery_capacity == 100 && cable_state)
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
val->intval = battery_status;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@ -2723,19 +2862,17 @@ static int sony_input_configured(struct hid_device *hdev,
|
||||
|
||||
ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version);
|
||||
if (ret) {
|
||||
/* Make zero for cleanup reasons of sysfs entries. */
|
||||
sc->fw_version = 0;
|
||||
sc->hw_version = 0;
|
||||
hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret);
|
||||
goto err_stop;
|
||||
}
|
||||
sc->fw_version_created = true;
|
||||
|
||||
ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version);
|
||||
if (ret) {
|
||||
sc->hw_version = 0;
|
||||
hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret);
|
||||
goto err_stop;
|
||||
}
|
||||
sc->hw_version_created = true;
|
||||
|
||||
/*
|
||||
* The Dualshock 4 touchpad supports 2 touches and has a
|
||||
@ -2827,9 +2964,9 @@ err_stop:
|
||||
*/
|
||||
if (sc->ds4_bt_poll_interval)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
|
||||
if (sc->fw_version)
|
||||
if (sc->fw_version_created)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
|
||||
if (sc->hw_version)
|
||||
if (sc->hw_version_created)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
|
||||
sony_cancel_work_sync(sc);
|
||||
sony_remove_dev_list(sc);
|
||||
@ -2902,6 +3039,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
|
||||
timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0);
|
||||
mod_timer(&sc->ghl_poke_timer,
|
||||
jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2909,15 +3052,18 @@ static void sony_remove(struct hid_device *hdev)
|
||||
{
|
||||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||||
|
||||
if (sc->quirks & GHL_GUITAR_PS3WIIU)
|
||||
del_timer_sync(&sc->ghl_poke_timer);
|
||||
|
||||
hid_hw_close(hdev);
|
||||
|
||||
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
|
||||
|
||||
if (sc->fw_version)
|
||||
if (sc->fw_version_created)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
|
||||
|
||||
if (sc->hw_version)
|
||||
if (sc->hw_version_created)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
|
||||
|
||||
sony_cancel_work_sync(sc);
|
||||
@ -3020,6 +3166,9 @@ static const struct hid_device_id sony_devices[] = {
|
||||
/* SMK-Link NSG-MR7U Remote Control */
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE),
|
||||
.driver_data = NSG_MR7U_REMOTE_BT },
|
||||
/* Guitar Hero Live PS3 and Wii U guitar dongles */
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY_GHLIVE, USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE),
|
||||
.driver_data = GHL_GUITAR_PS3WIIU},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, sony_devices);
|
||||
|
@ -170,7 +170,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
|
||||
/*
|
||||
* This function performs a Get_Report transfer over the control endpoint
|
||||
* per section 7.2.1 of the HID specification, version 1.1. The first byte
|
||||
* of buffer is the report number to request, or 0x0 if the defice does not
|
||||
* of buffer is the report number to request, or 0x0 if the device does not
|
||||
* use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
|
||||
* or HID_INPUT_REPORT.
|
||||
*/
|
||||
@ -428,6 +428,28 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
|
||||
break;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSINPUT(0))) {
|
||||
int len = _IOC_SIZE(cmd);
|
||||
ret = hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT);
|
||||
break;
|
||||
}
|
||||
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGINPUT(0))) {
|
||||
int len = _IOC_SIZE(cmd);
|
||||
ret = hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSOUTPUT(0))) {
|
||||
int len = _IOC_SIZE(cmd);
|
||||
ret = hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT);
|
||||
break;
|
||||
}
|
||||
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGOUTPUT(0))) {
|
||||
int len = _IOC_SIZE(cmd);
|
||||
ret = hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Begin Read-only ioctls. */
|
||||
if (_IOC_DIR(cmd) != _IOC_READ) {
|
||||
ret = -EINVAL;
|
||||
|
@ -1106,8 +1106,11 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
ret = i2c_hid_fetch_hid_descriptor(ihid);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to fetch the HID Descriptor\n");
|
||||
goto err_regulator;
|
||||
}
|
||||
|
||||
ret = i2c_hid_init_irq(client);
|
||||
if (ret < 0)
|
||||
|
@ -405,6 +405,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{
|
||||
.ident = "Vero K147",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VERO"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "K147"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{ } /* Terminate list */
|
||||
};
|
||||
|
||||
|
@ -211,10 +211,8 @@ int ishtp_hid_probe(unsigned int cur_hid_dev,
|
||||
struct ishtp_hid_data *hid_data;
|
||||
|
||||
hid = hid_allocate_device();
|
||||
if (IS_ERR(hid)) {
|
||||
rv = PTR_ERR(hid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (IS_ERR(hid))
|
||||
return PTR_ERR(hid);
|
||||
|
||||
hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
|
||||
if (!hid_data) {
|
||||
|
@ -438,6 +438,7 @@ static void hid_irq_out(struct urb *urb)
|
||||
break;
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
unplug = 1;
|
||||
break;
|
||||
case -EILSEQ: /* protocol error or unplug */
|
||||
case -EPROTO: /* protocol error or unplug */
|
||||
case -ECONNRESET: /* unlink */
|
||||
@ -489,6 +490,7 @@ static void hid_ctrl(struct urb *urb)
|
||||
break;
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
unplug = 1;
|
||||
break;
|
||||
case -EILSEQ: /* protocol error or unplug */
|
||||
case -EPROTO: /* protocol error or unplug */
|
||||
case -ECONNRESET: /* unlink */
|
||||
|
@ -1173,7 +1173,7 @@ static struct attribute *cintiq_led_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group cintiq_led_attr_group = {
|
||||
static const struct attribute_group cintiq_led_attr_group = {
|
||||
.name = "wacom_led",
|
||||
.attrs = cintiq_led_attrs,
|
||||
};
|
||||
@ -1194,7 +1194,7 @@ static struct attribute *intuos4_led_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group intuos4_led_attr_group = {
|
||||
static const struct attribute_group intuos4_led_attr_group = {
|
||||
.name = "wacom_led",
|
||||
.attrs = intuos4_led_attrs,
|
||||
};
|
||||
@ -1205,7 +1205,7 @@ static struct attribute *intuos5_led_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group intuos5_led_attr_group = {
|
||||
static const struct attribute_group intuos5_led_attr_group = {
|
||||
.name = "wacom_led",
|
||||
.attrs = intuos5_led_attrs,
|
||||
};
|
||||
@ -1216,13 +1216,13 @@ static struct attribute *generic_led_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group generic_led_attr_group = {
|
||||
static const struct attribute_group generic_led_attr_group = {
|
||||
.name = "wacom_led",
|
||||
.attrs = generic_led_attrs,
|
||||
};
|
||||
|
||||
struct wacom_sysfs_group_devres {
|
||||
struct attribute_group *group;
|
||||
const struct attribute_group *group;
|
||||
struct kobject *root;
|
||||
};
|
||||
|
||||
@ -1238,7 +1238,7 @@ static void wacom_devm_sysfs_group_release(struct device *dev, void *res)
|
||||
|
||||
static int __wacom_devm_sysfs_create_group(struct wacom *wacom,
|
||||
struct kobject *root,
|
||||
struct attribute_group *group)
|
||||
const struct attribute_group *group)
|
||||
{
|
||||
struct wacom_sysfs_group_devres *devres;
|
||||
int error;
|
||||
@ -1264,7 +1264,7 @@ static int __wacom_devm_sysfs_create_group(struct wacom *wacom,
|
||||
}
|
||||
|
||||
static int wacom_devm_sysfs_create_group(struct wacom *wacom,
|
||||
struct attribute_group *group)
|
||||
const struct attribute_group *group)
|
||||
{
|
||||
return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj,
|
||||
group);
|
||||
@ -1847,7 +1847,7 @@ static struct attribute *remote##SET_ID##_serial_attrs[] = { \
|
||||
&remote##SET_ID##_mode_attr.attr, \
|
||||
NULL \
|
||||
}; \
|
||||
static struct attribute_group remote##SET_ID##_serial_group = { \
|
||||
static const struct attribute_group remote##SET_ID##_serial_group = { \
|
||||
.name = NULL, \
|
||||
.attrs = remote##SET_ID##_serial_attrs, \
|
||||
}
|
||||
|
@ -494,7 +494,7 @@ struct hid_report_enum {
|
||||
};
|
||||
|
||||
#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */
|
||||
#define HID_MAX_BUFFER_SIZE 8192 /* 8kb */
|
||||
#define HID_MAX_BUFFER_SIZE 16384 /* 16kb */
|
||||
#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */
|
||||
#define HID_OUTPUT_FIFO_SIZE 64
|
||||
|
||||
@ -585,6 +585,7 @@ struct hid_device { /* device report descriptor */
|
||||
__s32 battery_report_id;
|
||||
enum hid_battery_status battery_status;
|
||||
bool battery_avoid_query;
|
||||
ktime_t battery_ratelimit_time;
|
||||
#endif
|
||||
|
||||
unsigned long status; /* see STAT flags above */
|
||||
|
@ -40,6 +40,12 @@ struct hidraw_devinfo {
|
||||
#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
|
||||
#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
|
||||
#define HIDIOCGRAWUNIQ(len) _IOC(_IOC_READ, 'H', 0x08, len)
|
||||
/* The first byte of SINPUT and GINPUT is the report number */
|
||||
#define HIDIOCSINPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x09, len)
|
||||
#define HIDIOCGINPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0A, len)
|
||||
/* The first byte of SOUTPUT and GOUTPUT is the report number */
|
||||
#define HIDIOCSOUTPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0B, len)
|
||||
#define HIDIOCGOUTPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0C, len)
|
||||
|
||||
#define HIDRAW_FIRST_MINOR 0
|
||||
#define HIDRAW_MAX_DEVICES 64
|
||||
|
@ -128,7 +128,7 @@ int main(int argc, char **argv)
|
||||
perror("HIDIOCGFEATURE");
|
||||
} else {
|
||||
printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
|
||||
printf("Report data (not containing the report number):\n\t");
|
||||
printf("Report data:\n\t");
|
||||
for (i = 0; i < res; i++)
|
||||
printf("%hhx ", buf[i]);
|
||||
puts("\n");
|
||||
|
Loading…
Reference in New Issue
Block a user