Files
hid_apple_fn_lock/hid_apple_fn_lock.c
2026-09-15 20:39:55 -07:00

150 lines
2.8 KiB
C

#include <unistd.h> /* access */
#include <stdlib.h> /* exit */
#include <syslog.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <string.h> /* strcmp */
/* Kernel module entry for the Apple Human Interface Device driver. */
#define APPLE_HID_PATH "/sys/module/hid_apple"
char file_exists(const char *filename)
{
return access(filename, F_OK) != -1;
}
int init_apple_hid_module()
{
int fd;
if(!file_exists(APPLE_HID_PATH)) {
syslog(LOG_WARNING, "Apple hid module is unloaded.");
return -1;
}
fd = open(APPLE_HID_PATH"/parameters/fnmode", O_RDWR);
if(fd == -1) {
syslog(LOG_WARNING, "Failed to open %s.",
APPLE_HID_PATH"/parameters/fnmode");
return -1;
}
return fd;
}
int get_fn_lock()
{
int fd;
char state;
fd = init_apple_hid_module();
if(fd != -1) {
if(read(fd, &state, 1) != 1)
state = '0';
close(fd);
}
return state == '2';
}
void set_fn_lock_on()
{
int fd;
fd = init_apple_hid_module();
if(fd != -1) {
if(write(fd, "2", 1) != 1)
syslog(LOG_WARNING, "Failed to write to Apple HID driver.");
else
syslog(LOG_INFO, "Fn lock is on.");
close(fd);
}
}
void set_fn_lock_off()
{
int fd = init_apple_hid_module();
if(fd != -1) {
if(write(fd, "1", 1) != 1)
syslog(LOG_WARNING, "Failed to write Apple HID driver.");
else
syslog(LOG_INFO, "Fn lock is off.");
close(fd);
}
}
void daemonize()
{
close(0);
close(1);
close(2);
open("/dev/null", O_RDONLY); /* stdin */
open("/dev/null", O_WRONLY); /* stdout */
open("/dev/null", O_WRONLY); /* stderr */
chdir("/");
int pid = fork();
if(pid > 0)
exit(0);
setsid();
pid = fork();
if(pid > 0)
exit(0);
}
#if 1
static volatile sig_atomic_t n = 0;
void usr1hdl(int sig)
{
int save_errno = errno;
signal(SIGUSR1, usr1hdl);
n = 0;
errno = save_errno;
}
void termhdl(int sig)
{
int save_errno = errno;
signal(SIGTERM, termhdl);
n = 1;
errno = save_errno;
}
#endif
int main(int argc, char *argv[])
{
/*daemonize();*/
signal(SIGUSR1, usr1hdl);
signal(SIGTERM, termhdl);
openlog("hid_apple_fn_lock", 0, LOG_USER);
syslog(LOG_INFO, "Daemon started, pid == %d", getpid());
uid_t euid = geteuid();
if(euid != 0) {
syslog(LOG_WARNING, "Must have root priviliges. Quitting...");
return 1;
}
for(;;) {
pause();
if(n == 0) {
if(get_fn_lock())
set_fn_lock_off();
else
set_fn_lock_on();
} else if(n == 1) {
syslog(LOG_INFO, "Shutting down...");
break;
} else {
/* ignore */
}
}
closelog();
return 0;
}