Work in progress of the battery driver.
TODO: - Move watching stuff from driver to device cookie so it can be used by multiple instances. - Find out why we only get notified about AC / battery changes. - Fetch _BMD info. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31483 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
8c042be3d7
commit
34fc10ad1f
@ -1,5 +1,6 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers power ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_battery ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_button ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_embedded_controller ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_lid ;
|
||||
|
9
src/add-ons/kernel/drivers/power/acpi_battery/Jamfile
Normal file
9
src/add-ons/kernel/drivers/power/acpi_battery/Jamfile
Normal file
@ -0,0 +1,9 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers power acpi_battery ;
|
||||
|
||||
UsePrivateHeaders kernel ;
|
||||
|
||||
KernelAddon acpi_battery :
|
||||
acpi_battery.cpp
|
||||
;
|
||||
|
||||
Depends acpi_battery : acpi ;
|
518
src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.cpp
Normal file
518
src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.cpp
Normal file
@ -0,0 +1,518 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Clemens Zeidler, haiku@clemens-zeidler.de
|
||||
*/
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <Drivers.h>
|
||||
#include <Errors.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <kernel/arch/x86/arch_cpu.h>
|
||||
|
||||
#include <ACPI.h>
|
||||
#include "acpi_battery.h"
|
||||
#include <condition_variable.h>
|
||||
|
||||
#define ACPI_BATTERY_DRIVER_NAME "drivers/power/acpi_battery/driver_v1"
|
||||
#define ACPI_BATTERY_DEVICE_NAME "drivers/power/acpi_battery/device_v1"
|
||||
|
||||
/* Base Namespace devices are published to */
|
||||
#define ACPI_BATTERY_BASENAME "power/acpi_battery/%d"
|
||||
|
||||
// name of pnp generator of path ids
|
||||
#define ACPI_BATTERY_PATHID_GENERATOR "acpi_battery/path_id"
|
||||
|
||||
static device_manager_info *sDeviceManager;
|
||||
static ConditionVariable sBatteryCondition;
|
||||
|
||||
|
||||
status_t ReadBatteryStatus(acpi_battery_cookie* cookie,
|
||||
acpi_battery_info* status);
|
||||
|
||||
int32 acpi_battery_handler(void *data);
|
||||
|
||||
int32
|
||||
acpi_battery_handler(void *data)
|
||||
{
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReadBatteryStatus(acpi_battery_cookie* cookie, acpi_battery_info* batteryStatus)
|
||||
{
|
||||
status_t status = B_ERROR;
|
||||
|
||||
acpi_data buffer;
|
||||
buffer.pointer = NULL;
|
||||
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
|
||||
acpi_object_type* object;
|
||||
acpi_object_type* pointer;
|
||||
|
||||
status = cookie->acpi->evaluate_method(cookie->acpi_cookie, "_BST", NULL,
|
||||
&buffer);
|
||||
if (status != B_OK)
|
||||
goto exit;
|
||||
|
||||
object = (acpi_object_type*)buffer.pointer;
|
||||
|
||||
pointer = object->data.package.objects;
|
||||
|
||||
batteryStatus->state = pointer->data.integer;
|
||||
pointer++;
|
||||
batteryStatus->current_rate = pointer->data.integer;
|
||||
pointer++;
|
||||
batteryStatus->capacity = pointer->data.integer;
|
||||
pointer++;
|
||||
batteryStatus->voltage = pointer->data.integer;
|
||||
|
||||
exit:
|
||||
free(buffer.pointer);
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t
|
||||
ReadBatteryInfo(acpi_battery_cookie* cookie,
|
||||
acpi_extended_battery_info* batteryInfo)
|
||||
{
|
||||
status_t status = B_ERROR;
|
||||
|
||||
acpi_data buffer;
|
||||
buffer.pointer = NULL;
|
||||
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
|
||||
acpi_object_type* object;
|
||||
acpi_object_type* pointer;
|
||||
|
||||
status = cookie->acpi->evaluate_method(cookie->acpi_cookie, "_BIF", NULL,
|
||||
&buffer);
|
||||
if (status != B_OK)
|
||||
goto exit;
|
||||
|
||||
object = (acpi_object_type*)buffer.pointer;
|
||||
if (object->object_type != ACPI_TYPE_PACKAGE ||
|
||||
object->data.package.count < 13)
|
||||
goto exit;
|
||||
|
||||
pointer = object->data.package.objects;
|
||||
|
||||
batteryInfo->power_unit = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->design_capacity = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->last_full_charge = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->technology = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->design_voltage = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->design_capacity_warning = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->design_capacity_low = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->capacity_granularity_1 = pointer->data.integer;
|
||||
pointer ++;
|
||||
batteryInfo->capacity_granularity_2 = pointer->data.integer;
|
||||
pointer ++;
|
||||
strcpy(batteryInfo->model_number, pointer->data.string.string);
|
||||
pointer ++;
|
||||
strcpy(batteryInfo->serial_number, pointer->data.string.string);
|
||||
pointer ++;
|
||||
strcpy(batteryInfo->type, pointer->data.string.string);
|
||||
pointer ++;
|
||||
strcpy(batteryInfo->oem_info, pointer->data.string.string);
|
||||
|
||||
exit:
|
||||
free(buffer.pointer);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
EstimatedRuntime(acpi_battery_cookie* cookie, acpi_battery_info* info)
|
||||
{
|
||||
status_t status = B_ERROR;
|
||||
|
||||
acpi_object_type argument;
|
||||
argument.object_type = ACPI_TYPE_INTEGER;
|
||||
argument.data.integer = info->current_rate;
|
||||
|
||||
acpi_objects arguments;
|
||||
arguments.count = 1;
|
||||
arguments.pointer = &argument;
|
||||
|
||||
acpi_object_type object;
|
||||
|
||||
acpi_data buffer;
|
||||
buffer.pointer = &object;
|
||||
buffer.length = sizeof(object);
|
||||
|
||||
acpi_object_type* returnObject;
|
||||
|
||||
status = cookie->acpi->evaluate_method(cookie->acpi_cookie, "_BTM",
|
||||
&arguments, &buffer);
|
||||
if (status != B_OK)
|
||||
return -1;
|
||||
|
||||
returnObject = (acpi_object_type*)buffer.pointer;
|
||||
|
||||
if (returnObject->object_type != ACPI_TYPE_INTEGER)
|
||||
return -1;
|
||||
|
||||
int result = returnObject->data.integer;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
battery_notify_handler(acpi_handle device, uint32 value, void *context)
|
||||
{
|
||||
TRACE("battery_notify_handler\n");
|
||||
sBatteryCondition.NotifyAll();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TraceBatteryInfo(acpi_extended_battery_info* batteryInfo)
|
||||
{
|
||||
TRACE("BIF power unit %i\n", batteryInfo->power_unit);
|
||||
TRACE("BIF design capacity %i\n", batteryInfo->design_capacity);
|
||||
TRACE("BIF last full charge %i\n", batteryInfo->last_full_charge);
|
||||
TRACE("BIF technology %i\n", batteryInfo->technology);
|
||||
TRACE("BIF design voltage %i\n", batteryInfo->design_voltage);
|
||||
TRACE("BIF design capacity warning %i\n", batteryInfo->design_capacity_warning);
|
||||
TRACE("BIF design capacity low %i\n", batteryInfo->design_capacity_low);
|
||||
TRACE("BIF capacity granularity 1 %i\n", batteryInfo->capacity_granularity_1);
|
||||
TRACE("BIF capacity granularity 2 %i\n", batteryInfo->capacity_granularity_2);
|
||||
TRACE("BIF model number %s\n", batteryInfo->model_number);
|
||||
TRACE("BIF serial number %s\n", batteryInfo->serial_number);
|
||||
TRACE("BIF type %s\n", batteryInfo->type);
|
||||
TRACE("BIF oem info %s\n", batteryInfo->oem_info);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_open(void *initCookie, const char *path, int flags, void** cookie)
|
||||
{
|
||||
acpi_battery_cookie *device = (acpi_battery_cookie*)initCookie;
|
||||
*cookie = device;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_close(void* cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_read(void* _cookie, off_t position, void *buffer, size_t* numBytes)
|
||||
{
|
||||
if (*numBytes < 1)
|
||||
return B_IO_ERROR;
|
||||
|
||||
acpi_battery_cookie *device = (acpi_battery_cookie *)_cookie;
|
||||
|
||||
acpi_battery_info batteryStatus;
|
||||
ReadBatteryStatus(device, &batteryStatus);
|
||||
|
||||
acpi_extended_battery_info batteryInfo;
|
||||
ReadBatteryInfo(device, &batteryInfo);
|
||||
|
||||
if (position == 0) {
|
||||
size_t max_len = *numBytes;
|
||||
char *str = (char *)buffer;
|
||||
|
||||
snprintf(str, max_len, "Battery Status:\n");
|
||||
max_len-= strlen(str);
|
||||
str += strlen(str);
|
||||
|
||||
snprintf(str, max_len, " State %i, Current Rate %i, Capacity %i, "
|
||||
"Voltage %i\n", batteryStatus.state, batteryStatus.current_rate,
|
||||
batteryStatus.capacity, batteryStatus.voltage);
|
||||
max_len-= strlen(str);
|
||||
str += strlen(str);
|
||||
|
||||
snprintf(str, max_len, "\nBattery Info:\n");
|
||||
max_len-= strlen(str);
|
||||
str += strlen(str);
|
||||
|
||||
snprintf(str, max_len, " Power Unit %i, Design Capacity %i, "
|
||||
"Last Full Charge %i, Technology %i\n", batteryInfo.power_unit,
|
||||
batteryInfo.design_capacity, batteryInfo.last_full_charge,
|
||||
batteryInfo.technology);
|
||||
max_len-= strlen(str);
|
||||
str += strlen(str);
|
||||
snprintf(str, max_len, " Design Voltage %i, Design Capacity Warning %i, "
|
||||
"Design Capacity Low %i, Capacity Granularity1 %i, "
|
||||
"Capacity Granularity1 %i\n", batteryInfo.design_voltage,
|
||||
batteryInfo.design_capacity_warning, batteryInfo.design_capacity_low,
|
||||
batteryInfo.capacity_granularity_1, batteryInfo.capacity_granularity_1);
|
||||
max_len-= strlen(str);
|
||||
str += strlen(str);
|
||||
snprintf(str, max_len, " Model Number %s, Serial Number %s, "
|
||||
"Type %s, OEM Info %s\n", batteryInfo.model_number,
|
||||
batteryInfo.serial_number, batteryInfo.type, batteryInfo.oem_info);
|
||||
max_len-= strlen(str);
|
||||
str += strlen(str);
|
||||
|
||||
*numBytes = strlen((char *)buffer);
|
||||
} else
|
||||
*numBytes = 0;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_write(void* cookie, off_t position, const void* buffer, size_t* numBytes)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
acpi_battery_control(void* _cookie, uint32 op, void* arg, size_t len)
|
||||
{
|
||||
TRACE("acpi_battery: acpi_battery_control op %u\n", int(op));
|
||||
acpi_battery_cookie* device = (acpi_battery_cookie*)_cookie;
|
||||
status_t err = B_ERROR;
|
||||
|
||||
uint32* magicId;
|
||||
acpi_battery_info* batteryInfo;
|
||||
acpi_extended_battery_info* extBatteryInfo;
|
||||
switch (op) {
|
||||
case IDENTIFY_DEVICE:
|
||||
if (len < sizeof(uint32))
|
||||
return B_IO_ERROR;
|
||||
magicId = (uint32*)arg;
|
||||
*magicId = kMagicACPIBatteryID;
|
||||
err = B_OK;
|
||||
break;
|
||||
|
||||
case GET_BATTERY_INFO:
|
||||
if (len < sizeof(acpi_battery_info))
|
||||
return B_IO_ERROR;
|
||||
batteryInfo = (acpi_battery_info*)arg;
|
||||
err = ReadBatteryStatus(device, batteryInfo);
|
||||
break;
|
||||
|
||||
case GET_EXTENDED_BATTERY_INFO:
|
||||
if (len < sizeof(acpi_extended_battery_info))
|
||||
return B_IO_ERROR;
|
||||
extBatteryInfo = (acpi_extended_battery_info*)arg;
|
||||
err = ReadBatteryInfo(device, extBatteryInfo);
|
||||
break;
|
||||
|
||||
case WATCH_BATTERY:
|
||||
sBatteryCondition.Wait();
|
||||
if (atomic_get(&(device->stop_watching))) {
|
||||
atomic_set(&(device->stop_watching), 0);
|
||||
err = B_ERROR;
|
||||
} else
|
||||
err = B_OK;
|
||||
break;
|
||||
|
||||
case STOP_WATCHING_BATTERY:
|
||||
atomic_set(&(device->stop_watching), 1);
|
||||
sBatteryCondition.NotifyAll();
|
||||
err = B_OK;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_free(void* cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - driver module API
|
||||
|
||||
|
||||
static float
|
||||
acpi_battery_support(device_node *parent)
|
||||
{
|
||||
// make sure parent is really the ACPI bus manager
|
||||
const char *bus;
|
||||
uint32 device_type;
|
||||
const char *name;
|
||||
|
||||
if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
|
||||
return -1;
|
||||
|
||||
if (strcmp(bus, "acpi"))
|
||||
return 0.0;
|
||||
|
||||
// check whether it's really a device
|
||||
if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
|
||||
&device_type, false) != B_OK
|
||||
|| device_type != ACPI_TYPE_DEVICE) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// check whether it's a battery device
|
||||
if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
|
||||
false) != B_OK || strcmp(name, ACPI_NAME_BATTERY))
|
||||
return 0.0;
|
||||
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_register_device(device_node *node)
|
||||
{
|
||||
device_attr attrs[] = {
|
||||
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
|
||||
{ string: "ACPI Battery" }},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return sDeviceManager->register_node(node, ACPI_BATTERY_DRIVER_NAME, attrs,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_init_driver(device_node *node, void **driverCookie)
|
||||
{
|
||||
acpi_battery_cookie *device;
|
||||
device = (acpi_battery_cookie *)calloc(1, sizeof(acpi_battery_cookie));
|
||||
if (device == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
*driverCookie = device;
|
||||
|
||||
device->node = node;
|
||||
device->stop_watching = 0;
|
||||
|
||||
device_node *parent;
|
||||
parent = sDeviceManager->get_parent_node(node);
|
||||
sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
|
||||
(void **)&device->acpi_cookie);
|
||||
sDeviceManager->put_node(parent);
|
||||
|
||||
// install notify handler
|
||||
device->acpi->install_notify_handler(device->acpi_cookie,
|
||||
ACPI_ALL_NOTIFY, battery_notify_handler, NULL);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
acpi_battery_uninit_driver(void *driverCookie)
|
||||
{
|
||||
TRACE("acpi_battery_uninit_driver\n");
|
||||
acpi_battery_cookie *device = (acpi_battery_cookie*)driverCookie;
|
||||
|
||||
device->acpi->remove_notify_handler(device->acpi_cookie,
|
||||
ACPI_ALL_NOTIFY, battery_notify_handler);
|
||||
|
||||
free(device);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_register_child_devices(void *cookie)
|
||||
{
|
||||
acpi_battery_cookie *device = (acpi_battery_cookie*)cookie;
|
||||
|
||||
int pathID = sDeviceManager->create_id(ACPI_BATTERY_PATHID_GENERATOR);
|
||||
if (pathID < 0) {
|
||||
TRACE("register_child_devices: couldn't create a path_id\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
char name[128];
|
||||
snprintf(name, sizeof(name), ACPI_BATTERY_BASENAME, pathID);
|
||||
|
||||
return sDeviceManager->publish_device(device->node, name,
|
||||
ACPI_BATTERY_DEVICE_NAME);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
acpi_battery_init_device(void *driverCookie, void **cookie)
|
||||
{
|
||||
*cookie = driverCookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
acpi_battery_uninit_device(void *_cookie)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
driver_module_info acpi_battery_driver_module = {
|
||||
{
|
||||
ACPI_BATTERY_DRIVER_NAME,
|
||||
0,
|
||||
NULL
|
||||
},
|
||||
|
||||
acpi_battery_support,
|
||||
acpi_battery_register_device,
|
||||
acpi_battery_init_driver,
|
||||
acpi_battery_uninit_driver,
|
||||
acpi_battery_register_child_devices,
|
||||
NULL, // rescan
|
||||
NULL, // removed
|
||||
};
|
||||
|
||||
|
||||
struct device_module_info acpi_battery_device_module = {
|
||||
{
|
||||
ACPI_BATTERY_DEVICE_NAME,
|
||||
0,
|
||||
NULL
|
||||
},
|
||||
|
||||
acpi_battery_init_device,
|
||||
acpi_battery_uninit_device,
|
||||
NULL,
|
||||
|
||||
acpi_battery_open,
|
||||
acpi_battery_close,
|
||||
acpi_battery_free,
|
||||
acpi_battery_read,
|
||||
acpi_battery_write,
|
||||
NULL,
|
||||
acpi_battery_control,
|
||||
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
module_info *modules[] = {
|
||||
(module_info *)&acpi_battery_driver_module,
|
||||
(module_info *)&acpi_battery_device_module,
|
||||
NULL
|
||||
};
|
48
src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.h
Normal file
48
src/add-ons/kernel/drivers/power/acpi_battery/acpi_battery.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2009, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Clemens Zeidler, haiku@clemens-zeidler.de
|
||||
*/
|
||||
|
||||
#ifndef ACPI_BATTERY_H
|
||||
#define ACPI_BATTERY_H
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <ACPI.h>
|
||||
|
||||
#include "device/power_managment.h"
|
||||
|
||||
#define TRACE_BATTERY
|
||||
#ifdef TRACE_BATTERY
|
||||
# define TRACE(x...) dprintf("acpi_battery: "x)
|
||||
#else
|
||||
# define TRACE(x...)
|
||||
#endif
|
||||
|
||||
|
||||
#define ACPI_NAME_BATTERY "PNP0C0A"
|
||||
|
||||
|
||||
struct acpi_battery_cookie {
|
||||
// this three variables are not needed yet but helpfull when extend this
|
||||
// driver to use acpi
|
||||
device_node *node;
|
||||
acpi_device_module_info *acpi;
|
||||
acpi_device acpi_cookie;
|
||||
|
||||
vint32 stop_watching;
|
||||
};
|
||||
|
||||
/* Notify types */
|
||||
|
||||
#define ACPI_SYSTEM_NOTIFY 0x1
|
||||
#define ACPI_DEVICE_NOTIFY 0x2
|
||||
#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
|
||||
#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3
|
||||
#define ACPI_MAX_SYS_NOTIFY 0x7f
|
||||
|
||||
void battery_notify_handler(acpi_handle device, uint32 value, void *context);
|
||||
|
||||
#endif /* _EST_H */
|
Loading…
Reference in New Issue
Block a user