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

Pull HID updates from Jiri Kosina:

 - patch series that ensures that hid-multitouch driver disables touch
   and button-press reporting on hid-mt devices during suspend when the
   device is not configured as a wakeup-source, from Hans de Goede

 - support for ISH DMA on Intel EHL platform, from Even Xu

 - support for Renoir and Cezanne SoCs, Ambient Light Sensor and Human
   Presence Detection sensor for amd-sfh driver, from Basavaraj Natikar

 - other assorted code cleanups and device-specific fixes/quirks

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (45 commits)
  HID: thrustmaster: Switch to kmemdup() when allocate change_request
  HID: multitouch: Disable event reporting on suspend when the device is not a wakeup-source
  HID: logitech-dj: Implement may_wakeup ll-driver callback
  HID: usbhid: Implement may_wakeup ll-driver callback
  HID: core: Add hid_hw_may_wakeup() function
  HID: input: Add support for Programmable Buttons
  HID: wacom: Correct base usage for capacitive ExpressKey status bits
  HID: amd_sfh: Add initial support for HPD sensor
  HID: amd_sfh: Extend ALS support for newer AMD platform
  HID: amd_sfh: Extend driver capabilities for multi-generation support
  HID: surface-hid: Fix get-report request
  HID: sony: fix freeze when inserting ghlive ps3/wii dongles
  HID: usbkbd: Avoid GFP_ATOMIC when GFP_KERNEL is possible
  HID: amd_sfh: change in maintainer
  HID: intel-ish-hid: ipc: Specify that EHL no cache snooping
  HID: intel-ish-hid: ishtp: Add dma_no_cache_snooping() callback
  HID: intel-ish-hid: Set ISH driver depends on x86
  HID: hid-input: add Surface Go battery quirk
  HID: intel-ish-hid: Fix minor typos in comments
  HID: usbmouse: Avoid GFP_ATOMIC when GFP_KERNEL is possible
  ...
This commit is contained in:
Linus Torvalds
2021-06-30 11:31:32 -07:00
40 changed files with 704 additions and 220 deletions

View File

@@ -973,7 +973,7 @@ F: drivers/net/ethernet/amd/xgbe/
AMD SENSOR FUSION HUB DRIVER
M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
M: Sandeep Singh <sandeep.singh@amd.com>
M: Basavaraj Natikar <basavaraj.natikar@amd.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/hid/amd-sfh*

View File

@@ -77,6 +77,7 @@ int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type)
static void amd_sfh_work(struct work_struct *work)
{
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work);
struct amd_input_data *in_data = cli_data->in_data;
struct request_list *req_node;
u8 current_index, sensor_index;
u8 report_id, node_type;
@@ -101,13 +102,11 @@ static void amd_sfh_work(struct work_struct *work)
pr_err("AMDSFH: Invalid report size\n");
} else if (node_type == HID_INPUT_REPORT) {
report_size = get_input_report(sensor_index, report_id,
cli_data->input_report[current_index],
cli_data->sensor_virt_addr[current_index]);
report_size = get_input_report(current_index, sensor_index, report_id, in_data);
if (report_size)
hid_input_report(cli_data->hid_sensor_hubs[current_index],
cli_data->report_type[current_index],
cli_data->input_report[current_index], report_size, 0);
in_data->input_report[current_index], report_size, 0);
else
pr_err("AMDSFH: Invalid report size\n");
}
@@ -119,21 +118,22 @@ static void amd_sfh_work(struct work_struct *work)
static void amd_sfh_work_buffer(struct work_struct *work)
{
struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work);
struct amd_input_data *in_data = cli_data->in_data;
u8 report_size;
int i;
for (i = 0; i < cli_data->num_hid_devices; i++) {
report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i],
cli_data->input_report[i],
cli_data->sensor_virt_addr[i]);
report_size = get_input_report(i, cli_data->sensor_idx[i], cli_data->report_id[i],
in_data);
hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
cli_data->input_report[i], report_size, 0);
in_data->input_report[i], report_size, 0);
}
schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
}
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
{
struct amd_input_data *in_data = &privdata->in_data;
struct amdtp_cl_data *cl_data = privdata->cl_data;
struct amd_mp2_sensor_info info;
struct device *dev;
@@ -143,18 +143,16 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
int rc, i;
dev = &privdata->pdev->dev;
cl_data = devm_kzalloc(dev, sizeof(*cl_data), GFP_KERNEL);
if (!cl_data)
return -ENOMEM;
cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
INIT_LIST_HEAD(&req_list.list);
cl_data->in_data = in_data;
for (i = 0; i < cl_data->num_hid_devices; i++) {
cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
in_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
&cl_data->sensor_dma_addr[i],
GFP_KERNEL);
cl_data->sensor_sts[i] = 0;
@@ -181,8 +179,8 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
rc = -ENOMEM;
goto cleanup;
}
cl_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
if (!cl_data->input_report[i]) {
in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
if (!in_data->input_report[i]) {
rc = -ENOMEM;
goto cleanup;
}
@@ -202,44 +200,43 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
if (rc)
return rc;
amd_start_sensor(privdata, info);
privdata->mp2_ops->start(privdata, info);
cl_data->sensor_sts[i] = 1;
}
privdata->cl_data = cl_data;
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
return 0;
cleanup:
for (i = 0; i < cl_data->num_hid_devices; i++) {
if (cl_data->sensor_virt_addr[i]) {
if (in_data->sensor_virt_addr[i]) {
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
cl_data->sensor_virt_addr[i],
in_data->sensor_virt_addr[i],
cl_data->sensor_dma_addr[i]);
}
devm_kfree(dev, cl_data->feature_report[i]);
devm_kfree(dev, cl_data->input_report[i]);
devm_kfree(dev, in_data->input_report[i]);
devm_kfree(dev, cl_data->report_descr[i]);
}
devm_kfree(dev, cl_data);
return rc;
}
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
{
struct amdtp_cl_data *cl_data = privdata->cl_data;
struct amd_input_data *in_data = cl_data->in_data;
int i;
for (i = 0; i < cl_data->num_hid_devices; i++)
amd_stop_sensor(privdata, i);
privdata->mp2_ops->stop(privdata, i);
cancel_delayed_work_sync(&cl_data->work);
cancel_delayed_work_sync(&cl_data->work_buffer);
amdtp_hid_remove(cl_data);
for (i = 0; i < cl_data->num_hid_devices; i++) {
if (cl_data->sensor_virt_addr[i]) {
if (in_data->sensor_virt_addr[i]) {
dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int),
cl_data->sensor_virt_addr[i],
in_data->sensor_virt_addr[i],
cl_data->sensor_dma_addr[i]);
}
}

View File

@@ -9,11 +9,16 @@
#ifndef AMDSFH_HID_H
#define AMDSFH_HID_H
#define MAX_HID_DEVICES 4
#define MAX_HID_DEVICES 5
#define BUS_AMD_AMDTP 0x20
#define AMD_SFH_HID_VENDOR 0x1022
#define AMD_SFH_HID_PRODUCT 0x0001
struct amd_input_data {
u32 *sensor_virt_addr[MAX_HID_DEVICES];
u8 *input_report[MAX_HID_DEVICES];
};
struct amdtp_cl_data {
u8 init_done;
u32 cur_hid_dev;
@@ -26,7 +31,6 @@ struct amdtp_cl_data {
u8 *hid_descr[MAX_HID_DEVICES];
int hid_descr_size[MAX_HID_DEVICES];
phys_addr_t phys_addr_base;
u32 *sensor_virt_addr[MAX_HID_DEVICES];
dma_addr_t sensor_dma_addr[MAX_HID_DEVICES];
u32 sensor_sts[MAX_HID_DEVICES];
u32 sensor_requested_cnt[MAX_HID_DEVICES];
@@ -34,8 +38,8 @@ struct amdtp_cl_data {
u8 report_id[MAX_HID_DEVICES];
u8 sensor_idx[MAX_HID_DEVICES];
u8 *feature_report[MAX_HID_DEVICES];
u8 *input_report[MAX_HID_DEVICES];
u8 request_done[MAX_HID_DEVICES];
struct amd_input_data *in_data;
struct delayed_work work;
struct delayed_work work_buffer;
};
@@ -64,4 +68,6 @@ void amdtp_hid_remove(struct amdtp_cl_data *cli_data);
int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type);
void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type);
void amdtp_hid_wakeup(struct hid_device *hid);
u8 get_input_report(u8 current_index, int sensor_idx, int report_id,
struct amd_input_data *in_data);
#endif

View File

@@ -24,12 +24,55 @@
#define ACEL_EN BIT(0)
#define GYRO_EN BIT(1)
#define MAGNO_EN BIT(2)
#define HPD_EN BIT(16)
#define ALS_EN BIT(19)
static int sensor_mask_override = -1;
module_param_named(sensor_mask, sensor_mask_override, int, 0444);
MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
{
union sfh_cmd_base cmd_base;
cmd_base.ul = 0;
cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
cmd_base.cmd_v2.period = info.period;
cmd_base.cmd_v2.sensor_id = info.sensor_idx;
cmd_base.cmd_v2.length = 16;
if (info.sensor_idx == als_idx)
cmd_base.cmd_v2.mem_type = USE_C2P_REG;
writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG1);
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
}
static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
{
union sfh_cmd_base cmd_base;
cmd_base.ul = 0;
cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
cmd_base.cmd_v2.period = 0;
cmd_base.cmd_v2.sensor_id = sensor_idx;
cmd_base.cmd_v2.length = 16;
writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
}
static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
{
union sfh_cmd_base cmd_base;
cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
cmd_base.cmd_v2.period = 0;
cmd_base.cmd_v2.sensor_id = 0;
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
}
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
{
union sfh_cmd_param cmd_param;
@@ -98,7 +141,6 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
{
int activestatus, num_of_sensors = 0;
const struct dmi_system_id *dmi_id;
u32 activecontrolstatus;
if (sensor_mask_override == -1) {
dmi_id = dmi_first_match(dmi_sensor_mask_overrides);
@@ -109,8 +151,7 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
if (sensor_mask_override >= 0) {
activestatus = sensor_mask_override;
} else {
activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3);
activestatus = activecontrolstatus >> 4;
activestatus = privdata->mp2_acs >> 4;
}
if (ACEL_EN & activestatus)
@@ -125,13 +166,46 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
if (ALS_EN & activestatus)
sensor_id[num_of_sensors++] = als_idx;
if (HPD_EN & activestatus)
sensor_id[num_of_sensors++] = HPD_IDX;
return num_of_sensors;
}
static void amd_mp2_pci_remove(void *privdata)
{
struct amd_mp2_dev *mp2 = privdata;
amd_sfh_hid_client_deinit(privdata);
amd_stop_all_sensors(privdata);
mp2->mp2_ops->stop_all(mp2);
}
static const struct amd_mp2_ops amd_sfh_ops_v2 = {
.start = amd_start_sensor_v2,
.stop = amd_stop_sensor_v2,
.stop_all = amd_stop_all_sensor_v2,
};
static const struct amd_mp2_ops amd_sfh_ops = {
.start = amd_start_sensor,
.stop = amd_stop_sensor,
.stop_all = amd_stop_all_sensors,
};
static void mp2_select_ops(struct amd_mp2_dev *privdata)
{
u8 acs;
privdata->mp2_acs = readl(privdata->mmio + AMD_P2C_MSG3);
acs = privdata->mp2_acs & GENMASK(3, 0);
switch (acs) {
case V2_STATUS:
privdata->mp2_ops = &amd_sfh_ops_v2;
break;
default:
privdata->mp2_ops = &amd_sfh_ops;
break;
}
}
static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -160,10 +234,17 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
return rc;
}
privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
if (!privdata->cl_data)
return -ENOMEM;
rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
if (rc)
return rc;
mp2_select_ops(privdata);
return amd_sfh_hid_client_init(privdata);
}

