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