/** * mei_write - the write function. * * @file: pointer to file structure * @ubuf: pointer to user buffer * @length: buffer length * @offset: data offset in buffer * * Return: >=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 *cb; struct mei_device *dev; int rets; 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; } if (!mei_cl_is_connected(cl)) { cl_err(dev, cl, "is not connected"); rets = -ENODEV; goto out; } if (!mei_me_cl_is_active(cl->me_cl)) { rets = -ENOTTY; goto out; } if (length > mei_cl_mtu(cl)) { rets = -EFBIG; goto out; } if (length == 0) { rets = 0; goto out; } while (cl->tx_cb_queued >= dev->tx_queue_limit) { if (file->f_flags & O_NONBLOCK) { rets = -EAGAIN; goto out; } mutex_unlock(&dev->device_lock); rets = wait_event_interruptible(cl->tx_wait, cl->writing_state == MEI_WRITE_COMPLETE || (!mei_cl_is_connected(cl))); mutex_lock(&dev->device_lock); if (rets) { if (signal_pending(current)) rets = -EINTR; goto out; } if (!mei_cl_is_connected(cl)) { rets = -ENODEV; goto out; } } *offset = 0; cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); if (!cb) { rets = -ENOMEM; goto out; } rets = copy_from_user(cb->buf.data, ubuf, length); if (rets) { dev_dbg(dev->dev, "failed to copy data from userland\n"); rets = -EFAULT; mei_io_cb_free(cb); goto out; } rets = mei_cl_write(cl, cb); out: mutex_unlock(&dev->device_lock); 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 * * Return: >=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 *cb; struct mei_device *dev; int rets; 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; } if (!mei_cl_is_connected(cl)) { cl_err(dev, cl, "is not connected"); rets = -ENODEV; goto out; } if (!mei_me_cl_is_active(cl->me_cl)) { rets = -ENOTTY; goto out; } if (length > mei_cl_mtu(cl)) { rets = -EFBIG; goto out; } if (length == 0) { rets = 0; goto out; } *offset = 0; cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); if (!cb) { rets = -ENOMEM; goto out; } rets = copy_from_user(cb->buf.data, ubuf, length); if (rets) { dev_dbg(dev->dev, "failed to copy data from userland\n"); rets = -EFAULT; mei_io_cb_free(cb); goto out; } if (cl == &dev->iamthif_cl) { rets = mei_amthif_write(cl, cb); if (!rets) rets = length; goto out; } rets = mei_cl_write(cl, cb); out: mutex_unlock(&dev->device_lock); 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 * * Return: >=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; 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; } if (!mei_cl_is_connected(cl)) { cl_err(dev, cl, "is not connected"); rets = -ENODEV; goto out; } if (!mei_me_cl_is_active(cl->me_cl)) { rets = -ENOTTY; goto out; } if (length > mei_cl_mtu(cl)) { rets = -EFBIG; goto out; } if (length == 0) { rets = 0; 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)) { *offset = 0; mei_io_cb_free(write_cb); write_cb = NULL; } } } *offset = 0; write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); if (!write_cb) { rets = -ENOMEM; goto out; } rets = copy_from_user(write_cb->buf.data, ubuf, length); if (rets) { dev_dbg(dev->dev, "failed to copy data from userland\n"); rets = -EFAULT; goto out; } if (cl == &dev->iamthif_cl) { rets = mei_amthif_write(cl, write_cb); if (rets) { dev_err(dev->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; }