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
commit df04fbe868
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 AMD SENSOR FUSION HUB DRIVER
M: Nehal Shah <nehal-bakulchandra.shah@amd.com> 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 L: linux-input@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/hid/amd-sfh* 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) 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 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; struct request_list *req_node;
u8 current_index, sensor_index; u8 current_index, sensor_index;
u8 report_id, node_type; 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"); pr_err("AMDSFH: Invalid report size\n");
} else if (node_type == HID_INPUT_REPORT) { } else if (node_type == HID_INPUT_REPORT) {
report_size = get_input_report(sensor_index, report_id, report_size = get_input_report(current_index, sensor_index, report_id, in_data);
cli_data->input_report[current_index],
cli_data->sensor_virt_addr[current_index]);
if (report_size) if (report_size)
hid_input_report(cli_data->hid_sensor_hubs[current_index], hid_input_report(cli_data->hid_sensor_hubs[current_index],
cli_data->report_type[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 else
pr_err("AMDSFH: Invalid report size\n"); 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) 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 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; u8 report_size;
int i; int i;
for (i = 0; i < cli_data->num_hid_devices; 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], report_size = get_input_report(i, cli_data->sensor_idx[i], cli_data->report_id[i],
cli_data->input_report[i], in_data);
cli_data->sensor_virt_addr[i]);
hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, 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)); 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) 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 amdtp_cl_data *cl_data = privdata->cl_data;
struct amd_mp2_sensor_info info; struct amd_mp2_sensor_info info;
struct device *dev; struct device *dev;
@ -143,18 +143,16 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
int rc, i; int rc, i;
dev = &privdata->pdev->dev; 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]); 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, amd_sfh_work);
INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
INIT_LIST_HEAD(&req_list.list); INIT_LIST_HEAD(&req_list.list);
cl_data->in_data = in_data;
for (i = 0; i < cl_data->num_hid_devices; i++) { 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], &cl_data->sensor_dma_addr[i],
GFP_KERNEL); GFP_KERNEL);
cl_data->sensor_sts[i] = 0; cl_data->sensor_sts[i] = 0;
@ -181,8 +179,8 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
rc = -ENOMEM; rc = -ENOMEM;
goto cleanup; goto cleanup;
} }
cl_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL); in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
if (!cl_data->input_report[i]) { if (!in_data->input_report[i]) {
rc = -ENOMEM; rc = -ENOMEM;
goto cleanup; 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); rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
if (rc) if (rc)
return rc; return rc;
amd_start_sensor(privdata, info); privdata->mp2_ops->start(privdata, info);
cl_data->sensor_sts[i] = 1; 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)); schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
return 0; return 0;
cleanup: cleanup:
for (i = 0; i < cl_data->num_hid_devices; i++) { 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), 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]); cl_data->sensor_dma_addr[i]);
} }
devm_kfree(dev, cl_data->feature_report[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->report_descr[i]);
} }
devm_kfree(dev, cl_data);
return rc; return rc;
} }
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata) int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
{ {
struct amdtp_cl_data *cl_data = privdata->cl_data; struct amdtp_cl_data *cl_data = privdata->cl_data;
struct amd_input_data *in_data = cl_data->in_data;
int i; int i;
for (i = 0; i < cl_data->num_hid_devices; 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);
cancel_delayed_work_sync(&cl_data->work_buffer); cancel_delayed_work_sync(&cl_data->work_buffer);
amdtp_hid_remove(cl_data); amdtp_hid_remove(cl_data);
for (i = 0; i < cl_data->num_hid_devices; i++) { 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), 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]); cl_data->sensor_dma_addr[i]);
} }
} }

View File

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

View File

@ -24,12 +24,55 @@
#define ACEL_EN BIT(0) #define ACEL_EN BIT(0)
#define GYRO_EN BIT(1) #define GYRO_EN BIT(1)
#define MAGNO_EN BIT(2) #define MAGNO_EN BIT(2)
#define HPD_EN BIT(16)
#define ALS_EN BIT(19) #define ALS_EN BIT(19)
static int sensor_mask_override = -1; static int sensor_mask_override = -1;
module_param_named(sensor_mask, sensor_mask_override, int, 0444); module_param_named(sensor_mask, sensor_mask_override, int, 0444);
MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask"); 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) void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
{ {
union sfh_cmd_param cmd_param; union sfh_cmd_param cmd_param;
@ -98,7 +141,6 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
{ {
int activestatus, num_of_sensors = 0; int activestatus, num_of_sensors = 0;
const struct dmi_system_id *dmi_id; const struct dmi_system_id *dmi_id;
u32 activecontrolstatus;
if (sensor_mask_override == -1) { if (sensor_mask_override == -1) {
dmi_id = dmi_first_match(dmi_sensor_mask_overrides); 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) { if (sensor_mask_override >= 0) {
activestatus = sensor_mask_override; activestatus = sensor_mask_override;
} else { } else {
activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3); activestatus = privdata->mp2_acs >> 4;
activestatus = activecontrolstatus >> 4;
} }
if (ACEL_EN & activestatus) 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) if (ALS_EN & activestatus)
sensor_id[num_of_sensors++] = als_idx; sensor_id[num_of_sensors++] = als_idx;
if (HPD_EN & activestatus)
sensor_id[num_of_sensors++] = HPD_IDX;
return num_of_sensors; return num_of_sensors;
} }
static void amd_mp2_pci_remove(void *privdata) static void amd_mp2_pci_remove(void *privdata)
{ {
struct amd_mp2_dev *mp2 = privdata;
amd_sfh_hid_client_deinit(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) 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)); rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
return rc; 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); rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
if (rc) if (rc)
return rc; return rc;
mp2_select_ops(privdata);
return amd_sfh_hid_client_init(privdata); return amd_sfh_hid_client_init(privdata);
} }

View File

