xref: /minix3/minix/servers/devman/device.c (revision 5eefd0fec2bd5bc6ad818ba164bcc653f954426c)
1433d6423SLionel Sambuc #include "devman.h"
2433d6423SLionel Sambuc #include "proto.h"
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc 
5433d6423SLionel Sambuc static struct devman_device*devman_dev_add_child(struct devman_device
6433d6423SLionel Sambuc 	*parent, struct devman_device_info *devinf);
7433d6423SLionel Sambuc static struct devman_device *_find_dev(struct devman_device *dev, int
8433d6423SLionel Sambuc 	dev_id);
9433d6423SLionel Sambuc static int devman_dev_add_info(struct devman_device *dev, struct
10433d6423SLionel Sambuc 	devman_device_info_entry *entry, char *buf);
11*5eefd0feSDavid van Moolenbroek static ssize_t devman_event_read(char *ptr, size_t len, off_t offset, void
12433d6423SLionel Sambuc 	*data);
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc static int devman_del_device(struct devman_device *dev);
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc static int next_device_id = 1;
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc static struct inode_stat default_dir_stat = {
19433d6423SLionel Sambuc 	/* .mode  = */ S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH,
20433d6423SLionel Sambuc 	/* .uid   = */ 0,
21433d6423SLionel Sambuc 	/* .gid   = */ 0,
22433d6423SLionel Sambuc 	/* .size  = */ 0,
23433d6423SLionel Sambuc 	/* .dev   = */ NO_DEV,
24433d6423SLionel Sambuc };
25433d6423SLionel Sambuc 
26433d6423SLionel Sambuc static struct inode_stat default_file_stat = {
27433d6423SLionel Sambuc 	/* .mode  = */ S_IFREG | S_IRUSR | S_IRGRP | S_IROTH,
28433d6423SLionel Sambuc 	/* .uid   = */ 0,
29433d6423SLionel Sambuc 	/* .gid   = */ 0,
30433d6423SLionel Sambuc 	/* .size  = */ 0x1000,
31433d6423SLionel Sambuc 	/* .dev   = */ NO_DEV,
32433d6423SLionel Sambuc };
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc static struct devman_device root_dev;
36433d6423SLionel Sambuc static struct devman_event_inode event_inode_data = {
37433d6423SLionel Sambuc 	 TAILQ_HEAD_INITIALIZER(event_inode_data.event_queue),
38433d6423SLionel Sambuc };
39433d6423SLionel Sambuc static struct devman_inode event_inode;
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc /*===========================================================================*
42433d6423SLionel Sambuc  *           devman_generate_path                                            *
43433d6423SLionel Sambuc  *===========================================================================*/
44433d6423SLionel Sambuc static int
devman_generate_path(char * buf,int len,struct devman_device * dev)45433d6423SLionel Sambuc devman_generate_path(char* buf, int len, struct devman_device *dev)
46433d6423SLionel Sambuc {
47433d6423SLionel Sambuc 	int res =0;
48433d6423SLionel Sambuc  	const char * name = ".";
49433d6423SLionel Sambuc 	const char * sep = "/";
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc 	if (dev != NULL) {
52433d6423SLionel Sambuc 		res = devman_generate_path(buf, len, dev->parent);
53433d6423SLionel Sambuc 		if (res != 0) {
54433d6423SLionel Sambuc 			return res;
55433d6423SLionel Sambuc 		}
56433d6423SLionel Sambuc 		name = get_inode_name(dev->inode.inode);
57433d6423SLionel Sambuc 	} else {
58433d6423SLionel Sambuc 	}
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc 	/* does it fit? */
61433d6423SLionel Sambuc 	if (strlen(buf) + strlen(name) + strlen(sep) + 1 > len) {
62433d6423SLionel Sambuc 		return ENOMEM;
63433d6423SLionel Sambuc 	}
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc 	strcat(buf, name);
66433d6423SLionel Sambuc 	strcat(buf, sep);
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc 	return 0;
69433d6423SLionel Sambuc }
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc /*===========================================================================*
72433d6423SLionel Sambuc  *          devman_device_add_event                                          *
73433d6423SLionel Sambuc  *===========================================================================*/
74433d6423SLionel Sambuc static void
devman_device_add_event(struct devman_device * dev)75433d6423SLionel Sambuc devman_device_add_event(struct devman_device* dev)
76433d6423SLionel Sambuc {
77433d6423SLionel Sambuc 	struct devman_event * event;
78433d6423SLionel Sambuc 	char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
79433d6423SLionel Sambuc 	int res;
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc 	event = malloc(sizeof(struct devman_event));
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc 	if (event == NULL) {
84433d6423SLionel Sambuc 		panic("devman_device_remove_event: out of memory\n");
85433d6423SLionel Sambuc 	}
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc 	memset(event, 0, sizeof(*event));
88433d6423SLionel Sambuc 
89433d6423SLionel Sambuc 	strncpy(event->data, ADD_STRING, DEVMAN_STRING_LEN - 1);
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc 	res = devman_generate_path(event->data, DEVMAN_STRING_LEN - 11 , dev);
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc 	if (res) {
94433d6423SLionel Sambuc 		panic("devman_device_add_event: "
95433d6423SLionel Sambuc 		    "devman_generate_path failed: (%d)\n", res);
96433d6423SLionel Sambuc 	}
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc 	snprintf(buf, 12, " 0x%08x", dev->dev_id);
99433d6423SLionel Sambuc 	strcat(event->data,buf);
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc 	TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
102433d6423SLionel Sambuc }
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc /*===========================================================================*
105433d6423SLionel Sambuc  *          devman_device_remove_event                                       *
106433d6423SLionel Sambuc  *===========================================================================*/
107433d6423SLionel Sambuc static void
devman_device_remove_event(struct devman_device * dev)108433d6423SLionel Sambuc devman_device_remove_event(struct devman_device* dev)
109433d6423SLionel Sambuc {
110433d6423SLionel Sambuc 	struct devman_event * event;
111433d6423SLionel Sambuc 	char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
112433d6423SLionel Sambuc 	int res;
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc 	event = malloc(sizeof(struct devman_event));
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc 	if (event == NULL) {
117433d6423SLionel Sambuc 		panic("devman_device_remove_event: out of memory\n");
118433d6423SLionel Sambuc 	}
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc 	memset(event, 0, sizeof(*event));
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc 	strncpy(event->data, REMOVE_STRING, DEVMAN_STRING_LEN - 1);
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc 	res = devman_generate_path(event->data, DEVMAN_STRING_LEN-11, dev);
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc 	if (res) {
127433d6423SLionel Sambuc 		panic("devman_device_remove_event: "
128433d6423SLionel Sambuc 		    "devman_generate_path failed: (%d)\n", res);
129433d6423SLionel Sambuc 	}
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc 	snprintf(buf, 12, " 0x%08x", dev->dev_id);
132433d6423SLionel Sambuc 	strcat(event->data,buf);
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc 	TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
136433d6423SLionel Sambuc }
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc /*===========================================================================*
139433d6423SLionel Sambuc  *          devman_event_read                                                *
140433d6423SLionel Sambuc  *===========================================================================*/
141*5eefd0feSDavid van Moolenbroek static ssize_t
devman_event_read(char * ptr,size_t len,off_t offset,void * data)142*5eefd0feSDavid van Moolenbroek devman_event_read(char *ptr, size_t len, off_t offset, void *data)
143433d6423SLionel Sambuc {
144433d6423SLionel Sambuc 	struct devman_event *ev = NULL;
145433d6423SLionel Sambuc 	struct devman_event_inode *n;
146*5eefd0feSDavid van Moolenbroek 	ssize_t r;
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 	n = (struct devman_event_inode *) data;
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc 	if (!TAILQ_EMPTY(&n->event_queue)) {
151433d6423SLionel Sambuc 		ev = TAILQ_LAST(&n->event_queue, event_head);
152433d6423SLionel Sambuc 	}
153433d6423SLionel Sambuc 
154*5eefd0feSDavid van Moolenbroek 	buf_init(ptr, len, offset);
15510b1b4eeSDavid van Moolenbroek 	if (ev != NULL)
156433d6423SLionel Sambuc 		buf_printf("%s", ev->data);
157433d6423SLionel Sambuc 
158*5eefd0feSDavid van Moolenbroek 	r = buf_result();
159433d6423SLionel Sambuc 
16010b1b4eeSDavid van Moolenbroek 	/* read all (EOF)? */
161*5eefd0feSDavid van Moolenbroek 	if (ev != NULL && r == 0) {
16210b1b4eeSDavid van Moolenbroek 		TAILQ_REMOVE(&n->event_queue, ev, events);
16310b1b4eeSDavid van Moolenbroek 		free(ev);
16410b1b4eeSDavid van Moolenbroek 	}
16510b1b4eeSDavid van Moolenbroek 
166*5eefd0feSDavid van Moolenbroek 	return r;
167433d6423SLionel Sambuc }
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc /*===========================================================================*
170433d6423SLionel Sambuc  *          devman_static_info_read                                          *
171433d6423SLionel Sambuc  *===========================================================================*/
172*5eefd0feSDavid van Moolenbroek static ssize_t
devman_static_info_read(char * ptr,size_t len,off_t offset,void * data)173*5eefd0feSDavid van Moolenbroek devman_static_info_read(char *ptr, size_t len, off_t offset, void *data)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc 	struct devman_static_info_inode *n;
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc 	n = (struct devman_static_info_inode *) data;
178433d6423SLionel Sambuc 
179*5eefd0feSDavid van Moolenbroek 	buf_init(ptr, len, offset);
180433d6423SLionel Sambuc 	buf_printf("%s\n", n->data);
181*5eefd0feSDavid van Moolenbroek 	return buf_result();
182433d6423SLionel Sambuc }
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc /*===========================================================================*
185433d6423SLionel Sambuc  *           devman_init_devices                                             *
186433d6423SLionel Sambuc  *===========================================================================*/
devman_init_devices()187433d6423SLionel Sambuc void devman_init_devices()
188433d6423SLionel Sambuc {
189433d6423SLionel Sambuc 	event_inode.data   =  &event_inode_data;
190433d6423SLionel Sambuc 	event_inode.read_fn =  devman_event_read;
191433d6423SLionel Sambuc 
192433d6423SLionel Sambuc 	root_dev.dev_id =    0;
193433d6423SLionel Sambuc 	root_dev.major  =   -1;
194433d6423SLionel Sambuc 	root_dev.owner  =    0;
195433d6423SLionel Sambuc 	root_dev.parent = NULL;
196433d6423SLionel Sambuc 
197433d6423SLionel Sambuc 	root_dev.inode.inode=
198433d6423SLionel Sambuc 		add_inode(get_root_inode(), "devices",
199433d6423SLionel Sambuc 		    NO_INDEX, &default_dir_stat, 0, &root_dev.inode);
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc 	event_inode.inode=
202433d6423SLionel Sambuc 		add_inode(get_root_inode(), "events",
203433d6423SLionel Sambuc 		    NO_INDEX, &default_file_stat, 0, &event_inode);
204433d6423SLionel Sambuc 
205433d6423SLionel Sambuc 	TAILQ_INIT(&root_dev.children);
206433d6423SLionel Sambuc 	TAILQ_INIT(&root_dev.infos);
207433d6423SLionel Sambuc }
208433d6423SLionel Sambuc 
209433d6423SLionel Sambuc 
210433d6423SLionel Sambuc /*===========================================================================*
211433d6423SLionel Sambuc  *           do_reply                                                        *
212433d6423SLionel Sambuc  *===========================================================================*/
do_reply(message * msg,int res)213433d6423SLionel Sambuc static void do_reply(message *msg, int res)
214433d6423SLionel Sambuc {
215433d6423SLionel Sambuc 	msg->m_type = DEVMAN_REPLY;
216433d6423SLionel Sambuc 	msg->DEVMAN_RESULT = res;
217433d6423SLionel Sambuc 	ipc_send(msg->m_source, msg);
218433d6423SLionel Sambuc }
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc /*===========================================================================*
221433d6423SLionel Sambuc  *           do_add_device                                                   *
222433d6423SLionel Sambuc  *===========================================================================*/
do_add_device(message * msg)223433d6423SLionel Sambuc int do_add_device(message *msg)
224433d6423SLionel Sambuc {
225433d6423SLionel Sambuc 	endpoint_t ep = msg->m_source;
226433d6423SLionel Sambuc 	int res;
227433d6423SLionel Sambuc 	struct devman_device *dev;
228433d6423SLionel Sambuc 	struct devman_device *parent;
229433d6423SLionel Sambuc 	struct devman_device_info *devinf = NULL;
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc 	devinf = malloc(msg->DEVMAN_GRANT_SIZE);
232433d6423SLionel Sambuc 
233433d6423SLionel Sambuc 	if (devinf == NULL) {
234433d6423SLionel Sambuc 		res = ENOMEM;
235433d6423SLionel Sambuc 		do_reply(msg, res);
236433d6423SLionel Sambuc 		return 0;
237433d6423SLionel Sambuc 	}
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc 	res = sys_safecopyfrom(ep, msg->DEVMAN_GRANT_ID,
240433d6423SLionel Sambuc 	          0, (vir_bytes) devinf, msg->DEVMAN_GRANT_SIZE);
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc 	if (res != OK) {
243433d6423SLionel Sambuc 		res = EINVAL;
244433d6423SLionel Sambuc 		free(devinf);
245433d6423SLionel Sambuc 		do_reply(msg, res);
246433d6423SLionel Sambuc 		return 0;
247433d6423SLionel Sambuc 	}
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc 	if ((parent = _find_dev(&root_dev, devinf->parent_dev_id))
250433d6423SLionel Sambuc 		 == NULL) {
251433d6423SLionel Sambuc 		res = ENODEV;
252433d6423SLionel Sambuc 		free(devinf);
253433d6423SLionel Sambuc 		do_reply(msg, res);
254433d6423SLionel Sambuc 		return 0;
255433d6423SLionel Sambuc 	}
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc 	dev = devman_dev_add_child(parent, devinf);
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 	if (dev == NULL) {
260433d6423SLionel Sambuc 		res = ENODEV;
261433d6423SLionel Sambuc 		free(devinf);
262433d6423SLionel Sambuc 		do_reply(msg, res);
263433d6423SLionel Sambuc 		return 0;
264433d6423SLionel Sambuc 	}
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc 	dev->state = DEVMAN_DEVICE_UNBOUND;
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc 	dev->owner = msg->m_source;
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc 	msg->DEVMAN_DEVICE_ID = dev->dev_id;
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc 	devman_device_add_event(dev);
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc 	do_reply(msg, res);
275433d6423SLionel Sambuc 	return 0;
276433d6423SLionel Sambuc }
277433d6423SLionel Sambuc 
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc /*===========================================================================*
280433d6423SLionel Sambuc  *           _find_dev                                                       *
281433d6423SLionel Sambuc  *===========================================================================*/
282433d6423SLionel Sambuc static struct devman_device *
_find_dev(struct devman_device * dev,int dev_id)283433d6423SLionel Sambuc _find_dev(struct devman_device *dev, int dev_id)
284433d6423SLionel Sambuc {
285433d6423SLionel Sambuc 	struct devman_device *_dev;
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 	if(dev->dev_id == dev_id)
288433d6423SLionel Sambuc 		return dev;
289433d6423SLionel Sambuc 
290433d6423SLionel Sambuc 	TAILQ_FOREACH(_dev, &dev->children, siblings) {
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc 		struct devman_device *t = _find_dev(_dev, dev_id);
293433d6423SLionel Sambuc 
294433d6423SLionel Sambuc 		if (t !=NULL) {
295433d6423SLionel Sambuc 			return t;
296433d6423SLionel Sambuc 		}
297433d6423SLionel Sambuc 	}
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc 	return NULL;
300433d6423SLionel Sambuc }
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc /*===========================================================================*
303433d6423SLionel Sambuc  *           devman_find_dev                                                 *
304433d6423SLionel Sambuc  *===========================================================================*/
devman_find_device(int dev_id)305433d6423SLionel Sambuc struct devman_device *devman_find_device(int dev_id)
306433d6423SLionel Sambuc {
307433d6423SLionel Sambuc 	return _find_dev(&root_dev, dev_id);
308433d6423SLionel Sambuc }
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc /*===========================================================================*
311433d6423SLionel Sambuc  *           devman_dev_add_static_info                                      *
312433d6423SLionel Sambuc  *===========================================================================*/
313433d6423SLionel Sambuc static int
devman_dev_add_static_info(struct devman_device * dev,char * name,char * data)314433d6423SLionel Sambuc devman_dev_add_static_info
315433d6423SLionel Sambuc (struct devman_device *dev, char * name, char *data)
316433d6423SLionel Sambuc {
317433d6423SLionel Sambuc 	struct devman_inode *inode;
318433d6423SLionel Sambuc 	struct devman_static_info_inode *st_inode;
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc 	st_inode          = malloc(sizeof(struct devman_static_info_inode));
322433d6423SLionel Sambuc 	st_inode->dev     = dev;
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc 	strncpy(st_inode->data, data, DEVMAN_STRING_LEN);
325433d6423SLionel Sambuc 	/* if string is longer it's truncated */
326433d6423SLionel Sambuc 	st_inode->data[DEVMAN_STRING_LEN-1] = 0;
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc 	inode          = malloc (sizeof(struct devman_inode));
329433d6423SLionel Sambuc 	inode->data    = st_inode;
330433d6423SLionel Sambuc 	inode->read_fn = devman_static_info_read;
331433d6423SLionel Sambuc 
332433d6423SLionel Sambuc 	inode->inode = add_inode(dev->inode.inode, name,
333433d6423SLionel Sambuc 			NO_INDEX, &default_file_stat, 0, inode);
334433d6423SLionel Sambuc 
335433d6423SLionel Sambuc 	/* add info to info_list */
336433d6423SLionel Sambuc 	TAILQ_INSERT_HEAD(&dev->infos, inode, inode_list);
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc 	return 0;
339433d6423SLionel Sambuc }
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc /*===========================================================================*
342433d6423SLionel Sambuc  *           devman_dev_add_child                                            *
343433d6423SLionel Sambuc  *===========================================================================*/
344433d6423SLionel Sambuc static struct devman_device*
devman_dev_add_child(struct devman_device * parent,struct devman_device_info * devinf)345433d6423SLionel Sambuc devman_dev_add_child
346433d6423SLionel Sambuc (struct devman_device *parent, struct devman_device_info *devinf)
347433d6423SLionel Sambuc {
348433d6423SLionel Sambuc 	int i;
349433d6423SLionel Sambuc 	char * buffer = (char *) (devinf);
350433d6423SLionel Sambuc 	char tmp_buf[128];
351433d6423SLionel Sambuc 	struct devman_device_info_entry *entries;
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc 	/* create device */
354433d6423SLionel Sambuc 	struct devman_device * dev = malloc(sizeof(struct devman_device));
355433d6423SLionel Sambuc 	if (dev == NULL) {
356433d6423SLionel Sambuc 		panic("devman_dev_add_child: out of memory\n");
357433d6423SLionel Sambuc 	}
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc 	if (parent == NULL) {
361433d6423SLionel Sambuc 		free(dev);
362433d6423SLionel Sambuc 		return NULL;
363433d6423SLionel Sambuc 	}
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc 	dev->ref_count = 1;
366433d6423SLionel Sambuc 
367433d6423SLionel Sambuc 	/* set dev_info */
368433d6423SLionel Sambuc 	dev->parent   = parent;
369433d6423SLionel Sambuc 	dev->info = devinf;
370433d6423SLionel Sambuc 
371433d6423SLionel Sambuc     dev->dev_id = next_device_id++;
372433d6423SLionel Sambuc 
373433d6423SLionel Sambuc 	dev->inode.inode =
374433d6423SLionel Sambuc 		add_inode(parent->inode.inode, buffer + devinf->name_offset,
375433d6423SLionel Sambuc 		    NO_INDEX, &default_dir_stat, 0, &dev->inode);
376433d6423SLionel Sambuc 
377433d6423SLionel Sambuc 	TAILQ_INIT(&dev->children);
378433d6423SLionel Sambuc 	TAILQ_INIT(&dev->infos);
379433d6423SLionel Sambuc 
380433d6423SLionel Sambuc 	/* create information inodes */
381433d6423SLionel Sambuc 	entries = (struct devman_device_info_entry *)
382433d6423SLionel Sambuc 		(buffer + sizeof(struct devman_device_info));
383433d6423SLionel Sambuc 
384433d6423SLionel Sambuc 	for (i = 0; i < devinf->count ; i++) {
385433d6423SLionel Sambuc 		devman_dev_add_info(dev, &entries[i], buffer);
386433d6423SLionel Sambuc 	}
387433d6423SLionel Sambuc 
388433d6423SLionel Sambuc 	/* make device ID accessible to user land */
389433d6423SLionel Sambuc 	snprintf(tmp_buf, DEVMAN_STRING_LEN, "%d",dev->dev_id);
390433d6423SLionel Sambuc 	devman_dev_add_static_info(dev, "devman_id", tmp_buf);
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc 	TAILQ_INSERT_HEAD(&parent->children, dev, siblings);
393433d6423SLionel Sambuc 
394433d6423SLionel Sambuc 	devman_get_device(parent);
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc 	/* FUTURE TODO: create links(BUS, etc) */
397433d6423SLionel Sambuc 	return dev;
398433d6423SLionel Sambuc }
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc /*===========================================================================*
401433d6423SLionel Sambuc  *           devman_dev_add_info                                             *
402433d6423SLionel Sambuc  *===========================================================================*/
403433d6423SLionel Sambuc static int
devman_dev_add_info(struct devman_device * dev,struct devman_device_info_entry * entry,char * buf)404433d6423SLionel Sambuc devman_dev_add_info
405433d6423SLionel Sambuc (struct devman_device *dev, struct devman_device_info_entry *entry, char *buf)
406433d6423SLionel Sambuc {
407433d6423SLionel Sambuc 	switch(entry->type) {
408433d6423SLionel Sambuc 
409433d6423SLionel Sambuc 	case DEVMAN_DEVINFO_STATIC:
410433d6423SLionel Sambuc 			return devman_dev_add_static_info(dev,
411433d6423SLionel Sambuc 			    buf + entry->name_offset, buf + entry->data_offset);
412433d6423SLionel Sambuc 
413433d6423SLionel Sambuc 	case DEVMAN_DEVINFO_DYNAMIC:
414433d6423SLionel Sambuc 		/* TODO */
415433d6423SLionel Sambuc 		/* fall through */
416433d6423SLionel Sambuc 	default:
417433d6423SLionel Sambuc 		return -1;
418433d6423SLionel Sambuc 	}
419433d6423SLionel Sambuc }
420433d6423SLionel Sambuc 
421433d6423SLionel Sambuc /*===========================================================================*
422433d6423SLionel Sambuc  *           do_del_device                                                   *
423433d6423SLionel Sambuc  *===========================================================================*/
do_del_device(message * msg)424433d6423SLionel Sambuc int do_del_device(message *msg)
425433d6423SLionel Sambuc {
426433d6423SLionel Sambuc 	int dev_id = msg->DEVMAN_DEVICE_ID;
427433d6423SLionel Sambuc 
428433d6423SLionel Sambuc 	int res=0;
429433d6423SLionel Sambuc 
430433d6423SLionel Sambuc 	/* only parrent is allowed to add devices */
431433d6423SLionel Sambuc 	struct devman_device *dev = _find_dev(&root_dev, dev_id);
432433d6423SLionel Sambuc 
433433d6423SLionel Sambuc 	if (dev == NULL )  {
434433d6423SLionel Sambuc 		printf("devman: no dev with id %d\n",dev_id);
435433d6423SLionel Sambuc 		res = ENODEV;
436433d6423SLionel Sambuc 	}
437433d6423SLionel Sambuc 
438433d6423SLionel Sambuc #if 0
439433d6423SLionel Sambuc 	if  (dev->parent->owner != ep) {
440433d6423SLionel Sambuc 		res = EPERM;
441433d6423SLionel Sambuc 	}
442433d6423SLionel Sambuc #endif
443433d6423SLionel Sambuc 
444433d6423SLionel Sambuc 	if (!res) {
445433d6423SLionel Sambuc 		devman_device_remove_event(dev);
446433d6423SLionel Sambuc 		if (dev->state == DEVMAN_DEVICE_BOUND) {
447433d6423SLionel Sambuc 			dev->state = DEVMAN_DEVICE_ZOMBIE;
448433d6423SLionel Sambuc 		}
449433d6423SLionel Sambuc 		devman_put_device(dev);
450433d6423SLionel Sambuc 	}
451433d6423SLionel Sambuc 
452433d6423SLionel Sambuc 	do_reply(msg, res);
453433d6423SLionel Sambuc 
454433d6423SLionel Sambuc 	return 0;
455433d6423SLionel Sambuc }
456433d6423SLionel Sambuc 
457433d6423SLionel Sambuc /*===========================================================================*
458433d6423SLionel Sambuc  *           devman_get_device                                               *
459433d6423SLionel Sambuc  *===========================================================================*/
devman_get_device(struct devman_device * dev)460433d6423SLionel Sambuc void devman_get_device(struct devman_device *dev)
461433d6423SLionel Sambuc {
462433d6423SLionel Sambuc 	if (dev == NULL || dev == &root_dev) {
463433d6423SLionel Sambuc 		return;
464433d6423SLionel Sambuc 	}
465433d6423SLionel Sambuc 	dev->ref_count++;
466433d6423SLionel Sambuc }
467433d6423SLionel Sambuc 
468433d6423SLionel Sambuc /*===========================================================================*
469433d6423SLionel Sambuc  *           devman_put_device                                               *
470433d6423SLionel Sambuc  *===========================================================================*/
devman_put_device(struct devman_device * dev)471433d6423SLionel Sambuc void devman_put_device(struct devman_device *dev)
472433d6423SLionel Sambuc {
473433d6423SLionel Sambuc 	if (dev == NULL || dev == &root_dev ) {
474433d6423SLionel Sambuc 		return;
475433d6423SLionel Sambuc 	}
476433d6423SLionel Sambuc 	dev->ref_count--;
477433d6423SLionel Sambuc 	if (dev->ref_count == 0) {
478433d6423SLionel Sambuc 		devman_del_device(dev);
479433d6423SLionel Sambuc 	}
480433d6423SLionel Sambuc }
481433d6423SLionel Sambuc 
482433d6423SLionel Sambuc /*===========================================================================*
483433d6423SLionel Sambuc  *           devman_del_device                                               *
484433d6423SLionel Sambuc  *===========================================================================*/
devman_del_device(struct devman_device * dev)485433d6423SLionel Sambuc static int devman_del_device(struct devman_device *dev)
486433d6423SLionel Sambuc {
487433d6423SLionel Sambuc 	/* does device have children -> error */
488433d6423SLionel Sambuc 	/* evtl. remove links */
489433d6423SLionel Sambuc 
490433d6423SLionel Sambuc 	/* free devinfo inodes */
491433d6423SLionel Sambuc 	struct devman_inode *inode, *_inode;
492433d6423SLionel Sambuc 
493433d6423SLionel Sambuc 	TAILQ_FOREACH_SAFE(inode, &dev->infos, inode_list, _inode) {
494433d6423SLionel Sambuc 
495433d6423SLionel Sambuc 		delete_inode(inode->inode);
496433d6423SLionel Sambuc 
497433d6423SLionel Sambuc 		TAILQ_REMOVE(&dev->infos, inode, inode_list);
498433d6423SLionel Sambuc 
499433d6423SLionel Sambuc 		if (inode->data) {
500433d6423SLionel Sambuc 			free(inode->data);
501433d6423SLionel Sambuc 		}
502433d6423SLionel Sambuc 
503433d6423SLionel Sambuc 		free(inode);
504433d6423SLionel Sambuc 	}
505433d6423SLionel Sambuc 
506433d6423SLionel Sambuc 	/* free device inode */
507433d6423SLionel Sambuc 	delete_inode(dev->inode.inode);
508433d6423SLionel Sambuc 
509433d6423SLionel Sambuc 	/* remove from parent */
510433d6423SLionel Sambuc 	TAILQ_REMOVE(&dev->parent->children, dev, siblings);
511433d6423SLionel Sambuc 
512433d6423SLionel Sambuc 	devman_put_device(dev->parent);
513433d6423SLionel Sambuc 
514433d6423SLionel Sambuc 	/* free devinfo */
515433d6423SLionel Sambuc 	free(dev->info);
516433d6423SLionel Sambuc 
517433d6423SLionel Sambuc 	/* free device */
518433d6423SLionel Sambuc 	free(dev);
519433d6423SLionel Sambuc 	return 0;
520433d6423SLionel Sambuc }
521