Changeset 6519d6f in mainline
- Timestamp:
- 2009-03-02T17:35:46Z (16 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 8dc72b64
- Parents:
- 1fcfc94
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devmap/devmap.c
r1fcfc94 r6519d6f 29 29 /** 30 30 * @defgroup devmap Device mapper. 31 * @brief 31 * @brief HelenOS device mapper. 32 32 * @{ 33 */ 33 */ 34 34 35 35 /** @file … … 47 47 #include <ipc/devmap.h> 48 48 49 #define NAME "devmap" 50 49 #define NAME "devmap" 50 51 /** Pending lookup structure. */ 52 typedef struct { 53 link_t link; 54 char *name; /**< Device name */ 55 ipc_callid_t callid; /**< Call ID waiting for the lookup */ 56 } pending_req_t; 51 57 52 58 LIST_INITIALIZE(devices_list); 53 59 LIST_INITIALIZE(drivers_list); 54 55 /* order of locking: 56 * drivers_list_futex 57 * devices_list_futex 58 * (devmap_driver_t *)->devices_futex 59 * create_handle_futex 60 LIST_INITIALIZE(pending_req); 61 62 /* Locking order: 63 * drivers_list_futex 64 * devices_list_futex 65 * (devmap_driver_t *)->devices_futex 66 * create_handle_futex 60 67 **/ 61 68 … … 64 71 static atomic_t create_handle_futex = FUTEX_INITIALIZER; 65 72 66 67 73 static int devmap_create_handle(void) 68 74 { 69 75 static int last_handle = 0; 70 76 int handle; 71 77 72 78 /* TODO: allow reusing old handles after their unregistration 73 and implement some version of LRU algorithm */ 79 * and implement some version of LRU algorithm 80 */ 81 74 82 /* FIXME: overflow */ 75 futex_down(&create_handle_futex); 76 83 futex_down(&create_handle_futex); 84 77 85 last_handle += 1; 78 86 handle = last_handle; 79 80 futex_up(&create_handle_futex); 81 87 88 futex_up(&create_handle_futex); 89 82 90 return handle; 83 91 } 84 92 85 93 86 /** Initialize device mapper. 94 /** Initialize device mapper. 87 95 * 88 96 * … … 91 99 { 92 100 /* TODO: */ 93 101 94 102 return EOK; 95 103 } … … 100 108 static devmap_device_t *devmap_device_find_name(const char *name) 101 109 { 102 link_t *item ;110 link_t *item = devices_list.next; 103 111 devmap_device_t *device = NULL; 104 105 item = devices_list.next; 106 112 107 113 while (item != &devices_list) { 108 109 114 device = list_get_instance(item, devmap_device_t, devices); 110 if (0 == strcmp(device->name, name)) { 111 break; 112 } 115 if (0 == strcmp(device->name, name)) 116 break; 113 117 item = item->next; 114 118 } 115 119 116 120 if (item == &devices_list) 117 121 return NULL; 118 122 119 123 device = list_get_instance(item, devmap_device_t, devices); 120 124 return device; … … 122 126 123 127 /** Find device with given handle. 128 * 124 129 * @todo: use hash table 130 * 125 131 */ 126 132 static devmap_device_t *devmap_device_find_handle(int handle) 127 133 { 128 link_t *item; 134 futex_down(&devices_list_futex); 135 136 link_t *item = (&devices_list)->next; 129 137 devmap_device_t *device = NULL; 130 138 131 futex_down(&devices_list_futex);132 133 item = (&devices_list)->next;134 135 139 while (item != &devices_list) { 136 137 140 device = list_get_instance(item, devmap_device_t, devices); 138 if (device->handle == handle) { 139 break; 140 } 141 if (device->handle == handle) 142 break; 141 143 item = item->next; 142 144 } 143 145 144 146 if (item == &devices_list) { 145 147 futex_up(&devices_list_futex); 146 148 return NULL; 147 149 } 148 150 149 151 device = list_get_instance(item, devmap_device_t, devices); 150 152 151 153 futex_up(&devices_list_futex); 152 154 153 155 return device; 154 156 } 155 157 156 158 /** 159 * 157 160 * Unregister device and free it. It's assumed that driver's device list is 158 161 * already locked. 162 * 159 163 */ 160 164 static int devmap_device_unregister_core(devmap_device_t *device) 161 165 { 162 163 166 list_remove(&(device->devices)); 164 167 list_remove(&(device->driver_devices)); 165 166 free(device->name); 168 169 free(device->name); 167 170 free(device); 168 169 171 170 172 return EOK; 171 173 } 172 174 173 175 /** 176 * 174 177 * Read info about new driver and add it into linked list of registered 175 178 * drivers. 179 * 176 180 */ 177 181 static void devmap_driver_register(devmap_driver_t **odriver) 178 182 { 183 *odriver = NULL; 184 185 ipc_call_t icall; 186 ipc_callid_t iid = async_get_call(&icall); 187 188 if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) { 189 ipc_answer_0(iid, EREFUSED); 190 return; 191 } 192 193 devmap_driver_t *driver = (devmap_driver_t *) malloc(sizeof(devmap_driver_t)); 194 195 if (driver == NULL) { 196 ipc_answer_0(iid, ENOMEM); 197 return; 198 } 199 200 /* 201 * Get driver name 202 */ 203 ipc_callid_t callid; 179 204 size_t name_size; 180 ipc_callid_t callid;181 ipc_call_t call;182 devmap_driver_t *driver;183 ipc_callid_t iid;184 ipc_call_t icall;185 186 *odriver = NULL;187 188 iid = async_get_call(&icall);189 190 if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {191 ipc_answer_0(iid, EREFUSED);192 return;193 }194 195 if (NULL ==196 (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {197 ipc_answer_0(iid, ENOMEM);198 return;199 }200 201 /*202 * Get driver name203 */204 205 if (!ipc_data_write_receive(&callid, &name_size)) { 205 206 free(driver); … … 208 209 return; 209 210 } 210 211 211 212 if (name_size > DEVMAP_NAME_MAXLEN) { 212 213 free(driver); … … 215 216 return; 216 217 } 217 218 218 219 /* 219 220 * Allocate buffer for device name. 220 221 */ 221 if (NULL == (driver->name = (char *)malloc(name_size + 1))) { 222 driver->name = (char *) malloc(name_size + 1); 223 if (driver->name == NULL) { 222 224 free(driver); 223 225 ipc_answer_0(callid, ENOMEM); 224 226 ipc_answer_0(iid, EREFUSED); 225 227 return; 226 } 227 228 } 229 228 230 /* 229 231 * Send confirmation to sender and get data into buffer. … … 235 237 return; 236 238 } 237 239 238 240 driver->name[name_size] = 0; 239 241 240 242 /* Initialize futex for list of devices owned by this driver */ 241 243 futex_initialize(&(driver->devices_futex), 1); 242 243 /* 244 245 /* 244 246 * Initialize list of asociated devices 245 247 */ 246 248 list_initialize(&(driver->devices)); 247 248 /* 249 250 /* 249 251 * Create connection to the driver 250 252 */ 253 ipc_call_t call; 251 254 callid = async_get_call(&call); 252 255 253 256 if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) { 254 257 ipc_answer_0(callid, ENOTSUP); … … 259 262 return; 260 263 } 261 264 262 265 driver->phone = IPC_GET_ARG5(call); 263 266 … … 265 268 266 269 list_initialize(&(driver->drivers)); 267 268 futex_down(&drivers_list_futex); 270 271 futex_down(&drivers_list_futex); 269 272 270 273 /* TODO: 271 274 * check that no driver with name equal to driver->name is registered 272 275 */ 273 274 /* 276 277 /* 275 278 * Insert new driver into list of registered drivers 276 279 */ 277 280 list_append(&(driver->drivers), &drivers_list); 278 futex_up(&drivers_list_futex); 281 futex_up(&drivers_list_futex); 279 282 280 283 ipc_answer_0(iid, EOK); 281 284 282 285 *odriver = driver; 283 286 } 284 287 285 /** Unregister device driver, unregister all its devices and free driver 288 /** 289 * Unregister device driver, unregister all its devices and free driver 286 290 * structure. 291 * 287 292 */ 288 293 static int devmap_driver_unregister(devmap_driver_t *driver) 289 294 { 290 devmap_device_t *device; 291 292 if (NULL == driver) 295 if (driver == NULL) 293 296 return EEXISTS; 294 297 295 futex_down(&drivers_list_futex); 296 298 futex_down(&drivers_list_futex); 299 297 300 ipc_hangup(driver->phone); 298 301 299 302 /* remove it from list of drivers */ 300 303 list_remove(&(driver->drivers)); 301 304 302 305 /* unregister all its devices */ 303 306 304 futex_down(&devices_list_futex); 307 futex_down(&devices_list_futex); 305 308 futex_down(&(driver->devices_futex)); 306 309 307 310 while (!list_empty(&(driver->devices))) { 308 dev ice = list_get_instance(driver->devices.next,311 devmap_device_t *device = list_get_instance(driver->devices.next, 309 312 devmap_device_t, driver_devices); 310 313 devmap_device_unregister_core(device); … … 312 315 313 316 futex_up(&(driver->devices_futex)); 314 futex_up(&devices_list_futex); 315 futex_up(&drivers_list_futex); 316 317 futex_up(&devices_list_futex); 318 futex_up(&drivers_list_futex); 319 317 320 /* free name and driver */ 318 if (NULL != driver->name) {321 if (NULL != driver->name) 319 322 free(driver->name); 320 } 321 323 322 324 free(driver); 323 325 324 326 return EOK; 327 } 328 329 330 /** Process pending lookup requests */ 331 static void process_pending_lookup() 332 { 333 link_t *cur; 334 335 loop: 336 for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { 337 pending_req_t *pr = list_get_instance(cur, pending_req_t, link); 338 339 const devmap_device_t *dev = devmap_device_find_name(pr->name); 340 if (!dev) 341 continue; 342 343 ipc_answer_1(pr->callid, EOK, dev->handle); 344 345 free(pr->name); 346 list_remove(cur); 347 free(pr); 348 goto loop; 349 } 325 350 } 326 351 … … 332 357 devmap_driver_t *driver) 333 358 { 359 if (driver == NULL) { 360 ipc_answer_0(iid, EREFUSED); 361 return; 362 } 363 364 /* Create new device entry */ 365 devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t)); 366 if (device == NULL) { 367 ipc_answer_0(iid, ENOMEM); 368 return; 369 } 370 371 /* Get device name */ 334 372 ipc_callid_t callid; 335 373 size_t size; 336 devmap_device_t *device;337 338 if (NULL == driver) {339 ipc_answer_0(iid, EREFUSED);340 return;341 }342 343 /* Create new device entry */344 if (NULL ==345 (device = (devmap_device_t *) malloc(sizeof(devmap_device_t)))) {346 ipc_answer_0(iid, ENOMEM);347 return;348 }349 350 /* Get device name */351 374 if (!ipc_data_write_receive(&callid, &size)) { 352 375 free(device); … … 354 377 return; 355 378 } 356 379 357 380 if (size > DEVMAP_NAME_MAXLEN) { 358 381 free(device); … … 364 387 /* +1 for terminating \0 */ 365 388 device->name = (char *) malloc(size + 1); 366 367 if ( NULL == device->name) {389 390 if (device->name == NULL) { 368 391 free(device); 369 392 ipc_answer_0(callid, ENOMEM); … … 374 397 ipc_data_write_finalize(callid, device->name, size); 375 398 device->name[size] = 0; 376 399 377 400 list_initialize(&(device->devices)); 378 401 list_initialize(&(device->driver_devices)); 379 380 futex_down(&devices_list_futex); 381 402 403 futex_down(&devices_list_futex); 404 382 405 /* Check that device with such name is not already registered */ 383 406 if (NULL != devmap_device_find_name(device->name)) { … … 389 412 return; 390 413 } 391 414 392 415 /* Get unique device handle */ 393 device->handle = devmap_create_handle(); 394 416 device->handle = devmap_create_handle(); 417 395 418 device->driver = driver; 396 419 397 420 /* Insert device into list of all devices */ 398 421 list_append(&device->devices, &devices_list); 399 422 400 423 /* Insert device into list of devices that belog to one driver */ 401 424 futex_down(&device->driver->devices_futex); … … 403 426 list_append(&device->driver_devices, &device->driver->devices); 404 427 405 futex_up(&device->driver->devices_futex); 406 futex_up(&devices_list_futex); 407 428 futex_up(&device->driver->devices_futex); 429 futex_up(&devices_list_futex); 430 408 431 ipc_answer_1(iid, EOK, device->handle); 432 433 process_pending_lookup(); 409 434 } 410 435 … … 416 441 { 417 442 /* TODO */ 418 419 443 return EOK; 420 444 } 421 445 422 446 /** Connect client to the device. 447 * 423 448 * Find device driver owning requested device and forward 424 449 * the message to it. 450 * 425 451 */ 426 452 static void devmap_forward(ipc_callid_t callid, ipc_call_t *call) 427 453 { 428 devmap_device_t *dev;429 int handle;430 431 454 /* 432 455 * Get handle from request 433 456 */ 434 handle = IPC_GET_ARG2(*call);435 dev = devmap_device_find_handle(handle);436 457 int handle = IPC_GET_ARG2(*call); 458 devmap_device_t *dev = devmap_device_find_handle(handle); 459 437 460 if (NULL == dev) { 438 461 ipc_answer_0(callid, ENOENT); 439 462 return; 440 } 441 463 } 464 442 465 ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle), 443 466 IPC_GET_ARG3(*call), 0, IPC_FF_NONE); … … 445 468 446 469 /** Find handle for device instance identified by name. 470 * 447 471 * In answer will be send EOK and device handle in arg1 or a error 448 * code from errno.h. 472 * code from errno.h. 473 * 449 474 */ 450 475 static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall) 451 476 { 452 char *name = NULL; 453 size_t name_size; 454 const devmap_device_t *dev; 455 ipc_callid_t callid; 456 ipcarg_t retval; 457 458 /* 477 /* 459 478 * Wait for incoming message with device name (but do not 460 479 * read the name itself until the buffer is allocated). 461 480 */ 462 if (!ipc_data_write_receive(&callid, &name_size)) { 481 ipc_callid_t callid; 482 size_t size; 483 if (!ipc_data_write_receive(&callid, &size)) { 463 484 ipc_answer_0(callid, EREFUSED); 464 485 ipc_answer_0(iid, EREFUSED); 465 486 return; 466 487 } 467 468 if ( name_size > DEVMAP_NAME_MAXLEN) {488 489 if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) { 469 490 ipc_answer_0(callid, EINVAL); 470 491 ipc_answer_0(iid, EREFUSED); 471 492 return; 472 493 } 473 494 474 495 /* 475 496 * Allocate buffer for device name. 476 497 */ 477 if (NULL == (name = (char *)malloc(name_size))) { 498 char *name = (char *) malloc(size); 499 if (name == NULL) { 478 500 ipc_answer_0(callid, ENOMEM); 479 501 ipc_answer_0(iid, EREFUSED); 480 502 return; 481 } 482 503 } 504 483 505 /* 484 506 * Send confirmation to sender and get data into buffer. 485 507 */ 486 if (EOK != (retval = ipc_data_write_finalize(callid, name, 487 name_size))) { 488 ipc_answer_0(iid, EREFUSED); 489 return; 490 } 491 508 ipcarg_t retval = ipc_data_write_finalize(callid, name, size); 509 if (retval != EOK) { 510 ipc_answer_0(iid, EREFUSED); 511 free(name); 512 return; 513 } 514 name[size] = '\0'; 515 492 516 /* 493 517 * Find device name in linked list of known devices. 494 518 */ 495 dev = devmap_device_find_name(name);496 519 const devmap_device_t *dev = devmap_device_find_name(name); 520 497 521 /* 498 522 * Device was not found. 499 523 */ 500 if (NULL == dev) { 524 if (dev == NULL) { 525 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) { 526 /* Blocking lookup, add to pending list */ 527 pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t)); 528 if (!pr) { 529 ipc_answer_0(iid, ENOMEM); 530 free(name); 531 return; 532 } 533 534 pr->name = name; 535 pr->callid = iid; 536 list_append(&pr->link, &pending_req); 537 return; 538 } 539 501 540 ipc_answer_0(iid, ENOENT); 502 return; 503 } 504 541 free(name); 542 return; 543 } 544 505 545 ipc_answer_1(iid, EOK, dev->handle); 506 } 507 508 /** Find name of device identified by id and send it to caller. 546 free(name); 547 } 548 549 /** Find name of device identified by id and send it to caller. 509 550 * 510 551 */ 511 552 static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall) 512 553 { 513 const devmap_device_t *device; 514 size_t name_size; 515 516 device = devmap_device_find_handle(IPC_GET_ARG1(*icall)); 517 554 const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall)); 555 518 556 /* 519 557 * Device not found. 520 558 */ 521 if ( NULL == device) {559 if (device == NULL) { 522 560 ipc_answer_0(iid, ENOENT); 523 561 return; 524 } 525 562 } 563 526 564 ipc_answer_0(iid, EOK); 527 528 name_size = strlen(device->name);529 530 531 /* FIXME: 532 we have no channel from DEVMAP to client ->533 sending must be initiated by client534 535 int rc = ipc_data_write_send(phone, device->name, name_size);536 if (rc != EOK) {537 async_wait_for(req, NULL);538 return rc;539 }540 */565 566 size_t name_size = strlen(device->name); 567 568 /* FIXME: 569 * We have no channel from DEVMAP to client, therefore 570 * sending must be initiated by client. 571 * 572 * int rc = ipc_data_write_send(phone, device->name, name_size); 573 * if (rc != EOK) { 574 * async_wait_for(req, NULL); 575 * return rc; 576 * } 577 */ 578 541 579 /* TODO: send name in response */ 542 580 } … … 547 585 static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall) 548 586 { 549 ipc_callid_t callid; 550 ipc_call_t call; 587 /* Accept connection */ 588 ipc_answer_0(iid, EOK); 589 590 devmap_driver_t *driver = NULL; 591 devmap_driver_register(&driver); 592 593 if (NULL == driver) 594 return; 595 551 596 bool cont = true; 552 devmap_driver_t *driver = NULL;553 554 ipc_answer_0(iid, EOK);555 556 devmap_driver_register(&driver);557 558 if (NULL == driver)559 return;560 561 597 while (cont) { 562 callid = async_get_call(&call); 563 564 switch (IPC_GET_METHOD(call)) { 598 ipc_call_t call; 599 ipc_callid_t callid = async_get_call(&call); 600 601 switch (IPC_GET_METHOD(call)) { 565 602 case IPC_M_PHONE_HUNGUP: 566 603 cont = false; 567 continue; /* Exit thread */ 604 /* Exit thread */ 605 continue; 568 606 case DEVMAP_DRIVER_UNREGISTER: 569 if (NULL == driver) {607 if (NULL == driver) 570 608 ipc_answer_0(callid, ENOENT); 571 } else {609 else 572 610 ipc_answer_0(callid, EOK); 573 }574 611 break; 575 612 case DEVMAP_DEVICE_REGISTER: … … 588 625 break; 589 626 default: 590 if (!(callid & IPC_CALLID_NOTIFICATION)) {627 if (!(callid & IPC_CALLID_NOTIFICATION)) 591 628 ipc_answer_0(callid, ENOENT); 592 }593 629 } 594 630 } 595 631 596 632 if (NULL != driver) { 597 /* 633 /* 598 634 * Unregister the device driver and all its devices. 599 635 */ … … 601 637 driver = NULL; 602 638 } 603 604 639 } 605 640 … … 609 644 static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall) 610 645 { 611 ipc_callid_t callid; 612 ipc_call_t call; 646 /* Accept connection */ 647 ipc_answer_0(iid, EOK); 648 613 649 bool cont = true; 614 615 ipc_answer_0(iid, EOK); /* Accept connection */616 617 650 while (cont) { 618 callid = async_get_call(&call); 619 620 switch (IPC_GET_METHOD(call)) { 651 ipc_call_t call; 652 ipc_callid_t callid = async_get_call(&call); 653 654 switch (IPC_GET_METHOD(call)) { 621 655 case IPC_M_PHONE_HUNGUP: 622 656 cont = false; 623 continue;/* Exit thread */624 657 /* Exit thread */ 658 continue; 625 659 case DEVMAP_DEVICE_GET_HANDLE: 626 devmap_get_handle(callid, &call); 627 660 devmap_get_handle(callid, &call); 628 661 break; 629 662 case DEVMAP_DEVICE_GET_NAME: … … 632 665 break; 633 666 default: 634 if (!(callid & IPC_CALLID_NOTIFICATION)) {667 if (!(callid & IPC_CALLID_NOTIFICATION)) 635 668 ipc_answer_0(callid, ENOENT); 636 }637 669 } 638 670 } 639 671 } 640 672 641 /** Function for handling connections to devmap 673 /** Function for handling connections to devmap 642 674 * 643 675 */ … … 657 689 break; 658 690 default: 659 ipc_answer_0(iid, ENOENT); /* No such interface */ 660 } 661 662 /* Cleanup */ 691 /* No such interface */ 692 ipc_answer_0(iid, ENOENT); 693 } 663 694 } 664 695 … … 670 701 printf(NAME ": HelenOS Device Mapper\n"); 671 702 672 ipcarg_t phonead;673 674 703 if (devmap_init() != 0) { 675 704 printf(NAME ": Error while initializing service\n"); … … 679 708 /* Set a handler of incomming connections */ 680 709 async_set_client_connection(devmap_connection); 681 710 682 711 /* Register device mapper at naming service */ 712 ipcarg_t phonead; 683 713 if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0) 684 714 return -1; … … 686 716 printf(NAME ": Accepting connections\n"); 687 717 async_manager(); 718 688 719 /* Never reached */ 689 720 return 0;
Note:
See TracChangeset
for help on using the changeset viewer.