aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/virtio_console.c
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-01-18 08:45:01 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:36 -0500
commitfdb9a054554e1e435e927c9a47a999f026abd408 (patch)
tree4ef632d26bf6068de7ab14f99547fd94e0c939b6 /drivers/char/virtio_console.c
parent21206ede8826fd9d2eb72e05b429f3ccb1bdaff5 (diff)
virtio: console: encapsulate buffer information in a struct
Collect port buffer, used_len, offset fields into a single structure. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char/virtio_console.c')
-rw-r--r--drivers/char/virtio_console.c70
1 files changed, 55 insertions, 15 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 9ea9223c5c5c..699fc98ec8d9 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -21,12 +21,24 @@
21#include <linux/virtio_console.h> 21#include <linux/virtio_console.h>
22#include "hvc_console.h" 22#include "hvc_console.h"
23 23
24struct port_buffer {
25 char *buf;
26
27 /* size of the buffer in *buf above */
28 size_t size;
29
30 /* used length of the buffer */
31 size_t len;
32 /* offset in the buf from which to consume data */
33 size_t offset;
34};
35
24struct port { 36struct port {
25 struct virtqueue *in_vq, *out_vq; 37 struct virtqueue *in_vq, *out_vq;
26 struct virtio_device *vdev; 38 struct virtio_device *vdev;
27 /* This is our input buffer, and how much data is left in it. */ 39
28 char *inbuf; 40 /* The current buffer from which data has to be fed to readers */
29 unsigned int used_len, offset; 41 struct port_buffer *inbuf;
30 42
31 /* The hvc device */ 43 /* The hvc device */
32 struct hvc_struct *hvc; 44 struct hvc_struct *hvc;
@@ -38,6 +50,33 @@ static struct port console;
38/* This is the very early arch-specified put chars function. */ 50/* This is the very early arch-specified put chars function. */
39static int (*early_put_chars)(u32, const char *, int); 51static int (*early_put_chars)(u32, const char *, int);
40 52
53static void free_buf(struct port_buffer *buf)
54{
55 kfree(buf->buf);
56 kfree(buf);
57}
58
59static struct port_buffer *alloc_buf(size_t buf_size)
60{
61 struct port_buffer *buf;
62
63 buf = kmalloc(sizeof(*buf), GFP_KERNEL);
64 if (!buf)
65 goto fail;
66 buf->buf = kzalloc(buf_size, GFP_KERNEL);
67 if (!buf->buf)
68 goto free_buf;
69 buf->len = 0;
70 buf->offset = 0;
71 buf->size = buf_size;
72 return buf;
73
74free_buf:
75 kfree(buf);
76fail:
77 return NULL;
78}
79
41/* 80/*
42 * The put_chars() callback is pretty straightforward. 81 * The put_chars() callback is pretty straightforward.
43 * 82 *
@@ -79,7 +118,7 @@ static int put_chars(u32 vtermno, const char *buf, int count)
79static void add_inbuf(struct port *port) 118static void add_inbuf(struct port *port)
80{ 119{
81 struct scatterlist sg[1]; 120 struct scatterlist sg[1];
82 sg_init_one(sg, port->inbuf, PAGE_SIZE); 121 sg_init_one(sg, port->inbuf->buf, PAGE_SIZE);
83 122
84 /* Should always be able to add one buffer to an empty queue. */ 123 /* Should always be able to add one buffer to an empty queue. */
85 if (port->in_vq->vq_ops->add_buf(port->in_vq, sg, 0, 1, port) < 0) 124 if (port->in_vq->vq_ops->add_buf(port->in_vq, sg, 0, 1, port) < 0)
@@ -98,6 +137,7 @@ static void add_inbuf(struct port *port)
98static int get_chars(u32 vtermno, char *buf, int count) 137static int get_chars(u32 vtermno, char *buf, int count)
99{ 138{
100 struct port *port; 139 struct port *port;
140 unsigned int len;
101 141
102 port = &console; 142 port = &console;
103 143
@@ -105,22 +145,23 @@ static int get_chars(u32 vtermno, char *buf, int count)
105 BUG_ON(!port->in_vq); 145 BUG_ON(!port->in_vq);
106 146
107 /* No more in buffer? See if they've (re)used it. */ 147 /* No more in buffer? See if they've (re)used it. */
108 if (port->offset == port->used_len) { 148 if (port->inbuf->offset == port->inbuf->len) {
109 if (!port->in_vq->vq_ops->get_buf(port->in_vq, &port->used_len)) 149 if (!port->in_vq->vq_ops->get_buf(port->in_vq, &len))
110 return 0; 150 return 0;
111 port->offset = 0; 151 port->inbuf->offset = 0;
152 port->inbuf->len = len;
112 } 153 }
113 154
114 /* You want more than we have to give? Well, try wanting less! */ 155 /* You want more than we have to give? Well, try wanting less! */
115 if (port->offset + count > port->used_len) 156 if (port->inbuf->offset + count > port->inbuf->len)
116 count = port->used_len - port->offset; 157 count = port->inbuf->len - port->inbuf->offset;
117 158
118 /* Copy across to their buffer and increment offset. */ 159 /* Copy across to their buffer and increment offset. */
119 memcpy(buf, port->inbuf + port->offset, count); 160 memcpy(buf, port->inbuf->buf + port->inbuf->offset, count);
120 port->offset += count; 161 port->inbuf->offset += count;
121 162
122 /* Finished? Re-register buffer so Host will use it again. */ 163 /* Finished? Re-register buffer so Host will use it again. */
123 if (port->offset == port->used_len) 164 if (port->inbuf->offset == port->inbuf->len)
124 add_inbuf(port); 165 add_inbuf(port);
125 166
126 return count; 167 return count;
@@ -220,8 +261,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
220 port->vdev = vdev; 261 port->vdev = vdev;
221 262
222 /* This is the scratch page we use to receive console input */ 263 /* This is the scratch page we use to receive console input */
223 port->used_len = 0; 264 port->inbuf = alloc_buf(PAGE_SIZE);
224 port->inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
225 if (!port->inbuf) { 265 if (!port->inbuf) {
226 err = -ENOMEM; 266 err = -ENOMEM;
227 goto fail; 267 goto fail;
@@ -263,7 +303,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
263free_vqs: 303free_vqs:
264 vdev->config->del_vqs(vdev); 304 vdev->config->del_vqs(vdev);
265free: 305free:
266 kfree(port->inbuf); 306 free_buf(port->inbuf);
267fail: 307fail:
268 return err; 308 return err;
269} 309}