in clients/hsi_char.c [412:469]
static ssize_t hsc_read(struct file *file, char __user *buf, size_t len,
loff_t *ppos __maybe_unused)
{
struct hsc_channel *channel = file->private_data;
struct hsi_msg *msg;
ssize_t ret;
if (len == 0)
return 0;
if (!IS_ALIGNED(len, sizeof(u32)))
return -EINVAL;
if (len > max_data_size)
len = max_data_size;
if (channel->ch >= channel->cl->rx_cfg.num_hw_channels)
return -ECHRNG;
if (test_and_set_bit(HSC_CH_READ, &channel->flags))
return -EBUSY;
msg = hsc_get_first_msg(channel, &channel->free_msgs_list);
if (!msg) {
ret = -ENOSPC;
goto out;
}
hsc_msg_len_set(msg, len);
msg->complete = hsc_rx_completed;
msg->destructor = hsc_rx_msg_destructor;
ret = hsi_async_read(channel->cl, msg);
if (ret < 0) {
hsc_add_tail(channel, msg, &channel->free_msgs_list);
goto out;
}
ret = wait_event_interruptible(channel->rx_wait,
!list_empty(&channel->rx_msgs_queue));
if (ret < 0) {
clear_bit(HSC_CH_READ, &channel->flags);
hsi_flush(channel->cl);
return -EINTR;
}
msg = hsc_get_first_msg(channel, &channel->rx_msgs_queue);
if (msg) {
if (msg->status != HSI_STATUS_ERROR) {
ret = copy_to_user((void __user *)buf,
sg_virt(msg->sgt.sgl), hsc_msg_len_get(msg));
if (ret)
ret = -EFAULT;
else
ret = hsc_msg_len_get(msg);
} else {
ret = -EIO;
}
hsc_add_tail(channel, msg, &channel->free_msgs_list);
}
out:
clear_bit(HSC_CH_READ, &channel->flags);
return ret;
}