* each device manager node has now an autogenerated identifier

* added a generic syscall for device_manager
it enables to iterate the device manager tree from userland
* the listdev tool is now using it: it's still incomplete as it only dumps nodes and attributes


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19260 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2006-11-12 15:28:09 +00:00
parent 2177785876
commit bef4e1fc77
11 changed files with 322 additions and 464 deletions
+27
View File
@@ -38,6 +38,7 @@ struct device_node_info {
uint32 num_io_resources; // number of I/O resources
io_resource_handle *io_resources; // array of I/O resource (NULL-terminated)
bool automatically_loaded; // loaded automatically because PNP_DRIVER_ALWAYS_LOADED
uint32 internal_id; // internal identifier
};
@@ -50,6 +51,32 @@ extern "C" {
extern status_t probe_for_device_type(const char *type);
extern status_t device_manager_init(struct kernel_args *args);
// temporary/optional device manager syscall API
#define DEVICE_MANAGER_SYSCALLS "device_manager"
#define DM_GET_ROOT 1
#define DM_GET_CHILD 2
#define DM_GET_NEXT_CHILD 3
#define DM_GET_NEXT_ATTRIBUTE 4
struct dev_attr {
uint32 node_cookie;
uint32 cookie;
char name[255];
type_code type;
union {
uint8 ui8;
uint16 ui16;
uint32 ui32;
uint64 ui64;
char string[255];
struct {
void *data;
size_t length;
} raw;
} value;
};
#ifdef __cplusplus
}
#endif
+5 -1
View File
@@ -1,7 +1,11 @@
SubDir HAIKU_TOP src bin listdev ;
UsePrivateHeaders kernel ;
UsePrivateHeaders [ FDirName kernel arch $(TARGET_ARCH) ] ;
UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
BinCommand listdev :
cm_wrapper.c
dm_wrapper.c
listdev.c
;
-143
View File
@@ -1,143 +0,0 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <drivers/config_manager.h>
#include "cm_wrapper.h"
#include "config_driver.h"
static int fd;
status_t init_cm_wrapper(void)
{
static const char device[] = "/dev/" CM_DEVICE_NAME;
fd = open(device, 0);
if (fd < 0)
return errno;
return B_OK;
}
status_t uninit_cm_wrapper(void)
{
close(fd);
return B_OK;
}
status_t get_next_device_info(bus_type bus, uint64 *cookie,
struct device_info *info, uint32 size)
{
status_t result;
struct cm_ioctl_data params;
params.magic = CM_GET_NEXT_DEVICE_INFO;
params.bus = bus;
params.cookie = *cookie;
params.data = (void *)info;
params.data_len = size;
result = ioctl(fd, params.magic, &params, sizeof(params));
if (result == B_OK) *cookie = params.cookie;
return result;
}
status_t get_device_info_for(uint64 id, struct device_info *info,
uint32 size)
{
struct cm_ioctl_data params;
params.magic = CM_GET_DEVICE_INFO_FOR;
params.cookie = id;
params.data = (void *)info;
params.data_len = size;
return ioctl(fd, params.magic, &params, sizeof(params));
}
status_t get_size_of_current_configuration_for(uint64 id)
{
struct cm_ioctl_data params;
params.magic = CM_GET_SIZE_OF_CURRENT_CONFIGURATION_FOR;
params.cookie = id;
return ioctl(fd, params.magic, &params, sizeof(params));
}
status_t get_current_configuration_for(uint64 id,
struct device_configuration *current, uint32 size)
{
struct cm_ioctl_data params;
params.magic = CM_GET_CURRENT_CONFIGURATION_FOR;
params.cookie = id;
params.data = (void *)current;
params.data_len = size;
return ioctl(fd, params.magic, &params, sizeof(params));
}
status_t get_size_of_possible_configurations_for(uint64 id)
{
struct cm_ioctl_data params;
params.magic = CM_GET_SIZE_OF_POSSIBLE_CONFIGURATIONS_FOR;
params.cookie = id;
return ioctl(fd, params.magic, &params, sizeof(params));
}
status_t get_possible_configurations_for(uint64 id,
struct possible_device_configurations *possible, uint32 size)
{
struct cm_ioctl_data params;
params.magic = CM_GET_POSSIBLE_CONFIGURATIONS_FOR;
params.cookie = id;
params.data = (void *)possible;
params.data_len = size;
return ioctl(fd, params.magic, &params, sizeof(params));
}
status_t count_resource_descriptors_of_type(
struct device_configuration *c, resource_type type)
{
struct cm_ioctl_data params;
params.magic = CM_COUNT_RESOURCE_DESCRIPTORS_OF_TYPE;
params.config = c;
params.type = type;
return ioctl(fd, params.magic, &params, sizeof(params));
}
status_t get_nth_resource_descriptor_of_type(
struct device_configuration *c, uint32 n,
resource_type type, resource_descriptor *d, uint32 size)
{
struct cm_ioctl_data params;
params.magic = CM_GET_NTH_RESOURCE_DESCRIPTOR_OF_TYPE;
params.config = c;
params.n = n;
params.type = type;
params.data = d;
params.data_len = size;
return ioctl(fd, params.magic, &params, sizeof(params));
}
uchar mask_to_value(uint32 mask)
{
uchar value;
if (!mask) return 0;
for (value=0,mask>>=1;mask;value++,mask>>=1)
;
return value;
}
-25
View File
@@ -1,25 +0,0 @@
#ifndef _CM_WRAPPER_H_
#define _CM_WRAPPER_H_
status_t init_cm_wrapper(void);
status_t uninit_cm_wrapper(void);
status_t get_next_device_info(bus_type bus, uint64 *cookie,
struct device_info *info, uint32 size);
status_t get_device_info_for(uint64 id, struct device_info *info,
uint32 size);
status_t get_size_of_current_configuration_for(uint64 id);
status_t get_current_configuration_for(uint64 id,
struct device_configuration *current, uint32 size);
status_t get_size_of_possible_configurations_for(uint64 id);
status_t get_possible_configurations_for(uint64 id,
struct possible_device_configurations *possible, uint32 size);
status_t count_resource_descriptors_of_type(
struct device_configuration *c, resource_type type);
status_t get_nth_resource_descriptor_of_type(
struct device_configuration *c, uint32 n, resource_type type,
resource_descriptor *d, uint32 size);
uchar mask_to_value(uint32 mask);
#endif
-29
View File
@@ -1,29 +0,0 @@
#ifndef _CONFIG_MANAGER_DRIVER_H_
#define _CONFIG_MANAGER_DRIVER_H_
/* the magic is the ioctl */
#define CM_GET_NEXT_DEVICE_INFO 'GNDI'
#define CM_GET_DEVICE_INFO_FOR 'GDIF'
#define CM_GET_SIZE_OF_CURRENT_CONFIGURATION_FOR 'GSCC'
#define CM_GET_CURRENT_CONFIGURATION_FOR 'GCCF'
#define CM_GET_SIZE_OF_POSSIBLE_CONFIGURATIONS_FOR 'GSPC'
#define CM_GET_POSSIBLE_CONFIGURATIONS_FOR 'GPCF'
#define CM_COUNT_RESOURCE_DESCRIPTORS_OF_TYPE 'CRDT'
#define CM_GET_NTH_RESOURCE_DESCRIPTOR_OF_TYPE 'GNRD'
struct cm_ioctl_data {
uint32 magic;
bus_type bus;
uint64 cookie;
void *config;
uint32 n;
uint32 type;
void *data;
uint32 data_len;
};
#define CM_DEVICE_NAME "misc/config"
#endif
+48
View File
@@ -0,0 +1,48 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <drivers/device_manager.h>
#include <generic_syscall.h>
#include <string.h>
#include <syscalls.h>
#include "dm_wrapper.h"
status_t init_dm_wrapper(void)
{
uint32 version = 0;
return _kern_generic_syscall(DEVICE_MANAGER_SYSCALLS, B_SYSCALL_INFO, &version, sizeof(version));
}
status_t uninit_dm_wrapper(void)
{
return B_OK;
}
status_t
get_root(uint32 *cookie)
{
return _kern_generic_syscall(DEVICE_MANAGER_SYSCALLS, DM_GET_ROOT, cookie, sizeof(uint32));
}
status_t
get_child(uint32 *device)
{
return _kern_generic_syscall(DEVICE_MANAGER_SYSCALLS, DM_GET_CHILD, device, sizeof(uint32));
}
status_t
get_next_child(uint32 *device)
{
return _kern_generic_syscall(DEVICE_MANAGER_SYSCALLS, DM_GET_NEXT_CHILD, device, sizeof(uint32));
}
status_t
dm_get_next_attr(struct dev_attr *attr)
{
return _kern_generic_syscall(DEVICE_MANAGER_SYSCALLS, DM_GET_NEXT_ATTRIBUTE, attr, sizeof(struct dev_attr));
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef _DM_WRAPPER_H_
#define _DM_WRAPPER_H_
#include "kdevice_manager.h"
status_t init_dm_wrapper(void);
status_t uninit_dm_wrapper(void);
status_t get_root(uint32 *cookie);
status_t get_child(uint32 *cookie);
status_t get_next_child(uint32 *cookie);
status_t dm_get_next_attr(struct dev_attr *attr);
#endif
+58 -266
View File
@@ -3,304 +3,96 @@
#include <string.h>
#include <unistd.h>
#include <drivers/config_manager.h>
#include <drivers/isapnp.h>
#include <drivers/device_manager.h>
#include <drivers/module.h>
#include <drivers/PCI.h>
#include "cm_wrapper.h"
#include "config_driver.h"
#include "dm_wrapper.h"
#define NEXT_POSSIBLE(c) \
(c) = (void *)((uchar *)(c) + sizeof(struct device_configuration) \
+ (c)->num_resources * sizeof(resource_descriptor));
static void
put_level(int32 level)
{
while (level-- > 0)
printf(" ");
}
static void
dump_mask(uint32 mask)
dump_attribute(struct dev_attr *attr, int32 level)
{
bool first = true;
int i = 0;
printf("[");
if (!mask)
printf("none");
for (;mask;mask>>=1,i++)
if (mask & 1) {
printf("%s%d", first ? "" : ",", i);
first = false;
}
printf("]");
if (attr == NULL)
return;
put_level(level);
printf("\"%s\" : ", attr->name);
switch (attr->type) {
case B_STRING_TYPE:
printf("string : \"%s\"", attr->value.string);
break;
case B_UINT8_TYPE:
printf("uint8 : %u (%#x)", attr->value.ui8, attr->value.ui8);
break;
case B_UINT16_TYPE:
printf("uint16 : %u (%#x)", attr->value.ui16, attr->value.ui16);
break;
case B_UINT32_TYPE:
printf("uint32 : %lu (%#lx)", attr->value.ui32, attr->value.ui32);
break;
case B_UINT64_TYPE:
printf("uint64 : %Lu (%#Lx)", attr->value.ui64, attr->value.ui64);
break;
default:
printf("raw data");
}
printf("\n");
}
static void
dump_device_configuration(struct device_configuration *c)
dump_device(uint32 *node, uint8 level)
{
int i, num;
resource_descriptor r;
char data[256];
struct dev_attr attr;
attr.cookie = 0;
attr.node_cookie = *node;
attr.value.raw.data = data;
attr.value.raw.length = sizeof(data);
num = count_resource_descriptors_of_type(c, B_IRQ_RESOURCE);
if (num) {
printf("irq%s ", (num == 1) ? "" : "s");
for (i=0;i<num;i++) {
get_nth_resource_descriptor_of_type(c, i, B_IRQ_RESOURCE,
&r, sizeof(resource_descriptor));
dump_mask(r.d.m.mask);
}
printf(" ");
while (dm_get_next_attr(&attr) == B_OK) {
dump_attribute(&attr, level);
}
num = count_resource_descriptors_of_type(c, B_DMA_RESOURCE);
if (num) {
printf("dma%s ", (num == 1) ? "" : "s");
for (i=0;i<num;i++) {
get_nth_resource_descriptor_of_type(c, i, B_DMA_RESOURCE,
&r, sizeof(resource_descriptor));
dump_mask(r.d.m.mask);
}
printf(" ");
}
num = count_resource_descriptors_of_type(c, B_IO_PORT_RESOURCE);
if (num) {
for (i=0;i<num;i++) {
get_nth_resource_descriptor_of_type(c, i, B_IO_PORT_RESOURCE,
&r, sizeof(resource_descriptor));
printf("\n io range: min %lx max %lx align %lx len %lx",
r.d.r.minbase, r.d.r.maxbase,
r.d.r.basealign, r.d.r.len);
}
}
num = count_resource_descriptors_of_type(c, B_MEMORY_RESOURCE);
if (num) {
for (i=0;i<num;i++) {
get_nth_resource_descriptor_of_type(c, i, B_MEMORY_RESOURCE,
&r, sizeof(resource_descriptor));
printf("\n mem range: min %lx max %lx align %lx len %lx",
r.d.r.minbase, r.d.r.maxbase,
r.d.r.basealign, r.d.r.len);
}
}
printf("\n");
}
const char *base_desc[] = {
"Legacy",
"Mass Storage Controller",
"NIC",
"Display Controller",
"Multimedia Device",
"Memory Controller",
"Bridge Device",
"Communication Device",
"Generic System Peripheral",
"Input Device",
"Docking Station",
"CPU",
"Serial Bus Controller"
};
struct subtype_descriptions {
uchar base, subtype;
char *name;
} subtype_desc[] = {
{ 0, 0, "non-VGA" },
{ 0, 0, "VGA" },
{ 1, 0, "SCSI" },
{ 1, 1, "IDE" },
{ 1, 2, "Floppy" },
{ 1, 3, "IPI" },
{ 1, 4, "RAID" },
{ 2, 0, "Ethernet" },
{ 2, 1, "Token Ring" },
{ 2, 2, "FDDI" },
{ 2, 3, "ATM" },
{ 3, 0, "VGA/8514" },
{ 3, 1, "XGA" },
{ 4, 0, "Video" },
{ 4, 1, "Audio" },
{ 5, 0, "RAM" },
{ 5, 1, "Flash" },
{ 6, 0, "Host" },
{ 6, 1, "ISA" },
{ 6, 2, "EISA" },
{ 6, 3, "MCA" },
{ 6, 4, "PCI-PCI" },
{ 6, 5, "PCMCIA" },
{ 6, 6, "NuBus" },
{ 6, 7, "CardBus" },
{ 7, 0, "Serial" },
{ 7, 1, "Parallel" },
{ 8, 0, "PIC" },
{ 8, 1, "DMA" },
{ 8, 2, "Timer" },
{ 8, 3, "RTC" },
{ 9, 0, "Keyboard" },
{ 9, 1, "Digitizer" },
{ 9, 2, "Mouse" },
{10, 0, "Generic" },
{11, 0, "386" },
{11, 1, "486" },
{11, 2, "Pentium" },
{11,16, "Alpha" },
{11,32, "PowerPC" },
{11,48, "Coprocessor" },
{12, 0, "IEEE 1394" },
{12, 1, "ACCESS" },
{12, 2, "SSA" },
{12, 3, "USB" },
{12, 4, "Fibre Channel" },
{255,255, NULL }
};
static void
dump_device_info(struct device_info *info, struct device_configuration *current,
struct possible_device_configurations *possible)
dump_nodes(uint32 *node, uint8 level)
{
unsigned int i;
struct device_configuration *config;
status_t err;
uint32 child = *node;
dump_device(node, level);
printf((info->devtype.base < 13) ? base_desc[info->devtype.base] : "Unknown");
if (info->devtype.subtype == 0x80)
printf(" (Other)");
else {
struct subtype_descriptions *s = subtype_desc;
while (s->name) {
if ((info->devtype.base == s->base) && (info->devtype.subtype == s->subtype))
break;
s++;
}
printf(" (%s)", (s->name) ? s->name : "Unknown");
}
printf(" [%x|%x|%x]\n", info->devtype.base, info->devtype.subtype, info->devtype.interface);
if (get_child(&child) != B_OK)
return;
if (!(info->flags & B_DEVICE_INFO_ENABLED)) {
printf("Device is disabled (%s)\n", strerror(info->config_status));
} else if (info->flags & B_DEVICE_INFO_CONFIGURED) {
printf("Current configuration: ");
dump_device_configuration(current);
} else {
printf("Currently unconfigured.\n");
}
do {
dump_nodes(&child, level+1);
} while ((err = get_next_child(&child)) == B_OK);
printf("%lx configurations\n", possible->num_possible);
config = possible->possible + 0;
for (i=0;i<possible->num_possible;i++) {
printf("\nPossible configuration #%d: ", i);
dump_device_configuration(config);
NEXT_POSSIBLE(config);
}
printf("\n");
}
static void
dump_isa_info(struct device_info *info)
{
struct isa_info *isa = (struct isa_info *)
((uchar *)info + info->bus_dependent_info_offset);
printf("CSN %x LDN %x %s %s\n", isa->csn,
isa->ldn, isa->card_name, isa->logical_device_name);
}
static void
dump_pci_info(struct device_info *info)
{
struct pci_info *pci = (struct pci_info *)
((uchar *)info + info->bus_dependent_info_offset);
printf("vendor id: %x, device id: %x\n", pci->vendor_id, pci->device_id);
}
static void
dump_devices_for_bus(bus_type bus, void (*f)(struct device_info *))
{
status_t size;
uint64 cookie;
int index = 0;
void *current, *possible;
struct device_info dummy, *info;
cookie = 0;
while (get_next_device_info(bus, &cookie, &dummy, sizeof(dummy)) == B_OK) {
info = (struct device_info *)malloc(dummy.size);
if (!info) {
printf("Out of core\n");
break;
}
if (get_device_info_for(cookie, info, dummy.size) != B_OK) {
printf("Error getting device information\n");
break;
}
size = get_size_of_current_configuration_for(cookie);
if (size < B_OK) {
printf("Error getting the size of the current configuration\n");
break;
}
current = malloc(size);
if (!current) {
printf("Out of core\n");
break;
}
if (get_current_configuration_for(cookie, current, size) != B_OK) {
printf("Error getting the current configuration\n");
break;
}
size = get_size_of_possible_configurations_for(cookie);
if (size < B_OK) {
printf("Error getting the size of the possible configurations\n");
break;
}
possible = malloc(size);
if (!possible) {
printf("Out of core\n");
break;
}
if (get_possible_configurations_for(cookie, possible, size) != B_OK) {
printf("Error getting the possible configurations\n");
break;
}
switch (info->bus) {
case B_ISA_BUS : printf("ISA"); break;
case B_PCI_BUS : printf("PCI"); break;
default : printf("unknown"); break;
}
printf(" bus, device #%d: ", index++);
dump_device_info(info, current, possible);
if (f) {
printf("Bus-dependent information:\n");
(*f)(info);
}
printf("\n");
free(possible);
free(current);
free(info);
}
}
int main()
{
status_t error;
uint32 root;
if ((error = init_cm_wrapper()) < 0) {
printf("Error initializing configuration manager (%s)\n", strerror(error));
if ((error = init_dm_wrapper()) < 0) {
printf("Error initializing device manager (%s)\n", strerror(error));
return error;
}
dump_devices_for_bus(B_ISA_BUS, dump_isa_info);
dump_devices_for_bus(B_PCI_BUS, dump_pci_info);
get_root(&root);
dump_nodes(&root, 0);
uninit_cm_wrapper();
uninit_dm_wrapper();
return 0;
}
@@ -14,6 +14,7 @@
#include "device_manager_private.h"
#include <kdevice_manager.h>
#include <generic_syscall.h>
#include <KernelExport.h>
#include <string.h>
@@ -166,6 +167,7 @@ device_manager_init(struct kernel_args *args)
#endif
add_debugger_command("dm_tree", &dump_device_nodes, "dump device node tree");
register_generic_syscall(DEVICE_MANAGER_SYSCALLS, device_manager_control, 1, 0);
return B_OK;
}
@@ -176,6 +176,8 @@ status_t dm_get_next_child_node(device_node_info *parent,
device_node_info *dm_get_root(void);
device_node_info *dm_get_parent(device_node_info *node);
status_t device_manager_control(const char *subsystem, uint32 function, void *buffer, size_t bufferSize);
// notifications.c
+166
View File
@@ -24,6 +24,8 @@
#include "device_manager_private.h"
#include "dl_list.h"
#include <kernel.h>
#include <KernelExport.h>
#include <TypeConstants.h>
@@ -41,6 +43,8 @@
benaphore gNodeLock;
uint32 sNodeID; // nodes counter
static void
put_level(int32 level)
@@ -263,6 +267,7 @@ dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
node->num_blocked_loads = 0;
node->load_block_count = 0;
node->loading = 0;
node->internal_id = sNodeID++;
TRACE(("dm_allocate_node(): new node %p\n", node));
@@ -432,6 +437,7 @@ dm_dump_node(device_node_info *node, int32 level)
status_t
dm_init_nodes(void)
{
sNodeID = 1;
return benaphore_init(&gNodeLock, "device nodes");
}
@@ -513,3 +519,163 @@ dm_get_next_child_node(device_node_info *parent, device_node_info **_node,
return B_ENTRY_NOT_FOUND;
}
// hold gNodeLock
static device_node_info *
device_manager_find_device(device_node_info *parent, uint32 id)
{
device_node_info *node = NULL;
if (parent->internal_id == id)
return parent;
while ((node = (device_node_info *)list_get_next_item(&parent->children, node)) != NULL) {
device_node_info *child = device_manager_find_device(node, id);
if (child != NULL)
return child;
}
return NULL;
}
status_t
device_manager_control(const char *subsystem, uint32 function, void *buffer, size_t bufferSize)
{
switch (function) {
case DM_GET_ROOT: {
uint32 cookie;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(uint32))
return B_BAD_VALUE;
cookie = gRootNode->internal_id;
// copy back to user space
if (user_memcpy(buffer, &cookie, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
case DM_GET_CHILD: {
uint32 cookie;
device_node_info *node;
device_node_info *child;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(uint32))
return B_BAD_VALUE;
if (user_memcpy(&cookie, buffer, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
benaphore_lock(&gNodeLock);
node = device_manager_find_device(gRootNode, cookie);
if (!node) {
benaphore_unlock(&gNodeLock);
return B_BAD_VALUE;
}
child = (device_node_info *)list_get_next_item(&node->children, NULL);
if (child)
cookie = child->internal_id;
benaphore_unlock(&gNodeLock);
if (!child)
return B_ENTRY_NOT_FOUND;
// copy back to user space
if (user_memcpy(buffer, &cookie, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
case DM_GET_NEXT_CHILD: {
uint32 cookie;
device_node_info *node;
device_node_info *child;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(uint32))
return B_BAD_VALUE;
if (user_memcpy(&cookie, buffer, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
benaphore_lock(&gNodeLock);
node = device_manager_find_device(gRootNode, cookie);
if (!node) {
benaphore_unlock(&gNodeLock);
return B_BAD_VALUE;
}
child = (device_node_info *)list_get_next_item(&node->parent->children, node);
if (child)
cookie = child->internal_id;
benaphore_unlock(&gNodeLock);
cookie++;
if (!child)
return B_ENTRY_NOT_FOUND;
// copy back to user space
if (user_memcpy(buffer, &cookie, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
case DM_GET_NEXT_ATTRIBUTE: {
struct dev_attr attr;
device_node_info *node;
uint32 i = 0;
device_attr_info *attr_info;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(struct dev_attr))
return B_BAD_VALUE;
if (user_memcpy(&attr, buffer, sizeof(struct dev_attr)) < B_OK)
return B_BAD_ADDRESS;
benaphore_lock(&gNodeLock);
node = device_manager_find_device(gRootNode, attr.node_cookie);
if (!node) {
benaphore_unlock(&gNodeLock);
return B_BAD_VALUE;
}
for (attr_info = node->attributes; attr.cookie > i && attr_info != NULL; attr_info = attr_info->next) {
i++;
}
if (!attr_info) {
benaphore_unlock(&gNodeLock);
return B_ENTRY_NOT_FOUND;
}
attr.cookie++;
strlcpy(attr.name, attr_info->attr.name, 254);
attr.type = attr_info->attr.type;
switch (attr_info->attr.type) {
case B_UINT8_TYPE:
attr.value.ui8 = attr_info->attr.value.ui8; break;
case B_UINT16_TYPE:
attr.value.ui16 = attr_info->attr.value.ui16; break;
case B_UINT32_TYPE:
attr.value.ui32 = attr_info->attr.value.ui32; break;
case B_UINT64_TYPE:
attr.value.ui64 = attr_info->attr.value.ui64; break;
case B_STRING_TYPE:
strlcpy(attr.value.string, attr_info->attr.value.string, 254); break;
case B_RAW_TYPE:
if (attr.value.raw.length > attr_info->attr.value.raw.length)
attr.value.raw.length = attr_info->attr.value.raw.length;
memcpy(attr.value.raw.data, attr_info->attr.value.raw.data,
attr.value.raw.length);
break;
}
benaphore_unlock(&gNodeLock);
// copy back to user space
if (user_memcpy(buffer, &attr, sizeof(struct dev_attr)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
};
return B_BAD_HANDLER;
}