diff options
Diffstat (limited to 'src/lib/gamma-linux-drm.c')
-rw-r--r-- | src/lib/gamma-linux-drm.c | 1368 |
1 files changed, 674 insertions, 694 deletions
diff --git a/src/lib/gamma-linux-drm.c b/src/lib/gamma-linux-drm.c index 9693668..c2fc646 100644 --- a/src/lib/gamma-linux-drm.c +++ b/src/lib/gamma-linux-drm.c @@ -1,20 +1,4 @@ -/** - * libgamma -- Display server abstraction layer for gamma ramp adjustments - * Copyright (C) 2014, 2015 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 <http://www.gnu.org/licenses/>. - */ +/* See LICENSE file for copyright and license details. */ #ifndef HAVE_LIBGAMMA_METHOD_LINUX_DRM # error Compiling gamma-linux-drm.c without HAVE_LIBGAMMA_METHOD_LINUX_DRM #endif @@ -41,88 +25,87 @@ #include <xf86drmMode.h> #ifndef O_CLOEXEC -# define O_CLOEXEC 02000000 +# define O_CLOEXEC 02000000 #endif #ifndef NGROUPS_MAX -# define NGROUPS_MAX 65536 +# define NGROUPS_MAX 65536 #endif #ifndef PATH_MAX -# define PATH_MAX 4096 +# define PATH_MAX 4096 #endif /** - * Graphics card data for the Direct Rendering Manager adjustment method. + * 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; - - /** - * Resources for open connectors. - */ - drmModeConnector** connectors; - - /** - * Resources for open encoders. - */ - drmModeEncoder** encoders; - +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; + + /** + * Resources for open connectors + */ + drmModeConnector **connectors; + + /** + * Resources for open encoders + */ + drmModeEncoder **encoders; + } libgamma_drm_card_data_t; /** - * Return the capabilities of the adjustment method. + * Return the capabilities of the adjustment method * - * @param this The data structure to fill with the method's capabilities. + * @param this The data structure to fill with the method's capabilities */ -void libgamma_linux_drm_method_capabilities(libgamma_method_capabilities_t* restrict this) +void libgamma_linux_drm_method_capabilities(libgamma_method_capabilities_t *restrict this) { - /* Support for all information except gamma ramp support. */ - this->crtc_information = LIBGAMMA_CRTC_INFO_MACRO_EDID - | LIBGAMMA_CRTC_INFO_MACRO_VIEWPORT - | LIBGAMMA_CRTC_INFO_MACRO_RAMP - | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER - | LIBGAMMA_CRTC_INFO_ACTIVE - | LIBGAMMA_CRTC_INFO_MACRO_CONNECTOR; - /* DRM supports multiple partitions and CRTC:s but not sites. */ - this->default_site_known = 1; - this->multiple_sites = 0; - this->multiple_partitions = 1; - this->multiple_crtcs = 1; - /* Partitions are graphics cards in DRM. */ - this->partitions_are_graphics_cards = 1; - /* Linux does not have system restore capabilities. */ - this->site_restore = 0; - this->partition_restore = 0; - this->crtc_restore = 0; - /* Gamma ramp sizes are identical but not fixed. */ - this->identical_gamma_sizes = 1; - this->fixed_gamma_size = 0; - /* Gamma ramp depths are fixed. */ - this->fixed_gamma_depth = 1; - /* DRM is a real non-faked adjustment method */ - this->real = 1; - this->fake = 0; - /* Gamma ramp adjustments are persistent. */ - this->auto_restore = 0; + /* Support for all information except gamma ramp support */ + this->crtc_information = LIBGAMMA_CRTC_INFO_MACRO_EDID + | LIBGAMMA_CRTC_INFO_MACRO_VIEWPORT + | LIBGAMMA_CRTC_INFO_MACRO_RAMP + | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER + | LIBGAMMA_CRTC_INFO_ACTIVE + | LIBGAMMA_CRTC_INFO_MACRO_CONNECTOR; + /* DRM supports multiple partitions and CRTC:s but not sites */ + this->default_site_known = 1; + this->multiple_sites = 0; + this->multiple_partitions = 1; + this->multiple_crtcs = 1; + /* Partitions are graphics cards in DRM */ + this->partitions_are_graphics_cards = 1; + /* Linux does not have system restore capabilities */ + this->site_restore = 0; + this->partition_restore = 0; + this->crtc_restore = 0; + /* Gamma ramp sizes are identical but not fixed */ + this->identical_gamma_sizes = 1; + this->fixed_gamma_size = 0; + /* Gamma ramp depths are fixed */ + this->fixed_gamma_depth = 1; + /* DRM is a real non-faked adjustment method */ + this->real = 1; + this->fake = 0; + /* Gamma ramp adjustments are persistent */ + this->auto_restore = 0; } /** - * Initialise an allocated site state. + * Initialise an allocated site state * - * @param this The site state to initialise. + * @param this The site state to initialise * @param site The site identifier, unless it is `NULL` it must a * `free`:able. Once the state is destroyed the library * will attempt to free it. There you should not free @@ -130,58 +113,60 @@ void libgamma_linux_drm_method_capabilities(libgamma_method_capabilities_t* rest * or allocate on the stack. Note however that it will * not be free:d if this function fails. * @return Zero on success, otherwise (negative) the value of an - * error identifier provided by this library. + * error identifier provided by this library */ -int libgamma_linux_drm_site_initialise(libgamma_site_state_t* restrict this, - char* restrict site) +int +libgamma_linux_drm_site_initialise(libgamma_site_state_t *restrict this, char *restrict site) { - char pathname[PATH_MAX]; - struct stat _attr; - - if (site != NULL) - return LIBGAMMA_NO_SUCH_SITE; - - /* Count the number of available graphics cards by - `stat`:ing their existence in an API filesystem. */ - this->partitions_available = 0; - for (;;) - { - /* Construct pathname of graphics card device. */ - snprintf(pathname, sizeof(pathname) / sizeof(char), - DRM_DEV_NAME, DRM_DIR_NAME, (int)(this->partitions_available)); - /* `stat` the graphics card's existence. */ - if (stat(pathname, &_attr)) - break; - /* Move on to next graphics card. */ - if (this->partitions_available++ > INT_MAX) - return LIBGAMMA_IMPOSSIBLE_AMOUNT; - } - return 0; + char pathname[PATH_MAX]; + struct stat _attr; + + if (site) + return LIBGAMMA_NO_SUCH_SITE; + + /* Count the number of available graphics cards by + `stat`:ing their existence in an API filesystem */ + this->partitions_available = 0; + for (;;) { + /* Construct pathname of graphics card device */ + snprintf(pathname, sizeof(pathname) / sizeof(char), + DRM_DEV_NAME, DRM_DIR_NAME, (int)(this->partitions_available)); + /* `stat` the graphics card's existence */ + if (stat(pathname, &_attr)) + break; + /* Move on to next graphics card */ + if (this->partitions_available++ > INT_MAX) + return LIBGAMMA_IMPOSSIBLE_AMOUNT; + } + return 0; } /** - * Release all resources held by a site state. + * Release all resources held by a site state * - * @param this The site state. + * @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) { - (void) this; + (void) this; } /** - * Restore the gamma ramps all CRTC:s with a site to the system settings. + * Restore the gamma ramps all CRTC:s with a site to the system settings * - * @param this The site state. + * @param this The site state * @return Zero on success, otherwise (negative) the value of an - * error identifier provided by this library. + * error identifier provided by this library */ -int libgamma_linux_drm_site_restore(libgamma_site_state_t* restrict this) +int +libgamma_linux_drm_site_restore(libgamma_site_state_t *restrict this) { - (void) this; - return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; + (void) this; + errno = ENOTSUP; + return LIBGAMMA_ERRNO_SET; } @@ -191,209 +176,199 @@ int libgamma_linux_drm_site_restore(libgamma_site_state_t* restrict this) * @param pathname The pathname of the error card * @return The error code to report */ -static int figure_out_card_open_error(const char* pathname) +static int +figure_out_card_open_error(const char *pathname) { - gid_t supplemental_groups[NGROUPS_MAX]; - struct group* group; - struct stat attr; - int i, n; - - - /* Check which the device exists. */ - if ((errno == ENXIO) || (errno == ENODEV)) - return LIBGAMMA_NO_SUCH_PARTITION; - - - /* If we did not get access permission, figure out why. */ - - if (errno != EACCES) - /* If we could not figure out what - went wrong, just return the error - we got. */ - return LIBGAMMA_ERRNO_SET; - -#define __test(R, W) ((attr.st_mode & (R | W)) == (R | W)) - - /* Get permission requirement for the file. */ - if (stat(pathname, &attr) < 0) - return errno == EACCES ? LIBGAMMA_NO_SUCH_PARTITION : LIBGAMMA_ERRNO_SET; - - /* Test owner's, group's and others' permissions. */ - if ((attr.st_uid == geteuid() && __test(S_IRUSR, S_IWUSR)) || - (attr.st_gid == getegid() && __test(S_IRGRP, S_IWGRP)) || - __test(S_IROTH, S_IWOTH)) - return LIBGAMMA_DEVICE_ACCESS_FAILED; - - /* The group should be "video", but perhaps - it is "root" to restrict users. */ - if (attr.st_gid == 0 /* root group */ || __test(S_IRGRP, S_IWGRP)) - return LIBGAMMA_DEVICE_RESTRICTED; - - - /* Get the user's supplemental group membership list. */ - if ((n = getgroups(NGROUPS_MAX, supplemental_groups)) < 0) - return LIBGAMMA_ERRNO_SET; - - /* Test whether any of the supplemental - group should be satisfactory. */ - for (i = 0; i < n; i++) - if (supplemental_groups[i] == attr.st_gid) - break; - - /* If one of the supplemental groups - should be satisfactory, then we - do not know anything more than - that access failed. */ - if (i != n) - return LIBGAMMA_DEVICE_ACCESS_FAILED; - - /* Otherwise, try to get the name of - the group that is required and - report the missing group membership. */ -#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE - /* Thread-safe. */ - { - static __thread char buf[1024]; /* My output of `sysconf(_SC_GETGR_R_SIZE_MAX)`. */ - struct group _grp; + gid_t supplemental_groups[NGROUPS_MAX]; + struct group *group; + struct stat attr; + int i, n; + + + /* Check which the device exists */ + if (errno == ENXIO || errno == ENODEV) + return LIBGAMMA_NO_SUCH_PARTITION; + + + /* If we did not get access permission, figure out why */ + + if (errno != EACCES) { + /* If we could not figure out what went + * wrong, just return the error we got */ + return LIBGAMMA_ERRNO_SET; + } + +#define __test(R, W) ((attr.st_mode & ((R) | (W))) == ((R) | (W))) + + /* Get permission requirement for the file */ + if (stat(pathname, &attr)) + return errno == EACCES ? LIBGAMMA_NO_SUCH_PARTITION : LIBGAMMA_ERRNO_SET; + + /* Test owner's, group's and others' permissions */ + if ((attr.st_uid == geteuid() && __test(S_IRUSR, S_IWUSR)) || + (attr.st_gid == getegid() && __test(S_IRGRP, S_IWGRP)) || __test(S_IROTH, S_IWOTH)) + return LIBGAMMA_DEVICE_ACCESS_FAILED; + + /* The group should be "video", but perhaps + it is "root" to restrict users */ + if (!attr.st_gid /* root group */ || __test(S_IRGRP, S_IWGRP)) + return LIBGAMMA_DEVICE_RESTRICTED; + + + /* Get the user's supplemental group membership list */ + n = getgroups(NGROUPS_MAX, supplemental_groups); + if (n < 0) + return LIBGAMMA_ERRNO_SET; + + /* Test whether any of the supplemental + group should be satisfactory */ + for (i = 0; i < n; i++) + if (supplemental_groups[i] == attr.st_gid) + break; + + /* If one of the supplemental groups should be satisfactory, + then we do not know anything more than that access failed */ + if (i != n) + return LIBGAMMA_DEVICE_ACCESS_FAILED; + + /* Otherwise, try to get the name of the group that is + required and report the missing group membership */ + { + static __thread char buf[1024]; /* My output of `sysconf(_SC_GETGR_R_SIZE_MAX)`. */ + struct group _grp; - errno = getgrgid_r(attr.st_gid, &_grp, buf, sizeof(buf) / sizeof(char), &group); - if (errno == ERANGE) - { - /* The lenght of the group's name is absurdly long, degrade to thread-unsafe. */ - errno = 0; - group = getgrgid(attr.st_gid); - } - else if (errno) - return LIBGAMMA_ERRNO_SET; - } -#else -# ifdef __GCC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcpp" -# warning figure_out_card_open_error is not thread-safe. -# pragma GCC diagnostic pop -# endif - /* Not thread-safe. */ - errno = 0; - group = getgrgid(attr.st_gid); -#endif - - libgamma_group_gid = attr.st_gid; - libgamma_group_name = group != NULL ? group->gr_name : NULL; - return LIBGAMMA_DEVICE_REQUIRE_GROUP; + errno = getgrgid_r(attr.st_gid, &_grp, buf, sizeof(buf) / sizeof(char), &group); + if (errno == ERANGE) + { + /* The lenght of the group's name is absurdly long, degrade to thread-unsafe. */ + errno = 0; + group = getgrgid(attr.st_gid); + } + else if (errno) + return LIBGAMMA_ERRNO_SET; + } + + libgamma_group_gid = attr.st_gid; + libgamma_group_name = group ? group->gr_name : NULL; + return LIBGAMMA_DEVICE_REQUIRE_GROUP; #undef __test } /** - * Initialise an allocated partition state. + * Initialise an allocated partition state * - * @param this The partition state to initialise. - * @param site The site state for the site that the partition belongs to. - * @param partition The the index of the partition within the site. + * @param this The partition state to initialise + * @param site The site state for the site that the partition belongs to + * @param partition The the index of the partition within the site * @return Zero on success, otherwise (negative) the value of an - * error identifier provided by this library. + * error identifier provided by this library */ -int libgamma_linux_drm_partition_initialise(libgamma_partition_state_t* restrict this, - libgamma_site_state_t* restrict site, size_t partition) +int +libgamma_linux_drm_partition_initialise(libgamma_partition_state_t *restrict this, + libgamma_site_state_t *restrict site, size_t partition) { - int rc = 0; - libgamma_drm_card_data_t* restrict data; - char pathname[PATH_MAX]; - - (void) site; - - /* 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; - data->encoders = NULL; - data->connectors = 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) - { - rc = figure_out_card_open_error(pathname); - 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); - this->data = data; - return 0; - - fail_res: drmModeFreeResources(data->res); - fail_fd: close(data->fd); - fail_data: free(data); - return rc; + int rc = 0; + libgamma_drm_card_data_t *restrict data; + char pathname[PATH_MAX]; + + (void) site; + + /* 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) + return LIBGAMMA_ERRNO_SET; + data->fd = -1; + data->res = NULL; + data->encoders = NULL; + data->connectors = 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) { + rc = figure_out_card_open_error(pathname); + goto fail_data; + } + + /* Acquire mode resources */ + data->res = drmModeGetResources(data->fd); + if (!data->res) { + 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; + this->data = data; + return 0; + +fail_res: + drmModeFreeResources(data->res); +fail_fd: + close(data->fd); +fail_data: + free(data); + return rc; } /** - * Release all connectors and encoders. + * Release all connectors and encoders * - * @param this The graphics card data. + * @param this The graphics card data */ -static void release_connectors_and_encoders(libgamma_drm_card_data_t* restrict this) +static void +release_connectors_and_encoders(libgamma_drm_card_data_t *restrict this) { - size_t i, n; - /* Release individual encoders. */ - if (this->encoders != NULL) - for (i = 0, n = (size_t)(this->res->count_connectors); i < n; i++) - if (this->encoders[i] != NULL) - drmModeFreeEncoder(this->encoders[i]); - /* Release encoder array. */ - free(this->encoders); - this->encoders = NULL; - - /* Release individual connectors. */ - if (this->connectors != NULL) - for (i = 0, n = (size_t)(this->res->count_connectors); i < n; i++) - if (this->connectors[i] != NULL) - drmModeFreeConnector(this->connectors[i]); - /* Release connector array. */ - free(this->connectors); - this->connectors = NULL; + size_t i, n; + + /* Release individual encoders */ + if (this->encoders) + for (i = 0, n = (size_t)(this->res->count_connectors); i < n; i++) + if (this->encoders[i]) + drmModeFreeEncoder(this->encoders[i]); + /* Release encoder array */ + free(this->encoders); + this->encoders = NULL; + + /* Release individual connectors */ + if (this->connectors) + for (i = 0, n = (size_t)(this->res->count_connectors); i < n; i++) + if (this->connectors[i]) + drmModeFreeConnector(this->connectors[i]); + /* Release connector array */ + free(this->connectors); + this->connectors = NULL; } /** - * Release all resources held by a partition state. + * Release all resources held by a partition state * - * @param this The partition state. + * @param this The partition state */ -void libgamma_linux_drm_partition_destroy(libgamma_partition_state_t* restrict this) +void +libgamma_linux_drm_partition_destroy(libgamma_partition_state_t *restrict this) { - libgamma_drm_card_data_t* restrict data = this->data; - release_connectors_and_encoders(data); - if (data->res != NULL) drmModeFreeResources(data->res); - if (data->fd >= 0) close(data->fd); - free(data); + libgamma_drm_card_data_t *restrict data = this->data; + release_connectors_and_encoders(data); + if (data->res) + drmModeFreeResources(data->res); + if (data->fd >= 0) + close(data->fd); + free(data); } @@ -404,43 +379,47 @@ void libgamma_linux_drm_partition_destroy(libgamma_partition_state_t* restrict t * @return Zero on success, otherwise (negative) the value of an * error identifier provided by this library. */ -int libgamma_linux_drm_partition_restore(libgamma_partition_state_t* restrict this) +int +libgamma_linux_drm_partition_restore(libgamma_partition_state_t *restrict this) { - (void) this; - return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; + (void) this; + errno = ENOTSUP; + return LIBGAMMA_ERRNO_SET; } /** - * Initialise an allocated CRTC state. + * Initialise an allocated CRTC state * - * @param this The CRTC state to initialise. - * @param partition The partition state for the partition that the CRTC belongs to. - * @param crtc The the index of the CRTC within the site. + * @param this The CRTC state to initialise + * @param partition The partition state for the partition that the CRTC belongs to + * @param crtc The the index of the CRTC within the site * @return Zero on success, otherwise (negative) the value of an - * error identifier provided by this library. + * error identifier provided by this library */ -int libgamma_linux_drm_crtc_initialise(libgamma_crtc_state_t* restrict this, - libgamma_partition_state_t* restrict partition, size_t crtc) +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* restrict card = partition->data; - - if (crtc >= partition->crtcs_available) - return LIBGAMMA_NO_SUCH_CRTC; - this->data = (void*)(size_t)(card->res->crtcs[crtc]); - return 0; + libgamma_drm_card_data_t *restrict card = partition->data; + + if (crtc >= partition->crtcs_available) + return LIBGAMMA_NO_SUCH_CRTC; + this->data = (void*)(size_t)card->res->crtcs[crtc]; + return 0; } /** - * Release all resources held by a CRTC state. + * Release all resources held by a CRTC state * - * @param this The CRTC state. + * @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) { - (void) this; + (void) this; } @@ -451,125 +430,130 @@ void libgamma_linux_drm_crtc_destroy(libgamma_crtc_state_t* restrict this) * @return Zero on success, otherwise (negative) the value of an * error identifier provided by this library. */ -int libgamma_linux_drm_crtc_restore(libgamma_crtc_state_t* restrict this) +int +libgamma_linux_drm_crtc_restore(libgamma_crtc_state_t *restrict this) { - (void) this; - return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; + (void) this; + errno = ENOTSUP; + return LIBGAMMA_ERRNO_SET; } /** - * Find the connector that a CRTC belongs to. + * Find the connector that a CRTC belongs to * - * @param this The CRTC state. + * @param this The CRTC state * @param error Output of the error value to store of error report - * fields for data that requires the connector. -'* @return The CRTC's conncetor, `NULL` on error. + * fields for data that requires the connector +'* @return The CRTC's conncetor, `NULL` on error */ -static drmModeConnector* find_connector(libgamma_crtc_state_t* restrict this, int* restrict error) +static drmModeConnector * +find_connector(libgamma_crtc_state_t *restrict this, int *restrict error) { - uint32_t crtc_id = (uint32_t)(size_t)(this->data); - libgamma_drm_card_data_t* restrict card = this->partition->data; - size_t i, n = (size_t)(card->res->count_connectors); - /* Open connectors and encoders if not already opened. */ - if (card->connectors == NULL) - { - /* Allocate connector and encoder arrays. - We use `calloc` so all non-loaded elements are `NULL` after an error. */ - if ((card->connectors = calloc(n, sizeof(drmModeConnector*))) == NULL) goto fail; - if ((card->encoders = calloc(n, sizeof(drmModeEncoder*))) == NULL) goto fail; - /* Fill connector and encoder arrays. */ - for (i = 0; i < n; i++) - { - /* Get connector, */ - if ((card->connectors[i] = drmModeGetConnector(card->fd, card->res->connectors[i])) == NULL) - goto fail; - /* Get encoder if the connector is enabled. - If it is disabled it will not have an - encoder, which is indicated by the - encoder ID being 0. In such case, leave - the encoder to be `NULL`. */ - if ((card->connectors[i]->encoder_id != 0) && - ((card->encoders[i] = drmModeGetEncoder(card->fd, card->connectors[i]->encoder_id)) == NULL)) - goto fail; + uint32_t crtc_id = (uint32_t)(size_t)this->data; + libgamma_drm_card_data_t *restrict card = this->partition->data; + size_t i, n = (size_t)card->res->count_connectors; + /* Open connectors and encoders if not already opened */ + if (!card->connectors) { + /* Allocate connector and encoder arrays; we use `calloc` + so all non-loaded elements are `NULL` after an error */ + card->connectors = calloc(n, sizeof(drmModeConnector *)); + if (!card->connectors) + goto fail; + card->encoders = calloc(n, sizeof(drmModeEncoder *)); + if (!card->encoders) + goto fail; + /* Fill connector and encoder arrays */ + for (i = 0; i < n; i++) { + /* Get connector */ + card->connectors[i] = drmModeGetConnector(card->fd, card->res->connectors[i]); + if (!card->connectors[i]) + goto fail; + /* Get encoder if the connector is enabled. If it is disabled it + will not have an encoder, which is indicated by the encoder + ID being 0. In such case, leave the encoder to be `NULL`. */ + if (card->connectors[i]->encoder_id) { + card->encoders[i] = drmModeGetEncoder(card->fd, card->connectors[i]->encoder_id); + if (!card->encoders[i]) + goto fail; + } + } } - } - /* No error has occurred yet. */ - *error = 0; - /* Find connector. */ - for (i = 0; i < n; i++) - if ((card->encoders[i] != NULL) && (card->connectors[i] != NULL) && (card->encoders[i]->crtc_id == crtc_id)) - return card->connectors[i]; - /* We did not find the connector. */ - *error = LIBGAMMA_CONNECTOR_UNKNOWN; - return NULL; - - fail: - /* Report the error that got us here, release - resouces and exit with `NULL` for failure. */ - *error = errno; - release_connectors_and_encoders(card); - return NULL; + /* No error has occurred yet */ + *error = 0; + /* Find connector */ + for (i = 0; i < n; i++) + if (card->encoders[i] && card->connectors[i] && card->encoders[i]->crtc_id == crtc_id) + return card->connectors[i]; + /* We did not find the connector */ + *error = LIBGAMMA_CONNECTOR_UNKNOWN; + return NULL; + +fail: + /* Report the error that got us here, release + resouces and exit with `NULL` for failure */ + *error = errno; + release_connectors_and_encoders(card); + return NULL; } /** - * Get the size of the gamma ramps for a CRTC. + * Get the size of the gamma ramps for a CRTC * - * @param out Instance of a data structure to fill with the information about the CRTC. - * @param crtc The state of the CRTC whose information should be read. - * @return The value stored in `out->gamma_size_error`. + * @param out Instance of a data structure to fill with the information about the CRTC + * @param crtc The state of the CRTC whose information should be read + * @return The value stored in `out->gamma_size_error` */ -static int get_gamma_ramp_size(libgamma_crtc_information_t* restrict out, const libgamma_crtc_state_t* restrict crtc) +static int +get_gamma_ramp_size(libgamma_crtc_information_t *restrict out, const libgamma_crtc_state_t *restrict crtc) { - libgamma_drm_card_data_t* restrict card = crtc->partition->data; - uint32_t crtc_id = card->res->crtcs[crtc->crtc]; - drmModeCrtc* restrict crtc_info; - /* Get CRTC information. */ - errno = 0; - crtc_info = drmModeGetCrtc(card->fd, crtc_id); - out->gamma_size_error = crtc_info == NULL ? errno : 0; - /* Get gamma ramp size. */ - if (out->gamma_size_error == 0) - { - /* Store gamma ramp size. */ - out->red_gamma_size = out->green_gamma_size = out->blue_gamma_size = (size_t)(crtc_info->gamma_size); - /* Sanity check gamma ramp size. */ - out->gamma_size_error = crtc_info->gamma_size < 2 ? LIBGAMMA_SINGLETON_GAMMA_RAMP : 0; - /* Release CRTC information. */ - drmModeFreeCrtc(crtc_info); - } - return out->gamma_size_error; + libgamma_drm_card_data_t *restrict card = crtc->partition->data; + uint32_t crtc_id = card->res->crtcs[crtc->crtc]; + drmModeCrtc *restrict crtc_info; + /* Get CRTC information */ + errno = 0; + crtc_info = drmModeGetCrtc(card->fd, crtc_id); + out->gamma_size_error = crtc_info ? 0 : errno; + /* Get gamma ramp size */ + if (!out->gamma_size_error) { + /* Store gamma ramp size */ + out->red_gamma_size = out->green_gamma_size = out->blue_gamma_size = (size_t)crtc_info->gamma_size; + /* Sanity check gamma ramp size */ + out->gamma_size_error = crtc_info->gamma_size < 2 ? LIBGAMMA_SINGLETON_GAMMA_RAMP : 0; + /* Release CRTC information */ + drmModeFreeCrtc(crtc_info); + } + return out->gamma_size_error; } /** * Get the a monitor's subpixel order * - * @param out Instance of a data structure to fill with the information about the CRTC. - * @param connector The connector. + * @param out Instance of a data structure to fill with the information about the CRTC + * @param connector The connector */ -static void get_subpixel_order(libgamma_crtc_information_t* restrict out, - const drmModeConnector* restrict connector) +static void +get_subpixel_order(libgamma_crtc_information_t *restrict out, const drmModeConnector *restrict connector) { -#define __select(value) \ - case DRM_MODE_SUBPIXEL_##value: \ - out->subpixel_order = LIBGAMMA_SUBPIXEL_ORDER_##value; \ - break - - switch (connector->subpixel) - { - __select (UNKNOWN); - __select (HORIZONTAL_RGB); - __select (HORIZONTAL_BGR); - __select (VERTICAL_RGB); - __select (VERTICAL_BGR); - __select (NONE); - default: - out->subpixel_order_error = LIBGAMMA_SUBPIXEL_ORDER_NOT_RECOGNISED; - break; - } - +#define __select(value)\ + case DRM_MODE_SUBPIXEL_##value:\ + out->subpixel_order = LIBGAMMA_SUBPIXEL_ORDER_##value;\ + break + + switch (connector->subpixel) { + __select (UNKNOWN); + __select (HORIZONTAL_RGB); + __select (HORIZONTAL_BGR); + __select (VERTICAL_RGB); + __select (VERTICAL_BGR); + __select (NONE); + default: + out->subpixel_order_error = LIBGAMMA_SUBPIXEL_ORDER_NOT_RECOGNISED; + break; + } + #undef __select } @@ -577,346 +561,342 @@ static void get_subpixel_order(libgamma_crtc_information_t* restrict out, /** * Get a connector's type * - * @param out Instance of a data structure to fill with the information about the CRTC. - * @param connector The connector. - * @param connector_name_base Output for the basename of the connector. + * @param out Instance of a data structure to fill with the information about the CRTC + * @param connector The connector + * @param connector_name_base Output for the basename of the connector */ -static void get_connector_type(libgamma_crtc_information_t* restrict out, - const drmModeConnector* restrict connector, - const char** restrict connector_name_base) +static void +get_connector_type(libgamma_crtc_information_t *restrict out, const drmModeConnector *restrict connector, + const char **restrict connector_name_base) { -#define __select(type, name) \ - case DRM_MODE_CONNECTOR_##type: \ - out->connector_type = LIBGAMMA_CONNECTOR_TYPE_##type; \ - *connector_name_base = name; \ - break - - /* These may not have been included by <xf86drmMode.h>, - but they should be available. Becuase we define them - outself, it is best to test them last. */ +#define __select(type, name)\ + case DRM_MODE_CONNECTOR_##type:\ + out->connector_type = LIBGAMMA_CONNECTOR_TYPE_##type;\ + *connector_name_base = name;\ + break + + /* These may not have been included by <xf86drmMode.h>, + but they should be available. Becuase we define them + outself, it is best to test them last. */ #ifndef DRM_MODE_CONNECTOR_VIRTUAL -# define DRM_MODE_CONNECTOR_VIRTUAL 15 +# define DRM_MODE_CONNECTOR_VIRTUAL 15 #endif #ifndef DRM_MODE_CONNECTOR_DSI -# define DRM_MODE_CONNECTOR_DSI 16 +# define DRM_MODE_CONNECTOR_DSI 16 #endif - - /* Translate connector type from DRM to libgamma - and store connector basename. */ - switch (connector->connector_type) - { - __select (Unknown, "Unknown" ); - __select (VGA, "VGA" ); - __select (DVII, "DVI-I" ); - __select (DVID, "DVI-D" ); - __select (DVIA, "DVI-A" ); - __select (Composite, "Composite"); - __select (SVIDEO, "SVIDEO" ); - __select (LVDS, "LVDS" ); - __select (Component, "Component"); - __select (9PinDIN, "DIN" ); - __select (DisplayPort, "DP" ); - __select (HDMIA, "HDMI-A" ); - __select (HDMIB, "HDMI-B" ); - __select (TV, "TV" ); - __select (eDP, "eDP" ); - __select (VIRTUAL, "VIRTUAL" ); - __select (DSI, "DSI" ); - default: - out->connector_type_error = LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED; - out->connector_name_error = LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED; - break; - } - + + /* Translate connector type from DRM to libgamma + and store connector basename */ + switch (connector->connector_type) { + __select (Unknown, "Unknown" ); + __select (VGA, "VGA" ); + __select (DVII, "DVI-I" ); + __select (DVID, "DVI-D" ); + __select (DVIA, "DVI-A" ); + __select (Composite, "Composite"); + __select (SVIDEO, "SVIDEO" ); + __select (LVDS, "LVDS" ); + __select (Component, "Component"); + __select (9PinDIN, "DIN" ); + __select (DisplayPort, "DP" ); + __select (HDMIA, "HDMI-A" ); + __select (HDMIB, "HDMI-B" ); + __select (TV, "TV" ); + __select (eDP, "eDP" ); + __select (VIRTUAL, "VIRTUAL" ); + __select (DSI, "DSI" ); + default: + out->connector_type_error = LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED; + out->connector_name_error = LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED; + break; + } + #undef __select } /** - * Read information from the CRTC's conncetor. + * Read information from the CRTC's conncetor * - * @param crtc The state of the CRTC whose information should be read. - * @param out Instance of a data structure to fill with the information about the CRTC. - * @param connector The CRTC's connector. - * @param fields OR:ed identifiers for the information about the CRTC that should be read. - * @return Non-zero if at least on error occured. + * @param crtc The state of the CRTC whose information should be read + * @param out Instance of a data structure to fill with the information about the CRTC + * @param connector The CRTC's connector + * @param fields OR:ed identifiers for the information about the CRTC that should be read + * @return Non-zero if at least on error occured */ -static int read_connector_data(libgamma_crtc_state_t* restrict crtc, libgamma_crtc_information_t* restrict out, - const drmModeConnector* restrict connector, int32_t fields) +static int +read_connector_data(libgamma_crtc_state_t *restrict crtc, libgamma_crtc_information_t *restrict out, + const drmModeConnector *restrict connector, int32_t fields) { - const char* connector_name_base = NULL; - - /* Get some information that does not require too much work. */ - if ((fields & (LIBGAMMA_CRTC_INFO_MACRO_ACTIVE | LIBGAMMA_CRTC_INFO_MACRO_CONNECTOR))) - { - /* Get whether or not a monitor is plugged in. */ - out->active = connector->connection == DRM_MODE_CONNECTED; - out->active_error = connector->connection == DRM_MODE_UNKNOWNCONNECTION ? LIBGAMMA_STATE_UNKNOWN : 0; - if (out->active == 0) - { - if ((fields & (LIBGAMMA_CRTC_INFO_MACRO_VIEWPORT | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER))) - out->width_mm_error = out->height_mm_error = out->subpixel_order_error = LIBGAMMA_NOT_CONNECTED; - goto not_connected; + const char *connector_name_base = NULL; + libgamma_drm_card_data_t *restrict card; + uint32_t type; + size_t i, n, c; + + /* Get some information that does not require too much work */ + if (fields & (LIBGAMMA_CRTC_INFO_MACRO_ACTIVE | LIBGAMMA_CRTC_INFO_MACRO_CONNECTOR)) { + /* Get whether or not a monitor is plugged in */ + out->active = connector->connection == DRM_MODE_CONNECTED; + out->active_error = connector->connection == DRM_MODE_UNKNOWNCONNECTION ? LIBGAMMA_STATE_UNKNOWN : 0; + if (!out->active) { + if (fields & (LIBGAMMA_CRTC_INFO_MACRO_VIEWPORT | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER)) + out->width_mm_error = out->height_mm_error = out->subpixel_order_error = LIBGAMMA_NOT_CONNECTED; + goto not_connected; + } + + /* Get viewport dimension */ + out->width_mm = connector->mmWidth; + out->height_mm = connector->mmHeight; + + /* Get subpixel order */ + get_subpixel_order(out, connector); + + not_connected: + + /* Get connector type */ + get_connector_type(out, connector, &connector_name_base); } - - /* Get viewport dimension. */ - out->width_mm = connector->mmWidth; - out->height_mm = connector->mmHeight; - - /* Get subpixel order. */ - get_subpixel_order(out, connector); - - not_connected: - - /* Get connector type. */ - get_connector_type(out, connector, &connector_name_base); - } - - /* Get the connector's name. */ - if ((fields & LIBGAMMA_CRTC_INFO_CONNECTOR_NAME) && (out->connector_name_error == 0)) - { - libgamma_drm_card_data_t* restrict card = crtc->partition->data; - uint32_t type = connector->connector_type; - size_t i, n = (size_t)(card->res->count_connectors), c = 0; - - /* Allocate memory for the name of the connector. */ - out->connector_name = malloc((strlen(connector_name_base) + 12) * sizeof(char)); - if (out->connector_name == NULL) - return out->connector_name_error = errno; - - /* Get the number of connectors with the same type on the same graphics card. */ - for (i = 0; (i < n) && (card->connectors[i] != connector); i++) - if (card->connectors[i]->connector_type == type) - c++; - - /* Construct and store connect name that is unique to the graphics card. */ - sprintf(out->connector_name, "%s-%" PRIu32, connector_name_base, (uint32_t)(c + 1)); - } - - /* Did something go wrong? */ - return out->subpixel_order_error | out->active_error | out->connector_name_error; + + /* Get the connector's name */ + if ((fields & LIBGAMMA_CRTC_INFO_CONNECTOR_NAME) && !out->connector_name_error) { + card = crtc->partition->data; + type = connector->connector_type; + n = (size_t)card->res->count_connectors; + + /* Allocate memory for the name of the connector */ + out->connector_name = malloc((strlen(connector_name_base) + 12) * sizeof(char)); + if (!out->connector_name) + return (out->connector_name_error = errno); + + /* Get the number of connectors with the same type on the same graphics card */ + for (i = c = 0; i < n && card->connectors[i] != connector; i++) + if (card->connectors[i]->connector_type == type) + c++; + + /* Construct and store connect name that is unique to the graphics card */ + sprintf(out->connector_name, "%s-%" PRIu32, connector_name_base, (uint32_t)(c + 1)); + } + + /* Did something go wrong? */ + return out->subpixel_order_error | out->active_error | out->connector_name_error; } /** - * Get the extended display identification data for a monitor. + * Get the extended display identification data for a monitor * - * @param crtc The CRTC state. - * @param out Instance of a data structure to fill with the information about the CRTC. - * @param connector The CRTC's connector. - * @reutnr Non-zero on error. + * @param crtc The CRTC state + * @param out Instance of a data structure to fill with the information about the CRTC + * @param connector The CRTC's connector + * @reutnr Non-zero on error */ -static int get_edid(libgamma_crtc_state_t* restrict crtc, - libgamma_crtc_information_t* restrict out, drmModeConnector* connector) +static int +get_edid(libgamma_crtc_state_t *restrict crtc, libgamma_crtc_information_t *restrict out, drmModeConnector *connector) { - libgamma_drm_card_data_t* restrict card = crtc->partition->data; - int prop_n = connector->count_props; - int prop_i; - drmModePropertyRes* restrict prop; - drmModePropertyBlobRes* restrict blob; - - /* Test all properies on the connector. */ - for (prop_i = 0; prop_i < prop_n; prop_i++) - { - /* Get output property, */ - if ((prop = drmModeGetProperty(card->fd, connector->props[prop_i])) == NULL) - continue; - /* Is this property the EDID? */ - if (!strcmp(prop->name, "EDID")) - { - /* Get the property value. */ - if ((blob = drmModeGetPropertyBlob(card->fd, (uint32_t)(connector->prop_values[prop_i]))) == NULL) - return drmModeFreeProperty(prop), out->edid_error = LIBGAMMA_PROPERTY_VALUE_QUERY_FAILED; - if (blob->data != NULL) - { - /* Get and store the length of the EDID. */ - out->edid_length = blob->length; - /* Allocate memory for a copy of the EDID that is under our memory control. */ - if ((out->edid = malloc(out->edid_length * sizeof(unsigned char))) == NULL) - out->edid_error = errno; - else - /* Copy the EDID so we can free resources that got us here. */ - memcpy(out->edid, blob->data, (size_t)(out->edid_length) * sizeof(char)); - /* Free the propriety value and the propery. */ - drmModeFreePropertyBlob(blob); - drmModeFreeProperty(prop); - /* Were we successful? */ - return out->edid == NULL; - } - /* Free the propriety value. */ - drmModeFreePropertyBlob(blob); + libgamma_drm_card_data_t *restrict card = crtc->partition->data; + int prop_n = connector->count_props; + int prop_i; + drmModePropertyRes *restrict prop; + drmModePropertyBlobRes *restrict blob; + + /* Test all properies on the connector */ + for (prop_i = 0; prop_i < prop_n; prop_i++) { + /* Get output property */ + prop = drmModeGetProperty(card->fd, connector->props[prop_i]); + if (!prop) + continue; + /* Is this property the EDID? */ + if (!strcmp(prop->name, "EDID")) { + /* Get the property value */ + blob = drmModeGetPropertyBlob(card->fd, (uint32_t)connector->prop_values[prop_i]); + if (!blob) { + drmModeFreeProperty(prop); + return (out->edid_error = LIBGAMMA_PROPERTY_VALUE_QUERY_FAILED); + } + if (blob->data) { + /* Get and store the length of the EDID */ + out->edid_length = blob->length; + /* Allocate memory for a copy of the EDID that is under our memory control */ + out->edid = malloc(out->edid_length * sizeof(unsigned char)); + if (!out->edid) { + out->edid_error = errno; + } else { + /* Copy the EDID so we can free resources that got us here */ + memcpy(out->edid, blob->data, (size_t)out->edid_length * sizeof(char)); + } + /* Free the propriety value and the propery */ + drmModeFreePropertyBlob(blob); + drmModeFreeProperty(prop); + /* Were we successful? */ + return !out->edid; + } + /* Free the propriety value */ + drmModeFreePropertyBlob(blob); + } + /* Free the propriety */ + drmModeFreeProperty(prop); } - /* Free the propriety. */ - drmModeFreeProperty(prop); - } - /* If we get here, we did not find a EDID. */ - return out->edid_error = LIBGAMMA_EDID_NOT_FOUND; + /* If we get here, we did not find a EDID */ + return (out->edid_error = LIBGAMMA_EDID_NOT_FOUND); } /** - * Read information about a CRTC. + * Read information about a CRTC * - * @param this Instance of a data structure to fill with the information about the CRTC. - * @param crtc The state of the CRTC whose information should be read. - * @param fields OR:ed identifiers for the information about the CRTC that should be read. - * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + * @param this Instance of a data structure to fill with the information about the CRTC + * @param crtc The state of the CRTC whose information should be read + * @param fields OR:ed identifiers for the information about the CRTC that should be read + * @return Zero on success, -1 on error; on error refer to the error reports in `this` */ -int libgamma_linux_drm_get_crtc_information(libgamma_crtc_information_t* restrict this, - libgamma_crtc_state_t* restrict crtc, int32_t fields) +int +libgamma_linux_drm_get_crtc_information(libgamma_crtc_information_t *restrict this, + libgamma_crtc_state_t *restrict crtc, int32_t fields) { -#define _E(FIELD) ((fields & FIELD) ? LIBGAMMA_CRTC_INFO_NOT_SUPPORTED : 0) - int e = 0; - drmModeConnector* restrict connector; - int require_connector; - int free_edid; - int error; - - - /* Wipe all error indicators. */ - memset(this, 0, sizeof(libgamma_crtc_information_t)); - - /* We need to free the EDID after us if it is not explicitly requested. */ - free_edid = (fields & LIBGAMMA_CRTC_INFO_EDID) == 0; - - /* Figure out whether we require the connector to get all information we want. */ - require_connector = fields & (LIBGAMMA_CRTC_INFO_MACRO_ACTIVE | LIBGAMMA_CRTC_INFO_MACRO_CONNECTOR); - - /* If we are not interested in the connector or monitor, jump. */ - if (require_connector == 0) - goto cont; - /* Find connector. */ - if ((connector = find_connector(crtc, &error)) == NULL) - { - /* Store reported error in affected fields. */ - e |= this->width_mm_error = this->height_mm_error - = this->connector_type_error = this->subpixel_order_error - = this->active_error = this->connector_name_error - = this->edid_error = this->gamma_error - = this->width_mm_edid_error = this->height_mm_edid_error = error; - goto cont; - } - - /* Read connector data and monitor data, excluding EDID.. */ - e |= read_connector_data(crtc, this, connector, fields); - - /* If we do not want any EDID information, jump. */ - if ((fields & LIBGAMMA_CRTC_INFO_MACRO_EDID) == 0) - goto cont; - /* If there is not monitor that report error in EDID related fields. */ - if (this->active_error || (this->active == 0)) - { - e |= this->edid_error = this->gamma_error - = this->width_mm_edid_error = this->height_mm_edid_error - = LIBGAMMA_NOT_CONNECTED; - goto cont; - } - /* Get EDID. */ - e |= get_edid(crtc, this, connector); - if (this->edid == NULL) - { - this->gamma_error = this->width_mm_edid_error = this->height_mm_edid_error = this->edid_error; - goto cont; - } - /* Parse EDID. */ - if ((fields & (LIBGAMMA_CRTC_INFO_MACRO_EDID ^ LIBGAMMA_CRTC_INFO_EDID))) - e |= libgamma_parse_edid(this, fields); - - cont: - /* Get gamma ramp size. */ - e |= (fields & LIBGAMMA_CRTC_INFO_GAMMA_SIZE) ? get_gamma_ramp_size(this, crtc) : 0; - /* Store gamma ramp depth. */ - this->gamma_depth = 16; - /* DRM does not support quering gamma ramp support. */ - e |= this->gamma_support_error = _E(LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT); - - /* Free the EDID after us. */ - if (free_edid) - { - free(this->edid); - this->edid = NULL; - } - - return e ? -1 : 0; +#define _E(FIELD) ((fields & FIELD) ? LIBGAMMA_CRTC_INFO_NOT_SUPPORTED : 0) + + int e = 0, require_connector, free_edid, error; + drmModeConnector *restrict connector; + + /* Wipe all error indicators */ + memset(this, 0, sizeof(libgamma_crtc_information_t)); + + /* We need to free the EDID after us if it is not explicitly requested */ + free_edid = !(fields & LIBGAMMA_CRTC_INFO_EDID); + + /* Figure out whether we require the connector to get all information we want */ + require_connector = fields & (LIBGAMMA_CRTC_INFO_MACRO_ACTIVE | LIBGAMMA_CRTC_INFO_MACRO_CONNECTOR); + + /* If we are not interested in the connector or monitor, jump */ + if (!require_connector) + goto cont; + /* Find connector. */ + connector = find_connector(crtc, &error); + if (!connector) { + /* Store reported error in affected fields */ + e |= this->width_mm_error = this->height_mm_error + = this->connector_type_error = this->subpixel_order_error + = this->active_error = this->connector_name_error + = this->edid_error = this->gamma_error + = this->width_mm_edid_error = this->height_mm_edid_error = error; + goto cont; + } + + /* Read connector data and monitor data, excluding EDID */ + e |= read_connector_data(crtc, this, connector, fields); + + /* If we do not want any EDID information, jump */ + if (!(fields & LIBGAMMA_CRTC_INFO_MACRO_EDID)) + goto cont; + /* If there is not monitor that report error in EDID related fields */ + if (this->active_error || !this->active) { + e |= this->edid_error = this->gamma_error + = this->width_mm_edid_error = this->height_mm_edid_error + = LIBGAMMA_NOT_CONNECTED; + goto cont; + } + /* Get EDID */ + e |= get_edid(crtc, this, connector); + if (!this->edid) { + this->gamma_error = this->width_mm_edid_error = this->height_mm_edid_error = this->edid_error; + goto cont; + } + /* Parse EDID */ + if (fields & (LIBGAMMA_CRTC_INFO_MACRO_EDID ^ LIBGAMMA_CRTC_INFO_EDID)) + e |= libgamma_parse_edid(this, fields); + +cont: + /* Get gamma ramp size */ + e |= (fields & LIBGAMMA_CRTC_INFO_GAMMA_SIZE) ? get_gamma_ramp_size(this, crtc) : 0; + /* Store gamma ramp depth */ + this->gamma_depth = 16; + /* DRM does not support quering gamma ramp support */ + e |= this->gamma_support_error = _E(LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT); + + /* Free the EDID after us */ + if (free_edid) { + free(this->edid); + this->edid = NULL; + } + + return e ? -1 : 0; + #undef _E } /** - * Get the current gamma ramps for a CRTC, 16-bit gamma-depth version. + * Get the current gamma ramps for a CRTC, 16-bit gamma-depth version * - * @param this The CRTC state. - * @param ramps The gamma ramps to fill with the current values. + * @param this The CRTC state + * @param ramps The gamma ramps to fill with the current values * @return Zero on success, otherwise (negative) the value of an - * error identifier provided by this library. + * error identifier provided by this library */ -int libgamma_linux_drm_crtc_get_gamma_ramps16(libgamma_crtc_state_t* restrict this, - libgamma_gamma_ramps16_t* restrict ramps) +int +libgamma_linux_drm_crtc_get_gamma_ramps16(libgamma_crtc_state_t *restrict this, libgamma_gamma_ramps16_t *restrict ramps) { - libgamma_drm_card_data_t* restrict card = this->partition->data; - int r; + libgamma_drm_card_data_t *restrict card = this->partition->data; + int r; #ifdef DEBUG - /* Gamma ramp sizes are identical but not fixed. */ - if ((ramps->red_size != ramps->green_size) || - (ramps->red_size != ramps->blue_size)) - return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; + /* Gamma ramp sizes are identical but not fixed */ + if (ramps->red_size != ramps->green_size || ramps->red_size != ramps->blue_size) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; #endif - /* Read current gamma ramps. */ - r = drmModeCrtcGetGamma(card->fd, (uint32_t)(size_t)(this->data), (uint32_t)(ramps->red_size), - ramps->red, ramps->green, ramps->blue); - return r ? LIBGAMMA_GAMMA_RAMP_READ_FAILED : 0; + /* Read current gamma ramps */ + r = drmModeCrtcGetGamma(card->fd, (uint32_t)(size_t)this->data, (uint32_t)ramps->red_size, + ramps->red, ramps->green, ramps->blue); + return r ? LIBGAMMA_GAMMA_RAMP_READ_FAILED : 0; } /** - * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version * - * @param this The CRTC state. - * @param ramps The gamma ramps to apply. + * @param this The CRTC state + * @param ramps The gamma ramps to apply * @return Zero on success, otherwise (negative) the value of an - * error identifier provided by this library. + * error identifier provided by this library */ -int libgamma_linux_drm_crtc_set_gamma_ramps16(libgamma_crtc_state_t* restrict this, - libgamma_gamma_ramps16_t ramps) +int +libgamma_linux_drm_crtc_set_gamma_ramps16(libgamma_crtc_state_t *restrict this, libgamma_gamma_ramps16_t ramps) { - libgamma_drm_card_data_t* restrict card = this->partition->data; - int r; + libgamma_drm_card_data_t *restrict card = this->partition->data; + int r; #ifdef DEBUG - /* Gamma ramp sizes are identical but not fixed. */ - if ((ramps.red_size != ramps.green_size) || - (ramps.red_size != ramps.blue_size)) - return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; + /* Gamma ramp sizes are identical but not fixed */ + if (ramps.red_size != ramps.green_size || ramps.red_size != ramps.blue_size) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; #endif - - /* Apply gamma ramps. */ - r = drmModeCrtcSetGamma(card->fd, (uint32_t)(size_t)(this->data), - (uint32_t)(ramps.red_size), ramps.red, ramps.green, ramps.blue); - /* Check for errors. */ - if (r) - switch (errno) - { - case EACCES: - case EAGAIN: - case EIO: - /* Permission denied errors must be ignored, because we do not - * have permission to do this while a display server is active. - * We are also checking for some other error codes just in case. */ - case EBUSY: - case EINPROGRESS: - /* It is hard to find documentation for DRM (in fact all of this is - * just based on the functions names and some testing,) perhaps we - * could get this if we are updating to fast. */ - break; - case EBADF: - case ENODEV: - case ENXIO: - /* XXX: I have not actually tested removing my graphics card or, - * monitor but I imagine either of these is what would happen. */ - return LIBGAMMA_GRAPHICS_CARD_REMOVED; - - default: - return LIBGAMMA_ERRNO_SET; - } - return 0; -} + /* Apply gamma ramps */ + r = drmModeCrtcSetGamma(card->fd, (uint32_t)(size_t)this->data, + (uint32_t)ramps.red_size, ramps.red, ramps.green, ramps.blue); + /* Check for errors */ + if (r) { + switch (errno) { + case EACCES: + case EAGAIN: + case EIO: + /* Permission denied errors must be ignored, because we do not + * have permission to do this while a display server is active. + * We are also checking for some other error codes just in case. */ + case EBUSY: + case EINPROGRESS: + /* It is hard to find documentation for DRM (in fact all of this is + * just based on the functions names and some testing,) perhaps we + * could get this if we are updating to fast. */ + break; + case EBADF: + case ENODEV: + case ENXIO: + /* XXX: I have not actually tested removing my graphics card or, + * monitor but I imagine either of these is what would happen. */ + return LIBGAMMA_GRAPHICS_CARD_REMOVED; + + default: + return LIBGAMMA_ERRNO_SET; + } + } + return 0; +} |