root/src/tests/system/kernel/device_manager/config.c
/* config driver
 * provides userland access to the device manager
 *
 * Copyright 2002-2004, Axel Doerfler. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors : Axel Doerfler, Jerome Duval
 */


#include <Drivers.h>
#include <drivers/device_manager.h>
#include <stdlib.h>
#include <string.h>

#include "config_driver.h"

#ifdef DEBUG
#define TRACE(x...) dprintf(x)
#else
#define TRACE(x...)
#endif

#define DEVICE_NAME "misc/config"

int32 api_version = B_CUR_DRIVER_API_VERSION;

device_manager_info *gDeviceManager;

typedef struct _driver_cookie {
        device_node_handle parent;
        device_node_handle child;
        device_attr_handle attr;
} driver_cookie;

//      Device interface


static status_t
config_open(const char *name, uint32 flags, void **_cookie)
{
        driver_cookie *cookie = malloc(sizeof(driver_cookie));
        if (cookie == NULL)
                return B_ERROR;
        *_cookie = cookie;
        cookie->child = gDeviceManager->get_root();
        cookie->parent = NULL;
        cookie->attr = NULL;
        return B_OK;
}


static status_t
config_close(void *cookie)
{
        return B_OK;
}


static status_t
config_free_cookie(void *cookie)
{
        driver_cookie *cook = (driver_cookie *)cookie;
        gDeviceManager->put_device_node(cook->child);
        if (cook->parent)
                gDeviceManager->put_device_node(cook->parent);
        return B_OK;
}


static status_t
config_ioctl(void *cookie, uint32 op, void *buffer, size_t len)
{
        driver_cookie *cook = (driver_cookie *)cookie;
        device_node_handle child = NULL;
        const device_attr *attr = NULL;
        
        struct dm_ioctl_data *params = (struct dm_ioctl_data *)buffer;
        status_t err = B_OK;

        // simple check for validity of the argument
        if (params == NULL || params->magic != op)
                return B_BAD_VALUE;

        switch (op) {
                case DM_GET_CHILD:
                        TRACE("DM_GET_CHILD parent %p child %p\n", cook->parent, cook->child);
                        if (cook->attr) {
                                gDeviceManager->release_attr(cook->child, cook->attr);
                                cook->attr = NULL;
                        }
                        err = gDeviceManager->get_next_child_device(cook->child, &child, NULL);
                        if (err == B_OK) {
                                if (cook->parent)
                                        gDeviceManager->put_device_node(cook->parent);
                                cook->parent = cook->child;
                                cook->child = child;
                        }
                        return err;
                case DM_GET_NEXT_CHILD:
                        TRACE("DM_GET_NEXT_CHILD parent %p child %p\n", cook->parent, cook->child);
                        if (!cook->parent)
                                return B_ENTRY_NOT_FOUND;
                        if (cook->attr) {
                                gDeviceManager->release_attr(cook->child, cook->attr);
                                cook->attr = NULL;
                        }
                        return gDeviceManager->get_next_child_device(cook->parent, &cook->child, NULL);
                case DM_GET_PARENT:
                        TRACE("DM_GET_PARENT parent %p child %p\n", cook->parent, cook->child);
                        if (!cook->parent)
                                return B_ENTRY_NOT_FOUND;
                        if (cook->attr) {
                                gDeviceManager->release_attr(cook->child, cook->attr);
                                cook->attr = NULL;
                        }
                        if (cook->child)
                                gDeviceManager->put_device_node(cook->child);
                        cook->child = cook->parent;
                        cook->parent = gDeviceManager->get_parent(cook->child);
                        return B_OK;
                case DM_GET_NEXT_ATTRIBUTE:
                        TRACE("DM_NEXT_ATTRIBUTE parent %p child %p attr %p\n", cook->parent, cook->child, cook->attr);
                        return gDeviceManager->get_next_attr(cook->child, &cook->attr);
                case DM_RETRIEVE_ATTRIBUTE:
                        TRACE("DM_RETRIEVE_ATTRIBUTE parent %p child %p attr %p\n", cook->parent, cook->child, cook->attr);
                        err = gDeviceManager->retrieve_attr(cook->attr, &attr);
                        if (err == B_OK) {
                                strlcpy(params->attr->name, attr->name, 254);
                                params->attr->type = attr->type;
                                switch (attr->type) {
                                        case B_UINT8_TYPE:
                                                params->attr->value.ui8 = attr->value.ui8; break;
                                        case B_UINT16_TYPE:
                                                params->attr->value.ui16 = attr->value.ui16; break;
                                        case B_UINT32_TYPE:
                                                params->attr->value.ui32 = attr->value.ui32; break;
                                        case B_UINT64_TYPE:
                                                params->attr->value.ui64 = attr->value.ui64; break;
                                        case B_STRING_TYPE:
                                                strlcpy(params->attr->value.string, attr->value.string, 254); break;
                                        case B_RAW_TYPE:
                                                if (params->attr->value.raw.length > attr->value.raw.length)
                                                        params->attr->value.raw.length = attr->value.raw.length;
                                                memcpy(params->attr->value.raw.data, attr->value.raw.data, 
                                                        params->attr->value.raw.length);
                                                break;
                                }
                        }
                        return err;
        }

        return B_BAD_VALUE;
}


static status_t
config_read(void * cookie, off_t pos, void *buf, size_t *_length)
{
        *_length = 0;
        return B_OK;
}


static status_t
config_write(void * cookie, off_t pos, const void *buf, size_t *_length)
{
        *_length = 0;
        return B_OK;
}


//      #pragma mark -
//      Driver interface


status_t
init_hardware()
{
        return B_OK;
}


const char **
publish_devices(void)
{
        static const char *devices[] = {
                DEVICE_NAME, 
                NULL
        };

        return devices;
}


device_hooks *
find_device(const char *name)
{
        static device_hooks hooks = {
                &config_open,
                &config_close,
                &config_free_cookie,
                &config_ioctl,
                &config_read,
                &config_write,
                /* Leave select/deselect/readv/writev undefined. The kernel will
                 * use its own default implementation. The basic hooks above this
                 * line MUST be defined, however. */
                NULL,
                NULL,
                NULL,
                NULL
        };

        if (!strcmp(name, DEVICE_NAME))
                return &hooks;

        return NULL;
}


status_t
init_driver()
{
        return get_module(B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager);
}


void
uninit_driver()
{
        if (gDeviceManager != NULL)
                put_module(B_DEVICE_MANAGER_MODULE_NAME);
}