Rev 4419 | Rev 4537 | Go to most recent revision | Show entire file | Ignore 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 | ||
| - | 108 | static dev_handle_t last_handle = 0; |
|
| - | 109 | ||
| 73 | static int devmap_create_handle(void) |
110 | static dev_handle_t devmap_create_handle(void) |
| 74 | { |
111 | { |
| 75 | static int last_handle = 0; |
- | |
| 76 | int handle; |
- | |
| 77 | - | ||
| 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 547... | Line 566... | ||
| 547 | } |
566 | } |
| 548 | 567 | ||
| 549 | /** Find name of device identified by id and send it to caller. |
568 | /** Find name of device identified by id and send it to caller. |
| 550 | * |
569 | * |
| 551 | */ |
570 | */ |
| 552 | static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall) |
571 | static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall) |
| 553 | { |
572 | { |
| 554 | const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall)); |
573 | const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall)); |
| 555 | 574 | ||
| 556 | /* |
575 | /* |
| 557 | * Device not found. |
576 | * Device not found. |
| 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 */ |