149851ca0SDmitry Torokhov /* 249851ca0SDmitry Torokhov * Xen para-virtual input device 349851ca0SDmitry Torokhov * 449851ca0SDmitry Torokhov * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> 549851ca0SDmitry Torokhov * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> 649851ca0SDmitry Torokhov * 749851ca0SDmitry Torokhov * Based on linux/drivers/input/mouse/sermouse.c 849851ca0SDmitry Torokhov * 949851ca0SDmitry Torokhov * This file is subject to the terms and conditions of the GNU General Public 1049851ca0SDmitry Torokhov * License. See the file COPYING in the main directory of this archive for 1149851ca0SDmitry Torokhov * more details. 1249851ca0SDmitry Torokhov */ 1349851ca0SDmitry Torokhov 1449851ca0SDmitry Torokhov #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1549851ca0SDmitry Torokhov 1649851ca0SDmitry Torokhov #include <linux/kernel.h> 1749851ca0SDmitry Torokhov #include <linux/errno.h> 1849851ca0SDmitry Torokhov #include <linux/module.h> 1949851ca0SDmitry Torokhov #include <linux/input.h> 2049851ca0SDmitry Torokhov #include <linux/slab.h> 2149851ca0SDmitry Torokhov 2249851ca0SDmitry Torokhov #include <asm/xen/hypervisor.h> 2349851ca0SDmitry Torokhov 2449851ca0SDmitry Torokhov #include <xen/xen.h> 2549851ca0SDmitry Torokhov #include <xen/events.h> 2649851ca0SDmitry Torokhov #include <xen/page.h> 2749851ca0SDmitry Torokhov #include <xen/grant_table.h> 2849851ca0SDmitry Torokhov #include <xen/interface/grant_table.h> 2949851ca0SDmitry Torokhov #include <xen/interface/io/fbif.h> 3049851ca0SDmitry Torokhov #include <xen/interface/io/kbdif.h> 3149851ca0SDmitry Torokhov #include <xen/xenbus.h> 3249851ca0SDmitry Torokhov 3349851ca0SDmitry Torokhov struct xenkbd_info { 3449851ca0SDmitry Torokhov struct input_dev *kbd; 3549851ca0SDmitry Torokhov struct input_dev *ptr; 3649851ca0SDmitry Torokhov struct xenkbd_page *page; 3749851ca0SDmitry Torokhov int gref; 3849851ca0SDmitry Torokhov int irq; 3949851ca0SDmitry Torokhov struct xenbus_device *xbdev; 4049851ca0SDmitry Torokhov char phys[32]; 4149851ca0SDmitry Torokhov }; 4249851ca0SDmitry Torokhov 4349851ca0SDmitry Torokhov static int xenkbd_remove(struct xenbus_device *); 4449851ca0SDmitry Torokhov static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); 4549851ca0SDmitry Torokhov static void xenkbd_disconnect_backend(struct xenkbd_info *); 4649851ca0SDmitry Torokhov 4749851ca0SDmitry Torokhov /* 4849851ca0SDmitry Torokhov * Note: if you need to send out events, see xenfb_do_update() for how 4949851ca0SDmitry Torokhov * to do that. 5049851ca0SDmitry Torokhov */ 5149851ca0SDmitry Torokhov 5249851ca0SDmitry Torokhov static irqreturn_t input_handler(int rq, void *dev_id) 5349851ca0SDmitry Torokhov { 5449851ca0SDmitry Torokhov struct xenkbd_info *info = dev_id; 5549851ca0SDmitry Torokhov struct xenkbd_page *page = info->page; 5649851ca0SDmitry Torokhov __u32 cons, prod; 5749851ca0SDmitry Torokhov 5849851ca0SDmitry Torokhov prod = page->in_prod; 5949851ca0SDmitry Torokhov if (prod == page->in_cons) 6049851ca0SDmitry Torokhov return IRQ_HANDLED; 6149851ca0SDmitry Torokhov rmb(); /* ensure we see ring contents up to prod */ 6249851ca0SDmitry Torokhov for (cons = page->in_cons; cons != prod; cons++) { 6349851ca0SDmitry Torokhov union xenkbd_in_event *event; 6449851ca0SDmitry Torokhov struct input_dev *dev; 6549851ca0SDmitry Torokhov event = &XENKBD_IN_RING_REF(page, cons); 6649851ca0SDmitry Torokhov 6749851ca0SDmitry Torokhov dev = info->ptr; 6849851ca0SDmitry Torokhov switch (event->type) { 6949851ca0SDmitry Torokhov case XENKBD_TYPE_MOTION: 7049851ca0SDmitry Torokhov input_report_rel(dev, REL_X, event->motion.rel_x); 7149851ca0SDmitry Torokhov input_report_rel(dev, REL_Y, event->motion.rel_y); 7249851ca0SDmitry Torokhov if (event->motion.rel_z) 7349851ca0SDmitry Torokhov input_report_rel(dev, REL_WHEEL, 7449851ca0SDmitry Torokhov -event->motion.rel_z); 7549851ca0SDmitry Torokhov break; 7649851ca0SDmitry Torokhov case XENKBD_TYPE_KEY: 7749851ca0SDmitry Torokhov dev = NULL; 7849851ca0SDmitry Torokhov if (test_bit(event->key.keycode, info->kbd->keybit)) 7949851ca0SDmitry Torokhov dev = info->kbd; 8049851ca0SDmitry Torokhov if (test_bit(event->key.keycode, info->ptr->keybit)) 8149851ca0SDmitry Torokhov dev = info->ptr; 8249851ca0SDmitry Torokhov if (dev) 8349851ca0SDmitry Torokhov input_report_key(dev, event->key.keycode, 8449851ca0SDmitry Torokhov event->key.pressed); 8549851ca0SDmitry Torokhov else 8649851ca0SDmitry Torokhov pr_warning("unhandled keycode 0x%x\n", 8749851ca0SDmitry Torokhov event->key.keycode); 8849851ca0SDmitry Torokhov break; 8949851ca0SDmitry Torokhov case XENKBD_TYPE_POS: 9049851ca0SDmitry Torokhov input_report_abs(dev, ABS_X, event->pos.abs_x); 9149851ca0SDmitry Torokhov input_report_abs(dev, ABS_Y, event->pos.abs_y); 9249851ca0SDmitry Torokhov if (event->pos.rel_z) 9349851ca0SDmitry Torokhov input_report_rel(dev, REL_WHEEL, 9449851ca0SDmitry Torokhov -event->pos.rel_z); 9549851ca0SDmitry Torokhov break; 9649851ca0SDmitry Torokhov } 9749851ca0SDmitry Torokhov if (dev) 9849851ca0SDmitry Torokhov input_sync(dev); 9949851ca0SDmitry Torokhov } 10049851ca0SDmitry Torokhov mb(); /* ensure we got ring contents */ 10149851ca0SDmitry Torokhov page->in_cons = cons; 10249851ca0SDmitry Torokhov notify_remote_via_irq(info->irq); 10349851ca0SDmitry Torokhov 10449851ca0SDmitry Torokhov return IRQ_HANDLED; 10549851ca0SDmitry Torokhov } 10649851ca0SDmitry Torokhov 1075298cc4cSBill Pemberton static int xenkbd_probe(struct xenbus_device *dev, 10849851ca0SDmitry Torokhov const struct xenbus_device_id *id) 10949851ca0SDmitry Torokhov { 11049851ca0SDmitry Torokhov int ret, i, abs; 11149851ca0SDmitry Torokhov struct xenkbd_info *info; 11249851ca0SDmitry Torokhov struct input_dev *kbd, *ptr; 11349851ca0SDmitry Torokhov 11449851ca0SDmitry Torokhov info = kzalloc(sizeof(*info), GFP_KERNEL); 11549851ca0SDmitry Torokhov if (!info) { 11649851ca0SDmitry Torokhov xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); 11749851ca0SDmitry Torokhov return -ENOMEM; 11849851ca0SDmitry Torokhov } 11949851ca0SDmitry Torokhov dev_set_drvdata(&dev->dev, info); 12049851ca0SDmitry Torokhov info->xbdev = dev; 12149851ca0SDmitry Torokhov info->irq = -1; 12249851ca0SDmitry Torokhov info->gref = -1; 12349851ca0SDmitry Torokhov snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); 12449851ca0SDmitry Torokhov 12549851ca0SDmitry Torokhov info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); 12649851ca0SDmitry Torokhov if (!info->page) 12749851ca0SDmitry Torokhov goto error_nomem; 12849851ca0SDmitry Torokhov 12949851ca0SDmitry Torokhov if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) 13049851ca0SDmitry Torokhov abs = 0; 13149851ca0SDmitry Torokhov if (abs) 13249851ca0SDmitry Torokhov xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); 13349851ca0SDmitry Torokhov 13449851ca0SDmitry Torokhov /* keyboard */ 13549851ca0SDmitry Torokhov kbd = input_allocate_device(); 13649851ca0SDmitry Torokhov if (!kbd) 13749851ca0SDmitry Torokhov goto error_nomem; 13849851ca0SDmitry Torokhov kbd->name = "Xen Virtual Keyboard"; 13949851ca0SDmitry Torokhov kbd->phys = info->phys; 14049851ca0SDmitry Torokhov kbd->id.bustype = BUS_PCI; 14149851ca0SDmitry Torokhov kbd->id.vendor = 0x5853; 14249851ca0SDmitry Torokhov kbd->id.product = 0xffff; 14349851ca0SDmitry Torokhov 14449851ca0SDmitry Torokhov __set_bit(EV_KEY, kbd->evbit); 14549851ca0SDmitry Torokhov for (i = KEY_ESC; i < KEY_UNKNOWN; i++) 14649851ca0SDmitry Torokhov __set_bit(i, kbd->keybit); 14749851ca0SDmitry Torokhov for (i = KEY_OK; i < KEY_MAX; i++) 14849851ca0SDmitry Torokhov __set_bit(i, kbd->keybit); 14949851ca0SDmitry Torokhov 15049851ca0SDmitry Torokhov ret = input_register_device(kbd); 15149851ca0SDmitry Torokhov if (ret) { 15249851ca0SDmitry Torokhov input_free_device(kbd); 15349851ca0SDmitry Torokhov xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); 15449851ca0SDmitry Torokhov goto error; 15549851ca0SDmitry Torokhov } 15649851ca0SDmitry Torokhov info->kbd = kbd; 15749851ca0SDmitry Torokhov 15849851ca0SDmitry Torokhov /* pointing device */ 15949851ca0SDmitry Torokhov ptr = input_allocate_device(); 16049851ca0SDmitry Torokhov if (!ptr) 16149851ca0SDmitry Torokhov goto error_nomem; 16249851ca0SDmitry Torokhov ptr->name = "Xen Virtual Pointer"; 16349851ca0SDmitry Torokhov ptr->phys = info->phys; 16449851ca0SDmitry Torokhov ptr->id.bustype = BUS_PCI; 16549851ca0SDmitry Torokhov ptr->id.vendor = 0x5853; 16649851ca0SDmitry Torokhov ptr->id.product = 0xfffe; 16749851ca0SDmitry Torokhov 16849851ca0SDmitry Torokhov if (abs) { 16949851ca0SDmitry Torokhov __set_bit(EV_ABS, ptr->evbit); 17049851ca0SDmitry Torokhov input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); 17149851ca0SDmitry Torokhov input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); 17249851ca0SDmitry Torokhov } else { 17349851ca0SDmitry Torokhov input_set_capability(ptr, EV_REL, REL_X); 17449851ca0SDmitry Torokhov input_set_capability(ptr, EV_REL, REL_Y); 17549851ca0SDmitry Torokhov } 17649851ca0SDmitry Torokhov input_set_capability(ptr, EV_REL, REL_WHEEL); 17749851ca0SDmitry Torokhov 17849851ca0SDmitry Torokhov __set_bit(EV_KEY, ptr->evbit); 17949851ca0SDmitry Torokhov for (i = BTN_LEFT; i <= BTN_TASK; i++) 18049851ca0SDmitry Torokhov __set_bit(i, ptr->keybit); 18149851ca0SDmitry Torokhov 18249851ca0SDmitry Torokhov ret = input_register_device(ptr); 18349851ca0SDmitry Torokhov if (ret) { 18449851ca0SDmitry Torokhov input_free_device(ptr); 18549851ca0SDmitry Torokhov xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); 18649851ca0SDmitry Torokhov goto error; 18749851ca0SDmitry Torokhov } 18849851ca0SDmitry Torokhov info->ptr = ptr; 18949851ca0SDmitry Torokhov 19049851ca0SDmitry Torokhov ret = xenkbd_connect_backend(dev, info); 19149851ca0SDmitry Torokhov if (ret < 0) 19249851ca0SDmitry Torokhov goto error; 19349851ca0SDmitry Torokhov 19449851ca0SDmitry Torokhov return 0; 19549851ca0SDmitry Torokhov 19649851ca0SDmitry Torokhov error_nomem: 19749851ca0SDmitry Torokhov ret = -ENOMEM; 19849851ca0SDmitry Torokhov xenbus_dev_fatal(dev, ret, "allocating device memory"); 19949851ca0SDmitry Torokhov error: 20049851ca0SDmitry Torokhov xenkbd_remove(dev); 20149851ca0SDmitry Torokhov return ret; 20249851ca0SDmitry Torokhov } 20349851ca0SDmitry Torokhov 20449851ca0SDmitry Torokhov static int xenkbd_resume(struct xenbus_device *dev) 20549851ca0SDmitry Torokhov { 20649851ca0SDmitry Torokhov struct xenkbd_info *info = dev_get_drvdata(&dev->dev); 20749851ca0SDmitry Torokhov 20849851ca0SDmitry Torokhov xenkbd_disconnect_backend(info); 20949851ca0SDmitry Torokhov memset(info->page, 0, PAGE_SIZE); 21049851ca0SDmitry Torokhov return xenkbd_connect_backend(dev, info); 21149851ca0SDmitry Torokhov } 21249851ca0SDmitry Torokhov 21349851ca0SDmitry Torokhov static int xenkbd_remove(struct xenbus_device *dev) 21449851ca0SDmitry Torokhov { 21549851ca0SDmitry Torokhov struct xenkbd_info *info = dev_get_drvdata(&dev->dev); 21649851ca0SDmitry Torokhov 21749851ca0SDmitry Torokhov xenkbd_disconnect_backend(info); 21849851ca0SDmitry Torokhov if (info->kbd) 21949851ca0SDmitry Torokhov input_unregister_device(info->kbd); 22049851ca0SDmitry Torokhov if (info->ptr) 22149851ca0SDmitry Torokhov input_unregister_device(info->ptr); 22249851ca0SDmitry Torokhov free_page((unsigned long)info->page); 22349851ca0SDmitry Torokhov kfree(info); 22449851ca0SDmitry Torokhov return 0; 22549851ca0SDmitry Torokhov } 22649851ca0SDmitry Torokhov 22749851ca0SDmitry Torokhov static int xenkbd_connect_backend(struct xenbus_device *dev, 22849851ca0SDmitry Torokhov struct xenkbd_info *info) 22949851ca0SDmitry Torokhov { 23049851ca0SDmitry Torokhov int ret, evtchn; 23149851ca0SDmitry Torokhov struct xenbus_transaction xbt; 23249851ca0SDmitry Torokhov 23349851ca0SDmitry Torokhov ret = gnttab_grant_foreign_access(dev->otherend_id, 23449851ca0SDmitry Torokhov virt_to_mfn(info->page), 0); 23549851ca0SDmitry Torokhov if (ret < 0) 23649851ca0SDmitry Torokhov return ret; 23749851ca0SDmitry Torokhov info->gref = ret; 23849851ca0SDmitry Torokhov 23949851ca0SDmitry Torokhov ret = xenbus_alloc_evtchn(dev, &evtchn); 24049851ca0SDmitry Torokhov if (ret) 24149851ca0SDmitry Torokhov goto error_grant; 24249851ca0SDmitry Torokhov ret = bind_evtchn_to_irqhandler(evtchn, input_handler, 24349851ca0SDmitry Torokhov 0, dev->devicetype, info); 24449851ca0SDmitry Torokhov if (ret < 0) { 24549851ca0SDmitry Torokhov xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); 24649851ca0SDmitry Torokhov goto error_evtchan; 24749851ca0SDmitry Torokhov } 24849851ca0SDmitry Torokhov info->irq = ret; 24949851ca0SDmitry Torokhov 25049851ca0SDmitry Torokhov again: 25149851ca0SDmitry Torokhov ret = xenbus_transaction_start(&xbt); 25249851ca0SDmitry Torokhov if (ret) { 25349851ca0SDmitry Torokhov xenbus_dev_fatal(dev, ret, "starting transaction"); 25449851ca0SDmitry Torokhov goto error_irqh; 25549851ca0SDmitry Torokhov } 25649851ca0SDmitry Torokhov ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", 25749851ca0SDmitry Torokhov virt_to_mfn(info->page)); 25849851ca0SDmitry Torokhov if (ret) 25949851ca0SDmitry Torokhov goto error_xenbus; 26049851ca0SDmitry Torokhov ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); 26149851ca0SDmitry Torokhov if (ret) 26249851ca0SDmitry Torokhov goto error_xenbus; 26349851ca0SDmitry Torokhov ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", 26449851ca0SDmitry Torokhov evtchn); 26549851ca0SDmitry Torokhov if (ret) 26649851ca0SDmitry Torokhov goto error_xenbus; 26749851ca0SDmitry Torokhov ret = xenbus_transaction_end(xbt, 0); 26849851ca0SDmitry Torokhov if (ret) { 26949851ca0SDmitry Torokhov if (ret == -EAGAIN) 27049851ca0SDmitry Torokhov goto again; 27149851ca0SDmitry Torokhov xenbus_dev_fatal(dev, ret, "completing transaction"); 27249851ca0SDmitry Torokhov goto error_irqh; 27349851ca0SDmitry Torokhov } 27449851ca0SDmitry Torokhov 27549851ca0SDmitry Torokhov xenbus_switch_state(dev, XenbusStateInitialised); 27649851ca0SDmitry Torokhov return 0; 27749851ca0SDmitry Torokhov 27849851ca0SDmitry Torokhov error_xenbus: 27949851ca0SDmitry Torokhov xenbus_transaction_end(xbt, 1); 28049851ca0SDmitry Torokhov xenbus_dev_fatal(dev, ret, "writing xenstore"); 28149851ca0SDmitry Torokhov error_irqh: 28249851ca0SDmitry Torokhov unbind_from_irqhandler(info->irq, info); 28349851ca0SDmitry Torokhov info->irq = -1; 28449851ca0SDmitry Torokhov error_evtchan: 28549851ca0SDmitry Torokhov xenbus_free_evtchn(dev, evtchn); 28649851ca0SDmitry Torokhov error_grant: 28749851ca0SDmitry Torokhov gnttab_end_foreign_access_ref(info->gref, 0); 28849851ca0SDmitry Torokhov info->gref = -1; 28949851ca0SDmitry Torokhov return ret; 29049851ca0SDmitry Torokhov } 29149851ca0SDmitry Torokhov 29249851ca0SDmitry Torokhov static void xenkbd_disconnect_backend(struct xenkbd_info *info) 29349851ca0SDmitry Torokhov { 29449851ca0SDmitry Torokhov if (info->irq >= 0) 29549851ca0SDmitry Torokhov unbind_from_irqhandler(info->irq, info); 29649851ca0SDmitry Torokhov info->irq = -1; 29749851ca0SDmitry Torokhov if (info->gref >= 0) 29849851ca0SDmitry Torokhov gnttab_end_foreign_access_ref(info->gref, 0); 29949851ca0SDmitry Torokhov info->gref = -1; 30049851ca0SDmitry Torokhov } 30149851ca0SDmitry Torokhov 30249851ca0SDmitry Torokhov static void xenkbd_backend_changed(struct xenbus_device *dev, 30349851ca0SDmitry Torokhov enum xenbus_state backend_state) 30449851ca0SDmitry Torokhov { 30549851ca0SDmitry Torokhov struct xenkbd_info *info = dev_get_drvdata(&dev->dev); 306c36b58e8SIgor Mammedov int ret, val; 30749851ca0SDmitry Torokhov 30849851ca0SDmitry Torokhov switch (backend_state) { 30949851ca0SDmitry Torokhov case XenbusStateInitialising: 31049851ca0SDmitry Torokhov case XenbusStateInitialised: 31149851ca0SDmitry Torokhov case XenbusStateReconfiguring: 31249851ca0SDmitry Torokhov case XenbusStateReconfigured: 31349851ca0SDmitry Torokhov case XenbusStateUnknown: 31449851ca0SDmitry Torokhov break; 31549851ca0SDmitry Torokhov 31649851ca0SDmitry Torokhov case XenbusStateInitWait: 31749851ca0SDmitry Torokhov InitWait: 318c36b58e8SIgor Mammedov ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, 319c36b58e8SIgor Mammedov "feature-abs-pointer", "%d", &val); 320c36b58e8SIgor Mammedov if (ret < 0) 321c36b58e8SIgor Mammedov val = 0; 322c36b58e8SIgor Mammedov if (val) { 323c36b58e8SIgor Mammedov ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, 324c36b58e8SIgor Mammedov "request-abs-pointer", "1"); 325c36b58e8SIgor Mammedov if (ret) 326c36b58e8SIgor Mammedov pr_warning("xenkbd: can't request abs-pointer"); 327c36b58e8SIgor Mammedov } 328c36b58e8SIgor Mammedov 32949851ca0SDmitry Torokhov xenbus_switch_state(dev, XenbusStateConnected); 33049851ca0SDmitry Torokhov break; 33149851ca0SDmitry Torokhov 33249851ca0SDmitry Torokhov case XenbusStateConnected: 33349851ca0SDmitry Torokhov /* 33449851ca0SDmitry Torokhov * Work around xenbus race condition: If backend goes 33549851ca0SDmitry Torokhov * through InitWait to Connected fast enough, we can 33649851ca0SDmitry Torokhov * get Connected twice here. 33749851ca0SDmitry Torokhov */ 33849851ca0SDmitry Torokhov if (dev->state != XenbusStateConnected) 33949851ca0SDmitry Torokhov goto InitWait; /* no InitWait seen yet, fudge it */ 34049851ca0SDmitry Torokhov 34149851ca0SDmitry Torokhov /* Set input abs params to match backend screen res */ 34249851ca0SDmitry Torokhov if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, 34349851ca0SDmitry Torokhov "width", "%d", &val) > 0) 34449851ca0SDmitry Torokhov input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); 34549851ca0SDmitry Torokhov 34649851ca0SDmitry Torokhov if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, 34749851ca0SDmitry Torokhov "height", "%d", &val) > 0) 34849851ca0SDmitry Torokhov input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); 34949851ca0SDmitry Torokhov 35049851ca0SDmitry Torokhov break; 35149851ca0SDmitry Torokhov 3522ebb939aSDavid Vrabel case XenbusStateClosed: 3532ebb939aSDavid Vrabel if (dev->state == XenbusStateClosed) 3542ebb939aSDavid Vrabel break; 3552ebb939aSDavid Vrabel /* Missed the backend's CLOSING state -- fallthrough */ 35649851ca0SDmitry Torokhov case XenbusStateClosing: 35749851ca0SDmitry Torokhov xenbus_frontend_closed(dev); 35849851ca0SDmitry Torokhov break; 35949851ca0SDmitry Torokhov } 36049851ca0SDmitry Torokhov } 36149851ca0SDmitry Torokhov 36249851ca0SDmitry Torokhov static const struct xenbus_device_id xenkbd_ids[] = { 36349851ca0SDmitry Torokhov { "vkbd" }, 36449851ca0SDmitry Torokhov { "" } 36549851ca0SDmitry Torokhov }; 36649851ca0SDmitry Torokhov 36773db144bSJan Beulich static DEFINE_XENBUS_DRIVER(xenkbd, , 36849851ca0SDmitry Torokhov .probe = xenkbd_probe, 36949851ca0SDmitry Torokhov .remove = xenkbd_remove, 37049851ca0SDmitry Torokhov .resume = xenkbd_resume, 37149851ca0SDmitry Torokhov .otherend_changed = xenkbd_backend_changed, 37273db144bSJan Beulich ); 37349851ca0SDmitry Torokhov 37449851ca0SDmitry Torokhov static int __init xenkbd_init(void) 37549851ca0SDmitry Torokhov { 3765f098ecdSStefano Stabellini if (!xen_domain()) 37749851ca0SDmitry Torokhov return -ENODEV; 37849851ca0SDmitry Torokhov 37949851ca0SDmitry Torokhov /* Nothing to do if running in dom0. */ 38049851ca0SDmitry Torokhov if (xen_initial_domain()) 38149851ca0SDmitry Torokhov return -ENODEV; 38249851ca0SDmitry Torokhov 38349851ca0SDmitry Torokhov return xenbus_register_frontend(&xenkbd_driver); 38449851ca0SDmitry Torokhov } 38549851ca0SDmitry Torokhov 38649851ca0SDmitry Torokhov static void __exit xenkbd_cleanup(void) 38749851ca0SDmitry Torokhov { 38849851ca0SDmitry Torokhov xenbus_unregister_driver(&xenkbd_driver); 38949851ca0SDmitry Torokhov } 39049851ca0SDmitry Torokhov 39149851ca0SDmitry Torokhov module_init(xenkbd_init); 39249851ca0SDmitry Torokhov module_exit(xenkbd_cleanup); 39349851ca0SDmitry Torokhov 39449851ca0SDmitry Torokhov MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); 39549851ca0SDmitry Torokhov MODULE_LICENSE("GPL"); 39649851ca0SDmitry Torokhov MODULE_ALIAS("xen:vkbd"); 397