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