for-linus-2022052401
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIVAwUAYoyfbaZi849r7WBJAQKARA//RCMaGSBQ4RMzLBlXJX7wr1ab+iCh6HkE J67SW7Nvq3fUAnznXvGinU14XOuZ4tnmBaz8xBWaUmH9JDjHng79tVkuw5scehk9 92pwqCyLDa5Jt9PJ/BqalubaEK68n3dq37o8AiBkDFqncjak2032ozveB8rES/UA BZ7nPvemr7bWilrYlgvlmHh0q5H6pjIpAP7DULsldfNHz16ouwUyv8dKQYs6tZ/A 4XBK5cpQ8jl5FEJOLt4DR6+uTz5FtU0/nkjUgeejg/kk9oFYJ8F/7+9WLuRwa/mF cos6yIMRFY+1Ta9WLLKFnc9AZietwTnbTxYhi8FPadRzQRMv4rTlIDSfHP4dm9BF zf7AQRCDlLCMTjvVzPHjQfkqsbfUIZW7fmUWPde1EvE/mKvZJ4Yrlhn6d3OYhvSn 4BYkDykH/JAe17DFk+j+zsDN9E75sve6QRa3gA30VeYVERM3K8ubjpKAhzY7uQDg ZRVntmL46pjxFU1cHb+BZgrDeGyK21rTGqbUO49xY3byMetVqyR9JCFtla8OogTs qyUpP27qdBvPfgpTA7JUj3uqSKtdeB2MZXjFMhsG491ZzTiLODtC53haQENzqgw4 +a0JMpf8GOBvnER04yEOWTbp2a/iS9xL8/leuC8MEujPWdLuxH8vG9I3zCl/ICg6 6V5wY6+yaSI= =JrXf -----END PGP SIGNATURE----- Merge tag 'for-linus-2022052401' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid Pull HID updates from Jiri Kosina: - support for pens with 3 buttons with Wacom driver (Joshua Dickens) - support for HID_DG_SCANTIME to report the timestamp for pen and touch events in Wacom driver (Joshua Dickens) - support for sensor discovery in amd-sfh driver (Basavaraj Natikar) - support for wider variety of Huion tablets ported from DIGImend project (José Expósito, Nikolai Kondrashov) - new device IDs and other assorted small code cleanups * tag 'for-linus-2022052401' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (44 commits) HID: apple: Properly handle function keys on Keychron keyboards HID: uclogic: Switch to Digitizer usage for styluses HID: uclogic: Add pen support for XP-PEN Star 06 HID: uclogic: Differentiate touch ring and touch strip HID: uclogic: Always shift touch reports to zero HID: uclogic: Do not focus on touch ring only HID: uclogic: Return raw parameters from v2 pen init HID: uclogic: Move param printing to a function HID: core: Display "SENSOR HUB" for sensor hub bus string in hid_info HID: amd_sfh: Move bus declaration outside of amd-sfh HID: amd_sfh: Add physical location to HID device HID: amd_sfh: Modify the hid name HID: amd_sfh: Modify the bus name HID: amd_sfh: Add sensor name by index for debug info HID: amd_sfh: Add support for sensor discovery HID: bigben: fix slab-out-of-bounds Write in bigben_probe Hid: wacom: Fix kernel test robot warning HID: uclogic: Disable pen usage for Huion keyboard interfaces HID: uclogic: Support disabling pen usage HID: uclogic: Pass keyboard reports as is ...
This commit is contained in:
commit
aa051d36ce
|
@ -1044,7 +1044,6 @@ F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
|
||||||
F: drivers/net/ethernet/amd/xgbe/
|
F: drivers/net/ethernet/amd/xgbe/
|
||||||
|
|
||||||
AMD SENSOR FUSION HUB DRIVER
|
AMD SENSOR FUSION HUB DRIVER
|
||||||
M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
|
|
||||||
M: Basavaraj Natikar <basavaraj.natikar@amd.com>
|
M: Basavaraj Natikar <basavaraj.natikar@amd.com>
|
||||||
L: linux-input@vger.kernel.org
|
L: linux-input@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
@ -8766,6 +8765,14 @@ F: drivers/hid/hid-sensor-*
|
||||||
F: drivers/iio/*/hid-*
|
F: drivers/iio/*/hid-*
|
||||||
F: include/linux/hid-sensor-*
|
F: include/linux/hid-sensor-*
|
||||||
|
|
||||||
|
HID WACOM DRIVER
|
||||||
|
M: Ping Cheng <ping.cheng@wacom.com>
|
||||||
|
M: Jason Gerecke <jason.gerecke@wacom.com>
|
||||||
|
L: linux-input@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/hid/wacom.h
|
||||||
|
F: drivers/hid/wacom_*
|
||||||
|
|
||||||
HIGH-RESOLUTION TIMERS, CLOCKEVENTS
|
HIGH-RESOLUTION TIMERS, CLOCKEVENTS
|
||||||
M: Thomas Gleixner <tglx@linutronix.de>
|
M: Thomas Gleixner <tglx@linutronix.de>
|
||||||
L: linux-kernel@vger.kernel.org
|
L: linux-kernel@vger.kernel.org
|
||||||
|
|
|
@ -697,6 +697,14 @@ config HID_MAYFLASH
|
||||||
Say Y here if you have HJZ Mayflash PS3 game controller adapters
|
Say Y here if you have HJZ Mayflash PS3 game controller adapters
|
||||||
and want to enable force feedback support.
|
and want to enable force feedback support.
|
||||||
|
|
||||||
|
config HID_MEGAWORLD_FF
|
||||||
|
tristate "Mega World based game controller force feedback support"
|
||||||
|
depends on USB_HID
|
||||||
|
select INPUT_FF_MEMLESS
|
||||||
|
help
|
||||||
|
Say Y here if you have a Mega World based game controller and want
|
||||||
|
to have force feedback support for it.
|
||||||
|
|
||||||
config HID_REDRAGON
|
config HID_REDRAGON
|
||||||
tristate "Redragon keyboards"
|
tristate "Redragon keyboards"
|
||||||
depends on HID
|
depends on HID
|
||||||
|
|
|
@ -77,6 +77,7 @@ obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
|
||||||
obj-$(CONFIG_HID_MALTRON) += hid-maltron.o
|
obj-$(CONFIG_HID_MALTRON) += hid-maltron.o
|
||||||
obj-$(CONFIG_HID_MCP2221) += hid-mcp2221.o
|
obj-$(CONFIG_HID_MCP2221) += hid-mcp2221.o
|
||||||
obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
|
obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
|
||||||
|
obj-$(CONFIG_HID_MEGAWORLD_FF) += hid-megaworld.o
|
||||||
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
|
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
|
||||||
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
|
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
|
||||||
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
|
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
|
||||||
|
|
|
@ -141,6 +141,24 @@ u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
|
||||||
return sensor_sts;
|
return sensor_sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *get_sensor_name(int idx)
|
||||||
|
{
|
||||||
|
switch (idx) {
|
||||||
|
case accel_idx:
|
||||||
|
return "accelerometer";
|
||||||
|
case gyro_idx:
|
||||||
|
return "gyroscope";
|
||||||
|
case mag_idx:
|
||||||
|
return "magnetometer";
|
||||||
|
case als_idx:
|
||||||
|
return "ALS";
|
||||||
|
case HPD_IDX:
|
||||||
|
return "HPD";
|
||||||
|
default:
|
||||||
|
return "unknown sensor type";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||||
{
|
{
|
||||||
struct amd_input_data *in_data = &privdata->in_data;
|
struct amd_input_data *in_data = &privdata->in_data;
|
||||||
|
@ -219,13 +237,27 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||||
(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
||||||
if (status != SENSOR_ENABLED)
|
if (status != SENSOR_ENABLED)
|
||||||
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
||||||
dev_dbg(dev, "sid 0x%x status 0x%x\n",
|
dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
|
||||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
cl_data->sensor_idx[i],
|
||||||
|
get_sensor_name(cl_data->sensor_idx[i]),
|
||||||
|
cl_data->sensor_sts[i]);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dev_dbg(dev, "sid 0x%x status 0x%x\n",
|
dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
|
||||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
|
||||||
|
cl_data->sensor_sts[i]);
|
||||||
|
}
|
||||||
|
if (privdata->mp2_ops->discovery_status &&
|
||||||
|
privdata->mp2_ops->discovery_status(privdata) == 0) {
|
||||||
|
amd_sfh_hid_client_deinit(privdata);
|
||||||
|
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||||
|
devm_kfree(dev, cl_data->feature_report[i]);
|
||||||
|
devm_kfree(dev, in_data->input_report[i]);
|
||||||
|
devm_kfree(dev, cl_data->report_descr[i]);
|
||||||
|
}
|
||||||
|
dev_warn(dev, "Failed to discover, sensors not enabled\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
|
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -257,8 +289,9 @@ int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
|
||||||
(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
||||||
if (status != SENSOR_ENABLED)
|
if (status != SENSOR_ENABLED)
|
||||||
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
||||||
dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x status 0x%x\n",
|
dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n",
|
||||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
|
||||||
|
cl_data->sensor_sts[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
#include "amd_sfh_hid.h"
|
#include "amd_sfh_hid.h"
|
||||||
|
#include "amd_sfh_pcie.h"
|
||||||
|
|
||||||
#define AMD_SFH_RESPONSE_TIMEOUT 1500
|
#define AMD_SFH_RESPONSE_TIMEOUT 1500
|
||||||
|
|
||||||
|
@ -120,6 +121,8 @@ static struct hid_ll_driver amdtp_hid_ll_driver = {
|
||||||
|
|
||||||
int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
|
int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
|
||||||
{
|
{
|
||||||
|
struct amd_mp2_dev *mp2 = container_of(cli_data->in_data, struct amd_mp2_dev, in_data);
|
||||||
|
struct device *dev = &mp2->pdev->dev;
|
||||||
struct hid_device *hid;
|
struct hid_device *hid;
|
||||||
struct amdtp_hid_data *hid_data;
|
struct amdtp_hid_data *hid_data;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -141,10 +144,12 @@ int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data)
|
||||||
|
|
||||||
hid->driver_data = hid_data;
|
hid->driver_data = hid_data;
|
||||||
cli_data->hid_sensor_hubs[cur_hid_dev] = hid;
|
cli_data->hid_sensor_hubs[cur_hid_dev] = hid;
|
||||||
hid->bus = BUS_AMD_AMDTP;
|
strscpy(hid->phys, dev->driver ? dev->driver->name : dev_name(dev),
|
||||||
|
sizeof(hid->phys));
|
||||||
|
hid->bus = BUS_AMD_SFH;
|
||||||
hid->vendor = AMD_SFH_HID_VENDOR;
|
hid->vendor = AMD_SFH_HID_VENDOR;
|
||||||
hid->product = AMD_SFH_HID_PRODUCT;
|
hid->product = AMD_SFH_HID_PRODUCT;
|
||||||
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp",
|
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdsfh",
|
||||||
hid->vendor, hid->product);
|
hid->vendor, hid->product);
|
||||||
|
|
||||||
rc = hid_add_device(hid);
|
rc = hid_add_device(hid);
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#define AMDSFH_HID_H
|
#define AMDSFH_HID_H
|
||||||
|
|
||||||
#define MAX_HID_DEVICES 5
|
#define MAX_HID_DEVICES 5
|
||||||
#define BUS_AMD_AMDTP 0x20
|
|
||||||
#define AMD_SFH_HID_VENDOR 0x1022
|
#define AMD_SFH_HID_VENDOR 0x1022
|
||||||
#define AMD_SFH_HID_PRODUCT 0x0001
|
#define AMD_SFH_HID_PRODUCT 0x0001
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,12 @@ static int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int amd_sfh_dis_sts_v2(struct amd_mp2_dev *privdata)
|
||||||
|
{
|
||||||
|
return (readl(privdata->mmio + AMD_P2C_MSG(1)) &
|
||||||
|
SENSOR_DISCOVERY_STATUS_MASK) >> SENSOR_DISCOVERY_STATUS_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
|
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
|
||||||
{
|
{
|
||||||
union sfh_cmd_param cmd_param;
|
union sfh_cmd_param cmd_param;
|
||||||
|
@ -245,6 +251,7 @@ static const struct amd_mp2_ops amd_sfh_ops_v2 = {
|
||||||
.response = amd_sfh_wait_response_v2,
|
.response = amd_sfh_wait_response_v2,
|
||||||
.clear_intr = amd_sfh_clear_intr_v2,
|
.clear_intr = amd_sfh_clear_intr_v2,
|
||||||
.init_intr = amd_sfh_irq_init_v2,
|
.init_intr = amd_sfh_irq_init_v2,
|
||||||
|
.discovery_status = amd_sfh_dis_sts_v2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct amd_mp2_ops amd_sfh_ops = {
|
static const struct amd_mp2_ops amd_sfh_ops = {
|
||||||
|
@ -346,8 +353,9 @@ static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
|
||||||
(mp2, cl_data->sensor_idx[i], SENSOR_ENABLED);
|
(mp2, cl_data->sensor_idx[i], SENSOR_ENABLED);
|
||||||
if (status == SENSOR_ENABLED)
|
if (status == SENSOR_ENABLED)
|
||||||
cl_data->sensor_sts[i] = SENSOR_ENABLED;
|
cl_data->sensor_sts[i] = SENSOR_ENABLED;
|
||||||
dev_dbg(dev, "resume sid 0x%x status 0x%x\n",
|
dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n",
|
||||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
|
||||||
|
cl_data->sensor_sts[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,8 +379,9 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
|
||||||
(mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
(mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
||||||
if (status != SENSOR_ENABLED)
|
if (status != SENSOR_ENABLED)
|
||||||
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
||||||
dev_dbg(dev, "suspend sid 0x%x status 0x%x\n",
|
dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n",
|
||||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
|
||||||
|
cl_data->sensor_sts[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
|
|
||||||
#define AMD_SFH_IDLE_LOOP 200
|
#define AMD_SFH_IDLE_LOOP 200
|
||||||
|
|
||||||
|
#define SENSOR_DISCOVERY_STATUS_MASK GENMASK(5, 3)
|
||||||
|
#define SENSOR_DISCOVERY_STATUS_SHIFT 3
|
||||||
|
|
||||||
/* SFH Command register */
|
/* SFH Command register */
|
||||||
union sfh_cmd_base {
|
union sfh_cmd_base {
|
||||||
u32 ul;
|
u32 ul;
|
||||||
|
@ -135,6 +138,7 @@ int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);
|
||||||
u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts);
|
u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts);
|
||||||
void amd_mp2_suspend(struct amd_mp2_dev *mp2);
|
void amd_mp2_suspend(struct amd_mp2_dev *mp2);
|
||||||
void amd_mp2_resume(struct amd_mp2_dev *mp2);
|
void amd_mp2_resume(struct amd_mp2_dev *mp2);
|
||||||
|
const char *get_sensor_name(int idx);
|
||||||
|
|
||||||
struct amd_mp2_ops {
|
struct amd_mp2_ops {
|
||||||
void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
|
void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
|
||||||
|
@ -143,5 +147,6 @@ struct amd_mp2_ops {
|
||||||
int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts);
|
int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts);
|
||||||
void (*clear_intr)(struct amd_mp2_dev *privdata);
|
void (*clear_intr)(struct amd_mp2_dev *privdata);
|
||||||
int (*init_intr)(struct amd_mp2_dev *privdata);
|
int (*init_intr)(struct amd_mp2_dev *privdata);
|
||||||
|
int (*discovery_status)(struct amd_mp2_dev *privdata);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -179,7 +179,7 @@ static const u8 accel3_report_descriptor[] = {
|
||||||
0xC0 /* HID end collection */
|
0xC0 /* HID end collection */
|
||||||
};
|
};
|
||||||
|
|
||||||
const u8 gyro3_report_descriptor[] = {
|
static const u8 gyro3_report_descriptor[] = {
|
||||||
0x05, 0x20, /* Usage page */
|
0x05, 0x20, /* Usage page */
|
||||||
0x09, 0x76, /* Motion type Gyro3D */
|
0x09, 0x76, /* Motion type Gyro3D */
|
||||||
0xA1, 0x00, /* HID Collection (Physical) */
|
0xA1, 0x00, /* HID Collection (Physical) */
|
||||||
|
@ -340,7 +340,7 @@ const u8 gyro3_report_descriptor[] = {
|
||||||
0xC0, /* HID end collection */
|
0xC0, /* HID end collection */
|
||||||
};
|
};
|
||||||
|
|
||||||
const u8 comp3_report_descriptor[] = {
|
static const u8 comp3_report_descriptor[] = {
|
||||||
0x05, 0x20, /* Usage page */
|
0x05, 0x20, /* Usage page */
|
||||||
0x09, 0x83, /* Motion type Orientation compass 3D */
|
0x09, 0x83, /* Motion type Orientation compass 3D */
|
||||||
0xA1, 0x00, /* HID Collection (Physical) */
|
0xA1, 0x00, /* HID Collection (Physical) */
|
||||||
|
@ -512,7 +512,7 @@ const u8 comp3_report_descriptor[] = {
|
||||||
0xC0 /* HID end collection */
|
0xC0 /* HID end collection */
|
||||||
};
|
};
|
||||||
|
|
||||||
const u8 als_report_descriptor[] = {
|
static const u8 als_report_descriptor[] = {
|
||||||
0x05, 0x20, /* HID usage page sensor */
|
0x05, 0x20, /* HID usage page sensor */
|
||||||
0x09, 0x41, /* HID usage sensor type Ambientlight */
|
0x09, 0x41, /* HID usage sensor type Ambientlight */
|
||||||
0xA1, 0x00, /* HID Collection (Physical) */
|
0xA1, 0x00, /* HID Collection (Physical) */
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
|
||||||
#include "hid-ids.h"
|
#include "hid-ids.h"
|
||||||
|
|
||||||
|
@ -35,16 +36,17 @@
|
||||||
#define APPLE_NUMLOCK_EMULATION BIT(8)
|
#define APPLE_NUMLOCK_EMULATION BIT(8)
|
||||||
#define APPLE_RDESC_BATTERY BIT(9)
|
#define APPLE_RDESC_BATTERY BIT(9)
|
||||||
#define APPLE_BACKLIGHT_CTL BIT(10)
|
#define APPLE_BACKLIGHT_CTL BIT(10)
|
||||||
|
#define APPLE_IS_KEYCHRON BIT(11)
|
||||||
|
|
||||||
#define APPLE_FLAG_FKEY 0x01
|
#define APPLE_FLAG_FKEY 0x01
|
||||||
|
|
||||||
#define HID_COUNTRY_INTERNATIONAL_ISO 13
|
#define HID_COUNTRY_INTERNATIONAL_ISO 13
|
||||||
#define APPLE_BATTERY_TIMEOUT_MS 60000
|
#define APPLE_BATTERY_TIMEOUT_MS 60000
|
||||||
|
|
||||||
static unsigned int fnmode = 1;
|
static unsigned int fnmode = 3;
|
||||||
module_param(fnmode, uint, 0644);
|
module_param(fnmode, uint, 0644);
|
||||||
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
|
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
|
||||||
"[1] = fkeyslast, 2 = fkeysfirst)");
|
"1 = fkeyslast, 2 = fkeysfirst, [3] = auto)");
|
||||||
|
|
||||||
static int iso_layout = -1;
|
static int iso_layout = -1;
|
||||||
module_param(iso_layout, int, 0644);
|
module_param(iso_layout, int, 0644);
|
||||||
|
@ -349,6 +351,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||||
const struct apple_key_translation *trans, *table;
|
const struct apple_key_translation *trans, *table;
|
||||||
bool do_translate;
|
bool do_translate;
|
||||||
u16 code = 0;
|
u16 code = 0;
|
||||||
|
unsigned int real_fnmode;
|
||||||
|
|
||||||
u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
|
u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
|
||||||
|
|
||||||
|
@ -359,7 +362,13 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fnmode) {
|
if (fnmode == 3) {
|
||||||
|
real_fnmode = (asc->quirks & APPLE_IS_KEYCHRON) ? 2 : 1;
|
||||||
|
} else {
|
||||||
|
real_fnmode = fnmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (real_fnmode) {
|
||||||
if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
|
if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
|
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
|
||||||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS ||
|
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS ||
|
||||||
|
@ -406,7 +415,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||||
|
|
||||||
if (!code) {
|
if (!code) {
|
||||||
if (trans->flags & APPLE_FLAG_FKEY) {
|
if (trans->flags & APPLE_FLAG_FKEY) {
|
||||||
switch (fnmode) {
|
switch (real_fnmode) {
|
||||||
case 1:
|
case 1:
|
||||||
do_translate = !asc->fn_on;
|
do_translate = !asc->fn_on;
|
||||||
break;
|
break;
|
||||||
|
@ -660,6 +669,11 @@ static int apple_input_configured(struct hid_device *hdev,
|
||||||
asc->quirks &= ~APPLE_HAS_FN;
|
asc->quirks &= ~APPLE_HAS_FN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strncmp(hdev->name, "Keychron", 8) == 0) {
|
||||||
|
hid_info(hdev, "Keychron keyboard detected; function keys will default to fnmode=2 behavior\n");
|
||||||
|
asc->quirks |= APPLE_IS_KEYCHRON;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -347,6 +347,12 @@ static int bigben_probe(struct hid_device *hid,
|
||||||
bigben->report = list_entry(report_list->next,
|
bigben->report = list_entry(report_list->next,
|
||||||
struct hid_report, list);
|
struct hid_report, list);
|
||||||
|
|
||||||
|
if (list_empty(&hid->inputs)) {
|
||||||
|
hid_err(hid, "no inputs found\n");
|
||||||
|
error = -ENODEV;
|
||||||
|
goto error_hw_stop;
|
||||||
|
}
|
||||||
|
|
||||||
hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
|
hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
|
||||||
set_bit(FF_RUMBLE, hidinput->input->ffbit);
|
set_bit(FF_RUMBLE, hidinput->input->ffbit);
|
||||||
|
|
||||||
|
|
|
@ -2222,6 +2222,10 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
||||||
case BUS_VIRTUAL:
|
case BUS_VIRTUAL:
|
||||||
bus = "VIRTUAL";
|
bus = "VIRTUAL";
|
||||||
break;
|
break;
|
||||||
|
case BUS_INTEL_ISHTP:
|
||||||
|
case BUS_AMD_SFH:
|
||||||
|
bus = "SENSOR HUB";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
bus = "<UNKNOWN>";
|
bus = "<UNKNOWN>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,7 +188,6 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||||
ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER);
|
ret = input_mt_init_slots(input, ELAN_MAX_FINGERS, INPUT_MT_POINTER);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
|
hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
|
||||||
input_free_device(input);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +199,6 @@ static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||||
hid_err(hdev, "Failed to register elan input device: %d\n",
|
hid_err(hdev, "Failed to register elan input device: %d\n",
|
||||||
ret);
|
ret);
|
||||||
input_mt_destroy_slots(input);
|
input_mt_destroy_slots(input);
|
||||||
input_free_device(input);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -761,13 +761,16 @@
|
||||||
#define USB_VENDOR_ID_LENOVO 0x17ef
|
#define USB_VENDOR_ID_LENOVO 0x17ef
|
||||||
#define USB_DEVICE_ID_LENOVO_TPKBD 0x6009
|
#define USB_DEVICE_ID_LENOVO_TPKBD 0x6009
|
||||||
#define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047
|
#define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047
|
||||||
|
#define USB_DEVICE_ID_LENOVO_TPIIUSBKBD 0x60ee
|
||||||
#define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048
|
#define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048
|
||||||
|
#define USB_DEVICE_ID_LENOVO_TPIIBTKBD 0x60e1
|
||||||
#define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL 0x6049
|
#define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL 0x6049
|
||||||
#define USB_DEVICE_ID_LENOVO_TP10UBKBD 0x6062
|
#define USB_DEVICE_ID_LENOVO_TP10UBKBD 0x6062
|
||||||
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
|
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
|
||||||
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
|
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
|
||||||
#define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3
|
#define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3
|
||||||
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
|
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
|
||||||
|
#define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
|
||||||
#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e
|
#define USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E 0x600e
|
||||||
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
|
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
|
||||||
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
|
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
|
||||||
|
@ -868,6 +871,9 @@
|
||||||
#define USB_VENDOR_ID_MCS 0x16d0
|
#define USB_VENDOR_ID_MCS 0x16d0
|
||||||
#define USB_DEVICE_ID_MCS_GAMEPADBLOCK 0x0bcc
|
#define USB_DEVICE_ID_MCS_GAMEPADBLOCK 0x0bcc
|
||||||
|
|
||||||
|
#define USB_VENDOR_MEGAWORLD 0x07b5
|
||||||
|
#define USB_DEVICE_ID_MEGAWORLD_GAMEPAD 0x0312
|
||||||
|
|
||||||
#define USB_VENDOR_ID_MGE 0x0463
|
#define USB_VENDOR_ID_MGE 0x0463
|
||||||
#define USB_DEVICE_ID_MGE_UPS 0xffff
|
#define USB_DEVICE_ID_MGE_UPS 0xffff
|
||||||
#define USB_DEVICE_ID_MGE_UPS1 0x0001
|
#define USB_DEVICE_ID_MGE_UPS1 0x0001
|
||||||
|
@ -1272,6 +1278,7 @@
|
||||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075
|
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075
|
||||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
|
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
|
||||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
|
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
|
||||||
|
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
||||||
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
|
#define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055
|
||||||
|
|
|
@ -33,7 +33,7 @@ static __u8 easypen_i405x_rdesc_fixed[] = {
|
||||||
0xB1, 0x02, /* Feature (Variable), */
|
0xB1, 0x02, /* Feature (Variable), */
|
||||||
0xC0, /* End Collection, */
|
0xC0, /* End Collection, */
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x10, /* Report ID (16), */
|
0x85, 0x10, /* Report ID (16), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -91,7 +91,7 @@ static __u8 mousepen_i608x_rdesc_fixed[] = {
|
||||||
0xB1, 0x02, /* Feature (Variable), */
|
0xB1, 0x02, /* Feature (Variable), */
|
||||||
0xC0, /* End Collection, */
|
0xC0, /* End Collection, */
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x10, /* Report ID (16), */
|
0x85, 0x10, /* Report ID (16), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -190,7 +190,7 @@ static __u8 mousepen_i608x_v2_rdesc_fixed[] = {
|
||||||
0xB1, 0x02, /* Feature (Variable), */
|
0xB1, 0x02, /* Feature (Variable), */
|
||||||
0xC0, /* End Collection, */
|
0xC0, /* End Collection, */
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x10, /* Report ID (16), */
|
0x85, 0x10, /* Report ID (16), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -289,7 +289,7 @@ static __u8 easypen_m610x_rdesc_fixed[] = {
|
||||||
0xB1, 0x02, /* Feature (Variable), */
|
0xB1, 0x02, /* Feature (Variable), */
|
||||||
0xC0, /* End Collection, */
|
0xC0, /* End Collection, */
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x10, /* Report ID (16), */
|
0x85, 0x10, /* Report ID (16), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -368,7 +368,7 @@ static __u8 pensketch_m912_rdesc_fixed[] = {
|
||||||
0xB1, 0x02, /* Feature (Variable), */
|
0xB1, 0x02, /* Feature (Variable), */
|
||||||
0xC0, /* End Collection, */
|
0xC0, /* End Collection, */
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x10, /* Report ID (16), */
|
0x85, 0x10, /* Report ID (16), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -497,7 +497,7 @@ static __u8 easypen_m406xe_rdesc_fixed[] = {
|
||||||
0xB1, 0x02, /* Feature (Variable), */
|
0xB1, 0x02, /* Feature (Variable), */
|
||||||
0xC0, /* End Collection, */
|
0xC0, /* End Collection, */
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x10, /* Report ID (16), */
|
0x85, 0x10, /* Report ID (16), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
|
|
@ -366,7 +366,7 @@ static const struct hidled_config hidled_configs[] = {
|
||||||
.type = DREAM_CHEEKY,
|
.type = DREAM_CHEEKY,
|
||||||
.name = "Dream Cheeky Webmail Notifier",
|
.name = "Dream Cheeky Webmail Notifier",
|
||||||
.short_name = "dream_cheeky",
|
.short_name = "dream_cheeky",
|
||||||
.max_brightness = 31,
|
.max_brightness = 63,
|
||||||
.num_leds = 1,
|
.num_leds = 1,
|
||||||
.report_size = 9,
|
.report_size = 9,
|
||||||
.report_type = RAW_REQUEST,
|
.report_type = RAW_REQUEST,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* - ThinkPad USB Keyboard with TrackPoint (tpkbd)
|
* - ThinkPad USB Keyboard with TrackPoint (tpkbd)
|
||||||
* - ThinkPad Compact Bluetooth Keyboard with TrackPoint (cptkbd)
|
* - ThinkPad Compact Bluetooth Keyboard with TrackPoint (cptkbd)
|
||||||
* - ThinkPad Compact USB Keyboard with TrackPoint (cptkbd)
|
* - ThinkPad Compact USB Keyboard with TrackPoint (cptkbd)
|
||||||
|
* - ThinkPad TrackPoint Keyboard II USB/Bluetooth (cptkbd/tpIIkbd)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Bernhard Seibold
|
* Copyright (c) 2012 Bernhard Seibold
|
||||||
* Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
|
* Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
|
||||||
|
@ -110,6 +111,23 @@ static const __u8 lenovo_pro_dock_need_fixup_collection[] = {
|
||||||
0x2a, 0xff, 0xff, /* Usage Maximum (65535) */
|
0x2a, 0xff, 0xff, /* Usage Maximum (65535) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Broken ThinkPad TrackPoint II collection (Bluetooth mode) */
|
||||||
|
static const __u8 lenovo_tpIIbtkbd_need_fixup_collection[] = {
|
||||||
|
0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined 0xFF00) */
|
||||||
|
0x09, 0x01, /* Usage (0x01) */
|
||||||
|
0xA1, 0x01, /* Collection (Application) */
|
||||||
|
0x85, 0x05, /* Report ID (5) */
|
||||||
|
0x1A, 0xF1, 0x00, /* Usage Minimum (0xF1) */
|
||||||
|
0x2A, 0xFC, 0x00, /* Usage Maximum (0xFC) */
|
||||||
|
0x15, 0x00, /* Logical Minimum (0) */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1) */
|
||||||
|
0x75, 0x01, /* Report Size (1) */
|
||||||
|
0x95, 0x0D, /* Report Count (13) */
|
||||||
|
0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) */
|
||||||
|
0x95, 0x03, /* Report Count (3) */
|
||||||
|
0x81, 0x01, /* Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) */
|
||||||
|
};
|
||||||
|
|
||||||
static __u8 *lenovo_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
static __u8 *lenovo_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
unsigned int *rsize)
|
unsigned int *rsize)
|
||||||
{
|
{
|
||||||
|
@ -126,6 +144,19 @@ static __u8 *lenovo_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
rdesc[152] = 0x00;
|
rdesc[152] = 0x00;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
|
if (*rsize >= 263 &&
|
||||||
|
memcmp(&rdesc[234], lenovo_tpIIbtkbd_need_fixup_collection,
|
||||||
|
sizeof(lenovo_tpIIbtkbd_need_fixup_collection)) == 0) {
|
||||||
|
rdesc[244] = 0x00; /* usage minimum = 0x00 */
|
||||||
|
rdesc[247] = 0xff; /* usage maximum = 0xff */
|
||||||
|
rdesc[252] = 0xff; /* logical maximum = 0xff */
|
||||||
|
rdesc[254] = 0x08; /* report size = 0x08 */
|
||||||
|
rdesc[256] = 0x01; /* report count = 0x01 */
|
||||||
|
rdesc[258] = 0x00; /* input = 0x00 */
|
||||||
|
rdesc[260] = 0x01; /* report count (2) = 0x01 */
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return rdesc;
|
return rdesc;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +248,101 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lenovo_input_mapping_tpIIkbd(struct hid_device *hdev,
|
||||||
|
struct hid_input *hi, struct hid_field *field,
|
||||||
|
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 0xff0a0000 = USB, HID_UP_MSVENDOR = BT.
|
||||||
|
*
|
||||||
|
* In BT mode, there are two HID_UP_MSVENDOR pages.
|
||||||
|
* Use only the page that contains report ID == 5.
|
||||||
|
*/
|
||||||
|
if (((usage->hid & HID_USAGE_PAGE) == 0xff0a0000 ||
|
||||||
|
(usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) &&
|
||||||
|
field->report->id == 5) {
|
||||||
|
switch (usage->hid & HID_USAGE) {
|
||||||
|
case 0x00bb: /* Fn-F4: Mic mute */
|
||||||
|
map_key_clear(LENOVO_KEY_MICMUTE);
|
||||||
|
return 1;
|
||||||
|
case 0x00c3: /* Fn-F5: Brightness down */
|
||||||
|
map_key_clear(KEY_BRIGHTNESSDOWN);
|
||||||
|
return 1;
|
||||||
|
case 0x00c4: /* Fn-F6: Brightness up */
|
||||||
|
map_key_clear(KEY_BRIGHTNESSUP);
|
||||||
|
return 1;
|
||||||
|
case 0x00c1: /* Fn-F8: Notification center */
|
||||||
|
map_key_clear(KEY_NOTIFICATION_CENTER);
|
||||||
|
return 1;
|
||||||
|
case 0x00bc: /* Fn-F9: Control panel */
|
||||||
|
map_key_clear(KEY_CONFIG);
|
||||||
|
return 1;
|
||||||
|
case 0x00b6: /* Fn-F10: Bluetooth */
|
||||||
|
map_key_clear(KEY_BLUETOOTH);
|
||||||
|
return 1;
|
||||||
|
case 0x00b7: /* Fn-F11: Keyboard config */
|
||||||
|
map_key_clear(KEY_KEYBOARD);
|
||||||
|
return 1;
|
||||||
|
case 0x00b8: /* Fn-F12: User function */
|
||||||
|
map_key_clear(KEY_PROG1);
|
||||||
|
return 1;
|
||||||
|
case 0x00b9: /* Fn-PrtSc: Snipping tool */
|
||||||
|
map_key_clear(KEY_SELECTIVE_SCREENSHOT);
|
||||||
|
return 1;
|
||||||
|
case 0x00b5: /* Fn-Esc: Fn-lock toggle */
|
||||||
|
map_key_clear(KEY_FN_ESC);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((usage->hid & HID_USAGE_PAGE) == 0xffa00000) {
|
||||||
|
switch (usage->hid & HID_USAGE) {
|
||||||
|
case 0x00fb: /* Middle mouse (in native USB mode) */
|
||||||
|
map_key_clear(BTN_MIDDLE);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR &&
|
||||||
|
field->report->id == 21) {
|
||||||
|
switch (usage->hid & HID_USAGE) {
|
||||||
|
case 0x0004: /* Middle mouse (in native Bluetooth mode) */
|
||||||
|
map_key_clear(BTN_MIDDLE);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compatibility middle/wheel mappings should be ignored */
|
||||||
|
if (usage->hid == HID_GD_WHEEL)
|
||||||
|
return -1;
|
||||||
|
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON &&
|
||||||
|
(usage->hid & HID_USAGE) == 0x003)
|
||||||
|
return -1;
|
||||||
|
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER &&
|
||||||
|
(usage->hid & HID_USAGE) == 0x238)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Map wheel emulation reports: 0xff10 */
|
||||||
|
if ((usage->hid & HID_USAGE_PAGE) == 0xff100000) {
|
||||||
|
field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE;
|
||||||
|
field->logical_minimum = -127;
|
||||||
|
field->logical_maximum = 127;
|
||||||
|
|
||||||
|
switch (usage->hid & HID_USAGE) {
|
||||||
|
case 0x0000:
|
||||||
|
hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
|
||||||
|
return 1;
|
||||||
|
case 0x0001:
|
||||||
|
hid_map_usage(hi, usage, bit, max, EV_REL, REL_WHEEL);
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev,
|
static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev,
|
||||||
struct hid_input *hi, struct hid_field *field,
|
struct hid_input *hi, struct hid_field *field,
|
||||||
struct hid_usage *usage, unsigned long **bit, int *max)
|
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||||
|
@ -326,6 +452,10 @@ static int lenovo_input_mapping(struct hid_device *hdev,
|
||||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||||
return lenovo_input_mapping_cptkbd(hdev, hi, field,
|
return lenovo_input_mapping_cptkbd(hdev, hi, field,
|
||||||
usage, bit, max);
|
usage, bit, max);
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
|
return lenovo_input_mapping_tpIIkbd(hdev, hi, field,
|
||||||
|
usage, bit, max);
|
||||||
case USB_DEVICE_ID_IBM_SCROLLPOINT_III:
|
case USB_DEVICE_ID_IBM_SCROLLPOINT_III:
|
||||||
case USB_DEVICE_ID_IBM_SCROLLPOINT_PRO:
|
case USB_DEVICE_ID_IBM_SCROLLPOINT_PRO:
|
||||||
case USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL:
|
case USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL:
|
||||||
|
@ -357,16 +487,23 @@ static int lenovo_send_cmd_cptkbd(struct hid_device *hdev,
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Feature report 0x13 is used for USB,
|
||||||
|
* output report 0x18 is used for Bluetooth.
|
||||||
|
* buf[0] is ignored by hid_hw_raw_request.
|
||||||
|
*/
|
||||||
buf[0] = 0x18;
|
buf[0] = 0x18;
|
||||||
buf[1] = byte2;
|
buf[1] = byte2;
|
||||||
buf[2] = byte3;
|
buf[2] = byte3;
|
||||||
|
|
||||||
switch (hdev->product) {
|
switch (hdev->product) {
|
||||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
|
||||||
ret = hid_hw_raw_request(hdev, 0x13, buf, 3,
|
ret = hid_hw_raw_request(hdev, 0x13, buf, 3,
|
||||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||||
break;
|
break;
|
||||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
ret = hid_hw_output_report(hdev, buf, 3);
|
ret = hid_hw_output_report(hdev, buf, 3);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -422,6 +559,8 @@ static ssize_t attr_fn_lock_store(struct device *dev,
|
||||||
switch (hdev->product) {
|
switch (hdev->product) {
|
||||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
lenovo_features_set_cptkbd(hdev);
|
lenovo_features_set_cptkbd(hdev);
|
||||||
break;
|
break;
|
||||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||||
|
@ -556,6 +695,15 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
|
||||||
|
/*
|
||||||
|
* The user has toggled the Fn-lock state. Toggle our own
|
||||||
|
* cached value of it and sync our value to the keyboard to
|
||||||
|
* ensure things are in sync (the syncing should be a no-op).
|
||||||
|
*/
|
||||||
|
cptkbd_data->fn_lock = !cptkbd_data->fn_lock;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,6 +716,8 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
|
||||||
switch (hdev->product) {
|
switch (hdev->product) {
|
||||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
return lenovo_event_cptkbd(hdev, field, usage, value);
|
return lenovo_event_cptkbd(hdev, field, usage, value);
|
||||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||||
|
@ -960,8 +1110,9 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
|
||||||
struct lenovo_drvdata *cptkbd_data;
|
struct lenovo_drvdata *cptkbd_data;
|
||||||
|
|
||||||
/* All the custom action happens on the USBMOUSE device for USB */
|
/* All the custom action happens on the USBMOUSE device for USB */
|
||||||
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
|
if (((hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD) ||
|
||||||
&& hdev->type != HID_TYPE_USBMOUSE) {
|
(hdev->product == USB_DEVICE_ID_LENOVO_TPIIUSBKBD)) &&
|
||||||
|
hdev->type != HID_TYPE_USBMOUSE) {
|
||||||
hid_dbg(hdev, "Ignoring keyboard half of device\n");
|
hid_dbg(hdev, "Ignoring keyboard half of device\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -977,11 +1128,14 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
|
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
|
||||||
* regular keys
|
* regular keys (Compact only)
|
||||||
*/
|
*/
|
||||||
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
|
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
|
||||||
if (ret)
|
hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
|
||||||
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
|
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
|
||||||
|
if (ret)
|
||||||
|
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
/* Switch middle button to native mode */
|
/* Switch middle button to native mode */
|
||||||
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
|
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
|
||||||
|
@ -1088,6 +1242,8 @@ static int lenovo_probe(struct hid_device *hdev,
|
||||||
break;
|
break;
|
||||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
ret = lenovo_probe_cptkbd(hdev);
|
ret = lenovo_probe_cptkbd(hdev);
|
||||||
break;
|
break;
|
||||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||||
|
@ -1154,6 +1310,8 @@ static void lenovo_remove(struct hid_device *hdev)
|
||||||
break;
|
break;
|
||||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
lenovo_remove_cptkbd(hdev);
|
lenovo_remove_cptkbd(hdev);
|
||||||
break;
|
break;
|
||||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||||
|
@ -1172,6 +1330,8 @@ static int lenovo_input_configured(struct hid_device *hdev,
|
||||||
case USB_DEVICE_ID_LENOVO_TPKBD:
|
case USB_DEVICE_ID_LENOVO_TPKBD:
|
||||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
|
||||||
|
case USB_DEVICE_ID_LENOVO_TPIIBTKBD:
|
||||||
if (test_bit(EV_REL, hi->input->evbit)) {
|
if (test_bit(EV_REL, hi->input->evbit)) {
|
||||||
/* set only for trackpoint device */
|
/* set only for trackpoint device */
|
||||||
__set_bit(INPUT_PROP_POINTER, hi->input->propbit);
|
__set_bit(INPUT_PROP_POINTER, hi->input->propbit);
|
||||||
|
@ -1188,7 +1348,9 @@ static int lenovo_input_configured(struct hid_device *hdev,
|
||||||
static const struct hid_device_id lenovo_devices[] = {
|
static const struct hid_device_id lenovo_devices[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPIIUSBKBD) },
|
||||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
|
||||||
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPIIBTKBD) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_III) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_III) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_PRO) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_PRO) },
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Vibration support for Mega World controllers
|
||||||
|
*
|
||||||
|
* Copyright 2022 Frank Zago
|
||||||
|
*
|
||||||
|
* Derived from hid-zpff.c:
|
||||||
|
* Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/hid.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include "hid-ids.h"
|
||||||
|
|
||||||
|
struct mwctrl_device {
|
||||||
|
struct hid_report *report;
|
||||||
|
s32 *weak;
|
||||||
|
s32 *strong;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mwctrl_play(struct input_dev *dev, void *data,
|
||||||
|
struct ff_effect *effect)
|
||||||
|
{
|
||||||
|
struct hid_device *hid = input_get_drvdata(dev);
|
||||||
|
struct mwctrl_device *mwctrl = data;
|
||||||
|
|
||||||
|
*mwctrl->strong = effect->u.rumble.strong_magnitude >> 8;
|
||||||
|
*mwctrl->weak = effect->u.rumble.weak_magnitude >> 8;
|
||||||
|
|
||||||
|
hid_hw_request(hid, mwctrl->report, HID_REQ_SET_REPORT);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mwctrl_init(struct hid_device *hid)
|
||||||
|
{
|
||||||
|
struct mwctrl_device *mwctrl;
|
||||||
|
struct hid_report *report;
|
||||||
|
struct hid_input *hidinput;
|
||||||
|
struct input_dev *dev;
|
||||||
|
int error;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (list_empty(&hid->inputs)) {
|
||||||
|
hid_err(hid, "no inputs found\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
hidinput = list_entry(hid->inputs.next, struct hid_input, list);
|
||||||
|
dev = hidinput->input;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);
|
||||||
|
if (!report)
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
mwctrl = kzalloc(sizeof(struct mwctrl_device), GFP_KERNEL);
|
||||||
|
if (!mwctrl)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
set_bit(FF_RUMBLE, dev->ffbit);
|
||||||
|
|
||||||
|
error = input_ff_create_memless(dev, mwctrl, mwctrl_play);
|
||||||
|
if (error) {
|
||||||
|
kfree(mwctrl);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
mwctrl->report = report;
|
||||||
|
|
||||||
|
/* Field 0 is always 2, and field 1 is always 0. The original
|
||||||
|
* windows driver has a 5 bytes command, where the 5th byte is
|
||||||
|
* a repeat of the 3rd byte, however the device has only 4
|
||||||
|
* fields. It could be a bug in the driver, or there is a
|
||||||
|
* different device that needs it.
|
||||||
|
*/
|
||||||
|
report->field[0]->value[0] = 0x02;
|
||||||
|
|
||||||
|
mwctrl->strong = &report->field[2]->value[0];
|
||||||
|
mwctrl->weak = &report->field[3]->value[0];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mwctrl_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = hid_parse(hdev);
|
||||||
|
if (ret) {
|
||||||
|
hid_err(hdev, "parse failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
|
||||||
|
if (ret) {
|
||||||
|
hid_err(hdev, "hw start failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mwctrl_init(hdev);
|
||||||
|
if (ret)
|
||||||
|
hid_hw_stop(hdev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct hid_device_id mwctrl_devices[] = {
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_MEGAWORLD,
|
||||||
|
USB_DEVICE_ID_MEGAWORLD_GAMEPAD) },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(hid, mwctrl_devices);
|
||||||
|
|
||||||
|
static struct hid_driver mwctrl_driver = {
|
||||||
|
.name = "megaworld",
|
||||||
|
.id_table = mwctrl_devices,
|
||||||
|
.probe = mwctrl_probe,
|
||||||
|
};
|
||||||
|
module_hid_driver(mwctrl_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -2034,6 +2034,12 @@ static const struct hid_device_id mt_devices[] = {
|
||||||
USB_VENDOR_ID_LENOVO,
|
USB_VENDOR_ID_LENOVO,
|
||||||
USB_DEVICE_ID_LENOVO_X1_TAB3) },
|
USB_DEVICE_ID_LENOVO_X1_TAB3) },
|
||||||
|
|
||||||
|
/* Lenovo X12 TAB Gen 1 */
|
||||||
|
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
|
||||||
|
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
|
||||||
|
USB_VENDOR_ID_LENOVO,
|
||||||
|
USB_DEVICE_ID_LENOVO_X12_TAB) },
|
||||||
|
|
||||||
/* MosArt panels */
|
/* MosArt panels */
|
||||||
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||||
MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
|
MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
|
||||||
|
@ -2178,6 +2184,9 @@ static const struct hid_device_id mt_devices[] = {
|
||||||
{ .driver_data = MT_CLS_GOOGLE,
|
{ .driver_data = MT_CLS_GOOGLE,
|
||||||
HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
|
HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
|
||||||
USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) },
|
USB_DEVICE_ID_GOOGLE_TOUCH_ROSE) },
|
||||||
|
{ .driver_data = MT_CLS_GOOGLE,
|
||||||
|
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_GOOGLE,
|
||||||
|
USB_DEVICE_ID_GOOGLE_WHISKERS) },
|
||||||
|
|
||||||
/* Generic MT device */
|
/* Generic MT device */
|
||||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
|
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
|
||||||
|
|
|
@ -81,6 +81,24 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
return rdesc;
|
return rdesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int uclogic_input_mapping(struct hid_device *hdev,
|
||||||
|
struct hid_input *hi,
|
||||||
|
struct hid_field *field,
|
||||||
|
struct hid_usage *usage,
|
||||||
|
unsigned long **bit,
|
||||||
|
int *max)
|
||||||
|
{
|
||||||
|
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
|
||||||
|
struct uclogic_params *params = &drvdata->params;
|
||||||
|
|
||||||
|
/* Discard invalid pen usages */
|
||||||
|
if (params->pen.usage_invalid && (field->application == HID_DG_PEN))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Let hid-core decide what to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int uclogic_input_configured(struct hid_device *hdev,
|
static int uclogic_input_configured(struct hid_device *hdev,
|
||||||
struct hid_input *hi)
|
struct hid_input *hi)
|
||||||
{
|
{
|
||||||
|
@ -90,6 +108,8 @@ static int uclogic_input_configured(struct hid_device *hdev,
|
||||||
const char *suffix = NULL;
|
const char *suffix = NULL;
|
||||||
struct hid_field *field;
|
struct hid_field *field;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
size_t i;
|
||||||
|
const struct uclogic_params_frame *frame;
|
||||||
|
|
||||||
/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
|
/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
|
||||||
if (!hi->report)
|
if (!hi->report)
|
||||||
|
@ -104,27 +124,44 @@ static int uclogic_input_configured(struct hid_device *hdev,
|
||||||
drvdata->pen_input = hi->input;
|
drvdata->pen_input = hi->input;
|
||||||
}
|
}
|
||||||
|
|
||||||
field = hi->report->field[0];
|
/* If it's one of the frame devices */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
|
||||||
|
frame = ¶ms->frame_list[i];
|
||||||
|
if (hi->report->id == frame->id) {
|
||||||
|
/* Assign custom suffix, if any */
|
||||||
|
suffix = frame->suffix;
|
||||||
|
/*
|
||||||
|
* Disable EV_MSC reports for touch ring interfaces to
|
||||||
|
* make the Wacom driver pickup touch ring extents
|
||||||
|
*/
|
||||||
|
if (frame->touch_byte > 0)
|
||||||
|
__clear_bit(EV_MSC, hi->input->evbit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (field->application) {
|
if (!suffix) {
|
||||||
case HID_GD_KEYBOARD:
|
field = hi->report->field[0];
|
||||||
suffix = "Keyboard";
|
|
||||||
break;
|
switch (field->application) {
|
||||||
case HID_GD_MOUSE:
|
case HID_GD_KEYBOARD:
|
||||||
suffix = "Mouse";
|
suffix = "Keyboard";
|
||||||
break;
|
break;
|
||||||
case HID_GD_KEYPAD:
|
case HID_GD_MOUSE:
|
||||||
suffix = "Pad";
|
suffix = "Mouse";
|
||||||
break;
|
break;
|
||||||
case HID_DG_PEN:
|
case HID_GD_KEYPAD:
|
||||||
suffix = "Pen";
|
suffix = "Pad";
|
||||||
break;
|
break;
|
||||||
case HID_CP_CONSUMER_CONTROL:
|
case HID_DG_PEN:
|
||||||
suffix = "Consumer Control";
|
suffix = "Pen";
|
||||||
break;
|
break;
|
||||||
case HID_GD_SYSTEM_CONTROL:
|
case HID_CP_CONSUMER_CONTROL:
|
||||||
suffix = "System Control";
|
suffix = "Consumer Control";
|
||||||
break;
|
break;
|
||||||
|
case HID_GD_SYSTEM_CONTROL:
|
||||||
|
suffix = "System Control";
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (suffix) {
|
if (suffix) {
|
||||||
|
@ -172,8 +209,8 @@ static int uclogic_probe(struct hid_device *hdev,
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
params_initialized = true;
|
params_initialized = true;
|
||||||
hid_dbg(hdev, "parameters:\n" UCLOGIC_PARAMS_FMT_STR,
|
hid_dbg(hdev, "parameters:\n");
|
||||||
UCLOGIC_PARAMS_FMT_ARGS(&drvdata->params));
|
uclogic_params_hid_dbg(hdev, &drvdata->params);
|
||||||
if (drvdata->params.invalid) {
|
if (drvdata->params.invalid) {
|
||||||
hid_info(hdev, "interface is invalid, ignoring\n");
|
hid_info(hdev, "interface is invalid, ignoring\n");
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
|
@ -313,8 +350,15 @@ static int uclogic_raw_event_frame(
|
||||||
|
|
||||||
/* If need to, and can, set pad device ID for Wacom drivers */
|
/* If need to, and can, set pad device ID for Wacom drivers */
|
||||||
if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
|
if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
|
||||||
data[frame->dev_id_byte] = 0xf;
|
/* If we also have a touch ring and the finger left it */
|
||||||
|
if (frame->touch_byte > 0 && frame->touch_byte < size &&
|
||||||
|
data[frame->touch_byte] == 0) {
|
||||||
|
data[frame->dev_id_byte] = 0;
|
||||||
|
} else {
|
||||||
|
data[frame->dev_id_byte] = 0xf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If need to, and can, read rotary encoder state change */
|
/* If need to, and can, read rotary encoder state change */
|
||||||
if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
|
if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
|
||||||
unsigned int byte = frame->re_lsb / 8;
|
unsigned int byte = frame->re_lsb / 8;
|
||||||
|
@ -341,6 +385,26 @@ static int uclogic_raw_event_frame(
|
||||||
drvdata->re_state = state;
|
drvdata->re_state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If need to, and can, transform the touch ring reports */
|
||||||
|
if (frame->touch_byte > 0 && frame->touch_byte < size) {
|
||||||
|
__s8 value = data[frame->touch_byte];
|
||||||
|
|
||||||
|
if (value != 0) {
|
||||||
|
if (frame->touch_flip_at != 0) {
|
||||||
|
value = frame->touch_flip_at - value;
|
||||||
|
if (value <= 0)
|
||||||
|
value = frame->touch_max + value;
|
||||||
|
}
|
||||||
|
data[frame->touch_byte] = value - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If need to, and can, transform the bitmap dial reports */
|
||||||
|
if (frame->bitmap_dial_byte > 0 && frame->bitmap_dial_byte < size) {
|
||||||
|
if (data[frame->bitmap_dial_byte] == 2)
|
||||||
|
data[frame->bitmap_dial_byte] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,6 +521,8 @@ static const struct hid_device_id uclogic_devices[] = {
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
|
||||||
|
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||||
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(hid, uclogic_devices);
|
MODULE_DEVICE_TABLE(hid, uclogic_devices);
|
||||||
|
@ -468,6 +534,7 @@ static struct hid_driver uclogic_driver = {
|
||||||
.remove = uclogic_remove,
|
.remove = uclogic_remove,
|
||||||
.report_fixup = uclogic_report_fixup,
|
.report_fixup = uclogic_report_fixup,
|
||||||
.raw_event = uclogic_raw_event,
|
.raw_event = uclogic_raw_event,
|
||||||
|
.input_mapping = uclogic_input_mapping,
|
||||||
.input_configured = uclogic_input_configured,
|
.input_configured = uclogic_input_configured,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.resume = uclogic_resume,
|
.resume = uclogic_resume,
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
* Returns:
|
* Returns:
|
||||||
* The string representing the type, or NULL if the type is unknown.
|
* The string representing the type, or NULL if the type is unknown.
|
||||||
*/
|
*/
|
||||||
const char *uclogic_params_pen_inrange_to_str(
|
static const char *uclogic_params_pen_inrange_to_str(
|
||||||
enum uclogic_params_pen_inrange inrange)
|
enum uclogic_params_pen_inrange inrange)
|
||||||
{
|
{
|
||||||
switch (inrange) {
|
switch (inrange) {
|
||||||
case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
|
case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
|
||||||
|
@ -44,6 +44,91 @@ const char *uclogic_params_pen_inrange_to_str(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump tablet interface pen parameters with hid_dbg(), indented with one tab.
|
||||||
|
*
|
||||||
|
* @hdev: The HID device the pen parameters describe.
|
||||||
|
* @pen: The pen parameters to dump.
|
||||||
|
*/
|
||||||
|
static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev,
|
||||||
|
const struct uclogic_params_pen *pen)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
hid_dbg(hdev, "\t.usage_invalid = %s\n",
|
||||||
|
(pen->usage_invalid ? "true" : "false"));
|
||||||
|
hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr);
|
||||||
|
hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size);
|
||||||
|
hid_dbg(hdev, "\t.id = %u\n", pen->id);
|
||||||
|
hid_dbg(hdev, "\t.subreport_list = {\n");
|
||||||
|
for (i = 0; i < ARRAY_SIZE(pen->subreport_list); i++) {
|
||||||
|
hid_dbg(hdev, "\t\t{0x%02hhx, %hhu}%s\n",
|
||||||
|
pen->subreport_list[i].value,
|
||||||
|
pen->subreport_list[i].id,
|
||||||
|
i < (ARRAY_SIZE(pen->subreport_list) - 1) ? "," : "");
|
||||||
|
}
|
||||||
|
hid_dbg(hdev, "\t}\n");
|
||||||
|
hid_dbg(hdev, "\t.inrange = %s\n",
|
||||||
|
uclogic_params_pen_inrange_to_str(pen->inrange));
|
||||||
|
hid_dbg(hdev, "\t.fragmented_hires = %s\n",
|
||||||
|
(pen->fragmented_hires ? "true" : "false"));
|
||||||
|
hid_dbg(hdev, "\t.tilt_y_flipped = %s\n",
|
||||||
|
(pen->tilt_y_flipped ? "true" : "false"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump tablet interface frame parameters with hid_dbg(), indented with two
|
||||||
|
* tabs.
|
||||||
|
*
|
||||||
|
* @hdev: The HID device the pen parameters describe.
|
||||||
|
* @frame: The frame parameters to dump.
|
||||||
|
*/
|
||||||
|
static void uclogic_params_frame_hid_dbg(
|
||||||
|
const struct hid_device *hdev,
|
||||||
|
const struct uclogic_params_frame *frame)
|
||||||
|
{
|
||||||
|
hid_dbg(hdev, "\t\t.desc_ptr = %p\n", frame->desc_ptr);
|
||||||
|
hid_dbg(hdev, "\t\t.desc_size = %u\n", frame->desc_size);
|
||||||
|
hid_dbg(hdev, "\t\t.id = %u\n", frame->id);
|
||||||
|
hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix);
|
||||||
|
hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb);
|
||||||
|
hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte);
|
||||||
|
hid_dbg(hdev, "\t\t.touch_byte = %u\n", frame->touch_byte);
|
||||||
|
hid_dbg(hdev, "\t\t.touch_max = %hhd\n", frame->touch_max);
|
||||||
|
hid_dbg(hdev, "\t\t.touch_flip_at = %hhd\n",
|
||||||
|
frame->touch_flip_at);
|
||||||
|
hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
|
||||||
|
frame->bitmap_dial_byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump tablet interface parameters with hid_dbg().
|
||||||
|
*
|
||||||
|
* @hdev: The HID device the parameters describe.
|
||||||
|
* @params: The parameters to dump.
|
||||||
|
*/
|
||||||
|
void uclogic_params_hid_dbg(const struct hid_device *hdev,
|
||||||
|
const struct uclogic_params *params)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
hid_dbg(hdev, ".invalid = %s\n",
|
||||||
|
params->invalid ? "true" : "false");
|
||||||
|
hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr);
|
||||||
|
hid_dbg(hdev, ".desc_size = %u\n", params->desc_size);
|
||||||
|
hid_dbg(hdev, ".pen = {\n");
|
||||||
|
uclogic_params_pen_hid_dbg(hdev, ¶ms->pen);
|
||||||
|
hid_dbg(hdev, "\t}\n");
|
||||||
|
hid_dbg(hdev, ".frame_list = {\n");
|
||||||
|
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
|
||||||
|
hid_dbg(hdev, "\t{\n");
|
||||||
|
uclogic_params_frame_hid_dbg(hdev, ¶ms->frame_list[i]);
|
||||||
|
hid_dbg(hdev, "\t}%s\n",
|
||||||
|
i < (ARRAY_SIZE(params->frame_list) - 1) ? "," : "");
|
||||||
|
}
|
||||||
|
hid_dbg(hdev, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* uclogic_params_get_str_desc - retrieve a string descriptor from a HID
|
* uclogic_params_get_str_desc - retrieve a string descriptor from a HID
|
||||||
* device interface, putting it into a kmalloc-allocated buffer as is, without
|
* device interface, putting it into a kmalloc-allocated buffer as is, without
|
||||||
|
@ -253,28 +338,45 @@ static s32 uclogic_params_get_le24(const void *p)
|
||||||
* uclogic_params_pen_init_v2() - initialize tablet interface pen
|
* uclogic_params_pen_init_v2() - initialize tablet interface pen
|
||||||
* input and retrieve its parameters from the device, using v2 protocol.
|
* input and retrieve its parameters from the device, using v2 protocol.
|
||||||
*
|
*
|
||||||
* @pen: Pointer to the pen parameters to initialize (to be
|
* @pen: Pointer to the pen parameters to initialize (to be
|
||||||
* cleaned up with uclogic_params_pen_cleanup()). Not modified in
|
* cleaned up with uclogic_params_pen_cleanup()). Not
|
||||||
* case of error, or if parameters are not found. Cannot be NULL.
|
* modified in case of error, or if parameters are not
|
||||||
* @pfound: Location for a flag which is set to true if the parameters
|
* found. Cannot be NULL.
|
||||||
* were found, and to false if not (e.g. device was
|
* @pfound: Location for a flag which is set to true if the
|
||||||
* incompatible). Not modified in case of error. Cannot be NULL.
|
* parameters were found, and to false if not (e.g.
|
||||||
* @hdev: The HID device of the tablet interface to initialize and get
|
* device was incompatible). Not modified in case of
|
||||||
* parameters from. Cannot be NULL.
|
* error. Cannot be NULL.
|
||||||
|
* @pparams_ptr: Location for a kmalloc'ed pointer to the retrieved raw
|
||||||
|
* parameters, which could be used to identify the tablet
|
||||||
|
* to some extent. Should be freed with kfree after use.
|
||||||
|
* NULL, if not needed. Not modified in case of error.
|
||||||
|
* Only set if *pfound is set to true.
|
||||||
|
* @pparams_len: Location for the length of the retrieved raw
|
||||||
|
* parameters. NULL, if not needed. Not modified in case
|
||||||
|
* of error. Only set if *pfound is set to true.
|
||||||
|
* @hdev: The HID device of the tablet interface to initialize
|
||||||
|
* and get parameters from. Cannot be NULL.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* Zero, if successful. A negative errno code on error.
|
* Zero, if successful. A negative errno code on error.
|
||||||
*/
|
*/
|
||||||
static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
||||||
bool *pfound,
|
bool *pfound,
|
||||||
|
__u8 **pparams_ptr,
|
||||||
|
size_t *pparams_len,
|
||||||
struct hid_device *hdev)
|
struct hid_device *hdev)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
/* Buffer for (part of) the string descriptor */
|
/* Buffer for (part of) the parameter string descriptor */
|
||||||
__u8 *buf = NULL;
|
__u8 *buf = NULL;
|
||||||
/* Descriptor length required */
|
/* Parameter string descriptor required length */
|
||||||
const int len = 18;
|
const int params_len_min = 18;
|
||||||
|
/* Parameter string descriptor accepted length */
|
||||||
|
const int params_len_max = 32;
|
||||||
|
/* Parameter string descriptor received length */
|
||||||
|
int params_len;
|
||||||
|
size_t i;
|
||||||
s32 resolution;
|
s32 resolution;
|
||||||
/* Pen report descriptor template parameters */
|
/* Pen report descriptor template parameters */
|
||||||
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
|
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
|
||||||
|
@ -292,7 +394,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
||||||
* the Windows driver traffic.
|
* the Windows driver traffic.
|
||||||
* NOTE: This enables fully-functional tablet mode.
|
* NOTE: This enables fully-functional tablet mode.
|
||||||
*/
|
*/
|
||||||
rc = uclogic_params_get_str_desc(&buf, hdev, 200, len);
|
rc = uclogic_params_get_str_desc(&buf, hdev, 200, params_len_max);
|
||||||
if (rc == -EPIPE) {
|
if (rc == -EPIPE) {
|
||||||
hid_dbg(hdev,
|
hid_dbg(hdev,
|
||||||
"string descriptor with pen parameters not found, assuming not compatible\n");
|
"string descriptor with pen parameters not found, assuming not compatible\n");
|
||||||
|
@ -300,27 +402,28 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
||||||
} else if (rc < 0) {
|
} else if (rc < 0) {
|
||||||
hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
|
hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if (rc != len) {
|
} else if (rc < params_len_min) {
|
||||||
hid_dbg(hdev,
|
hid_dbg(hdev,
|
||||||
"string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
|
"string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n",
|
||||||
rc, len);
|
rc, params_len_min);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
params_len = rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check it's not just a catch-all UTF-16LE-encoded ASCII
|
||||||
|
* string (such as the model name) some tablets put into all
|
||||||
|
* unknown string descriptors.
|
||||||
|
*/
|
||||||
|
for (i = 2;
|
||||||
|
i < params_len &&
|
||||||
|
(buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
|
||||||
|
i += 2);
|
||||||
|
if (i >= params_len) {
|
||||||
|
hid_dbg(hdev,
|
||||||
|
"string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
|
||||||
goto finish;
|
goto finish;
|
||||||
} else {
|
|
||||||
size_t i;
|
|
||||||
/*
|
|
||||||
* Check it's not just a catch-all UTF-16LE-encoded ASCII
|
|
||||||
* string (such as the model name) some tablets put into all
|
|
||||||
* unknown string descriptors.
|
|
||||||
*/
|
|
||||||
for (i = 2;
|
|
||||||
i < len &&
|
|
||||||
(buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
|
|
||||||
i += 2);
|
|
||||||
if (i >= len) {
|
|
||||||
hid_dbg(hdev,
|
|
||||||
"string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -344,8 +447,6 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
||||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
|
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
|
||||||
resolution;
|
resolution;
|
||||||
}
|
}
|
||||||
kfree(buf);
|
|
||||||
buf = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate pen report descriptor
|
* Generate pen report descriptor
|
||||||
|
@ -371,6 +472,13 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
|
||||||
pen->fragmented_hires = true;
|
pen->fragmented_hires = true;
|
||||||
pen->tilt_y_flipped = true;
|
pen->tilt_y_flipped = true;
|
||||||
found = true;
|
found = true;
|
||||||
|
if (pparams_ptr != NULL) {
|
||||||
|
*pparams_ptr = buf;
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
if (pparams_len != NULL)
|
||||||
|
*pparams_len = params_len;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
*pfound = found;
|
*pfound = found;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
@ -700,6 +808,14 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
|
||||||
static const char transition_ver[] = "HUION_T153_160607";
|
static const char transition_ver[] = "HUION_T153_160607";
|
||||||
char *ver_ptr = NULL;
|
char *ver_ptr = NULL;
|
||||||
const size_t ver_len = sizeof(transition_ver) + 1;
|
const size_t ver_len = sizeof(transition_ver) + 1;
|
||||||
|
__u8 *params_ptr = NULL;
|
||||||
|
size_t params_len = 0;
|
||||||
|
/* Parameters string descriptor of a model with touch ring (HS610) */
|
||||||
|
const __u8 touch_ring_model_params_buf[] = {
|
||||||
|
0x13, 0x03, 0x70, 0xC6, 0x00, 0x06, 0x7C, 0x00,
|
||||||
|
0xFF, 0x1F, 0xD8, 0x13, 0x03, 0x0D, 0x10, 0x01,
|
||||||
|
0x04, 0x3C, 0x3E
|
||||||
|
};
|
||||||
|
|
||||||
/* Check arguments */
|
/* Check arguments */
|
||||||
if (params == NULL || hdev == NULL) {
|
if (params == NULL || hdev == NULL) {
|
||||||
|
@ -711,8 +827,13 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
|
||||||
iface = to_usb_interface(hdev->dev.parent);
|
iface = to_usb_interface(hdev->dev.parent);
|
||||||
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
|
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
|
||||||
|
|
||||||
/* If it's not a pen interface */
|
/* If it's a custom keyboard interface */
|
||||||
if (bInterfaceNumber != 0) {
|
if (bInterfaceNumber == 1) {
|
||||||
|
/* Keep everything intact, but mark pen usage invalid */
|
||||||
|
p.pen.usage_invalid = true;
|
||||||
|
goto output;
|
||||||
|
/* Else, if it's not a pen interface */
|
||||||
|
} else if (bInterfaceNumber != 0) {
|
||||||
uclogic_params_init_invalid(&p);
|
uclogic_params_init_invalid(&p);
|
||||||
goto output;
|
goto output;
|
||||||
}
|
}
|
||||||
|
@ -738,29 +859,103 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
|
||||||
"transition firmware detected, not probing pen v2 parameters\n");
|
"transition firmware detected, not probing pen v2 parameters\n");
|
||||||
} else {
|
} else {
|
||||||
/* Try to probe v2 pen parameters */
|
/* Try to probe v2 pen parameters */
|
||||||
rc = uclogic_params_pen_init_v2(&p.pen, &found, hdev);
|
rc = uclogic_params_pen_init_v2(&p.pen, &found,
|
||||||
|
¶ms_ptr, ¶ms_len,
|
||||||
|
hdev);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
hid_err(hdev,
|
hid_err(hdev,
|
||||||
"failed probing pen v2 parameters: %d\n", rc);
|
"failed probing pen v2 parameters: %d\n", rc);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else if (found) {
|
} else if (found) {
|
||||||
hid_dbg(hdev, "pen v2 parameters found\n");
|
hid_dbg(hdev, "pen v2 parameters found\n");
|
||||||
/* Create v2 frame parameters */
|
/* Create v2 frame button parameters */
|
||||||
rc = uclogic_params_frame_init_with_desc(
|
rc = uclogic_params_frame_init_with_desc(
|
||||||
&p.frame_list[0],
|
&p.frame_list[0],
|
||||||
uclogic_rdesc_v2_frame_arr,
|
uclogic_rdesc_v2_frame_buttons_arr,
|
||||||
uclogic_rdesc_v2_frame_size,
|
uclogic_rdesc_v2_frame_buttons_size,
|
||||||
UCLOGIC_RDESC_V2_FRAME_ID);
|
UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
hid_err(hdev,
|
hid_err(hdev,
|
||||||
"failed creating v2 frame parameters: %d\n",
|
"failed creating v2 frame button parameters: %d\n",
|
||||||
rc);
|
rc);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
/* Link frame button subreports from pen reports */
|
|
||||||
|
/* Link from pen sub-report */
|
||||||
p.pen.subreport_list[0].value = 0xe0;
|
p.pen.subreport_list[0].value = 0xe0;
|
||||||
p.pen.subreport_list[0].id =
|
p.pen.subreport_list[0].id =
|
||||||
UCLOGIC_RDESC_V2_FRAME_ID;
|
UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID;
|
||||||
|
|
||||||
|
/* If this is the model with touch ring */
|
||||||
|
if (params_ptr != NULL &&
|
||||||
|
params_len == sizeof(touch_ring_model_params_buf) &&
|
||||||
|
memcmp(params_ptr, touch_ring_model_params_buf,
|
||||||
|
params_len) == 0) {
|
||||||
|
/* Create touch ring parameters */
|
||||||
|
rc = uclogic_params_frame_init_with_desc(
|
||||||
|
&p.frame_list[1],
|
||||||
|
uclogic_rdesc_v2_frame_touch_ring_arr,
|
||||||
|
uclogic_rdesc_v2_frame_touch_ring_size,
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
|
||||||
|
if (rc != 0) {
|
||||||
|
hid_err(hdev,
|
||||||
|
"failed creating v2 frame touch ring parameters: %d\n",
|
||||||
|
rc);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
p.frame_list[1].suffix = "Touch Ring";
|
||||||
|
p.frame_list[1].dev_id_byte =
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
|
||||||
|
p.frame_list[1].touch_byte = 5;
|
||||||
|
p.frame_list[1].touch_max = 12;
|
||||||
|
p.frame_list[1].touch_flip_at = 7;
|
||||||
|
} else {
|
||||||
|
/* Create touch strip parameters */
|
||||||
|
rc = uclogic_params_frame_init_with_desc(
|
||||||
|
&p.frame_list[1],
|
||||||
|
uclogic_rdesc_v2_frame_touch_strip_arr,
|
||||||
|
uclogic_rdesc_v2_frame_touch_strip_size,
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
|
||||||
|
if (rc != 0) {
|
||||||
|
hid_err(hdev,
|
||||||
|
"failed creating v2 frame touch strip parameters: %d\n",
|
||||||
|
rc);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
p.frame_list[1].suffix = "Touch Strip";
|
||||||
|
p.frame_list[1].dev_id_byte =
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
|
||||||
|
p.frame_list[1].touch_byte = 5;
|
||||||
|
p.frame_list[1].touch_max = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link from pen sub-report */
|
||||||
|
p.pen.subreport_list[1].value = 0xf0;
|
||||||
|
p.pen.subreport_list[1].id =
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_TOUCH_ID;
|
||||||
|
|
||||||
|
/* Create v2 frame dial parameters */
|
||||||
|
rc = uclogic_params_frame_init_with_desc(
|
||||||
|
&p.frame_list[2],
|
||||||
|
uclogic_rdesc_v2_frame_dial_arr,
|
||||||
|
uclogic_rdesc_v2_frame_dial_size,
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_DIAL_ID);
|
||||||
|
if (rc != 0) {
|
||||||
|
hid_err(hdev,
|
||||||
|
"failed creating v2 frame dial parameters: %d\n",
|
||||||
|
rc);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
p.frame_list[2].suffix = "Dial";
|
||||||
|
p.frame_list[2].dev_id_byte =
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE;
|
||||||
|
p.frame_list[2].bitmap_dial_byte = 5;
|
||||||
|
|
||||||
|
/* Link from pen sub-report */
|
||||||
|
p.pen.subreport_list[2].value = 0xf1;
|
||||||
|
p.pen.subreport_list[2].id =
|
||||||
|
UCLOGIC_RDESC_V2_FRAME_DIAL_ID;
|
||||||
|
|
||||||
goto output;
|
goto output;
|
||||||
}
|
}
|
||||||
hid_dbg(hdev, "pen v2 parameters not found\n");
|
hid_dbg(hdev, "pen v2 parameters not found\n");
|
||||||
|
@ -801,6 +996,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
|
||||||
memset(&p, 0, sizeof(p));
|
memset(&p, 0, sizeof(p));
|
||||||
rc = 0;
|
rc = 0;
|
||||||
cleanup:
|
cleanup:
|
||||||
|
kfree(params_ptr);
|
||||||
kfree(ver_ptr);
|
kfree(ver_ptr);
|
||||||
uclogic_params_cleanup(&p);
|
uclogic_params_cleanup(&p);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -999,6 +1195,8 @@ int uclogic_params_init(struct uclogic_params *params,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
|
||||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
|
||||||
|
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||||
|
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06):
|
||||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||||
USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
|
USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
|
||||||
/* If this is the pen interface */
|
/* If this is the pen interface */
|
||||||
|
|
|
@ -29,11 +29,6 @@ enum uclogic_params_pen_inrange {
|
||||||
UCLOGIC_PARAMS_PEN_INRANGE_NONE,
|
UCLOGIC_PARAMS_PEN_INRANGE_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Convert a pen in-range reporting type to a string */
|
|
||||||
extern const char *uclogic_params_pen_inrange_to_str(
|
|
||||||
enum uclogic_params_pen_inrange inrange);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pen report's subreport data.
|
* Pen report's subreport data.
|
||||||
*/
|
*/
|
||||||
|
@ -62,8 +57,13 @@ struct uclogic_params_pen_subreport {
|
||||||
*/
|
*/
|
||||||
struct uclogic_params_pen {
|
struct uclogic_params_pen {
|
||||||
/*
|
/*
|
||||||
* Pointer to report descriptor describing the inputs.
|
* True if pen usage is invalid for this interface and should be
|
||||||
* Allocated with kmalloc.
|
* ignored, false otherwise.
|
||||||
|
*/
|
||||||
|
bool usage_invalid;
|
||||||
|
/*
|
||||||
|
* Pointer to report descriptor part describing the pen inputs.
|
||||||
|
* Allocated with kmalloc. NULL if the part is not specified.
|
||||||
*/
|
*/
|
||||||
__u8 *desc_ptr;
|
__u8 *desc_ptr;
|
||||||
/*
|
/*
|
||||||
|
@ -73,8 +73,8 @@ struct uclogic_params_pen {
|
||||||
unsigned int desc_size;
|
unsigned int desc_size;
|
||||||
/* Report ID, if reports should be tweaked, zero if not */
|
/* Report ID, if reports should be tweaked, zero if not */
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
/* The list of subreports */
|
/* The list of subreports, only valid if "id" is not zero */
|
||||||
struct uclogic_params_pen_subreport subreport_list[1];
|
struct uclogic_params_pen_subreport subreport_list[3];
|
||||||
/* Type of in-range reporting, only valid if "id" is not zero */
|
/* Type of in-range reporting, only valid if "id" is not zero */
|
||||||
enum uclogic_params_pen_inrange inrange;
|
enum uclogic_params_pen_inrange inrange;
|
||||||
/*
|
/*
|
||||||
|
@ -101,8 +101,8 @@ struct uclogic_params_pen {
|
||||||
*/
|
*/
|
||||||
struct uclogic_params_frame {
|
struct uclogic_params_frame {
|
||||||
/*
|
/*
|
||||||
* Pointer to report descriptor describing the inputs.
|
* Pointer to report descriptor part describing the frame inputs.
|
||||||
* Allocated with kmalloc.
|
* Allocated with kmalloc. NULL if the part is not specified.
|
||||||
*/
|
*/
|
||||||
__u8 *desc_ptr;
|
__u8 *desc_ptr;
|
||||||
/*
|
/*
|
||||||
|
@ -114,6 +114,10 @@ struct uclogic_params_frame {
|
||||||
* Report ID, if reports should be tweaked, zero if not.
|
* Report ID, if reports should be tweaked, zero if not.
|
||||||
*/
|
*/
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
/*
|
||||||
|
* The suffix to add to the input device name, if not NULL.
|
||||||
|
*/
|
||||||
|
const char *suffix;
|
||||||
/*
|
/*
|
||||||
* Number of the least-significant bit of the 2-bit state of a rotary
|
* Number of the least-significant bit of the 2-bit state of a rotary
|
||||||
* encoder, in the report. Cannot point to a 2-bit field crossing a
|
* encoder, in the report. Cannot point to a 2-bit field crossing a
|
||||||
|
@ -123,10 +127,40 @@ struct uclogic_params_frame {
|
||||||
/*
|
/*
|
||||||
* Offset of the Wacom-style device ID byte in the report, to be set
|
* Offset of the Wacom-style device ID byte in the report, to be set
|
||||||
* to pad device ID (0xf), for compatibility with Wacom drivers. Zero
|
* to pad device ID (0xf), for compatibility with Wacom drivers. Zero
|
||||||
* if no changes to the report should be made. Only valid if "id" is
|
* if no changes to the report should be made. The ID byte will be set
|
||||||
* not zero.
|
* to zero whenever the byte pointed by "touch_byte" is zero, if
|
||||||
|
* the latter is valid. Only valid if "id" is not zero.
|
||||||
*/
|
*/
|
||||||
unsigned int dev_id_byte;
|
unsigned int dev_id_byte;
|
||||||
|
/*
|
||||||
|
* Offset of the touch ring/strip state byte, in the report.
|
||||||
|
* Zero if not present. If dev_id_byte is also valid and non-zero,
|
||||||
|
* then the device ID byte will be cleared when the byte pointed to by
|
||||||
|
* this offset is zero. Only valid if "id" is not zero.
|
||||||
|
*/
|
||||||
|
unsigned int touch_byte;
|
||||||
|
/*
|
||||||
|
* The value to anchor the reversed touch ring/strip reports at.
|
||||||
|
* I.e. one, if the reports should be flipped without offset.
|
||||||
|
* Zero if no reversal should be done.
|
||||||
|
* Only valid if "touch_byte" is valid and not zero.
|
||||||
|
*/
|
||||||
|
__s8 touch_flip_at;
|
||||||
|
/*
|
||||||
|
* Maximum value of the touch ring/strip report around which the value
|
||||||
|
* should be wrapped when flipping according to "touch_flip_at".
|
||||||
|
* The minimum valid value is considered to be one, with zero being
|
||||||
|
* out-of-proximity (finger lift) value.
|
||||||
|
* Only valid if "touch_flip_at" is valid and not zero.
|
||||||
|
*/
|
||||||
|
__s8 touch_max;
|
||||||
|
/*
|
||||||
|
* Offset of the bitmap dial byte, in the report. Zero if not present.
|
||||||
|
* Only valid if "id" is not zero. A bitmap dial sends reports with a
|
||||||
|
* dedicated bit per direction: 1 means clockwise rotation, 2 means
|
||||||
|
* counterclockwise, as opposed to the normal 1 and -1.
|
||||||
|
*/
|
||||||
|
unsigned int bitmap_dial_byte;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -156,7 +190,7 @@ struct uclogic_params {
|
||||||
__u8 *desc_ptr;
|
__u8 *desc_ptr;
|
||||||
/*
|
/*
|
||||||
* Size of the common part of the replacement report descriptor.
|
* Size of the common part of the replacement report descriptor.
|
||||||
* Only valid, if "desc_ptr" is not NULL.
|
* Only valid, if "desc_ptr" is valid and not NULL.
|
||||||
*/
|
*/
|
||||||
unsigned int desc_size;
|
unsigned int desc_size;
|
||||||
/*
|
/*
|
||||||
|
@ -168,50 +202,13 @@ struct uclogic_params {
|
||||||
* The list of frame control parameters and optional report descriptor
|
* The list of frame control parameters and optional report descriptor
|
||||||
* parts. Only valid, if "invalid" is false.
|
* parts. Only valid, if "invalid" is false.
|
||||||
*/
|
*/
|
||||||
struct uclogic_params_frame frame_list[1];
|
struct uclogic_params_frame frame_list[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Initialize a tablet interface and discover its parameters */
|
/* Initialize a tablet interface and discover its parameters */
|
||||||
extern int uclogic_params_init(struct uclogic_params *params,
|
extern int uclogic_params_init(struct uclogic_params *params,
|
||||||
struct hid_device *hdev);
|
struct hid_device *hdev);
|
||||||
|
|
||||||
/* Tablet interface parameters *printf format string */
|
|
||||||
#define UCLOGIC_PARAMS_FMT_STR \
|
|
||||||
".invalid = %s\n" \
|
|
||||||
".desc_ptr = %p\n" \
|
|
||||||
".desc_size = %u\n" \
|
|
||||||
".pen.desc_ptr = %p\n" \
|
|
||||||
".pen.desc_size = %u\n" \
|
|
||||||
".pen.id = %u\n" \
|
|
||||||
".pen.subreport_list[0] = {0x%02hhx, %hhu}\n" \
|
|
||||||
".pen.inrange = %s\n" \
|
|
||||||
".pen.fragmented_hires = %s\n" \
|
|
||||||
".pen.tilt_y_flipped = %s\n" \
|
|
||||||
".frame_list[0].desc_ptr = %p\n" \
|
|
||||||
".frame_list[0].desc_size = %u\n" \
|
|
||||||
".frame_list[0].id = %u\n" \
|
|
||||||
".frame_list[0].re_lsb = %u\n" \
|
|
||||||
".frame_list[0].dev_id_byte = %u\n"
|
|
||||||
|
|
||||||
/* Tablet interface parameters *printf format arguments */
|
|
||||||
#define UCLOGIC_PARAMS_FMT_ARGS(_params) \
|
|
||||||
((_params)->invalid ? "true" : "false"), \
|
|
||||||
(_params)->desc_ptr, \
|
|
||||||
(_params)->desc_size, \
|
|
||||||
(_params)->pen.desc_ptr, \
|
|
||||||
(_params)->pen.desc_size, \
|
|
||||||
(_params)->pen.id, \
|
|
||||||
(_params)->pen.subreport_list[0].value, \
|
|
||||||
(_params)->pen.subreport_list[0].id, \
|
|
||||||
uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \
|
|
||||||
((_params)->pen.fragmented_hires ? "true" : "false"), \
|
|
||||||
((_params)->pen.tilt_y_flipped ? "true" : "false"), \
|
|
||||||
(_params)->frame_list[0].desc_ptr, \
|
|
||||||
(_params)->frame_list[0].desc_size, \
|
|
||||||
(_params)->frame_list[0].id, \
|
|
||||||
(_params)->frame_list[0].re_lsb, \
|
|
||||||
(_params)->frame_list[0].dev_id_byte
|
|
||||||
|
|
||||||
/* Get a replacement report descriptor for a tablet's interface. */
|
/* Get a replacement report descriptor for a tablet's interface. */
|
||||||
extern int uclogic_params_get_desc(const struct uclogic_params *params,
|
extern int uclogic_params_get_desc(const struct uclogic_params *params,
|
||||||
__u8 **pdesc,
|
__u8 **pdesc,
|
||||||
|
@ -220,4 +217,8 @@ extern int uclogic_params_get_desc(const struct uclogic_params *params,
|
||||||
/* Free resources used by tablet interface's parameters */
|
/* Free resources used by tablet interface's parameters */
|
||||||
extern void uclogic_params_cleanup(struct uclogic_params *params);
|
extern void uclogic_params_cleanup(struct uclogic_params *params);
|
||||||
|
|
||||||
|
/* Dump tablet interface parameters with hid_dbg() */
|
||||||
|
extern void uclogic_params_hid_dbg(const struct hid_device *hdev,
|
||||||
|
const struct uclogic_params *params);
|
||||||
|
|
||||||
#endif /* _HID_UCLOGIC_PARAMS_H */
|
#endif /* _HID_UCLOGIC_PARAMS_H */
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
/* Fixed WP4030U report descriptor */
|
/* Fixed WP4030U report descriptor */
|
||||||
__u8 uclogic_rdesc_wp4030u_fixed_arr[] = {
|
__u8 uclogic_rdesc_wp4030u_fixed_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x09, /* Report ID (9), */
|
0x85, 0x09, /* Report ID (9), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -66,7 +66,7 @@ const size_t uclogic_rdesc_wp4030u_fixed_size =
|
||||||
/* Fixed WP5540U report descriptor */
|
/* Fixed WP5540U report descriptor */
|
||||||
__u8 uclogic_rdesc_wp5540u_fixed_arr[] = {
|
__u8 uclogic_rdesc_wp5540u_fixed_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x09, /* Report ID (9), */
|
0x85, 0x09, /* Report ID (9), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -143,7 +143,7 @@ const size_t uclogic_rdesc_wp5540u_fixed_size =
|
||||||
/* Fixed WP8060U report descriptor */
|
/* Fixed WP8060U report descriptor */
|
||||||
__u8 uclogic_rdesc_wp8060u_fixed_arr[] = {
|
__u8 uclogic_rdesc_wp8060u_fixed_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x09, /* Report ID (9), */
|
0x85, 0x09, /* Report ID (9), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -220,7 +220,7 @@ const size_t uclogic_rdesc_wp8060u_fixed_size =
|
||||||
/* Fixed WP1062 report descriptor */
|
/* Fixed WP1062 report descriptor */
|
||||||
__u8 uclogic_rdesc_wp1062_fixed_arr[] = {
|
__u8 uclogic_rdesc_wp1062_fixed_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x09, /* Report ID (9), */
|
0x85, 0x09, /* Report ID (9), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -268,7 +268,7 @@ const size_t uclogic_rdesc_wp1062_fixed_size =
|
||||||
/* Fixed PF1209 report descriptor */
|
/* Fixed PF1209 report descriptor */
|
||||||
__u8 uclogic_rdesc_pf1209_fixed_arr[] = {
|
__u8 uclogic_rdesc_pf1209_fixed_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x09, /* Report ID (9), */
|
0x85, 0x09, /* Report ID (9), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -345,7 +345,7 @@ const size_t uclogic_rdesc_pf1209_fixed_size =
|
||||||
/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
|
/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
|
||||||
__u8 uclogic_rdesc_twhl850_fixed0_arr[] = {
|
__u8 uclogic_rdesc_twhl850_fixed0_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x09, /* Report ID (9), */
|
0x85, 0x09, /* Report ID (9), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -457,7 +457,7 @@ const size_t uclogic_rdesc_twhl850_fixed2_size =
|
||||||
/* Fixed TWHA60 report descriptor, interface 0 (stylus) */
|
/* Fixed TWHA60 report descriptor, interface 0 (stylus) */
|
||||||
__u8 uclogic_rdesc_twha60_fixed0_arr[] = {
|
__u8 uclogic_rdesc_twha60_fixed0_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x09, /* Report ID (9), */
|
0x85, 0x09, /* Report ID (9), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -534,7 +534,7 @@ const size_t uclogic_rdesc_twha60_fixed1_size =
|
||||||
/* Fixed report descriptor template for (tweaked) v1 pen reports */
|
/* Fixed report descriptor template for (tweaked) v1 pen reports */
|
||||||
const __u8 uclogic_rdesc_v1_pen_template_arr[] = {
|
const __u8 uclogic_rdesc_v1_pen_template_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x07, /* Report ID (7), */
|
0x85, 0x07, /* Report ID (7), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -588,7 +588,7 @@ const size_t uclogic_rdesc_v1_pen_template_size =
|
||||||
/* Fixed report descriptor template for (tweaked) v2 pen reports */
|
/* Fixed report descriptor template for (tweaked) v2 pen reports */
|
||||||
const __u8 uclogic_rdesc_v2_pen_template_arr[] = {
|
const __u8 uclogic_rdesc_v2_pen_template_arr[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x08, /* Report ID (8), */
|
0x85, 0x08, /* Report ID (8), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
@ -652,12 +652,12 @@ const size_t uclogic_rdesc_v2_pen_template_size =
|
||||||
sizeof(uclogic_rdesc_v2_pen_template_arr);
|
sizeof(uclogic_rdesc_v2_pen_template_arr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Expand to the contents of a generic frame report descriptor.
|
* Expand to the contents of a generic frame buttons report descriptor.
|
||||||
*
|
*
|
||||||
* @_id: The report ID to use.
|
* @_id: The report ID to use.
|
||||||
* @_size: Size of the report to pad to, including report ID, bytes.
|
* @_size: Size of the report to pad to, including report ID, bytes.
|
||||||
*/
|
*/
|
||||||
#define UCLOGIC_RDESC_FRAME_BYTES(_id, _size) \
|
#define UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(_id, _size) \
|
||||||
0x05, 0x01, /* Usage Page (Desktop), */ \
|
0x05, 0x01, /* Usage Page (Desktop), */ \
|
||||||
0x09, 0x07, /* Usage (Keypad), */ \
|
0x09, 0x07, /* Usage (Keypad), */ \
|
||||||
0xA1, 0x01, /* Collection (Application), */ \
|
0xA1, 0x01, /* Collection (Application), */ \
|
||||||
|
@ -700,17 +700,164 @@ const size_t uclogic_rdesc_v2_pen_template_size =
|
||||||
|
|
||||||
/* Fixed report descriptor for (tweaked) v1 frame reports */
|
/* Fixed report descriptor for (tweaked) v1 frame reports */
|
||||||
const __u8 uclogic_rdesc_v1_frame_arr[] = {
|
const __u8 uclogic_rdesc_v1_frame_arr[] = {
|
||||||
UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8)
|
UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8)
|
||||||
};
|
};
|
||||||
const size_t uclogic_rdesc_v1_frame_size =
|
const size_t uclogic_rdesc_v1_frame_size =
|
||||||
sizeof(uclogic_rdesc_v1_frame_arr);
|
sizeof(uclogic_rdesc_v1_frame_arr);
|
||||||
|
|
||||||
/* Fixed report descriptor for (tweaked) v2 frame reports */
|
/* Fixed report descriptor for (tweaked) v2 frame button reports */
|
||||||
const __u8 uclogic_rdesc_v2_frame_arr[] = {
|
const __u8 uclogic_rdesc_v2_frame_buttons_arr[] = {
|
||||||
UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V2_FRAME_ID, 12)
|
UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID,
|
||||||
|
12)
|
||||||
};
|
};
|
||||||
const size_t uclogic_rdesc_v2_frame_size =
|
const size_t uclogic_rdesc_v2_frame_buttons_size =
|
||||||
sizeof(uclogic_rdesc_v2_frame_arr);
|
sizeof(uclogic_rdesc_v2_frame_buttons_arr);
|
||||||
|
|
||||||
|
/* Fixed report descriptor for (tweaked) v2 frame touch ring reports */
|
||||||
|
const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[] = {
|
||||||
|
0x05, 0x01, /* Usage Page (Desktop), */
|
||||||
|
0x09, 0x07, /* Usage (Keypad), */
|
||||||
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
|
0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID,
|
||||||
|
/* Report ID (TOUCH_ID), */
|
||||||
|
0x14, /* Logical Minimum (0), */
|
||||||
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
|
0x09, 0x39, /* Usage (Tablet Function Keys), */
|
||||||
|
0xA0, /* Collection (Physical), */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1), */
|
||||||
|
0x75, 0x01, /* Report Size (1), */
|
||||||
|
0x05, 0x09, /* Usage Page (Button), */
|
||||||
|
0x09, 0x01, /* Usage (01h), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x95, 0x07, /* Report Count (7), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0x75, 0x08, /* Report Size (8), */
|
||||||
|
0x95, 0x02, /* Report Count (2), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
|
0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */
|
||||||
|
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x05, 0x01, /* Usage Page (Desktop), */
|
||||||
|
0x09, 0x38, /* Usage (Wheel), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x15, 0x00, /* Logical Minimum (0), */
|
||||||
|
0x25, 0x0B, /* Logical Maximum (11), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x09, 0x30, /* Usage (X), */
|
||||||
|
0x09, 0x31, /* Usage (Y), */
|
||||||
|
0x14, /* Logical Minimum (0), */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1), */
|
||||||
|
0x75, 0x01, /* Report Size (1), */
|
||||||
|
0x95, 0x02, /* Report Count (2), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x95, 0x2E, /* Report Count (46), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0xC0, /* End Collection, */
|
||||||
|
0xC0 /* End Collection */
|
||||||
|
};
|
||||||
|
const size_t uclogic_rdesc_v2_frame_touch_ring_size =
|
||||||
|
sizeof(uclogic_rdesc_v2_frame_touch_ring_arr);
|
||||||
|
|
||||||
|
/* Fixed report descriptor for (tweaked) v2 frame touch strip reports */
|
||||||
|
const __u8 uclogic_rdesc_v2_frame_touch_strip_arr[] = {
|
||||||
|
0x05, 0x01, /* Usage Page (Desktop), */
|
||||||
|
0x09, 0x07, /* Usage (Keypad), */
|
||||||
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
|
0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID,
|
||||||
|
/* Report ID (TOUCH_ID), */
|
||||||
|
0x14, /* Logical Minimum (0), */
|
||||||
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
|
0x09, 0x39, /* Usage (Tablet Function Keys), */
|
||||||
|
0xA0, /* Collection (Physical), */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1), */
|
||||||
|
0x75, 0x01, /* Report Size (1), */
|
||||||
|
0x05, 0x09, /* Usage Page (Button), */
|
||||||
|
0x09, 0x01, /* Usage (01h), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x95, 0x07, /* Report Count (7), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0x75, 0x08, /* Report Size (8), */
|
||||||
|
0x95, 0x02, /* Report Count (2), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
|
0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */
|
||||||
|
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x05, 0x01, /* Usage Page (Desktop), */
|
||||||
|
0x09, 0x38, /* Usage (Wheel), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x15, 0x00, /* Logical Minimum (0), */
|
||||||
|
0x25, 0x07, /* Logical Maximum (7), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x09, 0x30, /* Usage (X), */
|
||||||
|
0x09, 0x31, /* Usage (Y), */
|
||||||
|
0x14, /* Logical Minimum (0), */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1), */
|
||||||
|
0x75, 0x01, /* Report Size (1), */
|
||||||
|
0x95, 0x02, /* Report Count (2), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x95, 0x2E, /* Report Count (46), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0xC0, /* End Collection, */
|
||||||
|
0xC0 /* End Collection */
|
||||||
|
};
|
||||||
|
const size_t uclogic_rdesc_v2_frame_touch_strip_size =
|
||||||
|
sizeof(uclogic_rdesc_v2_frame_touch_strip_arr);
|
||||||
|
|
||||||
|
/* Fixed report descriptor for (tweaked) v2 frame dial reports */
|
||||||
|
const __u8 uclogic_rdesc_v2_frame_dial_arr[] = {
|
||||||
|
0x05, 0x01, /* Usage Page (Desktop), */
|
||||||
|
0x09, 0x07, /* Usage (Keypad), */
|
||||||
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
|
0x85, UCLOGIC_RDESC_V2_FRAME_DIAL_ID,
|
||||||
|
/* Report ID (DIAL_ID), */
|
||||||
|
0x14, /* Logical Minimum (0), */
|
||||||
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
|
0x09, 0x39, /* Usage (Tablet Function Keys), */
|
||||||
|
0xA0, /* Collection (Physical), */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1), */
|
||||||
|
0x75, 0x01, /* Report Size (1), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0x05, 0x09, /* Usage Page (Button), */
|
||||||
|
0x09, 0x01, /* Usage (01h), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x95, 0x06, /* Report Count (6), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0x75, 0x08, /* Report Size (8), */
|
||||||
|
0x95, 0x02, /* Report Count (2), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
|
0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */
|
||||||
|
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x05, 0x01, /* Usage Page (Desktop), */
|
||||||
|
0x09, 0x38, /* Usage (Wheel), */
|
||||||
|
0x95, 0x01, /* Report Count (1), */
|
||||||
|
0x15, 0xFF, /* Logical Minimum (-1), */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1), */
|
||||||
|
0x81, 0x06, /* Input (Variable, Relative), */
|
||||||
|
0x09, 0x30, /* Usage (X), */
|
||||||
|
0x09, 0x31, /* Usage (Y), */
|
||||||
|
0x14, /* Logical Minimum (0), */
|
||||||
|
0x25, 0x01, /* Logical Maximum (1), */
|
||||||
|
0x75, 0x01, /* Report Size (1), */
|
||||||
|
0x95, 0x02, /* Report Count (2), */
|
||||||
|
0x81, 0x02, /* Input (Variable), */
|
||||||
|
0x95, 0x2E, /* Report Count (46), */
|
||||||
|
0x81, 0x01, /* Input (Constant), */
|
||||||
|
0xC0, /* End Collection, */
|
||||||
|
0xC0 /* End Collection */
|
||||||
|
};
|
||||||
|
const size_t uclogic_rdesc_v2_frame_dial_size =
|
||||||
|
sizeof(uclogic_rdesc_v2_frame_dial_arr);
|
||||||
|
|
||||||
/* Fixed report descriptor for Ugee EX07 frame */
|
/* Fixed report descriptor for Ugee EX07 frame */
|
||||||
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
|
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
|
||||||
|
|
|
@ -124,12 +124,36 @@ extern const size_t uclogic_rdesc_v2_pen_template_size;
|
||||||
extern const __u8 uclogic_rdesc_v1_frame_arr[];
|
extern const __u8 uclogic_rdesc_v1_frame_arr[];
|
||||||
extern const size_t uclogic_rdesc_v1_frame_size;
|
extern const size_t uclogic_rdesc_v1_frame_size;
|
||||||
|
|
||||||
/* Report ID for tweaked v2 frame reports */
|
/* Report ID for tweaked v2 frame button reports */
|
||||||
#define UCLOGIC_RDESC_V2_FRAME_ID 0xf7
|
#define UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID 0xf7
|
||||||
|
|
||||||
/* Fixed report descriptor for (tweaked) v2 frame reports */
|
/* Fixed report descriptor for (tweaked) v2 frame button reports */
|
||||||
extern const __u8 uclogic_rdesc_v2_frame_arr[];
|
extern const __u8 uclogic_rdesc_v2_frame_buttons_arr[];
|
||||||
extern const size_t uclogic_rdesc_v2_frame_size;
|
extern const size_t uclogic_rdesc_v2_frame_buttons_size;
|
||||||
|
|
||||||
|
/* Report ID for tweaked v2 frame touch ring/strip reports */
|
||||||
|
#define UCLOGIC_RDESC_V2_FRAME_TOUCH_ID 0xf8
|
||||||
|
|
||||||
|
/* Fixed report descriptor for (tweaked) v2 frame touch ring reports */
|
||||||
|
extern const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[];
|
||||||
|
extern const size_t uclogic_rdesc_v2_frame_touch_ring_size;
|
||||||
|
|
||||||
|
/* Fixed report descriptor for (tweaked) v2 frame touch strip reports */
|
||||||
|
extern const __u8 uclogic_rdesc_v2_frame_touch_strip_arr[];
|
||||||
|
extern const size_t uclogic_rdesc_v2_frame_touch_strip_size;
|
||||||
|
|
||||||
|
/* Device ID byte offset in v2 frame touch ring/strip reports */
|
||||||
|
#define UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE 0x4
|
||||||
|
|
||||||
|
/* Report ID for tweaked v2 frame dial reports */
|
||||||
|
#define UCLOGIC_RDESC_V2_FRAME_DIAL_ID 0xf9
|
||||||
|
|
||||||
|
/* Fixed report descriptor for (tweaked) v2 frame dial reports */
|
||||||
|
extern const __u8 uclogic_rdesc_v2_frame_dial_arr[];
|
||||||
|
extern const size_t uclogic_rdesc_v2_frame_dial_size;
|
||||||
|
|
||||||
|
/* Device ID byte offset in v2 frame dial reports */
|
||||||
|
#define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4
|
||||||
|
|
||||||
/* Fixed report descriptor for Ugee EX07 frame */
|
/* Fixed report descriptor for Ugee EX07 frame */
|
||||||
extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
|
extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
/* Fixed report descriptor of PD1011 signature pad */
|
/* Fixed report descriptor of PD1011 signature pad */
|
||||||
static __u8 pd1011_rdesc_fixed[] = {
|
static __u8 pd1011_rdesc_fixed[] = {
|
||||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||||
0x09, 0x02, /* Usage (Pen), */
|
0x09, 0x01, /* Usage (Digitizer), */
|
||||||
0xA1, 0x01, /* Collection (Application), */
|
0xA1, 0x01, /* Collection (Application), */
|
||||||
0x85, 0x02, /* Report ID (2), */
|
0x85, 0x02, /* Report ID (2), */
|
||||||
0x09, 0x20, /* Usage (Stylus), */
|
0x09, 0x20, /* Usage (Stylus), */
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#define TGL_H_DEVICE_ID 0x43FC
|
#define TGL_H_DEVICE_ID 0x43FC
|
||||||
#define ADL_S_DEVICE_ID 0x7AF8
|
#define ADL_S_DEVICE_ID 0x7AF8
|
||||||
#define ADL_P_DEVICE_ID 0x51FC
|
#define ADL_P_DEVICE_ID 0x51FC
|
||||||
|
#define ADL_N_DEVICE_ID 0x54FC
|
||||||
|
#define RPL_S_DEVICE_ID 0x7A78
|
||||||
|
|
||||||
#define REVISION_ID_CHT_A0 0x6
|
#define REVISION_ID_CHT_A0 0x6
|
||||||
#define REVISION_ID_CHT_Ax_SI 0x0
|
#define REVISION_ID_CHT_Ax_SI 0x0
|
||||||
|
|
|
@ -41,6 +41,8 @@ static const struct pci_device_id ish_pci_tbl[] = {
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_H_DEVICE_ID)},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, TGL_H_DEVICE_ID)},
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_S_DEVICE_ID)},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_S_DEVICE_ID)},
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_P_DEVICE_ID)},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_P_DEVICE_ID)},
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ADL_N_DEVICE_ID)},
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, RPL_S_DEVICE_ID)},
|
||||||
{0, }
|
{0, }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
|
MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
|
||||||
|
|
|
@ -1777,7 +1777,7 @@ static int __wacom_initialize_battery(struct wacom *wacom,
|
||||||
bat_desc->get_property = wacom_battery_get_property;
|
bat_desc->get_property = wacom_battery_get_property;
|
||||||
sprintf(battery->bat_name, "wacom_battery_%ld", n);
|
sprintf(battery->bat_name, "wacom_battery_%ld", n);
|
||||||
bat_desc->name = battery->bat_name;
|
bat_desc->name = battery->bat_name;
|
||||||
bat_desc->type = POWER_SUPPLY_TYPE_USB;
|
bat_desc->type = POWER_SUPPLY_TYPE_BATTERY;
|
||||||
bat_desc->use_for_apm = 0;
|
bat_desc->use_for_apm = 0;
|
||||||
|
|
||||||
ps_bat = devm_power_supply_register(dev, bat_desc, &psy_cfg);
|
ps_bat = devm_power_supply_register(dev, bat_desc, &psy_cfg);
|
||||||
|
|
|
@ -1811,7 +1811,9 @@ int wacom_equivalent_usage(int usage)
|
||||||
usage == WACOM_HID_WD_TOUCHSTRIP2 ||
|
usage == WACOM_HID_WD_TOUCHSTRIP2 ||
|
||||||
usage == WACOM_HID_WD_TOUCHRING ||
|
usage == WACOM_HID_WD_TOUCHRING ||
|
||||||
usage == WACOM_HID_WD_TOUCHRINGSTATUS ||
|
usage == WACOM_HID_WD_TOUCHRINGSTATUS ||
|
||||||
usage == WACOM_HID_WD_REPORT_VALID) {
|
usage == WACOM_HID_WD_REPORT_VALID ||
|
||||||
|
usage == WACOM_HID_WD_BARRELSWITCH3 ||
|
||||||
|
usage == WACOM_HID_WD_SEQUENCENUMBER) {
|
||||||
return usage;
|
return usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2196,8 +2198,11 @@ static void wacom_set_barrel_switch3_usage(struct wacom_wac *wacom_wac)
|
||||||
if (!(features->quirks & WACOM_QUIRK_AESPEN) &&
|
if (!(features->quirks & WACOM_QUIRK_AESPEN) &&
|
||||||
wacom_wac->hid_data.barrelswitch &&
|
wacom_wac->hid_data.barrelswitch &&
|
||||||
wacom_wac->hid_data.barrelswitch2 &&
|
wacom_wac->hid_data.barrelswitch2 &&
|
||||||
wacom_wac->hid_data.serialhi)
|
wacom_wac->hid_data.serialhi &&
|
||||||
|
!wacom_wac->hid_data.barrelswitch3) {
|
||||||
input_set_capability(input, EV_KEY, BTN_STYLUS3);
|
input_set_capability(input, EV_KEY, BTN_STYLUS3);
|
||||||
|
features->quirks |= WACOM_QUIRK_PEN_BUTTON3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
||||||
|
@ -2261,6 +2266,9 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
||||||
features->quirks |= WACOM_QUIRK_TOOLSERIAL;
|
features->quirks |= WACOM_QUIRK_TOOLSERIAL;
|
||||||
wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
|
wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
|
||||||
break;
|
break;
|
||||||
|
case HID_DG_SCANTIME:
|
||||||
|
wacom_map_usage(input, usage, field, EV_MSC, MSC_TIMESTAMP, 0);
|
||||||
|
break;
|
||||||
case WACOM_HID_WD_SENSE:
|
case WACOM_HID_WD_SENSE:
|
||||||
features->quirks |= WACOM_QUIRK_SENSE;
|
features->quirks |= WACOM_QUIRK_SENSE;
|
||||||
wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
|
wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
|
||||||
|
@ -2274,6 +2282,11 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
||||||
input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
|
input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
|
||||||
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
|
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
|
||||||
break;
|
break;
|
||||||
|
case WACOM_HID_WD_BARRELSWITCH3:
|
||||||
|
wacom_wac->hid_data.barrelswitch3 = true;
|
||||||
|
wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS3, 0);
|
||||||
|
features->quirks &= ~WACOM_QUIRK_PEN_BUTTON3;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2390,6 +2403,14 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
|
||||||
case WACOM_HID_WD_REPORT_VALID:
|
case WACOM_HID_WD_REPORT_VALID:
|
||||||
wacom_wac->is_invalid_bt_frame = !value;
|
wacom_wac->is_invalid_bt_frame = !value;
|
||||||
return;
|
return;
|
||||||
|
case WACOM_HID_WD_BARRELSWITCH3:
|
||||||
|
wacom_wac->hid_data.barrelswitch3 = value;
|
||||||
|
return;
|
||||||
|
case WACOM_HID_WD_SEQUENCENUMBER:
|
||||||
|
if (wacom_wac->hid_data.sequence_number != value)
|
||||||
|
hid_warn(hdev, "Dropped %hu packets", (unsigned short)(value - wacom_wac->hid_data.sequence_number));
|
||||||
|
wacom_wac->hid_data.sequence_number = value + 1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send pen events only when touch is up or forced out
|
/* send pen events only when touch is up or forced out
|
||||||
|
@ -2442,12 +2463,15 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
|
||||||
|
|
||||||
if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) {
|
if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) {
|
||||||
int id = wacom_wac->id[0];
|
int id = wacom_wac->id[0];
|
||||||
int sw_state = wacom_wac->hid_data.barrelswitch |
|
if (wacom_wac->features.quirks & WACOM_QUIRK_PEN_BUTTON3 &&
|
||||||
(wacom_wac->hid_data.barrelswitch2 << 1);
|
wacom_wac->hid_data.barrelswitch & wacom_wac->hid_data.barrelswitch2) {
|
||||||
|
wacom_wac->hid_data.barrelswitch = 0;
|
||||||
input_report_key(input, BTN_STYLUS, sw_state == 1);
|
wacom_wac->hid_data.barrelswitch2 = 0;
|
||||||
input_report_key(input, BTN_STYLUS2, sw_state == 2);
|
wacom_wac->hid_data.barrelswitch3 = 1;
|
||||||
input_report_key(input, BTN_STYLUS3, sw_state == 3);
|
}
|
||||||
|
input_report_key(input, BTN_STYLUS, wacom_wac->hid_data.barrelswitch);
|
||||||
|
input_report_key(input, BTN_STYLUS2, wacom_wac->hid_data.barrelswitch2);
|
||||||
|
input_report_key(input, BTN_STYLUS3, wacom_wac->hid_data.barrelswitch3);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non-USI EMR tools should have their IDs mangled to
|
* Non-USI EMR tools should have their IDs mangled to
|
||||||
|
@ -2529,6 +2553,9 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
|
||||||
field->logical_maximum = 255;
|
field->logical_maximum = 255;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case HID_DG_SCANTIME:
|
||||||
|
wacom_map_usage(input, usage, field, EV_MSC, MSC_TIMESTAMP, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@
|
||||||
#define WACOM_QUIRK_AESPEN 0x0004
|
#define WACOM_QUIRK_AESPEN 0x0004
|
||||||
#define WACOM_QUIRK_BATTERY 0x0008
|
#define WACOM_QUIRK_BATTERY 0x0008
|
||||||
#define WACOM_QUIRK_TOOLSERIAL 0x0010
|
#define WACOM_QUIRK_TOOLSERIAL 0x0010
|
||||||
|
#define WACOM_QUIRK_PEN_BUTTON3 0x0020
|
||||||
|
|
||||||
/* device types */
|
/* device types */
|
||||||
#define WACOM_DEVICETYPE_NONE 0x0000
|
#define WACOM_DEVICETYPE_NONE 0x0000
|
||||||
|
@ -108,6 +109,7 @@
|
||||||
#define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39)
|
#define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39)
|
||||||
#define WACOM_HID_WD_SERIALNUMBER (WACOM_HID_UP_WACOMDIGITIZER | 0x5b)
|
#define WACOM_HID_WD_SERIALNUMBER (WACOM_HID_UP_WACOMDIGITIZER | 0x5b)
|
||||||
#define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c)
|
#define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c)
|
||||||
|
#define WACOM_HID_WD_BARRELSWITCH3 (WACOM_HID_UP_WACOMDIGITIZER | 0x5d)
|
||||||
#define WACOM_HID_WD_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77)
|
#define WACOM_HID_WD_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77)
|
||||||
#define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132)
|
#define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132)
|
||||||
#define WACOM_HID_WD_TOUCHSTRIP (WACOM_HID_UP_WACOMDIGITIZER | 0x0136)
|
#define WACOM_HID_WD_TOUCHSTRIP (WACOM_HID_UP_WACOMDIGITIZER | 0x0136)
|
||||||
|
@ -115,6 +117,7 @@
|
||||||
#define WACOM_HID_WD_TOUCHRING (WACOM_HID_UP_WACOMDIGITIZER | 0x0138)
|
#define WACOM_HID_WD_TOUCHRING (WACOM_HID_UP_WACOMDIGITIZER | 0x0138)
|
||||||
#define WACOM_HID_WD_TOUCHRINGSTATUS (WACOM_HID_UP_WACOMDIGITIZER | 0x0139)
|
#define WACOM_HID_WD_TOUCHRINGSTATUS (WACOM_HID_UP_WACOMDIGITIZER | 0x0139)
|
||||||
#define WACOM_HID_WD_REPORT_VALID (WACOM_HID_UP_WACOMDIGITIZER | 0x01d0)
|
#define WACOM_HID_WD_REPORT_VALID (WACOM_HID_UP_WACOMDIGITIZER | 0x01d0)
|
||||||
|
#define WACOM_HID_WD_SEQUENCENUMBER (WACOM_HID_UP_WACOMDIGITIZER | 0x0220)
|
||||||
#define WACOM_HID_WD_ACCELEROMETER_X (WACOM_HID_UP_WACOMDIGITIZER | 0x0401)
|
#define WACOM_HID_WD_ACCELEROMETER_X (WACOM_HID_UP_WACOMDIGITIZER | 0x0401)
|
||||||
#define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402)
|
#define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402)
|
||||||
#define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403)
|
#define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403)
|
||||||
|
@ -300,6 +303,7 @@ struct hid_data {
|
||||||
bool tipswitch;
|
bool tipswitch;
|
||||||
bool barrelswitch;
|
bool barrelswitch;
|
||||||
bool barrelswitch2;
|
bool barrelswitch2;
|
||||||
|
bool barrelswitch3;
|
||||||
bool serialhi;
|
bool serialhi;
|
||||||
bool confidence;
|
bool confidence;
|
||||||
int x;
|
int x;
|
||||||
|
@ -320,6 +324,7 @@ struct hid_data {
|
||||||
int bat_connected;
|
int bat_connected;
|
||||||
int ps_connected;
|
int ps_connected;
|
||||||
bool pad_input_event_flag;
|
bool pad_input_event_flag;
|
||||||
|
unsigned short sequence_number;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wacom_remote_data {
|
struct wacom_remote_data {
|
||||||
|
|
|
@ -271,6 +271,7 @@ struct input_mask {
|
||||||
#define BUS_RMI 0x1D
|
#define BUS_RMI 0x1D
|
||||||
#define BUS_CEC 0x1E
|
#define BUS_CEC 0x1E
|
||||||
#define BUS_INTEL_ISHTP 0x1F
|
#define BUS_INTEL_ISHTP 0x1F
|
||||||
|
#define BUS_AMD_SFH 0x20
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MT_TOOL types
|
* MT_TOOL types
|
||||||
|
|
Loading…
Reference in New Issue