diff options
Diffstat (limited to 'src/lib/gamma-linux-drm.c')
-rw-r--r-- | src/lib/gamma-linux-drm.c | 902 |
1 files changed, 0 insertions, 902 deletions
diff --git a/src/lib/gamma-linux-drm.c b/src/lib/gamma-linux-drm.c deleted file mode 100644 index c2fc646..0000000 --- a/src/lib/gamma-linux-drm.c +++ /dev/null @@ -1,902 +0,0 @@ -/* 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 - -#define _GNU_SOURCE - -#include "gamma-linux-drm.h" - -#include "libgamma-error.h" -#include "edid.h" - -#include <limits.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <grp.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <inttypes.h> - -#include <xf86drm.h> -#include <xf86drmMode.h> - -#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; - - /** - * Resources for open connectors - */ - drmModeConnector **connectors; - - /** - * Resources for open encoders - */ - drmModeEncoder **encoders; - -} libgamma_drm_card_data_t; - - - -/** - * Return the capabilities of the adjustment method - * - * @param this The data structure to fill with the method's capabilities - */ -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; -} - - -/** - * Initialise an allocated site state - * - * @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 - * it yourself, and it must not be a string constant - * 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 - */ -int -libgamma_linux_drm_site_initialise(libgamma_site_state_t *restrict this, char *restrict site) -{ - 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 - * - * @param this The site state - */ -void -libgamma_linux_drm_site_destroy(libgamma_site_state_t *restrict this) -{ - (void) this; -} - - -/** - * Restore the gamma ramps all CRTC:s with a site to the system settings - * - * @param this The site state - * @return Zero on success, otherwise (negative) the value of an - * error identifier provided by this library - */ -int -libgamma_linux_drm_site_restore(libgamma_site_state_t *restrict this) -{ - (void) this; - errno = ENOTSUP; - return LIBGAMMA_ERRNO_SET; -} - - -/** - * Figure out why `open` failed for a graphics card - * - * @param pathname The pathname of the error card - * @return The error code to report - */ -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)) - 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; - } - - 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 - * - * @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 - */ -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) - 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 - * - * @param this The graphics card data - */ -static void -release_connectors_and_encoders(libgamma_drm_card_data_t *restrict this) -{ - 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 - * - * @param this The partition state - */ -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) - drmModeFreeResources(data->res); - if (data->fd >= 0) - close(data->fd); - free(data); -} - - -/** - * Restore the gamma ramps all CRTC:s with a partition to the system settings. - * - * @param this The partition state. - * @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) -{ - (void) this; - errno = ENOTSUP; - return LIBGAMMA_ERRNO_SET; -} - - - -/** - * 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 - * @return Zero on success, otherwise (negative) the value of an - * 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) -{ - 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 - * - * @param this The CRTC state - */ -void -libgamma_linux_drm_crtc_destroy(libgamma_crtc_state_t *restrict this) -{ - (void) this; -} - - -/** - * Restore the gamma ramps for a CRTC to the system settings for that CRTC. - * - * @param this The CRTC state. - * @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) -{ - (void) this; - errno = ENOTSUP; - return LIBGAMMA_ERRNO_SET; -} - - -/** - * Find the connector that a CRTC belongs to - * - * @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 - */ -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) { - /* 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] && 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 - * - * @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) -{ - 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 - */ -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; - } - -#undef __select -} - - -/** - * 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 - */ -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. */ -#ifndef DRM_MODE_CONNECTOR_VIRTUAL -# define DRM_MODE_CONNECTOR_VIRTUAL 15 -#endif -#ifndef DRM_MODE_CONNECTOR_DSI -# 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; - } - -#undef __select -} - - -/** - * 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 - */ -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; - 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 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 - * - * @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) -{ - 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); - } - /* If we get here, we did not find a EDID */ - return (out->edid_error = LIBGAMMA_EDID_NOT_FOUND); -} - - -/** - * 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` - */ -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, 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 - * - * @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 - */ -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; -#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; -#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; -} - - -/** - * Set the gamma ramps for a CRTC, 16-bit gamma-depth version - * - * @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 - */ -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; -#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; -#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; -} |