modetest.c revision 18210155
118210155Smrg/* 218210155Smrg * DRM based mode setting test program 318210155Smrg * Copyright 2008 Tungsten Graphics 418210155Smrg * Jakob Bornecrantz <jakob@tungstengraphics.com> 518210155Smrg * Copyright 2008 Intel Corporation 618210155Smrg * Jesse Barnes <jesse.barnes@intel.com> 718210155Smrg * 818210155Smrg * Permission is hereby granted, free of charge, to any person obtaining a 918210155Smrg * copy of this software and associated documentation files (the "Software"), 1018210155Smrg * to deal in the Software without restriction, including without limitation 1118210155Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1218210155Smrg * and/or sell copies of the Software, and to permit persons to whom the 1318210155Smrg * Software is furnished to do so, subject to the following conditions: 1418210155Smrg * 1518210155Smrg * The above copyright notice and this permission notice shall be included in 1618210155Smrg * all copies or substantial portions of the Software. 1718210155Smrg * 1818210155Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1918210155Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2018210155Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2118210155Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2218210155Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2318210155Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2418210155Smrg * IN THE SOFTWARE. 2518210155Smrg */ 2618210155Smrg 2718210155Smrg/* 2818210155Smrg * This fairly simple test program dumps output in a similar format to the 2918210155Smrg * "xrandr" tool everyone knows & loves. It's necessarily slightly different 3018210155Smrg * since the kernel separates outputs into encoder and connector structures, 3118210155Smrg * each with their own unique ID. The program also allows test testing of the 3218210155Smrg * memory management and mode setting APIs by allowing the user to specify a 3318210155Smrg * connector and mode to use for mode setting. If all works as expected, a 3418210155Smrg * blue background should be painted on the monitor attached to the specified 3518210155Smrg * connector after the selected mode is set. 3618210155Smrg * 3718210155Smrg * TODO: use cairo to write the mode info on the selected output once 3818210155Smrg * the mode has been programmed, along with possible test patterns. 3918210155Smrg */ 4018210155Smrg#include "config.h" 4118210155Smrg 4218210155Smrg#include <assert.h> 4318210155Smrg#include <stdio.h> 4418210155Smrg#include <stdlib.h> 4518210155Smrg#include <stdint.h> 4618210155Smrg#include <unistd.h> 4718210155Smrg#include <string.h> 4818210155Smrg#include <errno.h> 4918210155Smrg 5018210155Smrg#include "xf86drm.h" 5118210155Smrg#include "xf86drmMode.h" 5218210155Smrg#include "intel_bufmgr.h" 5318210155Smrg 5418210155Smrg#ifdef HAVE_CAIRO 5518210155Smrg#include <math.h> 5618210155Smrg#include <cairo.h> 5718210155Smrg#endif 5818210155Smrg 5918210155SmrgdrmModeRes *resources; 6018210155Smrgint fd, modes; 6118210155Smrg 6218210155Smrg#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 6318210155Smrg 6418210155Smrgstruct type_name { 6518210155Smrg int type; 6618210155Smrg char *name; 6718210155Smrg}; 6818210155Smrg 6918210155Smrg#define type_name_fn(res) \ 7018210155Smrgchar * res##_str(int type) { \ 7118210155Smrg int i; \ 7218210155Smrg for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 7318210155Smrg if (res##_names[i].type == type) \ 7418210155Smrg return res##_names[i].name; \ 7518210155Smrg } \ 7618210155Smrg return "(invalid)"; \ 7718210155Smrg} 7818210155Smrg 7918210155Smrgstruct type_name encoder_type_names[] = { 8018210155Smrg { DRM_MODE_ENCODER_NONE, "none" }, 8118210155Smrg { DRM_MODE_ENCODER_DAC, "DAC" }, 8218210155Smrg { DRM_MODE_ENCODER_TMDS, "TMDS" }, 8318210155Smrg { DRM_MODE_ENCODER_LVDS, "LVDS" }, 8418210155Smrg { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, 8518210155Smrg}; 8618210155Smrg 8718210155Smrgtype_name_fn(encoder_type) 8818210155Smrg 8918210155Smrgstruct type_name connector_status_names[] = { 9018210155Smrg { DRM_MODE_CONNECTED, "connected" }, 9118210155Smrg { DRM_MODE_DISCONNECTED, "disconnected" }, 9218210155Smrg { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, 9318210155Smrg}; 9418210155Smrg 9518210155Smrgtype_name_fn(connector_status) 9618210155Smrg 9718210155Smrgstruct type_name connector_type_names[] = { 9818210155Smrg { DRM_MODE_CONNECTOR_Unknown, "unknown" }, 9918210155Smrg { DRM_MODE_CONNECTOR_VGA, "VGA" }, 10018210155Smrg { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, 10118210155Smrg { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, 10218210155Smrg { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, 10318210155Smrg { DRM_MODE_CONNECTOR_Composite, "composite" }, 10418210155Smrg { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, 10518210155Smrg { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 10618210155Smrg { DRM_MODE_CONNECTOR_Component, "component" }, 10718210155Smrg { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, 10818210155Smrg { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, 10918210155Smrg { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 11018210155Smrg { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 11118210155Smrg}; 11218210155Smrg 11318210155Smrgtype_name_fn(connector_type) 11418210155Smrg 11518210155Smrgvoid dump_encoders(void) 11618210155Smrg{ 11718210155Smrg drmModeEncoder *encoder; 11818210155Smrg int i; 11918210155Smrg 12018210155Smrg printf("Encoders:\n"); 12118210155Smrg printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 12218210155Smrg for (i = 0; i < resources->count_encoders; i++) { 12318210155Smrg encoder = drmModeGetEncoder(fd, resources->encoders[i]); 12418210155Smrg 12518210155Smrg if (!encoder) { 12618210155Smrg fprintf(stderr, "could not get encoder %i: %s\n", 12718210155Smrg resources->encoders[i], strerror(errno)); 12818210155Smrg continue; 12918210155Smrg } 13018210155Smrg printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 13118210155Smrg encoder->encoder_id, 13218210155Smrg encoder->crtc_id, 13318210155Smrg encoder_type_str(encoder->encoder_type), 13418210155Smrg encoder->possible_crtcs, 13518210155Smrg encoder->possible_clones); 13618210155Smrg drmModeFreeEncoder(encoder); 13718210155Smrg } 13818210155Smrg printf("\n"); 13918210155Smrg} 14018210155Smrg 14118210155Smrgvoid dump_mode(drmModeModeInfo *mode) 14218210155Smrg{ 14318210155Smrg printf(" %s %.02f %d %d %d %d %d %d %d %d\n", 14418210155Smrg mode->name, 14518210155Smrg (float)mode->vrefresh / 1000, 14618210155Smrg mode->hdisplay, 14718210155Smrg mode->hsync_start, 14818210155Smrg mode->hsync_end, 14918210155Smrg mode->htotal, 15018210155Smrg mode->vdisplay, 15118210155Smrg mode->vsync_start, 15218210155Smrg mode->vsync_end, 15318210155Smrg mode->vtotal); 15418210155Smrg} 15518210155Smrg 15618210155Smrgstatic void 15718210155Smrgdump_props(drmModeConnector *connector) 15818210155Smrg{ 15918210155Smrg drmModePropertyPtr props; 16018210155Smrg int i; 16118210155Smrg 16218210155Smrg for (i = 0; i < connector->count_props; i++) { 16318210155Smrg props = drmModeGetProperty(fd, connector->props[i]); 16418210155Smrg printf("\t%s, flags %d\n", props->name, props->flags); 16518210155Smrg drmModeFreeProperty(props); 16618210155Smrg } 16718210155Smrg} 16818210155Smrg 16918210155Smrgvoid dump_connectors(void) 17018210155Smrg{ 17118210155Smrg drmModeConnector *connector; 17218210155Smrg int i, j; 17318210155Smrg 17418210155Smrg printf("Connectors:\n"); 17518210155Smrg printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n"); 17618210155Smrg for (i = 0; i < resources->count_connectors; i++) { 17718210155Smrg connector = drmModeGetConnector(fd, resources->connectors[i]); 17818210155Smrg 17918210155Smrg if (!connector) { 18018210155Smrg fprintf(stderr, "could not get connector %i: %s\n", 18118210155Smrg resources->connectors[i], strerror(errno)); 18218210155Smrg continue; 18318210155Smrg } 18418210155Smrg 18518210155Smrg printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", 18618210155Smrg connector->connector_id, 18718210155Smrg connector->encoder_id, 18818210155Smrg connector_status_str(connector->connection), 18918210155Smrg connector_type_str(connector->connector_type), 19018210155Smrg connector->mmWidth, connector->mmHeight, 19118210155Smrg connector->count_modes); 19218210155Smrg 19318210155Smrg if (!connector->count_modes) 19418210155Smrg continue; 19518210155Smrg 19618210155Smrg printf(" modes:\n"); 19718210155Smrg printf(" name refresh (Hz) hdisp hss hse htot vdisp " 19818210155Smrg "vss vse vtot)\n"); 19918210155Smrg for (j = 0; j < connector->count_modes; j++) 20018210155Smrg dump_mode(&connector->modes[j]); 20118210155Smrg 20218210155Smrg drmModeFreeConnector(connector); 20318210155Smrg 20418210155Smrg printf(" props:\n"); 20518210155Smrg dump_props(connector); 20618210155Smrg } 20718210155Smrg printf("\n"); 20818210155Smrg} 20918210155Smrg 21018210155Smrgvoid dump_crtcs(void) 21118210155Smrg{ 21218210155Smrg drmModeCrtc *crtc; 21318210155Smrg int i; 21418210155Smrg 21518210155Smrg printf("CRTCs:\n"); 21618210155Smrg printf("id\tfb\tpos\tsize\n"); 21718210155Smrg for (i = 0; i < resources->count_crtcs; i++) { 21818210155Smrg crtc = drmModeGetCrtc(fd, resources->crtcs[i]); 21918210155Smrg 22018210155Smrg if (!crtc) { 22118210155Smrg fprintf(stderr, "could not get crtc %i: %s\n", 22218210155Smrg resources->crtcs[i], strerror(errno)); 22318210155Smrg continue; 22418210155Smrg } 22518210155Smrg printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 22618210155Smrg crtc->crtc_id, 22718210155Smrg crtc->buffer_id, 22818210155Smrg crtc->x, crtc->y, 22918210155Smrg crtc->width, crtc->height); 23018210155Smrg dump_mode(&crtc->mode); 23118210155Smrg 23218210155Smrg drmModeFreeCrtc(crtc); 23318210155Smrg } 23418210155Smrg printf("\n"); 23518210155Smrg} 23618210155Smrg 23718210155Smrgvoid dump_framebuffers(void) 23818210155Smrg{ 23918210155Smrg drmModeFB *fb; 24018210155Smrg int i; 24118210155Smrg 24218210155Smrg printf("Frame buffers:\n"); 24318210155Smrg printf("id\tsize\tpitch\n"); 24418210155Smrg for (i = 0; i < resources->count_fbs; i++) { 24518210155Smrg fb = drmModeGetFB(fd, resources->fbs[i]); 24618210155Smrg 24718210155Smrg if (!fb) { 24818210155Smrg fprintf(stderr, "could not get fb %i: %s\n", 24918210155Smrg resources->fbs[i], strerror(errno)); 25018210155Smrg continue; 25118210155Smrg } 25218210155Smrg printf("%d\t(%dx%d)\t%d\n", 25318210155Smrg fb->fb_id, 25418210155Smrg fb->width, fb->height); 25518210155Smrg 25618210155Smrg drmModeFreeFB(fb); 25718210155Smrg } 25818210155Smrg printf("\n"); 25918210155Smrg} 26018210155Smrg 26118210155Smrg/* 26218210155Smrg * Mode setting with the kernel interfaces is a bit of a chore. 26318210155Smrg * First you have to find the connector in question and make sure the 26418210155Smrg * requested mode is available. 26518210155Smrg * Then you need to find the encoder attached to that connector so you 26618210155Smrg * can bind it with a free crtc. 26718210155Smrg */ 26818210155Smrgstruct connector { 26918210155Smrg int id; 27018210155Smrg char mode_str[64]; 27118210155Smrg drmModeModeInfo *mode; 27218210155Smrg drmModeEncoder *encoder; 27318210155Smrg int crtc; 27418210155Smrg}; 27518210155Smrg 27618210155Smrgstatic void 27718210155Smrgconnector_find_mode(struct connector *c) 27818210155Smrg{ 27918210155Smrg drmModeConnector *connector; 28018210155Smrg int i, j, size, ret, width, height; 28118210155Smrg 28218210155Smrg /* First, find the connector & mode */ 28318210155Smrg c->mode = NULL; 28418210155Smrg for (i = 0; i < resources->count_connectors; i++) { 28518210155Smrg connector = drmModeGetConnector(fd, resources->connectors[i]); 28618210155Smrg 28718210155Smrg if (!connector) { 28818210155Smrg fprintf(stderr, "could not get connector %i: %s\n", 28918210155Smrg resources->connectors[i], strerror(errno)); 29018210155Smrg drmModeFreeConnector(connector); 29118210155Smrg continue; 29218210155Smrg } 29318210155Smrg 29418210155Smrg if (!connector->count_modes) { 29518210155Smrg drmModeFreeConnector(connector); 29618210155Smrg continue; 29718210155Smrg } 29818210155Smrg 29918210155Smrg if (connector->connector_id != c->id) { 30018210155Smrg drmModeFreeConnector(connector); 30118210155Smrg continue; 30218210155Smrg } 30318210155Smrg 30418210155Smrg for (j = 0; j < connector->count_modes; j++) { 30518210155Smrg c->mode = &connector->modes[j]; 30618210155Smrg if (!strcmp(c->mode->name, c->mode_str)) 30718210155Smrg break; 30818210155Smrg } 30918210155Smrg 31018210155Smrg /* Found it, break out */ 31118210155Smrg if (c->mode) 31218210155Smrg break; 31318210155Smrg 31418210155Smrg drmModeFreeConnector(connector); 31518210155Smrg } 31618210155Smrg 31718210155Smrg if (!c->mode) { 31818210155Smrg fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 31918210155Smrg return; 32018210155Smrg } 32118210155Smrg 32218210155Smrg /* Now get the encoder */ 32318210155Smrg for (i = 0; i < resources->count_encoders; i++) { 32418210155Smrg c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); 32518210155Smrg 32618210155Smrg if (!c->encoder) { 32718210155Smrg fprintf(stderr, "could not get encoder %i: %s\n", 32818210155Smrg resources->encoders[i], strerror(errno)); 32918210155Smrg drmModeFreeEncoder(c->encoder); 33018210155Smrg continue; 33118210155Smrg } 33218210155Smrg 33318210155Smrg if (c->encoder->encoder_id == connector->encoder_id) 33418210155Smrg break; 33518210155Smrg 33618210155Smrg drmModeFreeEncoder(c->encoder); 33718210155Smrg } 33818210155Smrg 33918210155Smrg if (c->crtc == -1) 34018210155Smrg c->crtc = c->encoder->crtc_id; 34118210155Smrg} 34218210155Smrg 34318210155Smrg#ifdef HAVE_CAIRO 34418210155Smrg 34518210155Smrgstatic int 34618210155Smrgcreate_test_buffer(drm_intel_bufmgr *bufmgr, 34718210155Smrg int width, int height, int *stride_out, drm_intel_bo **bo_out) 34818210155Smrg{ 34918210155Smrg drm_intel_bo *bo; 35018210155Smrg unsigned int *fb_ptr; 35118210155Smrg int size, ret, i, stride; 35218210155Smrg div_t d; 35318210155Smrg cairo_surface_t *surface; 35418210155Smrg cairo_t *cr; 35518210155Smrg char buf[64]; 35618210155Smrg int x, y; 35718210155Smrg 35818210155Smrg surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); 35918210155Smrg stride = cairo_image_surface_get_stride(surface); 36018210155Smrg size = stride * height; 36118210155Smrg fb_ptr = (unsigned int *) cairo_image_surface_get_data(surface); 36218210155Smrg 36318210155Smrg /* paint the buffer with colored tiles */ 36418210155Smrg for (i = 0; i < width * height; i++) { 36518210155Smrg d = div(i, width); 36618210155Smrg fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); 36718210155Smrg } 36818210155Smrg 36918210155Smrg cr = cairo_create(surface); 37018210155Smrg cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); 37118210155Smrg for (x = 0; x < width; x += 250) 37218210155Smrg for (y = 0; y < height; y += 250) { 37318210155Smrg cairo_set_operator(cr, CAIRO_OPERATOR_OVER); 37418210155Smrg cairo_move_to(cr, x, y - 20); 37518210155Smrg cairo_line_to(cr, x, y + 20); 37618210155Smrg cairo_move_to(cr, x - 20, y); 37718210155Smrg cairo_line_to(cr, x + 20, y); 37818210155Smrg cairo_new_sub_path(cr); 37918210155Smrg cairo_arc(cr, x, y, 10, 0, M_PI * 2); 38018210155Smrg cairo_set_line_width(cr, 4); 38118210155Smrg cairo_set_source_rgb(cr, 0, 0, 0); 38218210155Smrg cairo_stroke_preserve(cr); 38318210155Smrg cairo_set_source_rgb(cr, 1, 1, 1); 38418210155Smrg cairo_set_line_width(cr, 2); 38518210155Smrg cairo_stroke(cr); 38618210155Smrg snprintf(buf, sizeof buf, "%d, %d", x, y); 38718210155Smrg cairo_move_to(cr, x + 20, y + 20); 38818210155Smrg cairo_text_path(cr, buf); 38918210155Smrg cairo_set_source_rgb(cr, 0, 0, 0); 39018210155Smrg cairo_stroke_preserve(cr); 39118210155Smrg cairo_set_source_rgb(cr, 1, 1, 1); 39218210155Smrg cairo_fill(cr); 39318210155Smrg } 39418210155Smrg 39518210155Smrg cairo_destroy(cr); 39618210155Smrg 39718210155Smrg bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 39818210155Smrg if (!bo) { 39918210155Smrg fprintf(stderr, "failed to alloc buffer: %s\n", 40018210155Smrg strerror(errno)); 40118210155Smrg return -1; 40218210155Smrg } 40318210155Smrg 40418210155Smrg drm_intel_bo_subdata(bo, 0, size, fb_ptr); 40518210155Smrg 40618210155Smrg cairo_surface_destroy(surface); 40718210155Smrg 40818210155Smrg *bo_out = bo; 40918210155Smrg *stride_out = stride; 41018210155Smrg 41118210155Smrg return 0; 41218210155Smrg} 41318210155Smrg 41418210155Smrg#else 41518210155Smrg 41618210155Smrgstatic int 41718210155Smrgcreate_test_buffer(drm_intel_bufmgr *bufmgr, 41818210155Smrg int width, int height, int *stride_out, drm_intel_bo **bo_out) 41918210155Smrg{ 42018210155Smrg drm_intel_bo *bo; 42118210155Smrg unsigned int *fb_ptr; 42218210155Smrg int size, ret, i, stride; 42318210155Smrg div_t d; 42418210155Smrg 42518210155Smrg /* Mode size at 32 bpp */ 42618210155Smrg stride = width * 4; 42718210155Smrg size = stride * height; 42818210155Smrg 42918210155Smrg bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); 43018210155Smrg if (!bo) { 43118210155Smrg fprintf(stderr, "failed to alloc buffer: %s\n", 43218210155Smrg strerror(errno)); 43318210155Smrg return -1; 43418210155Smrg } 43518210155Smrg 43618210155Smrg ret = drm_intel_gem_bo_map_gtt(bo); 43718210155Smrg if (ret) { 43818210155Smrg fprintf(stderr, "failed to GTT map buffer: %s\n", 43918210155Smrg strerror(errno)); 44018210155Smrg return -1; 44118210155Smrg } 44218210155Smrg 44318210155Smrg fb_ptr = bo->virtual; 44418210155Smrg 44518210155Smrg /* paint the buffer with colored tiles */ 44618210155Smrg for (i = 0; i < width * height; i++) { 44718210155Smrg d = div(i, width); 44818210155Smrg fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); 44918210155Smrg } 45018210155Smrg drm_intel_bo_unmap(bo); 45118210155Smrg 45218210155Smrg *bo_out = bo; 45318210155Smrg *stride_out = stride; 45418210155Smrg 45518210155Smrg return 0; 45618210155Smrg} 45718210155Smrg 45818210155Smrg#endif 45918210155Smrg 46018210155Smrgstatic void 46118210155Smrgset_mode(struct connector *c, int count) 46218210155Smrg{ 46318210155Smrg drmModeConnector *connector; 46418210155Smrg drmModeEncoder *encoder = NULL; 46518210155Smrg struct drm_mode_modeinfo *mode = NULL; 46618210155Smrg drm_intel_bufmgr *bufmgr; 46718210155Smrg drm_intel_bo *bo; 46818210155Smrg unsigned int fb_id; 46918210155Smrg int i, j, ret, width, height, x, stride; 47018210155Smrg 47118210155Smrg width = 0; 47218210155Smrg height = 0; 47318210155Smrg for (i = 0; i < count; i++) { 47418210155Smrg connector_find_mode(&c[i]); 47518210155Smrg if (c[i].mode == NULL) 47618210155Smrg continue; 47718210155Smrg width += c[i].mode->hdisplay; 47818210155Smrg if (height < c[i].mode->vdisplay) 47918210155Smrg height = c[i].mode->vdisplay; 48018210155Smrg } 48118210155Smrg 48218210155Smrg bufmgr = drm_intel_bufmgr_gem_init(fd, 2<<20); 48318210155Smrg if (!bufmgr) { 48418210155Smrg fprintf(stderr, "failed to init bufmgr: %s\n", strerror(errno)); 48518210155Smrg return; 48618210155Smrg } 48718210155Smrg 48818210155Smrg if (create_test_buffer(bufmgr, width, height, &stride, &bo)) 48918210155Smrg return; 49018210155Smrg 49118210155Smrg ret = drmModeAddFB(fd, width, height, 32, 32, stride, bo->handle, 49218210155Smrg &fb_id); 49318210155Smrg if (ret) { 49418210155Smrg fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 49518210155Smrg return; 49618210155Smrg } 49718210155Smrg 49818210155Smrg x = 0; 49918210155Smrg for (i = 0; i < count; i++) { 50018210155Smrg int crtc_id; 50118210155Smrg if (c[i].mode == NULL) 50218210155Smrg continue; 50318210155Smrg 50418210155Smrg printf("setting mode %s on connector %d, crtc %d\n", 50518210155Smrg c[i].mode_str, c[i].id, c[i].crtc); 50618210155Smrg 50718210155Smrg ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, 50818210155Smrg &c[i].id, 1, c[i].mode); 50918210155Smrg x += c[i].mode->hdisplay; 51018210155Smrg 51118210155Smrg if (ret) { 51218210155Smrg fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 51318210155Smrg return; 51418210155Smrg } 51518210155Smrg } 51618210155Smrg} 51718210155Smrg 51818210155Smrgextern char *optarg; 51918210155Smrgextern int optind, opterr, optopt; 52018210155Smrgstatic char optstr[] = "ecpmfs:"; 52118210155Smrg 52218210155Smrgvoid usage(char *name) 52318210155Smrg{ 52418210155Smrg fprintf(stderr, "usage: %s [-ecpmf]\n", name); 52518210155Smrg fprintf(stderr, "\t-e\tlist encoders\n"); 52618210155Smrg fprintf(stderr, "\t-c\tlist connectors\n"); 52718210155Smrg fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); 52818210155Smrg fprintf(stderr, "\t-m\tlist modes\n"); 52918210155Smrg fprintf(stderr, "\t-f\tlist framebuffers\n"); 53018210155Smrg fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n"); 53118210155Smrg fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n"); 53218210155Smrg fprintf(stderr, "\n\tDefault is to dump all info.\n"); 53318210155Smrg exit(0); 53418210155Smrg} 53518210155Smrg 53618210155Smrg#define dump_resource(res) if (res) dump_##res() 53718210155Smrg 53818210155Smrgint main(int argc, char **argv) 53918210155Smrg{ 54018210155Smrg int c; 54118210155Smrg int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; 54218210155Smrg char *modules[] = { "i915", "radeon" }; 54318210155Smrg char *modeset = NULL, *mode, *connector; 54418210155Smrg int i, connector_id, count = 0; 54518210155Smrg struct connector con_args[2]; 54618210155Smrg 54718210155Smrg opterr = 0; 54818210155Smrg while ((c = getopt(argc, argv, optstr)) != -1) { 54918210155Smrg switch (c) { 55018210155Smrg case 'e': 55118210155Smrg encoders = 1; 55218210155Smrg break; 55318210155Smrg case 'c': 55418210155Smrg connectors = 1; 55518210155Smrg break; 55618210155Smrg case 'p': 55718210155Smrg crtcs = 1; 55818210155Smrg break; 55918210155Smrg case 'm': 56018210155Smrg modes = 1; 56118210155Smrg break; 56218210155Smrg case 'f': 56318210155Smrg framebuffers = 1; 56418210155Smrg break; 56518210155Smrg case 's': 56618210155Smrg modeset = strdup(optarg); 56718210155Smrg con_args[count].crtc = -1; 56818210155Smrg if (sscanf(optarg, "%d:%64s", 56918210155Smrg &con_args[count].id, 57018210155Smrg &con_args[count].mode_str) != 2 && 57118210155Smrg sscanf(optarg, "%d@%d:%64s", 57218210155Smrg &con_args[count].id, 57318210155Smrg &con_args[count].crtc, 57418210155Smrg &con_args[count].mode_str) != 3) 57518210155Smrg usage(argv[0]); 57618210155Smrg count++; 57718210155Smrg break; 57818210155Smrg default: 57918210155Smrg usage(argv[0]); 58018210155Smrg break; 58118210155Smrg } 58218210155Smrg } 58318210155Smrg 58418210155Smrg if (argc == 1) 58518210155Smrg encoders = connectors = crtcs = modes = framebuffers = 1; 58618210155Smrg 58718210155Smrg for (i = 0; i < ARRAY_SIZE(modules); i++) { 58818210155Smrg printf("trying to load module %s...", modules[i]); 58918210155Smrg fd = drmOpen(modules[i], NULL); 59018210155Smrg if (fd < 0) { 59118210155Smrg printf("failed.\n"); 59218210155Smrg } else { 59318210155Smrg printf("success.\n"); 59418210155Smrg break; 59518210155Smrg } 59618210155Smrg } 59718210155Smrg 59818210155Smrg if (i == ARRAY_SIZE(modules)) { 59918210155Smrg fprintf(stderr, "failed to load any modules, aborting.\n"); 60018210155Smrg return -1; 60118210155Smrg } 60218210155Smrg 60318210155Smrg resources = drmModeGetResources(fd); 60418210155Smrg if (!resources) { 60518210155Smrg fprintf(stderr, "drmModeGetResources failed: %s\n", 60618210155Smrg strerror(errno)); 60718210155Smrg drmClose(fd); 60818210155Smrg return 1; 60918210155Smrg } 61018210155Smrg 61118210155Smrg dump_resource(encoders); 61218210155Smrg dump_resource(connectors); 61318210155Smrg dump_resource(crtcs); 61418210155Smrg dump_resource(framebuffers); 61518210155Smrg 61618210155Smrg if (count > 0) { 61718210155Smrg set_mode(con_args, count); 61818210155Smrg getchar(); 61918210155Smrg } 62018210155Smrg 62118210155Smrg drmModeFreeResources(resources); 62218210155Smrg 62318210155Smrg return 0; 62418210155Smrg} 625