1e5354107SSamuel Ortiz /* 2e5354107SSamuel Ortiz * Intel Management Engine Interface (Intel MEI) Linux driver 3e5354107SSamuel Ortiz * Copyright (c) 2012-2013, Intel Corporation. 4e5354107SSamuel Ortiz * 5e5354107SSamuel Ortiz * This program is free software; you can redistribute it and/or modify it 6e5354107SSamuel Ortiz * under the terms and conditions of the GNU General Public License, 7e5354107SSamuel Ortiz * version 2, as published by the Free Software Foundation. 8e5354107SSamuel Ortiz * 9e5354107SSamuel Ortiz * This program is distributed in the hope it will be useful, but WITHOUT 10e5354107SSamuel Ortiz * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11e5354107SSamuel Ortiz * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12e5354107SSamuel Ortiz * more details. 13e5354107SSamuel Ortiz * 14e5354107SSamuel Ortiz */ 15e5354107SSamuel Ortiz 16e5354107SSamuel Ortiz #include <linux/module.h> 17e5354107SSamuel Ortiz #include <linux/device.h> 18e5354107SSamuel Ortiz #include <linux/kernel.h> 193e833295SSamuel Ortiz #include <linux/sched.h> 20e5354107SSamuel Ortiz #include <linux/init.h> 21e5354107SSamuel Ortiz #include <linux/errno.h> 22e5354107SSamuel Ortiz #include <linux/slab.h> 23e5354107SSamuel Ortiz #include <linux/mutex.h> 24e5354107SSamuel Ortiz #include <linux/interrupt.h> 25e5354107SSamuel Ortiz #include <linux/pci.h> 26e5354107SSamuel Ortiz #include <linux/mei_cl_bus.h> 27e5354107SSamuel Ortiz 28e5354107SSamuel Ortiz #include "mei_dev.h" 293e833295SSamuel Ortiz #include "hw-me.h" 303e833295SSamuel Ortiz #include "client.h" 31e5354107SSamuel Ortiz 32e5354107SSamuel Ortiz #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver) 33e5354107SSamuel Ortiz #define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev) 34e5354107SSamuel Ortiz 35e5354107SSamuel Ortiz static int mei_cl_device_match(struct device *dev, struct device_driver *drv) 36e5354107SSamuel Ortiz { 37e5354107SSamuel Ortiz struct mei_cl_device *device = to_mei_cl_device(dev); 38e5354107SSamuel Ortiz struct mei_cl_driver *driver = to_mei_cl_driver(drv); 39e5354107SSamuel Ortiz const struct mei_cl_device_id *id; 40e5354107SSamuel Ortiz 41e5354107SSamuel Ortiz if (!device) 42e5354107SSamuel Ortiz return 0; 43e5354107SSamuel Ortiz 44e5354107SSamuel Ortiz if (!driver || !driver->id_table) 45e5354107SSamuel Ortiz return 0; 46e5354107SSamuel Ortiz 47e5354107SSamuel Ortiz id = driver->id_table; 48e5354107SSamuel Ortiz 49e5354107SSamuel Ortiz while (id->name[0]) { 50e5354107SSamuel Ortiz if (!strcmp(dev_name(dev), id->name)) 51e5354107SSamuel Ortiz return 1; 52e5354107SSamuel Ortiz 53e5354107SSamuel Ortiz id++; 54e5354107SSamuel Ortiz } 55e5354107SSamuel Ortiz 56e5354107SSamuel Ortiz return 0; 57e5354107SSamuel Ortiz } 58e5354107SSamuel Ortiz 59e5354107SSamuel Ortiz static int mei_cl_device_probe(struct device *dev) 60e5354107SSamuel Ortiz { 61e5354107SSamuel Ortiz struct mei_cl_device *device = to_mei_cl_device(dev); 62e5354107SSamuel Ortiz struct mei_cl_driver *driver; 63e5354107SSamuel Ortiz struct mei_cl_device_id id; 64e5354107SSamuel Ortiz 65e5354107SSamuel Ortiz if (!device) 66e5354107SSamuel Ortiz return 0; 67e5354107SSamuel Ortiz 68e5354107SSamuel Ortiz driver = to_mei_cl_driver(dev->driver); 69e5354107SSamuel Ortiz if (!driver || !driver->probe) 70e5354107SSamuel Ortiz return -ENODEV; 71e5354107SSamuel Ortiz 72e5354107SSamuel Ortiz dev_dbg(dev, "Device probe\n"); 73e5354107SSamuel Ortiz 74e5354107SSamuel Ortiz strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE); 75e5354107SSamuel Ortiz 76e5354107SSamuel Ortiz return driver->probe(device, &id); 77e5354107SSamuel Ortiz } 78e5354107SSamuel Ortiz 79e5354107SSamuel Ortiz static int mei_cl_device_remove(struct device *dev) 80e5354107SSamuel Ortiz { 81e5354107SSamuel Ortiz struct mei_cl_device *device = to_mei_cl_device(dev); 82e5354107SSamuel Ortiz struct mei_cl_driver *driver; 83e5354107SSamuel Ortiz 84e5354107SSamuel Ortiz if (!device || !dev->driver) 85e5354107SSamuel Ortiz return 0; 86e5354107SSamuel Ortiz 873e833295SSamuel Ortiz if (device->event_cb) { 883e833295SSamuel Ortiz device->event_cb = NULL; 893e833295SSamuel Ortiz cancel_work_sync(&device->event_work); 903e833295SSamuel Ortiz } 913e833295SSamuel Ortiz 92e5354107SSamuel Ortiz driver = to_mei_cl_driver(dev->driver); 93e5354107SSamuel Ortiz if (!driver->remove) { 94e5354107SSamuel Ortiz dev->driver = NULL; 95e5354107SSamuel Ortiz 96e5354107SSamuel Ortiz return 0; 97e5354107SSamuel Ortiz } 98e5354107SSamuel Ortiz 99e5354107SSamuel Ortiz return driver->remove(device); 100e5354107SSamuel Ortiz } 101e5354107SSamuel Ortiz 102e5354107SSamuel Ortiz static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 103e5354107SSamuel Ortiz char *buf) 104e5354107SSamuel Ortiz { 105e5354107SSamuel Ortiz int len; 106e5354107SSamuel Ortiz 107e5354107SSamuel Ortiz len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev)); 108e5354107SSamuel Ortiz 109e5354107SSamuel Ortiz return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 110e5354107SSamuel Ortiz } 111e5354107SSamuel Ortiz 112e5354107SSamuel Ortiz static struct device_attribute mei_cl_dev_attrs[] = { 113e5354107SSamuel Ortiz __ATTR_RO(modalias), 114e5354107SSamuel Ortiz __ATTR_NULL, 115e5354107SSamuel Ortiz }; 116e5354107SSamuel Ortiz 117e5354107SSamuel Ortiz static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) 118e5354107SSamuel Ortiz { 119e5354107SSamuel Ortiz if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev))) 120e5354107SSamuel Ortiz return -ENOMEM; 121e5354107SSamuel Ortiz 122e5354107SSamuel Ortiz return 0; 123e5354107SSamuel Ortiz } 124e5354107SSamuel Ortiz 125e5354107SSamuel Ortiz static struct bus_type mei_cl_bus_type = { 126e5354107SSamuel Ortiz .name = "mei", 127e5354107SSamuel Ortiz .dev_attrs = mei_cl_dev_attrs, 128e5354107SSamuel Ortiz .match = mei_cl_device_match, 129e5354107SSamuel Ortiz .probe = mei_cl_device_probe, 130e5354107SSamuel Ortiz .remove = mei_cl_device_remove, 131e5354107SSamuel Ortiz .uevent = mei_cl_uevent, 132e5354107SSamuel Ortiz }; 133e5354107SSamuel Ortiz 134e5354107SSamuel Ortiz static void mei_cl_dev_release(struct device *dev) 135e5354107SSamuel Ortiz { 136e5354107SSamuel Ortiz kfree(to_mei_cl_device(dev)); 137e5354107SSamuel Ortiz } 138e5354107SSamuel Ortiz 139e5354107SSamuel Ortiz static struct device_type mei_cl_device_type = { 140e5354107SSamuel Ortiz .release = mei_cl_dev_release, 141e5354107SSamuel Ortiz }; 142e5354107SSamuel Ortiz 143a7b71bc0SSamuel Ortiz static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev, 144a7b71bc0SSamuel Ortiz uuid_le uuid) 145a7b71bc0SSamuel Ortiz { 146a7b71bc0SSamuel Ortiz struct mei_cl *cl, *next; 147a7b71bc0SSamuel Ortiz 148a7b71bc0SSamuel Ortiz list_for_each_entry_safe(cl, next, &dev->device_list, device_link) { 149a7b71bc0SSamuel Ortiz if (!uuid_le_cmp(uuid, cl->device_uuid)) 150a7b71bc0SSamuel Ortiz return cl; 151a7b71bc0SSamuel Ortiz } 152a7b71bc0SSamuel Ortiz 153a7b71bc0SSamuel Ortiz return NULL; 154a7b71bc0SSamuel Ortiz } 155a7b71bc0SSamuel Ortiz struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, 156e5354107SSamuel Ortiz uuid_le uuid, char *name) 157e5354107SSamuel Ortiz { 158e5354107SSamuel Ortiz struct mei_cl_device *device; 159a7b71bc0SSamuel Ortiz struct mei_cl *cl; 160e5354107SSamuel Ortiz int status; 161e5354107SSamuel Ortiz 162a7b71bc0SSamuel Ortiz cl = mei_bus_find_mei_cl_by_uuid(dev, uuid); 163a7b71bc0SSamuel Ortiz if (cl == NULL) 164a7b71bc0SSamuel Ortiz return NULL; 165a7b71bc0SSamuel Ortiz 166e5354107SSamuel Ortiz device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); 167e5354107SSamuel Ortiz if (!device) 168e5354107SSamuel Ortiz return NULL; 169e5354107SSamuel Ortiz 170a7b71bc0SSamuel Ortiz device->cl = cl; 171a7b71bc0SSamuel Ortiz 172a7b71bc0SSamuel Ortiz device->dev.parent = &dev->pdev->dev; 173e5354107SSamuel Ortiz device->dev.bus = &mei_cl_bus_type; 174e5354107SSamuel Ortiz device->dev.type = &mei_cl_device_type; 175e5354107SSamuel Ortiz 176e5354107SSamuel Ortiz dev_set_name(&device->dev, "%s", name); 177e5354107SSamuel Ortiz 178e5354107SSamuel Ortiz status = device_register(&device->dev); 179a7b71bc0SSamuel Ortiz if (status) { 180a7b71bc0SSamuel Ortiz dev_err(&dev->pdev->dev, "Failed to register MEI device\n"); 181a7b71bc0SSamuel Ortiz kfree(device); 182a7b71bc0SSamuel Ortiz return NULL; 183a7b71bc0SSamuel Ortiz } 184a7b71bc0SSamuel Ortiz 185a7b71bc0SSamuel Ortiz cl->device = device; 186e5354107SSamuel Ortiz 187e5354107SSamuel Ortiz dev_dbg(&device->dev, "client %s registered\n", name); 188e5354107SSamuel Ortiz 189e5354107SSamuel Ortiz return device; 190e5354107SSamuel Ortiz } 191e5354107SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_add_device); 192e5354107SSamuel Ortiz 193e5354107SSamuel Ortiz void mei_cl_remove_device(struct mei_cl_device *device) 194e5354107SSamuel Ortiz { 195e5354107SSamuel Ortiz device_unregister(&device->dev); 196e5354107SSamuel Ortiz } 197e5354107SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_remove_device); 198333e4ee0SSamuel Ortiz 199333e4ee0SSamuel Ortiz int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner) 200333e4ee0SSamuel Ortiz { 201333e4ee0SSamuel Ortiz int err; 202333e4ee0SSamuel Ortiz 203333e4ee0SSamuel Ortiz driver->driver.name = driver->name; 204333e4ee0SSamuel Ortiz driver->driver.owner = owner; 205333e4ee0SSamuel Ortiz driver->driver.bus = &mei_cl_bus_type; 206333e4ee0SSamuel Ortiz 207333e4ee0SSamuel Ortiz err = driver_register(&driver->driver); 208333e4ee0SSamuel Ortiz if (err) 209333e4ee0SSamuel Ortiz return err; 210333e4ee0SSamuel Ortiz 211333e4ee0SSamuel Ortiz pr_debug("mei: driver [%s] registered\n", driver->driver.name); 212333e4ee0SSamuel Ortiz 213333e4ee0SSamuel Ortiz return 0; 214333e4ee0SSamuel Ortiz } 215333e4ee0SSamuel Ortiz EXPORT_SYMBOL_GPL(__mei_cl_driver_register); 216333e4ee0SSamuel Ortiz 217333e4ee0SSamuel Ortiz void mei_cl_driver_unregister(struct mei_cl_driver *driver) 218333e4ee0SSamuel Ortiz { 219333e4ee0SSamuel Ortiz driver_unregister(&driver->driver); 220333e4ee0SSamuel Ortiz 221333e4ee0SSamuel Ortiz pr_debug("mei: driver [%s] unregistered\n", driver->driver.name); 222333e4ee0SSamuel Ortiz } 223333e4ee0SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); 2243e833295SSamuel Ortiz 22544d88d91SSamuel Ortiz static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, 22644d88d91SSamuel Ortiz bool blocking) 2273e833295SSamuel Ortiz { 2283e833295SSamuel Ortiz struct mei_device *dev; 2293e833295SSamuel Ortiz struct mei_msg_hdr mei_hdr; 2303e833295SSamuel Ortiz struct mei_cl_cb *cb; 2313e833295SSamuel Ortiz int me_cl_id, err; 2323e833295SSamuel Ortiz 2333e833295SSamuel Ortiz if (WARN_ON(!cl || !cl->dev)) 2343e833295SSamuel Ortiz return -ENODEV; 2353e833295SSamuel Ortiz 2363e833295SSamuel Ortiz if (cl->state != MEI_FILE_CONNECTED) 2373e833295SSamuel Ortiz return -ENODEV; 2383e833295SSamuel Ortiz 2393e833295SSamuel Ortiz cb = mei_io_cb_init(cl, NULL); 2403e833295SSamuel Ortiz if (!cb) 2413e833295SSamuel Ortiz return -ENOMEM; 2423e833295SSamuel Ortiz 2433e833295SSamuel Ortiz err = mei_io_cb_alloc_req_buf(cb, length); 2443e833295SSamuel Ortiz if (err < 0) { 2453e833295SSamuel Ortiz mei_io_cb_free(cb); 2463e833295SSamuel Ortiz return err; 2473e833295SSamuel Ortiz } 2483e833295SSamuel Ortiz 2493e833295SSamuel Ortiz memcpy(cb->request_buffer.data, buf, length); 2503e833295SSamuel Ortiz cb->fop_type = MEI_FOP_WRITE; 2513e833295SSamuel Ortiz 2523e833295SSamuel Ortiz dev = cl->dev; 2533e833295SSamuel Ortiz 2543e833295SSamuel Ortiz mutex_lock(&dev->device_lock); 2553e833295SSamuel Ortiz 2563e833295SSamuel Ortiz /* Check if we have an ME client device */ 2573e833295SSamuel Ortiz me_cl_id = mei_me_cl_by_id(dev, cl->me_client_id); 2583e833295SSamuel Ortiz if (me_cl_id == dev->me_clients_num) { 2593e833295SSamuel Ortiz err = -ENODEV; 2603e833295SSamuel Ortiz goto out_err; 2613e833295SSamuel Ortiz } 2623e833295SSamuel Ortiz 2633e833295SSamuel Ortiz if (length > dev->me_clients[me_cl_id].props.max_msg_length) { 2643e833295SSamuel Ortiz err = -EINVAL; 2653e833295SSamuel Ortiz goto out_err; 2663e833295SSamuel Ortiz } 2673e833295SSamuel Ortiz 2683e833295SSamuel Ortiz err = mei_cl_flow_ctrl_creds(cl); 2693e833295SSamuel Ortiz if (err < 0) 2703e833295SSamuel Ortiz goto out_err; 2713e833295SSamuel Ortiz 2723e833295SSamuel Ortiz /* Host buffer is not ready, we queue the request */ 2733e833295SSamuel Ortiz if (err == 0 || !dev->hbuf_is_ready) { 2743e833295SSamuel Ortiz cb->buf_idx = 0; 2753e833295SSamuel Ortiz mei_hdr.msg_complete = 0; 2763e833295SSamuel Ortiz cl->writing_state = MEI_WRITING; 2773e833295SSamuel Ortiz 27844d88d91SSamuel Ortiz goto out; 2793e833295SSamuel Ortiz } 2803e833295SSamuel Ortiz 2813e833295SSamuel Ortiz dev->hbuf_is_ready = false; 2823e833295SSamuel Ortiz 2833e833295SSamuel Ortiz /* Check for a maximum length */ 2843e833295SSamuel Ortiz if (length > mei_hbuf_max_len(dev)) { 2853e833295SSamuel Ortiz mei_hdr.length = mei_hbuf_max_len(dev); 2863e833295SSamuel Ortiz mei_hdr.msg_complete = 0; 2873e833295SSamuel Ortiz } else { 2883e833295SSamuel Ortiz mei_hdr.length = length; 2893e833295SSamuel Ortiz mei_hdr.msg_complete = 1; 2903e833295SSamuel Ortiz } 2913e833295SSamuel Ortiz 2923e833295SSamuel Ortiz mei_hdr.host_addr = cl->host_client_id; 2933e833295SSamuel Ortiz mei_hdr.me_addr = cl->me_client_id; 2943e833295SSamuel Ortiz mei_hdr.reserved = 0; 2953e833295SSamuel Ortiz 2963e833295SSamuel Ortiz if (mei_write_message(dev, &mei_hdr, buf)) { 2973e833295SSamuel Ortiz err = -EIO; 2983e833295SSamuel Ortiz goto out_err; 2993e833295SSamuel Ortiz } 3003e833295SSamuel Ortiz 3013e833295SSamuel Ortiz cl->writing_state = MEI_WRITING; 3023e833295SSamuel Ortiz cb->buf_idx = mei_hdr.length; 3033e833295SSamuel Ortiz 30444d88d91SSamuel Ortiz out: 30544d88d91SSamuel Ortiz if (mei_hdr.msg_complete) { 3063e833295SSamuel Ortiz if (mei_cl_flow_ctrl_reduce(cl)) { 30744d88d91SSamuel Ortiz err = -ENODEV; 3083e833295SSamuel Ortiz goto out_err; 3093e833295SSamuel Ortiz } 3103e833295SSamuel Ortiz list_add_tail(&cb->list, &dev->write_waiting_list.list); 31144d88d91SSamuel Ortiz } else { 31244d88d91SSamuel Ortiz list_add_tail(&cb->list, &dev->write_list.list); 3133e833295SSamuel Ortiz } 3143e833295SSamuel Ortiz 3153e833295SSamuel Ortiz mutex_unlock(&dev->device_lock); 3163e833295SSamuel Ortiz 31744d88d91SSamuel Ortiz if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { 31844d88d91SSamuel Ortiz if (wait_event_interruptible(cl->tx_wait, 31944d88d91SSamuel Ortiz cl->writing_state == MEI_WRITE_COMPLETE)) { 32044d88d91SSamuel Ortiz if (signal_pending(current)) 32144d88d91SSamuel Ortiz err = -EINTR; 32244d88d91SSamuel Ortiz err = -ERESTARTSYS; 32344d88d91SSamuel Ortiz mutex_lock(&dev->device_lock); 32444d88d91SSamuel Ortiz goto out_err; 32544d88d91SSamuel Ortiz } 32644d88d91SSamuel Ortiz } 32744d88d91SSamuel Ortiz 3283e833295SSamuel Ortiz return mei_hdr.length; 3293e833295SSamuel Ortiz 3303e833295SSamuel Ortiz out_err: 3313e833295SSamuel Ortiz mutex_unlock(&dev->device_lock); 3323e833295SSamuel Ortiz mei_io_cb_free(cb); 3333e833295SSamuel Ortiz 3343e833295SSamuel Ortiz return err; 3353e833295SSamuel Ortiz } 3363e833295SSamuel Ortiz 3373e833295SSamuel Ortiz int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) 3383e833295SSamuel Ortiz { 3393e833295SSamuel Ortiz struct mei_device *dev; 3403e833295SSamuel Ortiz struct mei_cl_cb *cb; 3413e833295SSamuel Ortiz size_t r_length; 3423e833295SSamuel Ortiz int err; 3433e833295SSamuel Ortiz 3443e833295SSamuel Ortiz if (WARN_ON(!cl || !cl->dev)) 3453e833295SSamuel Ortiz return -ENODEV; 3463e833295SSamuel Ortiz 3473e833295SSamuel Ortiz dev = cl->dev; 3483e833295SSamuel Ortiz 3493e833295SSamuel Ortiz mutex_lock(&dev->device_lock); 3503e833295SSamuel Ortiz 3513e833295SSamuel Ortiz if (!cl->read_cb) { 3523e833295SSamuel Ortiz err = mei_cl_read_start(cl); 3533e833295SSamuel Ortiz if (err < 0) { 3543e833295SSamuel Ortiz mutex_unlock(&dev->device_lock); 3553e833295SSamuel Ortiz return err; 3563e833295SSamuel Ortiz } 3573e833295SSamuel Ortiz } 3583e833295SSamuel Ortiz 3593e833295SSamuel Ortiz if (cl->reading_state != MEI_READ_COMPLETE && 3603e833295SSamuel Ortiz !waitqueue_active(&cl->rx_wait)) { 3613e833295SSamuel Ortiz mutex_unlock(&dev->device_lock); 3623e833295SSamuel Ortiz 3633e833295SSamuel Ortiz if (wait_event_interruptible(cl->rx_wait, 3643e833295SSamuel Ortiz (MEI_READ_COMPLETE == cl->reading_state))) { 3653e833295SSamuel Ortiz if (signal_pending(current)) 3663e833295SSamuel Ortiz return -EINTR; 3673e833295SSamuel Ortiz return -ERESTARTSYS; 3683e833295SSamuel Ortiz } 3693e833295SSamuel Ortiz 3703e833295SSamuel Ortiz mutex_lock(&dev->device_lock); 3713e833295SSamuel Ortiz } 3723e833295SSamuel Ortiz 3733e833295SSamuel Ortiz cb = cl->read_cb; 3743e833295SSamuel Ortiz 3753e833295SSamuel Ortiz if (cl->reading_state != MEI_READ_COMPLETE) { 3763e833295SSamuel Ortiz r_length = 0; 3773e833295SSamuel Ortiz goto out; 3783e833295SSamuel Ortiz } 3793e833295SSamuel Ortiz 3803e833295SSamuel Ortiz r_length = min_t(size_t, length, cb->buf_idx); 3813e833295SSamuel Ortiz 3823e833295SSamuel Ortiz memcpy(buf, cb->response_buffer.data, r_length); 3833e833295SSamuel Ortiz 3843e833295SSamuel Ortiz mei_io_cb_free(cb); 3853e833295SSamuel Ortiz cl->reading_state = MEI_IDLE; 3863e833295SSamuel Ortiz cl->read_cb = NULL; 3873e833295SSamuel Ortiz 3883e833295SSamuel Ortiz out: 3893e833295SSamuel Ortiz mutex_unlock(&dev->device_lock); 3903e833295SSamuel Ortiz 3913e833295SSamuel Ortiz return r_length; 3923e833295SSamuel Ortiz } 3933e833295SSamuel Ortiz 39444d88d91SSamuel Ortiz inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length) 39544d88d91SSamuel Ortiz { 39644d88d91SSamuel Ortiz return ___mei_cl_send(cl, buf, length, 0); 39744d88d91SSamuel Ortiz } 39844d88d91SSamuel Ortiz 39944d88d91SSamuel Ortiz inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length) 40044d88d91SSamuel Ortiz { 40144d88d91SSamuel Ortiz return ___mei_cl_send(cl, buf, length, 1); 40244d88d91SSamuel Ortiz } 40344d88d91SSamuel Ortiz 4043e833295SSamuel Ortiz int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) 4053e833295SSamuel Ortiz { 406a7b71bc0SSamuel Ortiz struct mei_cl *cl = device->cl; 4073e833295SSamuel Ortiz 408a7b71bc0SSamuel Ortiz if (cl == NULL) 409a7b71bc0SSamuel Ortiz return -ENODEV; 4103e833295SSamuel Ortiz 4113e833295SSamuel Ortiz if (device->ops && device->ops->send) 4123e833295SSamuel Ortiz return device->ops->send(device, buf, length); 4133e833295SSamuel Ortiz 4143e833295SSamuel Ortiz return __mei_cl_send(cl, buf, length); 4153e833295SSamuel Ortiz } 4163e833295SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_send); 4173e833295SSamuel Ortiz 4183e833295SSamuel Ortiz int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) 4193e833295SSamuel Ortiz { 420a7b71bc0SSamuel Ortiz struct mei_cl *cl = device->cl; 4213e833295SSamuel Ortiz 422a7b71bc0SSamuel Ortiz if (cl == NULL) 423a7b71bc0SSamuel Ortiz return -ENODEV; 4243e833295SSamuel Ortiz 4253e833295SSamuel Ortiz if (device->ops && device->ops->recv) 4263e833295SSamuel Ortiz return device->ops->recv(device, buf, length); 4273e833295SSamuel Ortiz 4283e833295SSamuel Ortiz return __mei_cl_recv(cl, buf, length); 4293e833295SSamuel Ortiz } 4303e833295SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_recv); 4313e833295SSamuel Ortiz 4323e833295SSamuel Ortiz static void mei_bus_event_work(struct work_struct *work) 4333e833295SSamuel Ortiz { 4343e833295SSamuel Ortiz struct mei_cl_device *device; 4353e833295SSamuel Ortiz 4363e833295SSamuel Ortiz device = container_of(work, struct mei_cl_device, event_work); 4373e833295SSamuel Ortiz 4383e833295SSamuel Ortiz if (device->event_cb) 4393e833295SSamuel Ortiz device->event_cb(device, device->events, device->event_context); 4403e833295SSamuel Ortiz 4413e833295SSamuel Ortiz device->events = 0; 4423e833295SSamuel Ortiz 4433e833295SSamuel Ortiz /* Prepare for the next read */ 4443e833295SSamuel Ortiz mei_cl_read_start(device->cl); 4453e833295SSamuel Ortiz } 4463e833295SSamuel Ortiz 4473e833295SSamuel Ortiz int mei_cl_register_event_cb(struct mei_cl_device *device, 4483e833295SSamuel Ortiz mei_cl_event_cb_t event_cb, void *context) 4493e833295SSamuel Ortiz { 4503e833295SSamuel Ortiz if (device->event_cb) 4513e833295SSamuel Ortiz return -EALREADY; 4523e833295SSamuel Ortiz 4533e833295SSamuel Ortiz device->events = 0; 4543e833295SSamuel Ortiz device->event_cb = event_cb; 4553e833295SSamuel Ortiz device->event_context = context; 4563e833295SSamuel Ortiz INIT_WORK(&device->event_work, mei_bus_event_work); 4573e833295SSamuel Ortiz 4583e833295SSamuel Ortiz mei_cl_read_start(device->cl); 4593e833295SSamuel Ortiz 4603e833295SSamuel Ortiz return 0; 4613e833295SSamuel Ortiz } 4623e833295SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_register_event_cb); 463cf3baefbSSamuel Ortiz 464*aa6aef21SSamuel Ortiz void *mei_cl_get_drvdata(const struct mei_cl_device *device) 465*aa6aef21SSamuel Ortiz { 466*aa6aef21SSamuel Ortiz return dev_get_drvdata(&device->dev); 467*aa6aef21SSamuel Ortiz } 468*aa6aef21SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_get_drvdata); 469*aa6aef21SSamuel Ortiz 470*aa6aef21SSamuel Ortiz void mei_cl_set_drvdata(struct mei_cl_device *device, void *data) 471*aa6aef21SSamuel Ortiz { 472*aa6aef21SSamuel Ortiz dev_set_drvdata(&device->dev, data); 473*aa6aef21SSamuel Ortiz } 474*aa6aef21SSamuel Ortiz EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); 475*aa6aef21SSamuel Ortiz 476cf3baefbSSamuel Ortiz void mei_cl_bus_rx_event(struct mei_cl *cl) 477cf3baefbSSamuel Ortiz { 478cf3baefbSSamuel Ortiz struct mei_cl_device *device = cl->device; 479cf3baefbSSamuel Ortiz 480cf3baefbSSamuel Ortiz if (!device || !device->event_cb) 481cf3baefbSSamuel Ortiz return; 482cf3baefbSSamuel Ortiz 483cf3baefbSSamuel Ortiz set_bit(MEI_CL_EVENT_RX, &device->events); 484cf3baefbSSamuel Ortiz 485cf3baefbSSamuel Ortiz schedule_work(&device->event_work); 486cf3baefbSSamuel Ortiz } 487cf3baefbSSamuel Ortiz 488cf3baefbSSamuel Ortiz int __init mei_cl_bus_init(void) 489cf3baefbSSamuel Ortiz { 490cf3baefbSSamuel Ortiz return bus_register(&mei_cl_bus_type); 491cf3baefbSSamuel Ortiz } 492cf3baefbSSamuel Ortiz 493cf3baefbSSamuel Ortiz void __exit mei_cl_bus_exit(void) 494cf3baefbSSamuel Ortiz { 495cf3baefbSSamuel Ortiz bus_unregister(&mei_cl_bus_type); 496cf3baefbSSamuel Ortiz } 497