@ -10,6 +10,7 @@
#define PCIE_MP2_AMD_H #define PCIE_MP2_AMD_H
#include <linux/pci.h> #include <linux/pci.h>
#include "amd_sfh_hid.h"
#define PCI_DEVICE_ID_AMD_MP2 0x15E4 #define PCI_DEVICE_ID_AMD_MP2 0x15E4
@ -22,9 +23,15 @@
#define AMD_C2P_MSG1 0x10504 #define AMD_C2P_MSG1 0x10504
#define AMD_C2P_MSG2 0x10508 #define AMD_C2P_MSG2 0x10508
#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
/* MP2 P2C Message Registers */ /* MP2 P2C Message Registers */
#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */ #define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */
#define V2_STATUS 0x2
#define HPD_IDX 16
/* SFH Command register */ /* SFH Command register */
union sfh_cmd_base { union sfh_cmd_base {
u32 ul; u32 ul;
@ -33,6 +40,15 @@ union sfh_cmd_base {
u32 sensor_id : 8; u32 sensor_id : 8;
u32 period : 16; u32 period : 16;
} s; } 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 { union sfh_cmd_param {
@ -61,6 +77,10 @@ struct amd_mp2_dev {
struct pci_dev *pdev; struct pci_dev *pdev;
struct amdtp_cl_data *cl_data; struct amdtp_cl_data *cl_data;
void __iomem *mmio; 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 { struct amd_mp2_sensor_info {
@ -69,10 +89,33 @@ struct amd_mp2_sensor_info {
dma_addr_t dma_address; 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_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_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx);
void amd_stop_all_sensors(struct amd_mp2_dev *privdata); 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_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_init(struct amd_mp2_dev *privdata);
int amd_sfh_hid_client_deinit(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 #endif

View File

@ -12,6 +12,7 @@
#include "amd_sfh_pcie.h" #include "amd_sfh_pcie.h"
#include "amd_sfh_hid_desc.h" #include "amd_sfh_hid_desc.h"
#include "amd_sfh_hid_report_desc.h" #include "amd_sfh_hid_report_desc.h"
#include "amd_sfh_hid.h"
#define AMD_SFH_FW_MULTIPLIER (1000) #define AMD_SFH_FW_MULTIPLIER (1000)
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41 #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, memcpy(rep_desc, als_report_descriptor,
sizeof(als_report_descriptor)); sizeof(als_report_descriptor));
break; 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: default:
break; break;
} }
@ -98,6 +104,17 @@ u32 get_descr_sz(int sensor_idx, int descriptor_name)
return sizeof(struct als_feature_report); return sizeof(struct als_feature_report);
} }
break; 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: default:
break; 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 accel3_feature_report acc_feature;
struct gyro_feature_report gyro_feature; struct gyro_feature_report gyro_feature;
struct magno_feature_report magno_feature; struct magno_feature_report magno_feature;
struct hpd_feature_report hpd_feature;
struct als_feature_report als_feature; struct als_feature_report als_feature;
u8 report_size = 0; 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)); memcpy(feature_report, &als_feature, sizeof(als_feature));
report_size = sizeof(als_feature); report_size = sizeof(als_feature);
break; 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: default:
break; 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; 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 accel3_input_report acc_input;
struct gyro_input_report gyro_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 als_input_report als_input;
struct hpd_status hpdstatus;
u8 report_size = 0; u8 report_size = 0;
if (!sensor_virt_addr || !input_report) 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; break;
case als_idx: /* Als */ case als_idx: /* Als */
get_common_inputs(&als_input.common_property, report_id); 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); report_size = sizeof(als_input);
memcpy(input_report, &als_input, sizeof(als_input)); memcpy(input_report, &als_input, sizeof(als_input));
break; 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: default:
break; break;
} }

View File

@ -100,8 +100,17 @@ struct als_input_report {
int illuminance_value; int illuminance_value;
} __packed; } __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[]); int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
u32 get_descr_sz(int sensor_idx, int descriptor_name); 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_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 #endif

View File

@ -642,4 +642,116 @@ const u8 als_report_descriptor[] = {
0X81, 0x02, /* HID Input (Data_Arr_Abs) */ 0X81, 0x02, /* HID Input (Data_Arr_Abs) */
0xC0 /* HID end collection */ 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 #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_device *hdev = to_hid_device(dev);
struct hid_driver *hdrv; struct hid_driver *hdrv;
int ret = 0;
if (down_interruptible(&hdev->driver_input_lock)) { down(&hdev->driver_input_lock);
ret = -EINTR;
goto end;
}
hdev->io_started = false; hdev->io_started = false;
hdrv = hdev->driver; hdrv = hdev->driver;
@ -2326,8 +2322,8 @@ static int hid_device_remove(struct device *dev)
if (!hdev->io_started) if (!hdev->io_started)
up(&hdev->driver_input_lock); up(&hdev->driver_input_lock);
end:
return ret; return 0;
} }
static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 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" }, { 9, 0, "Button" },
{ 10, 0, "Ordinal" }, { 10, 0, "Ordinal" },
{ 12, 0, "Consumer" }, { 12, 0, "Consumer" },
{0, 0x003, "ProgrammableButtons"},
{0, 0x238, "HorizontalWheel"}, {0, 0x238, "HorizontalWheel"},
{ 13, 0, "Digitizers" }, { 13, 0, "Digitizers" },
{0, 0x01, "Digitizer"}, {0, 0x01, "Digitizer"},
@ -942,6 +943,16 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_KBDINPUTASSIST_NEXTGROUP] = "KbdInputAssistNextGroup", [KEY_KBDINPUTASSIST_NEXTGROUP] = "KbdInputAssistNextGroup",
[KEY_KBDINPUTASSIST_ACCEPT] = "KbdInputAssistAccept", [KEY_KBDINPUTASSIST_ACCEPT] = "KbdInputAssistAccept",
[KEY_KBDINPUTASSIST_CANCEL] = "KbdInputAssistCancel", [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] = { static const char *relatives[REL_MAX + 1] = {

View File

@ -17,6 +17,7 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h> #include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.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); 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 = { static struct platform_driver cbas_ec_driver = {
.probe = cbas_ec_probe, .probe = cbas_ec_probe,
.remove = cbas_ec_remove, .remove = cbas_ec_remove,
.driver = { .driver = {
.name = "cbas_ec", .name = "cbas_ec",
.acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids), .acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids),
.of_match_table = of_match_ptr(cbas_ec_of_match),
.pm = &cbas_ec_pm_ops, .pm = &cbas_ec_pm_ops,
}, },
}; };

View File

