diff options
Diffstat (limited to 'drivers/hid/intel-ish-hid/ishtp/bus.c')
| -rw-r--r-- | drivers/hid/intel-ish-hid/ishtp/bus.c | 232 |
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"); |