View File

@@ -10,6 +10,7 @@
#define PCIE_MP2_AMD_H
#include <linux/pci.h>
#include "amd_sfh_hid.h"
#define PCI_DEVICE_ID_AMD_MP2 0x15E4
@@ -22,9 +23,15 @@
#define AMD_C2P_MSG1 0x10504
#define AMD_C2P_MSG2 0x10508
#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
/* MP2 P2C Message Registers */
#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */
#define V2_STATUS 0x2
#define HPD_IDX 16
/* SFH Command register */
union sfh_cmd_base {
u32 ul;
@@ -33,6 +40,15 @@ union sfh_cmd_base {
u32 sensor_id : 8;
u32 period : 16;
} s;
struct {
u32 cmd_id : 4;
u32 intr_enable : 1;
u32 rsvd1 : 3;
u32 length : 7;
u32 mem_type : 1;
u32 sensor_id : 8;
u32 period : 8;
} cmd_v2;
};
union sfh_cmd_param {
@@ -61,6 +77,10 @@ struct amd_mp2_dev {
struct pci_dev *pdev;
struct amdtp_cl_data *cl_data;
void __iomem *mmio;
const struct amd_mp2_ops *mp2_ops;
struct amd_input_data in_data;
/* mp2 active control status */
u32 mp2_acs;
};
struct amd_mp2_sensor_info {
@@ -69,10 +89,33 @@ struct amd_mp2_sensor_info {
dma_addr_t dma_address;
};
enum mem_use_type {
USE_DRAM,
USE_C2P_REG,
};
struct hpd_status {
union {
struct {
u32 human_presence_report : 4;
u32 human_presence_actual : 4;
u32 probablity : 8;
u32 object_distance : 16;
} shpd;
u32 val;
};
};
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx);
void amd_stop_all_sensors(struct amd_mp2_dev *privdata);
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id);
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata);
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);
struct amd_mp2_ops {
void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx);
void (*stop_all)(struct amd_mp2_dev *privdata);
};
#endif

View File

@@ -12,6 +12,7 @@
#include "amd_sfh_pcie.h"
#include "amd_sfh_hid_desc.h"
#include "amd_sfh_hid_report_desc.h"
#include "amd_sfh_hid.h"
#define AMD_SFH_FW_MULTIPLIER (1000)
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41
@@ -49,6 +50,11 @@ int get_report_descriptor(int sensor_idx, u8 *rep_desc)
memcpy(rep_desc, als_report_descriptor,
sizeof(als_report_descriptor));
break;
case HPD_IDX: /* HPD sensor */
memset(rep_desc, 0, sizeof(hpd_report_descriptor));
memcpy(rep_desc, hpd_report_descriptor,
sizeof(hpd_report_descriptor));
break;
default:
break;
}
@@ -98,6 +104,17 @@ u32 get_descr_sz(int sensor_idx, int descriptor_name)
return sizeof(struct als_feature_report);
}
break;
case HPD_IDX:
switch (descriptor_name) {
case descr_size:
return sizeof(hpd_report_descriptor);
case input_size:
return sizeof(struct hpd_input_report);
case feature_size:
return sizeof(struct hpd_feature_report);
}
break;
default:
break;
}
@@ -119,6 +136,7 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
struct accel3_feature_report acc_feature;
struct gyro_feature_report gyro_feature;
struct magno_feature_report magno_feature;
struct hpd_feature_report hpd_feature;
struct als_feature_report als_feature;
u8 report_size = 0;
@@ -161,6 +179,12 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
memcpy(feature_report, &als_feature, sizeof(als_feature));
report_size = sizeof(als_feature);
break;
case HPD_IDX: /* human presence detection sensor */
get_common_features(&hpd_feature.common_property, report_id);
memcpy(feature_report, &hpd_feature, sizeof(hpd_feature));
report_size = sizeof(hpd_feature);
break;
default:
break;
}
@@ -174,12 +198,18 @@ static void get_common_inputs(struct common_input_property *common, int report_i
common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
}
u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr)
u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_input_data *in_data)
{
struct amd_mp2_dev *privdata = container_of(in_data, struct amd_mp2_dev, in_data);
u32 *sensor_virt_addr = in_data->sensor_virt_addr[current_index];
u8 *input_report = in_data->input_report[current_index];
u8 supported_input = privdata->mp2_acs & GENMASK(3, 0);
struct magno_input_report magno_input;
struct accel3_input_report acc_input;
struct gyro_input_report gyro_input;
struct magno_input_report magno_input;
struct hpd_input_report hpd_input;
struct als_input_report als_input;
struct hpd_status hpdstatus;
u8 report_size = 0;
if (!sensor_virt_addr || !input_report)
@@ -213,10 +243,22 @@ u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor
break;
case als_idx: /* Als */
get_common_inputs(&als_input.common_property, report_id);
als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
/* For ALS ,V2 Platforms uses C2P_MSG5 register instead of DRAM access method */
if (supported_input == V2_STATUS)
als_input.illuminance_value = (int)readl(privdata->mmio + AMD_C2P_MSG(5));
else
als_input.illuminance_value =
(int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER;
report_size = sizeof(als_input);
memcpy(input_report, &als_input, sizeof(als_input));
break;
case HPD_IDX: /* hpd */
get_common_inputs(&hpd_input.common_property, report_id);
hpdstatus.val = readl(privdata->mmio + AMD_C2P_MSG(4));
hpd_input.human_presence = hpdstatus.shpd.human_presence_actual;
report_size = sizeof(hpd_input);
memcpy(input_report, &hpd_input, sizeof(hpd_input));
break;
default:
break;
}

View File

@@ -100,8 +100,17 @@ struct als_input_report {
int illuminance_value;
} __packed;
struct hpd_feature_report {
struct common_feature_property common_property;
} __packed;
struct hpd_input_report {
struct common_input_property common_property;
/* values specific to human presence sensor */
u8 human_presence;
} __packed;
int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
u32 get_descr_sz(int sensor_idx, int descriptor_name);
u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report);
u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr);
#endif

