Subversion Repositories HelenOS

Rev

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)