This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / xen / fbfront / xenkbd.c
1 /*
2  * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
3  *
4  * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
5  * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
6  *
7  *  Based on linux/drivers/input/mouse/sermouse.c
8  *
9  *  This file is subject to the terms and conditions of the GNU General Public
10  *  License. See the file COPYING in the main directory of this archive for
11  *  more details.
12  */
13
14 /*
15  * TODO:
16  *
17  * Switch to grant tables together with xenfb.c.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/module.h>
23 #include <linux/input.h>
24 #include <asm/hypervisor.h>
25 #include <xen/evtchn.h>
26 #include <xen/interface/io/fbif.h>
27 #include <xen/interface/io/kbdif.h>
28 #include <xen/xenbus.h>
29
30 struct xenkbd_info
31 {
32         struct input_dev *dev;
33         struct xenkbd_page *page;
34         unsigned evtchn;
35         int irq;
36         struct xenbus_device *xbdev;
37 };
38
39 static int xenkbd_remove(struct xenbus_device *);
40 static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
41 static void xenkbd_disconnect_backend(struct xenkbd_info *);
42
43 /*
44  * Note: if you need to send out events, see xenfb_do_update() for how
45  * to do that.
46  */
47
48 static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
49 {
50         struct xenkbd_info *info = dev_id;
51         struct xenkbd_page *page = info->page;
52         __u32 cons, prod;
53
54         prod = page->in_prod;
55         if (prod == page->out_cons)
56                 return IRQ_HANDLED;
57         rmb();                  /* ensure we see ring contents up to prod */
58         for (cons = page->in_cons; cons != prod; cons++) {
59                 union xenkbd_in_event *event;
60                 event = &XENKBD_IN_RING_REF(page, cons);
61
62                 switch (event->type) {
63                 case XENKBD_TYPE_MOTION:
64                         input_report_rel(info->dev, REL_X, event->motion.rel_x);
65                         input_report_rel(info->dev, REL_Y, event->motion.rel_y);
66                         break;
67                 case XENKBD_TYPE_KEY:
68                         input_report_key(info->dev, event->key.keycode, event->key.pressed);
69                         break;
70                 case XENKBD_TYPE_POS:
71                         input_report_abs(info->dev, ABS_X, event->pos.abs_x);
72                         input_report_abs(info->dev, ABS_Y, event->pos.abs_y);
73                         break;
74                 }
75         }
76         input_sync(info->dev);
77         mb();                   /* ensure we got ring contents */
78         page->in_cons = cons;
79         notify_remote_via_evtchn(info->evtchn);
80
81         return IRQ_HANDLED;
82 }
83
84 int __devinit xenkbd_probe(struct xenbus_device *dev,
85                            const struct xenbus_device_id *id)
86 {
87         int ret, i;
88         struct xenkbd_info *info;
89         struct input_dev *input_dev;
90
91         info = kzalloc(sizeof(*info), GFP_KERNEL);
92         if (!info) {
93                 xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
94                 return -ENOMEM;
95         }
96         dev->dev.driver_data = info;
97         info->xbdev = dev;
98
99         info->page = (void *)__get_free_page(GFP_KERNEL);
100         if (!info->page)
101                 goto error_nomem;
102         info->page->in_cons = info->page->in_prod = 0;
103         info->page->out_cons = info->page->out_prod = 0;
104
105         input_dev = input_allocate_device();
106         if (!input_dev)
107                 goto error_nomem;
108
109         input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
110         input_dev->keybit[LONG(BTN_MOUSE)]
111                 = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
112         /* TODO additional buttons */
113         input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
114
115         /* FIXME not sure this is quite right */
116         for (i = 0; i < 256; i++)
117                 set_bit(i, input_dev->keybit);
118
119         input_dev->name = "Xen Virtual Keyboard/Mouse";
120
121         input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0);
122         input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
123
124         ret = input_register_device(input_dev);
125         if (ret) {
126                 input_free_device(input_dev);
127                 xenbus_dev_fatal(dev, ret, "input_register_device");
128                 goto error;
129         }
130         info->dev = input_dev;
131
132         ret = xenkbd_connect_backend(dev, info);
133         if (ret < 0)
134                 goto error;
135
136         return 0;
137
138  error_nomem:
139         ret = -ENOMEM;
140         xenbus_dev_fatal(dev, ret, "allocating device memory");
141  error:
142         xenkbd_remove(dev);
143         return ret;
144 }
145
146 static int xenkbd_resume(struct xenbus_device *dev)
147 {
148         struct xenkbd_info *info = dev->dev.driver_data;
149
150         xenkbd_disconnect_backend(info);
151         return xenkbd_connect_backend(dev, info);
152 }
153
154 static int xenkbd_remove(struct xenbus_device *dev)
155 {
156         struct xenkbd_info *info = dev->dev.driver_data;
157
158         xenkbd_disconnect_backend(info);
159         input_unregister_device(info->dev);
160         free_page((unsigned long)info->page);
161         kfree(info);
162         return 0;
163 }
164
165 static int xenkbd_connect_backend(struct xenbus_device *dev,
166                                   struct xenkbd_info *info)
167 {
168         int ret;
169         struct xenbus_transaction xbt;
170
171         ret = xenbus_alloc_evtchn(dev, &info->evtchn);
172         if (ret)
173                 return ret;
174         ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0,
175                                         "xenkbd", info);
176         if (ret < 0) {
177                 xenbus_free_evtchn(dev, info->evtchn);
178                 xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
179                 return ret;
180         }
181         info->irq = ret;
182
183  again:
184         ret = xenbus_transaction_start(&xbt);
185         if (ret) {
186                 xenbus_dev_fatal(dev, ret, "starting transaction");
187                 return ret;
188         }
189         ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
190                             virt_to_mfn(info->page));
191         if (ret)
192                 goto error_xenbus;
193         ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
194                             info->evtchn);
195         if (ret)
196                 goto error_xenbus;
197         ret = xenbus_transaction_end(xbt, 0);
198         if (ret) {
199                 if (ret == -EAGAIN)
200                         goto again;
201                 xenbus_dev_fatal(dev, ret, "completing transaction");
202                 return ret;
203         }
204
205         xenbus_switch_state(dev, XenbusStateInitialised);
206         return 0;
207
208  error_xenbus:
209         xenbus_transaction_end(xbt, 1);
210         xenbus_dev_fatal(dev, ret, "writing xenstore");
211         return ret;
212 }
213
214 static void xenkbd_disconnect_backend(struct xenkbd_info *info)
215 {
216         if (info->irq >= 0)
217                 unbind_from_irqhandler(info->irq, info);
218         info->irq = -1;
219 }
220
221 static void xenkbd_backend_changed(struct xenbus_device *dev,
222                                    enum xenbus_state backend_state)
223 {
224         struct xenkbd_info *info = dev->dev.driver_data;
225         int ret, val;
226
227         switch (backend_state) {
228         case XenbusStateInitialising:
229         case XenbusStateInitialised:
230         case XenbusStateUnknown:
231         case XenbusStateClosed:
232                 break;
233
234         case XenbusStateInitWait:
235         InitWait:
236                 ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
237                                    "feature-abs-pointer", "%d", &val);
238                 if (ret < 0)
239                         val = 0;
240                 if (val) {
241                         ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
242                                             "request-abs-pointer", "1");
243                         if (ret)
244                                 ; /* FIXME */
245                 }
246                 xenbus_switch_state(dev, XenbusStateConnected);
247                 break;
248
249         case XenbusStateConnected:
250                 /*
251                  * Work around xenbus race condition: If backend goes
252                  * through InitWait to Connected fast enough, we can
253                  * get Connected twice here.
254                  */
255                 if (dev->state != XenbusStateConnected)
256                         goto InitWait; /* no InitWait seen yet, fudge it */
257                 break;
258
259         case XenbusStateClosing:
260                 xenbus_frontend_closed(dev);
261                 break;
262         }
263 }
264
265 static struct xenbus_device_id xenkbd_ids[] = {
266         { "vkbd" },
267         { "" }
268 };
269
270 static struct xenbus_driver xenkbd = {
271         .name = "vkbd",
272         .owner = THIS_MODULE,
273         .ids = xenkbd_ids,
274         .probe = xenkbd_probe,
275         .remove = xenkbd_remove,
276         .resume = xenkbd_resume,
277         .otherend_changed = xenkbd_backend_changed,
278 };
279
280 static int __init xenkbd_init(void)
281 {
282         if (!is_running_on_xen())
283                 return -ENODEV;
284
285         /* Nothing to do if running in dom0. */
286         if (is_initial_xendomain())
287                 return -ENODEV;
288
289         return xenbus_register_frontend(&xenkbd);
290 }
291
292 static void __exit xenkbd_cleanup(void)
293 {
294         return xenbus_unregister_driver(&xenkbd);
295 }
296
297 module_init(xenkbd_init);
298 module_exit(xenkbd_cleanup);
299
300 MODULE_LICENSE("GPL");