View File

@@ -642,4 +642,116 @@ const u8 als_report_descriptor[] = {
0X81, 0x02, /* HID Input (Data_Arr_Abs) */
0xC0 /* HID end collection */
};
/* BIOMETRIC PRESENCE*/
static const u8 hpd_report_descriptor[] = {
0x05, 0x20, /* Usage page */
0x09, 0x11, /* BIOMETRIC PRESENCE */
0xA1, 0x00, /* HID Collection (Physical) */
//feature reports(xmit/receive)
0x85, 5, /* HID Report ID */
0x05, 0x20, /* HID usage page sensor */
0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */
0x15, 0, /* HID logical MIN_8(0) */
0x25, 2, /* HID logical MAX_8(2) */
0x75, 8, /* HID report size(8) */
0x95, 1, /* HID report count(1) */
0xA1, 0x02, /* HID collection (logical) */
0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel*/
0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */
0x0A, 0x32, 0x08, /* Sensor property connection type external sel */
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
0xC0, /* HID end collection */
0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */
0x15, 0, /* HID logical Min_8(0) */
0x25, 5, /* HID logical Max_8(5) */
0x75, 8, /* HID report size(8) */
0x95, 1, /* HID report count(1) */
0xA1, 0x02, /* HID collection(logical) */
0x0A, 0x40, 0x08, /* Sensor property report state no events sel */
0x0A, 0x41, 0x08, /* Sensor property report state all events sel */
0x0A, 0x42, 0x08, /* Sensor property report state threshold events sel */
0x0A, 0x43, 0x08, /* Sensor property report state no events wake sel */
0x0A, 0x44, 0x08, /* Sensor property report state all events wake sel */
0x0A, 0x45, 0x08, /* Sensor property report state threshold events wake sel */
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
0xC0, /* HID end collection */
0x0A, 0x19, 0x03, /* HID usage sensor property power state */
0x15, 0, /* HID logical Min_8(0) */
0x25, 5, /* HID logical Max_8(5) */
0x75, 8, /* HID report size(8) */
0x95, 1, /* HID report count(1) */
0xA1, 0x02, /* HID collection(logical) */
0x0A, 0x50, 0x08, /* Sensor property power state undefined sel */
0x0A, 0x51, 0x08, /* Sensor property power state D0 full power sel */
0x0A, 0x52, 0x08, /* Sensor property power state D1 low power sel */
0x0A, 0x53, 0x08, /* Sensor property power state D2 standby with wake sel */
0x0A, 0x54, 0x08, /* Sensor property power state D3 sleep with wake sel */
0x0A, 0x55, 0x08, /* Sensor property power state D4 power off sel */
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
0xC0, /* HID end collection */
0x0A, 0x01, 0x02, /* HID usage sensor state */
0x15, 0, /* HID logical Min_8(0) */
0x25, 6, /* HID logical Max_8(6) */
0x75, 8, /* HID report size(8) */
0x95, 1, /* HID report count(1) */
0xA1, 0x02, /* HID collection(logical) */
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
0xB1, 0x00, /* HID feature (Data_Arr_Abs) */
0xC0, /* HID end collection */
0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */
0x15, 0, /* HID logical Min_8(0) */
0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */
0x75, 32, /* HID report size(32) */
0x95, 1, /* HID report count(1) */
0x55, 0, /* HID unit exponent(0) */
0xB1, 0x02, /* HID feature (Data_Var_Abs) */
//input report (transmit)
0x05, 0x20, /* HID usage page sensors */
0x0A, 0x01, 0x02, /* HID usage sensor state */
0x15, 0, /* HID logical Min_8(0) */
0x25, 6, /* HID logical Max_8(6) */
0x75, 8, /* HID report size(8) */
0x95, 1, /* HID report count (1) */
0xA1, 0x02, /* HID end collection (logical) */
0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */
0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */
0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */
0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */
0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */
0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */
0x0A, 0x06, 0x08, /* HID usage sensor state error sel */
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
0xC0, /* HID end collection */
0x0A, 0x02, 0x02, /* HID usage sensor event */
0x15, 0, /* HID logical Min_8(0) */
0x25, 5, /* HID logical Max_8(5) */
0x75, 8, /* HID report size(8) */
0x95, 1, /* HID report count (1) */
0xA1, 0x02, /* HID end collection (logical) */
0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */
0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */
0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */
0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */
0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */
0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */
0X81, 0x00, /* HID Input (Data_Arr_Abs) */
0xC0, /* HID end collection */
0x0A, 0xB1, 0x04, /* HID usage sensor data BIOMETRIC HUMAN PRESENCE */
0x15, 0, /* HID logical Min_8(0) */
0x25, 1, /* HID logical Max_8(1) */
0x75, 8, /* HID report size(8) */
0x95, 1, /* HID report count (1) */
0X81, 0x02, /* HID Input (Data_Var_Abs) */
0xC0 /* HID end collection */
};
#endif

View File

@@ -2306,12 +2306,8 @@ static int hid_device_remove(struct device *dev)
{
struct hid_device *hdev = to_hid_device(dev);
struct hid_driver *hdrv;
int ret = 0;
if (down_interruptible(&hdev->driver_input_lock)) {
ret = -EINTR;
goto end;
}
down(&hdev->driver_input_lock);
hdev->io_started = false;
hdrv = hdev->driver;
@@ -2326,8 +2322,8 @@ static int hid_device_remove(struct device *dev)
if (!hdev->io_started)
up(&hdev->driver_input_lock);
end:
return ret;
return 0;
}
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,

View File

@@ -122,6 +122,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{ 9, 0, "Button" },
{ 10, 0, "Ordinal" },
{ 12, 0, "Consumer" },
{0, 0x003, "ProgrammableButtons"},
{0, 0x238, "HorizontalWheel"},
{ 13, 0, "Digitizers" },
{0, 0x01, "Digitizer"},
@@ -942,6 +943,16 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_KBDINPUTASSIST_NEXTGROUP] = "KbdInputAssistNextGroup",
[KEY_KBDINPUTASSIST_ACCEPT] = "KbdInputAssistAccept",
[KEY_KBDINPUTASSIST_CANCEL] = "KbdInputAssistCancel",
[KEY_MACRO1] = "Macro1", [KEY_MACRO2] = "Macro2", [KEY_MACRO3] = "Macro3",
[KEY_MACRO4] = "Macro4", [KEY_MACRO5] = "Macro5", [KEY_MACRO6] = "Macro6",
[KEY_MACRO7] = "Macro7", [KEY_MACRO8] = "Macro8", [KEY_MACRO9] = "Macro9",
[KEY_MACRO10] = "Macro10", [KEY_MACRO11] = "Macro11", [KEY_MACRO12] = "Macro12",
[KEY_MACRO13] = "Macro13", [KEY_MACRO14] = "Macro14", [KEY_MACRO15] = "Macro15",
[KEY_MACRO16] = "Macro16", [KEY_MACRO17] = "Macro17", [KEY_MACRO18] = "Macro18",
[KEY_MACRO19] = "Macro19", [KEY_MACRO20] = "Macro20", [KEY_MACRO21] = "Macro21",
[KEY_MACRO22] = "Macro22", [KEY_MACRO23] = "Macro23", [KEY_MACRO24] = "Macro24",
[KEY_MACRO25] = "Macro25", [KEY_MACRO26] = "Macro26", [KEY_MACRO27] = "Macro27",
[KEY_MACRO28] = "Macro28", [KEY_MACRO29] = "Macro29", [KEY_MACRO30] = "Macro30",
};
static const char *relatives[REL_MAX + 1] = {

View File

@@ -17,6 +17,7 @@
#include <linux/hid.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
@@ -272,12 +273,21 @@ static const struct acpi_device_id cbas_ec_acpi_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
#ifdef CONFIG_OF
static const struct of_device_id cbas_ec_of_match[] = {
{ .compatible = "google,cros-cbas" },
{ },
};
MODULE_DEVICE_TABLE(of, cbas_ec_of_match);
#endif
static struct platform_driver cbas_ec_driver = {
.probe = cbas_ec_probe,
.remove = cbas_ec_remove,
.driver = {
.name = "cbas_ec",
.acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids),
.of_match_table = of_match_ptr(cbas_ec_of_match),
.pm = &cbas_ec_pm_ops,
},
};

View File

@@ -396,6 +396,7 @@
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
#define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817
#define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
#define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
@@ -763,6 +764,7 @@
#define I2C_DEVICE_ID_LG_7010 0x7010
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_Z_10_SPK 0x0a07
#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
#define USB_DEVICE_ID_LOGITECH_T651 0xb00c
#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309

View File

