* 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
This commit is contained in:
Bryan Varner 2006-03-02 05:26:09 +00:00
parent f19839c230
commit 90200dfec1
6 changed files with 382 additions and 1 deletions

View File

@ -1,4 +1,5 @@
SubDir HAIKU_TOP src add-ons kernel drivers power ; 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_button ;
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_thermal ;
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_ns_dump ; SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_ns_dump ;

View File

@ -66,6 +66,7 @@ void dump_acpi_namespace(char *root, void *buf, size_t* num_bytes, int indenting
sprintf(tabs, "%s|--- ", tabs); sprintf(tabs, "%s|--- ", tabs);
depth = sizeof(char) * 5 * indenting + sizeof(char); // index into result where the device name will be. 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) { while (acpi->get_next_entry(ACPI_TYPE_ANY, root, result, 255, &counter) == B_OK) {
type = acpi->get_object_type(result); type = acpi->get_object_type(result);
sprintf(output, "%s%s", tabs, result + depth); sprintf(output, "%s%s", tabs, result + depth);

View File

@ -0,0 +1,15 @@
SubDir HAIKU_TOP src add-ons kernel drivers power acpi_thermal ;
SetSubDirSupportedPlatformsBeOSCompatible ;
if $(TARGET_PLATFORM) != haiku {
# Needed for <ACPI.h>. 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 ;

View File

@ -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;
}

View File

@ -0,0 +1,43 @@
/* ++++++++++
Public interface to the ACPI thermal device driver.
+++++ */
#ifndef _ACPI_THERMAL_H
#define _ACPI_THERMAL_H
#include <KernelExport.h>
#include <ACPI.h>
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 */

View File

@ -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 <KernelExport.h>
#include <Drivers.h>
#include <Errors.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ACPI.h>
/* 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 */