/* * Some defines to define the behavior of the program */ #define CLEAN_FBDEV #undef DEMO_CLONE #define SIZE_X 2048 #define SIZE_Y 2048 /* Pitch needs to be power of two */ #define PITCH 2048 #include #include #include #include #include #include #ifdef CLEAN_FBDEV #include #include #include #include #endif #include #include "xf86drm.h" #include "xf86drmMode.h" /* old functions to be replaced */ drmModeFBPtr createFB(int fd, drmModeResPtr res); void testCursor(int fd, uint32_t crtc); void prettyColors(int fd, unsigned int handle); void prettyCursor(int fd, unsigned int handle, unsigned int color); #ifdef CLEAN_FBDEV struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; #endif /* structs for the demo_driver */ struct demo_driver; struct demo_screen { /* drm stuff */ drmBO buffer; drmModeFBPtr fb; drmModeCrtcPtr crtc; size_t num_outputs; uint32_t outputs_id[8]; drmModeOutputPtr outputs[8]; struct drm_mode_modeinfo *mode; /* virtual buffer */ uint32_t virt_x; uint32_t virt_y; uint32_t pitch; /* parent */ struct demo_driver *driver; }; #define DEMO_MAX_SCREENS 4 #define MAX_FIND_OUTPUTS 8 struct demo_driver { /* drm stuff */ int fd; drmModeResPtr res; /* screens */ size_t numScreens; struct demo_screen screens[DEMO_MAX_SCREENS]; }; struct demo_driver* demoCreateDriver(void); void demoUpdateRes(struct demo_driver *driver); int demoCreateScreens(struct demo_driver *driver); int demoCreateScreenCloned(struct demo_driver *driver); void demoTakeDownScreen(struct demo_screen *screen); int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out); drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output); void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y); /* yet to be implemented */ void demoMouseActivate(struct demo_screen *screen); void demoMouseMove(struct demo_screen *screen, uint16_t x, uint16_t y); static struct drm_mode_modeinfo mode = { .name = "Test mode", .clock = 25200, .hdisplay = 640, .hsync_start = 656, .hsync_end = 752, .htotal = 800, .hskew = 0, .vdisplay = 480, .vsync_start = 490, .vsync_end = 492, .vtotal = 525, .vscan = 0, .vrefresh = 60000, /* vertical refresh * 1000 */ .flags = 10, }; int main(int argc, char **argv) { struct demo_driver *driver; int num; int i; #ifdef CLEAN_FBDEV int fbdev_fd; fbdev_fd = open("/dev/fb0", O_RDWR); memset(&var, 0, sizeof(struct fb_var_screeninfo)); memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &var)) printf("var %s\n", strerror(errno)); if (ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fix)) printf("fix %s\n", strerror(errno)); #endif printf("starting demo\n"); driver = demoCreateDriver(); if (!driver) { printf("failed to create driver\n"); return 1; } #ifndef DEMO_CLONE num = demoCreateScreens(driver); #else num = demoCreateScreenCloned(driver); #endif if (num < 1) { printf("no screens attached or an error occured\n"); return 1; } printf("created %i screens\n", num); for (i = 0; i < num; i++) { prettyColors(driver->fd, driver->screens[i].fb->handle); } sleep(1); for (i = 0; i < num; i++) { printf("%i: 100 0\n", i); demoPanScreen(&driver->screens[i], 100, 0); sleep(1); printf("%i: 0 100\n", i); demoPanScreen(&driver->screens[i], 0, 100); sleep(1); printf("%i: 100 100\n", i); demoPanScreen(&driver->screens[i], 100, 100); sleep(1); printf("%i: 0 0\n", i); demoPanScreen(&driver->screens[i], 0, 1); sleep(1); testCursor(driver->fd, driver->screens[i].crtc->crtc_id); } sleep(2); printf("taking down screens\n"); for (i = 0; i < num; i++) { demoTakeDownScreen(&driver->screens[i]); } #ifdef CLEAN_FBDEV if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var)) printf("var %s\n", strerror(errno)); close(fbdev_fd); #endif printf("ok\n"); return 0; } int demoCreateScreens(struct demo_driver *driver) { drmModeOutputPtr out[MAX_FIND_OUTPUTS]; int num; int num_screens = 0; struct demo_screen *screen; int ret = 0; int i; num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS); if (num < 0) return 0; printf("found %i connected outputs\n", num); for (i = 0; i < num; i++) { screen = &driver->screens[i]; screen->crtc = demoFindFreeCrtc(driver, out[i]); if (!screen->crtc) { printf("found no free crtc for output\n"); drmModeFreeOutput(out[i]); continue; } screen->fb = createFB(driver->fd, driver->res); if (!screen->fb) { drmModeFreeOutput(out[i]); drmModeFreeCrtc(screen->crtc); screen->crtc = 0; printf("could not create framebuffer\n"); continue; } screen->virt_x = SIZE_X; screen->virt_y = SIZE_Y; screen->pitch = PITCH; screen->outputs[0] = out[i]; screen->outputs_id[0] = out[i]->output_id; screen->num_outputs = 1; screen->mode = &mode; screen->driver = driver; ret = drmModeSetCrtc( driver->fd, screen->crtc->crtc_id, screen->fb->buffer_id, 0, 0, screen->outputs_id, screen->num_outputs, screen->mode); if (ret) { printf("failed to set mode\n"); demoTakeDownScreen(screen); } else { num_screens++; } demoUpdateRes(driver); } return num_screens; } int demoCreateScreenCloned(struct demo_driver *driver) { drmModeOutputPtr out[MAX_FIND_OUTPUTS]; int num; struct demo_screen *screen; int ret = 0; int i; num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS); if (num < 0) return 0; printf("found %i connected outputs\n", num); screen = &driver->screens[0]; screen->fb = createFB(driver->fd, driver->res); if (!screen->fb) { printf("could not create framebuffer\n"); return 0; } screen->mode = &mode; screen->driver = driver; screen->virt_x = SIZE_X; screen->virt_y = SIZE_Y; screen->pitch = PITCH; screen->num_outputs = 0; for (i = 0; i < num; i++) { screen->crtc = demoFindFreeCrtc(driver, out[i]); if (!screen->crtc) { printf("found no free crtc for output\n"); drmModeFreeOutput(out[i]); continue; } screen->outputs[screen->num_outputs] = out[i]; screen->outputs_id[screen->num_outputs] = out[i]->output_id; screen->num_outputs++; printf("%u, %u\n", out[i]->output_id, screen->num_outputs); } ret = drmModeSetCrtc( driver->fd, screen->crtc->crtc_id, screen->fb->buffer_id, 0, 0, screen->outputs_id, screen->num_outputs, screen->mode); if (ret) { printf("failed to set mode\n"); demoTakeDownScreen(screen); return 0; } demoUpdateRes(driver); return 1; } void demoTakeDownScreen(struct demo_screen *screen) { int fd = screen->driver->fd; int i; drmBO bo; #if 0 /* This can bust the fbdev arrangement as it basically unhooks * the outputs and the fbdev backend doesn't know how to put things * back on track. Realistically, it's up to the crtc owner to restore * things..... * * So if you are mixing API's make sure the modesetting owner puts * back the original CRTC arrangement so fbdev can continue... * * Ho-hum.. */ if (screen->crtc) drmModeSetCrtc(fd, screen->crtc->crtc_id, 0, 0, 0, 0, 0, 0); #endif if (screen->fb) drmModeRmFB(fd, screen->fb->buffer_id); /* maybe we should keep a pointer to the bo on the screen */ if (screen->fb && !drmBOReference(fd, screen->fb->handle, &bo)) { drmBOUnreference(fd, &bo); drmBOUnreference(fd, &bo); } else { printf("bo error\n"); } for (i = 0; i < screen->num_outputs; i++) { drmModeFreeOutput(screen->outputs[i]); screen->outputs[i] = NULL; } drmModeFreeCrtc(screen->crtc); drmModeFreeFB(screen->fb); screen->crtc = NULL; screen->fb = NULL; } drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output) { drmModeCrtcPtr crtc; int i, j, used = 0; drmModeResPtr res = driver->res; for (i = 0; i < res->count_crtcs; i++) { used = 0; for (j = 0; j < DEMO_MAX_SCREENS; j++) { crtc = driver->screens[j].crtc; if (crtc && crtc->crtc_id == res->crtcs[i]) used = 1; } if (!used) { crtc = drmModeGetCrtc(driver->fd, res->crtcs[i]); break; } else { crtc = 0; } } return crtc; } static int driverfd; static void hotplugSIGNAL(int sig, siginfo_t *si, void *d) { union drm_wait_hotplug hw; int ret; printf("GOT HOTPLUG EVENT!\n"); /* ask for another hotplug event ! */ memset(&hw, 0, sizeof(hw)); hw.request.type = _DRM_HOTPLUG_SIGNAL; hw.request.signal = SIGUSR1; ret = ioctl(driverfd, DRM_IOCTL_WAIT_HOTPLUG, &hw); } struct demo_driver* demoCreateDriver(void) { struct demo_driver* driver = malloc(sizeof(struct demo_driver)); union drm_wait_hotplug hw; int ret = 0; memset(driver, 0, sizeof(struct demo_driver)); driver->fd = drmOpen("i915",NULL); if (driver->fd < 0) { printf("Failed to open the card fb\n"); goto err_driver; } #if 0 /* ioctl wait for hotplug */ do { memset(&hw, 0, sizeof(hw)); ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw); printf("HOTPLUG %d %d %d\n",ret,errno,hw.reply.counter); } while (ret && errno == EBUSY); #else /* signal for hotplug */ { struct sigaction sa; struct sigaction osa; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = hotplugSIGNAL; sigaction(SIGUSR1, &sa, &osa); driverfd = driver->fd; memset(&hw, 0, sizeof(hw)); hw.request.type = _DRM_HOTPLUG_SIGNAL; hw.request.signal = SIGUSR1; ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw); } #endif demoUpdateRes(driver); if (!driver->res) { printf("could not retrive resources\n"); goto err_res; } return driver; err_res: drmClose(driver->fd); err_driver: free(driver); return NULL; } void demoUpdateRes(struct demo_driver *driver) { if (driver->res) drmModeFreeResources(driver->res); driver->res = drmModeGetResources(driver->fd); if (!driver->res) printf("failed to get resources from kernel\n"); } int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out) { int count = 0; int i,j; int fd = driver->fd; drmModeResPtr res = driver->res; drmModeOutputPtr output; for (i = 0; i < res->count_outputs && count < max_out; i++) { output = drmModeGetOutput(fd, res->outputs[i]); if (!output) continue; if (output->connection == DRM_MODE_DISCONNECTED) { drmModeFreeOutput(output); continue; } for (j = 0; j < output->count_props; j++) { drmModePropertyPtr prop; prop = drmModeGetProperty(fd, output->props[j]); printf("Property: %s\n",prop->name); if (prop->count_enums) printf("%s\n",prop->enums[output->prop_values[j]].name); } out[count++] = output; } return count; } void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y) { drmModeSetCrtc( screen->driver->fd, screen->crtc->crtc_id, screen->fb->buffer_id, x, y, screen->outputs_id, screen->num_outputs, screen->mode); } drmModeFBPtr createFB(int fd, drmModeResPtr res) { drmModeFBPtr frame; unsigned int fb = 0; int ret = 0; drmBO bo; ret = drmBOCreate(fd, SIZE_X * SIZE_Y * 4, 0, 0, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_NO_EVICT, DRM_BO_HINT_DONT_FENCE, &bo); if (ret) { printf("failed to create framebuffer (ret %d)\n",ret); goto err; } ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, bo.handle, &fb); if (ret) goto err_bo; frame = drmModeGetFB(fd, fb); if (!frame) goto err_bo; return frame; err_bo: drmBOUnreference(fd, &bo); err: return 0; } void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) { int i, j; for (i = x; i < x + w; i++) for(j = y; j < y + h; j++) ptr[(i * PITCH) + j] = v; } void prettyColors(int fd, unsigned int handle) { drmBO bo; unsigned int *ptr; int i; drmBOReference(fd, handle, &bo); drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); for (i = 0; i < (SIZE_X*SIZE_Y); i++) ptr[i] = 0xFFFFFFFF; for (i = 0; i < 8; i++) draw(i * 40, i * 40, 40, 40, 0, ptr); draw(200, 100, 40, 40, 0xff00ff, ptr); draw(100, 200, 40, 40, 0xff00ff, ptr); drmBOUnmap(fd, &bo); } void testCursor(int fd, uint32_t crtc) { drmBO bo; int ret; ret = drmBOCreate(fd, 64 * 64 * 4, 0, 0, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_NO_EVICT, DRM_BO_HINT_DONT_FENCE, &bo); prettyCursor(fd, bo.handle, 0xFFFF00FF); printf("set cursor\n"); drmModeSetCursor(fd, crtc, bo.handle, 64, 64); printf("move cursor 0, 0\n"); drmModeMoveCursor(fd, crtc, 0, 0); sleep(1); prettyCursor(fd, bo.handle, 0xFFFF0000); printf("move cursor 40, 40\n"); drmModeMoveCursor(fd, crtc, 40, 40); sleep(1); printf("move cursor 100, 100\n"); drmModeMoveCursor(fd, crtc, 100, 100); sleep(1); drmModeSetCursor(fd, crtc, 0, 0, 0); } void prettyCursor(int fd, unsigned int handle, unsigned int color) { drmBO bo; unsigned int *ptr; int i; drmBOReference(fd, handle, &bo); drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); for (i = 0; i < (64 * 64); i++) ptr[i] = color; drmBOUnmap(fd, &bo); drmBOUnreference(fd, &bo); }