/** * mei_amthif_read_start - queue message for sending read credential * * @cl: host client * @file: file pointer of message recipient * * Return: 0 on success, <0 on failure. */ static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file) { struct mei_device *dev = cl->dev; struct mei_cl_cb *cb; int rets; cb = mei_io_cb_init(cl, MEI_FOP_READ, file); if (!cb) { rets = -ENOMEM; goto err; } rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl)); if (rets) goto err; list_add_tail(&cb->list, &dev->ctrl_wr_list.list); dev->iamthif_state = MEI_IAMTHIF_READING; dev->iamthif_fp = cb->fp; dev->iamthif_current_cb = cb; return 0; err: mei_io_cb_free(cb); return rets; }
/** * mei_write - the write function. * * @file: pointer to file structure * @ubuf: pointer to user buffer * @length: buffer length * @offset: data offset in buffer * * returns >=0 data length on success , <0 on error */ 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_cl_cb *write_cb = NULL; struct mei_device *dev; unsigned long timeout = 0; int rets; int id; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; dev = cl->dev; mutex_lock(&dev->device_lock); if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; goto out; } id = mei_me_cl_by_id(dev, cl->me_client_id); if (id < 0) { rets = -ENOTTY; goto out; } if (length == 0) { rets = 0; goto out; } if (length > dev->me_clients[id].props.max_msg_length) { rets = -EFBIG; goto out; } if (cl->state != MEI_FILE_CONNECTED) { dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", cl->host_client_id, cl->me_client_id); rets = -ENODEV; goto out; } if (cl == &dev->iamthif_cl) { write_cb = mei_amthif_find_read_list_entry(dev, file); if (write_cb) { timeout = write_cb->read_time + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); if (time_after(jiffies, timeout) || cl->reading_state == MEI_READ_COMPLETE) { *offset = 0; list_del(&write_cb->list); mei_io_cb_free(write_cb); write_cb = NULL; } } } /* free entry used in read */ if (cl->reading_state == MEI_READ_COMPLETE) { *offset = 0; write_cb = mei_cl_find_read_cb(cl); if (write_cb) { list_del(&write_cb->list); mei_io_cb_free(write_cb); write_cb = NULL; cl->reading_state = MEI_IDLE; cl->read_cb = NULL; } } else if (cl->reading_state == MEI_IDLE) *offset = 0; write_cb = mei_io_cb_init(cl, file); if (!write_cb) { dev_err(&dev->pdev->dev, "write cb allocation failed\n"); rets = -ENOMEM; goto out; } rets = mei_io_cb_alloc_req_buf(write_cb, length); if (rets) goto out; rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); if (rets) { dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n"); rets = -EFAULT; goto out; } if (cl == &dev->iamthif_cl) { rets = mei_amthif_write(dev, write_cb); if (rets) { dev_err(&dev->pdev->dev, "amthif write failed with status = %d\n", rets); goto out; } mutex_unlock(&dev->device_lock); return length; } rets = mei_cl_write(cl, write_cb, false); out: mutex_unlock(&dev->device_lock); if (rets < 0) mei_io_cb_free(write_cb); return rets; }