@ -396,6 +396,7 @@
#define USB_DEVICE_ID_HP_X2_10_COVER 0x0755 #define USB_DEVICE_ID_HP_X2_10_COVER 0x0755
#define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817 #define I2C_DEVICE_ID_HP_SPECTRE_X360_15 0x2817
#define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706
#define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A
#define USB_VENDOR_ID_ELECOM 0x056e #define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061 #define USB_DEVICE_ID_ELECOM_BM084 0x0061
@ -763,6 +764,7 @@
#define I2C_DEVICE_ID_LG_7010 0x7010 #define I2C_DEVICE_ID_LG_7010 0x7010
#define USB_VENDOR_ID_LOGITECH 0x046d #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_AUDIOHUB 0x0a0e
#define USB_DEVICE_ID_LOGITECH_T651 0xb00c #define USB_DEVICE_ID_LOGITECH_T651 0xb00c
#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 #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_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15), { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),
HID_BATTERY_QUIRK_IGNORE }, 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 */ #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, static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage) struct hid_usage *usage)
{ {
@ -632,6 +644,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
else else
code += BTN_TRIGGER_HAPPY - 0x10; code += BTN_TRIGGER_HAPPY - 0x10;
break; 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: default:
switch (field->physical) { switch (field->physical) {
case HID_GD_MOUSE: case HID_GD_MOUSE:
@ -1316,12 +1340,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return; 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); *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
return; return;
} }
if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ if (usage->hid == HID_DG_INRANGE) {
if (value) { if (value) {
input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
return; return;
@ -1331,7 +1355,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return; 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 a = field->logical_minimum;
int b = field->logical_maximum; int b = field->logical_maximum;
input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); 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_hid_driver(ite_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -28,6 +28,7 @@ enum lg_g15_model {
LG_G15_V2, LG_G15_V2,
LG_G510, LG_G510,
LG_G510_USB_AUDIO, LG_G510_USB_AUDIO,
LG_Z10,
}; };
enum lg_g15_led_type { 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 ret;
return lg_g510_update_mkey_led_brightness(g15); 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 */ return -EINVAL; /* Never reached */
} }
@ -464,7 +472,20 @@ static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
/******** Input functions ********/ /******** Input functions ********/
/* On the G15 Mark I Logitech has been quite creative with which bit is what */ /* 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; int i, val;
@ -494,13 +515,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
/* MR */ /* MR */
input_report_key(g15->input, KEY_MACRO_RECORD_START, data[7] & 0x40); input_report_key(g15->input, KEY_MACRO_RECORD_START, data[7] & 0x40);
/* Most left (round) button below the LCD */ lg_g15_handle_lcd_menu_keys(g15, data);
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);
}
/* Backlight cycle button pressed? */ /* Backlight cycle button pressed? */
if (data[1] & 0x80) if (data[1] & 0x80)
@ -510,7 +525,7 @@ static int lg_g15_event(struct lg_g15_data *g15, u8 *data, int size)
return 0; 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; int i, val;
@ -542,7 +557,7 @@ static int lg_g15_v2_event(struct lg_g15_data *g15, u8 *data, int size)
return 0; 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; bool game_mode_enabled;
int i, val; int i, val;
@ -586,7 +601,7 @@ static int lg_g510_event(struct lg_g15_data *g15, u8 *data, int size)
return 0; 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; bool backlight_disabled;
@ -613,18 +628,24 @@ static int lg_g15_raw_event(struct hid_device *hdev, struct hid_report *report,
switch (g15->model) { switch (g15->model) {
case LG_G15: case LG_G15:
if (data[0] == 0x02 && size == 9) if (data[0] == 0x02 && size == 9)
return lg_g15_event(g15, data, size); return lg_g15_event(g15, data);
break; break;
case LG_G15_V2: case LG_G15_V2:
if (data[0] == 0x02 && size == 5) 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; break;
case LG_G510: case LG_G510:
case LG_G510_USB_AUDIO: case LG_G510_USB_AUDIO:
if (data[0] == 0x03 && size == 5) 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) if (data[0] == 0x04 && size == 2)
return lg_g510_leds_event(g15, data, size); return lg_g510_leds_event(g15, data);
break; break;
} }
@ -645,25 +666,18 @@ static void lg_g15_input_close(struct input_dev *dev)
hid_hw_close(hdev); 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].led = i;
g15->leds[i].cdev.name = led_names[i]; g15->leds[i].cdev.name = name;
switch (g15->model) { switch (g15->model) {
case LG_G15: case LG_G15:
case LG_G15_V2: 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; 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) { if (i < LG_G15_BRIGHTNESS_MAX) {
g15->leds[i].cdev.flags = LED_BRIGHT_HW_CHANGED; g15->leds[i].cdev.flags = LED_BRIGHT_HW_CHANGED;
g15->leds[i].cdev.max_brightness = 2; 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); 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 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_output_report = 0;
u8 gkeys_settings_feature_report = 0; u8 gkeys_settings_feature_report = 0;
struct hid_report_enum *rep_enum; 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->hdev = hdev;
g15->model = id->driver_data; g15->model = id->driver_data;
g15->input = input;
input_set_drvdata(input, hdev);
hid_set_drvdata(hdev, (void *)g15); hid_set_drvdata(hdev, (void *)g15);
switch (g15->model) { 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_settings_feature_report = 0x01;
gkeys = 18; gkeys = 18;
break; break;
case LG_Z10:
connect_mask = HID_CONNECT_HIDRAW;
break;
} }
ret = hid_hw_start(hdev, connect_mask); 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) if (ret)
goto error_hw_stop; 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 */ /* Setup and register input device */
input->name = "Logitech Gaming Keyboard Gaming Keys"; lg_g15_init_input_dev(hdev, input, "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;
/* G-keys */ /* G-keys */
for (i = 0; i < gkeys; i++) 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_PRESET1 + i);
input_set_capability(input, EV_KEY, KEY_MACRO_RECORD_START); 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 * 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 * 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); input_set_capability(input, EV_KEY, KEY_F20);
} }
g15->input = input;
input_set_drvdata(input, hdev);
ret = input_register_device(input); ret = input_register_device(input);
if (ret) if (ret)
goto error_hw_stop; goto error_hw_stop;
/* Register LED devices */ /* Register LED devices */
for (i = 0; i < LG_G15_LED_MAX; i++) { 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) if (ret)
goto error_hw_stop; goto error_hw_stop;
} }
@ -890,6 +936,10 @@ static const struct hid_device_id lg_g15_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO), USB_DEVICE_ID_LOGITECH_G510_USB_AUDIO),
.driver_data = LG_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); 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_hid_driver(lg_g15_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -100,6 +100,7 @@
#define HIDPP_DEVICE_TYPE_MASK GENMASK(3, 0) #define HIDPP_DEVICE_TYPE_MASK GENMASK(3, 0)
#define HIDPP_LINK_STATUS_MASK BIT(6) #define HIDPP_LINK_STATUS_MASK BIT(6)
#define HIDPP_MANUFACTURER_MASK BIT(7) #define HIDPP_MANUFACTURER_MASK BIT(7)
#define HIDPP_27MHZ_SECURE_MASK BIT(7)
#define HIDPP_DEVICE_TYPE_KEYBOARD 1 #define HIDPP_DEVICE_TYPE_KEYBOARD 1
#define HIDPP_DEVICE_TYPE_MOUSE 2 #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; workitem->reports_supported |= STD_MOUSE | HIDPP;
break; break;
case 3: /* Index 3 is always the keyboard */ 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 */ case 4: /* Index 4 is used for an optional separate numpad */
workitem->device_type = HIDPP_DEVICE_TYPE_KEYBOARD; workitem->device_type = HIDPP_DEVICE_TYPE_KEYBOARD;
workitem->reports_supported |= STD_KEYBOARD | MULTIMEDIA | 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__); 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 = { static struct hid_ll_driver logi_dj_ll_driver = {
.parse = logi_dj_ll_parse, .parse = logi_dj_ll_parse,
@ -1497,6 +1512,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
.open = logi_dj_ll_open, .open = logi_dj_ll_open,
.close = logi_dj_ll_close, .close = logi_dj_ll_close,
.raw_request = logi_dj_ll_raw_request, .raw_request = logi_dj_ll_raw_request,
.may_wakeup = logi_dj_ll_may_wakeup,
}; };
static int logi_dj_dj_event(struct hid_device *hdev, 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_CONSUMER_VENDOR_KEYS 0x03
#define HIDPP_SUB_ID_ROLLER 0x05 #define HIDPP_SUB_ID_ROLLER 0x05
#define HIDPP_SUB_ID_MOUSE_EXTRA_BTNS 0x06 #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_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1) #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; 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) { if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
ret = hidpp20_battery_event_1000(hidpp, data, size); ret = hidpp20_battery_event_1000(hidpp, data, size);
if (ret != 0) 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); struct mt_device *td = hid_get_drvdata(hdev);
/* High latency is desirable for power savings during S3/S0ix */ /* 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); mt_set_modes(hdev, HID_LATENCY_HIGH, false, false);
else else
mt_set_modes(hdev, HID_LATENCY_HIGH, true, true); mt_set_modes(hdev, HID_LATENCY_HIGH, true, true);

View File

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

View File

@ -5,6 +5,7 @@ menu "Intel ISH HID support"
config INTEL_ISH_HID config INTEL_ISH_HID
tristate "Intel Integrated Sensor Hub" tristate "Intel Integrated Sensor Hub"
default n default n
depends on X86
select HID select HID
help help
The Integrated Sensor Hub (ISH) enables the ability to offload The Integrated Sensor Hub (ISH) enables the ability to offload

View File

@ -544,7 +544,7 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
#define TIMEOUT_FOR_HW_RDY_MS 300 #define TIMEOUT_FOR_HW_RDY_MS 300
/** /**
* ish_fw_reset_work_fn() - FW reset worker function * fw_reset_work_fn() - FW reset worker function
* @unused: not used * @unused: not used
* *
* Call ish_fw_reset_handler to complete FW reset * Call ish_fw_reset_handler to complete FW reset
@ -889,6 +889,29 @@ static uint32_t ish_ipc_get_header(struct ishtp_device *dev, int length,
return drbl_val; return drbl_val;
} }
/**
* _dma_no_cache_snooping()
*
* Check on current platform, DMA supports cache snooping or not.
* This callback is used to notify uplayer driver if manully cache
* flush is needed when do DMA operation.
*
* Please pay attention to this callback implementation, if declare
* having cache snooping on a cache snooping not supported platform
* will cause uplayer driver receiving mismatched data; and if
* declare no cache snooping on a cache snooping supported platform
* will cause cache be flushed twice and performance hit.
*
* @dev: ishtp device pointer
*
* Return: false - has cache snooping capability
* true - no cache snooping, need manually cache flush
*/
static bool _dma_no_cache_snooping(struct ishtp_device *dev)
{
return dev->pdev->device == EHL_Ax_DEVICE_ID;
}
static const struct ishtp_hw_ops ish_hw_ops = { static const struct ishtp_hw_ops ish_hw_ops = {
.hw_reset = _ish_hw_reset, .hw_reset = _ish_hw_reset,
.ipc_reset = _ish_ipc_reset, .ipc_reset = _ish_ipc_reset,
@ -897,7 +920,8 @@ static const struct ishtp_hw_ops ish_hw_ops = {
.write = write_ipc_to_queue, .write = write_ipc_to_queue,
.get_fw_status = _ish_read_fw_sts_reg, .get_fw_status = _ish_read_fw_sts_reg,
.sync_fw_clock = _ish_sync_fw_clock, .sync_fw_clock = _ish_sync_fw_clock,
.ishtp_read_hdr = _ishtp_read_hdr .ishtp_read_hdr = _ishtp_read_hdr,
.dma_no_cache_snooping = _dma_no_cache_snooping
}; };
/** /**

View File

@ -263,7 +263,6 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
struct pci_dev *pdev = to_pci_dev(ish_resume_device); struct pci_dev *pdev = to_pci_dev(ish_resume_device);
struct ishtp_device *dev = pci_get_drvdata(pdev); struct ishtp_device *dev = pci_get_drvdata(pdev);
uint32_t fwsts = dev->ops->get_fw_status(dev); uint32_t fwsts = dev->ops->get_fw_status(dev);
int ret;
if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag
&& IPC_IS_ISH_ILUP(fwsts)) { && IPC_IS_ISH_ILUP(fwsts)) {
@ -275,7 +274,7 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
/* Waiting to get resume response */ /* Waiting to get resume response */
if (dev->resume_flag) if (dev->resume_flag)
ret = wait_event_interruptible_timeout(dev->resume_wait, wait_event_interruptible_timeout(dev->resume_wait,
!dev->resume_flag, !dev->resume_flag,
msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS)); msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));

