aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2010-01-18 08:45:00 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:34 -0500
commit21206ede8826fd9d2eb72e05b429f3ccb1bdaff5 (patch)
treefadcaacdd854522fc2b0f95e9191baca83185cfd /drivers/char
parentf550804ab92e37a08d2622522a0f11252a2158ea (diff)
virtio: console: port encapsulation
We are heading towards a multiple-"port" system, so as part of weaning off globals we encapsulate the information into 'struct port'. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/virtio_console.c107
1 files changed, 58 insertions, 49 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index bfc0abf825ed..9ea9223c5c5c 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -21,15 +21,19 @@
21#include <linux/virtio_console.h> 21#include <linux/virtio_console.h>
22#include "hvc_console.h" 22#include "hvc_console.h"
23 23
24static struct virtqueue *in_vq, *out_vq; 24struct port {
25static struct virtio_device *vdev; 25 struct virtqueue *in_vq, *out_vq;
26 26 struct virtio_device *vdev;
27/* This is our input buffer, and how much data is left in it. */ 27 /* This is our input buffer, and how much data is left in it. */
28static unsigned int in_len; 28 char *inbuf;
29static char *in, *inbuf; 29 unsigned int used_len, offset;
30
31 /* The hvc device */
32 struct hvc_struct *hvc;
33};
30 34
31/* The hvc device */ 35/* We have one port ready to go immediately, for a console. */
32static struct hvc_struct *hvc; 36static struct port console;
33 37
34/* This is the very early arch-specified put chars function. */ 38/* This is the very early arch-specified put chars function. */
35static int (*early_put_chars)(u32, const char *, int); 39static int (*early_put_chars)(u32, const char *, int);
@@ -46,22 +50,21 @@ static int put_chars(u32 vtermno, const char *buf, int count)
46{ 50{
47 struct scatterlist sg[1]; 51 struct scatterlist sg[1];
48 unsigned int len; 52 unsigned int len;
53 struct port *port;
49 54
50 if (unlikely(early_put_chars)) 55 if (unlikely(early_put_chars))
51 return early_put_chars(vtermno, buf, count); 56 return early_put_chars(vtermno, buf, count);
52 57
58 port = &console;
59
53 /* This is a convenient routine to initialize a single-elem sg list */ 60 /* This is a convenient routine to initialize a single-elem sg list */
54 sg_init_one(sg, buf, count); 61 sg_init_one(sg, buf, count);
55 62
56 /* 63 /* This shouldn't fail: if it does, we lose chars. */
57 * add_buf wants a token to identify this buffer: we hand it 64 if (port->out_vq->vq_ops->add_buf(port->out_vq, sg, 1, 0, port) >= 0) {
58 * any non-NULL pointer, since there's only ever one buffer.
59 */
60 if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) >= 0) {
61 /* Tell Host to go! */ 65 /* Tell Host to go! */
62 out_vq->vq_ops->kick(out_vq); 66 port->out_vq->vq_ops->kick(port->out_vq);
63 /* Chill out until it's done with the buffer. */ 67 while (!port->out_vq->vq_ops->get_buf(port->out_vq, &len))
64 while (!out_vq->vq_ops->get_buf(out_vq, &len))
65 cpu_relax(); 68 cpu_relax();
66 } 69 }
67 70
@@ -73,15 +76,15 @@ static int put_chars(u32 vtermno, const char *buf, int count)
73 * Create a scatter-gather list representing our input buffer and put 76 * Create a scatter-gather list representing our input buffer and put
74 * it in the queue. 77 * it in the queue.
75 */ 78 */
76static void add_inbuf(void) 79static void add_inbuf(struct port *port)
77{ 80{
78 struct scatterlist sg[1]; 81 struct scatterlist sg[1];
79 sg_init_one(sg, inbuf, PAGE_SIZE); 82 sg_init_one(sg, port->inbuf, PAGE_SIZE);
80 83
81 /* We should always be able to add one buffer to an empty queue. */ 84 /* Should always be able to add one buffer to an empty queue. */
82 if (in_vq->vq_ops->add_buf(in_vq, sg, 0, 1, inbuf) < 0) 85 if (port->in_vq->vq_ops->add_buf(port->in_vq, sg, 0, 1, port) < 0)
83 BUG(); 86 BUG();
84 in_vq->vq_ops->kick(in_vq); 87 port->in_vq->vq_ops->kick(port->in_vq);
85} 88}
86 89
87/* 90/*
@@ -94,28 +97,31 @@ static void add_inbuf(void)
94 */ 97 */
95static int get_chars(u32 vtermno, char *buf, int count) 98static int get_chars(u32 vtermno, char *buf, int count)
96{ 99{
100 struct port *port;
101
102 port = &console;
103
97 /* If we don't have an input queue yet, we can't get input. */ 104 /* If we don't have an input queue yet, we can't get input. */
98 BUG_ON(!in_vq); 105 BUG_ON(!port->in_vq);
99 106
100 /* No buffer? Try to get one. */ 107 /* No more in buffer? See if they've (re)used it. */
101 if (!in_len) { 108 if (port->offset == port->used_len) {
102 in = in_vq->vq_ops->get_buf(in_vq, &in_len); 109 if (!port->in_vq->vq_ops->get_buf(port->in_vq, &port->used_len))
103 if (!in)
104 return 0; 110 return 0;
111 port->offset = 0;
105 } 112 }
106 113
107 /* You want more than we have to give? Well, try wanting less! */ 114 /* You want more than we have to give? Well, try wanting less! */
108 if (in_len < count) 115 if (port->offset + count > port->used_len)
109 count = in_len; 116 count = port->used_len - port->offset;
110 117
111 /* Copy across to their buffer and increment offset. */ 118 /* Copy across to their buffer and increment offset. */
112 memcpy(buf, in, count); 119 memcpy(buf, port->inbuf + port->offset, count);
113 in += count; 120 port->offset += count;
114 in_len -= count;
115 121
116 /* Finished? Re-register buffer so Host will use it again. */ 122 /* Finished? Re-register buffer so Host will use it again. */
117 if (in_len == 0) 123 if (port->offset == port->used_len)
118 add_inbuf(); 124 add_inbuf(port);
119 125
120 return count; 126 return count;
121} 127}
@@ -135,7 +141,7 @@ static void virtcons_apply_config(struct virtio_device *dev)
135 dev->config->get(dev, 141 dev->config->get(dev,
136 offsetof(struct virtio_console_config, rows), 142 offsetof(struct virtio_console_config, rows),
137 &ws.ws_row, sizeof(u16)); 143 &ws.ws_row, sizeof(u16));
138 hvc_resize(hvc, ws); 144 hvc_resize(console.hvc, ws);
139 } 145 }
140} 146}
141 147
@@ -146,7 +152,7 @@ static void virtcons_apply_config(struct virtio_device *dev)
146static int notifier_add_vio(struct hvc_struct *hp, int data) 152static int notifier_add_vio(struct hvc_struct *hp, int data)
147{ 153{
148 hp->irq_requested = 1; 154 hp->irq_requested = 1;
149 virtcons_apply_config(vdev); 155 virtcons_apply_config(console.vdev);
150 156
151 return 0; 157 return 0;
152} 158}
@@ -158,7 +164,7 @@ static void notifier_del_vio(struct hvc_struct *hp, int data)
158 164
159static void hvc_handle_input(struct virtqueue *vq) 165static void hvc_handle_input(struct virtqueue *vq)
160{ 166{
161 if (hvc_poll(hvc)) 167 if (hvc_poll(console.hvc))
162 hvc_kick(); 168 hvc_kick();
163} 169}
164 170
@@ -197,23 +203,26 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
197 * Finally we put our input buffer in the input queue, ready to 203 * Finally we put our input buffer in the input queue, ready to
198 * receive. 204 * receive.
199 */ 205 */
200static int __devinit virtcons_probe(struct virtio_device *dev) 206static int __devinit virtcons_probe(struct virtio_device *vdev)
201{ 207{
202 vq_callback_t *callbacks[] = { hvc_handle_input, NULL}; 208 vq_callback_t *callbacks[] = { hvc_handle_input, NULL};
203 const char *names[] = { "input", "output" }; 209 const char *names[] = { "input", "output" };
204 struct virtqueue *vqs[2]; 210 struct virtqueue *vqs[2];
211 struct port *port;
205 int err; 212 int err;
206 213
207 if (vdev) { 214 port = &console;
208 dev_warn(&vdev->dev, 215 if (port->vdev) {
216 dev_warn(&port->vdev->dev,
209 "Multiple virtio-console devices not supported yet\n"); 217 "Multiple virtio-console devices not supported yet\n");
210 return -EEXIST; 218 return -EEXIST;
211 } 219 }
212 vdev = dev; 220 port->vdev = vdev;
213 221
214 /* This is the scratch page we use to receive console input */ 222 /* This is the scratch page we use to receive console input */
215 inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); 223 port->used_len = 0;
216 if (!inbuf) { 224 port->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
225 if (!port->inbuf) {
217 err = -ENOMEM; 226 err = -ENOMEM;
218 goto fail; 227 goto fail;
219 } 228 }
@@ -223,8 +232,8 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
223 if (err) 232 if (err)
224 goto free; 233 goto free;
225 234
226 in_vq = vqs[0]; 235 port->in_vq = vqs[0];
227 out_vq = vqs[1]; 236 port->out_vq = vqs[1];
228 237
229 /* 238 /*
230 * The first argument of hvc_alloc() is the virtual console 239 * The first argument of hvc_alloc() is the virtual console
@@ -238,14 +247,14 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
238 * pointers. The final argument is the output buffer size: we 247 * pointers. The final argument is the output buffer size: we
239 * can do any size, so we put PAGE_SIZE here. 248 * can do any size, so we put PAGE_SIZE here.
240 */ 249 */
241 hvc = hvc_alloc(0, 0, &hv_ops, PAGE_SIZE); 250 port->hvc = hvc_alloc(0, 0, &hv_ops, PAGE_SIZE);
242 if (IS_ERR(hvc)) { 251 if (IS_ERR(port->hvc)) {
243 err = PTR_ERR(hvc); 252 err = PTR_ERR(port->hvc);
244 goto free_vqs; 253 goto free_vqs;
245 } 254 }
246 255
247 /* Register the input buffer the first time. */ 256 /* Register the input buffer the first time. */
248 add_inbuf(); 257 add_inbuf(port);
249 258
250 /* Start using the new console output. */ 259 /* Start using the new console output. */
251 early_put_chars = NULL; 260 early_put_chars = NULL;
@@ -254,7 +263,7 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
254free_vqs: 263free_vqs:
255 vdev->config->del_vqs(vdev); 264 vdev->config->del_vqs(vdev);
256free: 265free:
257 kfree(inbuf); 266 kfree(port->inbuf);
258fail: 267fail:
259 return err; 268 return err;
260} 269}