aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/virtio_console.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/virtio_console.c')
-rw-r--r--drivers/char/virtio_console.c81
1 files changed, 61 insertions, 20 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index f404ccfc9c20..196428c2287a 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -25,6 +25,7 @@
25#include <linux/list.h> 25#include <linux/list.h>
26#include <linux/poll.h> 26#include <linux/poll.h>
27#include <linux/sched.h> 27#include <linux/sched.h>
28#include <linux/slab.h>
28#include <linux/spinlock.h> 29#include <linux/spinlock.h>
29#include <linux/virtio.h> 30#include <linux/virtio.h>
30#include <linux/virtio_console.h> 31#include <linux/virtio_console.h>
@@ -32,6 +33,35 @@
32#include <linux/workqueue.h> 33#include <linux/workqueue.h>
33#include "hvc_console.h" 34#include "hvc_console.h"
34 35
36/* Moved here from .h file in order to disable MULTIPORT. */
37#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */
38
39struct virtio_console_multiport_conf {
40 struct virtio_console_config config;
41 /* max. number of ports this device can hold */
42 __u32 max_nr_ports;
43 /* number of ports added so far */
44 __u32 nr_ports;
45} __attribute__((packed));
46
47/*
48 * A message that's passed between the Host and the Guest for a
49 * particular port.
50 */
51struct virtio_console_control {
52 __u32 id; /* Port number */
53 __u16 event; /* The kind of control event (see below) */
54 __u16 value; /* Extra information for the key */
55};
56
57/* Some events for control messages */
58#define VIRTIO_CONSOLE_PORT_READY 0
59#define VIRTIO_CONSOLE_CONSOLE_PORT 1
60#define VIRTIO_CONSOLE_RESIZE 2
61#define VIRTIO_CONSOLE_PORT_OPEN 3
62#define VIRTIO_CONSOLE_PORT_NAME 4
63#define VIRTIO_CONSOLE_PORT_REMOVE 5
64
35/* 65/*
36 * This is a global struct for storing common data for all the devices 66 * This is a global struct for storing common data for all the devices
37 * this driver handles. 67 * this driver handles.
@@ -120,7 +150,7 @@ struct ports_device {
120 spinlock_t cvq_lock; 150 spinlock_t cvq_lock;
121 151
122 /* The current config space is stored here */ 152 /* The current config space is stored here */
123 struct virtio_console_config config; 153 struct virtio_console_multiport_conf config;
124 154
125 /* The virtio device we're associated with */ 155 /* The virtio device we're associated with */
126 struct virtio_device *vdev; 156 struct virtio_device *vdev;
@@ -415,20 +445,16 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
415 out_vq->vq_ops->kick(out_vq); 445 out_vq->vq_ops->kick(out_vq);
416 446
417 if (ret < 0) { 447 if (ret < 0) {
418 len = 0; 448 in_count = 0;
419 goto fail; 449 goto fail;
420 } 450 }
421 451
422 /* 452 /* Wait till the host acknowledges it pushed out the data we sent. */
423 * Wait till the host acknowledges it pushed out the data we
424 * sent. Also ensure we return to userspace the number of
425 * bytes that were successfully consumed by the host.
426 */
427 while (!out_vq->vq_ops->get_buf(out_vq, &len)) 453 while (!out_vq->vq_ops->get_buf(out_vq, &len))
428 cpu_relax(); 454 cpu_relax();
429fail: 455fail:
430 /* We're expected to return the amount of data we wrote */ 456 /* We're expected to return the amount of data we wrote */
431 return len; 457 return in_count;
432} 458}
433 459
434/* 460/*
@@ -645,13 +671,13 @@ static int put_chars(u32 vtermno, const char *buf, int count)
645{ 671{
646 struct port *port; 672 struct port *port;
647 673
674 if (unlikely(early_put_chars))
675 return early_put_chars(vtermno, buf, count);
676
648 port = find_port_by_vtermno(vtermno); 677 port = find_port_by_vtermno(vtermno);
649 if (!port) 678 if (!port)
650 return 0; 679 return 0;
651 680
652 if (unlikely(early_put_chars))
653 return early_put_chars(vtermno, buf, count);
654
655 return send_buf(port, (void *)buf, count); 681 return send_buf(port, (void *)buf, count);
656} 682}
657 683
@@ -681,6 +707,10 @@ static void resize_console(struct port *port)
681 struct virtio_device *vdev; 707 struct virtio_device *vdev;
682 struct winsize ws; 708 struct winsize ws;
683 709
710 /* The port could have been hot-unplugged */
711 if (!port)
712 return;
713
684 vdev = port->portdev->vdev; 714 vdev = port->portdev->vdev;
685 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) { 715 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) {
686 vdev->config->get(vdev, 716 vdev->config->get(vdev,
@@ -947,11 +977,18 @@ static void handle_control_message(struct ports_device *portdev,
947 */ 977 */
948 err = sysfs_create_group(&port->dev->kobj, 978 err = sysfs_create_group(&port->dev->kobj,
949 &port_attribute_group); 979 &port_attribute_group);
950 if (err) 980 if (err) {
951 dev_err(port->dev, 981 dev_err(port->dev,
952 "Error %d creating sysfs device attributes\n", 982 "Error %d creating sysfs device attributes\n",
953 err); 983 err);
954 984 } else {
985 /*
986 * Generate a udev event so that appropriate
987 * symlinks can be created based on udev
988 * rules.
989 */
990 kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
991 }
955 break; 992 break;
956 case VIRTIO_CONSOLE_PORT_REMOVE: 993 case VIRTIO_CONSOLE_PORT_REMOVE:
957 /* 994 /*
@@ -1206,7 +1243,7 @@ fail:
1206 */ 1243 */
1207static void config_work_handler(struct work_struct *work) 1244static void config_work_handler(struct work_struct *work)
1208{ 1245{
1209 struct virtio_console_config virtconconf; 1246 struct virtio_console_multiport_conf virtconconf;
1210 struct ports_device *portdev; 1247 struct ports_device *portdev;
1211 struct virtio_device *vdev; 1248 struct virtio_device *vdev;
1212 int err; 1249 int err;
@@ -1215,7 +1252,8 @@ static void config_work_handler(struct work_struct *work)
1215 1252
1216 vdev = portdev->vdev; 1253 vdev = portdev->vdev;
1217 vdev->config->get(vdev, 1254 vdev->config->get(vdev,
1218 offsetof(struct virtio_console_config, nr_ports), 1255 offsetof(struct virtio_console_multiport_conf,
1256 nr_ports),
1219 &virtconconf.nr_ports, 1257 &virtconconf.nr_ports,
1220 sizeof(virtconconf.nr_ports)); 1258 sizeof(virtconconf.nr_ports));
1221 1259
@@ -1407,16 +1445,19 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1407 multiport = false; 1445 multiport = false;
1408 portdev->config.nr_ports = 1; 1446 portdev->config.nr_ports = 1;
1409 portdev->config.max_nr_ports = 1; 1447 portdev->config.max_nr_ports = 1;
1448#if 0 /* Multiport is not quite ready yet --RR */
1410 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) { 1449 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
1411 multiport = true; 1450 multiport = true;
1412 vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT; 1451 vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
1413 1452
1414 vdev->config->get(vdev, offsetof(struct virtio_console_config, 1453 vdev->config->get(vdev,
1415 nr_ports), 1454 offsetof(struct virtio_console_multiport_conf,
1455 nr_ports),
1416 &portdev->config.nr_ports, 1456 &portdev->config.nr_ports,
1417 sizeof(portdev->config.nr_ports)); 1457 sizeof(portdev->config.nr_ports));
1418 vdev->config->get(vdev, offsetof(struct virtio_console_config, 1458 vdev->config->get(vdev,
1419 max_nr_ports), 1459 offsetof(struct virtio_console_multiport_conf,
1460 max_nr_ports),
1420 &portdev->config.max_nr_ports, 1461 &portdev->config.max_nr_ports,
1421 sizeof(portdev->config.max_nr_ports)); 1462 sizeof(portdev->config.max_nr_ports));
1422 if (portdev->config.nr_ports > portdev->config.max_nr_ports) { 1463 if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
@@ -1432,6 +1473,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1432 1473
1433 /* Let the Host know we support multiple ports.*/ 1474 /* Let the Host know we support multiple ports.*/
1434 vdev->config->finalize_features(vdev); 1475 vdev->config->finalize_features(vdev);
1476#endif
1435 1477
1436 err = init_vqs(portdev); 1478 err = init_vqs(portdev);
1437 if (err < 0) { 1479 if (err < 0) {
@@ -1514,7 +1556,6 @@ static struct virtio_device_id id_table[] = {
1514 1556
1515static unsigned int features[] = { 1557static unsigned int features[] = {
1516 VIRTIO_CONSOLE_F_SIZE, 1558 VIRTIO_CONSOLE_F_SIZE,
1517 VIRTIO_CONSOLE_F_MULTIPORT,
1518}; 1559};
1519 1560
1520static struct virtio_driver virtio_console = { 1561static struct virtio_driver virtio_console = {