/* * 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 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) { int result; int tolerance = val * TOLERANCE / 100; 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. Just check that it's close enough. */ igt_assert_lte(result, min(context->max, val + tolerance)); igt_assert_lte(max(0, val - tolerance), result); } 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); } } igt_main { struct context context = {0}; int old; igt_display_t display; struct igt_fb fb; igt_skip_on_simulation(); igt_fixture { enum pipe pipe; igt_output_t *output; 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_init(&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_assert_f(found, "Could not map \"%s\" to output (%s?)\n", name, name + 6); 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); } igt_subtest("basic-brightness") test_brightness(&context); igt_subtest("bad-brightness") test_bad_brightness(&context); igt_subtest("fade") test_fade(&context); igt_fixture { /* Restore old brightness */ backlight_write(old, "brightness"); igt_display_fini(&display); igt_remove_fb(display.drm_fd, &fb); close(display.drm_fd); } }