From 90200dfec13f22e03b6a5572c51b8ba63c0c5bb0 Mon Sep 17 00:00:00 2001 From: Bryan Varner Date: Thu, 2 Mar 2006 05:26:09 +0000 Subject: [PATCH] * added the beginnings of an acpi_thermal driver. * currently should detect thermal zones and allow interrogation of their current and critical (possibly HOT) temps. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16562 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/drivers/power/Jamfile | 3 +- .../drivers/power/acpi_ns_dump/acpi_ns_dump.c | 1 + .../kernel/drivers/power/acpi_thermal/Jamfile | 15 + .../drivers/power/acpi_thermal/acpi_thermal.c | 277 ++++++++++++++++++ .../drivers/power/acpi_thermal/acpi_thermal.h | 43 +++ .../power/acpi_thermal/acpi_thermal_dev.h | 44 +++ 6 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 src/add-ons/kernel/drivers/power/acpi_thermal/Jamfile create mode 100644 src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.c create mode 100644 src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.h create mode 100644 src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal_dev.h diff --git a/src/add-ons/kernel/drivers/power/Jamfile b/src/add-ons/kernel/drivers/power/Jamfile index 8fd0ef4b8b..f070b1c5d2 100644 --- a/src/add-ons/kernel/drivers/power/Jamfile +++ b/src/add-ons/kernel/drivers/power/Jamfile @@ -1,4 +1,5 @@ SubDir HAIKU_TOP src add-ons kernel drivers power ; SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_button ; -SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_ns_dump ; \ No newline at end of file +SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_thermal ; +SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_ns_dump ; diff --git a/src/add-ons/kernel/drivers/power/acpi_ns_dump/acpi_ns_dump.c b/src/add-ons/kernel/drivers/power/acpi_ns_dump/acpi_ns_dump.c index f533f3185d..6d2c1489d5 100644 --- a/src/add-ons/kernel/drivers/power/acpi_ns_dump/acpi_ns_dump.c +++ b/src/add-ons/kernel/drivers/power/acpi_ns_dump/acpi_ns_dump.c @@ -66,6 +66,7 @@ void dump_acpi_namespace(char *root, void *buf, size_t* num_bytes, int indenting sprintf(tabs, "%s|--- ", tabs); depth = sizeof(char) * 5 * indenting + sizeof(char); // index into result where the device name will be. + dprintf("acpi_ns_dump: recursing from %s\n", root); while (acpi->get_next_entry(ACPI_TYPE_ANY, root, result, 255, &counter) == B_OK) { type = acpi->get_object_type(result); sprintf(output, "%s%s", tabs, result + depth); diff --git a/src/add-ons/kernel/drivers/power/acpi_thermal/Jamfile b/src/add-ons/kernel/drivers/power/acpi_thermal/Jamfile new file mode 100644 index 0000000000..8e73357340 --- /dev/null +++ b/src/add-ons/kernel/drivers/power/acpi_thermal/Jamfile @@ -0,0 +1,15 @@ +SubDir HAIKU_TOP src add-ons kernel drivers power acpi_thermal ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +if $(TARGET_PLATFORM) != haiku { + # Needed for . Unfortunately we also get the other headers there, + # that we don't really want. + UsePublicHeaders drivers ; +} + +KernelAddon acpi_thermal : kernel drivers bin : + acpi_thermal.c + ; + +Depends acpi_thermal : acpi ; diff --git a/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.c b/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.c new file mode 100644 index 0000000000..36afe92f9e --- /dev/null +++ b/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.c @@ -0,0 +1,277 @@ +/* ++++++++++ + ACPI Generic Thermal Zone Driver. + Obtains general status of passive devices, monitors / sets critical temperatures + Controls active devices. ++++++ */ +#include "acpi_thermal_dev.h" +#include "acpi_thermal.h" + +acpi_module_info *acpi; + +static thermal_dev *device_list = NULL; +static sem_id dev_list_lock = -1; +static int device_count = 0; + +static char **device_names = NULL; + +/* Enumerates the devices of ACPI_THERMAL_TYPE + * looking for devices with _CRT and _TMP methods. + * Those devices, be they passive or active + * are usefull things to monitor / control. + */ +void enumerate_devices (char* parent) +{ + char result[255]; + void *counter = NULL; + thermal_dev *td = NULL; + + acpi_object_type buf; + size_t bufsize = sizeof(buf); + + while (acpi->get_next_entry(ACPI_TYPE_THERMAL, parent, result, 255, &counter) == B_OK) { + if ((acpi->evaluate_method(result, "_TMP", &buf, bufsize, NULL, 0) == B_OK) && + (acpi->evaluate_method(result, "_CRT", &buf, bufsize, NULL, 0) == B_OK)) + { + td = (thermal_dev *) malloc(sizeof(thermal_dev)); + if (td != NULL) { + td->open = 0; + td->num = device_count; + dprintf("acpi_thermal: Adding thermal device from: %s\n", result); + td->path = malloc(sizeof(char) * strlen(result) + 1); + strcpy(td->path, result); + + acquire_sem(dev_list_lock); + td->next = device_list; + device_list = td; + device_count++; + release_sem(dev_list_lock); + } + } + enumerate_devices(result); + } +} + +void +cleanup_published_names(void) +{ + int i; + + dprintf("acpi_thermal: cleanup_published_names()\n"); + if (device_names) { + for (i = 0; device_names[i]; i++){ + free(device_names[i]); + } + free(device_names); + } +} + +status_t +init_hardware (void) +{ + return B_OK; +} + +status_t +init_driver (void) +{ + if (get_module(B_ACPI_MODULE_NAME, (module_info **)&acpi) < 0) { + dprintf("Failed to get ACPI module\n"); + return B_ERROR; + } + + if ((dev_list_lock = create_sem(1, "dev_list_lock")) < 0) { + put_module(B_ACPI_MODULE_NAME); + return dev_list_lock; + } + + enumerate_devices("\\"); + return B_OK; +} + + +void +uninit_driver (void) +{ + thermal_dev *td; + acquire_sem(dev_list_lock); + td = device_list; + + while (td != NULL) { + device_list = td->next; + device_count--; + + free(td->path); + free(td); + td = device_list; + } + + delete_sem(dev_list_lock); + + put_module(B_ACPI_MODULE_NAME); + + cleanup_published_names(); +} + + +static status_t +acpi_thermal_open (const char *name, uint32 flags, void** cookie) +{ + thermal_dev *td; + int devnum = atoi(name + strlen(basename)); + + acquire_sem(dev_list_lock); + for (td = device_list; td; td = td->next) { + if (td->num == devnum) { + dprintf("acpi_thermal: opening ACPI path %s\n", td->path); + td->open++; + *cookie = td; + + release_sem(dev_list_lock); + return B_OK; + } + } + release_sem(dev_list_lock); + + *cookie = NULL; + return B_ERROR; +} + +static status_t +acpi_thermal_read (void* cookie, off_t position, void *buf, size_t* num_bytes) +{ + acpi_thermal_type therm_info; + if (*num_bytes < 1) + return B_IO_ERROR; + + if (position == 0) { + dprintf("acpi_thermal: read()\n"); + acpi_thermal_control(cookie, drvOpGetThermalType, &therm_info, 0); + sprintf((char *)buf, "ACPI Thermal Device %u\n", therm_info.devnum); + *num_bytes = strlen((char *)buf); + + sprintf((char *)buf + *num_bytes, " Critical Temperature: %lu.%lu K\n", (therm_info.critical_temp / 10), (therm_info.critical_temp % 10)); + *num_bytes = strlen((char *)buf); + + sprintf((char *)buf + *num_bytes, " Current Temperature: %lu.%lu K\n", (therm_info.current_temp / 10), (therm_info.current_temp % 10)); + *num_bytes = strlen((char *)buf); + + if (therm_info.hot_temp > 0) { + sprintf((char *)buf, "Hot Temperature: %lu.%lu K\n", (therm_info.hot_temp / 10), (therm_info.hot_temp % 10)); + *num_bytes = strlen((char *)buf); + } + } else { + *num_bytes = 0; + } + + return B_OK; +} + +static status_t +acpi_thermal_write (void* cookie, off_t position, const void* buffer, size_t* num_bytes) +{ + return B_ERROR; +} + +static status_t +acpi_thermal_control (void* cookie, uint32 op, void* arg, size_t len) +{ + status_t err = B_ERROR; + + thermal_dev *td = (thermal_dev *)cookie; + acpi_thermal_type *att = NULL; + + acpi_object_type buf; + size_t bufsize = sizeof(buf); + + switch (op) { + case drvOpGetThermalType: { + dprintf("acpi_thermal: GetThermalType()\n"); + att = (acpi_thermal_type *)arg; + + att->devnum = td->num; + err = acpi->evaluate_method(td->path, "_CRT", &buf, bufsize, NULL, 0); + att->critical_temp = buf.data.integer; + err = acpi->evaluate_method(td->path, "_TMP", &buf, bufsize, NULL, 0); + att->current_temp = buf.data.integer; + err = acpi->evaluate_method(td->path, "_HOT", &buf, bufsize, NULL, 0); + if (err == B_OK) { + att->hot_temp = buf.data.integer; + } else { + att->hot_temp = 0; + } + dprintf("acpi_thermal: GotBasicTemperatures()\n"); + + // TODO: Fill this out + att->passive_count = 0; + att->passive_package = NULL; + + att->active_count = 0; + att->active_devices = NULL; + + err = B_OK; + break; + } + } + return err; +} + +static status_t +acpi_thermal_close (void* cookie) +{ + return B_OK; +} + +static status_t +acpi_thermal_free (void* cookie) +{ + thermal_dev *td = (thermal_dev *)cookie; + + acquire_sem(dev_list_lock); + td->open--; + release_sem(dev_list_lock); + + return B_OK; +} + +device_hooks acpi_thermal_hooks = { + acpi_thermal_open, /* -> open entry point */ + acpi_thermal_close, /* -> close entry point */ + acpi_thermal_free, /* -> free cookie */ + acpi_thermal_control, /* -> control entry point */ + acpi_thermal_read, /* -> read entry point */ + acpi_thermal_write, /* -> write entry point */ + NULL, NULL, NULL, NULL +}; + +const char** +publish_devices() +{ + thermal_dev *td; + int i; + + dprintf("acpi_thermal: publish_devices()\n"); + + cleanup_published_names(); + + acquire_sem(dev_list_lock); + device_names = (char **) malloc(sizeof(char*) * (device_count + 1)); + if (device_names) { + for (i = 0, td = device_list; td; td = td->next) { + if ((device_names[i] = (char *) malloc(strlen(basename) + 4))) { + sprintf(device_names[i], "%s%d", basename, td->num); + dprintf("acpi_thermal: Publishing \"/dev/%s\"\n", device_names[i]); + i++; + } + } + device_names[i] = NULL; + } + release_sem(dev_list_lock); + + return (const char**) device_names; +} + +device_hooks* +find_device(const char* name) +{ + return &acpi_thermal_hooks; +} diff --git a/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.h b/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.h new file mode 100644 index 0000000000..2fbc7a3d39 --- /dev/null +++ b/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal.h @@ -0,0 +1,43 @@ +/* ++++++++++ + Public interface to the ACPI thermal device driver. ++++++ */ +#ifndef _ACPI_THERMAL_H +#define _ACPI_THERMAL_H + +#include +#include + +enum { /* ioctl op-codes */ + drvOpGetThermalType = B_DEVICE_OP_CODES_END + 10001, +}; + + +typedef struct acpi_thermal_active_object acpi_thermal_active_object; +typedef struct acpi_thermal_type acpi_thermal_type; + +struct acpi_thermal_type { + /* Published thermal device number */ + int devnum; + + /* Required fields for thermal devices */ + uint32 critical_temp; + uint32 current_temp; + + /* Optional HOT temp, S4 sleep threshold */ + uint32 hot_temp; + + /* List of acpi_objects_types assigned to the passive device list */ + uint32 passive_count; + acpi_object_type *passive_package; + + /* List of acpi_thermal_active_objects that can actively manage this thermal device */ + uint32 active_count; + acpi_thermal_active_object *active_devices; +}; + +struct acpi_thermal_active_object { + uint32 threshold_temp; + acpi_object_type *active_package; +}; + +#endif /* _ACPI_THERMAL_H */ \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal_dev.h b/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal_dev.h new file mode 100644 index 0000000000..6d8bfa24df --- /dev/null +++ b/src/add-ons/kernel/drivers/power/acpi_thermal/acpi_thermal_dev.h @@ -0,0 +1,44 @@ +/* ++++++++++ + ACPI Generic Thermal Zone Driver. + Obtains general status of passive devices, monitors / sets critical temperatures + Controls active devices. ++++++ */ +#ifndef _ACPI_THERMAL_DEV_H +#define _ACPI_THERMAL_DEV_H + +#include +#include +#include +#include + +#include +#include + +#include + +/* Base Namespace devices are published to */ +static const char *basename = "power/thermal/"; + +typedef struct thermal_dev thermal_dev; +struct thermal_dev +{ + thermal_dev *next; + + int num; + int open; + char* path; +}; + +/* + * builds the device lsit + */ +void enumerate_devices (char* base); + +/* + * Frees allocated memory to device list entries + */ +void cleanup_published_names (void); + +static status_t acpi_thermal_control (void* cookie, uint32 op, void* arg, size_t len); + +#endif /* _ACPI_THERMAL_DEV_H */