...

Text file src/github.com/shirou/gopsutil/host/smc_darwin.c

Documentation: github.com/shirou/gopsutil/host

     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
    10typedef 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
    21typedef struct {
    22  unsigned char major;
    23  unsigned char minor;
    24  unsigned char build;
    25  unsigned char reserved;
    26  unsigned short release;
    27} SMCVersion;
    28
    29typedef struct {
    30  uint16_t version;
    31  uint16_t length;
    32  uint32_t cpuPLimit;
    33  uint32_t gpuPLimit;
    34  uint32_t memPLimit;
    35} SMCPLimitData;
    36
    37typedef struct {
    38  IOByteCount data_size;
    39  uint32_t data_type;
    40  uint8_t data_attributes;
    41} SMCKeyInfoData;
    42
    43typedef 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
    55typedef enum {
    56  kSMCSuccess = 0,
    57  kSMCError = 1,
    58  kSMCKeyNotFound = 0x84,
    59} kSMC_t;
    60
    61typedef 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
    68static const int SMC_KEY_SIZE = 4; // number of characters in an SMC key.
    69static io_connect_t conn;          // our connection to the SMC.
    70
    71kern_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
    89kern_return_t close_smc(void) { return IOServiceClose(conn); }
    90
    91static 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
   107static 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
   121static 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
   158double 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}

View as plain text