blob: eb770613a9bd847930cf295aff81e25a6673d3f1 [file] [log] [blame]
Markus Armbruster4ee36dc2008-04-02 10:54:07 -07001/*
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
Joe Perchesda0c4902010-11-29 23:33:07 -080014#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070016#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/module.h>
19#include <linux/input.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Jeremy Fitzhardinge1ccbf532009-10-06 15:11:14 -070021
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070022#include <asm/xen/hypervisor.h>
Jeremy Fitzhardinge1ccbf532009-10-06 15:11:14 -070023
24#include <xen/xen.h>
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070025#include <xen/events.h>
26#include <xen/page.h>
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -070027#include <xen/grant_table.h>
28#include <xen/interface/grant_table.h>
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070029#include <xen/interface/io/fbif.h>
30#include <xen/interface/io/kbdif.h>
31#include <xen/xenbus.h>
Konrad Rzeszutek Wilk51c71a32013-11-26 15:05:40 -050032#include <xen/platform_pci.h>
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070033
34struct xenkbd_info {
35 struct input_dev *kbd;
36 struct input_dev *ptr;
37 struct xenkbd_page *page;
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -070038 int gref;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070039 int irq;
40 struct xenbus_device *xbdev;
41 char phys[32];
42};
43
Juergen Gross8b3afdf2017-04-19 08:47:06 -070044enum { KPARAM_X, KPARAM_Y, KPARAM_CNT };
45static int ptr_size[KPARAM_CNT] = { XENFB_WIDTH, XENFB_HEIGHT };
46module_param_array(ptr_size, int, NULL, 0444);
47MODULE_PARM_DESC(ptr_size,
48 "Pointing device width, height in pixels (default 800,600)");
49
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070050static int xenkbd_remove(struct xenbus_device *);
51static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
52static 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
59static 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);
Markus Armbruster6ba0e7b2008-05-26 23:31:08 +010079 if (event->motion.rel_z)
80 input_report_rel(dev, REL_WHEEL,
81 -event->motion.rel_z);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070082 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
Joe Perchesfef5f562017-03-17 17:15:38 -070093 pr_warn("unhandled keycode 0x%x\n",
94 event->key.keycode);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -070095 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);
Markus Armbruster6ba0e7b2008-05-26 23:31:08 +010099 if (event->pos.rel_z)
100 input_report_rel(dev, REL_WHEEL,
101 -event->pos.rel_z);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700102 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
Bill Pemberton5298cc42012-11-23 21:38:25 -0800114static int xenkbd_probe(struct xenbus_device *dev,
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700115 const struct xenbus_device_id *id)
116{
Juergen Gross81362c62016-10-31 14:58:40 +0100117 int ret, i;
118 unsigned int abs;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700119 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 }
Greg Kroah-Hartman1b713e02009-05-04 12:40:54 -0700127 dev_set_drvdata(&dev->dev, info);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700128 info->xbdev = dev;
129 info->irq = -1;
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700130 info->gref = -1;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700131 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
Juergen Gross8b3afdf2017-04-19 08:47:06 -0700137 /* Set input abs params to match backend screen res */
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700138 abs = xenbus_read_unsigned(dev->otherend,
139 XENKBD_FIELD_FEAT_ABS_POINTER, 0);
140 ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend,
141 XENKBD_FIELD_WIDTH,
Juergen Gross8b3afdf2017-04-19 08:47:06 -0700142 ptr_size[KPARAM_X]);
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700143 ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend,
144 XENKBD_FIELD_HEIGHT,
Juergen Gross8b3afdf2017-04-19 08:47:06 -0700145 ptr_size[KPARAM_Y]);
Insu Yunec7aa962015-10-19 09:42:21 -0700146 if (abs) {
Jan Beulichcd6763b2016-07-08 17:35:30 -0700147 ret = xenbus_write(XBT_NIL, dev->nodename,
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700148 XENKBD_FIELD_REQ_ABS_POINTER, "1");
Insu Yunec7aa962015-10-19 09:42:21 -0700149 if (ret) {
Joe Perchesfef5f562017-03-17 17:15:38 -0700150 pr_warn("xenkbd: can't request abs-pointer\n");
Insu Yunec7aa962015-10-19 09:42:21 -0700151 abs = 0;
152 }
153 }
Olaf Hering8c3c2832011-03-16 22:11:46 -0700154
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700155 /* keyboard */
156 kbd = input_allocate_device();
157 if (!kbd)
158 goto error_nomem;
159 kbd->name = "Xen Virtual Keyboard";
160 kbd->phys = info->phys;
161 kbd->id.bustype = BUS_PCI;
162 kbd->id.vendor = 0x5853;
163 kbd->id.product = 0xffff;
Olaf Hering8c3c2832011-03-16 22:11:46 -0700164
165 __set_bit(EV_KEY, kbd->evbit);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700166 for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
Olaf Hering8c3c2832011-03-16 22:11:46 -0700167 __set_bit(i, kbd->keybit);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700168 for (i = KEY_OK; i < KEY_MAX; i++)
Olaf Hering8c3c2832011-03-16 22:11:46 -0700169 __set_bit(i, kbd->keybit);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700170
171 ret = input_register_device(kbd);
172 if (ret) {
173 input_free_device(kbd);
174 xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
175 goto error;
176 }
177 info->kbd = kbd;
178
179 /* pointing device */
180 ptr = input_allocate_device();
181 if (!ptr)
182 goto error_nomem;
183 ptr->name = "Xen Virtual Pointer";
184 ptr->phys = info->phys;
185 ptr->id.bustype = BUS_PCI;
186 ptr->id.vendor = 0x5853;
187 ptr->id.product = 0xfffe;
Olaf Hering8c3c2832011-03-16 22:11:46 -0700188
189 if (abs) {
190 __set_bit(EV_ABS, ptr->evbit);
Juergen Gross8b3afdf2017-04-19 08:47:06 -0700191 input_set_abs_params(ptr, ABS_X, 0, ptr_size[KPARAM_X], 0, 0);
192 input_set_abs_params(ptr, ABS_Y, 0, ptr_size[KPARAM_Y], 0, 0);
Olaf Hering8c3c2832011-03-16 22:11:46 -0700193 } else {
194 input_set_capability(ptr, EV_REL, REL_X);
195 input_set_capability(ptr, EV_REL, REL_Y);
196 }
197 input_set_capability(ptr, EV_REL, REL_WHEEL);
198
199 __set_bit(EV_KEY, ptr->evbit);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700200 for (i = BTN_LEFT; i <= BTN_TASK; i++)
Olaf Hering8c3c2832011-03-16 22:11:46 -0700201 __set_bit(i, ptr->keybit);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700202
203 ret = input_register_device(ptr);
204 if (ret) {
205 input_free_device(ptr);
206 xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
207 goto error;
208 }
209 info->ptr = ptr;
210
211 ret = xenkbd_connect_backend(dev, info);
212 if (ret < 0)
213 goto error;
214
215 return 0;
216
217 error_nomem:
218 ret = -ENOMEM;
219 xenbus_dev_fatal(dev, ret, "allocating device memory");
220 error:
221 xenkbd_remove(dev);
222 return ret;
223}
224
225static int xenkbd_resume(struct xenbus_device *dev)
226{
Greg Kroah-Hartman1b713e02009-05-04 12:40:54 -0700227 struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700228
229 xenkbd_disconnect_backend(info);
230 memset(info->page, 0, PAGE_SIZE);
231 return xenkbd_connect_backend(dev, info);
232}
233
234static int xenkbd_remove(struct xenbus_device *dev)
235{
Greg Kroah-Hartman1b713e02009-05-04 12:40:54 -0700236 struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700237
238 xenkbd_disconnect_backend(info);
239 if (info->kbd)
240 input_unregister_device(info->kbd);
241 if (info->ptr)
242 input_unregister_device(info->ptr);
243 free_page((unsigned long)info->page);
244 kfree(info);
245 return 0;
246}
247
248static int xenkbd_connect_backend(struct xenbus_device *dev,
249 struct xenkbd_info *info)
250{
251 int ret, evtchn;
252 struct xenbus_transaction xbt;
253
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700254 ret = gnttab_grant_foreign_access(dev->otherend_id,
Julien Grall0df4f262015-08-07 17:34:37 +0100255 virt_to_gfn(info->page), 0);
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700256 if (ret < 0)
257 return ret;
258 info->gref = ret;
259
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700260 ret = xenbus_alloc_evtchn(dev, &evtchn);
261 if (ret)
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700262 goto error_grant;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700263 ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
264 0, dev->devicetype, info);
265 if (ret < 0) {
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700266 xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700267 goto error_evtchan;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700268 }
269 info->irq = ret;
270
271 again:
272 ret = xenbus_transaction_start(&xbt);
273 if (ret) {
274 xenbus_dev_fatal(dev, ret, "starting transaction");
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700275 goto error_irqh;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700276 }
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700277 ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_REF, "%lu",
Julien Grall0df4f262015-08-07 17:34:37 +0100278 virt_to_gfn(info->page));
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700279 if (ret)
280 goto error_xenbus;
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700281 ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_GREF,
282 "%u", info->gref);
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700283 if (ret)
284 goto error_xenbus;
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700285 ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_EVT_CHANNEL, "%u",
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700286 evtchn);
287 if (ret)
288 goto error_xenbus;
289 ret = xenbus_transaction_end(xbt, 0);
290 if (ret) {
291 if (ret == -EAGAIN)
292 goto again;
293 xenbus_dev_fatal(dev, ret, "completing transaction");
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700294 goto error_irqh;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700295 }
296
297 xenbus_switch_state(dev, XenbusStateInitialised);
298 return 0;
299
300 error_xenbus:
301 xenbus_transaction_end(xbt, 1);
302 xenbus_dev_fatal(dev, ret, "writing xenstore");
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700303 error_irqh:
304 unbind_from_irqhandler(info->irq, info);
305 info->irq = -1;
306 error_evtchan:
307 xenbus_free_evtchn(dev, evtchn);
308 error_grant:
Chang Huaixin4d544e32014-10-16 13:33:24 -0700309 gnttab_end_foreign_access(info->gref, 0, 0UL);
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700310 info->gref = -1;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700311 return ret;
312}
313
314static void xenkbd_disconnect_backend(struct xenkbd_info *info)
315{
316 if (info->irq >= 0)
317 unbind_from_irqhandler(info->irq, info);
318 info->irq = -1;
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700319 if (info->gref >= 0)
Chang Huaixin4d544e32014-10-16 13:33:24 -0700320 gnttab_end_foreign_access(info->gref, 0, 0UL);
Daniel De Graaf0a4dfa52011-03-16 22:52:42 -0700321 info->gref = -1;
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700322}
323
324static void xenkbd_backend_changed(struct xenbus_device *dev,
325 enum xenbus_state backend_state)
326{
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700327 switch (backend_state) {
328 case XenbusStateInitialising:
329 case XenbusStateInitialised:
Noboru Iwamatsub78c9512009-10-13 17:22:29 -0400330 case XenbusStateReconfiguring:
331 case XenbusStateReconfigured:
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700332 case XenbusStateUnknown:
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700333 break;
334
335 case XenbusStateInitWait:
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700336 xenbus_switch_state(dev, XenbusStateConnected);
337 break;
338
339 case XenbusStateConnected:
340 /*
341 * Work around xenbus race condition: If backend goes
342 * through InitWait to Connected fast enough, we can
343 * get Connected twice here.
344 */
345 if (dev->state != XenbusStateConnected)
Juergen Gross8b3afdf2017-04-19 08:47:06 -0700346 xenbus_switch_state(dev, XenbusStateConnected);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700347 break;
348
David Vrabel2ebb9392012-10-18 11:03:38 +0100349 case XenbusStateClosed:
350 if (dev->state == XenbusStateClosed)
351 break;
352 /* Missed the backend's CLOSING state -- fallthrough */
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700353 case XenbusStateClosing:
354 xenbus_frontend_closed(dev);
355 break;
356 }
357}
358
Márton Némethc6d5709382010-01-09 23:25:44 -0800359static const struct xenbus_device_id xenkbd_ids[] = {
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700360 { XENKBD_DRIVER_NAME },
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700361 { "" }
362};
363
David Vrabel95afae42014-09-08 17:30:41 +0100364static struct xenbus_driver xenkbd_driver = {
365 .ids = xenkbd_ids,
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700366 .probe = xenkbd_probe,
367 .remove = xenkbd_remove,
368 .resume = xenkbd_resume,
369 .otherend_changed = xenkbd_backend_changed,
David Vrabel95afae42014-09-08 17:30:41 +0100370};
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700371
372static int __init xenkbd_init(void)
373{
Stefano Stabellini5f098ec2011-07-04 19:22:00 -0700374 if (!xen_domain())
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700375 return -ENODEV;
376
377 /* Nothing to do if running in dom0. */
Jeremy Fitzhardinge6e833582008-08-19 13:16:17 -0700378 if (xen_initial_domain())
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700379 return -ENODEV;
380
Konrad Rzeszutek Wilk51c71a32013-11-26 15:05:40 -0500381 if (!xen_has_pv_devices())
382 return -ENODEV;
383
Al Viroffb78a22008-11-22 17:38:14 +0000384 return xenbus_register_frontend(&xenkbd_driver);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700385}
386
387static void __exit xenkbd_cleanup(void)
388{
Al Viroffb78a22008-11-22 17:38:14 +0000389 xenbus_unregister_driver(&xenkbd_driver);
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700390}
391
392module_init(xenkbd_init);
393module_exit(xenkbd_cleanup);
394
Markus Armbruster1e892c92008-05-26 23:31:09 +0100395MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
Markus Armbruster4ee36dc2008-04-02 10:54:07 -0700396MODULE_LICENSE("GPL");
Oleksandr Andrushchenkoad2ee012017-05-28 23:52:23 -0700397MODULE_ALIAS("xen:" XENKBD_DRIVER_NAME);