1 /* ++++++++++ 2 ACPI Generic Thermal Zone Driver. 3 Obtains general status of passive devices, monitors / sets critical temperatures 4 Controls active devices. 5 +++++ */ 6 #include "acpi_thermal_dev.h" 7 #include "acpi_thermal.h" 8 9 acpi_module_info *acpi; 10 11 static thermal_dev *device_list = NULL; 12 static sem_id dev_list_lock = -1; 13 static int device_count = 0; 14 15 static char **device_names = NULL; 16 17 /* Enumerates the devices of ACPI_THERMAL_TYPE 18 * looking for devices with _CRT and _TMP methods. 19 * Those devices, be they passive or active 20 * are usefull things to monitor / control. 21 */ 22 void enumerate_devices (char* parent) 23 { 24 char result[255]; 25 void *counter = NULL; 26 thermal_dev *td = NULL; 27 28 acpi_object_type buf; 29 size_t bufsize = sizeof(buf); 30 31 while (acpi->get_next_entry(ACPI_TYPE_THERMAL, parent, result, 255, &counter) == B_OK) { 32 if ((acpi->evaluate_method(result, "_TMP", &buf, bufsize, NULL, 0) == B_OK) && 33 (acpi->evaluate_method(result, "_CRT", &buf, bufsize, NULL, 0) == B_OK)) 34 { 35 td = (thermal_dev *) malloc(sizeof(thermal_dev)); 36 if (td != NULL) { 37 td->open = 0; 38 td->num = device_count; 39 40 dprintf("acpi_thermal: Adding thermal device from: %s\n", result); 41 td->path = malloc(sizeof(char) * strlen(result) + 1); 42 strcpy(td->path, result); 43 44 acquire_sem(dev_list_lock); 45 td->next = device_list; 46 device_list = td; 47 device_count++; 48 release_sem(dev_list_lock); 49 } 50 } 51 enumerate_devices(result); 52 } 53 } 54 55 void 56 cleanup_published_names(void) 57 { 58 int i; 59 60 dprintf("acpi_thermal: cleanup_published_names()\n"); 61 if (device_names) { 62 for (i = 0; device_names[i]; i++){ 63 free(device_names[i]); 64 } 65 free(device_names); 66 } 67 } 68 69 status_t 70 init_hardware (void) 71 { 72 return B_OK; 73 } 74 75 status_t 76 init_driver (void) 77 { 78 if (get_module(B_ACPI_MODULE_NAME, (module_info **)&acpi) < 0) { 79 dprintf("Failed to get ACPI module\n"); 80 return B_ERROR; 81 } 82 83 if ((dev_list_lock = create_sem(1, "dev_list_lock")) < 0) { 84 put_module(B_ACPI_MODULE_NAME); 85 return dev_list_lock; 86 } 87 88 enumerate_devices("\\"); 89 return B_OK; 90 } 91 92 93 void 94 uninit_driver (void) 95 { 96 thermal_dev *td; 97 acquire_sem(dev_list_lock); 98 td = device_list; 99 100 while (td != NULL) { 101 device_list = td->next; 102 device_count--; 103 104 free(td->path); 105 free(td); 106 td = device_list; 107 } 108 109 delete_sem(dev_list_lock); 110 111 put_module(B_ACPI_MODULE_NAME); 112 113 cleanup_published_names(); 114 } 115 116 117 static status_t 118 acpi_thermal_open (const char *name, uint32 flags, void** cookie) 119 { 120 thermal_dev *td; 121 int devnum = atoi(name + strlen(basename)); 122 123 acquire_sem(dev_list_lock); 124 for (td = device_list; td; td = td->next) { 125 if (td->num == devnum) { 126 dprintf("acpi_thermal: opening ACPI path %s\n", td->path); 127 td->open++; 128 *cookie = td; 129 130 release_sem(dev_list_lock); 131 return B_OK; 132 } 133 } 134 release_sem(dev_list_lock); 135 136 *cookie = NULL; 137 return B_ERROR; 138 } 139 140 static status_t 141 acpi_thermal_read (void* cookie, off_t position, void *buf, size_t* num_bytes) 142 { 143 int i; 144 acpi_thermal_type therm_info; 145 if (*num_bytes < 1) 146 return B_IO_ERROR; 147 148 if (position == 0) { 149 dprintf("acpi_thermal: read()\n"); 150 acpi_thermal_control(cookie, drvOpGetThermalType, &therm_info, 0); 151 sprintf((char *)buf, "ACPI Thermal Device %u\n", therm_info.devnum); 152 *num_bytes = strlen((char *)buf); 153 154 sprintf((char *)buf + *num_bytes, " Critical Temperature: %lu.%lu K\n", 155 (therm_info.critical_temp / 10), (therm_info.critical_temp % 10)); 156 *num_bytes = strlen((char *)buf); 157 158 sprintf((char *)buf + *num_bytes, " Current Temperature: %lu.%lu K\n", 159 (therm_info.current_temp / 10), (therm_info.current_temp % 10)); 160 *num_bytes = strlen((char *)buf); 161 162 if (therm_info.hot_temp > 0) { 163 sprintf((char *)buf + *num_bytes, " Hot Temperature: %lu.%lu K\n", 164 (therm_info.hot_temp / 10), (therm_info.hot_temp % 10)); 165 *num_bytes = strlen((char *)buf); 166 } 167 168 if (therm_info.passive_package) { 169 /* Incomplete. 170 Needs to obtain acpi global lock. 171 acpi_object_type needs Reference entry (with Handle that can be resolved) 172 what you see here is _highly_ unreliable. 173 */ 174 /* if (therm_info.passive_package->data.package.count > 0) { 175 sprintf((char *)buf + *num_bytes, " Passive Devices\n"); 176 *num_bytes = strlen((char *)buf); 177 for (i = 0; i < therm_info.passive_package->data.package.count; i++) { 178 sprintf((char *)buf + *num_bytes, " Processor: %lu\n", therm_info.passive_package->data.package.objects[i].data.processor.cpu_id); 179 *num_bytes = strlen((char *)buf); 180 } 181 } 182 */ 183 free(therm_info.passive_package); 184 } 185 } else { 186 *num_bytes = 0; 187 } 188 189 return B_OK; 190 } 191 192 static status_t 193 acpi_thermal_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes) 194 { 195 return B_ERROR; 196 } 197 198 static status_t 199 acpi_thermal_control (void* cookie, uint32 op, void* arg, size_t len) 200 { 201 status_t err = B_ERROR; 202 203 thermal_dev *td = (thermal_dev *)cookie; 204 char objname[255]; 205 acpi_thermal_type *att = NULL; 206 207 size_t bufsize = sizeof(acpi_object_type); 208 acpi_object_type buf; 209 210 switch (op) { 211 case drvOpGetThermalType: { 212 dprintf("acpi_thermal: GetThermalType()\n"); 213 att = (acpi_thermal_type *)arg; 214 215 // Read basic temperature thresholds. 216 att->devnum = td->num; 217 err = acpi->evaluate_method(td->path, "_CRT", &buf, bufsize, NULL, 0); 218 att->critical_temp = buf.data.integer; 219 err = acpi->evaluate_method(td->path, "_TMP", &buf, bufsize, NULL, 0); 220 att->current_temp = buf.data.integer; 221 err = acpi->evaluate_method(td->path, "_HOT", &buf, bufsize, NULL, 0); 222 if (err == B_OK) { 223 att->hot_temp = buf.data.integer; 224 } else { 225 att->hot_temp = 0; 226 } 227 dprintf("acpi_thermal: GotBasicTemperatures()\n"); 228 229 // Read Passive Cooling devices 230 att->passive_package = NULL; 231 sprintf(objname, "%s._PSL", td->path); 232 err = acpi->get_object(objname, &(att->passive_package)); 233 234 att->active_count = 0; 235 att->active_devices = NULL; 236 237 err = B_OK; 238 break; 239 } 240 } 241 return err; 242 } 243 244 static status_t 245 acpi_thermal_close (void* cookie) 246 { 247 return B_OK; 248 } 249 250 static status_t 251 acpi_thermal_free (void* cookie) 252 { 253 thermal_dev *td = (thermal_dev *)cookie; 254 255 acquire_sem(dev_list_lock); 256 td->open--; 257 release_sem(dev_list_lock); 258 259 return B_OK; 260 } 261 262 device_hooks acpi_thermal_hooks = { 263 acpi_thermal_open, /* -> open entry point */ 264 acpi_thermal_close, /* -> close entry point */ 265 acpi_thermal_free, /* -> free cookie */ 266 acpi_thermal_control, /* -> control entry point */ 267 acpi_thermal_read, /* -> read entry point */ 268 acpi_thermal_write, /* -> write entry point */ 269 NULL, NULL, NULL, NULL 270 }; 271 272 const char** 273 publish_devices() 274 { 275 thermal_dev *td; 276 int i; 277 278 dprintf("acpi_thermal: publish_devices()\n"); 279 280 cleanup_published_names(); 281 282 acquire_sem(dev_list_lock); 283 device_names = (char **) malloc(sizeof(char*) * (device_count + 1)); 284 if (device_names) { 285 for (i = 0, td = device_list; td; td = td->next) { 286 if ((device_names[i] = (char *) malloc(strlen(basename) + 4))) { 287 sprintf(device_names[i], "%s%d", basename, td->num); 288 dprintf("acpi_thermal: Publishing \"/dev/%s\"\n", device_names[i]); 289 i++; 290 } 291 } 292 device_names[i] = NULL; 293 } 294 release_sem(dev_list_lock); 295 296 return (const char**) device_names; 297 } 298 299 device_hooks* 300 find_device(const char* name) 301 { 302 return &acpi_thermal_hooks; 303 } 304