/* *libproc * *ACPI interface header file * *A library interface for finding process information from /proc. *This is also an interface into various things which haven't yet been integrated into sysfs, * as appropriate. Copyright (C) 2004 Joseph Pingenot This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include "acpi.h" #include "libproc-utils.h" #define BATPATH "/proc/acpi/battery/" #define BATPREFIX "BAT" #define BATSTATE "state" #define BATINFO "info" #define BATALARM "alarm" #define CPUPATH "/proc/acpi/processor/" #define CPUPREFIX "CPU" #define CPUINFO "info" #define CPULIMIT "limit" #define CPUPOWER "power" #define CPUTHROTTLE "throttling" struct libproc_acpi_battery *libproc_acpi_get_batteries(int *err) { /*Holders for directory info*/ DIR *batdir; struct dirent *dirfile; /*Head of the cpu info structures linked list.*/ struct libproc_acpi_battery *head = NULL; struct libproc_acpi_battery *current = NULL; struct libproc_acpi_battery *tmp = NULL; int suberr; unsigned int battnum; /*First, we need to iterate through the directory and find each cpu*/ batdir = opendir(BATPATH); if(batdir == NULL){ /*Error of some sort. What was it?*/ switch (errno) { case EACCES: *err = 1; return NULL; case ENFILE: *err = 2; return NULL; case ENOENT: *err = 3; return NULL; case ENOTDIR: *err = 4; return NULL; default: *err = 5; return NULL; } } /*Initialize the head.*/ head = NULL; while((dirfile = readdir(batdir)) != NULL){ //fprintf(stderr, "acpi: found file %s\n", dirfile->d_name); /*Read the dir name, make sure it's CPUX, then process it. If we have more than * 10 cpus, we don't care about power management anyway! */ if((dirfile->d_name)[0] != 'B'){ continue; } if((dirfile->d_name)[1] != 'A'){ continue; } if((dirfile->d_name)[2] != 'T'){ continue; } switch ((dirfile->d_name)[3]) { case '0': battnum = 0; break; case '1': battnum = 1; break; case '2': battnum = 2; break; case '3': battnum = 3; break; case '4': battnum = 4; break; case '5': battnum = 5; break; case '6': battnum = 6; break; case '7': battnum = 7; break; case '8': battnum = 8; break; case '9': break; battnum = 9; break; default: continue; } if((dirfile->d_name)[4] != '\0'){ continue; } //printf("acpi: battery %d valid\n", battnum); /*Alright. Now we have the pathnames. Use the internal functions to get * the battery info.... */ if((tmp = libproc_acpi_get_battery(battnum, &suberr)) == NULL){ *err = 6+10*suberr; /*Is alright that this failed; we just won't link it into the list!*/ continue; } /*Add the battery to our list!*/ tmp->next = NULL; if(head == NULL) { /*This is the first one.*/ head = current = tmp; }else{ /*Just link it in.*/ current->next = tmp; current = tmp; } } *err = 0; return head; } struct libproc_acpi_battery *libproc_acpi_get_battery(unsigned int battery, int *err) { /*Length is determined by path + "BATTX/" + filename + a little space*/ const size_t BatPathLen = strlen(BATPATH); const size_t BatInfoLen = strlen(BATINFO); char BatInfoFile[BatPathLen + 6 + BatInfoLen + 2]; /*Pointer to hold the working copy before it's linked in.*/ struct libproc_acpi_battery *batt; /*String to hold the line just read.*/ char *value; /*Stores the handle for our data file*/ void *handle; /*Assemble the info file name.*/ if(sprintf(BatInfoFile, "%s%s%i/%s", BATPATH, BATPREFIX, battery, BATINFO) <= 0){ /*Error copying the filename down. No path, no shoes, no service. Return!*/ *err = 7; return NULL; } //printf("acpi: battery info file is %s\n", BatInfoFile); /*Create our battery struct.*/ batt = (struct libproc_acpi_battery*) malloc(sizeof(struct libproc_acpi_battery)); if(batt == NULL){ /*Error allocating structure. Return what we have, flag the error.*/ *err = 6; } /*First off, assign the battnum*/ batt->battnum = battery; /*This is pretty scripted. Read line by line.*/ /*First, read in the file.*/ handle = readfile_init(BatInfoFile, err); if(handle == NULL) { //printf(" readfile_init error: %d\n", *err); /*Error happened. Free the struct.*/ free(batt); *err = 8; return NULL; } if((value = readfile_getline(handle, "present", err)) == NULL) { /*Error happened. Free the struct.*/ free(batt); *err = 9; readfile_end(handle); return NULL; } //printf("present: %s\n", value); /*This line is "present"; Is value 'y' or 'n'?*/ if((value[0] == 'y') || (value[0] == 'Y')){ batt->present = 1; }else{ /*Not present. Set that info, set err to success (0), and return the battery!*/ batt->present = 0; *err = 0; readfile_end(handle); return batt; } batt->descap = readfile_getline_lint(handle, "design capacity", err); //printf("batt->descap=%ld; err=%d\n", batt->descap, *err); if(*err != 0) { /*Error happened. Free the struct.*/ free(batt); *err = 10; readfile_end(handle); return NULL; } batt->lastfullcap = readfile_getline_lint(handle, "last full capacity", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(batt); *err = 11; readfile_end(handle); return NULL; } if((value = readfile_getline(handle, "battery technology", err)) == NULL) { /*Error happened. Free the struct.*/ free(batt); *err = 12; readfile_end(handle); return NULL; }else{ /*Copy the string to our buffer. *Given that value IS null-terminated and our memory is allocated as * a part of the struct, nothing should fail. Note that we will limit * the string to the buffer size. */ strncpy((batt->tech), value, LIBPROC_BATTERY_TECHLEN); } batt->desvolt = readfile_getline_lint(handle, "design voltage", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(batt); *err = 13; readfile_end(handle); return NULL; } batt->deswarn = readfile_getline_lint(handle, "design capacity warning", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(batt); *err = 14; readfile_end(handle); return NULL; } batt->deslow = readfile_getline_lint(handle, "design capacity low", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(batt); *err = 15; readfile_end(handle); return NULL; } batt->capgran1 = readfile_getline_lint(handle, "capacity granularity 1", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(batt); *err = 16; readfile_end(handle); return NULL; } batt->capgran2 = readfile_getline_lint(handle, "capacity granularity 2", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(batt); *err = 17; readfile_end(handle); return NULL; } if((value = readfile_getline(handle, "model number", err)) == NULL) { /*Error happened. Free the struct.*/ free(batt); *err = 18; readfile_end(handle); return NULL; }else{ /*Copy the string to our buffer. *Given that value IS null-terminated and our memory is allocated as * a part of the struct, nothing should fail. Note that we will limit * the string to the buffer size. */ strncpy((batt->model), value, LIBPROC_BATTERY_MODELLEN); } if((value = readfile_getline(handle, "serial number", err)) == NULL) { /*Error happened. Free the struct.*/ free(batt); *err = 19; readfile_end(handle); return NULL; }else{ /*Copy the string to our buffer. *Given that value IS null-terminated and our memory is allocated as * a part of the struct, nothing should fail. Note that we will limit * the string to the buffer size. */ strncpy((batt->serial), value, LIBPROC_BATTERY_SERIALLEN); } if((value = readfile_getline(handle, "battery type", err)) == NULL) { /*Error happened. Free the struct.*/ free(batt); *err = 20; readfile_end(handle); return NULL; }else{ /*Copy the string to our buffer. *Given that value IS null-terminated and our memory is allocated as * a part of the struct, nothing should fail. Note that we will limit * the string to the buffer size. */ strncpy((batt->type), value, LIBPROC_BATTERY_TYPELEN); } if((value = readfile_getline(handle, "OEM info", err)) == NULL) { /*Error happened. Free the struct.*/ free(batt); *err = 21; readfile_end(handle); return NULL; }else{ /*Copy the string to our buffer. *Given that value IS null-terminated and our memory is allocated as * a part of the struct, nothing should fail. Note that we will limit * the string to the buffer size. */ strncpy((batt->oem), value, LIBPROC_BATTERY_OEMLEN); } /*We've copied all strings into new buffers, and we're done with this file. *Go ahead and clean it up. */ readfile_end(handle); /*Placeholder*/ batt->state = libproc_acpi_get_battery_state(battery, err); /*if((batt->state) == NULL){ printf("batt->state is NULL; err is %d.\n", *err); }*/ batt->alarm = libproc_acpi_get_battery_alarm(battery, err); /*if(*err != 0) { printf("batt->alarm: got error %d.\n", *err); } printf("alarm: %ld\n", batt->alarm);*/ *err = 0; return batt; } struct libproc_acpi_battstate *libproc_acpi_get_battery_state(unsigned int battery, int *err) { const size_t BatPathLen = strlen(BATPATH); const size_t BatStateLen = strlen(BATSTATE); char BatStateFile[BatPathLen + 6 + BatStateLen + 2]; struct libproc_acpi_battstate* state; void* handle; char* value; if(sprintf(BatStateFile, "%s%s%i/%s", BATPATH, BATPREFIX, battery, BATSTATE) <= 0){ /*Error copying the filename down. No path, no shoes, no service. Return!*/ *err = 7; return NULL; } //printf("acpi: battery state file is %s\n", BatStateFile); state = (struct libproc_acpi_battstate*)malloc(sizeof(struct libproc_acpi_battstate)); if(state == NULL) { *err = 1; return NULL; } /*Now we fill in the struct.*/ handle = readfile_init(BatStateFile, err); if(handle == NULL) { //printf(" readfile_init error: %d\n", *err); /*Error happened. Free the struct.*/ free(state); *err = 8; return NULL; } if((value = readfile_getline(handle, "present", err)) == NULL) { /*Error happened. Free the struct.*/ free(state); *err = 9; readfile_end(handle); return NULL; } //printf("present: %s\n", value); /*This line is "present"; Is value 'y' or 'n'?*/ if((value[0] == 'y') || (value[0] == 'Y')){ state->present = 1; }else{ /*Not present. Set that info, set err to success (0), and return the battery!*/ state->present = 0; *err = 0; readfile_end(handle); return state; } if((value = readfile_getline(handle, "capacity state", err)) == NULL) { /*Error happened. Free the struct.*/ free(state); *err = 10; readfile_end(handle); return NULL; }else{ /*What is our state? Go paranoid: if not ok, critical!*/ if((value[0] == 'o') || (value[0] == 'O')) { state->capstate = LIBPROC_BATTERY_OK; }else{ state->capstate = LIBPROC_BATTERY_CRITICAL; } } if((value = readfile_getline(handle, "charging state", err)) == NULL) { /*Error happened. Free the struct.*/ free(state); *err = 11; readfile_end(handle); return NULL; }else{ /*We have 4 states to distinguish from: * charging * charged * discharging * charging/discharging *We use a short cut to be quick.*/ if((value[0] == 'd') || (value[0] == 'D')){ /*Discharging.*/ state->chargestate = LIBPROC_BATTERY_DISCHARGING; }else if((value[5] == 'e') || (value[5] == 'E')){ /*chargEd*/ state->chargestate = LIBPROC_BATTERY_CHARGED; }else if((strcmp(value, "charging") == 0) || (strcmp(value, "Charging") == 0) || (strcmp(value, "CHARGING") == 0)) { /*We have to compare all, since accessing past the last 'g' would be in * error if we're in the (much much more common) charging state. *NOTE that we can use strcmp not strncmp, since both are known to be * null-terminated. */ state->chargestate = LIBPROC_BATTERY_CHARGING; }else { /*Default. This is teh "charging/discharging" state.*/ state->chargestate = LIBPROC_BATTERY_CHARGING_DISCHARGING; } } state->rate = readfile_getline_lint(handle, "present rate", err); if(*err != 0) { /*We can't find a long int rate. That is OK; it's probably "unknown", i.e. * not discharging.*/ state->rate = 0; } state->capacity = readfile_getline_lint(handle, "remaining capacity", err); if(*err != 0) { free(state); *err = 13; readfile_end(handle); return NULL; } state->voltage = readfile_getline_lint(handle, "present voltage", err); if(*err != 0) { free(state); *err = 14; readfile_end(handle); return NULL; } readfile_end(handle); *err = 0; return state; } unsigned long int libproc_acpi_get_battery_alarm(unsigned int battery, int *err) { const size_t BatPathLen = strlen(BATPATH); const size_t BatAlarmLen = strlen(BATALARM); char BatAlarmFile[BatPathLen + 6 + BatAlarmLen + 2]; void* handle; long int alarm; if(sprintf(BatAlarmFile, "%s%s%i/%s", BATPATH, BATPREFIX, battery, BATALARM) <= 0){ /*Error copying the filename down. No path, no shoes, no service. Return!*/ *err = 7; return 0; } //printf("acpi: battery alarm file is %s\n", BatAlarmFile); handle = readfile_init(BatAlarmFile, err); if(handle == NULL) { //printf(" readfile_init error: %d\n", *err); /*Error happened. Free the struct.*/ *err = 8; return 0; } alarm = readfile_getline_lint(handle, "alarm", err); if(*err != 0) { //printf("reading alarm: err is %d\n", *err); *err = 9; readfile_end(handle); return 0; } //printf("alarm is %ld\n", alarm); readfile_end(handle); /*that was all. Simple!*/ *err = 0; return alarm; } /**************************************************************** *CPU ACCESS FUNCTIONS ****************************************************************/ /*Internal functions*/ /*Provides a pointer to where in the string the whitespace (first arg * provides a list of whitespace chars) ends. */ char *eat_whitespace(char* whites, char* string); /*API implementation*/ /*Error codes: * 0 Success * 1 Access denied * 2 Too many open files in this process/system. * 3 No such directory * 4 Insufficient memory to opendir * 5 Not a directory * 6 Ran out of memory allocating cpu struct */ struct libproc_acpi_cpu *libproc_acpi_get_cpus(int *err) { unsigned int cpunum; int suberr; /*Holders for directory info*/ DIR *cpudir; struct dirent *dirfile; /*Head of the cpu info structures linked list.*/ struct libproc_acpi_cpu* head = NULL; struct libproc_acpi_cpu* current = NULL; /*Pointer to hold the working copy before it's linked in.*/ struct libproc_acpi_cpu* tmp = NULL; /*First, we need to iterate through the directory and find each cpu*/ cpudir = opendir(CPUPATH); if(cpudir == NULL){ /*Error of some sort. What was it?*/ switch (errno) { case EACCES: *err = 1; return NULL; case ENFILE: *err = 2; return NULL; case ENOENT: *err = 3; return NULL; case ENOTDIR: *err = 4; return NULL; default: *err = 5; return NULL; } } *err = 0; /*Initialize the head.*/ while((dirfile = readdir(cpudir)) != NULL){ //fprintf(stderr, "acpi: found file %s\n", dirfile->d_name); /*Read the dir name, make sure it's CPUX, then process it. If we have more than * 10 cpus, we don't care about power management anyway! */ if((dirfile->d_name)[0] != 'C'){ continue; } if((dirfile->d_name)[1] != 'P'){ continue; } if((dirfile->d_name)[2] != 'U'){ continue; } switch ((dirfile->d_name)[3]) { case '0': cpunum = 0; break; case '1': cpunum = 1; break; case '2': cpunum = 2; break; case '3': cpunum = 3; break; case '4': cpunum = 4; break; case '5': cpunum = 5; break; case '6': cpunum = 6; break; case '7': cpunum = 7; break; case '8': cpunum = 8; break; case '9': cpunum = 9; break; default: continue; } if((dirfile->d_name)[4] != '\0'){ continue; } //printf("acpi: valid\n"); /*Alright. Now we have the pathnames. Use the internal functions to get * the battery info.... */ if((tmp = libproc_acpi_get_cpu(cpunum, &suberr)) == NULL){ //printf("get_cpu(%d, %d) returned NULL\n", cpunum, suberr); *err = 6+10*suberr; /*Is alright that this failed; we just won't link it into the list!*/ continue; } //printf("get_cpu(%d, %d) returned %x.\n", cpunum, suberr, (unsigned int)tmp); /*Add the battery to our list!*/ tmp->next = NULL; if(head == NULL) { /*This is the first one.*/ head = current = tmp; }else{ /*Just link it in.*/ current->next = tmp; current = tmp; } } return head; } struct libproc_acpi_cpu* libproc_acpi_get_cpu(unsigned int cpu, int *err) { const size_t cpuPathLen = strlen(CPUPATH); const size_t cpuInfoLen = strlen(CPUINFO); /*Length is determined by path + "CPUXX/" + filename + a little space*/ char cpuInfoFile[cpuPathLen + 6 + cpuInfoLen + 2]; struct libproc_acpi_cpu* scpu; void* handle; char* value; /*Alright. It's valid! Now, make the cpu info struct and fill it.*/ scpu = (struct libproc_acpi_cpu*) malloc(sizeof(struct libproc_acpi_cpu)); if(scpu == NULL){ /*Error allocating structure. Return what we have, flag the error.*/ *err = 6; return NULL; } /*Assemble the info file name.*/ if(sprintf(cpuInfoFile, "%s%s%i/%s", CPUPATH, CPUPREFIX, cpu, CPUINFO) <= 0){ /*Error copying the filename down. Continue, but first free the struct.*/ free(scpu); *err = 7; return NULL; } //printf("acpi: cpu info file is %s\n", cpuInfoFile); handle = readfile_init(cpuInfoFile, err); if(handle == NULL) { //printf(" readfile_init error: %d\n", *err); /*Error happened. Free the struct.*/ free(scpu); *err = 8; return NULL; } scpu->id = readfile_getline_int(handle, "processor id", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(scpu); *err = 10; readfile_end(handle); return NULL; } scpu->acpiId = readfile_getline_int(handle, "acpi id", err); if(*err != 0) { /*Error happened. Free the struct.*/ free(scpu); *err = 10; readfile_end(handle); return NULL; } if((value = readfile_getline(handle, "bus mastering control", err)) == NULL) { /*Error happened. Free the struct.*/ free(scpu); *err = 9; readfile_end(handle); return NULL; } /*This line is "present"; Is value 'y' or 'n'?*/ if((value[0] == 'y') || (value[0] == 'Y')){ scpu->busmastering = 1; }else{ /*Not present. Set that info, set err to success (0), and return the battery!*/ scpu->busmastering = 0; } if((value = readfile_getline(handle, "power management", err)) == NULL) { /*Error happened. Free the struct.*/ free(scpu); *err = 9; readfile_end(handle); return NULL; } /*This line is "present"; Is value 'y' or 'n'?*/ if((value[0] == 'y') || (value[0] == 'Y')){ scpu->powerman = 1; }else{ /*Not present. Set that info, set err to success (0), and return the battery!*/ scpu->powerman = 0; } if((value = readfile_getline(handle, "throttling control", err)) == NULL) { /*Error happened. Free the struct.*/ free(scpu); *err = 9; readfile_end(handle); return NULL; } /*This line is "present"; Is value 'y' or 'n'?*/ if((value[0] == 'y') || (value[0] == 'Y')){ scpu->throttling = 1; }else{ /*Not present. Set that info, set err to success (0), and return the battery!*/ scpu->throttling = 0; } if((value = readfile_getline(handle, "limit interface", err)) == NULL) { /*Error happened. Free the struct.*/ free(scpu); *err = 9; readfile_end(handle); return NULL; } /*This line is "present"; Is value 'y' or 'n'?*/ if((value[0] == 'y') || (value[0] == 'Y')){ scpu->limitflag = 1; }else{ /*Not present. Set that info, set err to success (0), and return the battery!*/ scpu->limitflag = 0; } /*Close things up.*/ readfile_end(handle); if(scpu->limitflag){ scpu->limit = libproc_acpi_get_cpulimit(cpu, err); }else{ scpu->limit = NULL; } if(scpu->powerman){ //printf("powerman\n"); scpu->power = libproc_acpi_get_cpupower(cpu, err); //printf(" power is %x, err is %d.\n", (int)scpu->power, *err); }else{ //printf("no powerman\n"); scpu->power = NULL; } if(scpu->throttling){ scpu->throttle = libproc_acpi_get_cputhrottling(cpu, err); }else{ scpu->throttle = NULL; } *err = 0; return scpu; } struct libproc_acpi_cpulimit *libproc_acpi_get_cpulimit(unsigned int cpu, int *err) { const size_t cpuPathLen = strlen(CPUPATH); const size_t cpuLimitLen = strlen(CPULIMIT); /*Length is determined by path + "CPUXX/" + filename + a little space*/ char cpuLimitFile[cpuPathLen + 6 + cpuLimitLen + 2]; struct libproc_acpi_cpulimit* scpulim; void* handle; char* value; unsigned int p, t; if(sprintf(cpuLimitFile, "%s%s%d/%s", CPUPATH, "CPU", cpu, CPULIMIT) <= 0){ /*Error copying the filename down. Continue, but first free the struct.*/ *err = 7; return NULL; } /*Allocate a CPUlimit struct.*/ if((scpulim = (struct libproc_acpi_cpulimit*)malloc(sizeof(struct libproc_acpi_cpulimit))) == NULL) { *err = 15; return NULL; } //printf("acpi: cpu limit file is %s\n", cpuLimitFile); handle = readfile_init(cpuLimitFile, err); if(handle == NULL) { //printf(" readfile_init error: %d\n", *err); /*Error happened. Free the struct.*/ free(scpulim); *err = 8; return NULL; } if((value = readfile_getline(handle, "active limit", err)) == NULL) { /*Error happened. Free the struct.*/ free(scpulim); *err = 9; readfile_end(handle); return NULL; } if(sscanf(value, "P%d:T%d", &p, &t) != 2){ free(scpulim); *err = 10; readfile_end(handle); return NULL; } scpulim->activep = p; scpulim->activep = t; if((value = readfile_getline(handle, "user limit", err)) == NULL) { /*Error happened. Free the struct.*/ free(scpulim); *err = 11; readfile_end(handle); return NULL; } if(sscanf(value, "P%d:T%d", &p, &t) != 2){ free(scpulim); *err = 12; readfile_end(handle); return NULL; } scpulim->userp = p; scpulim->userp = t; if((value = readfile_getline(handle, "thermal limit", err)) == NULL) { /*Error happened. Free the struct.*/ free(scpulim); *err = 13; readfile_end(handle); return NULL; } if(sscanf(value, "P%d:T%d", &p, &t) != 2){ free(scpulim); *err = 14; readfile_end(handle); return NULL; } scpulim->thermp = p; scpulim->thermp = t; /*Close things up.*/ readfile_end(handle); *err = 0; return scpulim; } int libproc_acpi_set_cpulimit(unsigned int cpu, int p, int t) { const size_t cpuPathLen = strlen(CPUPATH); const size_t cpuLimitLen = strlen(CPULIMIT); FILE* file; /*Length is determined by path + "CPUXX/" + filename + a little space*/ char cpuLimitFile[cpuPathLen + 6 + cpuLimitLen + 2]; if(sprintf(cpuLimitFile, "%s%s%d/%s", CPUPATH, "CPU", cpu, CPULIMIT) <= 0){ /*Error copying the filename down. Continue, but first free the struct.*/ return -1; } //printf("acpi: cpu limit file is %s\n", cpuLimitFile); if((file = fopen(cpuLimitFile, "w")) == NULL) { /*File couldn't be opened.*/ return -2; } if(fprintf(file, "%d:%d", p, t) <= 0) { /*Couldn't write enough chars to the file.*/ fclose(file); return -3; } fclose(file); return 0; } struct libproc_acpi_cpupower *libproc_acpi_get_cpupower(unsigned int cpu, int *err) { const size_t cpuPathLen = strlen(CPUPATH); const size_t cpuPowerLen = strlen(CPUPOWER); /*Length is determined by path + "CPUXX/" + filename + a little space*/ char cpuPowerFile[cpuPathLen + 6 + cpuPowerLen + 2]; void* handle; char* value; char *line; /*var to hold our state info*/ unsigned int c; /*Line number in the power file.*/ int statesline; int linenum; /*power struct*/ struct libproc_acpi_cpupower* power; /*Linked list pointers for the cstate linked list. *NOTE that the head of the list is in the power struct.*/ struct libproc_acpi_cstate* current; struct libproc_acpi_cstate* tmp; /*promotion, demotion, latency, usage.*/ unsigned int promo; unsigned int demo; unsigned int latency; unsigned long int usage; if(sprintf(cpuPowerFile, "%s%s%d/%s", CPUPATH, "CPU", cpu, CPUPOWER) <= 0){ /*Error copying the filename down. Continue, but first free the struct.*/ *err = 7; return NULL; } /*Alocate our cpupowefile*/ if((power = (struct libproc_acpi_cpupower*)malloc(sizeof(struct libproc_acpi_cpupower))) == NULL) { *err = 11; return NULL; } //printf("acpi: cpu power file is %s\n", cpuPowerFile); handle = readfile_init(cpuPowerFile, err); if(handle == NULL) { //printf(" readfile_init error: %d\n", *err); /*Error happened. Free the struct.*/ free(power); /*heh. Now if we could only make free power work in real life....*/ *err = 8; return NULL; } if((value = readfile_getline(handle, "active state", err)) == NULL) { /*Error happened. Free the struct.*/ free(power); *err = 9; readfile_end(handle); return NULL; } if(sscanf(value, "C%d", &c) != 1){ free(power); *err = 10; readfile_end(handle); return NULL; } power->activec = c; if((value = readfile_getline(handle, "default state", err)) == NULL) { /*Error happened. Free the struct.*/ free(power); *err = 12; readfile_end(handle); return NULL; } if(sscanf(value, "C%d", &c) != 1){ free(power); *err = 13; readfile_end(handle); return NULL; } power->defaultc = c; if((value = readfile_getline(handle, "bus master activity", err)) == NULL) { /*Error happened. Free the struct.*/ free(power); *err = 14; readfile_end(handle); return NULL; } if(sscanf(value, "%x", &c) != 1){ free(power); *err = 15; readfile_end(handle); return NULL; } power->busmaster = c; /*Make sure that the linked list head is NULL before we start in.*/ power->cstates = NULL; /*now for the c-states. *What a pain.*/ /*First, get the line corresponding to the string "states:"*/ if((statesline = readfile_getlinenum(handle, "states", err)) < 0){ /*No such line. BZZT.*/ free(power); *err = 16; readfile_end(handle); return NULL; } /*For each line:*/ for(linenum = statesline + 1; (line = eat_whitespace(" \t*", readfile_get_linen(handle, linenum, err))) != NULL; linenum++) { //printf("line %d, line = %s\n", linenum, line); /*Allocate the cstate struct.*/ if((tmp = (struct libproc_acpi_cstate*)malloc(sizeof(struct libproc_acpi_cstate))) == NULL) { /*Couldn't allocate.*/ /*Since this is the last part of the power info, we can just return the * power struct with a NULL cstates head.*/ power->cstates = NULL; *err = 17; readfile_end(handle); return power; } /*Now figure out which C-state it is*/ if(sscanf(line, "C%d", &c) != 1){ //printf(" bad line '%s'\n", line); /*Error. Free the cstate struct.*/ free(tmp); /*But get the other cstates.*/ continue; } //printf(" good line for state: %d\n", c); tmp->state=c; /*Now get the promotion demotion etc.*/ if((value = readfile_get_valuen(handle, linenum, err)) == NULL) { free(tmp); /*But get the other cstates.*/ continue; } if(sscanf(value, "promotion[C%d] demotion[C%d] latency[%d] usage[%ld]", &promo, &demo, &latency, &usage) != 4) { //printf(" pdlu line (%s) doesn't have all aspects.\n", value); /*It didn't match that pattern. Try there being *no* promo.*/ if(sscanf(value, "promotion[--] demotion[C%d] latency[%d] usage[%ld]", &demo, &latency, &usage) != 3) { //printf(" pdlu line (%s) doesn't have all non-promo aspects.\n", value); /*Nope. How about demo?*/ if(sscanf(value, "promotion[C%d] demotion[--] latency[%d] usage[%ld]", &promo, &latency, &usage) != 3) { //printf(" pdlu line (%s) unknown (doesn't even have all non-demo aspects.\n", value); /*Nope. Whelp, I'm fresh out of ideas as to what this could be.*/ free(tmp); continue; }else{ /*Yep. We simply nave no demotion. Use the invalid 65535 state.*/ tmp->p = promo; tmp->d = 65535; tmp->latency = latency; tmp->usage = usage; } }else{ /*We simply have no promotion. Use the invalid 65535 state.*/ tmp->p = 65535; tmp->d = demo; tmp->latency = latency; tmp->usage = usage; } }else{ /*All values are good.*/ tmp->p = promo; tmp->d = demo; tmp->latency = latency; tmp->usage = usage; } /*Make sure this is NULL (prevents walking off our memory*/ tmp->next = NULL; /*Alright. That's our state. Link it in.*/ if(power->cstates == NULL) { /*First. This is now the head.*/ power->cstates = current = tmp; }else{ current->next = tmp; current = tmp; } } /*Release our file info*/ readfile_end(handle); /*That is all!*/ return power; } struct libproc_acpi_cputhrottling *libproc_acpi_get_cputhrottling(unsigned int cpu, int *err) { const size_t cpuPathLen = strlen(CPUPATH); const size_t cpuThrottleLen = strlen(CPUTHROTTLE); /*Length is determined by path + "CPUXX/" + filename + a little space*/ char cpuThrottleFile[cpuPathLen + 6 + cpuThrottleLen + 2]; /*For dealing with out file reading mechanism*/ void *handle; char *line; char *value; unsigned int c; int statesline; int linenum; /*Our throttle struct.*/ struct libproc_acpi_cputhrottling* throttle; /*Our tstate list construction vars. Same deal as with the c-states.*/ struct libproc_acpi_tstate* current; struct libproc_acpi_tstate* tmp; if(sprintf(cpuThrottleFile, "%s%s%d/%s", CPUPATH, "CPU", cpu, CPUTHROTTLE) <= 0){ /*Error copying the filename down. Continue, but first free the struct.*/ *err = 7; return NULL; } //printf("acpi: cpu throttle file is %s\n", cpuThrottleFile); /*Alocate our cpupowefile*/ if((throttle = (struct libproc_acpi_cputhrottling*)malloc(sizeof(struct libproc_acpi_cputhrottling))) == NULL) { *err = 11; return NULL; } //printf("acpi: cpu power file is %s\n", cpuPowerFile); handle = readfile_init(cpuThrottleFile, err); if(handle == NULL) { //printf(" readfile_init error: %d\n", *err); /*Error happened. Free the struct.*/ free(throttle); /*heh. Now if we could only make free power work in real life....*/ *err = 8; return NULL; } if((value = readfile_getline(handle, "state count", err)) == NULL) { /*Error happened. Free the struct.*/ free(throttle); *err = 9; readfile_end(handle); return NULL; } if(sscanf(value, "%d", &c) != 1){ free(throttle); *err = 10; readfile_end(handle); return NULL; } throttle->numstates = c; if((value = readfile_getline(handle, "active state", err)) == NULL) { /*Error happened. Free the struct.*/ free(throttle); *err = 9; readfile_end(handle); return NULL; } if(sscanf(value, "T%d", &c) != 1){ free(throttle); *err = 10; readfile_end(handle); return NULL; } throttle->active = c; /*Make sure that the linked list head is NULL before we start in.*/ throttle->tstates = NULL; /*now for the t-states. *What a pain.*/ /*First, get the line corresponding to the string "states:"*/ if((statesline = readfile_getlinenum(handle, "states", err)) < 0){ /*No such line. BZZT.*/ free(value); *err = 16; readfile_end(handle); return NULL; } /*For each line:*/ for(linenum = statesline + 1; (line = eat_whitespace(" \t*", readfile_get_linen(handle, linenum, err))) != NULL; linenum++) { //printf("line %d, line = %s\n", linenum, line); /*Allocate the cstate struct.*/ if((tmp = (struct libproc_acpi_tstate*)malloc(sizeof(struct libproc_acpi_tstate))) == NULL) { /*Couldn't allocate.*/ /*Since this is the last part of the throttle info, we can just return the * throttle struct with a NULL tstates head.*/ throttle->tstates = NULL; *err = 17; readfile_end(handle); return throttle; } /*Now figure out which C-state it is*/ if(sscanf(line, "T%d", &c) != 1){ //printf(" bad line '%s'\n", line); /*Error. Free the cstate struct.*/ free(tmp); /*But get the other cstates.*/ continue; } //printf(" good line for state: %d\n", c); tmp->state=c; /*Now get the promotion demotion etc.*/ if((value = readfile_get_valuen(handle, linenum, err)) == NULL) { //printf(" unable to get value.\n"); free(tmp); /*But get the other cstates.*/ continue; } //printf(" got value (%s)\n", value); if(sscanf(value, "%d%%", &c) != 1){ //printf(" got bad value (%s).\n", value); free(tmp); /*But get the other cstates.*/ continue; } //printf("got good value (%s), c=%d\n", value, c); tmp->throttling = c; if((tmp->state) == (throttle->active)) { //printf(" state is active.\n"); tmp->active = 1; }else{ //printf(" state is not active.\n"); tmp->active = 0; } /*Make sure this is NULL (prevents walking off our memory*/ tmp->next = NULL; /*Alright. That's our state. Link it in.*/ if(throttle->tstates == NULL) { /*First. This is now the head.*/ throttle->tstates = current = tmp; }else{ current->next = tmp; current = tmp; } } /*Release our file info*/ readfile_end(handle); return throttle; } /***************************************************************** *Internal function implementations *****************************************************************/ char *eat_whitespace(char* whites, char* string) { register char* location; register char* whitei; register int whitefound; if((whites == NULL) || (string == NULL)) { return NULL; } //printf("eating whitepsace (%s) in string (%s)\n", whites, string); for(location=string; *location != '\0'; ++location){ //printf(" location='%c'\n", *location); /*We look through the list of whitespace chars to check*/ whitefound = 0; for(whitei=whites; *whitei != '\0'; ++whitei){ //printf(" whitei='%c'\n", *whitei); if(*whitei == *location) { whitefound = 1; break; } } if(!whitefound){ //printf(" End of white space! location='%c'\n", *location); /*We found the end of the white space!*/ return location; /*}else{ *printf(" Just found white space. location='%c'\n", *location); */ } /*Otherwise, we found whitespace. Move on to the next letter.*/ } /*We went through the whole string and it was all whitespace!*/ return NULL; } /*Helper functions*/ void libproc_acpi_freetstate(struct libproc_acpi_tstate* tstate) { /*Recursive!*/ if(tstate == NULL) return; libproc_acpi_freetstate(tstate->next); free(tstate); } void libproc_acpi_freecstate(struct libproc_acpi_cstate* cstate) { /*Recursive!*/ if(cstate == NULL) return; libproc_acpi_freecstate(cstate->next); free(cstate); } void libproc_acpi_freethrottling(struct libproc_acpi_cputhrottling* throttle) { /*We can just run the freetstate func, since it just returns if it's null*/ if(throttle == NULL) return; libproc_acpi_freetstate(throttle->tstates); free(throttle); } void libproc_acpi_freepower(struct libproc_acpi_cpupower* power) { if(power == NULL) return; /*We can just run the freecstate func, since it just returns if it's null*/ libproc_acpi_freecstate(power->cstates); free(power); } void libproc_acpi_freelimit(struct libproc_acpi_cpulimit* limit) { if(limit == NULL) return; free(limit); } void libproc_acpi_freecpu(struct libproc_acpi_cpu* cpu) { /*Recurive!*/ if(cpu == NULL) return; libproc_acpi_freecpu(cpu->next); libproc_acpi_freelimit(cpu->limit); libproc_acpi_freepower(cpu->power); libproc_acpi_freethrottling(cpu->throttle); free(cpu); } void libproc_acpi_freebattstate(struct libproc_acpi_battstate* state) { if(state == NULL) return; free(state); } void libproc_acpi_freebattery(struct libproc_acpi_battery* batt) { /*Recursive!*/ if(batt == NULL) return; libproc_acpi_freebattery(batt->next); libproc_acpi_freebattstate(batt->state); free(batt); }