/* * Copyright © 2015 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Author: * Antti Koskipaa * */ #include "igt.h" #include #include #include #include #include #include #include #include struct context { int max; }; #define TOLERANCE 5 /* percent */ #define BACKLIGHT_PATH "/sys/class/backlight/intel_backlight" #define FADESTEPS 10 #define FADESPEED 100 /* milliseconds between steps */ IGT_TEST_DESCRIPTION("Basic backlight sysfs test"); static int8_t *pm_data = NULL; static int backlight_read(int *result, const char *fname) { int fd; char full[PATH_MAX]; char dst[64]; int r, e; igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, fname) < PATH_MAX); fd = open(full, O_RDONLY); if (fd == -1) return -errno; r = read(fd, dst, sizeof(dst)); e = errno; close(fd); if (r < 0) return -e; errno = 0; *result = strtol(dst, NULL, 10); return errno; } static int backlight_write(int value, const char *fname) { int fd; char full[PATH_MAX]; char src[64]; int len; igt_assert(snprintf(full, PATH_MAX, "%s/%s", BACKLIGHT_PATH, fname) < PATH_MAX); fd = open(full, O_WRONLY); if (fd == -1) return -errno; len = snprintf(src, sizeof(src), "%i", value); len = write(fd, src, len); close(fd); if (len < 0) return len; return 0; } static void test_and_verify(struct context *context, int val) { const int tolerance = val * TOLERANCE / 100; int result; igt_assert_eq(backlight_write(val, "brightness"), 0); igt_assert_eq(backlight_read(&result, "brightness"), 0); /* Check that the exact value sticks */ igt_assert_eq(result, val); igt_assert_eq(backlight_read(&result, "actual_brightness"), 0); /* Some rounding may happen depending on hw */ igt_assert_f(result >= max(0, val - tolerance) && result <= min(context->max, val + tolerance), "actual_brightness [%d] did not match expected brightness [%d +- %d]\n", result, val, tolerance); } static void test_brightness(struct context *context) { test_and_verify(context, 0); test_and_verify(context, context->max); test_and_verify(context, context->max / 2); } static void test_bad_brightness(struct context *context) { int val; /* First write some sane value */ backlight_write(context->max / 2, "brightness"); /* Writing invalid values should fail and not change the value */ igt_assert_lt(backlight_write(-1, "brightness"), 0); backlight_read(&val, "brightness"); igt_assert_eq(val, context->max / 2); igt_assert_lt(backlight_write(context->max + 1, "brightness"), 0); backlight_read(&val, "brightness"); igt_assert_eq(val, context->max / 2); igt_assert_lt(backlight_write(INT_MAX, "brightness"), 0); backlight_read(&val, "brightness"); igt_assert_eq(val, context->max / 2); } static void test_fade(struct context *context) { int i; static const struct timespec ts = { .tv_sec = 0, .tv_nsec = FADESPEED*1000000 }; /* Fade out, then in */ for (i = context->max; i > 0; i -= context->max / FADESTEPS) { test_and_verify(context, i); nanosleep(&ts, NULL); } for (i = 0; i <= context->max; i += context->max / FADESTEPS) { test_and_verify(context, i); nanosleep(&ts, NULL); } } static void test_fade_with_dpms(struct context *context, igt_output_t *output) { igt_require(igt_setup_runtime_pm()); kmstest_set_connector_dpms(output->display->drm_fd, output->config.connector, DRM_MODE_DPMS_OFF); igt_require(igt_wait_for_pm_status(IGT_RUNTIME_PM_STATUS_SUSPENDED)); kmstest_set_connector_dpms(output->display->drm_fd, output->config.connector, DRM_MODE_DPMS_ON); igt_assert(igt_wait_for_pm_status(IGT_RUNTIME_PM_STATUS_ACTIVE)); test_fade(context); } static void test_fade_with_suspend(struct context *context, igt_output_t *output) { igt_system_suspend_autoresume(SUSPEND_STATE_MEM, SUSPEND_TEST_NONE); test_fade(context); } igt_main { struct context context = {0}; int old; igt_display_t display; igt_output_t *output; struct igt_fb fb; igt_skip_on_simulation(); igt_fixture { enum pipe pipe; bool found = false; char full_name[32] = {}; char *name; drmModeModeInfo *mode; igt_plane_t *primary; /* Get the max value and skip the whole test if sysfs interface not available */ igt_skip_on(backlight_read(&old, "brightness")); igt_assert(backlight_read(&context.max, "max_brightness") > -1); /* * Backlight tests requires the output to be enabled, * try to enable all. */ kmstest_set_vt_graphics_mode(); igt_display_require(&display, drm_open_driver(DRIVER_INTEL)); /* should be ../../cardX-$output */ igt_assert_lt(12, readlink(BACKLIGHT_PATH "/device", full_name, sizeof(full_name) - 1)); name = basename(full_name); for_each_pipe_with_valid_output(&display, pipe, output) { if (strcmp(name + 6, output->name)) continue; found = true; break; } igt_require_f(found, "Could not map backlight for \"%s\" to connected output\n", name); igt_output_set_pipe(output, pipe); mode = igt_output_get_mode(output); igt_create_pattern_fb(display.drm_fd, mode->hdisplay, mode->vdisplay, DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb); primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY); igt_plane_set_fb(primary, &fb); igt_display_commit2(&display, display.is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY); pm_data = igt_pm_enable_sata_link_power_management(); } igt_subtest("basic-brightness") test_brightness(&context); igt_subtest("bad-brightness") test_bad_brightness(&context); igt_subtest("fade") test_fade(&context); igt_subtest("fade_with_dpms") test_fade_with_dpms(&context, output); igt_subtest("fade_with_suspend") test_fade_with_suspend(&context, output); igt_fixture { /* Restore old brightness */ backlight_write(old, "brightness"); igt_display_fini(&display); igt_remove_fb(display.drm_fd, &fb); igt_pm_restore_sata_link_power_management(pm_data); free(pm_data); close(display.drm_fd); } }