]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/input/misc/xen-kbdfront.c
blk-mq: Make it safe to quiesce and unquiesce from an interrupt handler
[karo-tx-linux.git] / drivers / input / misc / xen-kbdfront.c
1 /*
2  * Xen para-virtual input device
3  *
4  * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
5  * Copyright (C) 2006-2008 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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
16 #include <linux/kernel.h>
17 #include <linux/errno.h>
18 #include <linux/module.h>
19 #include <linux/input.h>
20 #include <linux/slab.h>
21
22 #include <asm/xen/hypervisor.h>
23
24 #include <xen/xen.h>
25 #include <xen/events.h>
26 #include <xen/page.h>
27 #include <xen/grant_table.h>
28 #include <xen/interface/grant_table.h>
29 #include <xen/interface/io/fbif.h>
30 #include <xen/interface/io/kbdif.h>
31 #include <xen/xenbus.h>
32 #include <xen/platform_pci.h>
33
34 struct xenkbd_info {
35         struct input_dev *kbd;
36         struct input_dev *ptr;
37         struct xenkbd_page *page;
38         int gref;
39         int irq;
40         struct xenbus_device *xbdev;
41         char phys[32];
42 };
43
44 enum { KPARAM_X, KPARAM_Y, KPARAM_CNT };
45 static int ptr_size[KPARAM_CNT] = { XENFB_WIDTH, XENFB_HEIGHT };
46 module_param_array(ptr_size, int, NULL, 0444);
47 MODULE_PARM_DESC(ptr_size,
48         "Pointing device width, height in pixels (default 800,600)");
49
50 static int xenkbd_remove(struct xenbus_device *);
51 static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
52 static void xenkbd_disconnect_backend(struct xenkbd_info *);
53
54 /*
55  * Note: if you need to send out events, see xenfb_do_update() for how
56  * to do that.
57  */
58
59 static irqreturn_t input_handler(int rq, void *dev_id)
60 {
61         struct xenkbd_info *info = dev_id;
62         struct xenkbd_page *page = info->page;
63         __u32 cons, prod;
64
65         prod = page->in_prod;
66         if (prod == page->in_cons)
67                 return IRQ_HANDLED;
68         rmb();                  /* ensure we see ring contents up to prod */
69         for (cons = page->in_cons; cons != prod; cons++) {
70                 union xenkbd_in_event *event;
71                 struct input_dev *dev;
72                 event = &XENKBD_IN_RING_REF(page, cons);
73
74                 dev = info->ptr;
75                 switch (event->type) {
76                 case XENKBD_TYPE_MOTION:
77                         input_report_rel(dev, REL_X, event->motion.rel_x);
78                         input_report_rel(dev, REL_Y, event->motion.rel_y);
79                         if (event->motion.rel_z)
80                                 input_report_rel(dev, REL_WHEEL,
81                                                  -event->motion.rel_z);
82                         break;
83                 case XENKBD_TYPE_KEY:
84                         dev = NULL;
85                         if (test_bit(event->key.keycode, info->kbd->keybit))
86                                 dev = info->kbd;
87                         if (test_bit(event->key.keycode, info->ptr->keybit))
88                                 dev = info->ptr;
89                         if (dev)
90                                 input_report_key(dev, event->key.keycode,
91                                                  event->key.pressed);
92                         else
93                                 pr_warn("unhandled keycode 0x%x\n",
94                                         event->key.keycode);
95                         break;
96                 case XENKBD_TYPE_POS:
97                         input_report_abs(dev, ABS_X, event->pos.abs_x);
98                         input_report_abs(dev, ABS_Y, event->pos.abs_y);
99                         if (event->pos.rel_z)
100                                 input_report_rel(dev, REL_WHEEL,
101                                                  -event->pos.rel_z);
102                         break;
103                 }
104                 if (dev)
105                         input_sync(dev);
106         }
107         mb();                   /* ensure we got ring contents */
108         page->in_cons = cons;
109         notify_remote_via_irq(info->irq);
110
111         return IRQ_HANDLED;
112 }
113
114 static int xenkbd_probe(struct xenbus_device *dev,
115                                   const struct xenbus_device_id *id)
116 {
117         int ret, i;
118         unsigned int abs;
119         struct xenkbd_info *info;
120         struct input_dev *kbd, *ptr;
121
122         info = kzalloc(sizeof(*info), GFP_KERNEL);
123         if (!info) {
124                 xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
125                 return -ENOMEM;
126         }
127         dev_set_drvdata(&dev->dev, info);
128         info->xbdev = dev;
129         info->irq = -1;
130         info->gref = -1;
131         snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
132
133         info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
134         if (!info->page)
135                 goto error_nomem;
136
137         /* Set input abs params to match backend screen res */
138         abs = xenbus_read_unsigned(dev->otherend, "feature-abs-pointer", 0);
139         ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend, "width",
140                                                   ptr_size[KPARAM_X]);
141         ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend, "height",
142                                                   ptr_size[KPARAM_Y]);
143         if (abs) {
144                 ret = xenbus_write(XBT_NIL, dev->nodename,
145                                    "request-abs-pointer", "1");
146                 if (ret) {
147                         pr_warn("xenkbd: can't request abs-pointer\n");
148                         abs = 0;
149                 }
150         }
151
152         /* keyboard */
153         kbd = input_allocate_device();
154         if (!kbd)
155                 goto error_nomem;
156         kbd->name = "Xen Virtual Keyboard";
157         kbd->phys = info->phys;
158         kbd->id.bustype = BUS_PCI;
159         kbd->id.vendor = 0x5853;
160         kbd->id.product = 0xffff;
161
162         __set_bit(EV_KEY, kbd->evbit);
163         for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
164                 __set_bit(i, kbd->keybit);
165         for (i = KEY_OK; i < KEY_MAX; i++)
166                 __set_bit(i, kbd->keybit);
167
168         ret = input_register_device(kbd);
169         if (ret) {
170                 input_free_device(kbd);
171                 xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
172                 goto error;
173         }
174         info->kbd = kbd;
175
176         /* pointing device */
177         ptr = input_allocate_device();
178         if (!ptr)
179                 goto error_nomem;
180         ptr->name = "Xen Virtual Pointer";
181         ptr->phys = info->phys;
182         ptr->id.bustype = BUS_PCI;
183         ptr->id.vendor = 0x5853;
184         ptr->id.product = 0xfffe;
185
186         if (abs) {
187                 __set_bit(EV_ABS, ptr->evbit);
188                 input_set_abs_params(ptr, ABS_X, 0, ptr_size[KPARAM_X], 0, 0);
189                 input_set_abs_params(ptr, ABS_Y, 0, ptr_size[KPARAM_Y], 0, 0);
190         } else {
191                 input_set_capability(ptr, EV_REL, REL_X);
192                 input_set_capability(ptr, EV_REL, REL_Y);
193         }
194         input_set_capability(ptr, EV_REL, REL_WHEEL);
195
196         __set_bit(EV_KEY, ptr->evbit);
197         for (i = BTN_LEFT; i <= BTN_TASK; i++)
198                 __set_bit(i, ptr->keybit);
199
200         ret = input_register_device(ptr);
201         if (ret) {
202                 input_free_device(ptr);
203                 xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
204                 goto error;
205         }
206         info->ptr = ptr;
207
208         ret = xenkbd_connect_backend(dev, info);
209         if (ret < 0)
210                 goto error;
211
212         return 0;
213
214  error_nomem:
215         ret = -ENOMEM;
216         xenbus_dev_fatal(dev, ret, "allocating device memory");
217  error:
218         xenkbd_remove(dev);
219         return ret;
220 }
221
222 static int xenkbd_resume(struct xenbus_device *dev)
223 {
224         struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
225
226         xenkbd_disconnect_backend(info);
227         memset(info->page, 0, PAGE_SIZE);
228         return xenkbd_connect_backend(dev, info);
229 }
230
231 static int xenkbd_remove(struct xenbus_device *dev)
232 {
233         struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
234
235         xenkbd_disconnect_backend(info);
236         if (info->kbd)
237                 input_unregister_device(info->kbd);
238         if (info->ptr)
239                 input_unregister_device(info->ptr);
240         free_page((unsigned long)info->page);
241         kfree(info);
242         return 0;
243 }
244
245 static int xenkbd_connect_backend(struct xenbus_device *dev,
246                                   struct xenkbd_info *info)
247 {
248         int ret, evtchn;
249         struct xenbus_transaction xbt;
250
251         ret = gnttab_grant_foreign_access(dev->otherend_id,
252                                           virt_to_gfn(info->page), 0);
253         if (ret < 0)
254                 return ret;
255         info->gref = ret;
256
257         ret = xenbus_alloc_evtchn(dev, &evtchn);
258         if (ret)
259                 goto error_grant;
260         ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
261                                         0, dev->devicetype, info);
262         if (ret < 0) {
263                 xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
264                 goto error_evtchan;
265         }
266         info->irq = ret;
267
268  again:
269         ret = xenbus_transaction_start(&xbt);
270         if (ret) {
271                 xenbus_dev_fatal(dev, ret, "starting transaction");
272                 goto error_irqh;
273         }
274         ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
275                             virt_to_gfn(info->page));
276         if (ret)
277                 goto error_xenbus;
278         ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref);
279         if (ret)
280                 goto error_xenbus;
281         ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
282                             evtchn);
283         if (ret)
284                 goto error_xenbus;
285         ret = xenbus_transaction_end(xbt, 0);
286         if (ret) {
287                 if (ret == -EAGAIN)
288                         goto again;
289                 xenbus_dev_fatal(dev, ret, "completing transaction");
290                 goto error_irqh;
291         }
292
293         xenbus_switch_state(dev, XenbusStateInitialised);
294         return 0;
295
296  error_xenbus:
297         xenbus_transaction_end(xbt, 1);
298         xenbus_dev_fatal(dev, ret, "writing xenstore");
299  error_irqh:
300         unbind_from_irqhandler(info->irq, info);
301         info->irq = -1;
302  error_evtchan:
303         xenbus_free_evtchn(dev, evtchn);
304  error_grant:
305         gnttab_end_foreign_access(info->gref, 0, 0UL);
306         info->gref = -1;
307         return ret;
308 }
309
310 static void xenkbd_disconnect_backend(struct xenkbd_info *info)
311 {
312         if (info->irq >= 0)
313                 unbind_from_irqhandler(info->irq, info);
314         info->irq = -1;
315         if (info->gref >= 0)
316                 gnttab_end_foreign_access(info->gref, 0, 0UL);
317         info->gref = -1;
318 }
319
320 static void xenkbd_backend_changed(struct xenbus_device *dev,
321                                    enum xenbus_state backend_state)
322 {
323         switch (backend_state) {
324         case XenbusStateInitialising:
325         case XenbusStateInitialised:
326         case XenbusStateReconfiguring:
327         case XenbusStateReconfigured:
328         case XenbusStateUnknown:
329                 break;
330
331         case XenbusStateInitWait:
332                 xenbus_switch_state(dev, XenbusStateConnected);
333                 break;
334
335         case XenbusStateConnected:
336                 /*
337                  * Work around xenbus race condition: If backend goes
338                  * through InitWait to Connected fast enough, we can
339                  * get Connected twice here.
340                  */
341                 if (dev->state != XenbusStateConnected)
342                         xenbus_switch_state(dev, XenbusStateConnected);
343                 break;
344
345         case XenbusStateClosed:
346                 if (dev->state == XenbusStateClosed)
347                         break;
348                 /* Missed the backend's CLOSING state -- fallthrough */
349         case XenbusStateClosing:
350                 xenbus_frontend_closed(dev);
351                 break;
352         }
353 }
354
355 static const struct xenbus_device_id xenkbd_ids[] = {
356         { "vkbd" },
357         { "" }
358 };
359
360 static struct xenbus_driver xenkbd_driver = {
361         .ids = xenkbd_ids,
362         .probe = xenkbd_probe,
363         .remove = xenkbd_remove,
364         .resume = xenkbd_resume,
365         .otherend_changed = xenkbd_backend_changed,
366 };
367
368 static int __init xenkbd_init(void)
369 {
370         if (!xen_domain())
371                 return -ENODEV;
372
373         /* Nothing to do if running in dom0. */
374         if (xen_initial_domain())
375                 return -ENODEV;
376
377         if (!xen_has_pv_devices())
378                 return -ENODEV;
379
380         return xenbus_register_frontend(&xenkbd_driver);
381 }
382
383 static void __exit xenkbd_cleanup(void)
384 {
385         xenbus_unregister_driver(&xenkbd_driver);
386 }
387
388 module_init(xenkbd_init);
389 module_exit(xenkbd_cleanup);
390
391 MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
392 MODULE_LICENSE("GPL");
393 MODULE_ALIAS("xen:vkbd");