📄 xenfb.c
字号:
} if (ret) return; /* Still waiting */ if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, "feature-abs-pointer", "1")) { xenfb_shutdown(dev->xenfb); exit(1); } fprintf(stderr, "FB: Waiting for FB backend creation\n"); xenfb_wait_for_backend(&dev->xenfb->fb, xenfb_backend_created_fb);}/* Callback invoked while waiting for FB backend to change * to the created state */static void xenfb_backend_created_fb(void *opaque){ struct xenfb_device *dev = (struct xenfb_device *)opaque; int ret = xenfb_backend_created(dev); if (ret < 0) { xenfb_shutdown(dev->xenfb); exit(1); } if (ret) return; /* Still waiting */ fprintf(stderr, "FB: Waiting for KBD frontend initialization\n"); xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_initialized_kbd);}/* Callback invoked while waiting for KBD frontend to change * to the initialized state */static void xenfb_frontend_initialized_kbd(void *opaque){ struct xenfb_device *dev = (struct xenfb_device *)opaque; int ret = xenfb_frontend_initialized(dev); if (ret < 0) { xenfb_shutdown(dev->xenfb); exit(1); } if (ret) return; /* Still waiting */ fprintf(stderr, "FB: Waiting for FB frontend initialization\n"); xenfb_wait_for_frontend(&dev->xenfb->fb, xenfb_frontend_initialized_fb);}/* Callback invoked while waiting for FB frontend to change * to the initialized state */static void xenfb_frontend_initialized_fb(void *opaque){ struct xenfb_device *dev = (struct xenfb_device *)opaque; int ret = xenfb_frontend_initialized(dev); if (ret < 0) { xenfb_shutdown(dev->xenfb); exit(1); } if (ret) return; /* Still waiting */ if (xenfb_read_frontend_fb_config(dev->xenfb)) { xenfb_shutdown(dev->xenfb); exit(1); } fprintf(stderr, "FB: Waiting for KBD frontend connection\n"); xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_connected_kbd);}/* Callback invoked while waiting for KBD frontend to change * to the connected state */static void xenfb_frontend_connected_kbd(void *opaque){ struct xenfb_device *dev = (struct xenfb_device *)opaque; int ret = xenfb_frontend_connected(dev); if (ret < 0) { xenfb_shutdown(dev->xenfb); exit(1); } if (ret) return; /* Still waiting */ if (xenfb_read_frontend_kbd_config(dev->xenfb) < 0) { xenfb_shutdown(dev->xenfb); exit(1); } xenfb_register_console(dev->xenfb);}/**************************************************************** * * Helper functions for checking state of frontend/backend devices * ****************************************************************//* Helper to determine if a frontend device is in Connected state */static int xenfb_frontend_connected(struct xenfb_device *dev){ unsigned int state; unsigned int dummy; char **vec; vec = xs_read_watch(dev->xenfb->xsh, &dummy); if (!vec) return -1; free(vec); state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); if (!((1 <<state) & ((1 << XenbusStateUnknown) | (1 << XenbusStateConnected)))) { fprintf(stderr, "FB: Carry on waiting\n"); return 1; } /* Don't unwatch frontend - we need to detect shutdown */ /*xs_unwatch(dev->xenfb->xsh, dev->otherend, "");*/ switch (state) { case XenbusStateConnected: break; default: return -1; } return 0;}/* Helper to determine if a frontend device is in Initialized state */static int xenfb_frontend_initialized(struct xenfb_device *dev){ unsigned int state; unsigned int dummy; char **vec; vec = xs_read_watch(dev->xenfb->xsh, &dummy); if (!vec) return -1; free(vec); state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); if (!((1 << state) & ((1 << XenbusStateUnknown) | (1 << XenbusStateInitialised)#if 1 /* TODO fudging state to permit restarting; to be removed */ | (1 << XenbusStateConnected)#endif ))) { fprintf(stderr, "FB: Carry on waiting\n"); return 1; } xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); switch (state) {#if 1 case XenbusStateConnected: printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */#endif case XenbusStateInitialised: break; default: return -1; } if (xenfb_bind(dev) < 0) return -1; return 0;}/* Helper to determine if a backend device is in Created state */static int xenfb_backend_created(struct xenfb_device *dev){ unsigned int state; unsigned int dummy; char **vec; vec = xs_read_watch(dev->xenfb->xsh, &dummy); if (!vec) return -1; free(vec); state = xenfb_read_state(dev->xenfb->xsh, dev->nodename); if (!((1 <<state) & ((1 << XenbusStateUnknown) | (1 << XenbusStateInitialising) | (1 << XenbusStateClosed)#if 1 /* TODO fudging state to permit restarting; to be removed */ | (1 << XenbusStateInitWait) | (1 << XenbusStateConnected) | (1 << XenbusStateClosing)#endif ))) { fprintf(stderr, "FB: Carry on waiting\n"); return 1; } xs_unwatch(dev->xenfb->xsh, dev->nodename, ""); switch (state) {#if 1 case XenbusStateInitWait: case XenbusStateConnected: printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */#endif case XenbusStateInitialising: case XenbusStateClosing: case XenbusStateClosed: break; default: fprintf(stderr, "Wrong state %d\n", state); return -1; } xenfb_switch_state(dev, XenbusStateInitWait); if (xenfb_hotplug(dev) < 0) return -1; return 0;}/**************************************************************** * * QEMU device model integration functions * ****************************************************************//* * Send a key event from the client to the guest OS * QEMU gives us a raw scancode from an AT / PS/2 style keyboard. * We have to turn this into a Linux Input layer keycode. * * Extra complexity from the fact that with extended scancodes * (like those produced by arrow keys) this method gets called * twice, but we only want to send a single event. So we have to * track the '0xe0' scancode state & collapse the extended keys * as needed. * * Wish we could just send scancodes straight to the guest which * already has code for dealing with this... */static void xenfb_key_event(void *opaque, int scancode){ static int extended = 0; int down = 1; if (scancode == 0xe0) { extended = 1; return; } else if (scancode & 0x80) { scancode &= 0x7f; down = 0; } if (extended) { scancode |= 0x80; extended = 0; } xenfb_send_key(opaque, down, scancode2linux[scancode]);}/* * Send a mouse event from the client to the guest OS * * The QEMU mouse can be in either relative, or absolute mode. * Movement is sent separately from button state, which has to * be encoded as virtual key events. We also don't actually get * given any button up/down events, so have to track changes in * the button state. */static void xenfb_mouse_event(void *opaque, int dx, int dy, int dz, int button_state){ int i; struct xenfb *xenfb = opaque; if (xenfb->abs_pointer_wanted) xenfb_send_position(xenfb, dx * (xenfb->ds->width - 1) / 0x7fff, dy * (xenfb->ds->height - 1) / 0x7fff, dz); else xenfb_send_motion(xenfb, dx, dy, dz); for (i = 0 ; i < 8 ; i++) { int lastDown = xenfb->button_state & (1 << i); int down = button_state & (1 << i); if (down == lastDown) continue; if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) return; } xenfb->button_state = button_state;}/* A convenient function for munging pixels between different depths */#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \ for (line = y ; line < h ; line++) { \ SRC_T *src = (SRC_T *)(xenfb->pixels \ + (line * xenfb->row_stride) \ + (x * xenfb->depth / 8)); \ DST_T *dst = (DST_T *)(xenfb->ds->data \ + (line * xenfb->ds->linesize) \ + (x * xenfb->ds->depth / 8)); \ int col; \ for (col = x ; col < w ; col++) { \ *dst = (((*src >> RRS) & RM) << RLS) | \ (((*src >> GRS) & GM) << GLS) | \ (((*src >> GRS) & BM) << BLS); \ src++; \ dst++; \ } \ }/* This copies data from the guest framebuffer region, into QEMU's copy * NB. QEMU's copy is stored in the pixel format of a) the local X * server (SDL case) or b) the current VNC client pixel format. * When shifting between colour depths we preserve the MSB. */static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h){ int line; if (xenfb->depth == xenfb->ds->depth) { /* Perfect match can use fast path */ for (line = y ; line < (y+h) ; line++) { memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x * xenfb->ds->depth / 8), xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8), w * xenfb->depth / 8); } } else { /* Mismatch requires slow pixel munging */ if (xenfb->depth == 8) { /* 8 bit source == r:3 g:3 b:2 */ if (xenfb->ds->depth == 16) { BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3); } else if (xenfb->ds->depth == 32) { BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3); } } else if (xenfb->depth == 16) { /* 16 bit source == r:5 g:6 b:5 */ if (xenfb->ds->depth == 8) { BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31); } else if (xenfb->ds->depth == 32) { BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31); } } else if (xenfb->depth == 32) { /* 32 bit source == r:8 g:8 b:8 (padding:8) */ if (xenfb->ds->depth == 8) { BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255); } else if (xenfb->ds->depth == 16) { BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255); } } } dpy_update(xenfb->ds, x, y, w, h);}/* QEMU display state changed, so refresh the framebuffer copy *//* XXX - can we optimize this, or the next func at all ? */ static void xenfb_update(void *opaque){ struct xenfb *xenfb = opaque; xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);}/* QEMU display state changed, so refresh the framebuffer copy */static void xenfb_invalidate(void *opaque){ struct xenfb *xenfb = opaque; xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);}/* Screen dump is not used in Xen, so no need to impl this....yet */static void xenfb_screen_dump(void *opaque, const char *name) { }/* Register a QEMU graphical console, and key/mouse handler, * connecting up their events to the frontend */static int xenfb_register_console(struct xenfb *xenfb) { /* Register our keyboard & mouse handlers */ qemu_add_kbd_event_handler(xenfb_key_event, xenfb); qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, xenfb->abs_pointer_wanted, "Xen PVFB Mouse"); /* Tell QEMU to allocate a graphical console */ graphic_console_init(xenfb->ds, xenfb_update, xenfb_invalidate, xenfb_screen_dump, xenfb); dpy_resize(xenfb->ds, xenfb->width, xenfb->height); if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) return -1; if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) return -1; fprintf(stderr, "Xen Framebuffer registered\n"); return 0;}/* * Local variables: * c-indent-level: 8 * c-basic-offset: 8 * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -