|
|
|
@@ -0,0 +1,370 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright 2020, Jérôme Duval, [email protected].
|
|
|
|
|
* Distributed under the terms of the MIT license.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <ACPI.h>
|
|
|
|
|
#include <condition_variable.h>
|
|
|
|
|
#include <Drivers.h>
|
|
|
|
|
#include <Errors.h>
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <kernel.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
# include "acpi.h"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct als_driver_cookie {
|
|
|
|
|
device_node* node;
|
|
|
|
|
acpi_device_module_info* acpi;
|
|
|
|
|
acpi_device acpi_cookie;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct als_device_cookie {
|
|
|
|
|
als_driver_cookie* driver_cookie;
|
|
|
|
|
int32 stop_watching;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define ACPI_ALS_DRIVER_NAME "drivers/sensor/acpi_als/driver_v1"
|
|
|
|
|
#define ACPI_ALS_DEVICE_NAME "drivers/sensor/acpi_als/device_v1"
|
|
|
|
|
|
|
|
|
|
/* Base Namespace devices are published to */
|
|
|
|
|
#define ACPI_ALS_BASENAME "sensor/acpi_als/%d"
|
|
|
|
|
|
|
|
|
|
// name of pnp generator of path ids
|
|
|
|
|
#define ACPI_ALS_PATHID_GENERATOR "acpi_als/path_id"
|
|
|
|
|
|
|
|
|
|
#define ACPI_NAME_ALS "ACPI0008"
|
|
|
|
|
|
|
|
|
|
#define TRACE_ALS
|
|
|
|
|
#ifdef TRACE_ALS
|
|
|
|
|
# define TRACE(x...) dprintf("acpi_als: " x)
|
|
|
|
|
#else
|
|
|
|
|
# define TRACE(x...)
|
|
|
|
|
#endif
|
|
|
|
|
#define ERROR(x...) dprintf("acpi_als: " x)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static device_manager_info *sDeviceManager;
|
|
|
|
|
static ConditionVariable sALSCondition;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_GetInteger(als_driver_cookie *device,
|
|
|
|
|
const char* path, uint64* number)
|
|
|
|
|
{
|
|
|
|
|
acpi_data buf;
|
|
|
|
|
acpi_object_type object;
|
|
|
|
|
buf.pointer = &object;
|
|
|
|
|
buf.length = sizeof(acpi_object_type);
|
|
|
|
|
|
|
|
|
|
// Assume that what we've been pointed at is an Integer object, or
|
|
|
|
|
// a method that will return an Integer.
|
|
|
|
|
status_t status = device->acpi->evaluate_method(device->acpi_cookie, path,
|
|
|
|
|
NULL, &buf);
|
|
|
|
|
if (status == B_OK) {
|
|
|
|
|
if (object.object_type == ACPI_TYPE_INTEGER)
|
|
|
|
|
*number = object.integer.integer;
|
|
|
|
|
else
|
|
|
|
|
status = B_BAD_VALUE;
|
|
|
|
|
}
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
als_notify_handler(acpi_handle device, uint32 value, void *context)
|
|
|
|
|
{
|
|
|
|
|
TRACE("als_notify_handler event 0x%" B_PRIx32 "\n", value);
|
|
|
|
|
sALSCondition.NotifyAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - device module API
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_init_device(void *driverCookie, void **cookie)
|
|
|
|
|
{
|
|
|
|
|
*cookie = driverCookie;
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
acpi_als_uninit_device(void *_cookie)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_open(void *initCookie, const char *path, int flags, void** cookie)
|
|
|
|
|
{
|
|
|
|
|
als_device_cookie *device;
|
|
|
|
|
device = (als_device_cookie*)calloc(1, sizeof(als_device_cookie));
|
|
|
|
|
if (device == NULL)
|
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
|
|
device->driver_cookie = (als_driver_cookie*)initCookie;
|
|
|
|
|
device->stop_watching = 0;
|
|
|
|
|
|
|
|
|
|
*cookie = device;
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_close(void* cookie)
|
|
|
|
|
{
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_read(void* _cookie, off_t position, void *buffer, size_t* numBytes)
|
|
|
|
|
{
|
|
|
|
|
if (*numBytes < 1)
|
|
|
|
|
return B_IO_ERROR;
|
|
|
|
|
|
|
|
|
|
als_device_cookie *device = (als_device_cookie*)_cookie;
|
|
|
|
|
|
|
|
|
|
if (position == 0) {
|
|
|
|
|
char string[10];
|
|
|
|
|
uint64 luminance = 0;
|
|
|
|
|
status_t status = acpi_GetInteger(device->driver_cookie,
|
|
|
|
|
"_ALI", &luminance);
|
|
|
|
|
if (status != B_OK)
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
snprintf(string, sizeof(string), "%" B_PRIu64 "\n", luminance);
|
|
|
|
|
size_t max_len = user_strlcpy((char*)buffer, string, *numBytes);
|
|
|
|
|
if (max_len < B_OK)
|
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
*numBytes = max_len;
|
|
|
|
|
} else
|
|
|
|
|
*numBytes = 0;
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_write(void* cookie, off_t position, const void* buffer,
|
|
|
|
|
size_t* numBytes)
|
|
|
|
|
{
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_control(void* _cookie, uint32 op, void* arg, size_t len)
|
|
|
|
|
{
|
|
|
|
|
//als_device_cookie* device = (als_device_cookie*)_cookie;
|
|
|
|
|
|
|
|
|
|
return B_DEV_INVALID_IOCTL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_free(void* cookie)
|
|
|
|
|
{
|
|
|
|
|
als_device_cookie* device = (als_device_cookie*)cookie;
|
|
|
|
|
free(device);
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - driver module API
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static float
|
|
|
|
|
acpi_als_support(device_node *parent)
|
|
|
|
|
{
|
|
|
|
|
// make sure parent is really the ACPI bus manager
|
|
|
|
|
const char *bus;
|
|
|
|
|
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
|
|
|
|
|
uint32 device_type;
|
|
|
|
|
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 als device
|
|
|
|
|
const char *name;
|
|
|
|
|
if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
|
|
|
|
|
false) != B_OK || strcmp(name, ACPI_NAME_ALS)) {
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0.6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_register_device(device_node *node)
|
|
|
|
|
{
|
|
|
|
|
device_attr attrs[] = {
|
|
|
|
|
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI ALS" }},
|
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return sDeviceManager->register_node(node, ACPI_ALS_DRIVER_NAME, attrs,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_init_driver(device_node *node, void **driverCookie)
|
|
|
|
|
{
|
|
|
|
|
als_driver_cookie *device;
|
|
|
|
|
device = (als_driver_cookie *)calloc(1, sizeof(als_driver_cookie));
|
|
|
|
|
if (device == NULL)
|
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
|
|
*driverCookie = device;
|
|
|
|
|
|
|
|
|
|
device->node = node;
|
|
|
|
|
|
|
|
|
|
device_node *parent;
|
|
|
|
|
parent = sDeviceManager->get_parent_node(node);
|
|
|
|
|
sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
|
|
|
|
|
(void **)&device->acpi_cookie);
|
|
|
|
|
|
|
|
|
|
#ifdef TRACE_ALS
|
|
|
|
|
const char* device_path;
|
|
|
|
|
if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_PATH_ITEM,
|
|
|
|
|
&device_path, false) == B_OK) {
|
|
|
|
|
TRACE("acpi_als_init_driver %s\n", device_path);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
sDeviceManager->put_node(parent);
|
|
|
|
|
|
|
|
|
|
uint64 sta;
|
|
|
|
|
status_t status = acpi_GetInteger(device, "_STA", &sta);
|
|
|
|
|
uint64 mask = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED
|
|
|
|
|
| ACPI_STA_DEVICE_FUNCTIONING;
|
|
|
|
|
if (status == B_OK && (sta & mask) != mask) {
|
|
|
|
|
ERROR("acpi_als_init_driver device disabled\n");
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64 luminance;
|
|
|
|
|
status = acpi_GetInteger(device, "_ALI", &luminance);
|
|
|
|
|
if (status != B_OK) {
|
|
|
|
|
ERROR("acpi_als_init_driver error when calling _ALI\n");
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// install notify handler
|
|
|
|
|
device->acpi->install_notify_handler(device->acpi_cookie,
|
|
|
|
|
ACPI_ALL_NOTIFY, als_notify_handler, device);
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
acpi_als_uninit_driver(void *driverCookie)
|
|
|
|
|
{
|
|
|
|
|
TRACE("acpi_als_uninit_driver\n");
|
|
|
|
|
als_driver_cookie *device = (als_driver_cookie*)driverCookie;
|
|
|
|
|
|
|
|
|
|
device->acpi->remove_notify_handler(device->acpi_cookie,
|
|
|
|
|
ACPI_ALL_NOTIFY, als_notify_handler);
|
|
|
|
|
|
|
|
|
|
free(device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static status_t
|
|
|
|
|
acpi_als_register_child_devices(void *cookie)
|
|
|
|
|
{
|
|
|
|
|
als_driver_cookie *device = (als_driver_cookie*)cookie;
|
|
|
|
|
|
|
|
|
|
int pathID = sDeviceManager->create_id(ACPI_ALS_PATHID_GENERATOR);
|
|
|
|
|
if (pathID < 0) {
|
|
|
|
|
ERROR("register_child_devices: couldn't create a path_id\n");
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char name[128];
|
|
|
|
|
snprintf(name, sizeof(name), ACPI_ALS_BASENAME, pathID);
|
|
|
|
|
|
|
|
|
|
return sDeviceManager->publish_device(device->node, name,
|
|
|
|
|
ACPI_ALS_DEVICE_NAME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module_dependency module_dependencies[] = {
|
|
|
|
|
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
driver_module_info acpi_als_driver_module = {
|
|
|
|
|
{
|
|
|
|
|
ACPI_ALS_DRIVER_NAME,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
acpi_als_support,
|
|
|
|
|
acpi_als_register_device,
|
|
|
|
|
acpi_als_init_driver,
|
|
|
|
|
acpi_als_uninit_driver,
|
|
|
|
|
acpi_als_register_child_devices,
|
|
|
|
|
NULL, // rescan
|
|
|
|
|
NULL, // removed
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct device_module_info acpi_als_device_module = {
|
|
|
|
|
{
|
|
|
|
|
ACPI_ALS_DEVICE_NAME,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
acpi_als_init_device,
|
|
|
|
|
acpi_als_uninit_device,
|
|
|
|
|
NULL,
|
|
|
|
|
|
|
|
|
|
acpi_als_open,
|
|
|
|
|
acpi_als_close,
|
|
|
|
|
acpi_als_free,
|
|
|
|
|
acpi_als_read,
|
|
|
|
|
acpi_als_write,
|
|
|
|
|
NULL,
|
|
|
|
|
acpi_als_control,
|
|
|
|
|
|
|
|
|
|
NULL,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
module_info *modules[] = {
|
|
|
|
|
(module_info *)&acpi_als_driver_module,
|
|
|
|
|
(module_info *)&acpi_als_device_module,
|
|
|
|
|
NULL
|
|
|
|
|
};
|