unstack - fix ipcvecs
[minix.git] / servers / devman / device.c
blob37cb5c238273912d671fff254daa67f89e974a74
1 #include "devman.h"
2 #include "proto.h"
5 static struct devman_device*devman_dev_add_child(struct devman_device
6 *parent, struct devman_device_info *devinf);
7 static struct devman_device *_find_dev(struct devman_device *dev, int
8 dev_id);
9 static int devman_dev_add_info(struct devman_device *dev, struct
10 devman_device_info_entry *entry, char *buf);
11 static int devman_event_read(char **ptr, size_t *len,off_t offset, void
12 *data);
14 static int devman_del_device(struct devman_device *dev);
16 static int next_device_id = 1;
18 static struct inode_stat default_dir_stat = {
19 /* .mode = */ S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH,
20 /* .uid = */ 0,
21 /* .gid = */ 0,
22 /* .size = */ 0,
23 /* .dev = */ NO_DEV,
26 static struct inode_stat default_file_stat = {
27 /* .mode = */ S_IFREG | S_IRUSR | S_IRGRP | S_IROTH,
28 /* .uid = */ 0,
29 /* .gid = */ 0,
30 /* .size = */ 0x1000,
31 /* .dev = */ NO_DEV,
35 static struct devman_device root_dev;
36 static struct devman_event_inode event_inode_data = {
37 TAILQ_HEAD_INITIALIZER(event_inode_data.event_queue),
39 static struct devman_inode event_inode;
41 /*===========================================================================*
42 * devman_generate_path *
43 *===========================================================================*/
44 static int
45 devman_generate_path(char* buf, int len, struct devman_device *dev)
47 int res =0;
48 const char * name = ".";
49 const char * sep = "/";
51 if (dev != NULL) {
52 res = devman_generate_path(buf, len, dev->parent);
53 if (res != 0) {
54 return res;
56 name = get_inode_name(dev->inode.inode);
57 } else {
60 /* does it fit? */
61 if (strlen(buf) + strlen(name) + strlen(sep) + 1 > len) {
62 return ENOMEM;
65 strcat(buf, name);
66 strcat(buf, sep);
68 return 0;
71 /*===========================================================================*
72 * devman_device_add_event *
73 *===========================================================================*/
74 static void
75 devman_device_add_event(struct devman_device* dev)
77 struct devman_event * event;
78 char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
79 int res;
81 event = malloc(sizeof(struct devman_event));
83 if (event == NULL) {
84 panic("devman_device_remove_event: out of memory\n");
87 memset(event, 0, sizeof(*event));
89 strncpy(event->data, ADD_STRING, DEVMAN_STRING_LEN - 1);
91 res = devman_generate_path(event->data, DEVMAN_STRING_LEN - 11 , dev);
93 if (res) {
94 panic("devman_device_add_event: "
95 "devman_generate_path failed: (%d)\n", res);
98 snprintf(buf, 12, " 0x%08x", dev->dev_id);
99 strcat(event->data,buf);
101 TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
104 /*===========================================================================*
105 * devman_device_remove_event *
106 *===========================================================================*/
107 static void
108 devman_device_remove_event(struct devman_device* dev)
110 struct devman_event * event;
111 char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
112 int res;
114 event = malloc(sizeof(struct devman_event));
116 if (event == NULL) {
117 panic("devman_device_remove_event: out of memory\n");
120 memset(event, 0, sizeof(*event));
122 strncpy(event->data, REMOVE_STRING, DEVMAN_STRING_LEN - 1);
124 res = devman_generate_path(event->data, DEVMAN_STRING_LEN-11, dev);
126 if (res) {
127 panic("devman_device_remove_event: "
128 "devman_generate_path failed: (%d)\n", res);
131 snprintf(buf, 12, " 0x%08x", dev->dev_id);
132 strcat(event->data,buf);
135 TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
138 /*===========================================================================*
139 * devman_event_read *
140 *===========================================================================*/
141 static int
142 devman_event_read(char **ptr, size_t *len,off_t offset, void *data)
144 struct devman_event *ev = NULL;
145 struct devman_event_inode *n;
146 static int eof = 0;
148 if (eof) {
149 *len=0;
150 eof = 0;
151 return 0;
153 n = (struct devman_event_inode *) data;
155 if (!TAILQ_EMPTY(&n->event_queue)) {
156 ev = TAILQ_LAST(&n->event_queue, event_head);
159 buf_init(offset, *len);
160 if (ev != NULL) {
161 buf_printf("%s", ev->data);
162 /* read all? */
163 if (*len + offset >= strlen(ev->data)) {
164 TAILQ_REMOVE(&n->event_queue, ev, events);
165 free(ev);
166 eof = 1;
170 *len = buf_get(ptr);
172 return 0;
175 /*===========================================================================*
176 * devman_static_info_read *
177 *===========================================================================*/
178 static int
179 devman_static_info_read(char **ptr, size_t *len, off_t offset, void *data)
181 struct devman_static_info_inode *n;
183 n = (struct devman_static_info_inode *) data;
185 buf_init(offset, *len);
186 buf_printf("%s\n", n->data);
187 *len = buf_get(ptr);
188 return 0;
191 /*===========================================================================*
192 * devman_init_devices *
193 *===========================================================================*/
194 void devman_init_devices()
196 event_inode.data = &event_inode_data;
197 event_inode.read_fn = devman_event_read;
199 root_dev.dev_id = 0;
200 root_dev.major = -1;
201 root_dev.owner = 0;
202 root_dev.parent = NULL;
204 root_dev.inode.inode=
205 add_inode(get_root_inode(), "devices",
206 NO_INDEX, &default_dir_stat, 0, &root_dev.inode);
208 event_inode.inode=
209 add_inode(get_root_inode(), "events",
210 NO_INDEX, &default_file_stat, 0, &event_inode);
212 TAILQ_INIT(&root_dev.children);
213 TAILQ_INIT(&root_dev.infos);
217 /*===========================================================================*
218 * do_reply *
219 *===========================================================================*/
220 static void do_reply(message *msg, int res)
222 msg->m_type = DEVMAN_REPLY;
223 msg->DEVMAN_RESULT = res;
224 send(msg->m_source, msg);
227 /*===========================================================================*
228 * do_add_device *
229 *===========================================================================*/
230 int do_add_device(message *msg)
232 endpoint_t ep = msg->m_source;
233 int res;
234 struct devman_device *dev;
235 struct devman_device *parent;
236 struct devman_device_info *devinf = NULL;
238 devinf = malloc(msg->DEVMAN_GRANT_SIZE);
240 if (devinf == NULL) {
241 res = ENOMEM;
242 do_reply(msg, res);
243 return 0;
246 res = sys_safecopyfrom(ep, msg->DEVMAN_GRANT_ID,
247 0, (vir_bytes) devinf, msg->DEVMAN_GRANT_SIZE);
249 if (res != OK) {
250 res = EINVAL;
251 free(devinf);
252 do_reply(msg, res);
253 return 0;
256 if ((parent = _find_dev(&root_dev, devinf->parent_dev_id))
257 == NULL) {
258 res = ENODEV;
259 free(devinf);
260 do_reply(msg, res);
261 return 0;
264 dev = devman_dev_add_child(parent, devinf);
266 if (dev == NULL) {
267 res = ENODEV;
268 free(devinf);
269 do_reply(msg, res);
270 return 0;
273 dev->state = DEVMAN_DEVICE_UNBOUND;
275 dev->owner = msg->m_source;
277 msg->DEVMAN_DEVICE_ID = dev->dev_id;
279 devman_device_add_event(dev);
281 do_reply(msg, res);
282 return 0;
286 /*===========================================================================*
287 * _find_dev *
288 *===========================================================================*/
289 static struct devman_device *
290 _find_dev(struct devman_device *dev, int dev_id)
292 struct devman_device *_dev;
294 if(dev->dev_id == dev_id)
295 return dev;
297 TAILQ_FOREACH(_dev, &dev->children, siblings) {
299 struct devman_device *t = _find_dev(_dev, dev_id);
301 if (t !=NULL) {
302 return t;
306 return NULL;
309 /*===========================================================================*
310 * devman_find_dev *
311 *===========================================================================*/
312 struct devman_device *devman_find_device(int dev_id)
314 return _find_dev(&root_dev, dev_id);
317 /*===========================================================================*
318 * devman_dev_add_static_info *
319 *===========================================================================*/
320 static int
321 devman_dev_add_static_info
322 (struct devman_device *dev, char * name, char *data)
324 struct devman_inode *inode;
325 struct devman_static_info_inode *st_inode;
328 st_inode = malloc(sizeof(struct devman_static_info_inode));
329 st_inode->dev = dev;
331 strncpy(st_inode->data, data, DEVMAN_STRING_LEN);
332 /* if string is longer it's truncated */
333 st_inode->data[DEVMAN_STRING_LEN-1] = 0;
335 inode = malloc (sizeof(struct devman_inode));
336 inode->data = st_inode;
337 inode->read_fn = devman_static_info_read;
339 inode->inode = add_inode(dev->inode.inode, name,
340 NO_INDEX, &default_file_stat, 0, inode);
342 /* add info to info_list */
343 TAILQ_INSERT_HEAD(&dev->infos, inode, inode_list);
345 return 0;
348 /*===========================================================================*
349 * devman_dev_add_child *
350 *===========================================================================*/
351 static struct devman_device*
352 devman_dev_add_child
353 (struct devman_device *parent, struct devman_device_info *devinf)
355 int i;
356 char * buffer = (char *) (devinf);
357 char tmp_buf[128];
358 struct devman_device_info_entry *entries;
360 /* create device */
361 struct devman_device * dev = malloc(sizeof(struct devman_device));
362 if (dev == NULL) {
363 panic("devman_dev_add_child: out of memory\n");
367 if (parent == NULL) {
368 free(dev);
369 return NULL;
372 dev->ref_count = 1;
374 /* set dev_info */
375 dev->parent = parent;
376 dev->info = devinf;
378 dev->dev_id = next_device_id++;
380 dev->inode.inode =
381 add_inode(parent->inode.inode, buffer + devinf->name_offset,
382 NO_INDEX, &default_dir_stat, 0, &dev->inode);
384 TAILQ_INIT(&dev->children);
385 TAILQ_INIT(&dev->infos);
387 /* create information inodes */
388 entries = (struct devman_device_info_entry *)
389 (buffer + sizeof(struct devman_device_info));
391 for (i = 0; i < devinf->count ; i++) {
392 devman_dev_add_info(dev, &entries[i], buffer);
395 /* make device ID accessible to user land */
396 snprintf(tmp_buf, DEVMAN_STRING_LEN, "%d",dev->dev_id);
397 devman_dev_add_static_info(dev, "devman_id", tmp_buf);
399 TAILQ_INSERT_HEAD(&parent->children, dev, siblings);
401 devman_get_device(parent);
403 /* FUTURE TODO: create links(BUS, etc) */
404 return dev;
407 /*===========================================================================*
408 * devman_dev_add_info *
409 *===========================================================================*/
410 static int
411 devman_dev_add_info
412 (struct devman_device *dev, struct devman_device_info_entry *entry, char *buf)
414 switch(entry->type) {
416 case DEVMAN_DEVINFO_STATIC:
417 return devman_dev_add_static_info(dev,
418 buf + entry->name_offset, buf + entry->data_offset);
420 case DEVMAN_DEVINFO_DYNAMIC:
421 /* TODO */
422 /* fall through */
423 default:
424 return -1;
428 /*===========================================================================*
429 * do_del_device *
430 *===========================================================================*/
431 int do_del_device(message *msg)
433 int dev_id = msg->DEVMAN_DEVICE_ID;
435 int res=0;
437 /* only parrent is allowed to add devices */
438 struct devman_device *dev = _find_dev(&root_dev, dev_id);
440 if (dev == NULL ) {
441 printf("devman: no dev with id %d\n",dev_id);
442 res = ENODEV;
445 #if 0
446 if (dev->parent->owner != ep) {
447 res = EPERM;
449 #endif
451 if (!res) {
452 devman_device_remove_event(dev);
453 if (dev->state == DEVMAN_DEVICE_BOUND) {
454 dev->state = DEVMAN_DEVICE_ZOMBIE;
456 devman_put_device(dev);
459 do_reply(msg, res);
461 return 0;
464 /*===========================================================================*
465 * devman_get_device *
466 *===========================================================================*/
467 void devman_get_device(struct devman_device *dev)
469 if (dev == NULL || dev == &root_dev) {
470 return;
472 dev->ref_count++;
475 /*===========================================================================*
476 * devman_put_device *
477 *===========================================================================*/
478 void devman_put_device(struct devman_device *dev)
480 if (dev == NULL || dev == &root_dev ) {
481 return;
483 dev->ref_count--;
484 if (dev->ref_count == 0) {
485 devman_del_device(dev);
489 /*===========================================================================*
490 * devman_del_device *
491 *===========================================================================*/
492 static int devman_del_device(struct devman_device *dev)
494 /* does device have children -> error */
495 /* evtl. remove links */
497 /* free devinfo inodes */
498 struct devman_inode *inode, *_inode;
500 TAILQ_FOREACH_SAFE(inode, &dev->infos, inode_list, _inode) {
502 delete_inode(inode->inode);
504 TAILQ_REMOVE(&dev->infos, inode, inode_list);
506 if (inode->data) {
507 free(inode->data);
510 free(inode);
513 /* free device inode */
514 delete_inode(dev->inode.inode);
516 /* remove from parent */
517 TAILQ_REMOVE(&dev->parent->children, dev, siblings);
519 devman_put_device(dev->parent);
521 /* free devinfo */
522 free(dev->info);
524 /* free device */
525 free(dev);
526 return 0;