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 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 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 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 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 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 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 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 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 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