summaryrefslogtreecommitdiffstats
path: root/src/detection/brightness/brightness_bsd.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/brightness/brightness_bsd.c
Add the files
Diffstat (limited to 'src/detection/brightness/brightness_bsd.c')
-rw-r--r--src/detection/brightness/brightness_bsd.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/src/detection/brightness/brightness_bsd.c b/src/detection/brightness/brightness_bsd.c
new file mode 100644
index 0000000..5ff411c
--- /dev/null
+++ b/src/detection/brightness/brightness_bsd.c
@@ -0,0 +1,147 @@
+#include "brightness.h"
+#include "common/arrutil.h"
+#include "common/io.h"
+#include "common/kmod.h"
+#include "common/debug.h"
+#include "common/time.h"
+
+#include <sys/ioctl.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+
+#if __has_include(<dev/iicbus/iic.h>)
+ #include <dev/iicbus/iic.h>
+
+const char* detectWithDdcci(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
+ // FIXME: doesn't work for me
+ for (char i = '0'; i <= '9'; ++i) {
+ char path[] = "/dev/iic0";
+ path[ARRAY_SIZE(path) - 2] = i;
+
+ FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ int err = errno;
+ if (err == ENOENT) {
+ FF_DEBUG("No more I2C devices");
+ break;
+ } else if (i == '0' && !ffKmodLoaded("iicbus")) {
+ FF_DEBUG("iicbus module is not loaded");
+ return "No I2C devices found and iicbus module is not loaded";
+ }
+ FF_DEBUG("open(/dev/iic%c) failed: %s", i, strerror(errno));
+ continue;
+ }
+
+ uint8_t i2cIn[] = { FF_DDC_CI_VCP_COMMAND, FF_DDC_CI_MAKE_HEADER(2), FF_DDC_CI_GET_VCP, FF_DDC_CI_LUMINANCE_OPCODE, 0 };
+ i2cIn[4] = FF_DDC_CI_WRITE_ADDR ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
+
+ int ret = ioctl(fd, I2CRDWR, &(struct iic_rdwr_data){ .msgs = &(struct iic_msg){ .slave = FF_DDC_CI_WRITE_ADDR, .flags = IIC_M_WR, .len = ARRAY_SIZE(i2cIn), .buf = i2cIn }, .nmsgs = 1 });
+ if (ret < 0) {
+ FF_DEBUG("First ioctl(/dev/iic%c, I2CRDWR) failed: %s", i, strerror(errno));
+ continue;
+ }
+
+ ffTimeSleep(options->ddcciSleep);
+
+ uint8_t i2cOut[12] = {};
+ ret = ioctl(fd, I2CRDWR, &(struct iic_rdwr_data){ .msgs = &(struct iic_msg){ .slave = FF_DDC_CI_READ_ADDR, // LSB will be overridden by kernel to set read bit
+ .flags = IIC_M_RD,
+ .len = ARRAY_SIZE(i2cOut),
+ .buf = i2cOut },
+ .nmsgs = 1 });
+ if (ret < 0) {
+ FF_DEBUG("Second ioctl(/dev/iic%c, I2CRDWR) failed: %s", i, strerror(errno));
+ continue;
+ }
+ if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) {
+ FF_DEBUG("i2c out validation failed: i2cOut[2] = 0x%02x, i2cOut[3] = 0x%02x", i2cOut[2], i2cOut[3]);
+ continue;
+ }
+
+ uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
+ uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
+
+ FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
+ brightness->max = max;
+ brightness->min = 0;
+ brightness->current = current;
+ ffStrbufInitS(&brightness->name, path + strlen("/dev/"));
+ brightness->builtin = false;
+ }
+
+ return NULL;
+}
+
+#else
+
+const char* detectWithDdcci(FF_A_UNUSED FFBrightnessOptions* options, FF_A_UNUSED FFlist* result) {
+ FF_DEBUG("DDC/CI support is not available on this system");
+ return "DDC/CI is supported only on FreeBSD";
+}
+
+#endif
+
+#if __has_include(<sys/backlight.h>)
+ #include <sys/backlight.h>
+
+const char* detectWithBacklight(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
+ // https://man.freebsd.org/cgi/man.cgi?query=backlight&sektion=9
+ char path[] = "/dev/backlight/backlight0";
+
+ for (char i = '0'; i <= '9'; ++i) {
+ path[ARRAY_SIZE(path) - 2] = i;
+
+ FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ int err = errno;
+ if (err == ENOENT) {
+ FF_DEBUG("No more backlight devices");
+ break;
+ } else if (i == '0' && !ffKmodLoaded("backlight")) {
+ FF_DEBUG("backlight module is not loaded");
+ return "No backlight devices found and backlight module is not loaded";
+ }
+ FF_DEBUG("open(/dev/backlight/backlight%c) failed: %s", i, strerror(errno));
+ continue;
+ }
+
+ struct backlight_props status;
+ if (ioctl(fd, BACKLIGHTGETSTATUS, &status) < 0) {
+ continue;
+ }
+
+ FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
+ ffStrbufInit(&brightness->name);
+
+ brightness->max = BACKLIGHTMAXLEVELS;
+ brightness->min = 0;
+ brightness->current = status.brightness;
+ brightness->builtin = true;
+
+ struct backlight_info info;
+ if (ioctl(fd, BACKLIGHTGETINFO, &info) == 0) {
+ ffStrbufAppendS(&brightness->name, info.name);
+ } else {
+ ffStrbufAppendS(&brightness->name, path + strlen("/dev/backlight/"));
+ }
+ }
+ return NULL;
+}
+
+#else
+
+const char* detectWithBacklight(FF_A_UNUSED FFBrightnessOptions* options, FF_A_UNUSED FFlist* result) {
+ FF_DEBUG("Backlight support is not available on this system");
+ return "Backlight is supported only on FreeBSD 13 and newer";
+}
+
+#endif
+
+const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
+ detectWithBacklight(options, result);
+
+ if (options->ddcciSleep != FF_BRIGHTNESS_DDCCI_SLEEP_SKIP && result->length == 0) {
+ detectWithDdcci(options, result);
+ }
+ return NULL;
+}