Skip to content

Instantly share code, notes, and snippets.

@Orochimarufan
Last active November 2, 2021 19:48
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Orochimarufan/d8e42cfaa32c2cdd13640dad6a10b847 to your computer and use it in GitHub Desktop.
Save Orochimarufan/d8e42cfaa32c2cdd13640dad6a10b847 to your computer and use it in GitHub Desktop.
Hi10 pro speaker enabler
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <fcntl.h>
int gpio_offset() {
struct utsname ver;
int major, minor;
uname(&ver);
sscanf(ver.release, "%d.%d.", &major, &minor);
if (major == 4) {
// until 4.15
if (minor < 16)
return 21;
}
// 4.16 +
return 27;
}
void die_usage(const char *prog) {
printf( "spken (c) 2018 Taeyeon Mori\n"
"CHUWI Hi10 Pro speaker enabler\n"
"\n"
"Usage: %s [enable:0/1]\n"
"\n"
"If omitted, speakers are enabled\n",
prog);
exit(1);
}
void die(const char *msg) {
perror(msg);
exit(errno);
}
int main(int argc, const char**argv) {
char pathbuf[256];
int enable = 1;
int fd, gpio;
DIR *dir;
struct dirent *ent;
// Check argv
if (argc > 2)
die_usage(argv[0]);
else if (argc == 2) {
if (argv[1][0] == '1')
;
else if (argv[1][0] == '0')
enable = 0;
else
die_usage(argv[0]);
if (argv[1][1] != 0)
die_usage(argv[0]);
}
// find chip
dir = opendir("/sys/devices/platform/INT33FF:01/gpio");
if (!dir)
die("Could not open INT33FF:01/gpio in sysfs");
while (1) {
ent = readdir(dir);
if (!ent) {
if (errno)
die("Could not list INT33FF:01/gpio in sysfs");
else {
puts("No gpiochip in INT33FF:01!");
exit(2);
}
}
if (!strncmp(ent->d_name, "gpiochip", 8))
break;
}
//printf("Found gpiochip: %s\n", ent->d_name);
closedir(dir);
// find number
gpio = atoi(ent->d_name + 8) + gpio_offset();
printf("Using gpio %d\n", gpio);
if (snprintf(pathbuf, 255, "/sys/class/gpio/gpio%d/value", gpio) < 0)
die("Could not build path name");
// Export
if (access(pathbuf, F_OK)) {
fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0)
die("Could not open /sys/class/gpio/export");
if(dprintf(fd, "%d", gpio) < 0)
die("Could not export GPIO");
close(fd);
}
// Open
fd = open(pathbuf, O_WRONLY);
if (fd < 0)
die("Could not open gpio pin");
if (dprintf(fd, "%d", enable) < 0)
die("Could not write gpio pin");
close(fd);
return 0;
}
@Orochimarufan
Copy link
Author

For some reason the pin offset changed. Code is updated to work with 4.16

Hardcoding numbers is a hack in the first place, so it's not all too surprising it broke. Unfortunately I'm not aware of a userspace solution to properly extract the pin number from the DSDT AND map it to the linux subsystem numbers...

@boschkundendienst
Copy link

boschkundendienst commented Apr 23, 2018

Thank you so much for the update. I am not very deep in this pin number thing but how do you currently find it out maybe I could then try to find a way to get it from userspace. Maybe something like this could work (if you can find the correct PIN number in the output)?

Extract ACPI tables (as root)

# cat /sys/firmware/acpi/tables/DSDT > dsdt.dat

Decompile

# iasl -d dsdt.dat

Maybe the needed info is in the dsdt.dsl??

Info taken from Arch Wiki (DSDT).

@Orochimarufan
Copy link
Author

Well yes, but you'll still have to somehow map it to the numbering system linux uses. I originally found out by writing a patch to the kernel driver, since driver code can get the info pretty easily; see the earlier discussion in danielotero/linux-on-hi10#8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment