mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
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:
@@ -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*
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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] = {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user