aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/virtio_console.c
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2009-12-21 11:19:30 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:54 -0500
commit2030fa496d74b49220308eaccf656e2338019cfd (patch)
treecf8d937551d8bfefadbbc5389caaf587f2d0b13b /drivers/char/virtio_console.c
parentfb08bd274df61967f40d49c4625fe6ed75a69ab5 (diff)
virtio: console: Add file operations to ports for open/read/write/poll
Allow guest userspace applications to open, read from, write to, poll the ports via the char dev interface. When a port gets opened, a notification is sent to the host via a control message indicating a connection has been established. Similarly, on closing of the port, a notification is sent indicating disconnection. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char/virtio_console.c')
-rw-r--r--drivers/char/virtio_console.c164
1 files changed, 163 insertions, 1 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 64ef476d6557..ece1546fbb20 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -19,11 +19,15 @@
19#include <linux/cdev.h> 19#include <linux/cdev.h>
20#include <linux/device.h> 20#include <linux/device.h>
21#include <linux/err.h> 21#include <linux/err.h>
22#include <linux/fs.h>
22#include <linux/init.h> 23#include <linux/init.h>
23#include <linux/list.h> 24#include <linux/list.h>
25#include <linux/poll.h>
26#include <linux/sched.h>
24#include <linux/spinlock.h> 27#include <linux/spinlock.h>
25#include <linux/virtio.h> 28#include <linux/virtio.h>
26#include <linux/virtio_console.h> 29#include <linux/virtio_console.h>
30#include <linux/wait.h>
27#include <linux/workqueue.h> 31#include <linux/workqueue.h>
28#include "hvc_console.h" 32#include "hvc_console.h"
29 33
@@ -163,8 +167,14 @@ struct port {
163 struct cdev cdev; 167 struct cdev cdev;
164 struct device *dev; 168 struct device *dev;
165 169
170 /* A waitqueue for poll() or blocking read operations */
171 wait_queue_head_t waitqueue;
172
166 /* The 'id' to identify the port with the Host */ 173 /* The 'id' to identify the port with the Host */
167 u32 id; 174 u32 id;
175
176 /* Is the host device open */
177 bool host_connected;
168}; 178};
169 179
170/* This is the very early arch-specified put chars function. */ 180/* This is the very early arch-specified put chars function. */
@@ -417,6 +427,146 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
417 return out_count; 427 return out_count;
418} 428}
419 429
430/* The condition that must be true for polling to end */
431static bool wait_is_over(struct port *port)
432{
433 return port_has_data(port) || !port->host_connected;
434}
435
436static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
437 size_t count, loff_t *offp)
438{
439 struct port *port;
440 ssize_t ret;
441
442 port = filp->private_data;
443
444 if (!port_has_data(port)) {
445 /*
446 * If nothing's connected on the host just return 0 in
447 * case of list_empty; this tells the userspace app
448 * that there's no connection
449 */
450 if (!port->host_connected)
451 return 0;
452 if (filp->f_flags & O_NONBLOCK)
453 return -EAGAIN;
454
455 ret = wait_event_interruptible(port->waitqueue,
456 wait_is_over(port));
457 if (ret < 0)
458 return ret;
459 }
460 /*
461 * We could've received a disconnection message while we were
462 * waiting for more data.
463 *
464 * This check is not clubbed in the if() statement above as we
465 * might receive some data as well as the host could get
466 * disconnected after we got woken up from our wait. So we
467 * really want to give off whatever data we have and only then
468 * check for host_connected.
469 */
470 if (!port_has_data(port) && !port->host_connected)
471 return 0;
472
473 return fill_readbuf(port, ubuf, count, true);
474}
475
476static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
477 size_t count, loff_t *offp)
478{
479 struct port *port;
480 char *buf;
481 ssize_t ret;
482
483 port = filp->private_data;
484
485 count = min((size_t)(32 * 1024), count);
486
487 buf = kmalloc(count, GFP_KERNEL);
488 if (!buf)
489 return -ENOMEM;
490
491 ret = copy_from_user(buf, ubuf, count);
492 if (ret) {
493 ret = -EFAULT;
494 goto free_buf;
495 }
496
497 ret = send_buf(port, buf, count);
498free_buf:
499 kfree(buf);
500 return ret;
501}
502
503static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
504{
505 struct port *port;
506 unsigned int ret;
507
508 port = filp->private_data;
509 poll_wait(filp, &port->waitqueue, wait);
510
511 ret = 0;
512 if (port->inbuf)
513 ret |= POLLIN | POLLRDNORM;
514 if (port->host_connected)
515 ret |= POLLOUT;
516 if (!port->host_connected)
517 ret |= POLLHUP;
518
519 return ret;
520}
521
522static int port_fops_release(struct inode *inode, struct file *filp)
523{
524 struct port *port;
525
526 port = filp->private_data;
527
528 /* Notify host of port being closed */
529 send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
530
531 return 0;
532}
533
534static int port_fops_open(struct inode *inode, struct file *filp)
535{
536 struct cdev *cdev = inode->i_cdev;
537 struct port *port;
538
539 port = container_of(cdev, struct port, cdev);
540 filp->private_data = port;
541
542 /*
543 * Don't allow opening of console port devices -- that's done
544 * via /dev/hvc
545 */
546 if (is_console_port(port))
547 return -ENXIO;
548
549 /* Notify host of port being opened */
550 send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
551
552 return 0;
553}
554
555/*
556 * The file operations that we support: programs in the guest can open
557 * a console device, read from it, write to it, poll for data and
558 * close it. The devices are at
559 * /dev/vport<device number>p<port number>
560 */
561static const struct file_operations port_fops = {
562 .owner = THIS_MODULE,
563 .open = port_fops_open,
564 .read = port_fops_read,
565 .write = port_fops_write,
566 .poll = port_fops_poll,
567 .release = port_fops_release,
568};
569
420/* 570/*
421 * The put_chars() callback is pretty straightforward. 571 * The put_chars() callback is pretty straightforward.
422 * 572 *
@@ -560,6 +710,9 @@ int init_port_console(struct port *port)
560 list_add_tail(&port->cons.list, &pdrvdata.consoles); 710 list_add_tail(&port->cons.list, &pdrvdata.consoles);
561 spin_unlock_irq(&pdrvdata_lock); 711 spin_unlock_irq(&pdrvdata_lock);
562 712
713 /* Notify host of port being opened */
714 send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
715
563 return 0; 716 return 0;
564} 717}
565 718
@@ -599,6 +752,10 @@ static void handle_control_message(struct ports_device *portdev,
599 port->cons.hvc->irq_requested = 1; 752 port->cons.hvc->irq_requested = 1;
600 resize_console(port); 753 resize_console(port);
601 break; 754 break;
755 case VIRTIO_CONSOLE_PORT_OPEN:
756 port->host_connected = cpkt->value;
757 wake_up_interruptible(&port->waitqueue);
758 break;
602 } 759 }
603} 760}
604 761
@@ -645,6 +802,8 @@ static void in_intr(struct virtqueue *vq)
645 802
646 spin_unlock_irqrestore(&port->inbuf_lock, flags); 803 spin_unlock_irqrestore(&port->inbuf_lock, flags);
647 804
805 wake_up_interruptible(&port->waitqueue);
806
648 if (is_console_port(port) && hvc_poll(port->cons.hvc)) 807 if (is_console_port(port) && hvc_poll(port->cons.hvc))
649 hvc_kick(); 808 hvc_kick();
650} 809}
@@ -697,10 +856,12 @@ static int add_port(struct ports_device *portdev, u32 id)
697 port->inbuf = NULL; 856 port->inbuf = NULL;
698 port->cons.hvc = NULL; 857 port->cons.hvc = NULL;
699 858
859 port->host_connected = false;
860
700 port->in_vq = portdev->in_vqs[port->id]; 861 port->in_vq = portdev->in_vqs[port->id];
701 port->out_vq = portdev->out_vqs[port->id]; 862 port->out_vq = portdev->out_vqs[port->id];
702 863
703 cdev_init(&port->cdev, NULL); 864 cdev_init(&port->cdev, &port_fops);
704 865
705 devt = MKDEV(portdev->chr_major, id); 866 devt = MKDEV(portdev->chr_major, id);
706 err = cdev_add(&port->cdev, devt, 1); 867 err = cdev_add(&port->cdev, devt, 1);
@@ -721,6 +882,7 @@ static int add_port(struct ports_device *portdev, u32 id)
721 } 882 }
722 883
723 spin_lock_init(&port->inbuf_lock); 884 spin_lock_init(&port->inbuf_lock);
885 init_waitqueue_head(&port->waitqueue);
724 886
725 inbuf = alloc_buf(PAGE_SIZE); 887 inbuf = alloc_buf(PAGE_SIZE);
726 if (!inbuf) { 888 if (!inbuf) {