Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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