/* * Xen para-virtual input device * * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> * * Based on linux/drivers/input/mouse/sermouse.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details.
*/
struct xenkbd_info { struct input_dev *kbd; struct input_dev *ptr; struct input_dev *mtouch; struct xenkbd_page *page; int gref; int irq; struct xenbus_device *xbdev; char phys[32]; /* current MT slot/contact ID we are injecting events in */ int mtouch_cur_contact_id;
};
prod = page->in_prod; if (prod == page->in_cons) return IRQ_HANDLED;
rmb(); /* ensure we see ring contents up to prod */ for (cons = page->in_cons; cons != prod; cons++)
xenkbd_handle_event(info, &XENKBD_IN_RING_REF(page, cons));
mb(); /* ensure we got ring contents */
page->in_cons = cons;
notify_remote_via_irq(info->irq);
info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); return -ENOMEM;
}
dev_set_drvdata(&dev->dev, info);
info->xbdev = dev;
info->irq = -1;
info->gref = -1;
snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); if (!info->page) goto error_nomem;
/* * The below are reverse logic, e.g. if the feature is set, then * do not expose the corresponding virtual device.
*/
with_kbd = !xenbus_read_unsigned(dev->otherend,
XENKBD_FIELD_FEAT_DSBL_KEYBRD, 0);
__set_bit(EV_KEY, kbd->evbit); for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
__set_bit(i, kbd->keybit); for (i = KEY_OK; i < KEY_MAX; i++)
__set_bit(i, kbd->keybit);
ret = input_register_device(kbd); if (ret) {
input_free_device(kbd);
xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); goto error;
}
info->kbd = kbd;
}
/* pointing device */ if (with_ptr) { unsignedint abs;
/* Set input abs params to match backend screen res */
abs = xenbus_read_unsigned(dev->otherend,
XENKBD_FIELD_FEAT_ABS_POINTER, 0);
ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend,
XENKBD_FIELD_WIDTH,
ptr_size[KPARAM_X]);
ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend,
XENKBD_FIELD_HEIGHT,
ptr_size[KPARAM_Y]); if (abs) {
ret = xenbus_write(XBT_NIL, dev->nodename,
XENKBD_FIELD_REQ_ABS_POINTER, "1"); if (ret) {
pr_warn("xenkbd: can't request abs-pointer\n");
abs = 0;
}
}
xenkbd_disconnect_backend(info); if (info->kbd)
input_unregister_device(info->kbd); if (info->ptr)
input_unregister_device(info->ptr); if (info->mtouch)
input_unregister_device(info->mtouch);
free_page((unsignedlong)info->page);
kfree(info);
}
staticvoid xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state)
{ switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: break;
case XenbusStateInitWait:
xenbus_switch_state(dev, XenbusStateConnected); break;
case XenbusStateConnected: /* * Work around xenbus race condition: If backend goes * through InitWait to Connected fast enough, we can * get Connected twice here.
*/ if (dev->state != XenbusStateConnected)
xenbus_switch_state(dev, XenbusStateConnected); break;
case XenbusStateClosed: if (dev->state == XenbusStateClosed) break;
fallthrough; /* Missed the backend's CLOSING state */ case XenbusStateClosing:
xenbus_frontend_closed(dev); break;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.