From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Wed, 12 Jun 2024 11:26:56 +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 1sHKFs-004jiP-0W for lore@lore.pengutronix.de; Wed, 12 Jun 2024 11:26:56 +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 1sHKFi-0004PI-Pm; Wed, 12 Jun 2024 11:26:46 +0200 Received: from mail-vi1eur05on20601.outbound.protection.outlook.com ([2a01:111:f403:2613::601] helo=EUR05-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 1sHInz-0002s3-KG; Wed, 12 Jun 2024 09:54:05 +0200 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Kfr+WTNcIB9YHWZjC7Qn0NK5Ki3KhiUcOY8m1HIRN01t7ifspAGtN6F5B4hvw5/FLMlqVVWrGrI/i6NOlSfHGVkXgHiJk2wjIQ8Ynk4eLKUwWQKlAxyRnqZdiNaWOwU671N8nQuHNGiDcl635yp+R76Ajj4CzgSallajha90+Z7iolRcESeVuF8ABVM7sJDul8vypAd63o98Fpm99uIcAMFNQX5ZLAEFo1DbF0F02qSpg6/PX5gmPhxdYETmAFCJCh9h7xcm9xHESs3GWdvGOOPfs9hqkog50gqizF97ccIqfs6MLOHyAFtT+iE3zoSFS6aXqOM7yChTlOjOdfWSQg== 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=aBpc/h5USsCoHdt5H6F3e/dC2qVl/Bhy1M0KlYcStFQ=; b=X5ej7rqLYpDzRnPLzTRZ41qhQ+RwDrzPVzi1lrimddgRSdmv7DhIa5TPW9UDQ+7WXqCrFqN2jeD9d8nwBAvlIrlxYB1VHOgTBVQa8LheAVfkLU5QzMvW6fG6HkzsP2QxWYhf6Omu+lNXraakkMSYU5GDs5P4oHWvbxdL9iFbrmOTCg2foyrfDxI2+nYDglGQzmJ3uQkeJbTx4gmH+JtIGHThzj+LSeDEVyNQQaJHuZF+k+6ERrz12+u/3fSb/xJ/37gD9tm5F3HkFIb2EtffDv3F6ojm9SCXqEj9wSnQGBt00jdb36rVDyOUq/pjk37squH+k/XCg6YwI7rCtXfGjQ== 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=aBpc/h5USsCoHdt5H6F3e/dC2qVl/Bhy1M0KlYcStFQ=; b=aweaHdFdmUyKrhiAD6LDw/QzXmaqo43ncJzauqWtx6J6cgE5Tkduh0prLFlrpgveTxke6KiIqUpvekOquGNboUPhEiLoMM4V2K/tqhtXQROzrZp8bNFcA/XlgdMOlPH9vlcuwTODxffOLk56w6WilICkLrSzNkg5F9tEoKDG8pE= Received: from DU2PR04CA0168.eurprd04.prod.outlook.com (2603:10a6:10:2b0::23) by DB9PR06MB7899.eurprd06.prod.outlook.com (2603:10a6:10:29a::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.20; Wed, 12 Jun 2024 07:53:57 +0000 Received: from DB5PEPF00014B8F.eurprd02.prod.outlook.com (2603:10a6:10:2b0:cafe::6) by DU2PR04CA0168.outlook.office365.com (2603:10a6:10:2b0::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.20 via Frontend Transport; Wed, 12 Jun 2024 07:53:57 +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 DB5PEPF00014B8F.mail.protection.outlook.com (10.167.8.203) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7677.15 via Frontend Transport; Wed, 12 Jun 2024 07:53:57 +0000 Received: from aherlnxbspsrv01.lgs-net.com ([10.60.34.116]) by hexagon.com with Microsoft SMTPSVC(10.0.17763.1697); Wed, 12 Jun 2024 09:53:55 +0200 From: LI Qingwu To: Qing-wu.Li@leica-geosystems.com.cn, oss-tools@pengutronix.de, m.felsch@pengutronix.de Date: Wed, 12 Jun 2024 09:53:52 +0200 Message-Id: <20240612075353.2551648-2-Qing-wu.Li@leica-geosystems.com.cn> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240612075353.2551648-1-Qing-wu.Li@leica-geosystems.com.cn> References: <20240612075353.2551648-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: 12 Jun 2024 07:53:55.0780 (UTC) FILETIME=[ACEAB040:01DABC9D] X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DB5PEPF00014B8F:EE_|DB9PR06MB7899:EE_ X-MS-Office365-Filtering-Correlation-Id: 48a9897b-e4e4-40a1-9d5c-08dc8ab4d04d X-SET-LOWER-SCL-SCANNER: YES X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230032|82310400018|36860700005|1800799016|376006; X-Microsoft-Antispam-Message-Info: =?utf-8?B?Z2JpRjhNODVtbWF2SURsNnpuZTluUnpTa0FiL2dZOGhkUUpVTElhTkNJVFo0?= =?utf-8?B?RHI3ZlEyditSK28zSEZGajRMT1ozWTZ6dUk5MWhWRXh5azU2VEdOTVppaThY?= =?utf-8?B?aXJWOGlVZEltVkNIbWhPN0hVQ3JLdTRVSzdweTltZExaUWFHNFRxV2NsVHBu?= =?utf-8?B?ckt3S2xCS0NlVDJqcTZNUHh0UVFReFlJeUUrc2RNTlNnTE9ueXoya1BnM3JY?= =?utf-8?B?NkY2b2FaTFA3ZXd2K1ozb2pwM2hrTjRkbit0amFoZkRueXpRakFuRlYrdS9C?= =?utf-8?B?a3MxSzhwZHpqWithN05vazNNQnM1eUUxNVFxMzc5bGVZV284OEFpSDhEUnV2?= =?utf-8?B?Y1hPNXovbnF0YTBEZTFNM28vYmw2VmxSZDlDZ2pITmpGUWJaZ3dBRVpScGRZ?= =?utf-8?B?UmVINzZhY253dUVVQnBETmIzcUk3N3FkdTg1VWdTZVhyYkt3eFcvUmRla0lz?= =?utf-8?B?bnBXZmRjelNseEFEV2FZdnhXL3E0SXpTaFlLS1EzOVdkOE5CcU42MkRoaVlB?= =?utf-8?B?N1lUR3FSMERwWWhwSThRN01VNUFOVldhTVIxUzByREwxcVg4bG92emFPWmND?= =?utf-8?B?dXBvdWVPVTUrVkhkZmpoUitid3dZaS9GOVFQYXI2TFpVRUpzVHBUVU9GYnJy?= =?utf-8?B?M0k3eEVMbnB3dHpSV3NZR281eXNOdlM1Wmd3eEpYVm95SVZEc29mZFJtMnpj?= =?utf-8?B?ZURtbkdhaFkyR0J2UmdsYXdyQm1TeTJoM01taHRMd3M4dE9GRFNPTVk5Um1n?= =?utf-8?B?THRFdTNKQ2lGdm55ODU5L0dhSkY2TjI2YkVDNjhPWUFtTTZJZTRiUzh1TlFt?= =?utf-8?B?ckhwOFV0SXZ6ekNWUW16QkhEYVlGdERtZ3V6OFVYdXJGcHo5UThWZm5XUmY0?= =?utf-8?B?RWtpM0xFc1NtUnN3OFdBRWFQK3NidDA0T3pzQ1RQQ3NnR2x2M0Y0RXp0OHl3?= =?utf-8?B?MEJ2WGhvMzNYdForblV5Znp3L1FUZll5dW5BRWQwVE5CSTFGVTZ4ZTZDTWpG?= =?utf-8?B?MUxVRlAxMDFPNEUra21lb05qZFVibEVSWXpEUGxMNU5iTGlmMmV1MlVmY3N5?= =?utf-8?B?UDRHdTM4YXNCZlE2eXRVS1Q5L05vd3ErZlBCd0VDeVRzNmlkR05zb1dNTFor?= =?utf-8?B?OGJLUHVoWWN4S1hhdStodXFCeVZEcmNDZklZTkM1azZXR2k0bG0vZnV0TEZR?= =?utf-8?B?TU1Kd2dFZHYxMVlHMVllcVJKckswdHpIT0pheHlzbnZGaFFqNFF2Tk1CK0JC?= =?utf-8?B?TXBzcFFEL3ZPSWt6NWdCQTEyS1dUTEdFRWpLaGcwSHJBQXNlcHUvTjBsVlcy?= =?utf-8?B?TzRlMkhYeklVVGxrbWxMTHFzRSs2Yytzek9PWHNiOU5oMEtId1RTSnhscmZs?= =?utf-8?B?R2tIMjJodlg3Z2xyZk1EVnV5aVJCdEdPcjRxaGlreGZmTTd6ZW9YK3BVaXg2?= =?utf-8?B?T3JFMEpsU3M4dTVHOHFtRThvUWQ0bk5HSkVQd0lSWU9QTHYxc2l2dTRTMDlV?= =?utf-8?B?THVmVnVkUEpCbllJRGx2aW5VT1g5K05rUWZKRU5NRmtQdmZ3M3dyOFp5VEhz?= =?utf-8?B?RzYxWVhWMnFYTHlRdmQxdG1DbUZlSUhGSjRDZXV5UVh2TnJ6WVJMbGZ4d1lo?= =?utf-8?B?ZnQ0NTJNOC85RHN2NmdvdzZFMnB2dXJCYnZIM3pQZ0pMTjhYdDUwQVgvL3Nu?= =?utf-8?B?VlFmYUdkMVlTS3pRNUdhbWVmelFhQTFBbUZ3OXkyTkk0SkNmbUpPenZleHRz?= =?utf-8?B?YVNVaWRnZVVaT21UZnBCbkpGVThLRG95ZTNabkx6OWF1a3ZlT29lem56b2Rz?= =?utf-8?Q?6JuarIiZRyJWvzCwXytIZlzc5POUHPEzMC0Us=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:(13230032)(82310400018)(36860700005)(1800799016)(376006); DIR:OUT; SFP:1101; X-OriginatorOrg: leica-geosystems.com.cn X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Jun 2024 07:53:57.1855 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 48a9897b-e4e4-40a1-9d5c-08dc8ab4d04d 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: DB5PEPF00014B8F.eurprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR06MB7899 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: Wed, 12 Jun 2024 11:26:43 +0200 Subject: [OSS-Tools] [PATCH platsch 2/3] 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 --- cairo.c | 4 +- libplatsch.c | 614 ++++++++++++++++++++++++++++++++++++++ platsch.h => libplatsch.h | 45 ++- meson.build | 21 +- platsch.c | 534 +-------------------------------- 5 files changed, 677 insertions(+), 541 deletions(-) create mode 100644 libplatsch.c rename platsch.h => libplatsch.h (51%) diff --git a/cairo.c b/cairo.c index 8ced3b2..d651b7a 100644 --- a/cairo.c +++ b/cairo.c @@ -25,7 +25,7 @@ #include #include -#include "platsch.h" +#include "libplatsch.h" static struct cairo_ctx { struct modeset_dev *dev; @@ -255,7 +255,7 @@ static uint32_t convert_to_cairo_format(uint32_t format) return CAIRO_FORMAT_INVALID; } -static cairo_t *cairo_init(struct modeset_dev *dev, const char *dir, const char *base) +cairo_t *cairo_init(struct modeset_dev *dev, const char *dir, const char *base) { cairo_surface_t *surface; cairo_status_t status; diff --git a/libplatsch.c b/libplatsch.c new file mode 100644 index 0000000..9fceda4 --- /dev/null +++ b/libplatsch.c @@ -0,0 +1,614 @@ +/* + * 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 +#include +#include +#include "libplatsch.h" + + +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) +{ + 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; +} + +static int draw_buffer(struct modeset_dev *dev, const char *dir, const char *base) +{ + int fd_src; + char filename[128]; + ssize_t size; + int ret; + + /* Try cairo draw first and fall back in case of failure. */ + ret = cairo_draw_buffer(dev, dir, base); + if (ret == 0) + return 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 -EINVAL; + } + + fd_src = open(filename, O_RDONLY | O_CLOEXEC); + if (fd_src < 0) { + error("Failed to open %s: %m\n", filename); + return -ENOENT; + } + + 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); + return -EIO; + } + + ret = close(fd_src); + if (ret < 0) { + /* Nothing we can do about this, so just warn */ + error("Failed to close image file\n"); + return -EIO; + } + + return 0; +} + +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; +} + + +int 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); + } + } + return ret; +} + +int draw(struct modeset_dev *dev, const char *dir, const char *base) +{ + int ret = 0; + ret = draw_buffer(dev, dir, base); + if (ret) { + error("Failed to draw buffer\n"); + return ret; + } + return update_display(dev); +} + +int finish(void) { + int ret = drmDropMaster(drmfd); + if (ret) { + error("Failed to drop master on DRM device\n"); + } + + return ret; +} + +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/platsch.h b/libplatsch.h similarity index 51% rename from platsch.h rename to libplatsch.h index dee22eb..87f6ef5 100644 --- a/platsch.h +++ b/libplatsch.h @@ -1,8 +1,27 @@ -#ifndef __PLATSCH_H__ -#define __PLATSCH_H__ +#ifndef __LIBPLATSCH_H__ +#define __LIBPLATSCH_H__ -#include +#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__) @@ -17,7 +36,6 @@ struct platsch_format { struct modeset_dev { struct modeset_dev *next; - uint32_t width; uint32_t height; uint32_t stride; @@ -25,7 +43,6 @@ struct modeset_dev { const struct platsch_format *format; uint32_t handle; void *map; - bool setmode; drmModeModeInfo mode; uint32_t fb_id; @@ -34,14 +51,24 @@ struct modeset_dev { }; ssize_t readfull(int fd, void *buf, size_t count); +struct modeset_dev * init(void); -#ifdef HAVE_CAIRO -int cairo_draw_buffer(struct modeset_dev *dev, const char *dir, const char *base); -#else +int draw(struct modeset_dev *dev, const char *dir, const char *base); +int finish(void); +int update_display(struct modeset_dev *dev); + +#ifndef HAVE_CAIRO static inline int cairo_draw_buffer(struct modeset_dev *dev, const char *dir, const char *base) { + printf("cairo_draw_buffer do nothing %s %s\n", dir, base); return -ENOTSUP; } +#else + +#include +int cairo_draw_buffer(struct modeset_dev *dev, const char *dir, const char *base); +cairo_t *cairo_init(struct modeset_dev *dev, const char *dir, const char *base); + #endif /* HAVE_CAIRO */ -#endif /* __PLATSCH_H__ */ +#endif /* __LIBPLATSCH_H__ */ diff --git a/meson.build b/meson.build index e7e8e80..8c15fb9 100644 --- a/meson.build +++ b/meson.build @@ -1,26 +1,35 @@ project('platsch', 'c') +have_cairo = get_option('HAVE_CAIRO') + # Define dependencies conditionally based on the HAVE_CAIRO option platsch_dep = [dependency('libdrm', required: true)] -sources = ['platsch.c'] +sources = ['libplatsch.c'] args = [] -have_cairo = get_option('HAVE_CAIRO') - if have_cairo platsch_dep += dependency('cairo', required: true) sources += 'cairo.c' args += ['-DHAVE_CAIRO'] endif +# Create a static library from libplatsch.c and optionally cairo.c +libplatsch = static_library('libplatsch', + sources, + dependencies: platsch_dep, + c_args: args, + install: true +) + # Define the headers -headers = ['platsch.h'] +headers = ['libplatsch.h', 'platsch.h'] -# Create the platsch executable +# Create the platsch executable, linking it statically with libplatsch executable('platsch', - sources, + 'platsch.c', dependencies: platsch_dep, c_args: args, + link_with: libplatsch, install: true, include_directories: include_directories('.') ) diff --git a/platsch.c b/platsch.c index a7e82a6..92123d8 100644 --- a/platsch.c +++ b/platsch.c @@ -35,16 +35,7 @@ #include #include -#include -#include -#include - -#include "platsch.h" - -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) { @@ -64,461 +55,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; -} - -void draw_buffer(struct modeset_dev *dev, const char *dir, const char *base) -{ - int fd_src; - char filename[128]; - ssize_t size; - int ret; - - /* Try cairo draw first and fall back in case of failure. */ - ret = cairo_draw_buffer(dev, dir, base); - if (ret == 0) - return; - - /* - * 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[] = { @@ -539,14 +75,14 @@ static void usage(const char *prog) int main(int argc, char *argv[]) { char **initsargv; - int drmfd; - char drmdev[128]; + //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) @@ -582,67 +118,17 @@ 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