int main(int argc, char **argv) { struct exynos_device *dev; struct exynos_bo *bo, *src; struct connector con; unsigned int fb_id; uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; drmModeRes *resources; int ret, fd, c; memset(&con, 0, sizeof(struct connector)); if (argc != 3) { usage(argv[0]); return -EINVAL; } while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 's': con.crtc = -1; if (sscanf(optarg, "%d:0x%64s", &con.id, con.mode_str) != 2 && sscanf(optarg, "%d@%d:%64s", &con.id, &con.crtc, con.mode_str) != 3) usage(argv[0]); break; default: usage(argv[0]); return -EINVAL; } } fd = drmOpen(DRM_MODULE_NAME, NULL); if (fd < 0) { fprintf(stderr, "failed to open.\n"); return fd; } dev = exynos_device_create(fd); if (!dev) { drmClose(dev->fd); return -EFAULT; } resources = drmModeGetResources(dev->fd); if (!resources) { fprintf(stderr, "drmModeGetResources failed: %s\n", strerror(errno)); ret = -EFAULT; goto err_drm_close; } connector_find_mode(dev->fd, &con, resources); drmModeFreeResources(resources); if (!con.mode) { fprintf(stderr, "failed to find usable connector\n"); ret = -EFAULT; goto err_drm_close; } screen_width = con.mode->hdisplay; screen_height = con.mode->vdisplay; if (screen_width == 0 || screen_height == 0) { fprintf(stderr, "failed to find sane resolution on connector\n"); ret = -EFAULT; goto err_drm_close; } printf("screen width = %d, screen height = %d\n", screen_width, screen_height); bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); if (!bo) { ret = -EFAULT; goto err_drm_close; } handles[0] = bo->handle; pitches[0] = screen_width * 4; offsets[0] = 0; ret = drmModeAddFB2(dev->fd, screen_width, screen_height, DRM_FORMAT_RGBA8888, handles, pitches, offsets, &fb_id, 0); if (ret < 0) goto err_destroy_buffer; con.plane_zpos = -1; memset(bo->vaddr, 0xff, screen_width * screen_height * 4); ret = drm_set_crtc(dev, &con, fb_id); if (ret < 0) goto err_rm_fb; ret = test_case.solid_fill(dev, bo); if (ret < 0) { fprintf(stderr, "failed to solid fill operation.\n"); goto err_rm_fb; } wait_for_user_input(0); src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); if (!src) { ret = -EFAULT; goto err_rm_fb; } ret = test_case.copy(dev, src, bo, G2D_IMGBUF_GEM); if (ret < 0) { fprintf(stderr, "failed to test copy operation.\n"); goto err_free_src; } wait_for_user_input(0); ret = test_case.copy_with_scale(dev, src, bo, G2D_IMGBUF_GEM); if (ret < 0) { fprintf(stderr, "failed to test copy and scale operation.\n"); goto err_free_src; } wait_for_user_input(0); ret = test_case.checkerboard(dev, src, bo, G2D_IMGBUF_GEM); if (ret < 0) { fprintf(stderr, "failed to issue checkerboard test.\n"); goto err_free_src; } wait_for_user_input(1); /* * The blend test uses the userptr functionality of exynos-drm, which * is currently not safe to use. If the kernel hasn't been build with * exynos-iommu support, then the blend test is going to produce (kernel) * memory corruption, eventually leading to a system crash. * * Disable the test for now, until the kernel code has been sanitized. */ #if 0 ret = test_case.blend(dev, src, bo, G2D_IMGBUF_USERPTR); if (ret < 0) fprintf(stderr, "failed to test blend operation.\n"); getchar(); #endif err_free_src: if (src) exynos_destroy_buffer(src); err_rm_fb: drmModeRmFB(dev->fd, fb_id); err_destroy_buffer: exynos_destroy_buffer(bo); err_drm_close: drmClose(dev->fd); exynos_device_destroy(dev); return 0; }
static int exynos_alloc(struct hook_data *data) { struct exynos_device *device; struct exynos_bo *bo; struct exynos_page *pages; struct drm_prime_handle req = { 0 }; unsigned i; const unsigned flags = 0; device = exynos_device_create(data->drm_fd); if (device == NULL) { fprintf(stderr, "[exynos_init] error: failed to create device from fd\n"); return -1; } pages = calloc(data->num_pages, sizeof(struct exynos_page)); if (pages == NULL) { fprintf(stderr, "[exynos_init] error: failed to allocate pages\n"); goto fail_alloc; } for (i = 0; i < data->num_pages; ++i) { bo = exynos_bo_create(device, data->size, flags); if (bo == NULL) { fprintf(stderr, "[exynos_init] error: failed to create buffer object\n"); goto fail; } req.handle = bo->handle; if (drmIoctl(data->drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &req) < 0) { fprintf(stderr, "[exynos_init] error: failed to get fd from bo\n"); exynos_bo_destroy(bo); goto fail; } /* Don't map the BO, since we don't access it through userspace. */ pages[i].bo = bo; pages[i].fd = req.fd; pages[i].base = data; pages[i].used = false; pages[i].clear = true; } if (vconf.use_screen == 1) { const uint32_t pixel_format = (data->bpp == 2) ? DRM_FORMAT_RGB565 : DRM_FORMAT_XRGB8888; uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; pitches[0] = data->pitch; offsets[0] = 0; for (i = 0; i < data->num_pages; ++i) { handles[0] = pages[i].bo->handle; if (drmModeAddFB2(data->drm_fd, data->width, data->height, pixel_format, handles, pitches, offsets, &pages[i].buf_id, flags)) { fprintf(stderr, "[exynos_init] error: failed to add bo %u to fb\n", i); goto fail; } } } if (vconf.use_screen == 1) { /* Setup CRTC: display the last allocated page. */ if (drmModeSetCrtc(data->drm_fd, data->drm->crtc_id, pages[data->num_pages - 1].buf_id, 0, 0, &data->drm->connector_id, 1, data->drm->mode)) { fprintf(stderr, "[exynos_init] error: drmModeSetCrtc failed\n"); goto fail; } } data->pages = pages; data->device = device; return 0; fail: clean_up_pages(pages, data->num_pages); fail_alloc: exynos_device_destroy(device); return -1; }