linux/drivers/input/misc/xen-kbdfront.c
<<
>>
Prefs
   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
  33struct 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
  43static int xenkbd_remove(struct xenbus_device *);
  44static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
  45static 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
  52static 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
 107static 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
 204static 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
 213static 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
 227static 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
 292static 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
 302static 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:
 317InitWait:
 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
 362static const struct xenbus_device_id xenkbd_ids[] = {
 363        { "vkbd" },
 364        { "" }
 365};
 366
 367static DEFINE_XENBUS_DRIVER(xenkbd, ,
 368        .probe = xenkbd_probe,
 369        .remove = xenkbd_remove,
 370        .resume = xenkbd_resume,
 371        .otherend_changed = xenkbd_backend_changed,
 372);
 373
 374static 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
 386static void __exit xenkbd_cleanup(void)
 387{
 388        xenbus_unregister_driver(&xenkbd_driver);
 389}
 390
 391module_init(xenkbd_init);
 392module_exit(xenkbd_cleanup);
 393
 394MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
 395MODULE_LICENSE("GPL");
 396MODULE_ALIAS("xen:vkbd");
 397