diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2010-01-18 08:45:00 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-02-23 22:52:34 -0500 |
commit | 21206ede8826fd9d2eb72e05b429f3ccb1bdaff5 (patch) | |
tree | fadcaacdd854522fc2b0f95e9191baca83185cfd /drivers/char | |
parent | f550804ab92e37a08d2622522a0f11252a2158ea (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.c | 107 |
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 | ||
24 | static struct virtqueue *in_vq, *out_vq; | 24 | struct port { |
25 | static 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. */ |
28 | static unsigned int in_len; | 28 | char *inbuf; |
29 | static 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. */ |
32 | static struct hvc_struct *hvc; | 36 | static 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. */ |
35 | static int (*early_put_chars)(u32, const char *, int); | 39 | static 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 | */ |
76 | static void add_inbuf(void) | 79 | static 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 | */ |
95 | static int get_chars(u32 vtermno, char *buf, int count) | 98 | static 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) | |||
146 | static int notifier_add_vio(struct hvc_struct *hp, int data) | 152 | static 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 | ||
159 | static void hvc_handle_input(struct virtqueue *vq) | 165 | static 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 | */ |
200 | static int __devinit virtcons_probe(struct virtio_device *dev) | 206 | static 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) | |||
254 | free_vqs: | 263 | free_vqs: |
255 | vdev->config->del_vqs(vdev); | 264 | vdev->config->del_vqs(vdev); |
256 | free: | 265 | free: |
257 | kfree(inbuf); | 266 | kfree(port->inbuf); |
258 | fail: | 267 | fail: |
259 | return err; | 268 | return err; |
260 | } | 269 | } |