From fee703567f1b5fce7d7ff2118024b39577bf8711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Thu, 9 Feb 2017 20:12:09 +0100 Subject: Add input-switch Moving common stuff for DDC/CI communicating programs to ddc-ci.c. --- brightness.c | 218 ++--------------------------------------------------------- 1 file changed, 7 insertions(+), 211 deletions(-) (limited to 'brightness.c') diff --git a/brightness.c b/brightness.c index 3b52fc5..4bf63a7 100644 --- a/brightness.c +++ b/brightness.c @@ -17,51 +17,20 @@ * */ -// Sources: ddcciv1r1.pdf, i2c-dev.c in Linux, ddccontrol source code, -// http://www.boichat.ch/nicolas/ddcci/specs.html was also helpful - // This makes openat() available even though I set _POSIX_C_SOURCE and // _XOPEN_SOURCE to a version of POSIX older than 2008 #define _GNU_SOURCE -// Undo some dwm Makefile damage and import my everything-library #include "config.h" #undef PROGRAM_NAME #define PROGRAM_NAME "brightness" #include "liberty/liberty.c" -#include +#include "ddc-ci.c" #include -#include -#ifndef I2C_FUNC_I2C -// Fuck you, openSUSE, for fucking up the previous file, see e.g. -// https://github.com/solettaproject/soletta/commit/427f47f -#include -#endif - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static void -log_message_custom (void *user_data, const char *quote, const char *fmt, - va_list ap) -{ - (void) user_data; - FILE *stream = stdout; - - fprintf (stream, PROGRAM_NAME ": "); - fputs (quote, stream); - vfprintf (stream, fmt, ap); - fputs ("\n", stream); -} - -static void -wait_ms (long ms) -{ - struct timespec ts = { 0, ms * 1000 * 1000 }; - nanosleep (&ts, NULL); -} - static bool xstrtol (const char *s, long *out) { @@ -73,189 +42,16 @@ xstrtol (const char *s, long *out) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#define DDC_LENGTH_XOR 0x80 - -enum -{ - DDC_ADDRESS_HOST = 0x50, ///< Bus master's base address - DDC_ADDRESS_DISPLAY = 0x6E ///< The display's base address -}; - -enum { I2C_WRITE, I2C_READ }; - -enum -{ - DDC_GET_VCP_FEATURE = 0x01, ///< Request info about a feature - DDC_GET_VCP_FEATURE_REPLY = 0x02, ///< Feature info response - DDC_SET_VCP_FEATURE = 0x03 ///< Set or activate a feature -}; - -enum -{ - VCP_BRIGHTNESS = 0x10, ///< Standard VCP opcode for brightness - VCP_CONTRAST = 0x12 ///< Standard VCP opcode for contrast -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static bool -check_edid (int fd, struct error **e) -{ - uint8_t edid_req[] = { 0x00 }; - uint8_t buf[8] = ""; - struct i2c_msg bufs[] = - { - { .addr = 0x50, .flags = 0, - .len = 1, .buf = edid_req }, - { .addr = 0x50, .flags = I2C_M_RD, - .len = sizeof buf, .buf = buf }, - }; - - struct i2c_rdwr_ioctl_data data; - data.msgs = bufs; - data.nmsgs = 2; - - if (ioctl (fd, I2C_RDWR, &data) < 0) - return error_set (e, "%s: %s", "ioctl", strerror (errno)); - if (memcmp ("\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", buf, sizeof buf)) - return error_set (e, "invalid EDID"); - return true; -} - -static bool -is_a_display (int fd, struct error **e) -{ - struct stat st; - if (fstat (fd, &st) < 0) - return error_set (e, "%s: %s", "fstat", strerror (errno)); - - unsigned long funcs; - if (!(st.st_mode & S_IFCHR) - || ioctl (fd, I2C_FUNCS, &funcs) < 0 - || !(funcs & I2C_FUNC_I2C)) - return error_set (e, "not an I2C device"); - - return check_edid (fd, e); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static bool -ddc_send (int fd, unsigned command, void *args, size_t args_len, - struct error **e) -{ - struct str buf; - str_init (&buf); - str_pack_u8 (&buf, DDC_ADDRESS_HOST | I2C_READ); - str_pack_u8 (&buf, DDC_LENGTH_XOR | (args_len + 1)); - str_pack_u8 (&buf, command); - str_append_data (&buf, args, args_len); - - unsigned xor = DDC_ADDRESS_DISPLAY; - for (size_t i = 0; i < buf.len; i++) - xor ^= buf.str[i]; - str_pack_u8 (&buf, xor); - - struct i2c_msg msg = - { - // The driver unshifts it back - .addr = DDC_ADDRESS_DISPLAY >> 1, .flags = 0, - .len = buf.len, .buf = (uint8_t *) buf.str, - }; - - struct i2c_rdwr_ioctl_data data; - data.msgs = &msg; - data.nmsgs = 1; - - bool failed = ioctl (fd, I2C_RDWR, &data) < 0; - str_free (&buf); - if (failed) - return error_set (e, "%s: %s", "ioctl", strerror (errno)); - return true; -} - -static bool -ddc_read (int fd, unsigned *command, void *out_buf, size_t *n_read, - struct error **e) -{ - uint8_t buf[128] = ""; - struct i2c_msg msg = - { - // The driver unshifts it back - .addr = DDC_ADDRESS_DISPLAY >> 1, .flags = I2C_M_RD, - .len = sizeof buf, .buf = buf, - }; - - struct i2c_rdwr_ioctl_data data; - data.msgs = &msg; - data.nmsgs = 1; - - if (ioctl (fd, I2C_RDWR, &data) < 0) - return error_set (e, "%s: %s", "ioctl", strerror (errno)); - - struct msg_unpacker unpacker; - msg_unpacker_init (&unpacker, buf, sizeof buf); - - uint8_t sender, length, cmd; - (void) msg_unpacker_u8 (&unpacker, &sender); - (void) msg_unpacker_u8 (&unpacker, &length); - (void) msg_unpacker_u8 (&unpacker, &cmd); - - if (sender != (DDC_ADDRESS_DISPLAY | I2C_WRITE) || !(length & 0x80)) - return error_set (e, "invalid response"); - if (!(length ^= 0x80)) - return error_set (e, "NULL response"); - - // TODO: also check the checksum - - *command = cmd; - memcpy (out_buf, unpacker.data + unpacker.offset, (*n_read = length - 1)); - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static bool set_brightness (int fd, long diff, struct error **e) { - uint8_t get_req[] = { VCP_BRIGHTNESS }; - if (!ddc_send (fd, DDC_GET_VCP_FEATURE, get_req, sizeof get_req, e)) + struct vcp_feature_readout readout; + if (!vcp_get_feature (fd, VCP_BRIGHTNESS, &readout, e)) return false; - wait_ms (40); - - unsigned command = 0; - uint8_t buf[128] = ""; - size_t len = 0; - if (!ddc_read (fd, &command, buf, &len, e)) - return false; - - if (command != DDC_GET_VCP_FEATURE_REPLY || len != 7) - return error_set (e, "invalid response"); - - struct msg_unpacker unpacker; - msg_unpacker_init (&unpacker, buf, len); - - uint8_t result; msg_unpacker_u8 (&unpacker, &result); - uint8_t vcp_opcode; msg_unpacker_u8 (&unpacker, &vcp_opcode); - uint8_t type; msg_unpacker_u8 (&unpacker, &type); - int16_t max; msg_unpacker_i16 (&unpacker, &max); - int16_t cur; msg_unpacker_i16 (&unpacker, &cur); - - if (result == 0x01) - return error_set (e, "error reported by monitor"); - - if (result != 0x00 - || vcp_opcode != VCP_BRIGHTNESS) - return error_set (e, "invalid response"); - - // These are unsigned but usually just one byte long - if (max < 0 || cur < 0) - return error_set (e, "capability range overflow"); - - int16_t req = (cur * 100 + diff * max + 50) / 100; - if (req > max) req = max; - if (req < 0) req = 0; + int16_t req = (readout.cur * 100 + diff * readout.max + 50) / 100; + req = MIN (req, readout.max); + req = MAX (req, 0); uint8_t set_req[] = { VCP_BRIGHTNESS, req >> 8, req }; if (!ddc_send (fd, DDC_SET_VCP_FEATURE, set_req, sizeof set_req, e)) @@ -263,7 +59,7 @@ set_brightness (int fd, long diff, struct error **e) wait_ms (50); - printf ("brightness set to %.2f%%\n", 100. * req / max); + printf ("brightness set to %.2f%%\n", 100. * req / readout.max); return true; } -- cgit v1.2.3