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 if (*num_bytes < 1) 59 return B_IO_ERROR; 60 61 if (position == 0) { 62 size_t max_len = *num_bytes; 63 char *str = (char *)buf; 64 dprintf("acpi_thermal: read()\n"); 65 acpi_thermal_control(device, drvOpGetThermalType, &therm_info, 0); 66 67 snprintf(str, max_len, " Critical Temperature: %lu.%lu 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: %lu.%lu 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: %lu.%lu 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 uint32 integer; 124 acpi_data buffer; 125 buffer.pointer = &integer; 126 buffer.length = sizeof(integer); 127 128 switch (op) { 129 case drvOpGetThermalType: { 130 dprintf("acpi_thermal: GetThermalType()\n"); 131 att = (acpi_thermal_type *)arg; 132 133 // Read basic temperature thresholds. 134 err = device->acpi->evaluate_method(device->acpi_cookie, "_CRT", NULL, &buffer); 135 att->critical_temp = (err == B_OK) ? integer : 0; 136 err = device->acpi->evaluate_method(device->acpi_cookie, "_TMP", NULL, &buffer); 137 att->current_temp = (err == B_OK) ? integer : 0; 138 err = device->acpi->evaluate_method(device->acpi_cookie, "_HOT", NULL, &buffer); 139 att->hot_temp = (err == B_OK) ? integer : 0; 140 141 dprintf("acpi_thermal: GotBasicTemperatures()\n"); 142 143 // Read Passive Cooling devices 144 att->passive_package = NULL; 145 err = device->acpi->get_object(device->acpi_cookie, "_PSL", &(att->passive_package)); 146 147 att->active_count = 0; 148 att->active_devices = NULL; 149 150 err = B_OK; 151 break; 152 } 153 } 154 return err; 155 } 156 157 158 static status_t 159 acpi_thermal_close (void* cookie) 160 { 161 return B_OK; 162 } 163 164 165 static status_t 166 acpi_thermal_free (void* cookie) 167 { 168 return B_OK; 169 } 170 171 172 // #pragma mark - driver module API 173 174 175 static float 176 acpi_thermal_support(device_node *parent) 177 { 178 const char *bus; 179 uint32 device_type; 180 181 // make sure parent is really the ACPI bus manager 182 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 183 return -1; 184 185 if (strcmp(bus, "acpi")) 186 return 0.0; 187 188 // check whether it's really a thermal Device 189 if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK 190 || device_type != ACPI_TYPE_THERMAL) { 191 return 0.0; 192 } 193 194 // TODO check there are _CRT and _TMP ? 195 196 return 0.6; 197 } 198 199 200 static status_t 201 acpi_thermal_register_device(device_node *node) 202 { 203 device_attr attrs[] = { 204 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI Thermal" }}, 205 { NULL } 206 }; 207 208 return sDeviceManager->register_node(node, ACPI_THERMAL_MODULE_NAME, attrs, NULL, NULL); 209 } 210 211 212 static status_t 213 acpi_thermal_init_driver(device_node *node, void **_driverCookie) 214 { 215 *_driverCookie = node; 216 return B_OK; 217 } 218 219 220 static void 221 acpi_thermal_uninit_driver(void *driverCookie) 222 { 223 } 224 225 226 static status_t 227 acpi_thermal_register_child_devices(void *_cookie) 228 { 229 device_node *node = _cookie; 230 int path_id; 231 char name[128]; 232 233 path_id = sDeviceManager->create_id(ACPI_THERMAL_PATHID_GENERATOR); 234 if (path_id < 0) { 235 dprintf("acpi_thermal_register_child_devices: couldn't create a path_id\n"); 236 return B_ERROR; 237 } 238 239 snprintf(name, sizeof(name), ACPI_THERMAL_BASENAME, path_id); 240 241 return sDeviceManager->publish_device(node, name, ACPI_THERMAL_DEVICE_MODULE_NAME); 242 } 243 244 245 static status_t 246 acpi_thermal_init_device(void *_cookie, void **cookie) 247 { 248 device_node *node = (device_node *)_cookie; 249 acpi_thermal_device_info *device; 250 device_node *parent; 251 252 device = (acpi_thermal_device_info *)calloc(1, sizeof(*device)); 253 if (device == NULL) 254 return B_NO_MEMORY; 255 256 device->node = node; 257 258 parent = sDeviceManager->get_parent_node(node); 259 sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi, 260 (void **)&device->acpi_cookie); 261 sDeviceManager->put_node(parent); 262 263 *cookie = device; 264 return B_OK; 265 } 266 267 268 static void 269 acpi_thermal_uninit_device(void *_cookie) 270 { 271 acpi_thermal_device_info *device = (acpi_thermal_device_info *)_cookie; 272 free(device); 273 } 274 275 276 277 module_dependency module_dependencies[] = { 278 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, 279 {} 280 }; 281 282 283 driver_module_info acpi_thermal_driver_module = { 284 { 285 ACPI_THERMAL_MODULE_NAME, 286 0, 287 NULL 288 }, 289 290 acpi_thermal_support, 291 acpi_thermal_register_device, 292 acpi_thermal_init_driver, 293 acpi_thermal_uninit_driver, 294 acpi_thermal_register_child_devices, 295 NULL, // rescan 296 NULL, // removed 297 }; 298 299 300 struct device_module_info acpi_thermal_device_module = { 301 { 302 ACPI_THERMAL_DEVICE_MODULE_NAME, 303 0, 304 NULL 305 }, 306 307 acpi_thermal_init_device, 308 acpi_thermal_uninit_device, 309 NULL, 310 311 acpi_thermal_open, 312 acpi_thermal_close, 313 acpi_thermal_free, 314 acpi_thermal_read, 315 acpi_thermal_write, 316 NULL, 317 acpi_thermal_control, 318 319 NULL, 320 NULL 321 }; 322 323 module_info *modules[] = { 324 (module_info *)&acpi_thermal_driver_module, 325 (module_info *)&acpi_thermal_device_module, 326 NULL 327 }; 328