diff --git a/src/add-ons/kernel/drivers/Jamfile b/src/add-ons/kernel/drivers/Jamfile index 7bbda5d0ea..96d31f5013 100644 --- a/src/add-ons/kernel/drivers/Jamfile +++ b/src/add-ons/kernel/drivers/Jamfile @@ -15,6 +15,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers misc ; SubInclude HAIKU_TOP src add-ons kernel drivers network ; SubInclude HAIKU_TOP src add-ons kernel drivers ports ; SubInclude HAIKU_TOP src add-ons kernel drivers power ; +SubInclude HAIKU_TOP src add-ons kernel drivers sensor ; SubInclude HAIKU_TOP src add-ons kernel drivers timer ; SubInclude HAIKU_TOP src add-ons kernel drivers tty ; SubInclude HAIKU_TOP src add-ons kernel drivers video ; diff --git a/src/add-ons/kernel/drivers/sensor/Jamfile b/src/add-ons/kernel/drivers/sensor/Jamfile new file mode 100644 index 0000000000..52011f6c26 --- /dev/null +++ b/src/add-ons/kernel/drivers/sensor/Jamfile @@ -0,0 +1,4 @@ +SubDir HAIKU_TOP src add-ons kernel drivers sensor ; + +SubInclude HAIKU_TOP src add-ons kernel drivers sensor acpi_als ; + diff --git a/src/add-ons/kernel/drivers/sensor/acpi_als/Jamfile b/src/add-ons/kernel/drivers/sensor/acpi_als/Jamfile new file mode 100644 index 0000000000..242b311f23 --- /dev/null +++ b/src/add-ons/kernel/drivers/sensor/acpi_als/Jamfile @@ -0,0 +1,11 @@ +SubDir HAIKU_TOP src add-ons kernel drivers sensor acpi_als ; + +UsePrivateKernelHeaders ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) bus_managers acpi acpica include ] ; +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) bus_managers acpi acpica include platform ] ; + +KernelAddon acpi_als : + acpi_als.cpp + ; + diff --git a/src/add-ons/kernel/drivers/sensor/acpi_als/acpi_als.cpp b/src/add-ons/kernel/drivers/sensor/acpi_als/acpi_als.cpp new file mode 100644 index 0000000000..5ff5367956 --- /dev/null +++ b/src/add-ons/kernel/drivers/sensor/acpi_als/acpi_als.cpp @@ -0,0 +1,370 @@ +/* + * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com. + * Distributed under the terms of the MIT license. + */ + + +#include +#include +#include +#include + +#include +#include +#include + +#include + + +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 +};