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 int 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 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 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 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 int 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 static int eof = 0; 147 148 if (eof) { 149 *len=0; 150 eof = 0; 151 return 0; 152 } 153 n = (struct devman_event_inode *) data; 154 155 if (!TAILQ_EMPTY(&n->event_queue)) { 156 ev = TAILQ_LAST(&n->event_queue, event_head); 157 } 158 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; 167 } 168 } 169 170 *len = buf_get(ptr); 171 172 return 0; 173 } 174 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) 180 { 181 struct devman_static_info_inode *n; 182 183 n = (struct devman_static_info_inode *) data; 184 185 buf_init(offset, *len); 186 buf_printf("%s\n", n->data); 187 *len = buf_get(ptr); 188 return 0; 189 } 190 191 /*===========================================================================* 192 * devman_init_devices * 193 *===========================================================================*/ 194 void devman_init_devices() 195 { 196 event_inode.data = &event_inode_data; 197 event_inode.read_fn = devman_event_read; 198 199 root_dev.dev_id = 0; 200 root_dev.major = -1; 201 root_dev.owner = 0; 202 root_dev.parent = NULL; 203 204 root_dev.inode.inode= 205 add_inode(get_root_inode(), "devices", 206 NO_INDEX, &default_dir_stat, 0, &root_dev.inode); 207 208 event_inode.inode= 209 add_inode(get_root_inode(), "events", 210 NO_INDEX, &default_file_stat, 0, &event_inode); 211 212 TAILQ_INIT(&root_dev.children); 213 TAILQ_INIT(&root_dev.infos); 214 } 215 216 217 /*===========================================================================* 218 * do_reply * 219 *===========================================================================*/ 220 static void do_reply(message *msg, int res) 221 { 222 msg->m_type = DEVMAN_REPLY; 223 msg->DEVMAN_RESULT = res; 224 ipc_send(msg->m_source, msg); 225 } 226 227 /*===========================================================================* 228 * do_add_device * 229 *===========================================================================*/ 230 int do_add_device(message *msg) 231 { 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; 237 238 devinf = malloc(msg->DEVMAN_GRANT_SIZE); 239 240 if (devinf == NULL) { 241 res = ENOMEM; 242 do_reply(msg, res); 243 return 0; 244 } 245 246 res = sys_safecopyfrom(ep, msg->DEVMAN_GRANT_ID, 247 0, (vir_bytes) devinf, msg->DEVMAN_GRANT_SIZE); 248 249 if (res != OK) { 250 res = EINVAL; 251 free(devinf); 252 do_reply(msg, res); 253 return 0; 254 } 255 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; 262 } 263 264 dev = devman_dev_add_child(parent, devinf); 265 266 if (dev == NULL) { 267 res = ENODEV; 268 free(devinf); 269 do_reply(msg, res); 270 return 0; 271 } 272 273 dev->state = DEVMAN_DEVICE_UNBOUND; 274 275 dev->owner = msg->m_source; 276 277 msg->DEVMAN_DEVICE_ID = dev->dev_id; 278 279 devman_device_add_event(dev); 280 281 do_reply(msg, res); 282 return 0; 283 } 284 285 286 /*===========================================================================* 287 * _find_dev * 288 *===========================================================================*/ 289 static struct devman_device * 290 _find_dev(struct devman_device *dev, int dev_id) 291 { 292 struct devman_device *_dev; 293 294 if(dev->dev_id == dev_id) 295 return dev; 296 297 TAILQ_FOREACH(_dev, &dev->children, siblings) { 298 299 struct devman_device *t = _find_dev(_dev, dev_id); 300 301 if (t !=NULL) { 302 return t; 303 } 304 } 305 306 return NULL; 307 } 308 309 /*===========================================================================* 310 * devman_find_dev * 311 *===========================================================================*/ 312 struct devman_device *devman_find_device(int dev_id) 313 { 314 return _find_dev(&root_dev, dev_id); 315 } 316 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) 323 { 324 struct devman_inode *inode; 325 struct devman_static_info_inode *st_inode; 326 327 328 st_inode = malloc(sizeof(struct devman_static_info_inode)); 329 st_inode->dev = dev; 330 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; 334 335 inode = malloc (sizeof(struct devman_inode)); 336 inode->data = st_inode; 337 inode->read_fn = devman_static_info_read; 338 339 inode->inode = add_inode(dev->inode.inode, name, 340 NO_INDEX, &default_file_stat, 0, inode); 341 342 /* add info to info_list */ 343 TAILQ_INSERT_HEAD(&dev->infos, inode, inode_list); 344 345 return 0; 346 } 347 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) 354 { 355 int i; 356 char * buffer = (char *) (devinf); 357 char tmp_buf[128]; 358 struct devman_device_info_entry *entries; 359 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"); 364 } 365 366 367 if (parent == NULL) { 368 free(dev); 369 return NULL; 370 } 371 372 dev->ref_count = 1; 373 374 /* set dev_info */ 375 dev->parent = parent; 376 dev->info = devinf; 377 378 dev->dev_id = next_device_id++; 379 380 dev->inode.inode = 381 add_inode(parent->inode.inode, buffer + devinf->name_offset, 382 NO_INDEX, &default_dir_stat, 0, &dev->inode); 383 384 TAILQ_INIT(&dev->children); 385 TAILQ_INIT(&dev->infos); 386 387 /* create information inodes */ 388 entries = (struct devman_device_info_entry *) 389 (buffer + sizeof(struct devman_device_info)); 390 391 for (i = 0; i < devinf->count ; i++) { 392 devman_dev_add_info(dev, &entries[i], buffer); 393 } 394 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); 398 399 TAILQ_INSERT_HEAD(&parent->children, dev, siblings); 400 401 devman_get_device(parent); 402 403 /* FUTURE TODO: create links(BUS, etc) */ 404 return dev; 405 } 406 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) 413 { 414 switch(entry->type) { 415 416 case DEVMAN_DEVINFO_STATIC: 417 return devman_dev_add_static_info(dev, 418 buf + entry->name_offset, buf + entry->data_offset); 419 420 case DEVMAN_DEVINFO_DYNAMIC: 421 /* TODO */ 422 /* fall through */ 423 default: 424 return -1; 425 } 426 } 427 428 /*===========================================================================* 429 * do_del_device * 430 *===========================================================================*/ 431 int do_del_device(message *msg) 432 { 433 int dev_id = msg->DEVMAN_DEVICE_ID; 434 435 int res=0; 436 437 /* only parrent is allowed to add devices */ 438 struct devman_device *dev = _find_dev(&root_dev, dev_id); 439 440 if (dev == NULL ) { 441 printf("devman: no dev with id %d\n",dev_id); 442 res = ENODEV; 443 } 444 445 #if 0 446 if (dev->parent->owner != ep) { 447 res = EPERM; 448 } 449 #endif 450 451 if (!res) { 452 devman_device_remove_event(dev); 453 if (dev->state == DEVMAN_DEVICE_BOUND) { 454 dev->state = DEVMAN_DEVICE_ZOMBIE; 455 } 456 devman_put_device(dev); 457 } 458 459 do_reply(msg, res); 460 461 return 0; 462 } 463 464 /*===========================================================================* 465 * devman_get_device * 466 *===========================================================================*/ 467 void devman_get_device(struct devman_device *dev) 468 { 469 if (dev == NULL || dev == &root_dev) { 470 return; 471 } 472 dev->ref_count++; 473 } 474 475 /*===========================================================================* 476 * devman_put_device * 477 *===========================================================================*/ 478 void devman_put_device(struct devman_device *dev) 479 { 480 if (dev == NULL || dev == &root_dev ) { 481 return; 482 } 483 dev->ref_count--; 484 if (dev->ref_count == 0) { 485 devman_del_device(dev); 486 } 487 } 488 489 /*===========================================================================* 490 * devman_del_device * 491 *===========================================================================*/ 492 static int devman_del_device(struct devman_device *dev) 493 { 494 /* does device have children -> error */ 495 /* evtl. remove links */ 496 497 /* free devinfo inodes */ 498 struct devman_inode *inode, *_inode; 499 500 TAILQ_FOREACH_SAFE(inode, &dev->infos, inode_list, _inode) { 501 502 delete_inode(inode->inode); 503 504 TAILQ_REMOVE(&dev->infos, inode, inode_list); 505 506 if (inode->data) { 507 free(inode->data); 508 } 509 510 free(inode); 511 } 512 513 /* free device inode */ 514 delete_inode(dev->inode.inode); 515 516 /* remove from parent */ 517 TAILQ_REMOVE(&dev->parent->children, dev, siblings); 518 519 devman_put_device(dev->parent); 520 521 /* free devinfo */ 522 free(dev->info); 523 524 /* free device */ 525 free(dev); 526 return 0; 527 } 528