aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/gamma-linux-drm.c165
-rw-r--r--src/gamma-linux-drm.h4
-rw-r--r--src/gamma-quartz-cg.c3
-rw-r--r--src/libgamma-error.c35
-rw-r--r--src/libgamma-error.h46
5 files changed, 248 insertions, 5 deletions
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 <errno.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 <xf86drm.h>
#include <xf86drmMode.h>
@@ -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 <http://www.gnu.org/licenses/>.
+ */
+#include "libgamma-error.h"
+
+
+#include <stddef.h>
+#include <sys/types.h>
+
+
+/**
+ * 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 <sys/types.h>
+
+
+/**
+ * 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