From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Thu, 13 Jun 2024 09:33:00 +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 1sHexA-005FX2-1D for lore@lore.pengutronix.de; Thu, 13 Jun 2024 09:33:00 +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 1sHex9-0006mw-3x; Thu, 13 Jun 2024 09:32:59 +0200 Received: from mail-vi1eur04on20619.outbound.protection.outlook.com ([2a01:111:f403:2611::619] helo=EUR04-VI1-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 1sHeYV-0004K5-8h; Thu, 13 Jun 2024 09:07:35 +0200 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=IVfGYoaEbdlS9wQ/N5kF98zzeimK1RE6kkXMaaC/qzqwi3cwjuyMwbqSQ4rpDwRs81NWBmA9iGkOLCG61qagxp2gGu2+odPnKWBb3yi7BzCu1NUMm+1KtMESKc57kIlsXzMBAU6/Bla+MBsDntxZeU2X3cpXMn7jToam1+SqcDKLtpoczPy3MawPpcp04SHPAbp5LGNDCwjieif+cLKrLPpt1ES6qgc4gl2vSP7mlhJppaHeqFbkltImVTDnGAQbz1JOesgNBuxr5p5hSjowk4n2tDoxNWBzk8xzGUC3UXY3ImWPtGg1D6nrxt3F364Q/OPhiBfDfdhdyuOQKl699w== 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=C/MAB2H3qZ2WCIXEvmhqrCFMGkQXowMvSXobGOxnchc=; b=Ehy39he9r8Dloqide+RrHOnNTGbHXCXRIE1kQ1pAwxs2yezeOJaVmPGPXMG3sdHb0wgXl4Ej2pOOTwxrtvQZSYNchmo20gU7s92pc3tKujwhgZUGDOxMouzKw78jtkMAfUmgPuIcE1bnR5Gprt4jyBPmDVkYWvTM50FNZ/gI/bryBR+EgM4FpuGvDW6bVwV17nVZlqcr7fUnOCD6ARq0alaABz6OsPco6pYHVxlJroAqWw6Cxy8ue+SvIuKofHDW0O9LkXyhqOIQXJ+V7uFbUO9HbdAlyG1JttaolwfM2bJjBt7dv/o0LVB1Fco5Ju6A5v7JewP+2CgvhiTRJfPjhw== 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=C/MAB2H3qZ2WCIXEvmhqrCFMGkQXowMvSXobGOxnchc=; b=SlEMPbrOnjRuPApejSbHrYRii9KvwdlfZJgqiZA4zwgnLTqOqeDJktdX3Qd2zgaQS/Z95a4uZARWpkBl61OJ2krQHQI04WHCSRmXJjhHMYyX29Nvc8kAtGU0ZzP2l2nnGBvtr3WAD4h22IOI3Op/YOUp2NJZluuLww5hXVyHdNY= Received: from DU2P251CA0003.EURP251.PROD.OUTLOOK.COM (2603:10a6:10:230::13) by DUZPR06MB8621.eurprd06.prod.outlook.com (2603:10a6:10:4b1::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.20; Thu, 13 Jun 2024 07:07:28 +0000 Received: from DU6PEPF0000A7E1.eurprd02.prod.outlook.com (2603:10a6:10:230:cafe::8d) by DU2P251CA0003.outlook.office365.com (2603:10a6:10:230::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.24 via Frontend Transport; Thu, 13 Jun 2024 07:07:28 +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 DU6PEPF0000A7E1.mail.protection.outlook.com (10.167.8.40) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.15 via Frontend Transport; Thu, 13 Jun 2024 07:07:28 +0000 Received: from aherlnxbspsrv01.lgs-net.com ([10.60.34.116]) by hexagon.com with Microsoft SMTPSVC(10.0.17763.1697); Thu, 13 Jun 2024 09:07:26 +0200 From: LI Qingwu To: Qing-wu.Li@leica-geosystems.com.cn, oss-tools@pengutronix.de, m.felsch@pengutronix.de Date: Thu, 13 Jun 2024 09:07:23 +0200 Message-Id: <20240613070724.3400651-3-Qing-wu.Li@leica-geosystems.com.cn> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240613070724.3400651-1-Qing-wu.Li@leica-geosystems.com.cn> References: <20240613070724.3400651-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: 13 Jun 2024 07:07:26.0133 (UTC) FILETIME=[58921650:01DABD60] X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DU6PEPF0000A7E1:EE_|DUZPR06MB8621:EE_ X-MS-Office365-Filtering-Correlation-Id: dc8066ca-2078-4afd-6270-08dc8b777c71 X-SET-LOWER-SCL-SCANNER: YES X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230034|36860700007|376008|1800799018|82310400020; X-Microsoft-Antispam-Message-Info: =?utf-8?B?ZlVmL2FENUNjcHhCdVpRWitrZDFRZCtHUkpaamUwSEw4aStZSkEzWWE3U3dV?= =?utf-8?B?Y0VRQVlJZFdpSEIrR0M0VDYyNmFTSmdiSldNU3VuQjUrOW9LdXRzY0lMZXZG?= =?utf-8?B?bC8xQ0VQZlZWTXMyc0JqTm05RGE1U2pJUXRtaklyb2xkZExWVGprMWxvRVRJ?= =?utf-8?B?aDIzZlZ5R1pMeDFRMklKZ1cxMG5zSEdkeXNhZUZXcGlIL2lHR3Z5ckdLOXBj?= =?utf-8?B?amJJajdJOUZ5Nk1MYVU2MEVRYXVuNUd1dEp0WU4zUGk5bUhQMklkUUp5a05m?= =?utf-8?B?OEpDNmt3OFhiekVBVUF1NElZeTBVSEZLSVdUV3k2VkthZEFpeHJWTTdFS29K?= =?utf-8?B?MUsxdVM3MGluRmtaSmhKWEFleFAwdXdDREhBOUZnall4dnFEV3h1aTluNldz?= =?utf-8?B?SW1vV0k4TmhRNDBXbU9XMFN6MjN0SzlaZGszbGZ6Q3NzVXNHTTRjYzk4djJN?= =?utf-8?B?VHdraHZlTWpEd0tleEpnVU5Bc1pNeG5zOGJuQ1hhb3lWN2lLU2paOVFSVlJC?= =?utf-8?B?Y0FiZDJhaUFVUGtnZkdRcldrS2w1Q2FQaVI4M2tYQVBka0N6TVJmWUNGaE8z?= =?utf-8?B?ZHBNb1V4ZjVZblh1Q3lQVkpGbitQSEVRNk01dlV1WjdMRnRrR1FZSDc2NFBK?= =?utf-8?B?UUpKYjZOcHI4Y1h1R3h3U0dDZkFXYUZsRHhMR05CcWtKVDVxMm90UGR4QUV1?= =?utf-8?B?dEJUeEVqL2FaMVVyUVZZdUpKdnRiS0NqMmhuZ1ByVXprZzZyTXJXbm9oRitx?= =?utf-8?B?cTJVTUhqR09NbGhKdjhoTWtvTGlCZ2FucXRUSjNsK2JkQUF6NFVidUxyZC9K?= =?utf-8?B?OWRsTWVMY1BjVVUzZmF0ZjhiUTIzQVpvU09mczFPZjRmOXFNMlQxcmNOT1Zv?= =?utf-8?B?b3lXMW8velg3bzNSNUYxZHhIN1N2WEFTejNzbk1WU3JTZW5NWnZ0bHRIeHp4?= =?utf-8?B?TnI0U1Y0d1B2WVYveHk0Q1lpTVd5NEZVTkllZjlwMTRXT3JVcGxHd1h1Q3or?= =?utf-8?B?YzJGWnJVQ3RqZndNK29teFVyUXZaNXlaUlJucGs2ZlB5bkxxdUQ3cGU1V3lO?= =?utf-8?B?NmFEZWw1c0g0SDVyVG1NWXZzTEo4RlVvL0REUEsrbVA3RlJQZVBJbTBnYXRm?= =?utf-8?B?OWxIRmEzUkFpbXRRbGJxT0lVY0xTQWtJbmZmelgwNFVOeHJHY0JwK2U0eStU?= =?utf-8?B?dTdDVnpmL1U1TW13aGJDT0J0dEVPd1NPK01BSXlPd1NxU2E4eVA1d0Zqbllr?= =?utf-8?B?L0ZTcXEwaTVRdXQ3VzZHZVdTSTdUL1NCb3hQd0RpdUVIdTRqd2pFNWp6aHl3?= =?utf-8?B?SWZZRHdvelpHamxVYU0zQVJPSVU0ejI1SFFKSHFYdFcySm1jZ3gzV0JYWnZl?= =?utf-8?B?cCtRaU5hNkNkaVdKL3FLS2dPQWcyV0RBTThLY3BzOHlMNDIzcWlWWDJLbS9L?= =?utf-8?B?Q1Ztb1hGNzhBdDZSRCtIQ05aRmlLYnBla1EvU1ZNajNRei93dU02b2lkUGJV?= =?utf-8?B?MmJ1MU81M3VGeVlLYUxWY3RDS3ZrT1pWL1Z6SSswL2ZUUERpbTRZZWtuS0RS?= =?utf-8?B?ZXNNQ2ZkcnloRnhtYXZkZUh2dVZ3UG05bElva1dVWWpzVTdLMVVKZ1dnT2dP?= =?utf-8?B?UVJObkxSM3RiYWJ2UU5kY25ia3Fldjhod2JBcS95L0d4emdFN054MlNnOWd5?= =?utf-8?B?RHNKc3lETk5mb1p4em00eTk2SjRnMFlFdGNrTkZpR1QwZ0cvRWVJNVJJNkY0?= =?utf-8?B?YzFGeW5BM21hN1RSalBjZXcwNFNJRWc3Y0xRVTlHZmtnaVorcVVmSWhVaSsw?= =?utf-8?Q?BisAiChvjYWtiIq71gn7W0YefVVNbfCMvewXU=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:(13230034)(36860700007)(376008)(1800799018)(82310400020); DIR:OUT; SFP:1101; X-OriginatorOrg: leica-geosystems.com.cn X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 Jun 2024 07:07:28.3536 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: dc8066ca-2078-4afd-6270-08dc8b777c71 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: DU6PEPF0000A7E1.eurprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DUZPR06MB8621 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, T_SCC_BODY_TEXT_LINE,URIBL_SBL,URIBL_SBL_A autolearn=no autolearn_force=no version=3.4.2 X-Mailman-Approved-At: Thu, 13 Jun 2024 09:32:56 +0200 Subject: [OSS-Tools] [PATCH platsch V3 3/4] 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: , 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 | 590 +++++++++++++++++++++++++++++++++++++++++++++++++++ libplatsch.h | 51 +++++ meson.build | 13 +- platsch.c | 582 +------------------------------------------------- 4 files changed, 658 insertions(+), 578 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..1d48e0e --- /dev/null +++ b/libplatsch.c @@ -0,0 +1,590 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "libplatsch.h" +#include +#include +#include + +#include "libplatsch.h" + +void redirect_stdfd(void) +{ + int devnull = open("/dev/null", O_RDWR, 0); + + if (devnull < 0) { + error("Failed to open /dev/null: %m\n"); + return; + } + + close(STDIN_FILENO); + dup2(devnull, STDIN_FILENO); + close(STDOUT_FILENO); + dup2(devnull, STDOUT_FILENO); + close(STDERR_FILENO); + dup2(devnull, STDERR_FILENO); + 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; +} + +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 int drmfd; + +struct modeset_dev *init(void) +{ + static char drmdev[128]; + 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)) { + 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; + } + } + + if (i == 64) { + error("No suitable DRM device found\n"); + goto execinit; + } + + ret = drmprepare(drmfd); + if (ret) { + error("Failed to prepare DRM device\n"); + goto execinit; + } + + return modeset_list; + +execinit: + return NULL; +} + +void update_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) { + error("Cannot set CRTC for connector #%u: %m\n", dev->conn_id); + } + dev->setmode = 0; + } else { + ret = drmModePageFlip(drmfd, dev->crtc_id, dev->fb_id, 0, NULL); + if (ret) { + error("Page flip failed on connector #%u: %m\n", dev->conn_id); + } + } +} + +void draw(struct modeset_dev *dev, const char *dir, const char *base) +{ + draw_buffer(dev, dir, base); + update_display(dev); +} + +void finish(void) { drmDropMaster(drmfd); } + +void deinit(void) +{ + struct modeset_dev *iter; + + for (iter = modeset_list; iter; iter = iter->next) { + if (iter->map) { + munmap(iter->map, iter->size); + } + if (iter->fb_id) { + drmModeRmFB(drmfd, iter->fb_id); + } + free(iter); + } +} diff --git a/libplatsch.h b/libplatsch.h new file mode 100644 index 0000000..77f74a9 --- /dev/null +++ b/libplatsch.h @@ -0,0 +1,51 @@ +#ifndef __LIBPLATSCH_H__ +#define __LIBPLATSCH_H__ + +#include +#include +#include "libplatsch.h" +#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; +}; + +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" }, +}; + +ssize_t readfull(int fd, void *buf, size_t count); +struct modeset_dev *init(void); +void draw(struct modeset_dev *dev, const char *dir, const char *base); +void finish(void); +void redirect_stdfd(void); +void update_display(struct modeset_dev *dev); + +#endif \ No newline at end of file diff --git a/meson.build b/meson.build index 9f6be1e..dc55238 100644 --- a/meson.build +++ b/meson.build @@ -1,15 +1,18 @@ project('platsch', 'c') platsch_dep = dependency('libdrm', version : '>= 2.4.112', required : true) -sources = ['platsch.c'] +sources = ['libplatsch.c'] -# Define the headers -headers = ['platsch.h'] -# Create the platsch executable -executable('platsch', +libplatsch = static_library('libplatsch', sources, dependencies: platsch_dep, +) + +executable('platsch', + 'platsch.c', + dependencies: platsch_dep, + link_with: libplatsch, install: true, include_directories: include_directories('.') ) diff --git a/platsch.c b/platsch.c index 1aaa8d5..917fec0 100644 --- a/platsch.c +++ b/platsch.c @@ -19,528 +19,15 @@ * 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 "libplatsch.h" -#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" }, -}; - -void redirect_stdfd(void) -{ - int devnull = open("/dev/null", O_RDWR, 0); - - if (devnull < 0) { - error("Failed to open /dev/null: %m\n"); - return; - } - - close(STDIN_FILENO); - dup2(devnull, STDIN_FILENO); - close(STDOUT_FILENO); - dup2(devnull, STDOUT_FILENO); - close(STDERR_FILENO); - dup2(devnull, STDERR_FILENO); - 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[] = { @@ -561,14 +48,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 +65,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; @@ -604,67 +89,18 @@ int main(int argc, char *argv[]) } } - 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 = init(); + if (!modeset_list) { + 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); - } + draw(iter, dir, base); } - ret = drmDropMaster(drmfd); - if (ret) - error("Failed to drop master on drm device\n"); + finish(); -execinit: if (pid1) { ret = fork(); if (ret < 0) { -- 2.34.1