1 #include "devman.h"
2 #include "proto.h"
3
4
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 ssize_t devman_event_read(char *ptr, size_t len, off_t offset, void
12 *data);
13
14 static int devman_del_device(struct devman_device *dev);
15
16 static int next_device_id = 1;
17
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,
24 };
25
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,
32 };
33
34
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),
38 };
39 static struct devman_inode event_inode;
40
41 /*===========================================================================*
42 * devman_generate_path *
43 *===========================================================================*/
44 static int
devman_generate_path(char * buf,int len,struct devman_device * dev)45 devman_generate_path(char* buf, int len, struct devman_device *dev)
46 {
47 int res =0;
48 const char * name = ".";
49 const char * sep = "/";
50
51 if (dev != NULL) {
52 res = devman_generate_path(buf, len, dev->parent);
53 if (res != 0) {
54 return res;
55 }
56 name = get_inode_name(dev->inode.inode);
57 } else {
58 }
59
60 /* does it fit? */
61 if (strlen(buf) + strlen(name) + strlen(sep) + 1 > len) {
62 return ENOMEM;
63 }
64
65 strcat(buf, name);
66 strcat(buf, sep);
67
68 return 0;
69 }
70
71 /*===========================================================================*
72 * devman_device_add_event *
73 *===========================================================================*/
74 static void
devman_device_add_event(struct devman_device * dev)75 devman_device_add_event(struct devman_device* dev)
76 {
77 struct devman_event * event;
78 char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
79 int res;
80
81 event = malloc(sizeof(struct devman_event));
82
83 if (event == NULL) {
84 panic("devman_device_remove_event: out of memory\n");
85 }
86
87 memset(event, 0, sizeof(*event));
88
89 strncpy(event->data, ADD_STRING, DEVMAN_STRING_LEN - 1);
90
91 res = devman_generate_path(event->data, DEVMAN_STRING_LEN - 11 , dev);
92
93 if (res) {
94 panic("devman_device_add_event: "
95 "devman_generate_path failed: (%d)\n", res);
96 }
97
98 snprintf(buf, 12, " 0x%08x", dev->dev_id);
99 strcat(event->data,buf);
100
101 TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
102 }
103
104 /*===========================================================================*
105 * devman_device_remove_event *
106 *===========================================================================*/
107 static void
devman_device_remove_event(struct devman_device * dev)108 devman_device_remove_event(struct devman_device* dev)
109 {
110 struct devman_event * event;
111 char buf[12]; /* this fits the device ID " 0xXXXXXXXX" */
112 int res;
113
114 event = malloc(sizeof(struct devman_event));
115
116 if (event == NULL) {
117 panic("devman_device_remove_event: out of memory\n");
118 }
119
120 memset(event, 0, sizeof(*event));
121
122 strncpy(event->data, REMOVE_STRING, DEVMAN_STRING_LEN - 1);
123
124 res = devman_generate_path(event->data, DEVMAN_STRING_LEN-11, dev);
125
126 if (res) {
127 panic("devman_device_remove_event: "
128 "devman_generate_path failed: (%d)\n", res);
129 }
130
131 snprintf(buf, 12, " 0x%08x", dev->dev_id);
132 strcat(event->data,buf);
133
134
135 TAILQ_INSERT_HEAD(&event_inode_data.event_queue, event, events);
136 }
137
138 /*===========================================================================*
139 * devman_event_read *
140 *===========================================================================*/
141 static ssize_t
devman_event_read(char * ptr,size_t len,off_t offset,void * data)142 devman_event_read(char *ptr, size_t len, off_t offset, void *data)
143 {
144 struct devman_event *ev = NULL;
145 struct devman_event_inode *n;
146 ssize_t r;
147
148 n = (struct devman_event_inode *) data;
149
150 if (!TAILQ_EMPTY(&n->event_queue)) {
151 ev = TAILQ_LAST(&n->event_queue, event_head);
152 }
153
154 buf_init(ptr, len, offset);
155 if (ev != NULL)
156 buf_printf("%s", ev->data);
157
158 r = buf_result();
159
160 /* read all (EOF)? */
161 if (ev != NULL && r == 0) {
162 TAILQ_REMOVE(&n->event_queue, ev, events);
163 free(ev);
164 }
165
166 return r;
167 }
168
169 /*===========================================================================*
170 * devman_static_info_read *
171 *===========================================================================*/
172 static ssize_t
devman_static_info_read(char * ptr,size_t len,off_t offset,void * data)173 devman_static_info_read(char *ptr, size_t len, off_t offset, void *data)
174 {
175 struct devman_static_info_inode *n;
176
177 n = (struct devman_static_info_inode *) data;
178
179 buf_init(ptr, len, offset);
180 buf_printf("%s\n", n->data);
181 return buf_result();
182 }
183
184 /*===========================================================================*
185 * devman_init_devices *
186 *===========================================================================*/
devman_init_devices()187 void devman_init_devices()
188 {
189 event_inode.data = &event_inode_data;
190 event_inode.read_fn = devman_event_read;
191
192 root_dev.dev_id = 0;
193 root_dev.major = -1;
194 root_dev.owner = 0;
195 root_dev.parent = NULL;
196
197 root_dev.inode.inode=
198 add_inode(get_root_inode(), "devices",
199 NO_INDEX, &default_dir_stat, 0, &root_dev.inode);
200
201 event_inode.inode=
202 add_inode(get_root_inode(), "events",
203 NO_INDEX, &default_file_stat, 0, &event_inode);
204
205 TAILQ_INIT(&root_dev.children);
206 TAILQ_INIT(&root_dev.infos);
207 }
208
209
210 /*===========================================================================*
211 * do_reply *
212 *===========================================================================*/
do_reply(message * msg,int res)213 static void do_reply(message *msg, int res)
214 {
215 msg->m_type = DEVMAN_REPLY;
216 msg->DEVMAN_RESULT = res;
217 ipc_send(msg->m_source, msg);
218 }
219
220 /*===========================================================================*
221 * do_add_device *
222 *===========================================================================*/
do_add_device(message * msg)223 int do_add_device(message *msg)
224 {
225 endpoint_t ep = msg->m_source;
226 int res;
227 struct devman_device *dev;
228 struct devman_device *parent;
229 struct devman_device_info *devinf = NULL;
230
231 devinf = malloc(msg->DEVMAN_GRANT_SIZE);
232
233 if (devinf == NULL) {
234 res = ENOMEM;
235 do_reply(msg, res);
236 return 0;
237 }
238
239 res = sys_safecopyfrom(ep, msg->DEVMAN_GRANT_ID,
240 0, (vir_bytes) devinf, msg->DEVMAN_GRANT_SIZE);
241
242 if (res != OK) {
243 res = EINVAL;
244 free(devinf);
245 do_reply(msg, res);
246 return 0;
247 }
248
249 if ((parent = _find_dev(&root_dev, devinf->parent_dev_id))
250 == NULL) {
251 res = ENODEV;
252 free(devinf);
253 do_reply(msg, res);
254 return 0;
255 }
256
257 dev = devman_dev_add_child(parent, devinf);
258
259 if (dev == NULL) {
260 res = ENODEV;
261 free(devinf);
262 do_reply(msg, res);
263 return 0;
264 }
265
266 dev->state = DEVMAN_DEVICE_UNBOUND;
267
268 dev->owner = msg->m_source;
269
270 msg->DEVMAN_DEVICE_ID = dev->dev_id;
271
272 devman_device_add_event(dev);
273
274 do_reply(msg, res);
275 return 0;
276 }
277
278
279 /*===========================================================================*
280 * _find_dev *
281 *===========================================================================*/
282 static struct devman_device *
_find_dev(struct devman_device * dev,int dev_id)283 _find_dev(struct devman_device *dev, int dev_id)
284 {
285 struct devman_device *_dev;
286
287 if(dev->dev_id == dev_id)
288 return dev;
289
290 TAILQ_FOREACH(_dev, &dev->children, siblings) {
291
292 struct devman_device *t = _find_dev(_dev, dev_id);
293
294 if (t !=NULL) {
295 return t;
296 }
297 }
298
299 return NULL;
300 }
301
302 /*===========================================================================*
303 * devman_find_dev *
304 *===========================================================================*/
devman_find_device(int dev_id)305 struct devman_device *devman_find_device(int dev_id)
306 {
307 return _find_dev(&root_dev, dev_id);
308 }
309
310 /*===========================================================================*
311 * devman_dev_add_static_info *
312 *===========================================================================*/
313 static int
devman_dev_add_static_info(struct devman_device * dev,char * name,char * data)314 devman_dev_add_static_info
315 (struct devman_device *dev, char * name, char *data)
316 {
317 struct devman_inode *inode;
318 struct devman_static_info_inode *st_inode;
319
320
321 st_inode = malloc(sizeof(struct devman_static_info_inode));
322 st_inode->dev = dev;
323
324 strncpy(st_inode->data, data, DEVMAN_STRING_LEN);
325 /* if string is longer it's truncated */
326 st_inode->data[DEVMAN_STRING_LEN-1] = 0;
327
328 inode = malloc (sizeof(struct devman_inode));
329 inode->data = st_inode;
330 inode->read_fn = devman_static_info_read;
331
332 inode->inode = add_inode(dev->inode.inode, name,
333 NO_INDEX, &default_file_stat, 0, inode);
334
335 /* add info to info_list */
336 TAILQ_INSERT_HEAD(&dev->infos, inode, inode_list);
337
338 return 0;
339 }
340
341 /*===========================================================================*
342 * devman_dev_add_child *
343 *===========================================================================*/
344 static struct devman_device*
devman_dev_add_child(struct devman_device * parent,struct devman_device_info * devinf)345 devman_dev_add_child
346 (struct devman_device *parent, struct devman_device_info *devinf)
347 {
348 int i;
349 char * buffer = (char *) (devinf);
350 char tmp_buf[128];
351 struct devman_device_info_entry *entries;
352
353 /* create device */
354 struct devman_device * dev = malloc(sizeof(struct devman_device));
355 if (dev == NULL) {
356 panic("devman_dev_add_child: out of memory\n");
357 }
358
359
360 if (parent == NULL) {
361 free(dev);
362 return NULL;
363 }
364
365 dev->ref_count = 1;
366
367 /* set dev_info */
368 dev->parent = parent;
369 dev->info = devinf;
370
371 dev->dev_id = next_device_id++;
372
373 dev->inode.inode =
374 add_inode(parent->inode.inode, buffer + devinf->name_offset,
375 NO_INDEX, &default_dir_stat, 0, &dev->inode);
376
377 TAILQ_INIT(&dev->children);
378 TAILQ_INIT(&dev->infos);
379
380 /* create information inodes */
381 entries = (struct devman_device_info_entry *)
382 (buffer + sizeof(struct devman_device_info));
383
384 for (i = 0; i < devinf->count ; i++) {
385 devman_dev_add_info(dev, &entries[i], buffer);
386 }
387
388 /* make device ID accessible to user land */
389 snprintf(tmp_buf, DEVMAN_STRING_LEN, "%d",dev->dev_id);
390 devman_dev_add_static_info(dev, "devman_id", tmp_buf);
391
392 TAILQ_INSERT_HEAD(&parent->children, dev, siblings);
393
394 devman_get_device(parent);
395
396 /* FUTURE TODO: create links(BUS, etc) */
397 return dev;
398 }
399
400 /*===========================================================================*
401 * devman_dev_add_info *
402 *===========================================================================*/
403 static int
devman_dev_add_info(struct devman_device * dev,struct devman_device_info_entry * entry,char * buf)404 devman_dev_add_info
405 (struct devman_device *dev, struct devman_device_info_entry *entry, char *buf)
406 {
407 switch(entry->type) {
408
409 case DEVMAN_DEVINFO_STATIC:
410 return devman_dev_add_static_info(dev,
411 buf + entry->name_offset, buf + entry->data_offset);
412
413 case DEVMAN_DEVINFO_DYNAMIC:
414 /* TODO */
415 /* fall through */
416 default:
417 return -1;
418 }
419 }
420
421 /*===========================================================================*
422 * do_del_device *
423 *===========================================================================*/
do_del_device(message * msg)424 int do_del_device(message *msg)
425 {
426 int dev_id = msg->DEVMAN_DEVICE_ID;
427
428 int res=0;
429
430 /* only parrent is allowed to add devices */
431 struct devman_device *dev = _find_dev(&root_dev, dev_id);
432
433 if (dev == NULL ) {
434 printf("devman: no dev with id %d\n",dev_id);
435 res = ENODEV;
436 }
437
438 #if 0
439 if (dev->parent->owner != ep) {
440 res = EPERM;
441 }
442 #endif
443
444 if (!res) {
445 devman_device_remove_event(dev);
446 if (dev->state == DEVMAN_DEVICE_BOUND) {
447 dev->state = DEVMAN_DEVICE_ZOMBIE;
448 }
449 devman_put_device(dev);
450 }
451
452 do_reply(msg, res);
453
454 return 0;
455 }
456
457 /*===========================================================================*
458 * devman_get_device *
459 *===========================================================================*/
devman_get_device(struct devman_device * dev)460 void devman_get_device(struct devman_device *dev)
461 {
462 if (dev == NULL || dev == &root_dev) {
463 return;
464 }
465 dev->ref_count++;
466 }
467
468 /*===========================================================================*
469 * devman_put_device *
470 *===========================================================================*/
devman_put_device(struct devman_device * dev)471 void devman_put_device(struct devman_device *dev)
472 {
473 if (dev == NULL || dev == &root_dev ) {
474 return;
475 }
476 dev->ref_count--;
477 if (dev->ref_count == 0) {
478 devman_del_device(dev);
479 }
480 }
481
482 /*===========================================================================*
483 * devman_del_device *
484 *===========================================================================*/
devman_del_device(struct devman_device * dev)485 static int devman_del_device(struct devman_device *dev)
486 {
487 /* does device have children -> error */
488 /* evtl. remove links */
489
490 /* free devinfo inodes */
491 struct devman_inode *inode, *_inode;
492
493 TAILQ_FOREACH_SAFE(inode, &dev->infos, inode_list, _inode) {
494
495 delete_inode(inode->inode);
496
497 TAILQ_REMOVE(&dev->infos, inode, inode_list);
498
499 if (inode->data) {
500 free(inode->data);
501 }
502
503 free(inode);
504 }
505
506 /* free device inode */
507 delete_inode(dev->inode.inode);
508
509 /* remove from parent */
510 TAILQ_REMOVE(&dev->parent->children, dev, siblings);
511
512 devman_put_device(dev->parent);
513
514 /* free devinfo */
515 free(dev->info);
516
517 /* free device */
518 free(dev);
519 return 0;
520 }
521