in core.c [123:185]
static ssize_t gnss_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
struct gnss_device *gdev = file->private_data;
size_t written = 0;
int ret;
if (gdev->disconnected)
return -EIO;
if (!count)
return 0;
if (!(gdev->flags & GNSS_FLAG_HAS_WRITE_RAW))
return -EIO;
/* Ignoring O_NONBLOCK, write_raw() is synchronous. */
ret = mutex_lock_interruptible(&gdev->write_mutex);
if (ret)
return -ERESTARTSYS;
for (;;) {
size_t n = count - written;
if (n > GNSS_WRITE_BUF_SIZE)
n = GNSS_WRITE_BUF_SIZE;
if (copy_from_user(gdev->write_buf, buf, n)) {
ret = -EFAULT;
goto out_unlock;
}
/*
* Assumes write_raw can always accept GNSS_WRITE_BUF_SIZE
* bytes.
*
* FIXME: revisit
*/
down_read(&gdev->rwsem);
if (!gdev->disconnected)
ret = gdev->ops->write_raw(gdev, gdev->write_buf, n);
else
ret = -EIO;
up_read(&gdev->rwsem);
if (ret < 0)
break;
written += ret;
buf += ret;
if (written == count)
break;
}
if (written)
ret = written;
out_unlock:
mutex_unlock(&gdev->write_mutex);
return ret;
}