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 <KernelExport.h> 7 #include <Drivers.h> 8 #include <Errors.h> 9 #include <string.h> 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 14 #include <ACPI.h> 15 #include <pnp_devfs.h> 16 #include "acpi_thermal.h" 17 18 #define ACPI_THERMAL_MODULE_NAME "drivers/bin/acpi_thermal/acpi_device_v1" 19 20 /* Base Namespace devices are published to */ 21 #define ACPI_THERMAL_BASENAME "acpi/thermal/%d" 22 23 // name of pnp generator of path ids 24 #define ACPI_THERMAL_PATHID_GENERATOR "acpi_thermal/path_id" 25 26 device_manager_info *gDeviceManager; 27 28 typedef struct acpi_ns_device_info { 29 device_node_handle node; 30 acpi_device_module_info *acpi; 31 acpi_device acpi_cookie; 32 } acpi_thermal_device_info; 33 34 35 status_t acpi_thermal_control(acpi_thermal_device_info* device, uint32 op, void* arg, size_t len); 36 37 38 static status_t 39 acpi_thermal_open(acpi_thermal_device_info *device, uint32 flags, void** cookie) 40 { 41 *cookie = device; 42 return B_OK; 43 } 44 45 46 static status_t 47 acpi_thermal_read(acpi_thermal_device_info* device, off_t position, void *buf, size_t* num_bytes) 48 { 49 acpi_thermal_type therm_info; 50 if (*num_bytes < 1) 51 return B_IO_ERROR; 52 53 if (position == 0) { 54 size_t max_len = *num_bytes; 55 char *str = (char *)buf; 56 dprintf("acpi_thermal: read()\n"); 57 acpi_thermal_control(device, drvOpGetThermalType, &therm_info, 0); 58 59 snprintf(str, max_len, " Critical Temperature: %lu.%lu K\n", 60 (therm_info.critical_temp / 10), (therm_info.critical_temp % 10)); 61 62 max_len -= strlen(str); 63 str += strlen(str); 64 snprintf(str, max_len, " Current Temperature: %lu.%lu K\n", 65 (therm_info.current_temp / 10), (therm_info.current_temp % 10)); 66 67 if (therm_info.hot_temp > 0) { 68 max_len -= strlen(str); 69 str += strlen(str); 70 snprintf(str, max_len, " Hot Temperature: %lu.%lu K\n", 71 (therm_info.hot_temp / 10), (therm_info.hot_temp % 10)); 72 } 73 74 if (therm_info.passive_package) { 75 /* Incomplete. 76 Needs to obtain acpi global lock. 77 acpi_object_type needs Reference entry (with Handle that can be resolved) 78 what you see here is _highly_ unreliable. 79 */ 80 /* if (therm_info.passive_package->data.package.count > 0) { 81 sprintf((char *)buf + *num_bytes, " Passive Devices\n"); 82 *num_bytes = strlen((char *)buf); 83 for (i = 0; i < therm_info.passive_package->data.package.count; i++) { 84 sprintf((char *)buf + *num_bytes, " Processor: %lu\n", therm_info.passive_package->data.package.objects[i].data.processor.cpu_id); 85 *num_bytes = strlen((char *)buf); 86 } 87 } 88 */ 89 free(therm_info.passive_package); 90 } 91 *num_bytes = strlen((char *)buf); 92 } else { 93 *num_bytes = 0; 94 } 95 96 return B_OK; 97 } 98 99 100 static status_t 101 acpi_thermal_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes) 102 { 103 return B_ERROR; 104 } 105 106 107 status_t 108 acpi_thermal_control (acpi_thermal_device_info* device, uint32 op, void* arg, size_t len) 109 { 110 status_t err = B_ERROR; 111 112 acpi_thermal_type *att = NULL; 113 114 size_t bufsize = sizeof(acpi_object_type); 115 acpi_object_type buf; 116 117 switch (op) { 118 case drvOpGetThermalType: { 119 dprintf("acpi_thermal: GetThermalType()\n"); 120 att = (acpi_thermal_type *)arg; 121 122 // Read basic temperature thresholds. 123 err = device->acpi->evaluate_method(device->acpi_cookie, "_CRT", &buf, bufsize, NULL, 0); 124 att->critical_temp = buf.data.integer; 125 err = device->acpi->evaluate_method(device->acpi_cookie, "_TMP", &buf, bufsize, NULL, 0); 126 att->current_temp = buf.data.integer; 127 err = device->acpi->evaluate_method(device->acpi_cookie, "_HOT", &buf, bufsize, NULL, 0); 128 if (err == B_OK) { 129 att->hot_temp = buf.data.integer; 130 } else { 131 att->hot_temp = 0; 132 } 133 dprintf("acpi_thermal: GotBasicTemperatures()\n"); 134 135 // Read Passive Cooling devices 136 att->passive_package = NULL; 137 err = device->acpi->get_object(device->acpi_cookie, "_PSL", &(att->passive_package)); 138 139 att->active_count = 0; 140 att->active_devices = NULL; 141 142 err = B_OK; 143 break; 144 } 145 } 146 return err; 147 } 148 149 150 static status_t 151 acpi_thermal_close (void* cookie) 152 { 153 return B_OK; 154 } 155 156 157 static status_t 158 acpi_thermal_free (void* cookie) 159 { 160 return B_OK; 161 } 162 163 164 static float 165 acpi_thermal_support(device_node_handle parent, bool *_noConnection) 166 { 167 char *bus; 168 uint32 device_type; 169 170 // make sure parent is really the ACPI bus manager 171 if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, false) != B_OK) { 172 dprintf("no bus\n"); 173 return 0.0; 174 } 175 176 if (strcmp(bus, "acpi")) { 177 dprintf("bad bus\n"); 178 goto err; 179 } 180 181 // check whether it's really a thermal Device 182 if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK 183 || device_type != ACPI_TYPE_THERMAL) { 184 dprintf("bad type\n"); 185 goto err; 186 } 187 188 // TODO check there are _CRT and _TMP ? 189 190 free(bus); 191 return 0.6; 192 err: 193 free(bus); 194 return 0.0; 195 } 196 197 198 static status_t 199 acpi_thermal_init_device(device_node_handle node, void *user_cookie, void **cookie) 200 { 201 acpi_thermal_device_info *device; 202 status_t res; 203 204 device = (acpi_thermal_device_info *)calloc(1, sizeof(*device)); 205 if (device == NULL) 206 return B_NO_MEMORY; 207 208 device->node = node; 209 210 // register it everywhere 211 res = gDeviceManager->init_driver(gDeviceManager->get_parent(node), NULL, 212 (driver_module_info **)&device->acpi, (void**) &device->acpi_cookie); 213 if (res != B_OK) 214 goto err; 215 216 *cookie = device; 217 return B_OK; 218 219 err: 220 free(device); 221 return res; 222 } 223 224 225 static status_t 226 acpi_thermal_uninit_device(acpi_thermal_device_info *device) 227 { 228 gDeviceManager->uninit_driver(gDeviceManager->get_parent(device->node)); 229 free(device); 230 231 return B_OK; 232 } 233 234 235 static status_t 236 acpi_thermal_added(device_node_handle node) 237 { 238 int path_id; 239 char name[128]; 240 241 path_id = gDeviceManager->create_id(ACPI_THERMAL_PATHID_GENERATOR); 242 if (path_id < 0) { 243 return B_ERROR; 244 } 245 246 snprintf(name, sizeof(name), ACPI_THERMAL_BASENAME, path_id); 247 { 248 device_attr attrs[] = { 249 { B_DRIVER_MODULE, B_STRING_TYPE, { string: ACPI_THERMAL_MODULE_NAME }}, 250 251 { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "acpi_thermal" }}, 252 // we want devfs on top of us (who wouldn't?) 253 { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }}, 254 255 { PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: ACPI_THERMAL_PATHID_GENERATOR }}, 256 { PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }}, 257 258 // tell which name we want to have in devfs 259 { PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }}, 260 { NULL } 261 }; 262 263 return gDeviceManager->register_device(node, attrs, NULL, &node); 264 } 265 266 } 267 268 269 static status_t 270 std_ops(int32 op, ...) 271 { 272 switch (op) { 273 case B_MODULE_INIT: 274 case B_MODULE_UNINIT: 275 return B_OK; 276 277 default: 278 return B_ERROR; 279 } 280 } 281 282 module_dependency module_dependencies[] = { 283 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager }, 284 {} 285 }; 286 287 288 pnp_devfs_driver_info acpi_thermal_dump_module = { 289 { 290 { 291 ACPI_THERMAL_MODULE_NAME, 292 0, 293 std_ops 294 }, 295 296 acpi_thermal_support, 297 acpi_thermal_added, 298 acpi_thermal_init_device, 299 (status_t (*) (void *))acpi_thermal_uninit_device, 300 NULL 301 }, 302 303 (pnp_device_open_hook) &acpi_thermal_open, 304 acpi_thermal_close, 305 acpi_thermal_free, 306 (device_control_hook) &acpi_thermal_control, 307 308 (device_read_hook) acpi_thermal_read, 309 acpi_thermal_write, 310 311 NULL, 312 NULL, 313 314 NULL, 315 NULL 316 }; 317 318 module_info *modules[] = { 319 (module_info *)&acpi_thermal_dump_module, 320 NULL 321 }; 322