Merge branch 'for-4.20/i2c-hid' into for-linus
- general cleanups of hid-i2c driver - SPIODEV device descriptor fixes
This commit is contained in:
Коммит
4e7be68e8d
|
@ -3,3 +3,6 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_I2C_HID) += i2c-hid.o
|
||||
|
||||
i2c-hid-objs = i2c-hid-core.o
|
||||
i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <linux/platform_data/i2c-hid.h>
|
||||
|
||||
#include "../hid-ids.h"
|
||||
#include "i2c-hid.h"
|
||||
|
||||
/* quirks to control the device */
|
||||
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
|
||||
|
@ -668,6 +669,7 @@ static int i2c_hid_parse(struct hid_device *hid)
|
|||
char *rdesc;
|
||||
int ret;
|
||||
int tries = 3;
|
||||
char *use_override;
|
||||
|
||||
i2c_hid_dbg(ihid, "entering %s\n", __func__);
|
||||
|
||||
|
@ -686,26 +688,37 @@ static int i2c_hid_parse(struct hid_device *hid)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
rdesc = kzalloc(rsize, GFP_KERNEL);
|
||||
use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
|
||||
&rsize);
|
||||
|
||||
if (!rdesc) {
|
||||
dbg_hid("couldn't allocate rdesc memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (use_override) {
|
||||
rdesc = use_override;
|
||||
i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
|
||||
} else {
|
||||
rdesc = kzalloc(rsize, GFP_KERNEL);
|
||||
|
||||
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
|
||||
if (!rdesc) {
|
||||
dbg_hid("couldn't allocate rdesc memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
|
||||
if (ret) {
|
||||
hid_err(hid, "reading report descriptor failed\n");
|
||||
kfree(rdesc);
|
||||
return -EIO;
|
||||
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
|
||||
|
||||
ret = i2c_hid_command(client, &hid_report_descr_cmd,
|
||||
rdesc, rsize);
|
||||
if (ret) {
|
||||
hid_err(hid, "reading report descriptor failed\n");
|
||||
kfree(rdesc);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
|
||||
|
||||
ret = hid_parse_report(hid, rdesc, rsize);
|
||||
kfree(rdesc);
|
||||
if (!use_override)
|
||||
kfree(rdesc);
|
||||
|
||||
if (ret) {
|
||||
dbg_hid("parsing report descriptor failed\n");
|
||||
return ret;
|
||||
|
@ -832,12 +845,19 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
|
|||
int ret;
|
||||
|
||||
/* i2c hid fetch using a fixed descriptor size (30 bytes) */
|
||||
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
|
||||
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
|
||||
sizeof(struct i2c_hid_desc));
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "hid_descr_cmd failed\n");
|
||||
return -ENODEV;
|
||||
if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
|
||||
i2c_hid_dbg(ihid, "Using a HID descriptor override\n");
|
||||
ihid->hdesc =
|
||||
*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
|
||||
} else {
|
||||
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
|
||||
ret = i2c_hid_command(client, &hid_descr_cmd,
|
||||
ihid->hdesc_buffer,
|
||||
sizeof(struct i2c_hid_desc));
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "hid_descr_cmd failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Validate the length of HID descriptor, the 4 first bytes:
|
|
@ -0,0 +1,376 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/*
|
||||
* Quirks for I2C-HID devices that do not supply proper descriptors
|
||||
*
|
||||
* Copyright (c) 2018 Julian Sax <jsbc@gmx.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include "i2c-hid.h"
|
||||
|
||||
|
||||
struct i2c_hid_desc_override {
|
||||
union {
|
||||
struct i2c_hid_desc *i2c_hid_desc;
|
||||
uint8_t *i2c_hid_desc_buffer;
|
||||
};
|
||||
uint8_t *hid_report_desc;
|
||||
unsigned int hid_report_desc_size;
|
||||
uint8_t *i2c_name;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* descriptors for the SIPODEV SP1064 touchpad
|
||||
*
|
||||
* This device does not supply any descriptors and on windows a filter
|
||||
* driver operates between the i2c-hid layer and the device and injects
|
||||
* these descriptors when the device is prompted. The descriptors were
|
||||
* extracted by listening to the i2c-hid traffic that occurs between the
|
||||
* windows filter driver and the windows i2c-hid driver.
|
||||
*/
|
||||
|
||||
static const struct i2c_hid_desc_override sipodev_desc = {
|
||||
.i2c_hid_desc_buffer = (uint8_t [])
|
||||
{0x1e, 0x00, /* Length of descriptor */
|
||||
0x00, 0x01, /* Version of descriptor */
|
||||
0xdb, 0x01, /* Length of report descriptor */
|
||||
0x21, 0x00, /* Location of report descriptor */
|
||||
0x24, 0x00, /* Location of input report */
|
||||
0x1b, 0x00, /* Max input report length */
|
||||
0x25, 0x00, /* Location of output report */
|
||||
0x11, 0x00, /* Max output report length */
|
||||
0x22, 0x00, /* Location of command register */
|
||||
0x23, 0x00, /* Location of data register */
|
||||
0x11, 0x09, /* Vendor ID */
|
||||
0x88, 0x52, /* Product ID */
|
||||
0x06, 0x00, /* Version ID */
|
||||
0x00, 0x00, 0x00, 0x00 /* Reserved */
|
||||
},
|
||||
|
||||
.hid_report_desc = (uint8_t [])
|
||||
{0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x09, 0x02, /* Usage (Mouse), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x01, /* Report ID (1), */
|
||||
0x09, 0x01, /* Usage (Pointer), */
|
||||
0xA1, 0x00, /* Collection (Physical), */
|
||||
0x05, 0x09, /* Usage Page (Button), */
|
||||
0x19, 0x01, /* Usage Minimum (01h), */
|
||||
0x29, 0x02, /* Usage Maximum (02h), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x06, /* Report Count (6), */
|
||||
0x81, 0x01, /* Input (Constant), */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x15, 0x81, /* Logical Minimum (-127), */
|
||||
0x25, 0x7F, /* Logical Maximum (127), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x81, 0x06, /* Input (Variable, Relative), */
|
||||
0xC0, /* End Collection, */
|
||||
0xC0, /* End Collection, */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x09, 0x05, /* Usage (Touchpad), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x04, /* Report ID (4), */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x09, 0x22, /* Usage (Finger), */
|
||||
0xA1, 0x02, /* Collection (Logical), */
|
||||
0x15, 0x00, /* Logical Minimum (0), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x09, 0x47, /* Usage (Touch Valid), */
|
||||
0x09, 0x42, /* Usage (Tip Switch), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x75, 0x03, /* Report Size (3), */
|
||||
0x25, 0x05, /* Logical Maximum (5), */
|
||||
0x09, 0x51, /* Usage (Contact Identifier), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0x55, 0x0E, /* Unit Exponent (14), */
|
||||
0x65, 0x11, /* Unit (Centimeter), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x46, 0xBC, 0x02, /* Physical Maximum (700), */
|
||||
0x26, 0x34, 0x05, /* Logical Maximum (1332), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x09, 0x22, /* Usage (Finger), */
|
||||
0xA1, 0x02, /* Collection (Logical), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x09, 0x47, /* Usage (Touch Valid), */
|
||||
0x09, 0x42, /* Usage (Tip Switch), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x75, 0x03, /* Report Size (3), */
|
||||
0x25, 0x05, /* Logical Maximum (5), */
|
||||
0x09, 0x51, /* Usage (Contact Identifier), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x46, 0xBC, 0x02, /* Physical Maximum (700), */
|
||||
0x26, 0x34, 0x05, /* Logical Maximum (1332), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x09, 0x22, /* Usage (Finger), */
|
||||
0xA1, 0x02, /* Collection (Logical), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x09, 0x47, /* Usage (Touch Valid), */
|
||||
0x09, 0x42, /* Usage (Tip Switch), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x75, 0x03, /* Report Size (3), */
|
||||
0x25, 0x05, /* Logical Maximum (5), */
|
||||
0x09, 0x51, /* Usage (Contact Identifier), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x46, 0xBC, 0x02, /* Physical Maximum (700), */
|
||||
0x26, 0x34, 0x05, /* Logical Maximum (1332), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x09, 0x22, /* Usage (Finger), */
|
||||
0xA1, 0x02, /* Collection (Logical), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x09, 0x47, /* Usage (Touch Valid), */
|
||||
0x09, 0x42, /* Usage (Tip Switch), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x75, 0x03, /* Report Size (3), */
|
||||
0x25, 0x05, /* Logical Maximum (5), */
|
||||
0x09, 0x51, /* Usage (Contact Identifier), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
0x26, 0x44, 0x0A, /* Logical Maximum (2628), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0x09, 0x30, /* Usage (X), */
|
||||
0x46, 0x1A, 0x04, /* Physical Maximum (1050), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x46, 0xBC, 0x02, /* Physical Maximum (700), */
|
||||
0x26, 0x34, 0x05, /* Logical Maximum (1332), */
|
||||
0x09, 0x31, /* Usage (Y), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x55, 0x0C, /* Unit Exponent (12), */
|
||||
0x66, 0x01, 0x10, /* Unit (Seconds), */
|
||||
0x47, 0xFF, 0xFF, 0x00, 0x00,/* Physical Maximum (65535), */
|
||||
0x27, 0xFF, 0xFF, 0x00, 0x00,/* Logical Maximum (65535), */
|
||||
0x75, 0x10, /* Report Size (16), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x09, 0x56, /* Usage (Scan Time), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0x54, /* Usage (Contact Count), */
|
||||
0x25, 0x7F, /* Logical Maximum (127), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x05, 0x09, /* Usage Page (Button), */
|
||||
0x09, 0x01, /* Usage (01h), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x95, 0x07, /* Report Count (7), */
|
||||
0x81, 0x03, /* Input (Constant, Variable), */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x85, 0x02, /* Report ID (2), */
|
||||
0x09, 0x55, /* Usage (Contact Count Maximum), */
|
||||
0x09, 0x59, /* Usage (59h), */
|
||||
0x75, 0x04, /* Report Size (4), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x25, 0x0F, /* Logical Maximum (15), */
|
||||
0xB1, 0x02, /* Feature (Variable), */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x85, 0x07, /* Report ID (7), */
|
||||
0x09, 0x60, /* Usage (60h), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0xB1, 0x02, /* Feature (Variable), */
|
||||
0x95, 0x07, /* Report Count (7), */
|
||||
0xB1, 0x03, /* Feature (Constant, Variable), */
|
||||
0x85, 0x06, /* Report ID (6), */
|
||||
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
|
||||
0x09, 0xC5, /* Usage (C5h), */
|
||||
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x96, 0x00, 0x01, /* Report Count (256), */
|
||||
0xB1, 0x02, /* Feature (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
|
||||
0x09, 0x01, /* Usage (01h), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x0D, /* Report ID (13), */
|
||||
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
|
||||
0x19, 0x01, /* Usage Minimum (01h), */
|
||||
0x29, 0x02, /* Usage Maximum (02h), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0xB1, 0x02, /* Feature (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0x05, 0x0D, /* Usage Page (Digitizer), */
|
||||
0x09, 0x0E, /* Usage (Configuration), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x85, 0x03, /* Report ID (3), */
|
||||
0x09, 0x22, /* Usage (Finger), */
|
||||
0xA1, 0x02, /* Collection (Logical), */
|
||||
0x09, 0x52, /* Usage (Device Mode), */
|
||||
0x25, 0x0A, /* Logical Maximum (10), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0xB1, 0x02, /* Feature (Variable), */
|
||||
0xC0, /* End Collection, */
|
||||
0x09, 0x22, /* Usage (Finger), */
|
||||
0xA1, 0x00, /* Collection (Physical), */
|
||||
0x85, 0x05, /* Report ID (5), */
|
||||
0x09, 0x57, /* Usage (57h), */
|
||||
0x09, 0x58, /* Usage (58h), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0xB1, 0x02, /* Feature (Variable), */
|
||||
0x95, 0x06, /* Report Count (6), */
|
||||
0xB1, 0x03, /* Feature (Constant, Variable),*/
|
||||
0xC0, /* End Collection, */
|
||||
0xC0 /* End Collection */
|
||||
},
|
||||
.hid_report_desc_size = 475,
|
||||
.i2c_name = "SYNA3602:00"
|
||||
};
|
||||
|
||||
|
||||
static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
|
||||
{
|
||||
.ident = "Teclast F6 Pro",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F6 Pro"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{
|
||||
.ident = "Teclast F7",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TECLAST"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "F7"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{
|
||||
.ident = "Trekstor Primebook C13",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C13"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{
|
||||
.ident = "Trekstor Primebook C11",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Primebook C11"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{
|
||||
.ident = "Direkt-Tek DTLAPY116-2",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "DTLAPY116-2"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{
|
||||
.ident = "Mediacom Flexbook Edge 11",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "MEDIACOM"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "FlexBook edge11 - M-FBE11"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
|
||||
{
|
||||
struct i2c_hid_desc_override *override;
|
||||
const struct dmi_system_id *system_id;
|
||||
|
||||
system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
|
||||
if (!system_id)
|
||||
return NULL;
|
||||
|
||||
override = system_id->driver_data;
|
||||
if (strcmp(override->i2c_name, i2c_name))
|
||||
return NULL;
|
||||
|
||||
return override->i2c_hid_desc;
|
||||
}
|
||||
|
||||
char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
|
||||
unsigned int *size)
|
||||
{
|
||||
struct i2c_hid_desc_override *override;
|
||||
const struct dmi_system_id *system_id;
|
||||
|
||||
system_id = dmi_first_match(i2c_hid_dmi_desc_override_table);
|
||||
if (!system_id)
|
||||
return NULL;
|
||||
|
||||
override = system_id->driver_data;
|
||||
if (strcmp(override->i2c_name, i2c_name))
|
||||
return NULL;
|
||||
|
||||
*size = override->hid_report_desc_size;
|
||||
return override->hid_report_desc;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef I2C_HID_H
|
||||
#define I2C_HID_H
|
||||
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
|
||||
char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
|
||||
unsigned int *size);
|
||||
#else
|
||||
static inline struct i2c_hid_desc
|
||||
*i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
|
||||
{ return NULL; }
|
||||
static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
|
||||
unsigned int *size)
|
||||
{ return NULL; }
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -280,14 +280,14 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
|
|||
* if tx send list is empty - return 0;
|
||||
* may happen, as RX_COMPLETE handler doesn't check list emptiness.
|
||||
*/
|
||||
if (list_empty(&dev->wr_processing_list_head.link)) {
|
||||
if (list_empty(&dev->wr_processing_list)) {
|
||||
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
|
||||
out_ipc_locked = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ipc_link = list_entry(dev->wr_processing_list_head.link.next,
|
||||
struct wr_msg_ctl_info, link);
|
||||
ipc_link = list_first_entry(&dev->wr_processing_list,
|
||||
struct wr_msg_ctl_info, link);
|
||||
/* first 4 bytes of the data is the doorbell value (IPC header) */
|
||||
length = ipc_link->length - sizeof(uint32_t);
|
||||
doorbell_val = *(uint32_t *)ipc_link->inline_data;
|
||||
|
@ -338,7 +338,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
|
|||
ipc_send_compl = ipc_link->ipc_send_compl;
|
||||
ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
|
||||
list_del_init(&ipc_link->link);
|
||||
list_add_tail(&ipc_link->link, &dev->wr_free_list_head.link);
|
||||
list_add(&ipc_link->link, &dev->wr_free_list);
|
||||
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
|
||||
|
||||
/*
|
||||
|
@ -372,18 +372,18 @@ static int write_ipc_to_queue(struct ishtp_device *dev,
|
|||
unsigned char *msg, int length)
|
||||
{
|
||||
struct wr_msg_ctl_info *ipc_link;
|
||||
unsigned long flags;
|
||||
unsigned long flags;
|
||||
|
||||
if (length > IPC_FULL_MSG_SIZE)
|
||||
return -EMSGSIZE;
|
||||
|
||||
spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
|
||||
if (list_empty(&dev->wr_free_list_head.link)) {
|
||||
if (list_empty(&dev->wr_free_list)) {
|
||||
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ipc_link = list_entry(dev->wr_free_list_head.link.next,
|
||||
struct wr_msg_ctl_info, link);
|
||||
ipc_link = list_first_entry(&dev->wr_free_list,
|
||||
struct wr_msg_ctl_info, link);
|
||||
list_del_init(&ipc_link->link);
|
||||
|
||||
ipc_link->ipc_send_compl = ipc_send_compl;
|
||||
|
@ -391,7 +391,7 @@ static int write_ipc_to_queue(struct ishtp_device *dev,
|
|||
ipc_link->length = length;
|
||||
memcpy(ipc_link->inline_data, msg, length);
|
||||
|
||||
list_add_tail(&ipc_link->link, &dev->wr_processing_list_head.link);
|
||||
list_add_tail(&ipc_link->link, &dev->wr_processing_list);
|
||||
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
|
||||
|
||||
write_ipc_from_queue(dev);
|
||||
|
@ -487,17 +487,13 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
|
|||
{
|
||||
uint32_t reset_id;
|
||||
unsigned long flags;
|
||||
struct wr_msg_ctl_info *processing, *next;
|
||||
|
||||
/* Read reset ID */
|
||||
reset_id = ish_reg_read(dev, IPC_REG_ISH2HOST_MSG) & 0xFFFF;
|
||||
|
||||
/* Clear IPC output queue */
|
||||
spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
|
||||
list_for_each_entry_safe(processing, next,
|
||||
&dev->wr_processing_list_head.link, link) {
|
||||
list_move_tail(&processing->link, &dev->wr_free_list_head.link);
|
||||
}
|
||||
list_splice_init(&dev->wr_processing_list, &dev->wr_free_list);
|
||||
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
|
||||
|
||||
/* ISHTP notification in IPC_RESET */
|
||||
|
@ -921,9 +917,9 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
|
|||
spin_lock_init(&dev->out_ipc_spinlock);
|
||||
|
||||
/* Init IPC processing and free lists */
|
||||
INIT_LIST_HEAD(&dev->wr_processing_list_head.link);
|
||||
INIT_LIST_HEAD(&dev->wr_free_list_head.link);
|
||||
for (i = 0; i < IPC_TX_FIFO_SIZE; ++i) {
|
||||
INIT_LIST_HEAD(&dev->wr_processing_list);
|
||||
INIT_LIST_HEAD(&dev->wr_free_list);
|
||||
for (i = 0; i < IPC_TX_FIFO_SIZE; i++) {
|
||||
struct wr_msg_ctl_info *tx_buf;
|
||||
|
||||
tx_buf = devm_kzalloc(&pdev->dev,
|
||||
|
@ -939,7 +935,7 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
|
|||
i);
|
||||
break;
|
||||
}
|
||||
list_add_tail(&tx_buf->link, &dev->wr_free_list_head.link);
|
||||
list_add_tail(&tx_buf->link, &dev->wr_free_list);
|
||||
}
|
||||
|
||||
dev->ops = &ish_hw_ops;
|
||||
|
|
|
@ -115,18 +115,19 @@ static const struct pci_device_id ish_invalid_pci_ids[] = {
|
|||
*/
|
||||
static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
struct ishtp_device *dev;
|
||||
int ret;
|
||||
struct ish_hw *hw;
|
||||
int ret;
|
||||
struct ishtp_device *ishtp;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
/* Check for invalid platforms for ISH support */
|
||||
if (pci_dev_present(ish_invalid_pci_ids))
|
||||
return -ENODEV;
|
||||
|
||||
/* enable pci dev */
|
||||
ret = pci_enable_device(pdev);
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "ISH: Failed to enable PCI device\n");
|
||||
dev_err(dev, "ISH: Failed to enable PCI device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -134,65 +135,44 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
pci_set_master(pdev);
|
||||
|
||||
/* pci request regions for ISH driver */
|
||||
ret = pci_request_regions(pdev, KBUILD_MODNAME);
|
||||
ret = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "ISH: Failed to get PCI regions\n");
|
||||
goto disable_device;
|
||||
dev_err(dev, "ISH: Failed to get PCI regions\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* allocates and initializes the ISH dev structure */
|
||||
dev = ish_dev_init(pdev);
|
||||
if (!dev) {
|
||||
ishtp = ish_dev_init(pdev);
|
||||
if (!ishtp) {
|
||||
ret = -ENOMEM;
|
||||
goto release_regions;
|
||||
return ret;
|
||||
}
|
||||
hw = to_ish_hw(dev);
|
||||
dev->print_log = ish_event_tracer;
|
||||
hw = to_ish_hw(ishtp);
|
||||
ishtp->print_log = ish_event_tracer;
|
||||
|
||||
/* mapping IO device memory */
|
||||
hw->mem_addr = pci_iomap(pdev, 0, 0);
|
||||
if (!hw->mem_addr) {
|
||||
dev_err(&pdev->dev, "ISH: mapping I/O range failure\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_device;
|
||||
}
|
||||
|
||||
dev->pdev = pdev;
|
||||
|
||||
hw->mem_addr = pcim_iomap_table(pdev)[0];
|
||||
ishtp->pdev = pdev;
|
||||
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
|
||||
|
||||
/* request and enable interrupt */
|
||||
ret = request_irq(pdev->irq, ish_irq_handler, IRQF_SHARED,
|
||||
KBUILD_MODNAME, dev);
|
||||
ret = devm_request_irq(dev, pdev->irq, ish_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, ishtp);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "ISH: request IRQ failure (%d)\n",
|
||||
pdev->irq);
|
||||
goto free_device;
|
||||
dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev->devc, dev);
|
||||
dev_set_drvdata(ishtp->devc, ishtp);
|
||||
|
||||
init_waitqueue_head(&dev->suspend_wait);
|
||||
init_waitqueue_head(&dev->resume_wait);
|
||||
init_waitqueue_head(&ishtp->suspend_wait);
|
||||
init_waitqueue_head(&ishtp->resume_wait);
|
||||
|
||||
ret = ish_init(dev);
|
||||
ret = ish_init(ishtp);
|
||||
if (ret)
|
||||
goto free_irq;
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
free_irq:
|
||||
free_irq(pdev->irq, dev);
|
||||
free_device:
|
||||
pci_iounmap(pdev, hw->mem_addr);
|
||||
release_regions:
|
||||
pci_release_regions(pdev);
|
||||
disable_device:
|
||||
pci_clear_master(pdev);
|
||||
pci_disable_device(pdev);
|
||||
dev_err(&pdev->dev, "ISH: PCI driver initialization failed.\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,16 +184,9 @@ disable_device:
|
|||
static void ish_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
|
||||
struct ish_hw *hw = to_ish_hw(ishtp_dev);
|
||||
|
||||
ishtp_bus_remove_all_clients(ishtp_dev, false);
|
||||
ish_device_disable(ishtp_dev);
|
||||
|
||||
free_irq(pdev->irq, ishtp_dev);
|
||||
pci_iounmap(pdev, hw->mem_addr);
|
||||
pci_release_regions(pdev);
|
||||
pci_clear_master(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
static struct device __maybe_unused *ish_resume_device;
|
||||
|
|
|
@ -320,23 +320,14 @@ do_get_report:
|
|||
*/
|
||||
static void ish_cl_event_cb(struct ishtp_cl_device *device)
|
||||
{
|
||||
struct ishtp_cl *hid_ishtp_cl = device->driver_data;
|
||||
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device);
|
||||
struct ishtp_cl_rb *rb_in_proc;
|
||||
size_t r_length;
|
||||
unsigned long flags;
|
||||
|
||||
if (!hid_ishtp_cl)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
|
||||
while (!list_empty(&hid_ishtp_cl->in_process_list.list)) {
|
||||
rb_in_proc = list_entry(
|
||||
hid_ishtp_cl->in_process_list.list.next,
|
||||
struct ishtp_cl_rb, list);
|
||||
list_del_init(&rb_in_proc->list);
|
||||
spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock,
|
||||
flags);
|
||||
|
||||
while ((rb_in_proc = ishtp_cl_rx_get_rb(hid_ishtp_cl)) != NULL) {
|
||||
if (!rb_in_proc->buffer.data)
|
||||
return;
|
||||
|
||||
|
@ -346,9 +337,7 @@ static void ish_cl_event_cb(struct ishtp_cl_device *device)
|
|||
process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
|
||||
|
||||
ishtp_cl_io_rb_recycle(rb_in_proc);
|
||||
spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -637,8 +626,8 @@ static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
|
|||
static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
|
||||
{
|
||||
struct ishtp_device *dev;
|
||||
unsigned long flags;
|
||||
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
|
||||
struct ishtp_fw_client *fw_client;
|
||||
int i;
|
||||
int rv;
|
||||
|
||||
|
@ -660,16 +649,14 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
|
|||
hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE;
|
||||
hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE;
|
||||
|
||||
spin_lock_irqsave(&dev->fw_clients_lock, flags);
|
||||
i = ishtp_fw_cl_by_uuid(dev, &hid_ishtp_guid);
|
||||
if (i < 0) {
|
||||
spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
|
||||
fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_guid);
|
||||
if (!fw_client) {
|
||||
dev_err(&client_data->cl_device->dev,
|
||||
"ish client uuid not found\n");
|
||||
return i;
|
||||
return -ENOENT;
|
||||
}
|
||||
hid_ishtp_cl->fw_client_id = dev->fw_clients[i].client_id;
|
||||
spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
|
||||
|
||||
hid_ishtp_cl->fw_client_id = fw_client->client_id;
|
||||
hid_ishtp_cl->state = ISHTP_CL_CONNECTING;
|
||||
|
||||
rv = ishtp_cl_connect(hid_ishtp_cl);
|
||||
|
@ -765,7 +752,7 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
|
|||
if (!hid_ishtp_cl)
|
||||
return;
|
||||
|
||||
cl_device->driver_data = hid_ishtp_cl;
|
||||
ishtp_set_drvdata(cl_device, hid_ishtp_cl);
|
||||
hid_ishtp_cl->client_data = client_data;
|
||||
client_data->hid_ishtp_cl = hid_ishtp_cl;
|
||||
|
||||
|
@ -814,7 +801,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
|
|||
if (!hid_ishtp_cl)
|
||||
return -ENOMEM;
|
||||
|
||||
cl_device->driver_data = hid_ishtp_cl;
|
||||
ishtp_set_drvdata(cl_device, hid_ishtp_cl);
|
||||
hid_ishtp_cl->client_data = client_data;
|
||||
client_data->hid_ishtp_cl = hid_ishtp_cl;
|
||||
client_data->cl_device = cl_device;
|
||||
|
@ -844,7 +831,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
|
|||
*/
|
||||
static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
|
||||
{
|
||||
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
|
||||
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
|
||||
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
|
||||
|
||||
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
|
||||
|
@ -874,7 +861,7 @@ static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
|
|||
*/
|
||||
static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
|
||||
{
|
||||
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
|
||||
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
|
||||
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
|
||||
|
||||
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
|
||||
|
@ -898,7 +885,7 @@ static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
|
|||
static int hid_ishtp_cl_suspend(struct device *device)
|
||||
{
|
||||
struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
|
||||
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
|
||||
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
|
||||
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
|
||||
|
||||
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
|
||||
|
@ -919,7 +906,7 @@ static int hid_ishtp_cl_suspend(struct device *device)
|
|||
static int hid_ishtp_cl_resume(struct device *device)
|
||||
{
|
||||
struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device);
|
||||
struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data;
|
||||
struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
|
||||
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
|
||||
|
||||
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
|
||||
|
|
|
@ -148,6 +148,31 @@ int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid)
|
|||
}
|
||||
EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
|
||||
|
||||
/**
|
||||
* ishtp_fw_cl_get_client() - return client information to client
|
||||
* @dev: the ishtp device structure
|
||||
* @uuid: uuid of the client to search
|
||||
*
|
||||
* Search firmware client using UUID and reture related client information.
|
||||
*
|
||||
* Return: pointer of client information on success, NULL on failure.
|
||||
*/
|
||||
struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
|
||||
const uuid_le *uuid)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->fw_clients_lock, flags);
|
||||
i = ishtp_fw_cl_by_uuid(dev, uuid);
|
||||
spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
|
||||
if (i < 0 || dev->fw_clients[i].props.fixed_address)
|
||||
return NULL;
|
||||
|
||||
return &dev->fw_clients[i];
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_fw_cl_get_client);
|
||||
|
||||
/**
|
||||
* ishtp_fw_cl_by_id() - return index to fw_clients for client_id
|
||||
* @dev: the ishtp device structure
|
||||
|
@ -563,6 +588,33 @@ void ishtp_put_device(struct ishtp_cl_device *cl_device)
|
|||
}
|
||||
EXPORT_SYMBOL(ishtp_put_device);
|
||||
|
||||
/**
|
||||
* ishtp_set_drvdata() - set client driver data
|
||||
* @cl_device: client device instance
|
||||
* @data: driver data need to be set
|
||||
*
|
||||
* Set client driver data to cl_device->driver_data.
|
||||
*/
|
||||
void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data)
|
||||
{
|
||||
cl_device->driver_data = data;
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_set_drvdata);
|
||||
|
||||
/**
|
||||
* ishtp_get_drvdata() - get client driver data
|
||||
* @cl_device: client device instance
|
||||
*
|
||||
* Get client driver data from cl_device->driver_data.
|
||||
*
|
||||
* Return: pointer of driver data
|
||||
*/
|
||||
void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
|
||||
{
|
||||
return cl_device->driver_data;
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_get_drvdata);
|
||||
|
||||
/**
|
||||
* ishtp_bus_new_client() - Create a new client
|
||||
* @dev: ISHTP device instance
|
||||
|
|
|
@ -101,6 +101,9 @@ void ishtp_reset_compl_handler(struct ishtp_device *dev);
|
|||
void ishtp_put_device(struct ishtp_cl_device *);
|
||||
void ishtp_get_device(struct ishtp_cl_device *);
|
||||
|
||||
void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data);
|
||||
void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device);
|
||||
|
||||
int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
|
||||
struct module *owner);
|
||||
#define ishtp_cl_driver_register(driver) \
|
||||
|
@ -110,5 +113,7 @@ void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver);
|
|||
int ishtp_register_event_cb(struct ishtp_cl_device *device,
|
||||
void (*read_cb)(struct ishtp_cl_device *));
|
||||
int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid);
|
||||
struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
|
||||
const uuid_le *uuid);
|
||||
|
||||
#endif /* _LINUX_ISHTP_CL_BUS_H */
|
||||
|
|
|
@ -69,6 +69,8 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
|
|||
int j;
|
||||
unsigned long flags;
|
||||
|
||||
cl->tx_ring_free_size = 0;
|
||||
|
||||
/* Allocate pool to free Tx bufs */
|
||||
for (j = 0; j < cl->tx_ring_size; ++j) {
|
||||
struct ishtp_cl_tx_ring *tx_buf;
|
||||
|
@ -85,6 +87,7 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl)
|
|||
|
||||
spin_lock_irqsave(&cl->tx_free_list_spinlock, flags);
|
||||
list_add_tail(&tx_buf->list, &cl->tx_free_list.list);
|
||||
++cl->tx_ring_free_size;
|
||||
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, flags);
|
||||
}
|
||||
return 0;
|
||||
|
@ -144,6 +147,7 @@ void ishtp_cl_free_tx_ring(struct ishtp_cl *cl)
|
|||
tx_buf = list_entry(cl->tx_free_list.list.next,
|
||||
struct ishtp_cl_tx_ring, list);
|
||||
list_del(&tx_buf->list);
|
||||
--cl->tx_ring_free_size;
|
||||
kfree(tx_buf->send_buf.data);
|
||||
kfree(tx_buf);
|
||||
}
|
||||
|
@ -255,3 +259,48 @@ int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb)
|
|||
return rets;
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_cl_io_rb_recycle);
|
||||
|
||||
/**
|
||||
* ishtp_cl_tx_empty() -test whether client device tx buffer is empty
|
||||
* @cl: Pointer to client device instance
|
||||
*
|
||||
* Look client device tx buffer list, and check whether this list is empty
|
||||
*
|
||||
* Return: true if client tx buffer list is empty else false
|
||||
*/
|
||||
bool ishtp_cl_tx_empty(struct ishtp_cl *cl)
|
||||
{
|
||||
int tx_list_empty;
|
||||
unsigned long tx_flags;
|
||||
|
||||
spin_lock_irqsave(&cl->tx_list_spinlock, tx_flags);
|
||||
tx_list_empty = list_empty(&cl->tx_list.list);
|
||||
spin_unlock_irqrestore(&cl->tx_list_spinlock, tx_flags);
|
||||
|
||||
return !!tx_list_empty;
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_cl_tx_empty);
|
||||
|
||||
/**
|
||||
* ishtp_cl_rx_get_rb() -Get a rb from client device rx buffer list
|
||||
* @cl: Pointer to client device instance
|
||||
*
|
||||
* Check client device in-processing buffer list and get a rb from it.
|
||||
*
|
||||
* Return: rb pointer if buffer list isn't empty else NULL
|
||||
*/
|
||||
struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl)
|
||||
{
|
||||
unsigned long rx_flags;
|
||||
struct ishtp_cl_rb *rb;
|
||||
|
||||
spin_lock_irqsave(&cl->in_process_spinlock, rx_flags);
|
||||
rb = list_first_entry_or_null(&cl->in_process_list.list,
|
||||
struct ishtp_cl_rb, list);
|
||||
if (rb)
|
||||
list_del_init(&rb->list);
|
||||
spin_unlock_irqrestore(&cl->in_process_spinlock, rx_flags);
|
||||
|
||||
return rb;
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_cl_rx_get_rb);
|
||||
|
|
|
@ -22,6 +22,25 @@
|
|||
#include "hbm.h"
|
||||
#include "client.h"
|
||||
|
||||
int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl)
|
||||
{
|
||||
unsigned long tx_free_flags;
|
||||
int size;
|
||||
|
||||
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
|
||||
size = cl->tx_ring_free_size * cl->device->fw_client->props.max_msg_length;
|
||||
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
|
||||
|
||||
return size;
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_cl_get_tx_free_buffer_size);
|
||||
|
||||
int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl)
|
||||
{
|
||||
return cl->tx_ring_free_size;
|
||||
}
|
||||
EXPORT_SYMBOL(ishtp_cl_get_tx_free_rings);
|
||||
|
||||
/**
|
||||
* ishtp_read_list_flush() - Flush read queue
|
||||
* @cl: ishtp client instance
|
||||
|
@ -90,6 +109,7 @@ static void ishtp_cl_init(struct ishtp_cl *cl, struct ishtp_device *dev)
|
|||
|
||||
cl->rx_ring_size = CL_DEF_RX_RING_SIZE;
|
||||
cl->tx_ring_size = CL_DEF_TX_RING_SIZE;
|
||||
cl->tx_ring_free_size = cl->tx_ring_size;
|
||||
|
||||
/* dma */
|
||||
cl->last_tx_path = CL_TX_PATH_IPC;
|
||||
|
@ -577,6 +597,8 @@ int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length)
|
|||
* max ISHTP message size per client
|
||||
*/
|
||||
list_del_init(&cl_msg->list);
|
||||
--cl->tx_ring_free_size;
|
||||
|
||||
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
|
||||
memcpy(cl_msg->send_buf.data, buf, length);
|
||||
cl_msg->send_buf.size = length;
|
||||
|
@ -685,6 +707,7 @@ static void ipc_tx_callback(void *prm)
|
|||
ishtp_write_message(dev, &ishtp_hdr, pmsg);
|
||||
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
|
||||
list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
|
||||
++cl->tx_ring_free_size;
|
||||
spin_unlock_irqrestore(&cl->tx_free_list_spinlock,
|
||||
tx_free_flags);
|
||||
} else {
|
||||
|
@ -778,6 +801,7 @@ static void ishtp_cl_send_msg_dma(struct ishtp_device *dev,
|
|||
ishtp_write_message(dev, &hdr, (unsigned char *)&dma_xfer);
|
||||
spin_lock_irqsave(&cl->tx_free_list_spinlock, tx_free_flags);
|
||||
list_add_tail(&cl_msg->list, &cl->tx_free_list.list);
|
||||
++cl->tx_ring_free_size;
|
||||
spin_unlock_irqrestore(&cl->tx_free_list_spinlock, tx_free_flags);
|
||||
++cl->send_msg_cnt_dma;
|
||||
}
|
||||
|
|
|
@ -84,6 +84,7 @@ struct ishtp_cl {
|
|||
/* Client Tx buffers list */
|
||||
unsigned int tx_ring_size;
|
||||
struct ishtp_cl_tx_ring tx_list, tx_free_list;
|
||||
int tx_ring_free_size;
|
||||
spinlock_t tx_list_spinlock;
|
||||
spinlock_t tx_free_list_spinlock;
|
||||
size_t tx_offs; /* Offset in buffer at head of 'tx_list' */
|
||||
|
@ -137,6 +138,8 @@ int ishtp_cl_alloc_rx_ring(struct ishtp_cl *cl);
|
|||
int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl);
|
||||
void ishtp_cl_free_rx_ring(struct ishtp_cl *cl);
|
||||
void ishtp_cl_free_tx_ring(struct ishtp_cl *cl);
|
||||
int ishtp_cl_get_tx_free_buffer_size(struct ishtp_cl *cl);
|
||||
int ishtp_cl_get_tx_free_rings(struct ishtp_cl *cl);
|
||||
|
||||
/* DMA I/F functions */
|
||||
void recv_ishtp_cl_msg_dma(struct ishtp_device *dev, void *msg,
|
||||
|
@ -178,5 +181,7 @@ int ishtp_cl_flush_queues(struct ishtp_cl *cl);
|
|||
|
||||
/* exported functions from ISHTP client buffer management scope */
|
||||
int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);
|
||||
bool ishtp_cl_tx_empty(struct ishtp_cl *cl);
|
||||
struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl);
|
||||
|
||||
#endif /* _ISHTP_CLIENT_H_ */
|
||||
|
|
|
@ -207,7 +207,7 @@ struct ishtp_device {
|
|||
struct work_struct bh_hbm_work;
|
||||
|
||||
/* IPC write queue */
|
||||
struct wr_msg_ctl_info wr_processing_list_head, wr_free_list_head;
|
||||
struct list_head wr_processing_list, wr_free_list;
|
||||
/* For both processing list and free list */
|
||||
spinlock_t wr_processing_spinlock;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче