...
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