github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/system/host/smc_darwin.c (about)

     1  #include <stdio.h>
     2  #include <string.h>
     3  #include "smc_darwin.h"
     4  
     5  #define IOSERVICE_SMC "AppleSMC"
     6  #define IOSERVICE_MODEL "IOPlatformExpertDevice"
     7  
     8  #define DATA_TYPE_SP78 "sp78"
     9  
    10  typedef enum {
    11    kSMCUserClientOpen = 0,
    12    kSMCUserClientClose = 1,
    13    kSMCHandleYPCEvent = 2,
    14    kSMCReadKey = 5,
    15    kSMCWriteKey = 6,
    16    kSMCGetKeyCount = 7,
    17    kSMCGetKeyFromIndex = 8,
    18    kSMCGetKeyInfo = 9,
    19  } selector_t;
    20  
    21  typedef struct {
    22    unsigned char major;
    23    unsigned char minor;
    24    unsigned char build;
    25    unsigned char reserved;
    26    unsigned short release;
    27  } SMCVersion;
    28  
    29  typedef struct {
    30    uint16_t version;
    31    uint16_t length;
    32    uint32_t cpuPLimit;
    33    uint32_t gpuPLimit;
    34    uint32_t memPLimit;
    35  } SMCPLimitData;
    36  
    37  typedef struct {
    38    IOByteCount data_size;
    39    uint32_t data_type;
    40    uint8_t data_attributes;
    41  } SMCKeyInfoData;
    42  
    43  typedef struct {
    44    uint32_t key;
    45    SMCVersion vers;
    46    SMCPLimitData p_limit_data;
    47    SMCKeyInfoData key_info;
    48    uint8_t result;
    49    uint8_t status;
    50    uint8_t data8;
    51    uint32_t data32;
    52    uint8_t bytes[32];
    53  } SMCParamStruct;
    54  
    55  typedef enum {
    56    kSMCSuccess = 0,
    57    kSMCError = 1,
    58    kSMCKeyNotFound = 0x84,
    59  } kSMC_t;
    60  
    61  typedef struct {
    62    uint8_t data[32];
    63    uint32_t data_type;
    64    uint32_t data_size;
    65    kSMC_t kSMC;
    66  } smc_return_t;
    67  
    68  static const int SMC_KEY_SIZE = 4; // number of characters in an SMC key.
    69  static io_connect_t conn;          // our connection to the SMC.
    70  
    71  kern_return_t open_smc(void) {
    72    kern_return_t result;
    73    io_service_t service;
    74  
    75    service = IOServiceGetMatchingService(kIOMasterPortDefault,
    76                                          IOServiceMatching(IOSERVICE_SMC));
    77    if (service == 0) {
    78      // Note: IOServiceMatching documents 0 on failure
    79      printf("ERROR: %s NOT FOUND\n", IOSERVICE_SMC);
    80      return kIOReturnError;
    81    }
    82  
    83    result = IOServiceOpen(service, mach_task_self(), 0, &conn);
    84    IOObjectRelease(service);
    85  
    86    return result;
    87  }
    88  
    89  kern_return_t close_smc(void) { return IOServiceClose(conn); }
    90  
    91  static uint32_t to_uint32(char *key) {
    92    uint32_t ans = 0;
    93    uint32_t shift = 24;
    94  
    95    if (strlen(key) != SMC_KEY_SIZE) {
    96      return 0;
    97    }
    98  
    99    for (int i = 0; i < SMC_KEY_SIZE; i++) {
   100      ans += key[i] << shift;
   101      shift -= 8;
   102    }
   103  
   104    return ans;
   105  }
   106  
   107  static kern_return_t call_smc(SMCParamStruct *input, SMCParamStruct *output) {
   108    kern_return_t result;
   109    size_t input_cnt = sizeof(SMCParamStruct);
   110    size_t output_cnt = sizeof(SMCParamStruct);
   111  
   112    result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent, input, input_cnt,
   113                                       output, &output_cnt);
   114  
   115    if (result != kIOReturnSuccess) {
   116      result = err_get_code(result);
   117    }
   118    return result;
   119  }
   120  
   121  static kern_return_t read_smc(char *key, smc_return_t *result_smc) {
   122    kern_return_t result;
   123    SMCParamStruct input;
   124    SMCParamStruct output;
   125  
   126    memset(&input, 0, sizeof(SMCParamStruct));
   127    memset(&output, 0, sizeof(SMCParamStruct));
   128    memset(result_smc, 0, sizeof(smc_return_t));
   129  
   130    input.key = to_uint32(key);
   131    input.data8 = kSMCGetKeyInfo;
   132  
   133    result = call_smc(&input, &output);
   134    result_smc->kSMC = output.result;
   135  
   136    if (result != kIOReturnSuccess || output.result != kSMCSuccess) {
   137      return result;
   138    }
   139  
   140    result_smc->data_size = output.key_info.data_size;
   141    result_smc->data_type = output.key_info.data_type;
   142  
   143    input.key_info.data_size = output.key_info.data_size;
   144    input.data8 = kSMCReadKey;
   145  
   146    result = call_smc(&input, &output);
   147    result_smc->kSMC = output.result;
   148  
   149    if (result != kIOReturnSuccess || output.result != kSMCSuccess) {
   150      return result;
   151    }
   152  
   153    memcpy(result_smc->data, output.bytes, sizeof(output.bytes));
   154  
   155    return result;
   156  }
   157  
   158  double get_temperature(char *key) {
   159    kern_return_t result;
   160    smc_return_t result_smc;
   161  
   162    result = read_smc(key, &result_smc);
   163  
   164    if (!(result == kIOReturnSuccess) && result_smc.data_size == 2 &&
   165        result_smc.data_type == to_uint32(DATA_TYPE_SP78)) {
   166      return 0.0;
   167    }
   168  
   169    return (double)result_smc.data[0];
   170  }