📄 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,RSB,GSB,BSB,RDB,GDB,BDB) \ for (line = y ; line < (y+h) ; line++) { \ SRC_T *src = (SRC_T *)(xenfb->pixels \ + xenfb->offset \ + (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; \ const int RSS = 32 - (RSB + GSB + BSB); \ const int GSS = 32 - (GSB + BSB); \ const int BSS = 32 - (BSB); \ const uint32_t RSM = (~0U) << (32 - RSB); \ const uint32_t GSM = (~0U) << (32 - GSB); \ const uint32_t BSM = (~0U) << (32 - BSB); \ const int RDS = 32 - (RDB + GDB + BDB); \ const int GDS = 32 - (GDB + BDB); \ const int BDS = 32 - (BDB); \ const uint32_t RDM = (~0U) << (32 - RDB); \ const uint32_t GDM = (~0U) << (32 - GDB); \ const uint32_t BDM = (~0U) << (32 - BDB); \ for (col = x ; col < (x+w) ; col++) { \ uint32_t spix = *src; \ *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \ (((spix << GSS) & GSM & GDM) >> GDS) | \ (((spix << BSS) & BSM & BDM) >> BDS); \ src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \ dst = (DST_T *) ((unsigned long) dst + xenfb->ds->depth / 8); \ } \ }/* 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->ds->shared_buf) { 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 + xenfb->offset + (line * xenfb->row_stride) + (x * xenfb->depth / 8), w * xenfb->depth / 8); } } else { /* Mismatch requires slow pixel munging */ /* 8 bit == r:3 g:3 b:2 */ /* 16 bit == r:5 g:6 b:5 */ /* 24 bit == r:8 g:8 b:8 */ /* 32 bit == r:8 g:8 b:8 (padding:8) */ if (xenfb->depth == 8) { if (xenfb->ds->depth == 16) { BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5); } else if (xenfb->ds->depth == 32) { BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8); } } else if (xenfb->depth == 16) { if (xenfb->ds->depth == 8) { BLT(uint16_t, uint8_t, 5, 6, 5, 3, 3, 2); } else if (xenfb->ds->depth == 32) { BLT(uint16_t, uint32_t, 5, 6, 5, 8, 8, 8); } } else if (xenfb->depth == 24 || xenfb->depth == 32) { if (xenfb->ds->depth == 8) { BLT(uint32_t, uint8_t, 8, 8, 8, 3, 3, 2); } else if (xenfb->ds->depth == 16) { BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5); } else if (xenfb->ds->depth == 32) { BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8); } } } } dpy_update(xenfb->ds, x, y, w, h);}/* Periodic update of display, transmit the refresh interval to the frontend */static void xenfb_update(void *opaque){ struct xenfb *xenfb = opaque; int period; if (xenfb_queue_full(xenfb)) return; if (xenfb->ds->idle) period = XENFB_NO_REFRESH; else { period = xenfb->ds->gui_timer_interval; if (!period) period = GUI_REFRESH_INTERVAL; } /* Will have to be disabled for frontends without feature-update */ if (xenfb->refresh_period != period) { xenfb_send_refresh_period(xenfb, period); xenfb->refresh_period = period; }}/* 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); if (xenfb->ds->dpy_resize_shared) dpy_resize_shared(xenfb->ds, xenfb->width, xenfb->height, xenfb->depth, xenfb->row_stride, xenfb->pixels + xenfb->offset); else 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 + -