diff options
Diffstat (limited to 'kernel/drivers/misc/mei/main.c')
-rw-r--r-- | kernel/drivers/misc/mei/main.c | 159 |
1 files changed, 129 insertions, 30 deletions
diff --git a/kernel/drivers/misc/mei/main.c b/kernel/drivers/misc/mei/main.c index e40bcd03b..80f9afcb1 100644 --- a/kernel/drivers/misc/mei/main.c +++ b/kernel/drivers/misc/mei/main.c @@ -94,7 +94,7 @@ static int mei_release(struct inode *inode, struct file *file) { struct mei_cl *cl = file->private_data; struct mei_device *dev; - int rets = 0; + int rets; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; @@ -106,11 +106,8 @@ static int mei_release(struct inode *inode, struct file *file) rets = mei_amthif_release(dev, file); goto out; } - if (mei_cl_is_connected(cl)) { - cl->state = MEI_FILE_DISCONNECTING; - cl_dbg(dev, cl, "disconnecting\n"); - rets = mei_cl_disconnect(cl); - } + rets = mei_cl_disconnect(cl); + mei_cl_flush_queues(cl, file); cl_dbg(dev, cl, "removing\n"); @@ -186,8 +183,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, err = mei_cl_read_start(cl, length, file); if (err && err != -EBUSY) { - dev_dbg(dev->dev, - "mei start read failure with status = %d\n", err); + cl_dbg(dev, cl, "mei start read failure status = %d\n", err); rets = err; goto out; } @@ -218,6 +214,11 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, cb = mei_cl_read_cb(cl, file); if (!cb) { + if (mei_cl_is_fixed_address(cl) && dev->allow_fixed_address) { + cb = mei_cl_read_cb(cl, NULL); + if (cb) + goto copy_buffer; + } rets = 0; goto out; } @@ -226,11 +227,11 @@ copy_buffer: /* now copy the data to user space */ if (cb->status) { rets = cb->status; - dev_dbg(dev->dev, "read operation failed %d\n", rets); + cl_dbg(dev, cl, "read operation failed %d\n", rets); goto free; } - dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n", + cl_dbg(dev, cl, "buf.size = %d buf.idx = %ld\n", cb->buf.size, cb->buf_idx); if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { rets = -EMSGSIZE; @@ -256,7 +257,7 @@ free: mei_io_cb_free(cb); out: - dev_dbg(dev->dev, "end mei read rets= %d\n", rets); + cl_dbg(dev, cl, "end mei read rets = %d\n", rets); mutex_unlock(&dev->device_lock); return rets; } @@ -274,7 +275,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, size_t length, loff_t *offset) { struct mei_cl *cl = file->private_data; - struct mei_me_client *me_cl = NULL; struct mei_cl_cb *write_cb = NULL; struct mei_device *dev; unsigned long timeout = 0; @@ -292,27 +292,27 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, goto out; } - me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); - if (!me_cl) { - rets = -ENOTTY; + if (!mei_cl_is_connected(cl)) { + cl_err(dev, cl, "is not connected"); + rets = -ENODEV; goto out; } - if (length == 0) { - rets = 0; + if (!mei_me_cl_is_active(cl->me_cl)) { + rets = -ENOTTY; goto out; } - if (length > me_cl->props.max_msg_length) { + if (length > mei_cl_mtu(cl)) { rets = -EFBIG; goto out; } - if (!mei_cl_is_connected(cl)) { - cl_err(dev, cl, "is not connected"); - rets = -ENODEV; + if (length == 0) { + rets = 0; goto out; } + if (cl == &dev->iamthif_cl) { write_cb = mei_amthif_find_read_list_entry(dev, file); @@ -350,14 +350,12 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, "amthif write failed with status = %d\n", rets); goto out; } - mei_me_cl_put(me_cl); mutex_unlock(&dev->device_lock); return length; } rets = mei_cl_write(cl, write_cb, false); out: - mei_me_cl_put(me_cl); mutex_unlock(&dev->device_lock); if (rets < 0) mei_io_cb_free(write_cb); @@ -395,17 +393,16 @@ static int mei_ioctl_connect_client(struct file *file, /* find ME client we're trying to connect to */ me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid); - if (!me_cl || me_cl->props.fixed_address) { + if (!me_cl || + (me_cl->props.fixed_address && !dev->allow_fixed_address)) { dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n", - &data->in_client_uuid); + &data->in_client_uuid); + mei_me_cl_put(me_cl); return -ENOTTY; } - cl->me_client_id = me_cl->client_id; - cl->cl_uuid = me_cl->props.protocol_name; - dev_dbg(dev->dev, "Connect to FW Client ID = %d\n", - cl->me_client_id); + me_cl->client_id); dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n", me_cl->props.protocol_version); dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n", @@ -441,7 +438,7 @@ static int mei_ioctl_connect_client(struct file *file, client->protocol_version = me_cl->props.protocol_version; dev_dbg(dev->dev, "Can connect?\n"); - rets = mei_cl_connect(cl, file); + rets = mei_cl_connect(cl, me_cl, file); end: mei_me_cl_put(me_cl); @@ -449,6 +446,49 @@ end: } /** + * mei_ioctl_client_notify_request - + * propagate event notification request to client + * + * @file: pointer to file structure + * @request: 0 - disable, 1 - enable + * + * Return: 0 on success , <0 on error + */ +static int mei_ioctl_client_notify_request(struct file *file, u32 request) +{ + struct mei_cl *cl = file->private_data; + + if (request != MEI_HBM_NOTIFICATION_START && + request != MEI_HBM_NOTIFICATION_STOP) + return -EINVAL; + + return mei_cl_notify_request(cl, file, (u8)request); +} + +/** + * mei_ioctl_client_notify_get - wait for notification request + * + * @file: pointer to file structure + * @notify_get: 0 - disable, 1 - enable + * + * Return: 0 on success , <0 on error + */ +static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get) +{ + struct mei_cl *cl = file->private_data; + bool notify_ev; + bool block = (file->f_flags & O_NONBLOCK) == 0; + int rets; + + rets = mei_cl_notify_get(cl, block, ¬ify_ev); + if (rets) + return rets; + + *notify_get = notify_ev ? 1 : 0; + return 0; +} + +/** * mei_ioctl - the IOCTL function * * @file: pointer to file structure @@ -462,6 +502,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) struct mei_device *dev; struct mei_cl *cl = file->private_data; struct mei_connect_client_data connect_data; + u32 notify_get, notify_req; int rets; @@ -502,6 +543,33 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) break; + case IOCTL_MEI_NOTIFY_SET: + dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_SET.\n"); + if (copy_from_user(¬ify_req, + (char __user *)data, sizeof(notify_req))) { + dev_dbg(dev->dev, "failed to copy data from userland\n"); + rets = -EFAULT; + goto out; + } + rets = mei_ioctl_client_notify_request(file, notify_req); + break; + + case IOCTL_MEI_NOTIFY_GET: + dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_GET.\n"); + rets = mei_ioctl_client_notify_get(file, ¬ify_get); + if (rets) + goto out; + + dev_dbg(dev->dev, "copy connect data to user\n"); + if (copy_to_user((char __user *)data, + ¬ify_get, sizeof(notify_get))) { + dev_dbg(dev->dev, "failed to copy data to userland\n"); + rets = -EFAULT; + goto out; + + } + break; + default: dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd); rets = -ENOIOCTLCMD; @@ -544,6 +612,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) struct mei_cl *cl = file->private_data; struct mei_device *dev; unsigned int mask = 0; + bool notify_en; if (WARN_ON(!cl || !cl->dev)) return POLLERR; @@ -552,6 +621,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) mutex_lock(&dev->device_lock); + notify_en = cl->notify_en && (req_events & POLLPRI); if (dev->dev_state != MEI_DEV_ENABLED || !mei_cl_is_connected(cl)) { @@ -564,6 +634,12 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) goto out; } + if (notify_en) { + poll_wait(file, &cl->ev_wait, wait); + if (cl->notify_ev) + mask |= POLLPRI; + } + if (req_events & (POLLIN | POLLRDNORM)) { poll_wait(file, &cl->rx_wait, wait); @@ -579,6 +655,28 @@ out: } /** + * mei_fasync - asynchronous io support + * + * @fd: file descriptor + * @file: pointer to file structure + * @band: band bitmap + * + * Return: negative on error, + * 0 if it did no changes, + * and positive a process was added or deleted + */ +static int mei_fasync(int fd, struct file *file, int band) +{ + + struct mei_cl *cl = file->private_data; + + if (!mei_cl_is_connected(cl)) + return -ENODEV; + + return fasync_helper(fd, file, band, &cl->ev_async); +} + +/** * fw_status_show - mei device attribute show method * * @device: device pointer @@ -630,6 +728,7 @@ static const struct file_operations mei_fops = { .release = mei_release, .write = mei_write, .poll = mei_poll, + .fasync = mei_fasync, .llseek = no_llseek }; |