1/* config driver
2 * provides userland access to the device manager
3 *
4 * Copyright 2002-2004, Axel Doerfler. All rights reserved.
5 * Distributed under the terms of the MIT License.
6 *
7 * Authors : Axel Doerfler, Jerome Duval
8 */
9
10
11#include <Drivers.h>
12#include <drivers/device_manager.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include "config_driver.h"
17
18#ifdef DEBUG
19#define TRACE(x...) dprintf(x)
20#else
21#define TRACE(x...)
22#endif
23
24#define DEVICE_NAME "misc/config"
25
26int32 api_version = B_CUR_DRIVER_API_VERSION;
27
28device_manager_info *gDeviceManager;
29
30typedef struct _driver_cookie {
31	device_node_handle parent;
32	device_node_handle child;
33	device_attr_handle attr;
34} driver_cookie;
35
36//	Device interface
37
38
39static status_t
40config_open(const char *name, uint32 flags, void **_cookie)
41{
42	driver_cookie *cookie = malloc(sizeof(driver_cookie));
43	if (cookie == NULL)
44		return B_ERROR;
45	*_cookie = cookie;
46	cookie->child = gDeviceManager->get_root();
47	cookie->parent = NULL;
48	cookie->attr = NULL;
49	return B_OK;
50}
51
52
53static status_t
54config_close(void *cookie)
55{
56	return B_OK;
57}
58
59
60static status_t
61config_free_cookie(void *cookie)
62{
63	driver_cookie *cook = (driver_cookie *)cookie;
64	gDeviceManager->put_device_node(cook->child);
65	if (cook->parent)
66		gDeviceManager->put_device_node(cook->parent);
67	return B_OK;
68}
69
70
71static status_t
72config_ioctl(void *cookie, uint32 op, void *buffer, size_t len)
73{
74	driver_cookie *cook = (driver_cookie *)cookie;
75	device_node_handle child = NULL;
76	const device_attr *attr = NULL;
77
78	struct dm_ioctl_data *params = (struct dm_ioctl_data *)buffer;
79	status_t err = B_OK;
80
81	// simple check for validity of the argument
82	if (params == NULL || params->magic != op)
83		return B_BAD_VALUE;
84
85	switch (op) {
86		case DM_GET_CHILD:
87			TRACE("DM_GET_CHILD parent %p child %p\n", cook->parent, cook->child);
88			if (cook->attr) {
89				gDeviceManager->release_attr(cook->child, cook->attr);
90				cook->attr = NULL;
91			}
92			err = gDeviceManager->get_next_child_device(cook->child, &child, NULL);
93			if (err == B_OK) {
94				if (cook->parent)
95					gDeviceManager->put_device_node(cook->parent);
96				cook->parent = cook->child;
97				cook->child = child;
98			}
99			return err;
100		case DM_GET_NEXT_CHILD:
101			TRACE("DM_GET_NEXT_CHILD parent %p child %p\n", cook->parent, cook->child);
102			if (!cook->parent)
103				return B_ENTRY_NOT_FOUND;
104			if (cook->attr) {
105				gDeviceManager->release_attr(cook->child, cook->attr);
106				cook->attr = NULL;
107			}
108			return gDeviceManager->get_next_child_device(cook->parent, &cook->child, NULL);
109		case DM_GET_PARENT:
110			TRACE("DM_GET_PARENT parent %p child %p\n", cook->parent, cook->child);
111			if (!cook->parent)
112				return B_ENTRY_NOT_FOUND;
113			if (cook->attr) {
114				gDeviceManager->release_attr(cook->child, cook->attr);
115				cook->attr = NULL;
116			}
117			if (cook->child)
118				gDeviceManager->put_device_node(cook->child);
119			cook->child = cook->parent;
120			cook->parent = gDeviceManager->get_parent(cook->child);
121			return B_OK;
122		case DM_GET_NEXT_ATTRIBUTE:
123			TRACE("DM_NEXT_ATTRIBUTE parent %p child %p attr %p\n", cook->parent, cook->child, cook->attr);
124			return gDeviceManager->get_next_attr(cook->child, &cook->attr);
125		case DM_RETRIEVE_ATTRIBUTE:
126			TRACE("DM_RETRIEVE_ATTRIBUTE parent %p child %p attr %p\n", cook->parent, cook->child, cook->attr);
127			err = gDeviceManager->retrieve_attr(cook->attr, &attr);
128			if (err == B_OK) {
129				strlcpy(params->attr->name, attr->name, 254);
130				params->attr->type = attr->type;
131				switch (attr->type) {
132					case B_UINT8_TYPE:
133						params->attr->value.ui8 = attr->value.ui8; break;
134					case B_UINT16_TYPE:
135						params->attr->value.ui16 = attr->value.ui16; break;
136					case B_UINT32_TYPE:
137						params->attr->value.ui32 = attr->value.ui32; break;
138					case B_UINT64_TYPE:
139						params->attr->value.ui64 = attr->value.ui64; break;
140					case B_STRING_TYPE:
141						strlcpy(params->attr->value.string, attr->value.string, 254); break;
142					case B_RAW_TYPE:
143						if (params->attr->value.raw.length > attr->value.raw.length)
144							params->attr->value.raw.length = attr->value.raw.length;
145						memcpy(params->attr->value.raw.data, attr->value.raw.data,
146							params->attr->value.raw.length);
147						break;
148				}
149			}
150			return err;
151	}
152
153	return B_BAD_VALUE;
154}
155
156
157static status_t
158config_read(void * cookie, off_t pos, void *buf, size_t *_length)
159{
160	*_length = 0;
161	return B_OK;
162}
163
164
165static status_t
166config_write(void * cookie, off_t pos, const void *buf, size_t *_length)
167{
168	*_length = 0;
169	return B_OK;
170}
171
172
173//	#pragma mark -
174//	Driver interface
175
176
177status_t
178init_hardware()
179{
180	return B_OK;
181}
182
183
184const char **
185publish_devices(void)
186{
187	static const char *devices[] = {
188		DEVICE_NAME,
189		NULL
190	};
191
192	return devices;
193}
194
195
196device_hooks *
197find_device(const char *name)
198{
199	static device_hooks hooks = {
200		&config_open,
201		&config_close,
202		&config_free_cookie,
203		&config_ioctl,
204		&config_read,
205		&config_write,
206		/* Leave select/deselect/readv/writev undefined. The kernel will
207		 * use its own default implementation. The basic hooks above this
208		 * line MUST be defined, however. */
209		NULL,
210		NULL,
211		NULL,
212		NULL
213	};
214
215	if (!strcmp(name, DEVICE_NAME))
216		return &hooks;
217
218	return NULL;
219}
220
221
222status_t
223init_driver()
224{
225	return get_module(B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager);
226}
227
228
229void
230uninit_driver()
231{
232	if (gDeviceManager != NULL)
233		put_module(B_DEVICE_MANAGER_MODULE_NAME);
234}
235
236