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