summaryrefslogtreecommitdiff
path: root/drivers/hid/intel-ish-hid/ishtp/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/intel-ish-hid/ishtp/bus.c')
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c232
1 files changed, 173 insertions, 59 deletions
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
index 728dc6d4561a..c6ce37244e49 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.c
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ISHTP bus driver
*
* Copyright (c) 2012-2016, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
*/
#include <linux/module.h>
@@ -119,7 +111,7 @@ int ishtp_send_msg(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
* Return: This returns IPC send message status.
*/
int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
- unsigned char *buf)
+ void *buf)
{
return ishtp_send_msg(dev, hdr, buf, NULL, NULL);
}
@@ -133,18 +125,15 @@ int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
*
* Return: fw client index or -ENOENT if not found
*/
-int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid)
+int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const guid_t *uuid)
{
- int i, res = -ENOENT;
+ unsigned int i;
for (i = 0; i < dev->fw_clients_num; ++i) {
- if (uuid_le_cmp(*uuid, dev->fw_clients[i].props.protocol_name)
- == 0) {
- res = i;
- break;
- }
+ if (guid_equal(uuid, &dev->fw_clients[i].props.protocol_name))
+ return i;
}
- return res;
+ return -ENOENT;
}
EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
@@ -158,7 +147,7 @@ EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
* 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)
+ const guid_t *uuid)
{
int i;
unsigned long flags;
@@ -174,6 +163,20 @@ struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
EXPORT_SYMBOL(ishtp_fw_cl_get_client);
/**
+ * 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.
+ *
+ * Return: firmware client id.
+ */
+int ishtp_get_fw_client_id(struct ishtp_fw_client *fw_client)
+{
+ return fw_client->client_id;
+}
+EXPORT_SYMBOL(ishtp_get_fw_client_id);
+
+/**
* ishtp_fw_cl_by_id() - return index to fw_clients for client_id
* @dev: the ishtp device structure
* @client_id: fw client id to search
@@ -223,6 +226,26 @@ static int ishtp_cl_device_probe(struct device *dev)
}
/**
+ * ishtp_cl_bus_match() - Bus match() callback
+ * @dev: the device structure
+ * @drv: the driver structure
+ *
+ * This is a bus match callback, called when a new ishtp_cl_device is
+ * registered during ishtp bus client enumeration. Use the guid_t in
+ * drv and dev to decide whether they match or not.
+ *
+ * Return: 1 if dev & drv matches, 0 otherwise.
+ */
+static int ishtp_cl_bus_match(struct device *dev, const struct device_driver *drv)
+{
+ struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
+ struct ishtp_cl_driver *driver = to_ishtp_cl_driver(drv);
+
+ return(device->fw_client ? guid_equal(&driver->id[0].guid,
+ &device->fw_client->props.protocol_name) : 0);
+}
+
+/**
* ishtp_cl_device_remove() - Bus remove() callback
* @dev: the device structure
*
@@ -232,27 +255,18 @@ static int ishtp_cl_device_probe(struct device *dev)
*
* Return: Return value from driver remove() call.
*/
-static int ishtp_cl_device_remove(struct device *dev)
+static void ishtp_cl_device_remove(struct device *dev)
{
struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
- struct ishtp_cl_driver *driver;
-
- if (!device || !dev->driver)
- return 0;
+ struct ishtp_cl_driver *driver = to_ishtp_cl_driver(dev->driver);
if (device->event_cb) {
device->event_cb = NULL;
cancel_work_sync(&device->event_work);
}
- driver = to_ishtp_cl_driver(dev->driver);
- if (!driver->remove) {
- dev->driver = NULL;
-
- return 0;
- }
-
- return driver->remove(device);
+ if (driver->remove)
+ driver->remove(device);
}
/**
@@ -298,13 +312,6 @@ static int ishtp_cl_device_resume(struct device *dev)
if (!device)
return 0;
- /*
- * When ISH needs hard reset, it is done asynchrnously, hence bus
- * resume will be called before full ISH resume
- */
- if (device->ishtp_dev->resume_flag)
- return 0;
-
driver = to_ishtp_cl_driver(dev->driver);
if (driver && driver->driver.pm) {
if (driver->driver.pm->resume)
@@ -343,7 +350,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
{
int len;
- len = snprintf(buf, PAGE_SIZE, "ishtp:%s\n", dev_name(dev));
+ len = snprintf(buf, PAGE_SIZE, ISHTP_MODULE_PREFIX "%s\n", dev_name(dev));
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
static DEVICE_ATTR_RO(modalias);
@@ -354,9 +361,9 @@ static struct attribute *ishtp_cl_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(ishtp_cl_dev);
-static int ishtp_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ishtp_cl_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- if (add_uevent_var(env, "MODALIAS=ishtp:%s", dev_name(dev)))
+ if (add_uevent_var(env, "MODALIAS=" ISHTP_MODULE_PREFIX "%s", dev_name(dev)))
return -ENOMEM;
return 0;
}
@@ -371,10 +378,11 @@ static const struct dev_pm_ops ishtp_cl_bus_dev_pm_ops = {
.restore = ishtp_cl_device_resume,
};
-static struct bus_type ishtp_cl_bus_type = {
+static const struct bus_type ishtp_cl_bus_type = {
.name = "ishtp",
.dev_groups = ishtp_cl_dev_groups,
.probe = ishtp_cl_device_probe,
+ .match = ishtp_cl_bus_match,
.remove = ishtp_cl_device_remove,
.pm = &ishtp_cl_bus_dev_pm_ops,
.uevent = ishtp_cl_uevent,
@@ -401,7 +409,7 @@ static const struct device_type ishtp_cl_device_type = {
* Return: ishtp_cl_device pointer or NULL on failure
*/
static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
- uuid_le uuid, char *name)
+ guid_t uuid, char *name)
{
struct ishtp_cl_device *device;
int status;
@@ -467,7 +475,7 @@ static void ishtp_bus_remove_device(struct ishtp_cl_device *device)
}
/**
- * __ishtp_cl_driver_register() - Client driver register
+ * ishtp_cl_driver_register() - Client driver register
* @driver: the client driver instance
* @owner: Owner of this driver module
*
@@ -476,11 +484,9 @@ static void ishtp_bus_remove_device(struct ishtp_cl_device *device)
*
* Return: Return value of driver_register or -ENODEV if not ready
*/
-int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
- struct module *owner)
+int ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
+ struct module *owner)
{
- int err;
-
if (!ishtp_device_ready)
return -ENODEV;
@@ -488,13 +494,9 @@ int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
driver->driver.owner = owner;
driver->driver.bus = &ishtp_cl_bus_type;
- err = driver_register(&driver->driver);
- if (err)
- return err;
-
- return 0;
+ return driver_register(&driver->driver);
}
-EXPORT_SYMBOL(__ishtp_cl_driver_register);
+EXPORT_SYMBOL(ishtp_cl_driver_register);
/**
* ishtp_cl_driver_unregister() - Client driver unregister
@@ -539,7 +541,7 @@ void ishtp_cl_bus_rx_event(struct ishtp_cl_device *device)
return;
if (device->event_cb)
- schedule_work(&device->event_work);
+ queue_work(device->ishtp_dev->unbound_wq, &device->event_work);
}
/**
@@ -616,6 +618,20 @@ void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
EXPORT_SYMBOL(ishtp_get_drvdata);
/**
+ * ishtp_dev_to_cl_device() - get ishtp_cl_device instance from device instance
+ * @device: device instance
+ *
+ * Get ish_cl_device instance which embeds device instance in it.
+ *
+ * Return: pointer to ishtp_cl_device instance
+ */
+struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *device)
+{
+ return to_ishtp_cl_device(device);
+}
+EXPORT_SYMBOL(ishtp_dev_to_cl_device);
+
+/**
* ishtp_bus_new_client() - Create a new client
* @dev: ISHTP device instance
*
@@ -629,7 +645,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev)
int i;
char *dev_name;
struct ishtp_cl_device *cl_device;
- uuid_le device_uuid;
+ guid_t device_uuid;
/*
* For all reported clients, create an unconnected client and add its
@@ -639,7 +655,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev)
*/
i = dev->fw_client_presentation_num - 1;
device_uuid = dev->fw_clients[i].props.protocol_name;
- dev_name = kasprintf(GFP_KERNEL, "{%pUL}", device_uuid.b);
+ dev_name = kasprintf(GFP_KERNEL, "{%pUL}", &device_uuid);
if (!dev_name)
return -ENOMEM;
@@ -675,7 +691,8 @@ int ishtp_cl_device_bind(struct ishtp_cl *cl)
spin_lock_irqsave(&cl->dev->device_list_lock, flags);
list_for_each_entry(cl_device, &cl->dev->device_list,
device_link) {
- if (cl_device->fw_client->client_id == cl->fw_client_id) {
+ if (cl_device->fw_client &&
+ cl_device->fw_client->client_id == cl->fw_client_id) {
cl->device = cl_device;
rv = 0;
break;
@@ -705,6 +722,8 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags);
list_for_each_entry(cl, &ishtp_dev->cl_list, link) {
cl->state = ISHTP_CL_DISCONNECTED;
+ if (warm_reset && cl->device->reference_count)
+ continue;
/*
* Wake any pending process. The waiter would check dev->state
@@ -735,6 +754,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
list_for_each_entry_safe(cl_device, n, &ishtp_dev->device_list,
device_link) {
+ cl_device->fw_client = NULL;
if (warm_reset && cl_device->reference_count)
continue;
@@ -808,6 +828,99 @@ int ishtp_use_dma_transfer(void)
}
/**
+ * ishtp_device() - Return device pointer
+ * @device: ISH-TP client device instance
+ *
+ * This interface is used to return device pointer from ishtp_cl_device
+ * instance.
+ *
+ * Return: device *.
+ */
+struct device *ishtp_device(struct ishtp_cl_device *device)
+{
+ return &device->dev;
+}
+EXPORT_SYMBOL(ishtp_device);
+
+/**
+ * ishtp_wait_resume() - Wait for IPC resume
+ * @dev: ishtp device
+ *
+ * Wait for IPC resume
+ *
+ * Return: resume complete or not
+ */
+bool ishtp_wait_resume(struct ishtp_device *dev)
+{
+ /* Waiting to get resume response */
+ if (dev->resume_flag)
+ wait_event_interruptible_timeout(dev->resume_wait,
+ !dev->resume_flag,
+ msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
+
+ return (!dev->resume_flag);
+}
+EXPORT_SYMBOL_GPL(ishtp_wait_resume);
+
+/**
+ * ishtp_get_pci_device() - Return PCI device dev pointer
+ * This interface is used to return PCI device pointer
+ * from ishtp_cl_device instance.
+ * @device: ISH-TP client device instance
+ *
+ * Return: device *.
+ */
+struct device *ishtp_get_pci_device(struct ishtp_cl_device *device)
+{
+ return device->ishtp_dev->devc;
+}
+EXPORT_SYMBOL(ishtp_get_pci_device);
+
+/**
+ * ishtp_get_workqueue - Retrieve the workqueue associated with an ISHTP device
+ * @cl_device: Pointer to the ISHTP client device structure
+ *
+ * Returns the workqueue_struct pointer (unbound_wq) associated with the given
+ * ISHTP client device. This workqueue is typically used for scheduling work
+ * related to the device.
+ *
+ * Return: Pointer to struct workqueue_struct.
+ */
+struct workqueue_struct *ishtp_get_workqueue(struct ishtp_cl_device *cl_device)
+{
+ return cl_device->ishtp_dev->unbound_wq;
+}
+EXPORT_SYMBOL(ishtp_get_workqueue);
+
+/**
+ * ishtp_trace_callback() - Return trace callback
+ * @cl_device: ISH-TP client device instance
+ *
+ * This interface is used to return trace callback function pointer.
+ *
+ * Return: *ishtp_print_log()
+ */
+ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device)
+{
+ return cl_device->ishtp_dev->print_log;
+}
+EXPORT_SYMBOL(ishtp_trace_callback);
+
+/**
+ * ish_hw_reset() - Call HW reset IPC callback
+ * @dev: ISHTP device instance
+ *
+ * This interface is used to reset HW in case of error.
+ *
+ * Return: value from IPC hw_reset callback
+ */
+int ish_hw_reset(struct ishtp_device *dev)
+{
+ return dev->ops->hw_reset(dev);
+}
+EXPORT_SYMBOL(ish_hw_reset);
+
+/**
* ishtp_bus_register() - Function to register bus
*
* This register ishtp bus
@@ -832,4 +945,5 @@ static void __exit ishtp_bus_unregister(void)
module_init(ishtp_bus_register);
module_exit(ishtp_bus_unregister);
+MODULE_DESCRIPTION("ISHTP bus driver");
MODULE_LICENSE("GPL");