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/input/mt.h>
  21#include <linux/slab.h>
  22
  23#include <asm/xen/hypervisor.h>
  24
  25#include <xen/xen.h>
  26#include <xen/events.h>
  27#include <xen/page.h>
  28#include <xen/grant_table.h>
  29#include <xen/interface/grant_table.h>
  30#include <xen/interface/io/fbif.h>
  31#include <xen/interface/io/kbdif.h>
  32#include <xen/xenbus.h>
  33#include <xen/platform_pci.h>
  34
  35struct xenkbd_info {
  36        struct input_dev *kbd;
  37        struct input_dev *ptr;
  38        struct input_dev *mtouch;
  39        struct xenkbd_page *page;
  40        int gref;
  41        int irq;
  42        struct xenbus_device *xbdev;
  43        char phys[32];
  44        /* current MT slot/contact ID we are injecting events in */
  45        int mtouch_cur_contact_id;
  46};
  47
  48enum { KPARAM_X, KPARAM_Y, KPARAM_CNT };
  49static int ptr_size[KPARAM_CNT] = { XENFB_WIDTH, XENFB_HEIGHT };
  50module_param_array(ptr_size, int, NULL, 0444);
  51MODULE_PARM_DESC(ptr_size,
  52        "Pointing device width, height in pixels (default 800,600)");
  53
  54static int xenkbd_remove(struct xenbus_device *);
  55static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
  56static void xenkbd_disconnect_backend(struct xenkbd_info *);
  57
  58/*
  59 * Note: if you need to send out events, see xenfb_do_update() for how
  60 * to do that.
  61 */
  62
  63static void xenkbd_handle_motion_event(struct xenkbd_info *info,
  64                                       struct xenkbd_motion *motion)
  65{
  66        input_report_rel(info->ptr, REL_X, motion->rel_x);
  67        input_report_rel(info->ptr, REL_Y, motion->rel_y);
  68        if (motion->rel_z)
  69                input_report_rel(info->ptr, REL_WHEEL, -motion->rel_z);
  70        input_sync(info->ptr);
  71}
  72
  73static void xenkbd_handle_position_event(struct xenkbd_info *info,
  74                                         struct xenkbd_position *pos)
  75{
  76        input_report_abs(info->ptr, ABS_X, pos->abs_x);
  77        input_report_abs(info->ptr, ABS_Y, pos->abs_y);
  78        if (pos->rel_z)
  79                input_report_rel(info->ptr, REL_WHEEL, -pos->rel_z);
  80        input_sync(info->ptr);
  81}
  82
  83static void xenkbd_handle_key_event(struct xenkbd_info *info,
  84                                    struct xenkbd_key *key)
  85{
  86        struct input_dev *dev;
  87        int value = key->pressed;
  88
  89        if (test_bit(key->keycode, info->ptr->keybit)) {
  90                dev = info->ptr;
  91        } else if (test_bit(key->keycode, info->kbd->keybit)) {
  92                dev = info->kbd;
  93                if (key->pressed && test_bit(key->keycode, info->kbd->key))
  94                        value = 2; /* Mark as autorepeat */
  95        } else {
  96                pr_warn("unhandled keycode 0x%x\n", key->keycode);
  97                return;
  98        }
  99
 100        input_event(dev, EV_KEY, key->keycode, value);
 101        input_sync(dev);
 102}
 103
 104static void xenkbd_handle_mt_event(struct xenkbd_info *info,
 105                                   struct xenkbd_mtouch *mtouch)
 106{
 107        if (unlikely(!info->mtouch))
 108                return;
 109
 110        if (mtouch->contact_id != info->mtouch_cur_contact_id) {
 111                info->mtouch_cur_contact_id = mtouch->contact_id;
 112                input_mt_slot(info->mtouch, mtouch->contact_id);
 113        }
 114
 115        switch (mtouch->event_type) {
 116        case XENKBD_MT_EV_DOWN:
 117                input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, true);
 118                /* fall through */
 119
 120        case XENKBD_MT_EV_MOTION:
 121                input_report_abs(info->mtouch, ABS_MT_POSITION_X,
 122                                 mtouch->u.pos.abs_x);
 123                input_report_abs(info->mtouch, ABS_MT_POSITION_Y,
 124                                 mtouch->u.pos.abs_y);
 125                break;
 126
 127        case XENKBD_MT_EV_SHAPE:
 128                input_report_abs(info->mtouch, ABS_MT_TOUCH_MAJOR,
 129                                 mtouch->u.shape.major);
 130                input_report_abs(info->mtouch, ABS_MT_TOUCH_MINOR,
 131                                 mtouch->u.shape.minor);
 132                break;
 133
 134        case XENKBD_MT_EV_ORIENT:
 135                input_report_abs(info->mtouch, ABS_MT_ORIENTATION,
 136                                 mtouch->u.orientation);
 137                break;
 138
 139        case XENKBD_MT_EV_UP:
 140                input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, false);
 141                break;
 142
 143        case XENKBD_MT_EV_SYN:
 144                input_mt_sync_frame(info->mtouch);
 145                input_sync(info->mtouch);
 146                break;
 147        }
 148}
 149
 150static void xenkbd_handle_event(struct xenkbd_info *info,
 151                                union xenkbd_in_event *event)
 152{
 153        switch (event->type) {
 154        case XENKBD_TYPE_MOTION:
 155                xenkbd_handle_motion_event(info, &event->motion);
 156                break;
 157
 158        case XENKBD_TYPE_KEY:
 159                xenkbd_handle_key_event(info, &event->key);
 160                break;
 161
 162        case XENKBD_TYPE_POS:
 163                xenkbd_handle_position_event(info, &event->pos);
 164                break;
 165
 166        case XENKBD_TYPE_MTOUCH:
 167                xenkbd_handle_mt_event(info, &event->mtouch);
 168                break;
 169        }
 170}
 171
 172static irqreturn_t input_handler(int rq, void *dev_id)
 173{
 174        struct xenkbd_info *info = dev_id;
 175        struct xenkbd_page *page = info->page;
 176        __u32 cons, prod;
 177
 178        prod = page->in_prod;
 179        if (prod == page->in_cons)
 180                return IRQ_HANDLED;
 181        rmb();                  /* ensure we see ring contents up to prod */
 182        for (cons = page->in_cons; cons != prod; cons++)
 183                xenkbd_handle_event(info, &XENKBD_IN_RING_REF(page, cons));
 184        mb();                   /* ensure we got ring contents */
 185        page->in_cons = cons;
 186        notify_remote_via_irq(info->irq);
 187
 188        return IRQ_HANDLED;
 189}
 190
 191static int xenkbd_probe(struct xenbus_device *dev,
 192                                  const struct xenbus_device_id *id)
 193{
 194        int ret, i;
 195        unsigned int abs, touch;
 196        struct xenkbd_info *info;
 197        struct input_dev *kbd, *ptr, *mtouch;
 198
 199        info = kzalloc(sizeof(*info), GFP_KERNEL);
 200        if (!info) {
 201                xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
 202                return -ENOMEM;
 203        }
 204        dev_set_drvdata(&dev->dev, info);
 205        info->xbdev = dev;
 206        info->irq = -1;
 207        info->gref = -1;
 208        snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
 209
 210        info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
 211        if (!info->page)
 212                goto error_nomem;
 213
 214        /* Set input abs params to match backend screen res */
 215        abs = xenbus_read_unsigned(dev->otherend,
 216                                   XENKBD_FIELD_FEAT_ABS_POINTER, 0);
 217        ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend,
 218                                                  XENKBD_FIELD_WIDTH,
 219                                                  ptr_size[KPARAM_X]);
 220        ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend,
 221                                                  XENKBD_FIELD_HEIGHT,
 222                                                  ptr_size[KPARAM_Y]);
 223        if (abs) {
 224                ret = xenbus_write(XBT_NIL, dev->nodename,
 225                                   XENKBD_FIELD_REQ_ABS_POINTER, "1");
 226                if (ret) {
 227                        pr_warn("xenkbd: can't request abs-pointer\n");
 228                        abs = 0;
 229                }
 230        }
 231
 232        touch = xenbus_read_unsigned(dev->nodename,
 233                                     XENKBD_FIELD_FEAT_MTOUCH, 0);
 234        if (touch) {
 235                ret = xenbus_write(XBT_NIL, dev->nodename,
 236                                   XENKBD_FIELD_REQ_MTOUCH, "1");
 237                if (ret) {
 238                        pr_warn("xenkbd: can't request multi-touch");
 239                        touch = 0;
 240                }
 241        }
 242
 243        /* keyboard */
 244        kbd = input_allocate_device();
 245        if (!kbd)
 246                goto error_nomem;
 247        kbd->name = "Xen Virtual Keyboard";
 248        kbd->phys = info->phys;
 249        kbd->id.bustype = BUS_PCI;
 250        kbd->id.vendor = 0x5853;
 251        kbd->id.product = 0xffff;
 252
 253        __set_bit(EV_KEY, kbd->evbit);
 254        for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
 255                __set_bit(i, kbd->keybit);
 256        for (i = KEY_OK; i < KEY_MAX; i++)
 257                __set_bit(i, kbd->keybit);
 258
 259        ret = input_register_device(kbd);
 260        if (ret) {
 261                input_free_device(kbd);
 262                xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
 263                goto error;
 264        }
 265        info->kbd = kbd;
 266
 267        /* pointing device */
 268        ptr = input_allocate_device();
 269        if (!ptr)
 270                goto error_nomem;
 271        ptr->name = "Xen Virtual Pointer";
 272        ptr->phys = info->phys;
 273        ptr->id.bustype = BUS_PCI;
 274        ptr->id.vendor = 0x5853;
 275        ptr->id.product = 0xfffe;
 276
 277        if (abs) {
 278                __set_bit(EV_ABS, ptr->evbit);
 279                input_set_abs_params(ptr, ABS_X, 0, ptr_size[KPARAM_X], 0, 0);
 280                input_set_abs_params(ptr, ABS_Y, 0, ptr_size[KPARAM_Y], 0, 0);
 281        } else {
 282                input_set_capability(ptr, EV_REL, REL_X);
 283                input_set_capability(ptr, EV_REL, REL_Y);
 284        }
 285        input_set_capability(ptr, EV_REL, REL_WHEEL);
 286
 287        __set_bit(EV_KEY, ptr->evbit);
 288        for (i = BTN_LEFT; i <= BTN_TASK; i++)
 289                __set_bit(i, ptr->keybit);
 290
 291        ret = input_register_device(ptr);
 292        if (ret) {
 293                input_free_device(ptr);
 294                xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
 295                goto error;
 296        }
 297        info->ptr = ptr;
 298
 299        /* multi-touch device */
 300        if (touch) {
 301                int num_cont, width, height;
 302
 303                mtouch = input_allocate_device();
 304                if (!mtouch)
 305                        goto error_nomem;
 306
 307                num_cont = xenbus_read_unsigned(info->xbdev->nodename,
 308                                                XENKBD_FIELD_MT_NUM_CONTACTS,
 309                                                1);
 310                width = xenbus_read_unsigned(info->xbdev->nodename,
 311                                             XENKBD_FIELD_MT_WIDTH,
 312                                             XENFB_WIDTH);
 313                height = xenbus_read_unsigned(info->xbdev->nodename,
 314                                              XENKBD_FIELD_MT_HEIGHT,
 315                                              XENFB_HEIGHT);
 316
 317                mtouch->name = "Xen Virtual Multi-touch";
 318                mtouch->phys = info->phys;
 319                mtouch->id.bustype = BUS_PCI;
 320                mtouch->id.vendor = 0x5853;
 321                mtouch->id.product = 0xfffd;
 322
 323                input_set_abs_params(mtouch, ABS_MT_TOUCH_MAJOR,
 324                                     0, 255, 0, 0);
 325                input_set_abs_params(mtouch, ABS_MT_POSITION_X,
 326                                     0, width, 0, 0);
 327                input_set_abs_params(mtouch, ABS_MT_POSITION_Y,
 328                                     0, height, 0, 0);
 329                input_set_abs_params(mtouch, ABS_MT_PRESSURE,
 330                                     0, 255, 0, 0);
 331
 332                ret = input_mt_init_slots(mtouch, num_cont, INPUT_MT_DIRECT);
 333                if (ret) {
 334                        input_free_device(mtouch);
 335                        xenbus_dev_fatal(info->xbdev, ret,
 336                                         "input_mt_init_slots");
 337                        goto error;
 338                }
 339
 340                ret = input_register_device(mtouch);
 341                if (ret) {
 342                        input_free_device(mtouch);
 343                        xenbus_dev_fatal(info->xbdev, ret,
 344                                         "input_register_device(mtouch)");
 345                        goto error;
 346                }
 347                info->mtouch_cur_contact_id = -1;
 348                info->mtouch = mtouch;
 349        }
 350
 351        ret = xenkbd_connect_backend(dev, info);
 352        if (ret < 0)
 353                goto error;
 354
 355        return 0;
 356
 357 error_nomem:
 358        ret = -ENOMEM;
 359        xenbus_dev_fatal(dev, ret, "allocating device memory");
 360 error:
 361        xenkbd_remove(dev);
 362        return ret;
 363}
 364
 365static int xenkbd_resume(struct xenbus_device *dev)
 366{
 367        struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
 368
 369        xenkbd_disconnect_backend(info);
 370        memset(info->page, 0, PAGE_SIZE);
 371        return xenkbd_connect_backend(dev, info);
 372}
 373
 374static int xenkbd_remove(struct xenbus_device *dev)
 375{
 376        struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
 377
 378        xenkbd_disconnect_backend(info);
 379        if (info->kbd)
 380                input_unregister_device(info->kbd);
 381        if (info->ptr)
 382                input_unregister_device(info->ptr);
 383        if (info->mtouch)
 384                input_unregister_device(info->mtouch);
 385        free_page((unsigned long)info->page);
 386        kfree(info);
 387        return 0;
 388}
 389
 390static int xenkbd_connect_backend(struct xenbus_device *dev,
 391                                  struct xenkbd_info *info)
 392{
 393        int ret, evtchn;
 394        struct xenbus_transaction xbt;
 395
 396        ret = gnttab_grant_foreign_access(dev->otherend_id,
 397                                          virt_to_gfn(info->page), 0);
 398        if (ret < 0)
 399                return ret;
 400        info->gref = ret;
 401
 402        ret = xenbus_alloc_evtchn(dev, &evtchn);
 403        if (ret)
 404                goto error_grant;
 405        ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
 406                                        0, dev->devicetype, info);
 407        if (ret < 0) {
 408                xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
 409                goto error_evtchan;
 410        }
 411        info->irq = ret;
 412
 413 again:
 414        ret = xenbus_transaction_start(&xbt);
 415        if (ret) {
 416                xenbus_dev_fatal(dev, ret, "starting transaction");
 417                goto error_irqh;
 418        }
 419        ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_REF, "%lu",
 420                            virt_to_gfn(info->page));
 421        if (ret)
 422                goto error_xenbus;
 423        ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_GREF,
 424                            "%u", info->gref);
 425        if (ret)
 426                goto error_xenbus;
 427        ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_EVT_CHANNEL, "%u",
 428                            evtchn);
 429        if (ret)
 430                goto error_xenbus;
 431        ret = xenbus_transaction_end(xbt, 0);
 432        if (ret) {
 433                if (ret == -EAGAIN)
 434                        goto again;
 435                xenbus_dev_fatal(dev, ret, "completing transaction");
 436                goto error_irqh;
 437        }
 438
 439        xenbus_switch_state(dev, XenbusStateInitialised);
 440        return 0;
 441
 442 error_xenbus:
 443        xenbus_transaction_end(xbt, 1);
 444        xenbus_dev_fatal(dev, ret, "writing xenstore");
 445 error_irqh:
 446        unbind_from_irqhandler(info->irq, info);
 447        info->irq = -1;
 448 error_evtchan:
 449        xenbus_free_evtchn(dev, evtchn);
 450 error_grant:
 451        gnttab_end_foreign_access(info->gref, 0, 0UL);
 452        info->gref = -1;
 453        return ret;
 454}
 455
 456static void xenkbd_disconnect_backend(struct xenkbd_info *info)
 457{
 458        if (info->irq >= 0)
 459                unbind_from_irqhandler(info->irq, info);
 460        info->irq = -1;
 461        if (info->gref >= 0)
 462                gnttab_end_foreign_access(info->gref, 0, 0UL);
 463        info->gref = -1;
 464}
 465
 466static void xenkbd_backend_changed(struct xenbus_device *dev,
 467                                   enum xenbus_state backend_state)
 468{
 469        switch (backend_state) {
 470        case XenbusStateInitialising:
 471        case XenbusStateInitialised:
 472        case XenbusStateReconfiguring:
 473        case XenbusStateReconfigured:
 474        case XenbusStateUnknown:
 475                break;
 476
 477        case XenbusStateInitWait:
 478                xenbus_switch_state(dev, XenbusStateConnected);
 479                break;
 480
 481        case XenbusStateConnected:
 482                /*
 483                 * Work around xenbus race condition: If backend goes
 484                 * through InitWait to Connected fast enough, we can
 485                 * get Connected twice here.
 486                 */
 487                if (dev->state != XenbusStateConnected)
 488                        xenbus_switch_state(dev, XenbusStateConnected);
 489                break;
 490
 491        case XenbusStateClosed:
 492                if (dev->state == XenbusStateClosed)
 493                        break;
 494                /* Missed the backend's CLOSING state -- fallthrough */
 495        case XenbusStateClosing:
 496                xenbus_frontend_closed(dev);
 497                break;
 498        }
 499}
 500
 501static const struct xenbus_device_id xenkbd_ids[] = {
 502        { XENKBD_DRIVER_NAME },
 503        { "" }
 504};
 505
 506static struct xenbus_driver xenkbd_driver = {
 507        .ids = xenkbd_ids,
 508        .probe = xenkbd_probe,
 509        .remove = xenkbd_remove,
 510        .resume = xenkbd_resume,
 511        .otherend_changed = xenkbd_backend_changed,
 512};
 513
 514static int __init xenkbd_init(void)
 515{
 516        if (!xen_domain())
 517                return -ENODEV;
 518
 519        /* Nothing to do if running in dom0. */
 520        if (xen_initial_domain())
 521                return -ENODEV;
 522
 523        if (!xen_has_pv_devices())
 524                return -ENODEV;
 525
 526        return xenbus_register_frontend(&xenkbd_driver);
 527}
 528
 529static void __exit xenkbd_cleanup(void)
 530{
 531        xenbus_unregister_driver(&xenkbd_driver);
 532}
 533
 534module_init(xenkbd_init);
 535module_exit(xenkbd_cleanup);
 536
 537MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
 538MODULE_LICENSE("GPL");
 539MODULE_ALIAS("xen:" XENKBD_DRIVER_NAME);
 540