|
|
|
@ -3,167 +3,72 @@
|
|
|
|
|
Obtains general status of passive devices, monitors / sets critical temperatures
|
|
|
|
|
Controls active devices.
|
|
|
|
|
+++++ */
|
|
|
|
|
#include "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>
|
|
|
|
|
#include <pnp_devfs.h>
|
|
|
|
|
#include "acpi_thermal.h"
|
|
|
|
|
|
|
|
|
|
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
|
|
|
|
acpi_module_info *acpi;
|
|
|
|
|
#define ACPI_THERMAL_MODULE_NAME "drivers/bin/acpi_thermal/acpi_device_v1"
|
|
|
|
|
|
|
|
|
|
static thermal_dev *device_list = NULL;
|
|
|
|
|
static sem_id dev_list_lock = -1;
|
|
|
|
|
static int device_count = 0;
|
|
|
|
|
/* Base Namespace devices are published to */
|
|
|
|
|
#define ACPI_THERMAL_BASENAME "acpi/thermal/%d"
|
|
|
|
|
|
|
|
|
|
static char **device_names = NULL;
|
|
|
|
|
// name of pnp generator of path ids
|
|
|
|
|
#define ACPI_THERMAL_PATHID_GENERATOR "acpi_thermal/path_id"
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
device_manager_info *gDeviceManager;
|
|
|
|
|
|
|
|
|
|
typedef struct acpi_ns_device_info {
|
|
|
|
|
device_node_handle node;
|
|
|
|
|
acpi_device_module_info *acpi;
|
|
|
|
|
acpi_device acpi_cookie;
|
|
|
|
|
} acpi_thermal_device_info;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t acpi_thermal_control(acpi_thermal_device_info* device, uint32 op, void* arg, size_t len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_thermal_open(acpi_thermal_device_info *device, uint32 flags, void** cookie)
|
|
|
|
|
{
|
|
|
|
|
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("\\");
|
|
|
|
|
*cookie = device;
|
|
|
|
|
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)
|
|
|
|
|
acpi_thermal_read(acpi_thermal_device_info* device, off_t position, void *buf, size_t* num_bytes)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
acpi_thermal_type therm_info;
|
|
|
|
|
if (*num_bytes < 1)
|
|
|
|
|
return B_IO_ERROR;
|
|
|
|
|
|
|
|
|
|
if (position == 0) {
|
|
|
|
|
size_t max_len = *num_bytes;
|
|
|
|
|
char *str = (char *)buf;
|
|
|
|
|
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",
|
|
|
|
|
acpi_thermal_control(device, drvOpGetThermalType, &therm_info, 0);
|
|
|
|
|
|
|
|
|
|
snprintf(str, max_len, " 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",
|
|
|
|
|
max_len -= strlen(str);
|
|
|
|
|
str += strlen(str);
|
|
|
|
|
snprintf(str, max_len, " 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 + *num_bytes, " Hot Temperature: %lu.%lu K\n",
|
|
|
|
|
max_len -= strlen(str);
|
|
|
|
|
str += strlen(str);
|
|
|
|
|
snprintf(str, max_len, " Hot Temperature: %lu.%lu K\n",
|
|
|
|
|
(therm_info.hot_temp / 10), (therm_info.hot_temp % 10));
|
|
|
|
|
*num_bytes = strlen((char *)buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (therm_info.passive_package) {
|
|
|
|
@ -183,6 +88,7 @@ acpi_thermal_read (void* cookie, off_t position, void *buf, size_t* num_bytes)
|
|
|
|
|
*/
|
|
|
|
|
free(therm_info.passive_package);
|
|
|
|
|
}
|
|
|
|
|
*num_bytes = strlen((char *)buf);
|
|
|
|
|
} else {
|
|
|
|
|
*num_bytes = 0;
|
|
|
|
|
}
|
|
|
|
@ -190,19 +96,19 @@ acpi_thermal_read (void* cookie, off_t position, void *buf, size_t* num_bytes)
|
|
|
|
|
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
|
|
|
|
|
acpi_thermal_control (acpi_thermal_device_info* device, uint32 op, void* arg, size_t len)
|
|
|
|
|
{
|
|
|
|
|
status_t err = B_ERROR;
|
|
|
|
|
|
|
|
|
|
thermal_dev *td = (thermal_dev *)cookie;
|
|
|
|
|
char objname[255];
|
|
|
|
|
acpi_thermal_type *att = NULL;
|
|
|
|
|
|
|
|
|
|
size_t bufsize = sizeof(acpi_object_type);
|
|
|
|
@ -214,12 +120,11 @@ acpi_thermal_control (void* cookie, uint32 op, void* arg, size_t len)
|
|
|
|
|
att = (acpi_thermal_type *)arg;
|
|
|
|
|
|
|
|
|
|
// Read basic temperature thresholds.
|
|
|
|
|
att->devnum = td->num;
|
|
|
|
|
err = acpi->evaluate_method(td->path, "_CRT", &buf, bufsize, NULL, 0);
|
|
|
|
|
err = device->acpi->evaluate_method(device->acpi_cookie, "_CRT", &buf, bufsize, NULL, 0);
|
|
|
|
|
att->critical_temp = buf.data.integer;
|
|
|
|
|
err = acpi->evaluate_method(td->path, "_TMP", &buf, bufsize, NULL, 0);
|
|
|
|
|
err = device->acpi->evaluate_method(device->acpi_cookie, "_TMP", &buf, bufsize, NULL, 0);
|
|
|
|
|
att->current_temp = buf.data.integer;
|
|
|
|
|
err = acpi->evaluate_method(td->path, "_HOT", &buf, bufsize, NULL, 0);
|
|
|
|
|
err = device->acpi->evaluate_method(device->acpi_cookie, "_HOT", &buf, bufsize, NULL, 0);
|
|
|
|
|
if (err == B_OK) {
|
|
|
|
|
att->hot_temp = buf.data.integer;
|
|
|
|
|
} else {
|
|
|
|
@ -229,8 +134,7 @@ acpi_thermal_control (void* cookie, uint32 op, void* arg, size_t len)
|
|
|
|
|
|
|
|
|
|
// Read Passive Cooling devices
|
|
|
|
|
att->passive_package = NULL;
|
|
|
|
|
sprintf(objname, "%s._PSL", td->path);
|
|
|
|
|
err = acpi->get_object(objname, &(att->passive_package));
|
|
|
|
|
err = device->acpi->get_object(device->acpi_cookie, "_PSL", &(att->passive_package));
|
|
|
|
|
|
|
|
|
|
att->active_count = 0;
|
|
|
|
|
att->active_devices = NULL;
|
|
|
|
@ -242,63 +146,176 @@ acpi_thermal_control (void* cookie, uint32 op, void* arg, size_t len)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
static float
|
|
|
|
|
acpi_thermal_support(device_node_handle parent, bool *_noConnection)
|
|
|
|
|
{
|
|
|
|
|
char *bus;
|
|
|
|
|
uint32 device_type;
|
|
|
|
|
|
|
|
|
|
// make sure parent is really the ACPI bus manager
|
|
|
|
|
if (gDeviceManager->get_attr_string(parent, B_DRIVER_BUS, &bus, false) != B_OK) {
|
|
|
|
|
dprintf("no bus\n");
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp(bus, "acpi")) {
|
|
|
|
|
dprintf("bad bus\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check whether it's really a thermal Device
|
|
|
|
|
if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK
|
|
|
|
|
|| device_type != ACPI_TYPE_THERMAL) {
|
|
|
|
|
dprintf("bad type\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO check there are _CRT and _TMP ?
|
|
|
|
|
|
|
|
|
|
free(bus);
|
|
|
|
|
return 0.6;
|
|
|
|
|
err:
|
|
|
|
|
free(bus);
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_thermal_init_device(device_node_handle node, void *user_cookie, void **cookie)
|
|
|
|
|
{
|
|
|
|
|
acpi_thermal_device_info *device;
|
|
|
|
|
status_t res;
|
|
|
|
|
|
|
|
|
|
device = (acpi_thermal_device_info *)calloc(1, sizeof(*device));
|
|
|
|
|
if (device == NULL)
|
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
|
|
device->node = node;
|
|
|
|
|
|
|
|
|
|
// register it everywhere
|
|
|
|
|
res = gDeviceManager->init_driver(gDeviceManager->get_parent(node), NULL,
|
|
|
|
|
(driver_module_info **)&device->acpi, (void**) &device->acpi_cookie);
|
|
|
|
|
if (res != B_OK)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
*cookie = device;
|
|
|
|
|
return B_OK;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
free(device);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_thermal_uninit_device(acpi_thermal_device_info *device)
|
|
|
|
|
{
|
|
|
|
|
gDeviceManager->uninit_driver(gDeviceManager->get_parent(device->node));
|
|
|
|
|
free(device);
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_thermal_added(device_node_handle node)
|
|
|
|
|
{
|
|
|
|
|
int path_id;
|
|
|
|
|
char name[128];
|
|
|
|
|
|
|
|
|
|
path_id = gDeviceManager->create_id(ACPI_THERMAL_PATHID_GENERATOR);
|
|
|
|
|
if (path_id < 0) {
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(name, sizeof(name), ACPI_THERMAL_BASENAME, path_id);
|
|
|
|
|
{
|
|
|
|
|
device_attr attrs[] = {
|
|
|
|
|
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: ACPI_THERMAL_MODULE_NAME }},
|
|
|
|
|
|
|
|
|
|
{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "acpi_thermal" }},
|
|
|
|
|
// we want devfs on top of us (who wouldn't?)
|
|
|
|
|
{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
|
|
|
|
|
|
|
|
|
|
{ PNP_MANAGER_ID_GENERATOR, B_STRING_TYPE, { string: ACPI_THERMAL_PATHID_GENERATOR }},
|
|
|
|
|
{ PNP_MANAGER_AUTO_ID, B_UINT32_TYPE, { ui32: path_id }},
|
|
|
|
|
|
|
|
|
|
// tell which name we want to have in devfs
|
|
|
|
|
{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
|
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return gDeviceManager->register_device(node, attrs, NULL, &node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
std_ops(int32 op, ...)
|
|
|
|
|
{
|
|
|
|
|
switch (op) {
|
|
|
|
|
case B_MODULE_INIT:
|
|
|
|
|
case B_MODULE_UNINIT:
|
|
|
|
|
return B_OK;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module_dependency module_dependencies[] = {
|
|
|
|
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
pnp_devfs_driver_info acpi_thermal_dump_module = {
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
ACPI_THERMAL_MODULE_NAME,
|
|
|
|
|
0,
|
|
|
|
|
std_ops
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
acpi_thermal_support,
|
|
|
|
|
acpi_thermal_added,
|
|
|
|
|
acpi_thermal_init_device,
|
|
|
|
|
(status_t (*) (void *))acpi_thermal_uninit_device,
|
|
|
|
|
NULL
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
(pnp_device_open_hook) &acpi_thermal_open,
|
|
|
|
|
acpi_thermal_close,
|
|
|
|
|
acpi_thermal_free,
|
|
|
|
|
(device_control_hook) &acpi_thermal_control,
|
|
|
|
|
|
|
|
|
|
(device_read_hook) acpi_thermal_read,
|
|
|
|
|
acpi_thermal_write,
|
|
|
|
|
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
|
|
|
|
|
NULL,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
module_info *modules[] = {
|
|
|
|
|
(module_info *)&acpi_thermal_dump_module,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|