open-nomad/lib/darwin/include/smc.c

169 lines
3.7 KiB
C
Raw Normal View History

#include "smc.h"
#define IOSERVICE_SMC "AppleSMC"
#define IOSERVICE_MODEL "IOPlatformExpertDevice"
#define DATA_TYPE_SP78 "sp78"
typedef enum {
kSMCUserClientOpen = 0,
kSMCUserClientClose = 1,
kSMCHandleYPCEvent = 2,
kSMCReadKey = 5,
kSMCWriteKey = 6,
kSMCGetKeyCount = 7,
kSMCGetKeyFromIndex = 8,
kSMCGetKeyInfo = 9,
} selector_t;
typedef struct {
unsigned char major;
unsigned char minor;
unsigned char build;
unsigned char reserved;
unsigned short release;
} SMCVersion;
typedef struct {
uint16_t version;
uint16_t length;
uint32_t cpuPLimit;
uint32_t gpuPLimit;
uint32_t memPLimit;
} SMCPLimitData;
typedef struct {
IOByteCount data_size;
uint32_t data_type;
uint8_t data_attributes;
} SMCKeyInfoData;
typedef struct {
uint32_t key;
SMCVersion vers;
SMCPLimitData p_limit_data;
SMCKeyInfoData key_info;
uint8_t result;
uint8_t status;
uint8_t data8;
uint32_t data32;
uint8_t bytes[32];
} SMCParamStruct;
typedef enum {
kSMCSuccess = 0,
kSMCError = 1,
kSMCKeyNotFound = 0x84,
} kSMC_t;
typedef struct {
uint8_t data[32];
uint32_t data_type;
uint32_t data_size;
kSMC_t kSMC;
} smc_return_t;
static const int SMC_KEY_SIZE = 4; // number of characters in an SMC key.
static io_connect_t conn; // our connection to the SMC.
kern_return_t open_smc(void) {
kern_return_t result;
io_service_t service;
service = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching(IOSERVICE_SMC));
if (service == 0) {
// Note: IOServiceMatching documents 0 on failure
printf("ERROR: %s NOT FOUND\n", IOSERVICE_SMC);
return kIOReturnError;
}
result = IOServiceOpen(service, mach_task_self(), 0, &conn);
IOObjectRelease(service);
return result;
}
kern_return_t close_smc(void) { return IOServiceClose(conn); }
static uint32_t to_uint32(char *key) {
uint32_t ans = 0;
uint32_t shift = 24;
if (strlen(key) != SMC_KEY_SIZE) {
return 0;
}
for (int i = 0; i < SMC_KEY_SIZE; i++) {
ans += key[i] << shift;
shift -= 8;
}
return ans;
}
static kern_return_t call_smc(SMCParamStruct *input, SMCParamStruct *output) {
kern_return_t result;
size_t input_cnt = sizeof(SMCParamStruct);
size_t output_cnt = sizeof(SMCParamStruct);
result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent, input, input_cnt,
output, &output_cnt);
if (result != kIOReturnSuccess) {
result = err_get_code(result);
}
return result;
}
static kern_return_t read_smc(char *key, smc_return_t *result_smc) {
kern_return_t result;
SMCParamStruct input;
SMCParamStruct output;
memset(&input, 0, sizeof(SMCParamStruct));
memset(&output, 0, sizeof(SMCParamStruct));
memset(result_smc, 0, sizeof(smc_return_t));
input.key = to_uint32(key);
input.data8 = kSMCGetKeyInfo;
result = call_smc(&input, &output);
result_smc->kSMC = output.result;
if (result != kIOReturnSuccess || output.result != kSMCSuccess) {
return result;
}
result_smc->data_size = output.key_info.data_size;
result_smc->data_type = output.key_info.data_type;
input.key_info.data_size = output.key_info.data_size;
input.data8 = kSMCReadKey;
result = call_smc(&input, &output);
result_smc->kSMC = output.result;
if (result != kIOReturnSuccess || output.result != kSMCSuccess) {
return result;
}
memcpy(result_smc->data, output.bytes, sizeof(output.bytes));
return result;
}
double get_temperature(char *key) {
kern_return_t result;
smc_return_t result_smc;
result = read_smc(key, &result_smc);
if (!(result == kIOReturnSuccess) && result_smc.data_size == 2 &&
result_smc.data_type == to_uint32(DATA_TYPE_SP78)) {
return 0.0;
}
return (double)result_smc.data[0];
}