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) |