From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Wed, 26 Jun 2024 10:41:41 +0200 Received: from metis.whiteo.stw.pengutronix.de ([2a0a:edc0:2:b01:1d::104]) by lore.white.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1sMODk-00CU79-0R for lore@lore.pengutronix.de; Wed, 26 Jun 2024 10:41:41 +0200 Received: from localhost ([127.0.0.1] helo=metis.whiteo.stw.pengutronix.de) by metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92) (envelope-from ) id 1sMODi-0007ur-82; Wed, 26 Jun 2024 10:41:38 +0200 Received: from mail-he1eur04on2062c.outbound.protection.outlook.com ([2a01:111:f403:260f::62c] helo=EUR04-HE1-obe.outbound.protection.outlook.com) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sLLnV-0008LB-F4; Sun, 23 Jun 2024 13:54:19 +0200 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=oLTJSWfS1/zndPQqKdSBzHuu5qBH+b6fgGsHR6g94WER0KAWyhPr+3UNvCmImSToEKgaHQU3ao01Voafws0TZ8EPSI7akWSs7GsmcXyx0BNztXY2upGdTaswCQBDOb+6Vv7L1nMgzR7HEoTGOtSMLnkLt6GDvOZ9tpgma463VtgqsmvsL7lUJQD35cvnwtrEGNVH9Ra0IGIrTIIBCemhz2K9Axf1OSUxxh+x8gNY4a/ctfH1dQOcKePMBBPRTWbXVNyrHHqXdN18kD6HUgv8auvmvDl6cwayNP/3I4I34qQKZklFd7qXEXG416Ma3sr0RSadwROCwk2haLRwxvvvMA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=SHFZDSjUykrQFWe4ZasWksCzSUSTfq+IDV2k+sEg1Ps=; b=XS1LYfkxSB2Nl29QluInQHFfLJDv667Zz7prwwEU2cur4etuBo9EFsFLNYi7hPMO91vvQFA6f+NUK19XguCqQLUzynfrrTZSc8MLVajLmzK20hnH7rfj2m7BAgi9Lgioiy6G+okOrXW+C38jb0XB8Yc/Xe57J3yvLcrpniTni6PKQMrurxlVBlJTYDPqUk50yuU2fOPXSto5kYTavPTrjE9kB5U0ITmE/KSLifqGuYjMaY7HrHZrnR3J6rCIgc1VTR9aZOEm242kx5xuFPf3hXKZD8hXaMuE5bpJR3OIvD8NyNoEmnrw7xYY73z9Vi/Y7q8p8wqNJuXaKwz0dgY1Kw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 193.8.40.94) smtp.rcpttodomain=pengutronix.de smtp.mailfrom=leica-geosystems.com.cn; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=leica-geosystems.com.cn; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=leica-geosystems.com.cn; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SHFZDSjUykrQFWe4ZasWksCzSUSTfq+IDV2k+sEg1Ps=; b=MT2mQjhmHXAFoNfPbgkGMSmJZGWT40gOo+0lCRToB+lRmhLdj65QQf1NW80obtElXXQTYQa/gW0CU2Vmpa2FmHvlUtqzlkaiZYtLMnxqQyfLhdYdljtnnnSdCUVdtueaFIrGkEmIRzfvxnhtZCGKhABWOoXhOL3jQ5JkyNjsGlU= Received: from AM8P251CA0002.EURP251.PROD.OUTLOOK.COM (2603:10a6:20b:21b::7) by VE1PR06MB6895.eurprd06.prod.outlook.com (2603:10a6:800:1b2::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7698.26; Sun, 23 Jun 2024 11:54:13 +0000 Received: from AMS0EPF00000190.eurprd05.prod.outlook.com (2603:10a6:20b:21b:cafe::34) by AM8P251CA0002.outlook.office365.com (2603:10a6:20b:21b::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.37 via Frontend Transport; Sun, 23 Jun 2024 11:54:13 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 193.8.40.94) smtp.mailfrom=leica-geosystems.com.cn; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=leica-geosystems.com.cn; Received-SPF: Pass (protection.outlook.com: domain of leica-geosystems.com.cn designates 193.8.40.94 as permitted sender) receiver=protection.outlook.com; client-ip=193.8.40.94; helo=hexagon.com; pr=C Received: from hexagon.com (193.8.40.94) by AMS0EPF00000190.mail.protection.outlook.com (10.167.16.213) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.15 via Frontend Transport; Sun, 23 Jun 2024 11:54:12 +0000 Received: from aherlnxbspsrv01.lgs-net.com ([10.60.34.116]) by hexagon.com with Microsoft SMTPSVC(10.0.17763.1697); Sun, 23 Jun 2024 13:54:09 +0200 From: LI Qingwu To: Qing-wu.Li@leica-geosystems.com.cn, oss-tools@pengutronix.de, m.felsch@pengutronix.de Date: Sun, 23 Jun 2024 13:54:05 +0200 Message-Id: <20240623115407.983326-3-Qing-wu.Li@leica-geosystems.com.cn> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240623115407.983326-1-Qing-wu.Li@leica-geosystems.com.cn> References: <20240623115407.983326-1-Qing-wu.Li@leica-geosystems.com.cn> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-OriginalArrivalTime: 23 Jun 2024 11:54:09.0367 (UTC) FILETIME=[0EA0C670:01DAC564] X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AMS0EPF00000190:EE_|VE1PR06MB6895:EE_ X-MS-Office365-Filtering-Correlation-Id: 3338ca30-4470-4144-5632-08dc937b334d X-SET-LOWER-SCL-SCANNER: YES X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230037|36860700010|1800799021|376011|82310400023; X-Microsoft-Antispam-Message-Info: =?utf-8?B?RXo2YmxGaEwwT0dJUVhsTEI5bm5GUGMvdWZ6NFFDWERLbk9sV3dNUENZNUhm?= =?utf-8?B?ai81cDhxeEdyNnZNWjdtUFVmOERHd0NCcXBKYlZSOWZYS2ljc1dKMEF3aGUr?= =?utf-8?B?emVNTitETjZzYldBZFl1Nlg1dlRCRVIwUGVaUTBMSHgvTi9OWFMwQ2xLNkt3?= =?utf-8?B?c0xwRGVYQ0dWSVJ2bkdNc3JKdCswRkxzU1oyWEpJK045MGVaa2I4eVVrVmdo?= =?utf-8?B?ZEJoZ0dGNnBDL3JKOXAxYnlYVHVCdHNLdXdxN08xQysrd3h4NUhZV2VtMW5w?= =?utf-8?B?bXZveHlXN2JpMnF2ZG1VdVVsdktNZXIvTUhXWGFobk14UCs2RHcwd0gvYkVN?= =?utf-8?B?U3hUYU1DYSt0WVJSYXdYSFkvbGkwVGlmOUhnR0U4Nkx6dUl5d3NlakxIRUJ6?= =?utf-8?B?cFQ1V0xod3d0TlYwUVJobEFNdXhYWkpiR281a0ROM3lCUnRzQ3hRczJML0xN?= =?utf-8?B?ZnRnemQ0VGhBQW5ha2pwRllMZVMrTWd2UExOWW9NcGk3WHgycE13ZEZBZEdp?= =?utf-8?B?aE03L2J4QWVXVkVpUURoYm5sOFRHR0hqMFlwUndDS3NJZVFPUDZaekQyZ3k1?= =?utf-8?B?WGEzT1VWR3YrT3RoeVJGN3BZYlJCT2pFTGZjZXVQbHU2SHBNWnE3ejNESTNk?= =?utf-8?B?OW5jVjdhcURpckxBTCtncmdOUFhGOGIzeEV5WlEwQXY5Ry9sanNNcGMrRGhW?= =?utf-8?B?TDVTOTlScUJENmxuR3YyQXpSMExyWSt3bzdhQ1pHYVhLbUlCUXR3Y1JnTWVx?= =?utf-8?B?ZjdFTnpsSVV3Y1o2Zzlaei90V0NnUysyNkdFdEpGS2tacDZpVE5UcVc2d1Yr?= =?utf-8?B?bUJ5RWxQVDdMdTBPMWdxT3cycTBTY3B2ZUg4NTlIZEhJV2RnNmkyd1d4SFht?= =?utf-8?B?Q0Y1VzJUOXViVGRsb2FtdjRESjI2eXJhMmxMNjM0cDRhUW1JUGdMb0krT2pH?= =?utf-8?B?YndRYnNSeDVmUEt6cTdpSmk3dnpUTHpUSXQ3S3A5emhCTWc4Z1d0d3pHclFz?= =?utf-8?B?L3ZHamhQVWJLZkdRY2RHNnJhWm1IVU0yNFZ6UzVveTJYUzVpc3FGa2Q0R1E0?= =?utf-8?B?R1hBOTVLTTRVaWZzTi95cTNGK00wWFRoWXpRMHNNdFdsamZ6R015aUZGbWd2?= =?utf-8?B?aHFuUUxCc1c5OW1OQzlPTmJrRDhKZmQ1VEpZNmc0QitoNkk2cDcwUkF4SFZ2?= =?utf-8?B?dzdodEcvQkhob01VRTlCSDlWcVlraVhvc004am8zbmFGVk9NS3BaZGdPVnRy?= =?utf-8?B?WXlWQWRuYzl2WTR2S0N3Q3NrbjloUjNRQTBuN1ovbXZYSVFCMEtVOXhqb05K?= =?utf-8?B?cVU1ZEE1MFpESG9zb2dpRzZaNlJiUk5RODJScVRyemFITzB4dE9XNm1DZjNK?= =?utf-8?B?ZldxRnA3TDVrRVYxQmxKcG81VFZ3ZjkvcWU1dER0ODRhSDNlMHQ2emphUDdO?= =?utf-8?B?NFoxUEFmODRiSk5abUJQODNOVG03VHdJNUUvRnZoRDgwd3hRVllxNDRoTGxm?= =?utf-8?B?KzUwckQ4TW1ZSzRwRVc1cnlXaE9ubFRRUGt4QW9yTkdqZ2h6aTIxNFd3cjNQ?= =?utf-8?B?bFBDb2xBTmdrRUQwdUEzY2NHSTRnSmNZY0JNZVlNVTVHQjZ5RktRNVc0eFNj?= =?utf-8?B?VFVPTFBXaEROOE9KTDNnWEk2RUFNZ1pHdzBXd2hnalplcExZN2M3Z2FRUGF0?= =?utf-8?B?S2FPMlJTdG8xRlJPbW5SVFgxZVZ6eW1Zd1FwVCtXTzN5MHdNaHp3Y3AyZXlD?= =?utf-8?B?MHVyeHl0U3BodmUyZWVkSDVjemNHOU9SclV1RzNSUjIzdW9hTlJURU04SmMx?= =?utf-8?Q?eUuZ78MjWGbR5Srmoe7+Q0oju9kBULy90Nx1I=3D?= X-Forefront-Antispam-Report: CIP:193.8.40.94; CTRY:CH; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:hexagon.com; PTR:ahersrvdom50.leica-geosystems.com; CAT:NONE; SFS:(13230037)(36860700010)(1800799021)(376011)(82310400023); DIR:OUT; SFP:1101; X-OriginatorOrg: leica-geosystems.com.cn X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jun 2024 11:54:12.9797 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 3338ca30-4470-4144-5632-08dc937b334d X-MS-Exchange-CrossTenant-Id: 1b16ab3e-b8f6-4fe3-9f3e-2db7fe549f6a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=1b16ab3e-b8f6-4fe3-9f3e-2db7fe549f6a; Ip=[193.8.40.94]; Helo=[hexagon.com] X-MS-Exchange-CrossTenant-AuthSource: AMS0EPF00000190.eurprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: VE1PR06MB6895 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on metis.whiteo.stw.pengutronix.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=4.0 tests=AWL,BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS, URIBL_SBL,URIBL_SBL_A autolearn=no autolearn_force=no version=3.4.2 X-Mailman-Approved-At: Wed, 26 Jun 2024 10:41:35 +0200 Subject: [OSS-Tools] [PATCH platsch V6 3/5] platsch: split into platsch and libplatsch X-BeenThere: oss-tools@pengutronix.de X-Mailman-Version: 2.1.29 Precedence: list List-Id: Pengutronix Public Open-Source-Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: bsp-development.geo@leica-geosystems.com Sender: "OSS-Tools" X-SA-Exim-Connect-IP: 127.0.0.1 X-SA-Exim-Mail-From: oss-tools-bounces@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false Signed-off-by: LI Qingwu --- libplatsch.c | 557 ++++++++++++++++++++++++++++++++++++++++++++++++ libplatsch.h | 43 ++++ meson.build | 12 +- platsch.c | 582 ++------------------------------------------------- 4 files changed, 629 insertions(+), 565 deletions(-) create mode 100644 libplatsch.c create mode 100644 libplatsch.h diff --git a/libplatsch.c b/libplatsch.c new file mode 100644 index 0000000..f002491 --- /dev/null +++ b/libplatsch.c @@ -0,0 +1,557 @@ +/* + * Copyright (C) 2019 Pengutronix, Uwe Kleine-König + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Some code parts base on example code written in 2012 by David Herrmann + * and dedicated to the Public Domain. It was found + * in 2019 on + * https://raw.githubusercontent.com/dvdhrm/docs/master/drm-howto/modeset.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libplatsch.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) + +ssize_t readfull(int fd, void *buf, size_t count) +{ + ssize_t ret = 0, err; + + while (count > 0) { + err = read(fd, buf, count); + if (err < 0) + return err; + else if (err > 0) { + buf += err; + count -= err; + ret += err; + } else { + return ret; + } + } + + return ret; +} + +void draw_buffer(struct modeset_dev *dev, const char *dir, const char *base) +{ + int fd_src; + char filename[PLATSCH_MAX_FILENAME_LENGTH]; + ssize_t size; + int ret; + + /* + * make it easy and load a raw file in the right format instead of + * opening an (say) PNG and convert the image data to the right format. + */ + ret = snprintf(filename, sizeof(filename), "%s/%s-%ux%u-%s.bin", dir, base, dev->width, + dev->height, dev->format->name); + if (ret >= sizeof(filename)) { + platsch_error("Failed to fit filename into buffer\n"); + return; + } + + fd_src = open(filename, O_RDONLY | O_CLOEXEC); + if (fd_src < 0) { + platsch_error("Failed to open %s: %m\n", filename); + return; + } + + size = readfull(fd_src, dev->map, dev->size); + if (size < dev->size) { + if (size < 0) + platsch_error("Failed to read from %s: %m\n", filename); + else + platsch_error("Could only read %zd/%u bytes from %s\n", size, dev->size, filename); + } + + ret = close(fd_src); + if (ret < 0) { + /* Nothing we can do about this, so just warn */ + platsch_error("Failed to close image file\n"); + } + + return; +} + +static struct modeset_dev *modeset_list = NULL; + +static int drmprepare_crtc(int fd, drmModeRes *res, drmModeConnector *conn, struct modeset_dev *dev) +{ + drmModeEncoder *enc; + unsigned int i, j; + int32_t crtc_id; + struct modeset_dev *iter; + + /* first try the currently connected encoder+crtc */ + if (conn->encoder_id) { + platsch_debug("connector #%d uses encoder #%d\n", conn->connector_id, conn->encoder_id); + enc = drmModeGetEncoder(fd, conn->encoder_id); + assert(enc); + assert(enc->encoder_id == conn->encoder_id); + } else { + platsch_debug("connector #%d has no active encoder\n", conn->connector_id); + enc = NULL; + dev->setmode = 1; + } + + if (enc) { + if (enc->crtc_id) { + crtc_id = enc->crtc_id; + assert(crtc_id >= 0); + + for (iter = modeset_list; iter; iter = iter->next) { + if (iter->crtc_id == crtc_id) { + crtc_id = -1; + break; + } + } + + if (crtc_id > 0) { + platsch_debug("encoder #%d uses crtc #%d\n", enc->encoder_id, enc->crtc_id); + drmModeFreeEncoder(enc); + dev->crtc_id = crtc_id; + return 0; + } else { + platsch_debug("encoder #%d used crtc #%d, but that's in use\n", + enc->encoder_id, iter->crtc_id); + } + } else { + platsch_debug("encoder #%d doesn't have an active crtc\n", enc->encoder_id); + } + + drmModeFreeEncoder(enc); + } + + /* If the connector is not currently bound to an encoder or if the + * encoder+crtc is already used by another connector (actually unlikely + * but let's be safe), iterate all other available encoders to find a + * matching CRTC. */ + for (i = 0; i < conn->count_encoders; ++i) { + enc = drmModeGetEncoder(fd, conn->encoders[i]); + if (!enc) { + platsch_error("Cannot retrieve encoder %u: %m\n", conn->encoders[i]); + continue; + } + assert(enc->encoder_id == conn->encoders[i]); + + /* iterate all global CRTCs */ + for (j = 0; j < res->count_crtcs; ++j) { + /* check whether this CRTC works with the encoder */ + if (!(enc->possible_crtcs & (1 << j))) + continue; + + /* check that no other device already uses this CRTC */ + crtc_id = res->crtcs[j]; + for (iter = modeset_list; iter; iter = iter->next) { + if (iter->crtc_id == crtc_id) { + crtc_id = -1; + break; + } + } + + /* we have found a CRTC, so save it and return */ + if (crtc_id >= 0) { + platsch_debug("encoder #%d will use crtc #%d\n", enc->encoder_id, crtc_id); + drmModeFreeEncoder(enc); + dev->crtc_id = crtc_id; + return 0; + } + } + drmModeFreeEncoder(enc); + } + + platsch_error("Cannot find suitable CRTC for connector #%u\n", conn->connector_id); + return -ENOENT; +} + +static int modeset_create_fb(int fd, struct modeset_dev *dev) +{ + struct drm_mode_create_dumb creq; + struct drm_mode_destroy_dumb dreq; + struct drm_mode_map_dumb mreq; + int ret; + + /* create dumb buffer */ + memset(&creq, 0, sizeof(creq)); + creq.width = dev->width; + creq.height = dev->height; + creq.bpp = dev->format->bpp; + ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); + if (ret < 0) { + platsch_error("Cannot create dumb buffer: %m\n"); + return -errno; + } + dev->stride = creq.pitch; + dev->size = creq.size; + dev->handle = creq.handle; + + /* create framebuffer object for the dumb-buffer */ + ret = drmModeAddFB2(fd, dev->width, dev->height, + dev->format->format, + (uint32_t[4]){ dev->handle, }, + (uint32_t[4]){ dev->stride, }, + (uint32_t[4]){ 0, }, + &dev->fb_id, 0); + if (ret) { + ret = -errno; + platsch_error("Cannot create framebuffer: %m\n"); + goto err_destroy; + } + + /* prepare buffer for memory mapping */ + memset(&mreq, 0, sizeof(mreq)); + mreq.handle = dev->handle; + ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); + if (ret) { + ret = -errno; + platsch_error("Cannot get mmap offset: %m\n"); + goto err_fb; + } + + /* perform actual memory mapping */ + dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); + if (dev->map == MAP_FAILED) { + ret = -errno; + platsch_error("Cannot mmap dumb buffer: %m\n"); + goto err_fb; + } + + /* + * Clear the framebuffer. Normally it's overwritten later with some + * image data, but in case this fails, initialize to all-black. + */ + memset(dev->map, 0x0, dev->size); + + return 0; + +err_fb: + drmModeRmFB(fd, dev->fb_id); +err_destroy: + memset(&dreq, 0, sizeof(dreq)); + dreq.handle = dev->handle; + drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + return ret; +} + +/* Returns lowercase connector type names with '_' for '-' */ +static char *get_normalized_conn_type_name(uint32_t connector_type) +{ + int i; + const char *connector_name; + char *normalized_name; + + connector_name = drmModeGetConnectorTypeName(connector_type); + if (!connector_name) + return NULL; + + normalized_name = strdup(connector_name); + + for (i = 0; normalized_name[i]; i++) { + normalized_name[i] = tolower(normalized_name[i]); + if (normalized_name[i] == '-') + normalized_name[i] = '_'; + } + + return normalized_name; +} + +static const struct platsch_format *platsch_format_find(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(platsch_formats); i++) + if (!strcmp(platsch_formats[i].name, name)) + return &platsch_formats[i]; + + return NULL; +} + +static int set_env_connector_mode(drmModeConnector *conn, struct modeset_dev *dev) +{ + int ret, i = 0; + u_int32_t width = 0, height = 0; + const char *mode; + char *connector_type_name, mode_env_name[32], fmt_specifier[32] = ""; + const struct platsch_format *format = NULL; + + connector_type_name = get_normalized_conn_type_name(conn->connector_type); + if (!connector_type_name) { + platsch_error("could not look up name for connector type %u\n", conn->connector_type); + goto fallback; + } + + ret = snprintf(mode_env_name, sizeof(mode_env_name), "platsch_%s%u_mode", + connector_type_name, conn->connector_type_id); + free(connector_type_name); + if (ret >= sizeof(mode_env_name)) { + platsch_error("failed to fit platsch env mode variable name into buffer\n"); + return -EFAULT; + } + + /* check for connector mode configuration in environment */ + platsch_debug("looking up %s env variable\n", mode_env_name); + mode = getenv(mode_env_name); + if (!mode) + goto fallback; + + /* format suffix is optional */ + ret = sscanf(mode, "%ux%u@%s", &width, &height, fmt_specifier); + if (ret < 2) { + platsch_error("error while scanning %s for mode\n", mode_env_name); + return -EFAULT; + } + + /* use first mode matching given resolution */ + for (i = 0; i < conn->count_modes; i++) { + drmModeModeInfo mode = conn->modes[i]; + if (mode.hdisplay == width && mode.vdisplay == height) { + memcpy(&dev->mode, &mode, sizeof(dev->mode)); + dev->width = width; + dev->height = height; + break; + } + } + + if (i == conn->count_modes) { + platsch_error("no mode available matching %ux%u\n", width, height); + return -ENOENT; + } + + format = platsch_format_find(fmt_specifier); + if (!format) { + if (strlen(fmt_specifier)) + platsch_error("unknown format specifier %s\n", fmt_specifier); + goto fallback_format; + } + + dev->format = format; + + return 0; + +fallback: + memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode)); + dev->width = conn->modes[0].hdisplay; + dev->height = conn->modes[0].vdisplay; + platsch_debug("using default mode for connector #%u\n", conn->connector_id); + +fallback_format: + dev->format = &platsch_formats[0]; + platsch_debug("using default format %s for connector #%u\n", dev->format->name, conn->connector_id); + + return 0; +} + +static int drmprepare_connector(int fd, drmModeRes *res, drmModeConnector *conn, + struct modeset_dev *dev) +{ + int ret; + + /* check if a monitor is connected */ + if (conn->connection != DRM_MODE_CONNECTED) { + platsch_error("Ignoring unused connector #%u\n", conn->connector_id); + return -ENOENT; + } + + /* check if there is at least one valid mode */ + if (conn->count_modes == 0) { + platsch_error("no valid mode for connector #%u\n", conn->connector_id); + return -EFAULT; + } + + /* configure mode information in our device structure */ + ret = set_env_connector_mode(conn, dev); + if (ret) { + platsch_error("no valid mode for connector #%u\n", conn->connector_id); + return ret; + } + platsch_debug("mode for connector #%u is %ux%u@%s\n", conn->connector_id, dev->width, dev->height, + dev->format->name); + + /* find a crtc for this connector */ + ret = drmprepare_crtc(fd, res, conn, dev); + if (ret) { + platsch_error("no valid crtc for connector #%u\n", conn->connector_id); + return ret; + } + + /* create a framebuffer for this CRTC */ + ret = modeset_create_fb(fd, dev); + if (ret) { + platsch_error("cannot create framebuffer for connector #%u\n", conn->connector_id); + return ret; + } + + return 0; +} + +static int drmprepare(int fd) +{ + drmModeRes *res; + drmModeConnector *conn; + unsigned int i; + struct modeset_dev *dev; + int ret; + + /* retrieve resources */ + res = drmModeGetResources(fd); + if (!res) { + platsch_error("cannot retrieve DRM resources: %m\n"); + return -errno; + } + + platsch_debug("Found %d connectors\n", res->count_connectors); + + /* iterate all connectors */ + for (i = 0; i < res->count_connectors; ++i) { + /* get information for each connector */ + conn = drmModeGetConnector(fd, res->connectors[i]); + if (!conn) { + platsch_error("Cannot retrieve DRM connector #%u: %m\n", res->connectors[i]); + continue; + } + assert(conn->connector_id == res->connectors[i]); + + platsch_debug("Connector #%u has type %s\n", conn->connector_id, + drmModeGetConnectorTypeName(conn->connector_type)); + + /* create a device structure */ + dev = malloc(sizeof(*dev)); + if (!dev) { + platsch_error("Cannot allocate memory for connector #%u: %m\n", res->connectors[i]); + continue; + } + memset(dev, 0, sizeof(*dev)); + dev->conn_id = conn->connector_id; + + ret = drmprepare_connector(fd, res, conn, dev); + if (ret) { + if (ret != -ENOENT) { + platsch_error("Cannot setup device for connector #%u: %m\n", + res->connectors[i]); + } + free(dev); + drmModeFreeConnector(conn); + continue; + } + + /* free connector data and link device into global list */ + drmModeFreeConnector(conn); + dev->next = modeset_list; + modeset_list = dev; + } + + /* free resources again */ + drmModeFreeResources(res); + return 0; +} + +static int drmfd; + +struct modeset_dev *platsch_init(void) +{ + char drmdev[PLATSCH_MAX_FILENAME_LENGTH]; + int ret = 0, i; + + for (i = 0; i < 64; i++) { + struct drm_mode_card_res res = {0}; + + /* + * XXX: Maybe use drmOpen instead? + * (Where should name/busid come from?) + * XXX: Loop through drm devices to find one with connectors. + */ + ret = snprintf(drmdev, sizeof(drmdev), DRM_DEV_NAME, DRM_DIR_NAME, i); + if (ret >= sizeof(drmdev)) { + platsch_error("Huh, device name overflowed buffer\n"); + goto fail; + } + + drmfd = open(drmdev, O_RDWR | O_CLOEXEC, 0); + if (drmfd < 0) { + platsch_error("Failed to open drm device: %m\n"); + goto fail; + } + + ret = drmIoctl(drmfd, DRM_IOCTL_MODE_GETRESOURCES, &res); + if (ret < 0) { + close(drmfd); + continue; + } else { + /* Device found */ + break; + } + } + + if (i == 64) { + platsch_error("No suitable DRM device found\n"); + goto fail; + } + + ret = drmprepare(drmfd); + if (ret) { + platsch_error("Failed to prepare DRM device\n"); + goto fail; + } + + return modeset_list; + +fail: + return NULL; +} + +void platsch_setup_display(struct modeset_dev *dev) +{ + int ret = 0; + + if (dev->setmode) { + ret = drmModeSetCrtc(drmfd, dev->crtc_id, dev->fb_id, 0, 0, &dev->conn_id, 1, + &dev->mode); + if (ret) { + platsch_error("Cannot set CRTC for connector #%u: %m\n", dev->conn_id); + } + /* don't need to set the mode again */ + dev->setmode = 0; + } else { + ret = drmModePageFlip(drmfd, dev->crtc_id, dev->fb_id, 0, NULL); + if (ret) { + platsch_error("Page flip failed on connector #%u: %m\n", dev->conn_id); + } + } +} + +void platsch_draw(struct modeset_dev *dev, const char *dir, const char *base) +{ + draw_buffer(dev, dir, base); + platsch_setup_display(dev); +} + +void platsch_drmDropMaster(void) +{ + int ret = 0; + + ret = drmDropMaster(drmfd); + if (ret) + platsch_error("Failed to drop master on drm device\n"); + +} diff --git a/libplatsch.h b/libplatsch.h new file mode 100644 index 0000000..cf84c1d --- /dev/null +++ b/libplatsch.h @@ -0,0 +1,43 @@ +#ifndef __LIBPLATSCH_H__ +#define __LIBPLATSCH_H__ + +#include +#include +#include + +#define platsch_debug(fmt, ...) printf("%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define platsch_error(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) +#define PLATSCH_MAX_FILENAME_LENGTH 128 +struct platsch_format { + uint32_t format; + uint32_t bpp; + const char *name; +}; +struct modeset_dev { + struct modeset_dev *next; + + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t size; + const struct platsch_format *format; + uint32_t handle; + void *map; + bool setmode; + drmModeModeInfo mode; + uint32_t fb_id; + uint32_t conn_id; + uint32_t crtc_id; +}; + +static const struct platsch_format platsch_formats[] = { + { DRM_FORMAT_RGB565, 16, "RGB565" }, /* default */ + { DRM_FORMAT_XRGB8888, 32, "XRGB8888" }, +}; + +struct modeset_dev *platsch_init(void); +void platsch_draw(struct modeset_dev *dev, const char *dir, const char *base); +void platsch_drmDropMaster(void); +void platsch_setup_display(struct modeset_dev *dev); + +#endif diff --git a/meson.build b/meson.build index 9060514..ccc3d2d 100644 --- a/meson.build +++ b/meson.build @@ -4,8 +4,18 @@ dep_libdrm = dependency('libdrm', version: '>= 2.4.112' ) +libplasch_sources = ['libplatsch.c'] + +libplatsch = static_library('platsch', + libplasch_sources, + dependencies: dep_libdrm +) + +platsch_sources = ['platsch.c'] + executable('platsch', - 'platsch.c', + platsch_sources, + link_with: libplatsch, dependencies: dep_libdrm, install: true, install_dir: 'sbin' diff --git a/platsch.c b/platsch.c index 1aaa8d5..6503066 100644 --- a/platsch.c +++ b/platsch.c @@ -19,48 +19,22 @@ * https://raw.githubusercontent.com/dvdhrm/docs/master/drm-howto/modeset.c */ -#include -#include -#include +#include #include #include -#include -#include #include #include #include #include -#include -#include -#include -#include - -#include -#include -#include - -#define debug(fmt, ...) printf("%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__) -#define error(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) -struct platsch_format { - uint32_t format; - uint32_t bpp; - const char *name; -}; - -static const struct platsch_format platsch_formats[] = { - { DRM_FORMAT_RGB565, 16, "RGB565" }, /* default */ - { DRM_FORMAT_XRGB8888, 32, "XRGB8888" }, -}; +#include "libplatsch.h" -void redirect_stdfd(void) +void platsch_redirect_stdfd(void) { int devnull = open("/dev/null", O_RDWR, 0); if (devnull < 0) { - error("Failed to open /dev/null: %m\n"); + platsch_error("Failed to open /dev/null: %m\n"); return; } @@ -73,475 +47,6 @@ void redirect_stdfd(void) close(devnull); } -ssize_t readfull(int fd, void *buf, size_t count) -{ - ssize_t ret = 0, err; - - while (count > 0) { - err = read(fd, buf, count); - if (err < 0) - return err; - else if (err > 0) { - buf += err; - count -= err; - ret += err; - } else { - return ret; - } - } - - return ret; -} - -struct modeset_dev { - struct modeset_dev *next; - - uint32_t width; - uint32_t height; - uint32_t stride; - uint32_t size; - const struct platsch_format *format; - uint32_t handle; - void *map; - - bool setmode; - drmModeModeInfo mode; - uint32_t fb_id; - uint32_t conn_id; - uint32_t crtc_id; -}; - -void draw_buffer(struct modeset_dev *dev, const char *dir, const char *base) -{ - int fd_src; - char filename[128]; - ssize_t size; - int ret; - - /* - * make it easy and load a raw file in the right format instead of - * opening an (say) PNG and convert the image data to the right format. - */ - ret = snprintf(filename, sizeof(filename), - "%s/%s-%ux%u-%s.bin", - dir, base, dev->width, dev->height, dev->format->name); - if (ret >= sizeof(filename)) { - error("Failed to fit filename into buffer\n"); - return; - } - - fd_src = open(filename, O_RDONLY | O_CLOEXEC); - if (fd_src < 0) { - error("Failed to open %s: %m\n", filename); - return; - } - - size = readfull(fd_src, dev->map, dev->size); - if (size < dev->size) { - if (size < 0) - error("Failed to read from %s: %m\n", filename); - else - error("Could only read %zd/%u bytes from %s\n", - size, dev->size, filename); - } - - ret = close(fd_src); - if (ret < 0) { - /* Nothing we can do about this, so just warn */ - error("Failed to close image file\n"); - } - - return; -} - -static struct modeset_dev *modeset_list = NULL; - -static int drmprepare_crtc(int fd, drmModeRes *res, drmModeConnector *conn, - struct modeset_dev *dev) -{ - drmModeEncoder *enc; - unsigned int i, j; - int32_t crtc_id; - struct modeset_dev *iter; - - /* first try the currently connected encoder+crtc */ - if (conn->encoder_id) { - debug("connector #%d uses encoder #%d\n", conn->connector_id, - conn->encoder_id); - enc = drmModeGetEncoder(fd, conn->encoder_id); - assert(enc); - assert(enc->encoder_id == conn->encoder_id); - } else { - debug("connector #%d has no active encoder\n", - conn->connector_id); - enc = NULL; - dev->setmode = 1; - } - - if (enc) { - if (enc->crtc_id) { - crtc_id = enc->crtc_id; - assert(crtc_id >= 0); - - for (iter = modeset_list; iter; iter = iter->next) { - if (iter->crtc_id == crtc_id) { - crtc_id = -1; - break; - } - } - - if (crtc_id > 0) { - debug("encoder #%d uses crtc #%d\n", - enc->encoder_id, enc->crtc_id); - drmModeFreeEncoder(enc); - dev->crtc_id = crtc_id; - return 0; - } else { - debug("encoder #%d used crtc #%d, but that's in use\n", - enc->encoder_id, iter->crtc_id); - } - } else { - debug("encoder #%d doesn't have an active crtc\n", - enc->encoder_id); - } - - drmModeFreeEncoder(enc); - } - - /* If the connector is not currently bound to an encoder or if the - * encoder+crtc is already used by another connector (actually unlikely - * but let's be safe), iterate all other available encoders to find a - * matching CRTC. */ - for (i = 0; i < conn->count_encoders; ++i) { - enc = drmModeGetEncoder(fd, conn->encoders[i]); - if (!enc) { - error("Cannot retrieve encoder %u: %m\n", - conn->encoders[i]); - continue; - } - assert(enc->encoder_id == conn->encoders[i]); - - /* iterate all global CRTCs */ - for (j = 0; j < res->count_crtcs; ++j) { - /* check whether this CRTC works with the encoder */ - if (!(enc->possible_crtcs & (1 << j))) - continue; - - /* check that no other device already uses this CRTC */ - crtc_id = res->crtcs[j]; - for (iter = modeset_list; iter; iter = iter->next) { - if (iter->crtc_id == crtc_id) { - crtc_id = -1; - break; - } - } - - /* we have found a CRTC, so save it and return */ - if (crtc_id >= 0) { - debug("encoder #%d will use crtc #%d\n", - enc->encoder_id, crtc_id); - drmModeFreeEncoder(enc); - dev->crtc_id = crtc_id; - return 0; - } - - } - drmModeFreeEncoder(enc); - } - - error("Cannot find suitable CRTC for connector #%u\n", - conn->connector_id); - return -ENOENT; -} - -static int modeset_create_fb(int fd, struct modeset_dev *dev) -{ - struct drm_mode_create_dumb creq; - struct drm_mode_destroy_dumb dreq; - struct drm_mode_map_dumb mreq; - int ret; - - /* create dumb buffer */ - memset(&creq, 0, sizeof(creq)); - creq.width = dev->width; - creq.height = dev->height; - creq.bpp = dev->format->bpp; - ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); - if (ret < 0) { - error("Cannot create dumb buffer: %m\n"); - return -errno; - } - dev->stride = creq.pitch; - dev->size = creq.size; - dev->handle = creq.handle; - - /* create framebuffer object for the dumb-buffer */ - ret = drmModeAddFB2(fd, dev->width, dev->height, - dev->format->format, - (uint32_t[4]){ dev->handle, }, - (uint32_t[4]){ dev->stride, }, - (uint32_t[4]){ 0, }, - &dev->fb_id, 0); - if (ret) { - ret = -errno; - error("Cannot create framebuffer: %m\n"); - goto err_destroy; - } - - /* prepare buffer for memory mapping */ - memset(&mreq, 0, sizeof(mreq)); - mreq.handle = dev->handle; - ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); - if (ret) { - ret = -errno; - error("Cannot get mmap offset: %m\n"); - goto err_fb; - } - - /* perform actual memory mapping */ - dev->map = mmap(0, dev->size, PROT_READ | PROT_WRITE, MAP_SHARED, - fd, mreq.offset); - if (dev->map == MAP_FAILED) { - ret = -errno; - error("Cannot mmap dumb buffer: %m\n"); - goto err_fb; - } - - /* - * Clear the framebuffer. Normally it's overwritten later with some - * image data, but in case this fails, initialize to all-black. - */ - memset(dev->map, 0x0, dev->size); - - return 0; - -err_fb: - drmModeRmFB(fd, dev->fb_id); -err_destroy: - memset(&dreq, 0, sizeof(dreq)); - dreq.handle = dev->handle; - drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); - return ret; -} - -/* Returns lowercase connector type names with '_' for '-' */ -static char *get_normalized_conn_type_name(uint32_t connector_type) -{ - int i; - const char *connector_name; - char *normalized_name; - - connector_name = drmModeGetConnectorTypeName(connector_type); - if (!connector_name) - return NULL; - - normalized_name = strdup(connector_name); - - for (i = 0; normalized_name[i]; i++) { - normalized_name[i] = tolower(normalized_name[i]); - if (normalized_name[i] == '-') - normalized_name[i] = '_'; - } - - return normalized_name; -} - -static const struct platsch_format *platsch_format_find(const char *name) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(platsch_formats); i++) - if (!strcmp(platsch_formats[i].name, name)) - return &platsch_formats[i]; - - return NULL; -} - -static int set_env_connector_mode(drmModeConnector *conn, - struct modeset_dev *dev) -{ - int ret, i = 0; - u_int32_t width = 0, height = 0; - const char *mode; - char *connector_type_name, mode_env_name[32], fmt_specifier[32] = ""; - const struct platsch_format *format = NULL; - - connector_type_name = get_normalized_conn_type_name(conn->connector_type); - if (!connector_type_name) { - error("could not look up name for connector type %u\n", - conn->connector_type); - goto fallback; - } - - ret = snprintf(mode_env_name, sizeof(mode_env_name), "platsch_%s%u_mode", - connector_type_name, conn->connector_type_id); - free(connector_type_name); - if (ret >= sizeof(mode_env_name)) { - error("failed to fit platsch env mode variable name into buffer\n"); - return -EFAULT; - } - - /* check for connector mode configuration in environment */ - debug("looking up %s env variable\n", mode_env_name); - mode = getenv(mode_env_name); - if (!mode) - goto fallback; - - /* format suffix is optional */ - ret = sscanf(mode, "%ux%u@%s", &width, &height, fmt_specifier); - if (ret < 2) { - error("error while scanning %s for mode\n", mode_env_name); - return -EFAULT; - } - - /* use first mode matching given resolution */ - for (i = 0; i < conn->count_modes; i++) { - drmModeModeInfo mode = conn->modes[i]; - if (mode.hdisplay == width && mode.vdisplay == height) { - memcpy(&dev->mode, &mode, sizeof(dev->mode)); - dev->width = width; - dev->height = height; - break; - } - } - - if (i == conn->count_modes) { - error("no mode available matching %ux%u\n", width, height); - return -ENOENT; - } - - format = platsch_format_find(fmt_specifier); - if (!format) { - if (strlen(fmt_specifier)) - error("unknown format specifier %s\n", fmt_specifier); - goto fallback_format; - } - - dev->format = format; - - return 0; - -fallback: - memcpy(&dev->mode, &conn->modes[0], sizeof(dev->mode)); - dev->width = conn->modes[0].hdisplay; - dev->height = conn->modes[0].vdisplay; - debug("using default mode for connector #%u\n", conn->connector_id); - -fallback_format: - dev->format = &platsch_formats[0]; - debug("using default format %s for connector #%u\n", dev->format->name, - conn->connector_id); - - return 0; -} - -static int drmprepare_connector(int fd, drmModeRes *res, drmModeConnector *conn, - struct modeset_dev *dev) -{ - int ret; - - /* check if a monitor is connected */ - if (conn->connection != DRM_MODE_CONNECTED) { - error("Ignoring unused connector #%u\n", conn->connector_id); - return -ENOENT; - } - - /* check if there is at least one valid mode */ - if (conn->count_modes == 0) { - error("no valid mode for connector #%u\n", conn->connector_id); - return -EFAULT; - } - - /* configure mode information in our device structure */ - ret = set_env_connector_mode(conn, dev); - if (ret) { - error("no valid mode for connector #%u\n", conn->connector_id); - return ret; - } - debug("mode for connector #%u is %ux%u@%s\n", - conn->connector_id, dev->width, dev->height, dev->format->name); - - /* find a crtc for this connector */ - ret = drmprepare_crtc(fd, res, conn, dev); - if (ret) { - error("no valid crtc for connector #%u\n", conn->connector_id); - return ret; - } - - /* create a framebuffer for this CRTC */ - ret = modeset_create_fb(fd, dev); - if (ret) { - error("cannot create framebuffer for connector #%u\n", - conn->connector_id); - return ret; - } - - return 0; -} - -static int drmprepare(int fd) -{ - drmModeRes *res; - drmModeConnector *conn; - unsigned int i; - struct modeset_dev *dev; - int ret; - - /* retrieve resources */ - res = drmModeGetResources(fd); - if (!res) { - error("cannot retrieve DRM resources: %m\n"); - return -errno; - } - - debug("Found %d connectors\n", res->count_connectors); - - /* iterate all connectors */ - for (i = 0; i < res->count_connectors; ++i) { - /* get information for each connector */ - conn = drmModeGetConnector(fd, res->connectors[i]); - if (!conn) { - error("Cannot retrieve DRM connector #%u: %m\n", - res->connectors[i]); - continue; - } - assert(conn->connector_id == res->connectors[i]); - - debug("Connector #%u has type %s\n", conn->connector_id, - drmModeGetConnectorTypeName(conn->connector_type)); - - /* create a device structure */ - dev = malloc(sizeof(*dev)); - if (!dev) { - error("Cannot allocate memory for connector #%u: %m\n", - res->connectors[i]); - continue; - } - memset(dev, 0, sizeof(*dev)); - dev->conn_id = conn->connector_id; - - ret = drmprepare_connector(fd, res, conn, dev); - if (ret) { - if (ret != -ENOENT) { - error("Cannot setup device for connector #%u: %m\n", - res->connectors[i]); - } - free(dev); - drmModeFreeConnector(conn); - continue; - } - - /* free connector data and link device into global list */ - drmModeFreeConnector(conn); - dev->next = modeset_list; - modeset_list = dev; - } - - /* free resources again */ - drmModeFreeResources(res); - return 0; -} - static struct option longopts[] = { { "help", no_argument, 0, 'h' }, @@ -552,7 +57,7 @@ static struct option longopts[] = static void usage(const char *prog) { - error("Usage:\n" + platsch_error("Usage:\n" "%s [-d|--directory ] [-b|--basename ]\n" " [-h|--help]\n", prog); @@ -561,14 +66,12 @@ static void usage(const char *prog) int main(int argc, char *argv[]) { char **initsargv; - int drmfd; - char drmdev[128]; struct modeset_dev *iter; bool pid1 = getpid() == 1; const char *dir = "/usr/share/platsch"; const char *base = "splash"; const char *env; - int ret = 0, c, i; + int ret = 0, c; env = getenv("platsch_directory"); if (env) @@ -580,7 +83,7 @@ int main(int argc, char *argv[]) if (!pid1) { while ((c = getopt_long(argc, argv, "hd:b:", longopts, NULL)) != EOF) { - switch(c) { + switch (c) { case 'd': dir = optarg; break; @@ -598,77 +101,28 @@ int main(int argc, char *argv[]) } if (optind < argc) { - error("Too many arguments!\n"); + platsch_error("Too many arguments!\n"); usage(basename(argv[0])); exit(1); } } - for (i = 0; i < 64; i++) { - struct drm_mode_card_res res = {0}; - - /* - * XXX: Maybe use drmOpen instead? - * (Where should name/busid come from?) - * XXX: Loop through drm devices to find one with connectors. - */ - ret = snprintf(drmdev, sizeof(drmdev), DRM_DEV_NAME, DRM_DIR_NAME, i); - if (ret >= sizeof(drmdev)) { - error("Huh, device name overflowed buffer\n"); - goto execinit; - } - - drmfd = open(drmdev, O_RDWR | O_CLOEXEC, 0); - if (drmfd < 0) { - error("Failed to open drm device: %m\n"); - goto execinit; - } - - ret = drmIoctl(drmfd, DRM_IOCTL_MODE_GETRESOURCES, &res); - if (ret < 0) { - close(drmfd); - continue; - } else { - /* Device found */ - break; - } + struct modeset_dev *modeset_list = platsch_init(); + if (!modeset_list) { + platsch_error("Failed to initialize modeset\n"); + return EXIT_FAILURE; } - ret = drmprepare(drmfd); - assert(!ret); - for (iter = modeset_list; iter; iter = iter->next) { - - /* draw first then set the mode */ - draw_buffer(iter, dir, base); - - if (iter->setmode) { - debug("set crtc\n"); - - ret = drmModeSetCrtc(drmfd, iter->crtc_id, iter->fb_id, - 0, 0, &iter->conn_id, 1, &iter->mode); - if (ret) - error("Cannot set CRTC for connector #%u: %m\n", - iter->conn_id); - } else { - debug("page flip\n"); - ret = drmModePageFlip(drmfd, iter->crtc_id, iter->fb_id, - 0, NULL); - if (ret) - error("Page flip failed on connector #%u: %m\n", - iter->conn_id); - } + platsch_draw(iter, dir, base); } - ret = drmDropMaster(drmfd); - if (ret) - error("Failed to drop master on drm device\n"); + platsch_drmDropMaster(); -execinit: if (pid1) { ret = fork(); if (ret < 0) { - error("failed to fork for init: %m\n"); + platsch_error("failed to fork for init: %m\n"); } else if (ret == 0) { /* * in the child go to sleep to keep the drm device open @@ -679,7 +133,7 @@ execinit: initsargv = calloc(sizeof(argv[0]), argc + 1); if (!initsargv) { - error("failed to allocate argv for init\n"); + platsch_error("failed to allocate argv for init\n"); return EXIT_FAILURE; } memcpy(initsargv, argv, argc * sizeof(argv[0])); @@ -688,13 +142,13 @@ execinit: execv("/sbin/init", initsargv); - error("failed to exec init: %m\n"); + platsch_error("failed to exec init: %m\n"); return EXIT_FAILURE; } sleep: - redirect_stdfd(); + platsch_redirect_stdfd(); do { sleep(10); -- 2.34.1