#include "display_adapter.h"
typedef struct acpi_ns_device_info {
device_node *node;
acpi_handle acpi_device;
} displayadapter_device_info;
device_manager_info *gDeviceManager = NULL;
acpi_module_info *gAcpi = NULL;
TODO: ACPI Spec 5 Appendix B: Implement:
_DOS Method to control display output switching
( _DOD Method to retrieve information about child output devices
- You can already do this by listing child devices )
_ROM Method to retrieve the ROM image for this device
_GPD Method for determining which VGA device will post
_SPD Method for controlling which VGA device will post
_VPO Method for determining the post options
Display cycling notifications
*/
static status_t
displayadapter_init_device(void *_cookie, void **cookie)
{
device_node *node = (device_node *)_cookie;
displayadapter_device_info *device;
const char *path;
dprintf("%s: start.\n", __func__);
device = (displayadapter_device_info *)calloc(1, sizeof(*device));
if (device == NULL)
return B_NO_MEMORY;
device->node = node;
if (gDeviceManager->get_attr_string(node, ACPI_DEVICE_PATH_ITEM, &path,
false) != B_OK
|| gAcpi->get_handle(NULL, path, &device->acpi_device) != B_OK) {
dprintf("%s: failed to get acpi node.\n", __func__);
free(device);
return B_ERROR;
}
argument.object_type = ACPI_TYPE_INTEGER;
argument.integer.integer = BIOS_DISPLAY_SWITCH | BIOS_BRIGHTNESS_CONTROL;
arguments.count = 1;
arguments.pointer = &argument;
if (gAcpi->evaluate_object(&device->acpi_device, "_DOS", &arguments, NULL,
0) != B_OK)
dprintf("%s: failed to set _DOS %s\n", __func__, path);
dprintf("%s: done.\n", __func__);
*/
*cookie = device;
return B_OK;
}
static void
displayadapter_uninit_device(void *_cookie)
{
displayadapter_device_info *device = (displayadapter_device_info *)_cookie;
free(device);
}
static status_t
displayadapter_open(void *_cookie, const char *path, int flags, void** cookie)
{
displayadapter_device_info *device = (displayadapter_device_info *)_cookie;
*cookie = device;
return B_OK;
}
static status_t
displayadapter_read(void* _cookie, off_t position, void *buf, size_t* num_bytes)
{
return B_ERROR;
}
static status_t
displayadapter_write(void* cookie, off_t position, const void* buffer,
size_t* num_bytes)
{
return B_ERROR;
}
static status_t
displayadapter_control(void* _cookie, uint32 op, void* arg, size_t len)
{
return B_ERROR;
}
static status_t
displayadapter_close(void* cookie)
{
return B_OK;
}
static status_t
displayadapter_free(void* cookie)
{
return B_OK;
}
static float
displayadapter_support(device_node *parent)
{
acpi_handle handle, method;
const char *bus;
const char *path;
uint32 device_type;
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
return -1;
if (strcmp(bus, "acpi"))
return 0.0;
if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_PATH_ITEM, &path,
false) != B_OK)
return 0.0;
if (gDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
&device_type, false) != B_OK
|| device_type != ACPI_TYPE_DEVICE) {
return 0.0;
}
if (gAcpi->get_handle(NULL, path, &handle) != B_OK)
return 0.0;
if (gAcpi->get_handle(handle, "_DOD", &method) != B_OK ||
gAcpi->get_handle(handle, "_DOS", &method) != B_OK) {
return 0.0;
}
dprintf("%s: found at bus: %s path: %s\n", __func__, bus, path);
return 0.6;
}
static status_t
register_displays(const char *parentName, device_node *node)
{
acpi_handle acpiHandle;
const char *path;
device_node *parent = gDeviceManager->get_parent_node(node);
if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_PATH_ITEM, &path,
false) != B_OK
|| gAcpi->get_handle(NULL, path, &acpiHandle) != B_OK) {
dprintf("%s: failed to get acpi node.\n", __func__);
gDeviceManager->put_node(parent);
return B_ERROR;
}
acpi_object_type *pkgData = (acpi_object_type *)malloc(128);
if (pkgData == NULL)
return B_ERROR;
status_t status = gAcpi->evaluate_object(acpiHandle, "_DOD", NULL, pkgData,
128);
if (status != B_OK || pkgData->object_type != ACPI_TYPE_PACKAGE) {
dprintf("%s: fail. %ld %lu\n", __func__, status, pkgData->object_type);
free(pkgData);
return status;
}
acpi_object_type *displayIDs = pkgData->package.objects;
for (uint32 i = 0; i < pkgData->package.count; i++) {
dprintf("Display ID = %lld\n", displayIDs[i].integer.integer);
}
acpi_object_type result;
acpi_handle child = NULL;
while (gAcpi->get_next_object(ACPI_TYPE_DEVICE, acpiHandle, &child)
== B_OK) {
char name[5] = {0};
if(gAcpi->get_name(child, 1, name, 5) == B_OK)
dprintf("name: %s\n", name);
if (gAcpi->evaluate_object(child, "_ADR", NULL, &result, sizeof(result))
!= B_OK)
continue;
dprintf("Child _adr %llu\n", result.integer.integer);
uint32 i;
for (i = 0; i < pkgData->package.count; i++)
if (displayIDs[i].integer.integer == result.integer.integer) break;
if (i == pkgData->package.count) continue;
device_attr attrs[] = {
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = name }},
{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_KEEP_DRIVER_LOADED }},
{ NULL }
};
device_node* deviceNode;
gDeviceManager->register_node(node, DISPLAY_DEVICE_MODULE_NAME, attrs,
NULL, &deviceNode);
char deviceName[128];
snprintf(deviceName, sizeof(deviceName), "%s/%s", parentName, name);
gDeviceManager->publish_device(parent, deviceName,
DISPLAY_DEVICE_MODULE_NAME);
}
gDeviceManager->put_node(parent);
free(pkgData);
return B_OK;
}
static status_t
displayadapter_register_device(device_node *node)
{
device_attr attrs[] = {
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "Display Adapter" }},
{ B_DEVICE_FLAGS, B_UINT32_TYPE, {
.ui32 = B_KEEP_DRIVER_LOADED | B_FIND_MULTIPLE_CHILDREN }},
{ NULL }
};
return gDeviceManager->register_node(node, DISPLAYADAPTER_MODULE_NAME,
attrs, NULL, NULL);
}
static status_t
displayadapter_init_driver(device_node *node, void **_driverCookie)
{
*_driverCookie = node;
return B_OK;
}
static void
displayadapter_uninit_driver(void *driverCookie)
{
}
static status_t
displayadapter_register_child_devices(void *_cookie)
{
device_node *node = (device_node*)_cookie;
int path_id = gDeviceManager->create_id(DISPLAYADAPTER_PATHID_GENERATOR);
if (path_id < 0) {
dprintf("displayadapter_register_child_devices: error creating path\n");
return B_ERROR;
}
char name[128];
snprintf(name, sizeof(name), DISPLAYADAPTER_BASENAME, path_id);
status_t status = gDeviceManager->publish_device(node, name,
DISPLAYADAPTER_DEVICE_MODULE_NAME);
if (status == B_OK)
register_displays(name, node);
return status;
}
module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
{ B_ACPI_MODULE_NAME, (module_info **)&gAcpi},
{}
};
driver_module_info displayadapter_driver_module = {
{
DISPLAYADAPTER_MODULE_NAME,
0,
NULL
},
displayadapter_support,
displayadapter_register_device,
displayadapter_init_driver,
displayadapter_uninit_driver,
displayadapter_register_child_devices,
NULL,
NULL,
};
device_module_info displayadapter_device_module = {
{
DISPLAYADAPTER_DEVICE_MODULE_NAME,
0,
NULL
},
displayadapter_init_device,
displayadapter_uninit_device,
NULL,
displayadapter_open,
displayadapter_close,
displayadapter_free,
displayadapter_read,
displayadapter_write,
NULL,
displayadapter_control,
NULL,
NULL
};
module_info *modules[] = {
(module_info *)&display_device_module,
(module_info *)&displayadapter_device_module,
(module_info *)&displayadapter_driver_module,
NULL
};