View File

@ -31,13 +31,13 @@
/** /**
* enum ish_loader_commands - ISH loader host commands. * enum ish_loader_commands - ISH loader host commands.
* LOADER_CMD_XFER_QUERY Query the Shim firmware loader for * @LOADER_CMD_XFER_QUERY: Query the Shim firmware loader for
* capabilities * capabilities
* LOADER_CMD_XFER_FRAGMENT Transfer one firmware image fragment at a * @LOADER_CMD_XFER_FRAGMENT: Transfer one firmware image fragment at a
* time. The command may be executed * time. The command may be executed
* multiple times until the entire firmware * multiple times until the entire firmware
* image is downloaded to SRAM. * image is downloaded to SRAM.
* LOADER_CMD_START Start executing the main firmware. * @LOADER_CMD_START: Start executing the main firmware.
*/ */
enum ish_loader_commands { enum ish_loader_commands {
LOADER_CMD_XFER_QUERY = 0, LOADER_CMD_XFER_QUERY = 0,
@ -95,6 +95,7 @@ static int dma_buf_size_limit = 4 * PAGE_SIZE;
/** /**
* struct loader_msg_hdr - Header for ISH Loader commands. * struct loader_msg_hdr - Header for ISH Loader commands.
* @command: LOADER_CMD* commands. Bit 7 is the response. * @command: LOADER_CMD* commands. Bit 7 is the response.
* @reserved: Reserved space
* @status: Command response status. Non 0, is error * @status: Command response status. Non 0, is error
* condition. * condition.
* *
@ -173,16 +174,16 @@ struct loader_start {
* struct response_info - Encapsulate firmware response related * struct response_info - Encapsulate firmware response related
* information for passing between function * information for passing between function
* loader_cl_send() and process_recv() callback. * loader_cl_send() and process_recv() callback.
* @data Copy the data received from firmware here. * @data: Copy the data received from firmware here.
* @max_size Max size allocated for the @data buffer. If the * @max_size: Max size allocated for the @data buffer. If the
* received data exceeds this value, we log an * received data exceeds this value, we log an
* error. * error.
* @size Actual size of data received from firmware. * @size: Actual size of data received from firmware.
* @error Returns 0 for success, negative error code for a * @error: Returns 0 for success, negative error code for a
* failure in function process_recv(). * failure in function process_recv().
* @received Set to true on receiving a valid firmware * @received: Set to true on receiving a valid firmware
* response to host command * response to host command
* @wait_queue Wait queue for Host firmware loading where the * @wait_queue: Wait queue for Host firmware loading where the
* client sends message to ISH firmware and waits * client sends message to ISH firmware and waits
* for response * for response
*/ */
@ -195,13 +196,13 @@ struct response_info {
wait_queue_head_t wait_queue; wait_queue_head_t wait_queue;
}; };
/** /*
* struct ishtp_cl_data - Encapsulate per ISH-TP Client Data. * struct ishtp_cl_data - Encapsulate per ISH-TP Client Data.
* @work_ishtp_reset: Work queue for reset handling. * @work_ishtp_reset: Work queue for reset handling.
* @work_fw_load: Work queue for host firmware loading. * @work_fw_load: Work queue for host firmware loading.
* @flag_retry Flag for indicating host firmware loading should * @flag_retry: Flag for indicating host firmware loading should
* be retried. * be retried.
* @retry_count Count the number of retries. * @retry_count: Count the number of retries.
* *
* This structure is used to store data per client. * This structure is used to store data per client.
*/ */
@ -240,8 +241,8 @@ struct ishtp_cl_data {
/** /**
* get_firmware_variant() - Gets the filename of firmware image to be * get_firmware_variant() - Gets the filename of firmware image to be
* loaded based on platform variant. * loaded based on platform variant.
* @client_data Client data instance. * @client_data: Client data instance.
* @filename Returns firmware filename. * @filename: Returns firmware filename.
* *
* Queries the firmware-name device property string. * Queries the firmware-name device property string.
* *
@ -266,11 +267,11 @@ static int get_firmware_variant(struct ishtp_cl_data *client_data,
/** /**
* loader_cl_send() Send message from host to firmware * loader_cl_send() Send message from host to firmware
* @client_data: Client data instance * @client_data: Client data instance
* @out_msg Message buffer to be sent to firmware * @out_msg: Message buffer to be sent to firmware
* @out_size Size of out going message * @out_size: Size of out going message
* @in_msg Message buffer where the incoming data copied. * @in_msg: Message buffer where the incoming data copied.
* This buffer is allocated by calling * This buffer is allocated by calling
* @in_size Max size of incoming message * @in_size: Max size of incoming message
* *
* Return: Number of bytes copied in the in_msg on success, negative * Return: Number of bytes copied in the in_msg on success, negative
* error code on failure. * error code on failure.
@ -435,7 +436,7 @@ end:
/** /**
* loader_cl_event_cb() - bus driver callback for incoming message * loader_cl_event_cb() - bus driver callback for incoming message
* @device: Pointer to the ishtp client device for which this * @cl_device: Pointer to the ishtp client device for which this
* message is targeted * message is targeted
* *
* Remove the packet from the list and process the message by calling * Remove the packet from the list and process the message by calling
@ -455,7 +456,7 @@ static void loader_cl_event_cb(struct ishtp_cl_device *cl_device)
/** /**
* ish_query_loader_prop() - Query ISH Shim firmware loader * ish_query_loader_prop() - Query ISH Shim firmware loader
* @client_data: Client data instance * @client_data: Client data instance
* @fw: Poiner to firmware data struct in host memory * @fw: Pointer to firmware data struct in host memory
* @fw_info: Loader firmware properties * @fw_info: Loader firmware properties
* *
* This function queries the ISH Shim firmware loader for capabilities. * This function queries the ISH Shim firmware loader for capabilities.
@ -536,7 +537,7 @@ static int ish_query_loader_prop(struct ishtp_cl_data *client_data,
} }
/** /**
* ish_fw_xfer_ishtp() Loads ISH firmware using ishtp interface * ish_fw_xfer_ishtp() - Loads ISH firmware using ishtp interface
* @client_data: Client data instance * @client_data: Client data instance
* @fw: Pointer to firmware data struct in host memory * @fw: Pointer to firmware data struct in host memory
* *
@ -733,7 +734,7 @@ end_err_dma_buf_release:
} }
/** /**
* ish_fw_start() Start executing ISH main firmware * ish_fw_start() - Start executing ISH main firmware
* @client_data: client data instance * @client_data: client data instance
* *
* This function sends message to Shim firmware loader to start * This function sends message to Shim firmware loader to start
@ -756,7 +757,7 @@ static int ish_fw_start(struct ishtp_cl_data *client_data)
} }
/** /**
* load_fw_from_host() Loads ISH firmware from host * load_fw_from_host() - Loads ISH firmware from host
* @client_data: Client data instance * @client_data: Client data instance
* *
* This function loads the ISH firmware to ISH SRAM and starts execution * This function loads the ISH firmware to ISH SRAM and starts execution
@ -1015,7 +1016,7 @@ static int loader_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
* *
* Return: 0 * Return: 0
*/ */
static int loader_ishtp_cl_remove(struct ishtp_cl_device *cl_device) static void loader_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
{ {
struct ishtp_cl_data *client_data; struct ishtp_cl_data *client_data;
struct ishtp_cl *loader_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl *loader_ishtp_cl = ishtp_get_drvdata(cl_device);
@ -1032,8 +1033,6 @@ static int loader_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
cancel_work_sync(&client_data->work_ishtp_reset); cancel_work_sync(&client_data->work_ishtp_reset);
loader_deinit(loader_ishtp_cl); loader_deinit(loader_ishtp_cl);
ishtp_put_device(cl_device); ishtp_put_device(cl_device);
return 0;
} }
/** /**

View File

@ -11,6 +11,11 @@
#include <linux/sched.h> #include <linux/sched.h>
#include "ishtp-hid.h" #include "ishtp-hid.h"
/* ISH Transport protocol (ISHTP in short) GUID */
static const guid_t hid_ishtp_guid =
GUID_INIT(0x33AECD58, 0xB679, 0x4E54,
0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26);
/* Rx ring buffer pool size */ /* Rx ring buffer pool size */
#define HID_CL_RX_RING_SIZE 32 #define HID_CL_RX_RING_SIZE 32
#define HID_CL_TX_RING_SIZE 16 #define HID_CL_TX_RING_SIZE 16
@ -18,7 +23,7 @@
#define cl_data_to_dev(client_data) ishtp_device(client_data->cl_device) #define cl_data_to_dev(client_data) ishtp_device(client_data->cl_device)
/** /**
* report_bad_packets() - Report bad packets * report_bad_packet() - Report bad packets
* @hid_ishtp_cl: Client instance to get stats * @hid_ishtp_cl: Client instance to get stats
* @recv_buf: Raw received host interface message * @recv_buf: Raw received host interface message
* @cur_pos: Current position index in payload * @cur_pos: Current position index in payload
@ -779,7 +784,7 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
} }
} }
void (*hid_print_trace)(void *unused, const char *format, ...); ishtp_print_log ishtp_hid_print_trace;
/** /**
* hid_ishtp_cl_probe() - ISHTP client driver probe * hid_ishtp_cl_probe() - ISHTP client driver probe
@ -818,7 +823,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler); INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
hid_print_trace = ishtp_trace_callback(cl_device); ishtp_hid_print_trace = ishtp_trace_callback(cl_device);
rv = hid_ishtp_cl_init(hid_ishtp_cl, 0); rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
if (rv) { if (rv) {
@ -838,7 +843,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
* *
* Return: 0 * Return: 0
*/ */
static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device) static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
{ {
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
@ -856,8 +861,6 @@ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
hid_ishtp_cl = NULL; hid_ishtp_cl = NULL;
client_data->num_hid_devices = 0; client_data->num_hid_devices = 0;
return 0;
} }
/** /**

View File

@ -254,7 +254,7 @@ err_hid_data:
} }
/** /**
* ishtp_hid_probe() - Remove registered hid device * ishtp_hid_remove() - Remove registered hid device
* @client_data: client data pointer * @client_data: client data pointer
* *
* This function is used to destroy allocatd HID device. * This function is used to destroy allocatd HID device.

View File

@ -16,14 +16,9 @@
#define IS_RESPONSE 0x80 #define IS_RESPONSE 0x80
/* Used to dump to Linux trace buffer, if enabled */ /* Used to dump to Linux trace buffer, if enabled */
extern void (*hid_print_trace)(void *unused, const char *format, ...); extern ishtp_print_log ishtp_hid_print_trace;
#define hid_ishtp_trace(client, ...) \ #define hid_ishtp_trace(client, ...) \
(hid_print_trace)(NULL, __VA_ARGS__) (ishtp_hid_print_trace)(NULL, __VA_ARGS__)
/* ISH Transport protocol (ISHTP in short) GUID */
static const guid_t hid_ishtp_guid =
GUID_INIT(0x33AECD58, 0xB679, 0x4E54,
0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26);
/* ISH HID message structure */ /* ISH HID message structure */
struct hostif_msg_hdr { struct hostif_msg_hdr {

View File

@ -164,6 +164,7 @@ EXPORT_SYMBOL(ishtp_fw_cl_get_client);
/** /**
* ishtp_get_fw_client_id() - Get fw client id * ishtp_get_fw_client_id() - Get fw client id
* @fw_client: firmware client used to fetch the ID
* *
* This interface is used to reset HW get FW client id. * This interface is used to reset HW get FW client id.
* *
@ -257,26 +258,19 @@ static int ishtp_cl_bus_match(struct device *dev, struct device_driver *drv)
static int ishtp_cl_device_remove(struct device *dev) static int ishtp_cl_device_remove(struct device *dev)
{ {
struct ishtp_cl_device *device = to_ishtp_cl_device(dev); struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
struct ishtp_cl_driver *driver; struct ishtp_cl_driver *driver = to_ishtp_cl_driver(dev->driver);
if (!device || !dev->driver)
return 0;
if (device->event_cb) { if (device->event_cb) {
device->event_cb = NULL; device->event_cb = NULL;
cancel_work_sync(&device->event_work); cancel_work_sync(&device->event_work);
} }
driver = to_ishtp_cl_driver(dev->driver); if (driver->remove)
if (!driver->remove) { driver->remove(device);
dev->driver = NULL;
return 0; return 0;
} }
return driver->remove(device);
}
/** /**
* ishtp_cl_device_suspend() - Bus suspend callback * ishtp_cl_device_suspend() - Bus suspend callback
* @dev: device * @dev: device
@ -842,6 +836,7 @@ int ishtp_use_dma_transfer(void)
/** /**
* ishtp_device() - Return device pointer * ishtp_device() - Return device pointer
* @device: ISH-TP client device instance
* *
* This interface is used to return device pointer from ishtp_cl_device * This interface is used to return device pointer from ishtp_cl_device
* instance. * instance.
@ -858,6 +853,7 @@ EXPORT_SYMBOL(ishtp_device);
* ishtp_get_pci_device() - Return PCI device dev pointer * ishtp_get_pci_device() - Return PCI device dev pointer
* This interface is used to return PCI device pointer * This interface is used to return PCI device pointer
* from ishtp_cl_device instance. * from ishtp_cl_device instance.
* @device: ISH-TP client device instance
* *
* Return: device *. * Return: device *.
*/ */
@ -869,12 +865,13 @@ EXPORT_SYMBOL(ishtp_get_pci_device);
/** /**
* ishtp_trace_callback() - Return trace callback * ishtp_trace_callback() - Return trace callback
* @cl_device: ISH-TP client device instance
* *
* This interface is used to return trace callback function pointer. * This interface is used to return trace callback function pointer.
* *
* Return: void *. * Return: *ishtp_print_log()
*/ */
void *ishtp_trace_callback(struct ishtp_cl_device *cl_device) ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device)
{ {
return cl_device->ishtp_dev->print_log; return cl_device->ishtp_dev->print_log;
} }
@ -882,6 +879,7 @@ EXPORT_SYMBOL(ishtp_trace_callback);
/** /**
* ish_hw_reset() - Call HW reset IPC callback * ish_hw_reset() - Call HW reset IPC callback
* @dev: ISHTP device instance
* *
* This interface is used to reset HW in case of error. * This interface is used to reset HW in case of error.
* *

View File

@ -10,6 +10,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include "hbm.h" #include "hbm.h"
#include "client.h" #include "client.h"
@ -111,7 +112,7 @@ static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev)
/** /**
* ishtp_cl_allocate() - allocates client structure and sets it up. * ishtp_cl_allocate() - allocates client structure and sets it up.
* @dev: ishtp device * @cl_device: ishtp client device
* *
* Allocate memory for new client device and call to initialize each field. * Allocate memory for new client device and call to initialize each field.
* *
@ -263,7 +264,6 @@ EXPORT_SYMBOL(ishtp_cl_unlink);
int ishtp_cl_disconnect(struct ishtp_cl *cl) int ishtp_cl_disconnect(struct ishtp_cl *cl)
{ {
struct ishtp_device *dev; struct ishtp_device *dev;
int err;
if (WARN_ON(!cl || !cl->dev)) if (WARN_ON(!cl || !cl->dev))
return -ENODEV; return -ENODEV;
@ -283,7 +283,7 @@ int ishtp_cl_disconnect(struct ishtp_cl *cl)
return -ENODEV; return -ENODEV;
} }
err = wait_event_interruptible_timeout(cl->wait_ctrl_res, wait_event_interruptible_timeout(cl->wait_ctrl_res,
(dev->dev_state != ISHTP_DEV_ENABLED || (dev->dev_state != ISHTP_DEV_ENABLED ||
cl->state == ISHTP_CL_DISCONNECTED), cl->state == ISHTP_CL_DISCONNECTED),
ishtp_secs_to_jiffies(ISHTP_CL_CONNECT_TIMEOUT)); ishtp_secs_to_jiffies(ISHTP_CL_CONNECT_TIMEOUT));
@ -773,6 +773,14 @@ static void ishtp_cl_send_msg_dma(struct ishtp_device *dev,
/* write msg to dma buf */ /* write msg to dma buf */
memcpy(msg_addr, cl_msg->send_buf.data, cl_msg->send_buf.size); memcpy(msg_addr, cl_msg->send_buf.data, cl_msg->send_buf.size);
/*
* if current fw don't support cache snooping, driver have to
* flush the cache manually.
*/
if (dev->ops->dma_no_cache_snooping &&
dev->ops->dma_no_cache_snooping(dev))
clflush_cache_range(msg_addr, cl_msg->send_buf.size);
/* send dma_xfer hbm msg */ /* send dma_xfer hbm msg */
off = msg_addr - (unsigned char *)dev->ishtp_host_dma_tx_buf; off = msg_addr - (unsigned char *)dev->ishtp_host_dma_tx_buf;
ishtp_hbm_hdr(&hdr, sizeof(struct dma_xfer_hbm)); ishtp_hbm_hdr(&hdr, sizeof(struct dma_xfer_hbm));
@ -997,6 +1005,15 @@ void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
} }
buffer = rb->buffer.data; buffer = rb->buffer.data;
/*
* if current fw don't support cache snooping, driver have to
* flush the cache manually.
*/
if (dev->ops->dma_no_cache_snooping &&
dev->ops->dma_no_cache_snooping(dev))
clflush_cache_range(msg, hbm->msg_length);
memcpy(buffer, msg, hbm->msg_length); memcpy(buffer, msg, hbm->msg_length);
rb->buf_idx = hbm->msg_length; rb->buf_idx = hbm->msg_length;

