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 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 ssize_t 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 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 * 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 *===========================================================================*/ 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 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* 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 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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