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