in ps3-vuart.c [598:654]
int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf,
unsigned int bytes)
{
int result;
struct ps3_vuart_port_priv *priv = to_port_priv(dev);
unsigned long flags;
struct list_buffer *lb, *n;
unsigned long bytes_read;
dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
bytes, bytes);
spin_lock_irqsave(&priv->rx_list.lock, flags);
/* Queue rx bytes here for polled reads. */
while (priv->rx_list.bytes_held < bytes) {
u64 tmp;
result = ps3_vuart_queue_rx_bytes(dev, &tmp);
if (result || !tmp) {
dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
__func__, __LINE__,
bytes - priv->rx_list.bytes_held);
spin_unlock_irqrestore(&priv->rx_list.lock, flags);
return -EAGAIN;
}
}
list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) {
bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
memcpy(buf, lb->head, bytes_read);
buf += bytes_read;
bytes -= bytes_read;
priv->rx_list.bytes_held -= bytes_read;
if (bytes_read < lb->tail - lb->head) {
lb->head += bytes_read;
dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh "
"bytes\n", __func__, __LINE__, lb->dbg_number,
bytes_read);
spin_unlock_irqrestore(&priv->rx_list.lock, flags);
return 0;
}
dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh "
"bytes\n", __func__, __LINE__, lb->dbg_number,
bytes_read);
list_del(&lb->link);
kfree(lb);
}
spin_unlock_irqrestore(&priv->rx_list.lock, flags);
return 0;
}