View File

@ -398,7 +398,7 @@ static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
} }
/** /**
* ishtp_client_disconnect_request() - Receive disconnect request * ishtp_hbm_fw_disconnect_req() - Receive disconnect request
* @dev: ISHTP device instance * @dev: ISHTP device instance
* @disconnect_req: disconnect request structure * @disconnect_req: disconnect request structure
* *
@ -430,7 +430,7 @@ static void ishtp_hbm_fw_disconnect_req(struct ishtp_device *dev,
} }
/** /**
* ishtp_hbm_dma_xfer_ack(() - Receive transfer ACK * ishtp_hbm_dma_xfer_ack() - Receive transfer ACK
* @dev: ISHTP device instance * @dev: ISHTP device instance
* @dma_xfer: HBM transfer message * @dma_xfer: HBM transfer message
* *
@ -914,7 +914,7 @@ static inline void fix_cl_hdr(struct ishtp_msg_hdr *hdr, size_t length,
/*** Suspend and resume notification ***/ /*** Suspend and resume notification ***/
static uint32_t current_state; static uint32_t current_state;
static uint32_t supported_states = 0 | SUSPEND_STATE_BIT; static uint32_t supported_states = SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT;
/** /**
* ishtp_send_suspend() - Send suspend message to FW * ishtp_send_suspend() - Send suspend message to FW
@ -933,7 +933,7 @@ void ishtp_send_suspend(struct ishtp_device *dev)
memset(&state_status_msg, 0, len); memset(&state_status_msg, 0, len);
state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS; state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
state_status_msg.supported_states = supported_states; state_status_msg.supported_states = supported_states;
current_state |= SUSPEND_STATE_BIT; current_state |= (SUSPEND_STATE_BIT | CONNECTED_STANDBY_STATE_BIT);
dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__); dev->print_log(dev, "%s() sends SUSPEND notification\n", __func__);
state_status_msg.states_status = current_state; state_status_msg.states_status = current_state;
@ -959,7 +959,7 @@ void ishtp_send_resume(struct ishtp_device *dev)
memset(&state_status_msg, 0, len); memset(&state_status_msg, 0, len);
state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS; state_status_msg.hdr.cmd = SYSTEM_STATE_STATUS;
state_status_msg.supported_states = supported_states; state_status_msg.supported_states = supported_states;
current_state &= ~SUSPEND_STATE_BIT; current_state &= ~(CONNECTED_STANDBY_STATE_BIT | SUSPEND_STATE_BIT);
dev->print_log(dev, "%s() sends RESUME notification\n", __func__); dev->print_log(dev, "%s() sends RESUME notification\n", __func__);
state_status_msg.states_status = current_state; state_status_msg.states_status = current_state;

View File

@ -235,6 +235,7 @@ struct dma_xfer_hbm {
#define SYSTEM_STATE_QUERY_SUBSCRIBERS 0x3 #define SYSTEM_STATE_QUERY_SUBSCRIBERS 0x3
#define SYSTEM_STATE_STATE_CHANGE_REQ 0x4 #define SYSTEM_STATE_STATE_CHANGE_REQ 0x4
/*indicates suspend and resume states*/ /*indicates suspend and resume states*/
#define CONNECTED_STANDBY_STATE_BIT (1<<0)
#define SUSPEND_STATE_BIT (1<<1) #define SUSPEND_STATE_BIT (1<<1)
struct ish_system_states_header { struct ish_system_states_header {

View File

@ -10,6 +10,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/intel-ish-client-if.h>
#include "bus.h" #include "bus.h"
#include "hbm.h" #include "hbm.h"
@ -118,6 +119,7 @@ struct ishtp_hw_ops {
unsigned long buffer_length); unsigned long buffer_length);
uint32_t (*get_fw_status)(struct ishtp_device *dev); uint32_t (*get_fw_status)(struct ishtp_device *dev);
void (*sync_fw_clock)(struct ishtp_device *dev); void (*sync_fw_clock)(struct ishtp_device *dev);
bool (*dma_no_cache_snooping)(struct ishtp_device *dev);
}; };
/** /**
@ -202,8 +204,7 @@ struct ishtp_device {
uint64_t ishtp_host_dma_rx_buf_phys; uint64_t ishtp_host_dma_rx_buf_phys;
/* Dump to trace buffers if enabled*/ /* Dump to trace buffers if enabled*/
__printf(2, 3) void (*print_log)(struct ishtp_device *dev, ishtp_print_log print_log;
const char *format, ...);
/* Debug stats */ /* Debug stats */
unsigned int ipc_rx_cnt; unsigned int ipc_rx_cnt;

