aboutsummaryrefslogtreecommitdiff
path: root/brightness.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2017-02-09 20:12:09 +0100
committerPřemysl Janouch <p.janouch@gmail.com>2017-02-09 20:12:09 +0100
commitfee703567f1b5fce7d7ff2118024b39577bf8711 (patch)
tree443bce295594eb8bea2dac52380c1b2188b1727c /brightness.c
parentdba39bb612ec7b61d0a440dfe0c3d048b5ecd2ba (diff)
downloaddesktop-tools-fee703567f1b5fce7d7ff2118024b39577bf8711.tar.gz
desktop-tools-fee703567f1b5fce7d7ff2118024b39577bf8711.tar.xz
desktop-tools-fee703567f1b5fce7d7ff2118024b39577bf8711.zip
Add input-switch
Moving common stuff for DDC/CI communicating programs to ddc-ci.c.
Diffstat (limited to 'brightness.c')
-rw-r--r--brightness.c218
1 files changed, 7 insertions, 211 deletions
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 <sys/ioctl.h>
+#include "ddc-ci.c"
#include <dirent.h>
-#include <linux/i2c-dev.h>
-#ifndef I2C_FUNC_I2C
-// Fuck you, openSUSE, for fucking up the previous file, see e.g.
-// https://github.com/solettaproject/soletta/commit/427f47f
-#include <linux/i2c.h>
-#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;
}