From 46d1ed733f99a6058b6117b0fa3c79b6f329caae Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 22 May 2014 22:49:57 +0200 Subject: m misc + most of the gamma-linux-drm stuff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gamma-linux-drm.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++- src/gamma-linux-drm.h | 4 +- src/gamma-quartz-cg.c | 3 +- src/libgamma-error.c | 35 +++++++++++ src/libgamma-error.h | 46 ++++++++++++++ 5 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 src/libgamma-error.c (limited to 'src') diff --git a/src/gamma-linux-drm.c b/src/gamma-linux-drm.c index fa0b517..e5e3482 100644 --- a/src/gamma-linux-drm.c +++ b/src/gamma-linux-drm.c @@ -19,13 +19,20 @@ # error Compiling gamma-linux-drm.c without HAVE_GAMMA_METHOD_LINUX_DRM #endif +#define _GNU_SOURCE + #include "gamma-linux-drm.h" #include "libgamma-error.h" -#include #include +#include +#include #include +#include +#include +#include +#include #include #include @@ -33,11 +40,34 @@ #ifndef O_CLOEXEC # define O_CLOEXEC 02000000 #endif +#ifndef NGROUPS_MAX +# define NGROUPS_MAX 65536 +#endif #ifndef PATH_MAX # define PATH_MAX 4096 #endif + +/** + * Graphics card data for the Direct Rendering Manager adjustment method + */ +typedef struct libgamma_drm_card_data +{ + /** + * File descriptor for the connection to the graphics card + */ + int fd; + + /** + * The graphics card's mode resources + */ + drmModeRes* res; + +} libgamma_drm_card_data_t; + + + /** * Return the capabilities of the adjustment method * @@ -147,7 +177,110 @@ int libgamma_linux_drm_site_restore(libgamma_site_state_t* restrict this) */ int libgamma_linux_drm_partition_initialise(libgamma_partition_state_t* restrict this, libgamma_site_state_t* restrict site, size_t partition) -{ +{ /* FIXME: This function is too large. */ + int rc = 0; + libgamma_drm_card_data_t* data; + char pathname[PATH_MAX]; + + /* Check for partition index overflow. */ + if (partition > INT_MAX) + return LIBGAMMA_NO_SUCH_PARTITION; + + /* Allocate and initialise graphics card data. */ + this->data = NULL; + data = malloc(sizeof(libgamma_drm_card_data_t)); + if (data == NULL) + return LIBGAMMA_ERRNO_SET; + data->fd = -1; + data->res = NULL; + + /* Get the pathname for the graphics card. */ + snprintf(pathname, sizeof(pathname) / sizeof(char), + DRM_DEV_NAME, DRM_DIR_NAME, (int)partition); + + /* Acquire access to the graphics card. */ + data->fd = open(pathname, O_RDWR | O_CLOEXEC); + if (data->fd < 0) + { + if ((errno == ENXIO) || (errno == ENODEV)) + rc = LIBGAMMA_NO_SUCH_PARTITION; + else if (errno == EACCES) + { + struct stat attr; + int r; + + r = stat(pathname, &attr); + rc = LIBGAMMA_NO_SUCH_PARTITION; + +#define __test(R, W) ((attr.st_mode & (R | W)) == (R | W)) + if (r) + rc = errno == EACCES ? LIBGAMMA_NO_SUCH_PARTITION : LIBGAMMA_ERRNO_SET; + else if ((attr.st_uid == geteuid() && __test(S_IRUSR, S_IWUSR)) || + (attr.st_gid == getegid() && __test(S_IRGRP, S_IWGRP)) || + __test(S_IROTH, S_IWOTH)) + rc = LIBGAMMA_DEVICE_ACCESS_FAILED; + else if (attr.st_gid == 0 /* root group */ || __test(S_IRGRP, S_IWGRP)) + rc = LIBGAMMA_DEVICE_RESTRICTED; + else + { + gid_t supplemental_groups[NGROUPS_MAX]; + struct group* group; + int i, n; + + n = getgroups(NGROUPS_MAX, supplemental_groups); + if (n < 0) + { + rc = LIBGAMMA_ERRNO_SET; + goto fail_data; + } + + for (i = 0; i < n; i++) + if (supplemental_groups[i] == attr.st_gid) + break; + + if (i != n) + { + rc = LIBGAMMA_DEVICE_ACCESS_FAILED; + goto fail_data; + } + + rc = LIBGAMMA_DEVICE_REQUIRE_GROUP; + errno = 0; + group = getgrgid(attr.st_gid); /* TODO: Not thread-safe. */ + libgamma_group_gid = attr.st_gid; + libgamma_group_name = group != NULL ? group->gr_name : NULL; + } +#undef __test + } + else + rc = LIBGAMMA_ERRNO_SET; + goto fail_data; + } + + /* Acquire mode resources. */ + data->res = drmModeGetResources(data->fd); + if (data->res == NULL) + { + rc = LIBGAMMA_ACQUIRING_MODE_RESOURCES_FAILED; + goto fail_fd; + } + + /* Get the number of CRTC:s that are available in the partition. */ + if (data->res->count_crtcs < 0) + { + rc = LIBGAMMA_NEGATIVE_CRTC_COUNT; + goto fail_res; + } + this->crtcs_available = (size_t)(data->res->count_crtcs); + return 0; + + fail_res: + drmModeFreeResources(data->res); + fail_fd: + close(data->fd); + fail_data: + free(data); + return rc; } @@ -158,6 +291,12 @@ int libgamma_linux_drm_partition_initialise(libgamma_partition_state_t* restrict */ void libgamma_linux_drm_partition_destroy(libgamma_partition_state_t* restrict this) { + libgamma_drm_card_data_t* data = this->data; + if (data->res != NULL) + drmModeFreeResources(data->res); + if (data->fd >= 0) + close(data->fd); + free(data); } @@ -188,6 +327,16 @@ int libgamma_linux_drm_partition_restore(libgamma_partition_state_t* restrict th int libgamma_linux_drm_crtc_initialise(libgamma_crtc_state_t* restrict this, libgamma_partition_state_t* restrict partition, size_t crtc) { + libgamma_drm_card_data_t* card; + uint32_t crtc_id; + + if (crtc >= partition->crtcs_available) + return LIBGAMMA_NO_SUCH_CRTC; + + card = partition->data; + crtc_id = card->res->crtcs[crtc]; + this->data = (void*)(size_t)crtc_id; + return 0; } @@ -242,6 +391,18 @@ int libgamma_linux_drm_get_crtc_information(libgamma_crtc_information_t* restric int libgamma_linux_drm_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, libgamma_gamma_ramps_t* restrict ramps) { + libgamma_drm_card_data_t* card = this->partition->data; + int r; +#ifdef DEBUG + if ((ramps->red_size != ramps->green_size) || + (ramps->red_size != ramps->blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + r = drmModeCrtcGetGamma(card->fd, (uint32_t)(this->crtc), (uint32_t)(ramps->red_size), + ramps->red, ramps->green, ramps->blue); + if (r < 0) + return LIBGAMMA_GAMMA_RAMP_READ_FAILED; + return 0; } diff --git a/src/gamma-linux-drm.h b/src/gamma-linux-drm.h index 2f757bf..91707ae 100644 --- a/src/gamma-linux-drm.h +++ b/src/gamma-linux-drm.h @@ -54,7 +54,7 @@ int libgamma_linux_drm_site_initialise(libgamma_site_state_t* restrict this, * * @param this The site state */ -void libgamma_linux_drm_site_destroy(libgamma_site_state_t* restrict this); +void libgamma_linux_drm_site_destroy(libgamma_site_state_t* restrict this) __attribute__((const)); /** * Restore the gamma ramps all CRTCS with a site to the system settings @@ -112,7 +112,7 @@ int libgamma_linux_drm_crtc_initialise(libgamma_crtc_state_t* restrict this, * * @param this The CRTC state */ -void libgamma_linux_drm_crtc_destroy(libgamma_crtc_state_t* restrict this); +void libgamma_linux_drm_crtc_destroy(libgamma_crtc_state_t* restrict this) __attribute__((const)); /** * Restore the gamma ramps for a CRTC to the system settings for that CRTC diff --git a/src/gamma-quartz-cg.c b/src/gamma-quartz-cg.c index 99d46e1..9bbe0a1 100644 --- a/src/gamma-quartz-cg.c +++ b/src/gamma-quartz-cg.c @@ -342,7 +342,8 @@ int libgamma_quartz_cg_crtc_set_gamma_rampsf(libgamma_crtc_state_t* restrict thi CGDirectDisplayID crtc_id = crtcs[this->crtc]; CGError r; #ifdef DEBUG - if ((ramps.red_size != ramps.green_size) || (ramps.red_size != ramps.blue_size)) + if ((ramps.red_size != ramps.green_size) || + (ramps.red_size != ramps.blue_size)) return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; #endif r = CGSetDisplayTransferByTable(crtc_id, (uint32_t)(ramps.red_size), diff --git a/src/libgamma-error.c b/src/libgamma-error.c new file mode 100644 index 0000000..cd63282 --- /dev/null +++ b/src/libgamma-error.c @@ -0,0 +1,35 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library. If not, see . + */ +#include "libgamma-error.h" + + +#include +#include + + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned + */ +gid_t libgamma_group_gid = 0; + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned, + * `NULL` if the name of the group `libgamma_group_gid` cannot be determined + */ +const char* libgamma_group_name = NULL; + diff --git a/src/libgamma-error.h b/src/libgamma-error.h index c3c3c2f..5223207 100644 --- a/src/libgamma-error.h +++ b/src/libgamma-error.h @@ -22,6 +22,20 @@ # error libgamma-error.h should not be included directly, include libgamma.h instead #endif +#include + + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned + */ +extern gid_t libgamma_group_gid; + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned, + * `NULL` if the name of the group `libgamma_group_gid` cannot be determined + */ +extern const char* libgamma_group_name; + /** * The selected adjustment method does not exist @@ -108,6 +122,38 @@ */ #define LIBGAMMA_LIST_CRTCS_FAILED (-16) +/** + * Failed to acquire mode resources from the adjustment method + */ +#define LIBGAMMA_ACQUIRING_MODE_RESOURCES_FAILED (-17) + +/** + * The adjustment method reported that a negative number of partitions exists in the site + */ +#define LIBGAMMA_NEGATIVE_PARTITION_COUNT (-18) + +/** + * The adjustment method reported that a negative number of CRTC:s exists in the partition + */ +#define LIBGAMMA_NEGATIVE_CRTC_COUNT (-19) + +/** + * Device cannot be access becauses of insufficient permissions + */ +#define LIBGAMMA_DEVICE_RESTRICTED (-20) + +/** + * Device cannot be access, reason unknown + */ +#define LIBGAMMA_DEVICE_ACCESS_FAILED (-21) + +/** + * Device cannot be access, membership of the `libgamma_group_gid` + * (named by `libgamma_group_name` (can be `NULL`, if so `errno` may + * have been set to tell why)) is required + */ +#define LIBGAMMA_DEVICE_REQUIRE_GROUP (-22) + #endif -- cgit v1.2.3-70-g09d2