@@ -326,6 +326,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),
HID_BATTERY_QUIRK_IGNORE },
{}
};
@@ -567,6 +569,16 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field,
unsigned int type, unsigned int usage)
{
struct hid_collection *collection;
collection = &device->collection[field->usage->collection_index];
return collection->type == type && collection->usage == usage;
}
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
@@ -632,6 +644,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
else
code += BTN_TRIGGER_HAPPY - 0x10;
break;
case HID_CP_CONSUMER_CONTROL:
if (hidinput_field_in_collection(device, field,
HID_COLLECTION_NAMED_ARRAY,
HID_CP_PROGRAMMABLEBUTTONS)) {
if (code <= 0x1d)
code += KEY_MACRO1;
else
code += BTN_TRIGGER_HAPPY - 0x1e;
} else {
goto ignore;
}
break;
default:
switch (field->physical) {
case HID_GD_MOUSE:
@@ -1316,12 +1340,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
if (usage->hid == HID_DG_INVERT) {
*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
return;
}
if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
if (usage->hid == HID_DG_INRANGE) {
if (value) {
input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
return;
@@ -1331,7 +1355,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
if (usage->hid == HID_DG_TIPPRESSURE && (*quirks & HID_QUIRK_NOTOUCH)) {
int a = field->logical_minimum;
int b = field->logical_maximum;
input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));

View File

@@ -135,4 +135,5 @@ static struct hid_driver ite_driver = {
};
module_hid_driver(ite_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");

View File

@@ -28,6 +28,7 @@ enum lg_g15_model {
LG_G15_V2,
LG_G510,
LG_G510_USB_AUDIO,
LG_Z10,
};
enum lg_g15_led_type {
@@ -457,6 +458,13 @@ static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
return ret;
return lg_g510_update_mkey_led_brightness(g15);
case LG_Z10:
/*
* Getting the LCD backlight brightness is not supported.
* Reading Feature(2) fails with -EPIPE and this crashes
* the LCD and touch keys part of the speakers.
*/
return 0;
}
return -EINVAL; /* Never reached */
}
@@ -464,7 +472,20 @@ static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
/******** Input functions ********/
/* On the G15 Mark I Logitech has been quite creative with which bit is what */
static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
static void lg_g15_handle_lcd_menu_keys(struct lg_g15_data *g15, u8 *data)
{
int i, val;
/* Most left (round/display) button below the LCD */
input_report_key(g15->input, KEY_KBD_LCD_MENU1, data[8] & 0x80);
/* 4 other buttons below the LCD */
for (i = 0; i < 4; i++) {
val = data[i + 2] & 0x80;
input_report_key(g15->input, KEY_KBD_LCD_MENU2 + i, val);
}
}
static int lg_g15_event(struct lg_g15_data *g15, u8 *data)
{
int i, val;
@@ -494,13 +515,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
/* MR */
input_report_key(g15->input, KEY_MACRO_RECORD_START, data[7] & 0x40);
/* Most left (round) button below the LCD */
input_report_key(g15->input, KEY_KBD_LCD_MENU1, data[8] & 0x80);
/* 4 other buttons below the LCD */
for (i = 0; i < 4; i++) {
val = data[i + 2] & 0x80;
input_report_key(g15->input, KEY_KBD_LCD_MENU2 + i, val);
}
lg_g15_handle_lcd_menu_keys(g15, data);
/* Backlight cycle button pressed? */
if (data[1] & 0x80)
@@ -510,7 +525,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
return 0;
}
static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data, int size)
static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data)
{
int i, val;
@@ -542,7 +557,7 @@ static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data, int size)
return 0;
}
static int lg_g510_event(struct lg_g15_data *g15, u8 *data, int size)
static int lg_g510_event(struct lg_g15_data *g15, u8 *data)
{
bool game_mode_enabled;
int i, val;
@@ -586,7 +601,7 @@ static int lg_g510_event(struct lg_g15_data *g15, u8 *data, int size)
return 0;
}
static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data, int size)
static int lg_g510_leds_event(struct lg_g15_data *g15, u8 *data)
{
bool backlight_disabled;
@@ -613,18 +628,24 @@ static int lg_g15_raw_event(struct hid_device *hdev, struct hid_report *report,
switch (g15->model) {
case LG_G15:
if (data[0] == 0x02 && size == 9)
return lg_g15_event(g15, data, size);
return lg_g15_event(g15, data);
break;
case LG_G15_V2:
if (data[0] == 0x02 && size == 5)
return lg_g15_v2_event(g15, data, size);
return lg_g15_v2_event(g15, data);
break;
case LG_Z10:
if (data[0] == 0x02 && size == 9) {
lg_g15_handle_lcd_menu_keys(g15, data);
input_sync(g15->input);
}
break;
case LG_G510:
case LG_G510_USB_AUDIO:
if (data[0] == 0x03 && size == 5)
return lg_g510_event(g15, data, size);
return lg_g510_event(g15, data);
if (data[0] == 0x04 && size == 2)
return lg_g510_leds_event(g15, data, size);
return lg_g510_leds_event(g15, data);
break;
}
@@ -645,25 +666,18 @@ static void lg_g15_input_close(struct input_dev *dev)
hid_hw_close(hdev);
}
static int lg_g15_register_led(struct lg_g15_data *g15, int i)
static int lg_g15_register_led(struct lg_g15_data *g15, int i, const char *name)
{
static const char * const led_names[] = {
"g15::kbd_backlight",
"g15::lcd_backlight",
"g15::macro_preset1",
"g15::macro_preset2",
"g15::macro_preset3",
"g15::macro_record",
};
g15->leds[i].led = i;
g15->leds[i].cdev.name = led_names[i];
g15->leds[i].cdev.name = name;
switch (g15->model) {
case LG_G15:
case LG_G15_V2:
g15->leds[i].cdev.brightness_set_blocking = lg_g15_led_set;
g15->leds[i].cdev.brightness_get = lg_g15_led_get;
fallthrough;
case LG_Z10:
g15->leds[i].cdev.brightness_set_blocking = lg_g15_led_set;
if (i < LG_G15_BRIGHTNESS_MAX) {
g15->leds[i].cdev.flags = LED_BRIGHT_HW_CHANGED;
g15->leds[i].cdev.max_brightness = 2;
@@ -702,8 +716,38 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i)
return devm_led_classdev_register(&g15->hdev->dev, &g15->leds[i].cdev);
}
/* Common input device init code shared between keyboards and Z-10 speaker handling */
static void lg_g15_init_input_dev(struct hid_device *hdev, struct input_dev *input,
const char *name)
{
int i;
input->name = name;
input->phys = hdev->phys;
input->uniq = hdev->uniq;
input->id.bustype = hdev->bus;
input->id.vendor = hdev->vendor;
input->id.product = hdev->product;
input->id.version = hdev->version;
input->dev.parent = &hdev->dev;
input->open = lg_g15_input_open;
input->close = lg_g15_input_close;
/* Keys below the LCD, intended for controlling a menu on the LCD */
for (i = 0; i < 5; i++)
input_set_capability(input, EV_KEY, KEY_KBD_LCD_MENU1 + i);
}
static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
static const char * const led_names[] = {
"g15::kbd_backlight",
"g15::lcd_backlight",
"g15::macro_preset1",
"g15::macro_preset2",
"g15::macro_preset3",
"g15::macro_record",
};
u8 gkeys_settings_output_report = 0;
u8 gkeys_settings_feature_report = 0;
struct hid_report_enum *rep_enum;
@@ -744,6 +788,8 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
g15->hdev = hdev;
g15->model = id->driver_data;
g15->input = input;
input_set_drvdata(input, hdev);
hid_set_drvdata(hdev, (void *)g15);
switch (g15->model) {
@@ -772,6 +818,9 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
gkeys_settings_feature_report = 0x01;
gkeys = 18;
break;
case LG_Z10:
connect_mask = HID_CONNECT_HIDRAW;
break;
}
ret = hid_hw_start(hdev, connect_mask);
@@ -814,17 +863,21 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
goto error_hw_stop;
if (g15->model == LG_Z10) {
lg_g15_init_input_dev(hdev, g15->input, "Logitech Z-10 LCD Menu Keys");
ret = input_register_device(g15->input);
if (ret)
goto error_hw_stop;
ret = lg_g15_register_led(g15, 1, "z-10::lcd_backlight");
if (ret)
goto error_hw_stop;
return 0; /* All done */
}
/* Setup and register input device */
input->name = "Logitech Gaming Keyboard Gaming Keys";
input->phys = hdev->phys;
input->uniq = hdev->uniq;
input->id.bustype = hdev->bus;
input->id.vendor = hdev->vendor;
input->id.product = hdev->product;
input->id.version = hdev->version;
input->dev.parent = &hdev->dev;
input->open = lg_g15_input_open;
input->close = lg_g15_input_close;
lg_g15_init_input_dev(hdev, input, "Logitech Gaming Keyboard Gaming Keys");
/* G-keys */
for (i = 0; i < gkeys; i++)
@@ -835,10 +888,6 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
input_set_capability(input, EV_KEY, KEY_MACRO_PRESET1 + i);
input_set_capability(input, EV_KEY, KEY_MACRO_RECORD_START);
/* Keys below the LCD, intended for controlling a menu on the LCD */
for (i = 0; i < 5; i++)
input_set_capability(input, EV_KEY, KEY_KBD_LCD_MENU1 + i);
/*
* On the G510 only report headphone and mic mute keys when *not* using
* the builtin USB audio device. When the builtin audio is used these
@@ -850,16 +899,13 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
input_set_capability(input, EV_KEY, KEY_F20);
}
g15->input = input;
input_set_drvdata(input, hdev);
ret = input_register_device(input);
if (ret)
goto error_hw_stop;
/* Register LED devices */
for (i = 0; i < LG_G15_LED_MAX; i++) {
ret = lg_g15_register_led(g15, i);
ret = lg_g15_register_led(g15, i, led_names[i]);
if (ret)
goto error_hw_stop;
}
@@ -890,6 +936,10 @@ static const struct hid_device_id lg_g15_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO),
.driver_data = LG_G510_USB_AUDIO },
/* Z-10 speakers */
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_Z_10_SPK),
.driver_data = LG_Z10 },
{ }
};
MODULE_DEVICE_TABLE(hid, lg_g15_devices);
@@ -902,4 +952,5 @@ static struct hid_driver lg_g15_driver = {
};
module_hid_driver(lg_g15_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");

View File

@@ -100,6 +100,7 @@
#define HIDPP_DEVICE_TYPE_MASK GENMASK(3, 0)
#define HIDPP_LINK_STATUS_MASK BIT(6)
#define HIDPP_MANUFACTURER_MASK BIT(7)
#define HIDPP_27MHZ_SECURE_MASK BIT(7)
#define HIDPP_DEVICE_TYPE_KEYBOARD 1
#define HIDPP_DEVICE_TYPE_MOUSE 2
@@ -984,6 +985,13 @@ static void logi_hidpp_dev_conn_notif_27mhz(struct hid_device *hdev,
workitem->reports_supported |= STD_MOUSE | HIDPP;
break;
case 3: /* Index 3 is always the keyboard */
if (hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & HIDPP_27MHZ_SECURE_MASK) {
hid_info(hdev, "Keyboard connection is encrypted\n");
} else {
hid_warn(hdev, "Keyboard events are send over the air in plain-text / unencrypted\n");
hid_warn(hdev, "See: https://gitlab.freedesktop.org/jwrdegoede/logitech-27mhz-keyboard-encryption-setup/\n");
}
fallthrough;
case 4: /* Index 4 is used for an optional separate numpad */
workitem->device_type = HIDPP_DEVICE_TYPE_KEYBOARD;
workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA |
@@ -1489,6 +1497,13 @@ static void logi_dj_ll_stop(struct hid_device *hid)
dbg_hid("%s\n", __func__);
}
static bool logi_dj_ll_may_wakeup(struct hid_device *hid)
{
struct dj_device *djdev = hid->driver_data;
struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
return hid_hw_may_wakeup(djrcv_dev->hidpp);
}
static struct hid_ll_driver logi_dj_ll_driver = {
.parse = logi_dj_ll_parse,
@@ -1497,6 +1512,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
.open = logi_dj_ll_open,
.close = logi_dj_ll_close,
.raw_request = logi_dj_ll_raw_request,
.may_wakeup = logi_dj_ll_may_wakeup,
};
static int logi_dj_dj_event(struct hid_device *hdev,

View File

@@ -56,6 +56,8 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define HIDPP_SUB_ID_CONSUMER_VENDOR_KEYS 0x03
#define HIDPP_SUB_ID_ROLLER 0x05
#define HIDPP_SUB_ID_MOUSE_EXTRA_BTNS 0x06
#define HIDPP_SUB_ID_USER_IFACE_EVENT 0x08
#define HIDPP_USER_IFACE_EVENT_ENCRYPTION_KEY_LOST BIT(5)
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
@@ -3529,6 +3531,16 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
return 1;
}
if (hidpp->hid_dev->group == HID_GROUP_LOGITECH_27MHZ_DEVICE &&
data[0] == REPORT_ID_HIDPP_SHORT &&
data[2] == HIDPP_SUB_ID_USER_IFACE_EVENT &&
(data[3] & HIDPP_USER_IFACE_EVENT_ENCRYPTION_KEY_LOST)) {
dev_err_ratelimited(&hidpp->hid_dev->dev,
"Error the keyboard's wireless encryption key has been lost, your keyboard will not work unless you re-configure encryption.\n");
dev_err_ratelimited(&hidpp->hid_dev->dev,
"See: https://gitlab.freedesktop.org/jwrdegoede/logitech-27mhz-keyboard-encryption-setup/\n");
}
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
ret = hidpp20_battery_event_1000(hidpp, data, size);
if (ret != 0)

View File

@@ -1768,7 +1768,8 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
struct mt_device *td = hid_get_drvdata(hdev);
/* High latency is desirable for power savings during S3/S0ix */
if (td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP)
if ((td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP) ||
!hid_hw_may_wakeup(hdev))
mt_set_modes(hdev, HID_LATENCY_HIGH, false, false);
else
mt_set_modes(hdev, HID_LATENCY_HIGH, true, true);

View File

@@ -597,9 +597,8 @@ struct sony_sc {
/* DS4 calibration data */
struct ds4_calibration_data ds4_calib_data[6];
/* GH Live */
struct urb *ghl_urb;
struct timer_list ghl_poke_timer;
struct usb_ctrlrequest *ghl_cr;
u8 *ghl_databuf;
};
static void sony_set_leds(struct sony_sc *sc);
@@ -625,66 +624,54 @@ static inline void sony_schedule_work(struct sony_sc *sc,
static void ghl_magic_poke_cb(struct urb *urb)
{
if (urb) {
/* Free sc->ghl_cr and sc->ghl_databuf allocated in
* ghl_magic_poke()
*/
kfree(urb->setup_packet);
kfree(urb->transfer_buffer);
}
struct sony_sc *sc = urb->context;
if (urb->status < 0)
hid_err(sc->hdev, "URB transfer failed : %d", urb->status);
mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
}
static void ghl_magic_poke(struct timer_list *t)
{
int ret;
struct sony_sc *sc = from_timer(sc, t, ghl_poke_timer);
int ret;
unsigned int pipe;
struct urb *urb;
struct usb_device *usbdev = to_usb_device(sc->hdev->dev.parent->parent);
const u16 poke_size =
ARRAY_SIZE(ghl_ps3wiiu_magic_data);
ret = usb_submit_urb(sc->ghl_urb, GFP_ATOMIC);
if (ret < 0)
hid_err(sc->hdev, "usb_submit_urb failed: %d", ret);
}
static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev)
{
struct usb_ctrlrequest *cr;
u16 poke_size;
u8 *databuf;
unsigned int pipe;
poke_size = ARRAY_SIZE(ghl_ps3wiiu_magic_data);
pipe = usb_sndctrlpipe(usbdev, 0);
if (!sc->ghl_cr) {
sc->ghl_cr = kzalloc(sizeof(*sc->ghl_cr), GFP_ATOMIC);
if (!sc->ghl_cr)
goto resched;
}
cr = devm_kzalloc(&sc->hdev->dev, sizeof(*cr), GFP_ATOMIC);
if (cr == NULL)
return -ENOMEM;
if (!sc->ghl_databuf) {
sc->ghl_databuf = kzalloc(poke_size, GFP_ATOMIC);
if (!sc->ghl_databuf)
goto resched;
}
databuf = devm_kzalloc(&sc->hdev->dev, poke_size, GFP_ATOMIC);
if (databuf == NULL)
return -ENOMEM;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb)
goto resched;
sc->ghl_cr->bRequestType =
cr->bRequestType =
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT;
sc->ghl_cr->bRequest = USB_REQ_SET_CONFIGURATION;
sc->ghl_cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
sc->ghl_cr->wIndex = 0;
sc->ghl_cr->wLength = cpu_to_le16(poke_size);
memcpy(sc->ghl_databuf, ghl_ps3wiiu_magic_data, poke_size);
cr->bRequest = USB_REQ_SET_CONFIGURATION;
cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
cr->wIndex = 0;
cr->wLength = cpu_to_le16(poke_size);
memcpy(databuf, ghl_ps3wiiu_magic_data, poke_size);
usb_fill_control_urb(
urb, usbdev, pipe,
(unsigned char *) sc->ghl_cr, sc->ghl_databuf,
poke_size, ghl_magic_poke_cb, NULL);
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
kfree(sc->ghl_databuf);
kfree(sc->ghl_cr);
}
usb_free_urb(urb);
resched:
/* Reschedule for next time */
mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
sc->ghl_urb, usbdev, pipe,
(unsigned char *) cr, databuf, poke_size,
ghl_magic_poke_cb, sc);
return 0;
}
static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -2981,6 +2968,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
int ret;
unsigned long quirks = id->driver_data;
struct sony_sc *sc;
struct usb_device *usbdev;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
if (!strcmp(hdev->name, "FutureMax Dance Mat"))
@@ -3000,6 +2988,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
sc->quirks = quirks;
hid_set_drvdata(hdev, sc);
sc->hdev = hdev;
usbdev = to_usb_device(sc->hdev->dev.parent->parent);
ret = hid_parse(hdev);
if (ret) {
@@ -3042,6 +3031,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!sc->ghl_urb)
return -ENOMEM;
ret = ghl_init_urb(sc, usbdev);
if (ret) {
hid_err(hdev, "error preparing URB\n");
return ret;
}
timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0);
mod_timer(&sc->ghl_poke_timer,
jiffies + GHL_GUITAR_POKE_INTERVAL*HZ);
@@ -3054,8 +3052,10 @@ static void sony_remove(struct hid_device *hdev)
{
struct sony_sc *sc = hid_get_drvdata(hdev);
if (sc->quirks & GHL_GUITAR_PS3WIIU)
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
del_timer_sync(&sc->ghl_poke_timer);
usb_free_urb(sc->ghl_urb);
}
hid_hw_close(hdev);

View File

@@ -311,12 +311,13 @@ static int thrustmaster_probe(struct hid_device *hdev, const struct hid_device_i
goto error4;
}
tm_wheel->change_request = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
tm_wheel->change_request = kmemdup(&change_request,
sizeof(struct usb_ctrlrequest),
GFP_KERNEL);
if (!tm_wheel->change_request) {
ret = -ENOMEM;
goto error5;
}
memcpy(tm_wheel->change_request, &change_request, sizeof(struct usb_ctrlrequest));
tm_wheel->usb_dev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
hid_set_drvdata(hdev, tm_wheel);

Some files were not shown because too many files have changed in this diff Show More