Rev 4537 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 4537 | Rev 4668 | ||
|---|---|---|---|
| Line 44... | Line 44... | ||
| 44 | #include <fibril_sync.h> |
44 | #include <fibril_sync.h> |
| 45 | #include <stdlib.h> |
45 | #include <stdlib.h> |
| 46 | #include <string.h> |
46 | #include <string.h> |
| 47 | #include <ipc/devmap.h> |
47 | #include <ipc/devmap.h> |
| 48 | 48 | ||
| 49 | #define NAME "devmap" |
49 | #define NAME "devmap" |
| - | 50 | #define NULL_DEVICES 256 |
|
| 50 | 51 | ||
| 51 | /** Representation of device driver. |
52 | /** Representation of device driver. |
| 52 | * |
53 | * |
| 53 | * Each driver is responsible for a set of devices. |
54 | * Each driver is responsible for a set of devices. |
| 54 | * |
55 | * |
| Line 81... | Line 82... | ||
| 81 | char *name; |
82 | char *name; |
| 82 | /** Device driver handling this device */ |
83 | /** Device driver handling this device */ |
| 83 | devmap_driver_t *driver; |
84 | devmap_driver_t *driver; |
| 84 | } devmap_device_t; |
85 | } devmap_device_t; |
| 85 | 86 | ||
| 86 | /** Pending lookup structure. */ |
- | |
| 87 | typedef struct { |
- | |
| 88 | link_t link; |
- | |
| 89 | char *name; /**< Device name */ |
- | |
| 90 | ipc_callid_t callid; /**< Call ID waiting for the lookup */ |
- | |
| 91 | } pending_req_t; |
- | |
| 92 | - | ||
| 93 | LIST_INITIALIZE(devices_list); |
87 | LIST_INITIALIZE(devices_list); |
| 94 | LIST_INITIALIZE(drivers_list); |
88 | LIST_INITIALIZE(drivers_list); |
| 95 | LIST_INITIALIZE(pending_req); |
- | |
| 96 | 89 | ||
| 97 | /* Locking order: |
90 | /* Locking order: |
| 98 | * drivers_list_mutex |
91 | * drivers_list_mutex |
| 99 | * devices_list_mutex |
92 | * devices_list_mutex |
| 100 | * (devmap_driver_t *)->devices_mutex |
93 | * (devmap_driver_t *)->devices_mutex |
| 101 | * create_handle_mutex |
94 | * create_handle_mutex |
| 102 | **/ |
95 | **/ |
| 103 | 96 | ||
| 104 | static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex); |
97 | static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex); |
| - | 98 | static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv); |
|
| 105 | static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex); |
99 | static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex); |
| 106 | static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex); |
100 | static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex); |
| - | 101 | static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex); |
|
| 107 | 102 | ||
| 108 | static dev_handle_t last_handle = 0; |
103 | static dev_handle_t last_handle = 0; |
| - | 104 | static devmap_device_t *null_devices[NULL_DEVICES]; |
|
| 109 | 105 | ||
| 110 | static dev_handle_t devmap_create_handle(void) |
106 | static dev_handle_t devmap_create_handle(void) |
| 111 | { |
107 | { |
| 112 | /* TODO: allow reusing old handles after their unregistration |
108 | /* TODO: allow reusing old handles after their unregistration |
| 113 | * and implement some version of LRU algorithm, avoid overflow |
109 | * and implement some version of LRU algorithm, avoid overflow |
| Line 172... | Line 168... | ||
| 172 | 168 | ||
| 173 | return device; |
169 | return device; |
| 174 | } |
170 | } |
| 175 | 171 | ||
| 176 | /** |
172 | /** |
| 177 | * |
- | |
| 178 | * Unregister device and free it. It's assumed that driver's device list is |
173 | * Unregister device and free it. It's assumed that driver's device list is |
| 179 | * already locked. |
174 | * already locked. |
| 180 | * |
- | |
| 181 | */ |
175 | */ |
| 182 | static int devmap_device_unregister_core(devmap_device_t *device) |
176 | static int devmap_device_unregister_core(devmap_device_t *device) |
| 183 | { |
177 | { |
| 184 | list_remove(&(device->devices)); |
178 | list_remove(&(device->devices)); |
| 185 | list_remove(&(device->driver_devices)); |
179 | list_remove(&(device->driver_devices)); |
| Line 189... | Line 183... | ||
| 189 | 183 | ||
| 190 | return EOK; |
184 | return EOK; |
| 191 | } |
185 | } |
| 192 | 186 | ||
| 193 | /** |
187 | /** |
| 194 | * |
- | |
| 195 | * Read info about new driver and add it into linked list of registered |
188 | * Read info about new driver and add it into linked list of registered |
| 196 | * drivers. |
189 | * drivers. |
| 197 | * |
- | |
| 198 | */ |
190 | */ |
| 199 | static void devmap_driver_register(devmap_driver_t **odriver) |
191 | static void devmap_driver_register(devmap_driver_t **odriver) |
| 200 | { |
192 | { |
| 201 | *odriver = NULL; |
193 | *odriver = NULL; |
| 202 | 194 | ||
| Line 342... | Line 334... | ||
| 342 | free(driver); |
334 | free(driver); |
| 343 | 335 | ||
| 344 | return EOK; |
336 | return EOK; |
| 345 | } |
337 | } |
| 346 | 338 | ||
| 347 | - | ||
| 348 | /** Process pending lookup requests */ |
- | |
| 349 | static void process_pending_lookup(void) |
- | |
| 350 | { |
- | |
| 351 | link_t *cur; |
- | |
| 352 | - | ||
| 353 | loop: |
- | |
| 354 | for (cur = pending_req.next; cur != &pending_req; cur = cur->next) { |
- | |
| 355 | pending_req_t *pr = list_get_instance(cur, pending_req_t, link); |
- | |
| 356 | - | ||
| 357 | const devmap_device_t *dev = devmap_device_find_name(pr->name); |
- | |
| 358 | if (!dev) |
- | |
| 359 | continue; |
- | |
| 360 | - | ||
| 361 | ipc_answer_1(pr->callid, EOK, dev->handle); |
- | |
| 362 | - | ||
| 363 | free(pr->name); |
- | |
| 364 | list_remove(cur); |
- | |
| 365 | free(pr); |
- | |
| 366 | - | ||
| 367 | goto loop; |
- | |
| 368 | } |
- | |
| 369 | } |
- | |
| 370 | - | ||
| 371 | - | ||
| 372 | /** Register instance of device |
339 | /** Register instance of device |
| 373 | * |
340 | * |
| 374 | */ |
341 | */ |
| 375 | static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall, |
342 | static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall, |
| 376 | devmap_driver_t *driver) |
343 | devmap_driver_t *driver) |
| Line 443... | Line 410... | ||
| 443 | fibril_mutex_lock(&device->driver->devices_mutex); |
410 | fibril_mutex_lock(&device->driver->devices_mutex); |
| 444 | 411 | ||
| 445 | list_append(&device->driver_devices, &device->driver->devices); |
412 | list_append(&device->driver_devices, &device->driver->devices); |
| 446 | 413 | ||
| 447 | fibril_mutex_unlock(&device->driver->devices_mutex); |
414 | fibril_mutex_unlock(&device->driver->devices_mutex); |
| - | 415 | fibril_condvar_broadcast(&devices_list_cv); |
|
| 448 | fibril_mutex_unlock(&devices_list_mutex); |
416 | fibril_mutex_unlock(&devices_list_mutex); |
| 449 | 417 | ||
| 450 | ipc_answer_1(iid, EOK, device->handle); |
418 | ipc_answer_1(iid, EOK, device->handle); |
| 451 | } |
419 | } |
| 452 | 420 | ||
| Line 528... | Line 496... | ||
| 528 | free(name); |
496 | free(name); |
| 529 | return; |
497 | return; |
| 530 | } |
498 | } |
| 531 | name[size] = '\0'; |
499 | name[size] = '\0'; |
| 532 | 500 | ||
| - | 501 | fibril_mutex_lock(&devices_list_mutex); |
|
| - | 502 | const devmap_device_t *dev; |
|
| - | 503 | recheck: |
|
| - | 504 | ||
| 533 | /* |
505 | /* |
| 534 | * Find device name in linked list of known devices. |
506 | * Find device name in the list of known devices. |
| 535 | */ |
507 | */ |
| 536 | const devmap_device_t *dev = devmap_device_find_name(name); |
508 | dev = devmap_device_find_name(name); |
| 537 | 509 | ||
| 538 | /* |
510 | /* |
| 539 | * Device was not found. |
511 | * Device was not found. |
| 540 | */ |
512 | */ |
| 541 | if (dev == NULL) { |
513 | if (dev == NULL) { |
| 542 | if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) { |
514 | if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) { |
| 543 | /* Blocking lookup, add to pending list */ |
515 | /* Blocking lookup */ |
| 544 | pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t)); |
- | |
| 545 | if (!pr) { |
- | |
| 546 | ipc_answer_0(iid, ENOMEM); |
516 | fibril_condvar_wait(&devices_list_cv, |
| 547 | free(name); |
517 | &devices_list_mutex); |
| 548 | return; |
518 | goto recheck; |
| 549 | } |
- | |
| 550 | - | ||
| 551 | pr->name = name; |
- | |
| 552 | pr->callid = iid; |
- | |
| 553 | list_append(&pr->link, &pending_req); |
- | |
| 554 | return; |
- | |
| 555 | } |
519 | } |
| 556 | 520 | ||
| 557 | ipc_answer_0(iid, ENOENT); |
521 | ipc_answer_0(iid, ENOENT); |
| 558 | free(name); |
522 | free(name); |
| - | 523 | fibril_mutex_unlock(&devices_list_mutex); |
|
| 559 | return; |
524 | return; |
| 560 | } |
525 | } |
| - | 526 | fibril_mutex_unlock(&devices_list_mutex); |
|
| 561 | 527 | ||
| 562 | ipc_answer_1(iid, EOK, dev->handle); |
528 | ipc_answer_1(iid, EOK, dev->handle); |
| 563 | free(name); |
529 | free(name); |
| 564 | } |
530 | } |
| 565 | 531 | ||
| Line 653... | Line 619... | ||
| 653 | fibril_mutex_unlock(&devices_list_mutex); |
619 | fibril_mutex_unlock(&devices_list_mutex); |
| 654 | 620 | ||
| 655 | ipc_answer_1(iid, EOK, pos); |
621 | ipc_answer_1(iid, EOK, pos); |
| 656 | } |
622 | } |
| 657 | 623 | ||
| 658 | /** Initialize device mapper. |
- | |
| 659 | * |
- | |
| 660 | * |
- | |
| 661 | */ |
- | |
| 662 | static bool devmap_init() |
624 | static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall) |
| 663 | { |
625 | { |
| - | 626 | fibril_mutex_lock(&null_devices_mutex); |
|
| - | 627 | ||
| - | 628 | unsigned int i; |
|
| - | 629 | bool fnd = false; |
|
| - | 630 | ||
| - | 631 | for (i = 0; i < NULL_DEVICES; i++) { |
|
| - | 632 | if (null_devices[i] == NULL) { |
|
| - | 633 | fnd = true; |
|
| - | 634 | break; |
|
| - | 635 | } |
|
| - | 636 | } |
|
| - | 637 | ||
| - | 638 | if (!fnd) { |
|
| - | 639 | fibril_mutex_unlock(&null_devices_mutex); |
|
| - | 640 | ipc_answer_0(iid, ENOMEM); |
|
| - | 641 | return; |
|
| - | 642 | } |
|
| - | 643 | ||
| 664 | /* Create NULL device entry */ |
644 | /* Create NULL device entry */ |
| 665 | devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t)); |
645 | devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t)); |
| 666 | if (device == NULL) |
646 | if (device == NULL) { |
| - | 647 | fibril_mutex_unlock(&null_devices_mutex); |
|
| - | 648 | ipc_answer_0(iid, ENOMEM); |
|
| 667 | return false; |
649 | return; |
| - | 650 | } |
|
| - | 651 | ||
| - | 652 | char null[DEVMAP_NAME_MAXLEN]; |
|
| - | 653 | snprintf(null, DEVMAP_NAME_MAXLEN, "null%u", i); |
|
| 668 | 654 | ||
| 669 | device->name = str_dup("null"); |
655 | device->name = str_dup(null); |
| 670 | if (device->name == NULL) { |
656 | if (device->name == NULL) { |
| - | 657 | fibril_mutex_unlock(&null_devices_mutex); |
|
| 671 | free(device); |
658 | free(device); |
| - | 659 | ipc_answer_0(iid, ENOMEM); |
|
| 672 | return false; |
660 | return; |
| 673 | } |
661 | } |
| 674 | 662 | ||
| 675 | list_initialize(&(device->devices)); |
663 | list_initialize(&(device->devices)); |
| 676 | list_initialize(&(device->driver_devices)); |
664 | list_initialize(&(device->driver_devices)); |
| 677 | 665 | ||
| Line 679... | Line 667... | ||
| 679 | 667 | ||
| 680 | /* Get unique device handle */ |
668 | /* Get unique device handle */ |
| 681 | device->handle = devmap_create_handle(); |
669 | device->handle = devmap_create_handle(); |
| 682 | device->driver = NULL; |
670 | device->driver = NULL; |
| 683 | 671 | ||
| 684 | /* Insert device into list of all devices */ |
672 | /* Insert device into list of all devices |
| - | 673 | and into null devices array */ |
|
| 685 | list_append(&device->devices, &devices_list); |
674 | list_append(&device->devices, &devices_list); |
| - | 675 | null_devices[i] = device; |
|
| 686 | 676 | ||
| 687 | fibril_mutex_unlock(&devices_list_mutex); |
677 | fibril_mutex_unlock(&devices_list_mutex); |
| - | 678 | fibril_mutex_unlock(&null_devices_mutex); |
|
| - | 679 | ||
| - | 680 | ipc_answer_1(iid, EOK, (ipcarg_t) i); |
|
| - | 681 | } |
|
| - | 682 | ||
| - | 683 | static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall) |
|
| - | 684 | { |
|
| - | 685 | fibril_mutex_lock(&null_devices_mutex); |
|
| - | 686 | ||
| - | 687 | ipcarg_t i = IPC_GET_ARG1(*icall); |
|
| - | 688 | ||
| - | 689 | if (null_devices[i] == NULL) { |
|
| - | 690 | ipc_answer_0(iid, ENOENT); |
|
| - | 691 | return; |
|
| - | 692 | } |
|
| - | 693 | ||
| - | 694 | devmap_device_unregister_core(null_devices[i]); |
|
| - | 695 | null_devices[i] = NULL; |
|
| - | 696 | ||
| - | 697 | fibril_mutex_unlock(&null_devices_mutex); |
|
| - | 698 | ||
| - | 699 | ipc_answer_0(iid, EOK); |
|
| - | 700 | } |
|
| - | 701 | ||
| - | 702 | /** Initialize device mapper. |
|
| - | 703 | * |
|
| - | 704 | * |
|
| - | 705 | */ |
|
| - | 706 | static bool devmap_init(void) |
|
| - | 707 | { |
|
| - | 708 | fibril_mutex_lock(&null_devices_mutex); |
|
| - | 709 | ||
| - | 710 | unsigned int i; |
|
| - | 711 | for (i = 0; i < NULL_DEVICES; i++) |
|
| - | 712 | null_devices[i] = NULL; |
|
| - | 713 | ||
| - | 714 | fibril_mutex_unlock(&null_devices_mutex); |
|
| 688 | 715 | ||
| 689 | return true; |
716 | return true; |
| 690 | } |
717 | } |
| 691 | 718 | ||
| 692 | /** Handle connection with device driver. |
719 | /** Handle connection with device driver. |
| Line 736... | Line 763... | ||
| 736 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
763 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
| 737 | ipc_answer_0(callid, ENOENT); |
764 | ipc_answer_0(callid, ENOENT); |
| 738 | } |
765 | } |
| 739 | } |
766 | } |
| 740 | 767 | ||
| 741 | if (NULL != driver) { |
768 | if (driver != NULL) { |
| 742 | /* |
769 | /* |
| 743 | * Unregister the device driver and all its devices. |
770 | * Unregister the device driver and all its devices. |
| 744 | */ |
771 | */ |
| 745 | devmap_driver_unregister(driver); |
772 | devmap_driver_unregister(driver); |
| 746 | driver = NULL; |
773 | driver = NULL; |
| Line 768... | Line 795... | ||
| 768 | devmap_get_handle(callid, &call); |
795 | devmap_get_handle(callid, &call); |
| 769 | break; |
796 | break; |
| 770 | case DEVMAP_DEVICE_GET_NAME: |
797 | case DEVMAP_DEVICE_GET_NAME: |
| 771 | devmap_get_name(callid, &call); |
798 | devmap_get_name(callid, &call); |
| 772 | break; |
799 | break; |
| - | 800 | case DEVMAP_DEVICE_NULL_CREATE: |
|
| - | 801 | devmap_null_create(callid, &call); |
|
| - | 802 | break; |
|
| - | 803 | case DEVMAP_DEVICE_NULL_DESTROY: |
|
| - | 804 | devmap_null_destroy(callid, &call); |
|
| - | 805 | break; |
|
| 773 | case DEVMAP_DEVICE_GET_COUNT: |
806 | case DEVMAP_DEVICE_GET_COUNT: |
| 774 | devmap_get_count(callid, &call); |
807 | devmap_get_count(callid, &call); |
| 775 | break; |
808 | break; |
| 776 | case DEVMAP_DEVICE_GET_DEVICES: |
809 | case DEVMAP_DEVICE_GET_DEVICES: |
| 777 | devmap_get_devices(callid, &call); |
810 | devmap_get_devices(callid, &call); |
| Line 816... | Line 849... | ||
| 816 | if (!devmap_init()) { |
849 | if (!devmap_init()) { |
| 817 | printf(NAME ": Error while initializing service\n"); |
850 | printf(NAME ": Error while initializing service\n"); |
| 818 | return -1; |
851 | return -1; |
| 819 | } |
852 | } |
| 820 | 853 | ||
| 821 | /* Set a handler of incomming connections and |
854 | /* Set a handler of incomming connections */ |
| 822 | pending operations */ |
- | |
| 823 | async_set_pending(process_pending_lookup); |
- | |
| 824 | async_set_client_connection(devmap_connection); |
855 | async_set_client_connection(devmap_connection); |
| 825 | 856 | ||
| 826 | /* Register device mapper at naming service */ |
857 | /* Register device mapper at naming service */ |
| 827 | ipcarg_t phonead; |
858 | ipcarg_t phonead; |
| 828 | if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0) |
859 | if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0) |