aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-01-18 08:45:05 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:41 -0500
commit38edf58d73c28b082ec808aecdeb0ef2b92af049 (patch)
treea0235a87189cc48efc4fb61a1a2d70ce386891e1
parent73954488b1cc74cf46d6b94b8d3175f45496bd32 (diff)
virtio: console: don't assume a single console port.
Keep a list of all ports being used as a console, and provide a lock and a lookup function. The hvc callbacks only give us a vterm number, so we need to map this. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--drivers/char/virtio_console.c74
1 files changed, 65 insertions, 9 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index e52ee1151f5f..6bbf707f9e33 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -17,10 +17,28 @@
17 */ 17 */
18#include <linux/err.h> 18#include <linux/err.h>
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/list.h>
21#include <linux/spinlock.h>
20#include <linux/virtio.h> 22#include <linux/virtio.h>
21#include <linux/virtio_console.h> 23#include <linux/virtio_console.h>
22#include "hvc_console.h" 24#include "hvc_console.h"
23 25
26/*
27 * This is a global struct for storing common data for all the devices
28 * this driver handles.
29 *
30 * Mainly, it has a linked list for all the consoles in one place so
31 * that callbacks from hvc for get_chars(), put_chars() work properly
32 * across multiple devices and multiple ports per device.
33 */
34struct ports_driver_data {
35 /* All the console devices handled by this driver */
36 struct list_head consoles;
37};
38static struct ports_driver_data pdrvdata;
39
40DEFINE_SPINLOCK(pdrvdata_lock);
41
24struct port_buffer { 42struct port_buffer {
25 char *buf; 43 char *buf;
26 44
@@ -40,8 +58,15 @@ struct port {
40 /* The current buffer from which data has to be fed to readers */ 58 /* The current buffer from which data has to be fed to readers */
41 struct port_buffer *inbuf; 59 struct port_buffer *inbuf;
42 60
61 /* For console ports, hvc != NULL and these are valid. */
43 /* The hvc device */ 62 /* The hvc device */
44 struct hvc_struct *hvc; 63 struct hvc_struct *hvc;
64
65 /* We'll place all consoles in a list in the pdrvdata struct */
66 struct list_head list;
67
68 /* Our vterm number. */
69 u32 vtermno;
45}; 70};
46 71
47/* We have one port ready to go immediately, for a console. */ 72/* We have one port ready to go immediately, for a console. */
@@ -50,6 +75,22 @@ static struct port console;
50/* This is the very early arch-specified put chars function. */ 75/* This is the very early arch-specified put chars function. */
51static int (*early_put_chars)(u32, const char *, int); 76static int (*early_put_chars)(u32, const char *, int);
52 77
78static struct port *find_port_by_vtermno(u32 vtermno)
79{
80 struct port *port;
81 unsigned long flags;
82
83 spin_lock_irqsave(&pdrvdata_lock, flags);
84 list_for_each_entry(port, &pdrvdata.consoles, list) {
85 if (port->vtermno == vtermno)
86 goto out;
87 }
88 port = NULL;
89out:
90 spin_unlock_irqrestore(&pdrvdata_lock, flags);
91 return port;
92}
93
53static void free_buf(struct port_buffer *buf) 94static void free_buf(struct port_buffer *buf)
54{ 95{
55 kfree(buf->buf); 96 kfree(buf->buf);
@@ -120,14 +161,16 @@ static void add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
120static int put_chars(u32 vtermno, const char *buf, int count) 161static int put_chars(u32 vtermno, const char *buf, int count)
121{ 162{
122 struct scatterlist sg[1]; 163 struct scatterlist sg[1];
123 unsigned int len;
124 struct port *port; 164 struct port *port;
165 unsigned int len;
166
167 port = find_port_by_vtermno(vtermno);
168 if (!port)
169 return 0;
125 170
126 if (unlikely(early_put_chars)) 171 if (unlikely(early_put_chars))
127 return early_put_chars(vtermno, buf, count); 172 return early_put_chars(vtermno, buf, count);
128 173
129 port = &console;
130
131 /* This is a convenient routine to initialize a single-elem sg list */ 174 /* This is a convenient routine to initialize a single-elem sg list */
132 sg_init_one(sg, buf, count); 175 sg_init_one(sg, buf, count);
133 176
@@ -155,7 +198,10 @@ static int get_chars(u32 vtermno, char *buf, int count)
155{ 198{
156 struct port *port; 199 struct port *port;
157 200
158 port = &console; 201
202 port = find_port_by_vtermno(vtermno);
203 if (!port)
204 return 0;
159 205
160 /* If we don't have an input queue yet, we can't get input. */ 206 /* If we don't have an input queue yet, we can't get input. */
161 BUG_ON(!port->in_vq); 207 BUG_ON(!port->in_vq);
@@ -201,14 +247,17 @@ static void virtcons_apply_config(struct virtio_device *dev)
201 } 247 }
202} 248}
203 249
204/* 250/* We set the configuration at this point, since we now have a tty */
205 * we support only one console, the hvc struct is a global var We set
206 * the configuration at this point, since we now have a tty
207 */
208static int notifier_add_vio(struct hvc_struct *hp, int data) 251static int notifier_add_vio(struct hvc_struct *hp, int data)
209{ 252{
253 struct port *port;
254
255 port = find_port_by_vtermno(hp->vtermno);
256 if (!port)
257 return -EINVAL;
258
210 hp->irq_requested = 1; 259 hp->irq_requested = 1;
211 virtcons_apply_config(console.vdev); 260 virtcons_apply_config(port->vdev);
212 261
213 return 0; 262 return 0;
214} 263}
@@ -313,6 +362,11 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
313 goto free_vqs; 362 goto free_vqs;
314 } 363 }
315 364
365 /* Add to vtermno list. */
366 spin_lock_irq(&pdrvdata_lock);
367 list_add(&port->list, &pdrvdata.consoles);
368 spin_unlock_irq(&pdrvdata_lock);
369
316 /* Register the input buffer the first time. */ 370 /* Register the input buffer the first time. */
317 add_inbuf(port->in_vq, port->inbuf); 371 add_inbuf(port->in_vq, port->inbuf);
318 372
@@ -349,6 +403,8 @@ static struct virtio_driver virtio_console = {
349 403
350static int __init init(void) 404static int __init init(void)
351{ 405{
406 INIT_LIST_HEAD(&pdrvdata.consoles);
407
352 return register_virtio_driver(&virtio_console); 408 return register_virtio_driver(&virtio_console);
353} 409}
354module_init(init); 410module_init(init);