View File

@ -143,7 +143,7 @@ static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id,
rqst.target_id = shid->uid.target; rqst.target_id = shid->uid.target;
rqst.instance_id = shid->uid.instance; rqst.instance_id = shid->uid.instance;
rqst.command_id = SURFACE_HID_CID_GET_FEATURE_REPORT; rqst.command_id = SURFACE_HID_CID_GET_FEATURE_REPORT;
rqst.flags = 0; rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
rqst.length = sizeof(rprt_id); rqst.length = sizeof(rprt_id);
rqst.payload = &rprt_id; rqst.payload = &rprt_id;

View File

@ -1304,6 +1304,13 @@ static int usbhid_idle(struct hid_device *hid, int report, int idle,
return hid_set_idle(dev, ifnum, report, idle); return hid_set_idle(dev, ifnum, report, idle);
} }
static bool usbhid_may_wakeup(struct hid_device *hid)
{
struct usb_device *dev = hid_to_usb_dev(hid);
return device_may_wakeup(&dev->dev);
}
struct hid_ll_driver usb_hid_driver = { struct hid_ll_driver usb_hid_driver = {
.parse = usbhid_parse, .parse = usbhid_parse,
.start = usbhid_start, .start = usbhid_start,
@ -1316,6 +1323,7 @@ struct hid_ll_driver usb_hid_driver = {
.raw_request = usbhid_raw_request, .raw_request = usbhid_raw_request,
.output_report = usbhid_output_report, .output_report = usbhid_output_report,
.idle = usbhid_idle, .idle = usbhid_idle,
.may_wakeup = usbhid_may_wakeup,
}; };
EXPORT_SYMBOL_GPL(usb_hid_driver); EXPORT_SYMBOL_GPL(usb_hid_driver);

View File

@ -239,11 +239,11 @@ static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
return -1; return -1;
if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
return -1; return -1;
if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &kbd->new_dma))) if (!(kbd->new = usb_alloc_coherent(dev, 8, GFP_KERNEL, &kbd->new_dma)))
return -1; return -1;
if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) if (!(kbd->cr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
return -1; return -1;
if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) if (!(kbd->leds = usb_alloc_coherent(dev, 1, GFP_KERNEL, &kbd->leds_dma)))
return -1; return -1;
return 0; return 0;

View File

@ -130,7 +130,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
if (!mouse || !input_dev) if (!mouse || !input_dev)
goto fail1; goto fail1;
mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma); mouse->data = usb_alloc_coherent(dev, 8, GFP_KERNEL, &mouse->data_dma);
if (!mouse->data) if (!mouse->data)
goto fail1; goto fail1;

