Rev 4419 | Rev 4668 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4419 | Rev 4420 | ||
---|---|---|---|
Line 46... | Line 46... | ||
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 | 50 | ||
- | 51 | /** Representation of device driver. |
|
- | 52 | * |
|
- | 53 | * Each driver is responsible for a set of devices. |
|
- | 54 | * |
|
- | 55 | */ |
|
- | 56 | typedef struct { |
|
- | 57 | /** Pointers to previous and next drivers in linked list */ |
|
- | 58 | link_t drivers; |
|
- | 59 | /** Pointer to the linked list of devices controlled by this driver */ |
|
- | 60 | link_t devices; |
|
- | 61 | /** Phone asociated with this driver */ |
|
- | 62 | ipcarg_t phone; |
|
- | 63 | /** Device driver name */ |
|
- | 64 | char *name; |
|
- | 65 | /** Futex for list of devices owned by this driver */ |
|
- | 66 | atomic_t devices_futex; |
|
- | 67 | } devmap_driver_t; |
|
- | 68 | ||
- | 69 | /** Info about registered device |
|
- | 70 | * |
|
- | 71 | */ |
|
- | 72 | typedef struct { |
|
- | 73 | /** Pointer to the previous and next device in the list of all devices */ |
|
- | 74 | link_t devices; |
|
- | 75 | /** Pointer to the previous and next device in the list of devices |
|
- | 76 | owned by one driver */ |
|
- | 77 | link_t driver_devices; |
|
- | 78 | /** Unique device identifier */ |
|
- | 79 | dev_handle_t handle; |
|
- | 80 | /** Device name */ |
|
- | 81 | char *name; |
|
- | 82 | /** Device driver handling this device */ |
|
- | 83 | devmap_driver_t *driver; |
|
- | 84 | } devmap_device_t; |
|
- | 85 | ||
51 | /** Pending lookup structure. */ |
86 | /** Pending lookup structure. */ |
52 | typedef struct { |
87 | typedef struct { |
53 | link_t link; |
88 | link_t link; |
54 | char *name; /**< Device name */ |
89 | char *name; /**< Device name */ |
55 | ipc_callid_t callid; /**< Call ID waiting for the lookup */ |
90 | ipc_callid_t callid; /**< Call ID waiting for the lookup */ |
Line 68... | Line 103... | ||
68 | 103 | ||
69 | static atomic_t devices_list_futex = FUTEX_INITIALIZER; |
104 | static atomic_t devices_list_futex = FUTEX_INITIALIZER; |
70 | static atomic_t drivers_list_futex = FUTEX_INITIALIZER; |
105 | static atomic_t drivers_list_futex = FUTEX_INITIALIZER; |
71 | static atomic_t create_handle_futex = FUTEX_INITIALIZER; |
106 | static atomic_t create_handle_futex = FUTEX_INITIALIZER; |
72 | 107 | ||
73 | static int devmap_create_handle(void) |
- | |
74 | { |
- | |
75 | static int last_handle = 0; |
108 | static dev_handle_t last_handle = 0; |
76 | int handle; |
- | |
77 | 109 | ||
- | 110 | static dev_handle_t devmap_create_handle(void) |
|
- | 111 | { |
|
78 | /* TODO: allow reusing old handles after their unregistration |
112 | /* TODO: allow reusing old handles after their unregistration |
79 | * and implement some version of LRU algorithm |
113 | * and implement some version of LRU algorithm |
80 | */ |
114 | */ |
81 | 115 | ||
82 | /* FIXME: overflow */ |
116 | /* FIXME: overflow */ |
83 | futex_down(&create_handle_futex); |
117 | futex_down(&create_handle_futex); |
84 | - | ||
85 | last_handle += 1; |
118 | last_handle++; |
86 | handle = last_handle; |
- | |
87 | - | ||
88 | futex_up(&create_handle_futex); |
119 | futex_up(&create_handle_futex); |
89 | 120 | ||
90 | return handle; |
121 | return last_handle; |
91 | } |
- | |
92 | - | ||
93 | - | ||
94 | /** Initialize device mapper. |
- | |
95 | * |
- | |
96 | * |
- | |
97 | */ |
- | |
98 | static int devmap_init() |
- | |
99 | { |
- | |
100 | /* TODO: */ |
- | |
101 | - | ||
102 | return EOK; |
- | |
103 | } |
122 | } |
104 | 123 | ||
105 | /** Find device with given name. |
124 | /** Find device with given name. |
106 | * |
125 | * |
107 | */ |
126 | */ |
Line 127... | Line 146... | ||
127 | /** Find device with given handle. |
146 | /** Find device with given handle. |
128 | * |
147 | * |
129 | * @todo: use hash table |
148 | * @todo: use hash table |
130 | * |
149 | * |
131 | */ |
150 | */ |
132 | static devmap_device_t *devmap_device_find_handle(int handle) |
151 | static devmap_device_t *devmap_device_find_handle(dev_handle_t handle) |
133 | { |
152 | { |
134 | futex_down(&devices_list_futex); |
153 | futex_down(&devices_list_futex); |
135 | 154 | ||
136 | link_t *item = (&devices_list)->next; |
155 | link_t *item = (&devices_list)->next; |
137 | devmap_device_t *device = NULL; |
156 | devmap_device_t *device = NULL; |
Line 295... | Line 314... | ||
295 | if (driver == NULL) |
314 | if (driver == NULL) |
296 | return EEXISTS; |
315 | return EEXISTS; |
297 | 316 | ||
298 | futex_down(&drivers_list_futex); |
317 | futex_down(&drivers_list_futex); |
299 | 318 | ||
- | 319 | if (driver->phone != 0) |
|
300 | ipc_hangup(driver->phone); |
320 | ipc_hangup(driver->phone); |
301 | 321 | ||
302 | /* remove it from list of drivers */ |
322 | /* Remove it from list of drivers */ |
303 | list_remove(&(driver->drivers)); |
323 | list_remove(&(driver->drivers)); |
304 | 324 | ||
305 | /* unregister all its devices */ |
325 | /* Unregister all its devices */ |
306 | - | ||
307 | futex_down(&devices_list_futex); |
326 | futex_down(&devices_list_futex); |
308 | futex_down(&(driver->devices_futex)); |
327 | futex_down(&(driver->devices_futex)); |
309 | 328 | ||
310 | while (!list_empty(&(driver->devices))) { |
329 | while (!list_empty(&(driver->devices))) { |
311 | devmap_device_t *device = list_get_instance(driver->devices.next, |
330 | devmap_device_t *device = list_get_instance(driver->devices.next, |
Line 316... | Line 335... | ||
316 | futex_up(&(driver->devices_futex)); |
335 | futex_up(&(driver->devices_futex)); |
317 | futex_up(&devices_list_futex); |
336 | futex_up(&devices_list_futex); |
318 | futex_up(&drivers_list_futex); |
337 | futex_up(&drivers_list_futex); |
319 | 338 | ||
320 | /* free name and driver */ |
339 | /* free name and driver */ |
321 | if (NULL != driver->name) |
340 | if (driver->name != NULL) |
322 | free(driver->name); |
341 | free(driver->name); |
323 | 342 | ||
324 | free(driver); |
343 | free(driver); |
325 | 344 | ||
326 | return EOK; |
345 | return EOK; |
Line 452... | Line 471... | ||
452 | static void devmap_forward(ipc_callid_t callid, ipc_call_t *call) |
471 | static void devmap_forward(ipc_callid_t callid, ipc_call_t *call) |
453 | { |
472 | { |
454 | /* |
473 | /* |
455 | * Get handle from request |
474 | * Get handle from request |
456 | */ |
475 | */ |
457 | int handle = IPC_GET_ARG2(*call); |
476 | dev_handle_t handle = IPC_GET_ARG2(*call); |
458 | devmap_device_t *dev = devmap_device_find_handle(handle); |
477 | devmap_device_t *dev = devmap_device_find_handle(handle); |
459 | 478 | ||
460 | if (NULL == dev) { |
479 | if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) { |
461 | ipc_answer_0(callid, ENOENT); |
480 | ipc_answer_0(callid, ENOENT); |
462 | return; |
481 | return; |
463 | } |
482 | } |
464 | 483 | ||
465 | ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle), |
484 | ipc_forward_fast(callid, dev->driver->phone, dev->handle, |
466 | IPC_GET_ARG3(*call), 0, IPC_FF_NONE); |
485 | IPC_GET_ARG3(*call), 0, IPC_FF_NONE); |
467 | } |
486 | } |
468 | 487 | ||
469 | /** Find handle for device instance identified by name. |
488 | /** Find handle for device instance identified by name. |
470 | * |
489 | * |
Line 493... | Line 512... | ||
493 | } |
512 | } |
494 | 513 | ||
495 | /* |
514 | /* |
496 | * Allocate buffer for device name. |
515 | * Allocate buffer for device name. |
497 | */ |
516 | */ |
498 | char *name = (char *) malloc(size); |
517 | char *name = (char *) malloc(size + 1); |
499 | if (name == NULL) { |
518 | if (name == NULL) { |
500 | ipc_answer_0(callid, ENOMEM); |
519 | ipc_answer_0(callid, ENOMEM); |
501 | ipc_answer_0(iid, EREFUSED); |
520 | ipc_answer_0(iid, EREFUSED); |
502 | return; |
521 | return; |
503 | } |
522 | } |
Line 577... | Line 596... | ||
577 | */ |
596 | */ |
578 | 597 | ||
579 | /* TODO: send name in response */ |
598 | /* TODO: send name in response */ |
580 | } |
599 | } |
581 | 600 | ||
- | 601 | static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall) |
|
- | 602 | { |
|
- | 603 | futex_down(&devices_list_futex); |
|
- | 604 | ipc_answer_1(iid, EOK, list_count(&devices_list)); |
|
- | 605 | futex_up(&devices_list_futex); |
|
- | 606 | } |
|
- | 607 | ||
- | 608 | static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall) |
|
- | 609 | { |
|
- | 610 | futex_down(&devices_list_futex); |
|
- | 611 | ||
- | 612 | ipc_callid_t callid; |
|
- | 613 | size_t size; |
|
- | 614 | if (!ipc_data_read_receive(&callid, &size)) { |
|
- | 615 | ipc_answer_0(callid, EREFUSED); |
|
- | 616 | ipc_answer_0(iid, EREFUSED); |
|
- | 617 | return; |
|
- | 618 | } |
|
- | 619 | ||
- | 620 | if ((size % sizeof(dev_desc_t)) != 0) { |
|
- | 621 | ipc_answer_0(callid, EINVAL); |
|
- | 622 | ipc_answer_0(iid, EREFUSED); |
|
- | 623 | return; |
|
- | 624 | } |
|
- | 625 | ||
- | 626 | count_t count = size / sizeof(dev_desc_t); |
|
- | 627 | dev_desc_t *desc = (dev_desc_t *) malloc(size); |
|
- | 628 | if (desc == NULL) { |
|
- | 629 | ipc_answer_0(callid, ENOMEM); |
|
- | 630 | ipc_answer_0(iid, EREFUSED); |
|
- | 631 | return; |
|
- | 632 | } |
|
- | 633 | ||
- | 634 | count_t pos = 0; |
|
- | 635 | link_t *item = devices_list.next; |
|
- | 636 | ||
- | 637 | while ((item != &devices_list) && (pos < count)) { |
|
- | 638 | devmap_device_t *device = list_get_instance(item, devmap_device_t, devices); |
|
- | 639 | ||
- | 640 | desc[pos].handle = device->handle; |
|
- | 641 | str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name); |
|
- | 642 | pos++; |
|
- | 643 | item = item->next; |
|
- | 644 | } |
|
- | 645 | ||
- | 646 | ipcarg_t retval = ipc_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t)); |
|
- | 647 | if (retval != EOK) { |
|
- | 648 | ipc_answer_0(iid, EREFUSED); |
|
- | 649 | free(desc); |
|
- | 650 | return; |
|
- | 651 | } |
|
- | 652 | ||
- | 653 | free(desc); |
|
- | 654 | ||
- | 655 | futex_up(&devices_list_futex); |
|
- | 656 | ||
- | 657 | ipc_answer_1(iid, EOK, pos); |
|
- | 658 | } |
|
- | 659 | ||
- | 660 | /** Initialize device mapper. |
|
- | 661 | * |
|
- | 662 | * |
|
- | 663 | */ |
|
- | 664 | static bool devmap_init() |
|
- | 665 | { |
|
- | 666 | /* Create NULL device entry */ |
|
- | 667 | devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t)); |
|
- | 668 | if (device == NULL) |
|
- | 669 | return false; |
|
- | 670 | ||
- | 671 | device->name = str_dup("null"); |
|
- | 672 | if (device->name == NULL) { |
|
- | 673 | free(device); |
|
- | 674 | return false; |
|
- | 675 | } |
|
- | 676 | ||
- | 677 | list_initialize(&(device->devices)); |
|
- | 678 | list_initialize(&(device->driver_devices)); |
|
- | 679 | ||
- | 680 | futex_down(&devices_list_futex); |
|
- | 681 | ||
- | 682 | /* Get unique device handle */ |
|
- | 683 | device->handle = devmap_create_handle(); |
|
- | 684 | device->driver = NULL; |
|
- | 685 | ||
- | 686 | /* Insert device into list of all devices */ |
|
- | 687 | list_append(&device->devices, &devices_list); |
|
- | 688 | ||
- | 689 | futex_up(&devices_list_futex); |
|
- | 690 | ||
- | 691 | return true; |
|
- | 692 | } |
|
- | 693 | ||
582 | /** Handle connection with device driver. |
694 | /** Handle connection with device driver. |
583 | * |
695 | * |
584 | */ |
696 | */ |
585 | static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall) |
697 | static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall) |
586 | { |
698 | { |
Line 619... | Line 731... | ||
619 | break; |
731 | break; |
620 | case DEVMAP_DEVICE_GET_HANDLE: |
732 | case DEVMAP_DEVICE_GET_HANDLE: |
621 | devmap_get_handle(callid, &call); |
733 | devmap_get_handle(callid, &call); |
622 | break; |
734 | break; |
623 | case DEVMAP_DEVICE_GET_NAME: |
735 | case DEVMAP_DEVICE_GET_NAME: |
624 | devmap_get_handle(callid, &call); |
736 | devmap_get_name(callid, &call); |
625 | break; |
737 | break; |
626 | default: |
738 | default: |
627 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
739 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
628 | ipc_answer_0(callid, ENOENT); |
740 | ipc_answer_0(callid, ENOENT); |
629 | } |
741 | } |
Line 658... | Line 770... | ||
658 | continue; |
770 | continue; |
659 | case DEVMAP_DEVICE_GET_HANDLE: |
771 | case DEVMAP_DEVICE_GET_HANDLE: |
660 | devmap_get_handle(callid, &call); |
772 | devmap_get_handle(callid, &call); |
661 | break; |
773 | break; |
662 | case DEVMAP_DEVICE_GET_NAME: |
774 | case DEVMAP_DEVICE_GET_NAME: |
663 | /* TODO */ |
- | |
664 | devmap_get_name(callid, &call); |
775 | devmap_get_name(callid, &call); |
665 | break; |
776 | break; |
- | 777 | case DEVMAP_DEVICE_GET_COUNT: |
|
- | 778 | devmap_get_count(callid, &call); |
|
- | 779 | break; |
|
- | 780 | case DEVMAP_DEVICE_GET_DEVICES: |
|
- | 781 | devmap_get_devices(callid, &call); |
|
- | 782 | break; |
|
666 | default: |
783 | default: |
667 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
784 | if (!(callid & IPC_CALLID_NOTIFICATION)) |
668 | ipc_answer_0(callid, ENOENT); |
785 | ipc_answer_0(callid, ENOENT); |
669 | } |
786 | } |
670 | } |
787 | } |
Line 698... | Line 815... | ||
698 | */ |
815 | */ |
699 | int main(int argc, char *argv[]) |
816 | int main(int argc, char *argv[]) |
700 | { |
817 | { |
701 | printf(NAME ": HelenOS Device Mapper\n"); |
818 | printf(NAME ": HelenOS Device Mapper\n"); |
702 | 819 | ||
703 | if (devmap_init() != 0) { |
820 | if (!devmap_init()) { |
704 | printf(NAME ": Error while initializing service\n"); |
821 | printf(NAME ": Error while initializing service\n"); |
705 | return -1; |
822 | return -1; |
706 | } |
823 | } |
707 | 824 | ||
708 | /* Set a handler of incomming connections */ |
825 | /* Set a handler of incomming connections */ |