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