View File

@ -122,7 +122,7 @@
#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0454) #define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0454)
#define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b) #define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b)
#define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910) #define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910)
#define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0950) #define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0940)
#define WACOM_HID_WD_MODE_CHANGE (WACOM_HID_UP_WACOMDIGITIZER | 0x0980) #define WACOM_HID_WD_MODE_CHANGE (WACOM_HID_UP_WACOMDIGITIZER | 0x0980)
#define WACOM_HID_WD_MUTE_DEVICE (WACOM_HID_UP_WACOMDIGITIZER | 0x0981) #define WACOM_HID_WD_MUTE_DEVICE (WACOM_HID_UP_WACOMDIGITIZER | 0x0981)
#define WACOM_HID_WD_CONTROLPANEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0982) #define WACOM_HID_WD_CONTROLPANEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0982)

View File

@ -703,7 +703,7 @@ end_ishtp_cl_alloc_error:
* *
* Return: 0 * Return: 0
*/ */
static int cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device) static void cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device)
{ {
struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device); struct ishtp_cl *cros_ish_cl = ishtp_get_drvdata(cl_device);
struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl); struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
@ -712,8 +712,6 @@ static int cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device)
cancel_work_sync(&client_data->work_ec_evt); cancel_work_sync(&client_data->work_ec_evt);
cros_ish_deinit(cros_ish_cl); cros_ish_deinit(cros_ish_cl);
ishtp_put_device(cl_device); ishtp_put_device(cl_device);
return 0;
} }
/** /**

View File

@ -102,6 +102,7 @@ struct hid_item {
#define HID_COLLECTION_PHYSICAL 0 #define HID_COLLECTION_PHYSICAL 0
#define HID_COLLECTION_APPLICATION 1 #define HID_COLLECTION_APPLICATION 1
#define HID_COLLECTION_LOGICAL 2 #define HID_COLLECTION_LOGICAL 2
#define HID_COLLECTION_NAMED_ARRAY 4
/* /*
* HID report descriptor global item tags * HID report descriptor global item tags
@ -800,6 +801,7 @@ struct hid_driver {
* @raw_request: send raw report request to device (e.g. feature report) * @raw_request: send raw report request to device (e.g. feature report)
* @output_report: send output report to device * @output_report: send output report to device
* @idle: send idle request to device * @idle: send idle request to device
* @may_wakeup: return if device may act as a wakeup source during system-suspend
*/ */
struct hid_ll_driver { struct hid_ll_driver {
int (*start)(struct hid_device *hdev); int (*start)(struct hid_device *hdev);
@ -824,6 +826,7 @@ struct hid_ll_driver {
int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len); int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len);
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype); int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
bool (*may_wakeup)(struct hid_device *hdev);
}; };
extern struct hid_ll_driver i2c_hid_ll_driver; extern struct hid_ll_driver i2c_hid_ll_driver;
@ -1149,6 +1152,22 @@ static inline int hid_hw_idle(struct hid_device *hdev, int report, int idle,
return 0; return 0;
} }
/**
* hid_may_wakeup - return if the hid device may act as a wakeup source during system-suspend
*
* @hdev: hid device
*/
static inline bool hid_hw_may_wakeup(struct hid_device *hdev)
{
if (hdev->ll_driver->may_wakeup)
return hdev->ll_driver->may_wakeup(hdev);
if (hdev->dev.parent)
return device_may_wakeup(hdev->dev.parent);
return false;
}
/** /**
* hid_hw_wait - wait for buffered io to complete * hid_hw_wait - wait for buffered io to complete
* *

View File

@ -8,11 +8,17 @@
#ifndef _INTEL_ISH_CLIENT_IF_H_ #ifndef _INTEL_ISH_CLIENT_IF_H_
#define _INTEL_ISH_CLIENT_IF_H_ #define _INTEL_ISH_CLIENT_IF_H_
#include <linux/device.h>
#include <linux/uuid.h>
struct ishtp_cl_device; struct ishtp_cl_device;
struct ishtp_device; struct ishtp_device;
struct ishtp_cl; struct ishtp_cl;
struct ishtp_fw_client; struct ishtp_fw_client;
typedef __printf(2, 3) void (*ishtp_print_log)(struct ishtp_device *dev,
const char *format, ...);
/* Client state */ /* Client state */
enum cl_state { enum cl_state {
ISHTP_CL_INITIALIZING = 0, ISHTP_CL_INITIALIZING = 0,
@ -36,7 +42,7 @@ struct ishtp_cl_driver {
const char *name; const char *name;
const guid_t *guid; const guid_t *guid;
int (*probe)(struct ishtp_cl_device *dev); int (*probe)(struct ishtp_cl_device *dev);
int (*remove)(struct ishtp_cl_device *dev); void (*remove)(struct ishtp_cl_device *dev);
int (*reset)(struct ishtp_cl_device *dev); int (*reset)(struct ishtp_cl_device *dev);
const struct dev_pm_ops *pm; const struct dev_pm_ops *pm;
}; };
@ -76,7 +82,7 @@ int ishtp_register_event_cb(struct ishtp_cl_device *device,
/* Get the device * from ishtp device instance */ /* Get the device * from ishtp device instance */
struct device *ishtp_device(struct ishtp_cl_device *cl_device); struct device *ishtp_device(struct ishtp_cl_device *cl_device);
/* Trace interface for clients */ /* Trace interface for clients */
void *ishtp_trace_callback(struct ishtp_cl_device *cl_device); ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device);
/* Get device pointer of PCI device for DMA acces */ /* Get device pointer of PCI device for DMA acces */
struct device *ishtp_get_pci_device(struct ishtp_cl_device *cl_device); struct device *ishtp_get_pci_device(struct ishtp_cl_device *cl_device);