diff options
-rw-r--r-- | drivers/char/Kconfig | 8 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 81 |
2 files changed, 82 insertions, 7 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index e023682be2c4..3141dd3b6e53 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -666,6 +666,14 @@ config VIRTIO_CONSOLE | |||
666 | help | 666 | help |
667 | Virtio console for use with lguest and other hypervisors. | 667 | Virtio console for use with lguest and other hypervisors. |
668 | 668 | ||
669 | Also serves as a general-purpose serial device for data | ||
670 | transfer between the guest and host. Character devices at | ||
671 | /dev/vportNpn will be created when corresponding ports are | ||
672 | found, where N is the device number and n is the port number | ||
673 | within that device. If specified by the host, a sysfs | ||
674 | attribute called 'name' will be populated with a name for | ||
675 | the port which can be used by udev scripts to create a | ||
676 | symlink to the device. | ||
669 | 677 | ||
670 | config HVCS | 678 | config HVCS |
671 | tristate "IBM Hypervisor Virtual Console Server support" | 679 | tristate "IBM Hypervisor Virtual Console Server support" |
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8e447e1e12bc..64ef476d6557 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -16,6 +16,8 @@ | |||
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | #include <linux/cdev.h> | ||
20 | #include <linux/device.h> | ||
19 | #include <linux/err.h> | 21 | #include <linux/err.h> |
20 | #include <linux/init.h> | 22 | #include <linux/init.h> |
21 | #include <linux/list.h> | 23 | #include <linux/list.h> |
@@ -34,6 +36,12 @@ | |||
34 | * across multiple devices and multiple ports per device. | 36 | * across multiple devices and multiple ports per device. |
35 | */ | 37 | */ |
36 | struct ports_driver_data { | 38 | struct ports_driver_data { |
39 | /* Used for registering chardevs */ | ||
40 | struct class *class; | ||
41 | |||
42 | /* Number of devices this driver is handling */ | ||
43 | unsigned int index; | ||
44 | |||
37 | /* | 45 | /* |
38 | * This is used to keep track of the number of hvc consoles | 46 | * This is used to keep track of the number of hvc consoles |
39 | * spawned by this driver. This number is given as the first | 47 | * spawned by this driver. This number is given as the first |
@@ -116,6 +124,12 @@ struct ports_device { | |||
116 | 124 | ||
117 | /* Array of per-port IO virtqueues */ | 125 | /* Array of per-port IO virtqueues */ |
118 | struct virtqueue **in_vqs, **out_vqs; | 126 | struct virtqueue **in_vqs, **out_vqs; |
127 | |||
128 | /* Used for numbering devices for sysfs and debugfs */ | ||
129 | unsigned int drv_index; | ||
130 | |||
131 | /* Major number for this device. Ports will be created as minors. */ | ||
132 | int chr_major; | ||
119 | }; | 133 | }; |
120 | 134 | ||
121 | /* This struct holds the per-port data */ | 135 | /* This struct holds the per-port data */ |
@@ -145,6 +159,10 @@ struct port { | |||
145 | */ | 159 | */ |
146 | struct console cons; | 160 | struct console cons; |
147 | 161 | ||
162 | /* Each port associates with a separate char device */ | ||
163 | struct cdev cdev; | ||
164 | struct device *dev; | ||
165 | |||
148 | /* The 'id' to identify the port with the Host */ | 166 | /* The 'id' to identify the port with the Host */ |
149 | u32 id; | 167 | u32 id; |
150 | }; | 168 | }; |
@@ -391,7 +409,7 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, | |||
391 | port->inbuf = NULL; | 409 | port->inbuf = NULL; |
392 | 410 | ||
393 | if (add_inbuf(port->in_vq, buf) < 0) | 411 | if (add_inbuf(port->in_vq, buf) < 0) |
394 | dev_warn(&port->portdev->vdev->dev, "failed add_buf\n"); | 412 | dev_warn(port->dev, "failed add_buf\n"); |
395 | 413 | ||
396 | spin_unlock_irqrestore(&port->inbuf_lock, flags); | 414 | spin_unlock_irqrestore(&port->inbuf_lock, flags); |
397 | } | 415 | } |
@@ -664,6 +682,7 @@ static int add_port(struct ports_device *portdev, u32 id) | |||
664 | { | 682 | { |
665 | struct port *port; | 683 | struct port *port; |
666 | struct port_buffer *inbuf; | 684 | struct port_buffer *inbuf; |
685 | dev_t devt; | ||
667 | int err; | 686 | int err; |
668 | 687 | ||
669 | port = kmalloc(sizeof(*port), GFP_KERNEL); | 688 | port = kmalloc(sizeof(*port), GFP_KERNEL); |
@@ -681,12 +700,32 @@ static int add_port(struct ports_device *portdev, u32 id) | |||
681 | port->in_vq = portdev->in_vqs[port->id]; | 700 | port->in_vq = portdev->in_vqs[port->id]; |
682 | port->out_vq = portdev->out_vqs[port->id]; | 701 | port->out_vq = portdev->out_vqs[port->id]; |
683 | 702 | ||
703 | cdev_init(&port->cdev, NULL); | ||
704 | |||
705 | devt = MKDEV(portdev->chr_major, id); | ||
706 | err = cdev_add(&port->cdev, devt, 1); | ||
707 | if (err < 0) { | ||
708 | dev_err(&port->portdev->vdev->dev, | ||
709 | "Error %d adding cdev for port %u\n", err, id); | ||
710 | goto free_port; | ||
711 | } | ||
712 | port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, | ||
713 | devt, port, "vport%up%u", | ||
714 | port->portdev->drv_index, id); | ||
715 | if (IS_ERR(port->dev)) { | ||
716 | err = PTR_ERR(port->dev); | ||
717 | dev_err(&port->portdev->vdev->dev, | ||
718 | "Error %d creating device for port %u\n", | ||
719 | err, id); | ||
720 | goto free_cdev; | ||
721 | } | ||
722 | |||
684 | spin_lock_init(&port->inbuf_lock); | 723 | spin_lock_init(&port->inbuf_lock); |
685 | 724 | ||
686 | inbuf = alloc_buf(PAGE_SIZE); | 725 | inbuf = alloc_buf(PAGE_SIZE); |
687 | if (!inbuf) { | 726 | if (!inbuf) { |
688 | err = -ENOMEM; | 727 | err = -ENOMEM; |
689 | goto free_port; | 728 | goto free_device; |
690 | } | 729 | } |
691 | 730 | ||
692 | /* Register the input buffer the first time. */ | 731 | /* Register the input buffer the first time. */ |
@@ -716,6 +755,10 @@ static int add_port(struct ports_device *portdev, u32 id) | |||
716 | 755 | ||
717 | free_inbuf: | 756 | free_inbuf: |
718 | free_buf(inbuf); | 757 | free_buf(inbuf); |
758 | free_device: | ||
759 | device_destroy(pdrvdata.class, port->dev->devt); | ||
760 | free_cdev: | ||
761 | cdev_del(&port->cdev); | ||
719 | free_port: | 762 | free_port: |
720 | kfree(port); | 763 | kfree(port); |
721 | fail: | 764 | fail: |
@@ -828,6 +871,10 @@ fail: | |||
828 | return err; | 871 | return err; |
829 | } | 872 | } |
830 | 873 | ||
874 | static const struct file_operations portdev_fops = { | ||
875 | .owner = THIS_MODULE, | ||
876 | }; | ||
877 | |||
831 | /* | 878 | /* |
832 | * Once we're further in boot, we get probed like any other virtio | 879 | * Once we're further in boot, we get probed like any other virtio |
833 | * device. | 880 | * device. |
@@ -853,6 +900,20 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) | |||
853 | portdev->vdev = vdev; | 900 | portdev->vdev = vdev; |
854 | vdev->priv = portdev; | 901 | vdev->priv = portdev; |
855 | 902 | ||
903 | spin_lock_irq(&pdrvdata_lock); | ||
904 | portdev->drv_index = pdrvdata.index++; | ||
905 | spin_unlock_irq(&pdrvdata_lock); | ||
906 | |||
907 | portdev->chr_major = register_chrdev(0, "virtio-portsdev", | ||
908 | &portdev_fops); | ||
909 | if (portdev->chr_major < 0) { | ||
910 | dev_err(&vdev->dev, | ||
911 | "Error %d registering chrdev for device %u\n", | ||
912 | portdev->chr_major, portdev->drv_index); | ||
913 | err = portdev->chr_major; | ||
914 | goto free; | ||
915 | } | ||
916 | |||
856 | multiport = false; | 917 | multiport = false; |
857 | portdev->config.nr_ports = 1; | 918 | portdev->config.nr_ports = 1; |
858 | portdev->config.max_nr_ports = 1; | 919 | portdev->config.max_nr_ports = 1; |
@@ -885,7 +946,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) | |||
885 | err = init_vqs(portdev); | 946 | err = init_vqs(portdev); |
886 | if (err < 0) { | 947 | if (err < 0) { |
887 | dev_err(&vdev->dev, "Error %d initializing vqs\n", err); | 948 | dev_err(&vdev->dev, "Error %d initializing vqs\n", err); |
888 | goto free; | 949 | goto free_chrdev; |
889 | } | 950 | } |
890 | 951 | ||
891 | spin_lock_init(&portdev->ports_lock); | 952 | spin_lock_init(&portdev->ports_lock); |
@@ -905,10 +966,8 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) | |||
905 | early_put_chars = NULL; | 966 | early_put_chars = NULL; |
906 | return 0; | 967 | return 0; |
907 | 968 | ||
908 | free_vqs: | 969 | free_chrdev: |
909 | vdev->config->del_vqs(vdev); | 970 | unregister_chrdev(portdev->chr_major, "virtio-portsdev"); |
910 | kfree(portdev->in_vqs); | ||
911 | kfree(portdev->out_vqs); | ||
912 | free: | 971 | free: |
913 | kfree(portdev); | 972 | kfree(portdev); |
914 | fail: | 973 | fail: |
@@ -937,6 +996,14 @@ static struct virtio_driver virtio_console = { | |||
937 | 996 | ||
938 | static int __init init(void) | 997 | static int __init init(void) |
939 | { | 998 | { |
999 | int err; | ||
1000 | |||
1001 | pdrvdata.class = class_create(THIS_MODULE, "virtio-ports"); | ||
1002 | if (IS_ERR(pdrvdata.class)) { | ||
1003 | err = PTR_ERR(pdrvdata.class); | ||
1004 | pr_err("Error %d creating virtio-ports class\n", err); | ||
1005 | return err; | ||
1006 | } | ||
940 | INIT_LIST_HEAD(&pdrvdata.consoles); | 1007 | INIT_LIST_HEAD(&pdrvdata.consoles); |
941 | 1008 | ||
942 | return register_virtio_driver(&virtio_console); | 1009 | return register_virtio_driver(&virtio_console); |