1 /* 2 * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. 3 * 4 * Distributed under the terms of the MIT License. 5 * 6 * ACPI Generic Thermal Zone Driver. 7 * Obtains general status of passive devices, monitors / sets critical temperatures 8 * Controls active devices. 9 */ 10 11 #include <KernelExport.h> 12 #include <Drivers.h> 13 #include <Errors.h> 14 #include <string.h> 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 19 #include <ACPI.h> 20 #include "acpi_thermal.h" 21 22 #define ACPI_THERMAL_MODULE_NAME "drivers/power/acpi_thermal/driver_v1" 23 24 #define ACPI_THERMAL_DEVICE_MODULE_NAME "drivers/power/acpi_thermal/device_v1" 25 26 /* Base Namespace devices are published to */ 27 #define ACPI_THERMAL_BASENAME "power/acpi_thermal/%d" 28 29 // name of pnp generator of path ids 30 #define ACPI_THERMAL_PATHID_GENERATOR "acpi_thermal/path_id" 31 32 static device_manager_info* sDeviceManager; 33 34 typedef struct acpi_ns_device_info { 35 device_node* node; 36 acpi_device_module_info* acpi; 37 acpi_device acpi_cookie; 38 } acpi_thermal_device_info; 39 40 41 status_t acpi_thermal_control(void* _cookie, uint32 op, void* arg, size_t len); 42 43 44 static status_t 45 acpi_thermal_open(void* _cookie, const char* path, int flags, void** cookie) 46 { 47 acpi_thermal_device_info* device = (acpi_thermal_device_info*)_cookie; 48 *cookie = device; 49 return B_OK; 50 } 51 52 53 static status_t 54 acpi_thermal_read(void* _cookie, off_t position, void* buf, size_t* num_bytes) 55 { 56 acpi_thermal_device_info* device = (acpi_thermal_device_info*)_cookie; 57 acpi_thermal_type therm_info; 58 59 if (*num_bytes < 1) 60 return B_IO_ERROR; 61 62 if (position == 0) { 63 size_t max_len = *num_bytes; 64 char* str = (char*)buf; 65 acpi_thermal_control(device, drvOpGetThermalType, &therm_info, 0); 66 67 snprintf(str, max_len, " Critical Temperature: %" B_PRIu32 ".%" B_PRIu32 " K\n", 68 (therm_info.critical_temp / 10), (therm_info.critical_temp % 10)); 69 70 max_len -= strlen(str); 71 str += strlen(str); 72 snprintf(str, max_len, " Current Temperature: %" B_PRIu32 ".%" B_PRIu32 " K\n", 73 (therm_info.current_temp / 10), (therm_info.current_temp % 10)); 74 75 if (therm_info.hot_temp > 0) { 76 max_len -= strlen(str); 77 str += strlen(str); 78 snprintf(str, max_len, " Hot Temperature: %" B_PRIu32 ".%" B_PRIu32 " K\n", 79 (therm_info.hot_temp / 10), (therm_info.hot_temp % 10)); 80 } 81 82 if (therm_info.passive_package) { 83 /* Incomplete. 84 Needs to obtain acpi global lock. 85 acpi_object_type needs Reference entry (with Handle that can be resolved) 86 what you see here is _highly_ unreliable. 87 */ 88 /* if (therm_info.passive_package->data.package.count > 0) { 89 sprintf((char *)buf + *num_bytes, " Passive Devices\n"); 90 *num_bytes = strlen((char *)buf); 91 for (i = 0; i < therm_info.passive_package->data.package.count; i++) { 92 sprintf((char *)buf + *num_bytes, " Processor: %lu\n", therm_info.passive_package->data.package.objects[i].data.processor.cpu_id); 93 *num_bytes = strlen((char *)buf); 94 } 95 } 96 */ 97 free(therm_info.passive_package); 98 } 99 *num_bytes = strlen((char*)buf); 100 } else { 101 *num_bytes = 0; 102 } 103 104 return B_OK; 105 } 106 107 108 static status_t 109 acpi_thermal_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 110 { 111 return B_ERROR; 112 } 113 114 115 status_t 116 acpi_thermal_control(void* _cookie, uint32 op, void* arg, size_t len) 117 { 118 acpi_thermal_device_info* device = (acpi_thermal_device_info*)_cookie; 119 status_t err = B_ERROR; 120 121 acpi_thermal_type* att = NULL; 122 123 acpi_object_type object; 124 125 acpi_data buffer; 126 buffer.pointer = &object; 127 buffer.length = sizeof(object); 128 129 switch (op) { 130 case drvOpGetThermalType: { 131 att = (acpi_thermal_type*)arg; 132 133 // Read basic temperature thresholds. 134 err = device->acpi->evaluate_method (device->acpi_cookie, "_CRT", 135 NULL, &buffer); 136 137 att->critical_temp = 138 (err == B_OK && object.object_type == ACPI_TYPE_INTEGER) 139 ? object.integer.integer : 0; 140 141 err = device->acpi->evaluate_method (device->acpi_cookie, "_TMP", 142 NULL, &buffer); 143 144 att->current_temp = 145 (err == B_OK && object.object_type == ACPI_TYPE_INTEGER) 146 ? object.integer.integer : 0; 147 148 err = device->acpi->evaluate_method(device->acpi_cookie, "_HOT", 149 NULL, &buffer); 150 151 att->hot_temp = 152 (err == B_OK && object.object_type == ACPI_TYPE_INTEGER) 153 ? object.integer.integer : 0; 154 155 // Read Passive Cooling devices 156 att->passive_package = NULL; 157 //err = device->acpi->get_object(device->acpi_cookie, "_PSL", &(att->passive_package)); 158 159 att->active_count = 0; 160 att->active_devices = NULL; 161 162 err = B_OK; 163 break; 164 } 165 } 166 return err; 167 } 168 169 170 static status_t 171 acpi_thermal_close (void* cookie) 172 { 173 return B_OK; 174 } 175 176 177 static status_t 178 acpi_thermal_free (void* cookie) 179 { 180 return B_OK; 181 } 182 183 184 // #pragma mark - driver module API 185 186 187 static float 188 acpi_thermal_support(device_node *parent) 189 { 190 const char* bus; 191 uint32 device_type; 192 193 // make sure parent is really the ACPI bus manager 194 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 195 return -1; 196 197 if (strcmp(bus, "acpi")) 198 return 0.0; 199 200 // check whether it's really a thermal Device 201 if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, 202 &device_type, false) != B_OK || device_type != ACPI_TYPE_THERMAL) { 203 return 0.0; 204 } 205 206 // TODO check there are _CRT and _TMP ? 207 208 return 0.6; 209 } 210 211 212 static status_t 213 acpi_thermal_register_device(device_node *node) 214 { 215 device_attr attrs[] = { 216 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI Thermal" }}, 217 { NULL } 218 }; 219 220 return sDeviceManager->register_node(node, ACPI_THERMAL_MODULE_NAME, attrs, 221 NULL, NULL); 222 } 223 224 225 static status_t 226 acpi_thermal_init_driver(device_node* node, void** _driverCookie) 227 { 228 *_driverCookie = node; 229 return B_OK; 230 } 231 232 233 static void 234 acpi_thermal_uninit_driver(void* driverCookie) 235 { 236 } 237 238 239 static status_t 240 acpi_thermal_register_child_devices(void* _cookie) 241 { 242 device_node* node = _cookie; 243 int path_id; 244 char name[128]; 245 246 path_id = sDeviceManager->create_id(ACPI_THERMAL_PATHID_GENERATOR); 247 if (path_id < 0) { 248 dprintf("acpi_thermal_register_child_devices: couldn't create a path_id\n"); 249 return B_ERROR; 250 } 251 252 snprintf(name, sizeof(name), ACPI_THERMAL_BASENAME, path_id); 253 254 return sDeviceManager->publish_device(node, name, 255 ACPI_THERMAL_DEVICE_MODULE_NAME); 256 } 257 258 259 static status_t 260 acpi_thermal_init_device(void* _cookie, void** cookie) 261 { 262 device_node* node = (device_node*)_cookie; 263 acpi_thermal_device_info* device; 264 device_node* parent; 265 266 device = (acpi_thermal_device_info*)calloc(1, sizeof(*device)); 267 if (device == NULL) 268 return B_NO_MEMORY; 269 270 device->node = node; 271 272 parent = sDeviceManager->get_parent_node(node); 273 sDeviceManager->get_driver(parent, (driver_module_info**)&device->acpi, 274 (void**)&device->acpi_cookie); 275 sDeviceManager->put_node(parent); 276 277 *cookie = device; 278 return B_OK; 279 } 280 281 282 static void 283 acpi_thermal_uninit_device(void* _cookie) 284 { 285 acpi_thermal_device_info* device = (acpi_thermal_device_info*)_cookie; 286 free(device); 287 } 288 289 290 291 module_dependency module_dependencies[] = { 292 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager }, 293 {} 294 }; 295 296 297 driver_module_info acpi_thermal_driver_module = { 298 { 299 ACPI_THERMAL_MODULE_NAME, 300 0, 301 NULL 302 }, 303 304 acpi_thermal_support, 305 acpi_thermal_register_device, 306 acpi_thermal_init_driver, 307 acpi_thermal_uninit_driver, 308 acpi_thermal_register_child_devices, 309 NULL, // rescan 310 NULL, // removed 311 }; 312 313 314 struct device_module_info acpi_thermal_device_module = { 315 { 316 ACPI_THERMAL_DEVICE_MODULE_NAME, 317 0, 318 NULL 319 }, 320 321 acpi_thermal_init_device, 322 acpi_thermal_uninit_device, 323 NULL, 324 325 acpi_thermal_open, 326 acpi_thermal_close, 327 acpi_thermal_free, 328 acpi_thermal_read, 329 acpi_thermal_write, 330 NULL, 331 acpi_thermal_control, 332 333 NULL, 334 NULL 335 }; 336 337 module_info* modules[] = { 338 (module_info*)&acpi_thermal_driver_module, 339 (module_info*)&acpi_thermal_device_module, 340 NULL 341 }; 342