Subversion Repositories HelenOS

Rev

Rev 4416 | Rev 4524 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4416 Rev 4458
Line 39... Line 39...
39
#include <ipc/ns.h>
39
#include <ipc/ns.h>
40
#include <async.h>
40
#include <async.h>
41
#include <stdio.h>
41
#include <stdio.h>
42
#include <errno.h>
42
#include <errno.h>
43
#include <bool.h>
43
#include <bool.h>
44
#include <futex.h>
-
 
45
#include <stdlib.h>
44
#include <stdlib.h>
46
#include <string.h>
45
#include <string.h>
47
#include <ipc/devmap.h>
46
#include <ipc/devmap.h>
48
 
47
 
49
#define NAME  "devmap"
48
#define NAME  "devmap"
Line 60... Line 59...
60
    link_t devices;
59
    link_t devices;
61
    /** Phone asociated with this driver */
60
    /** Phone asociated with this driver */
62
    ipcarg_t phone;
61
    ipcarg_t phone;
63
    /** Device driver name */
62
    /** Device driver name */
64
    char *name;
63
    char *name;
65
    /** Futex for list of devices owned by this driver */
-
 
66
    atomic_t devices_futex;
-
 
67
} devmap_driver_t;
64
} devmap_driver_t;
68
 
65
 
69
/** Info about registered device
66
/** Info about registered device
70
 *
67
 *
71
 */
68
 */
Line 92... Line 89...
92
 
89
 
93
LIST_INITIALIZE(devices_list);
90
LIST_INITIALIZE(devices_list);
94
LIST_INITIALIZE(drivers_list);
91
LIST_INITIALIZE(drivers_list);
95
LIST_INITIALIZE(pending_req);
92
LIST_INITIALIZE(pending_req);
96
 
93
 
97
/* Locking order:
-
 
98
 *  drivers_list_futex
-
 
99
 *  devices_list_futex
-
 
100
 *  (devmap_driver_t *)->devices_futex
-
 
101
 *  create_handle_futex
-
 
102
 **/
-
 
103
 
-
 
104
static atomic_t devices_list_futex = FUTEX_INITIALIZER;
-
 
105
static atomic_t drivers_list_futex = FUTEX_INITIALIZER;
-
 
106
static atomic_t create_handle_futex = FUTEX_INITIALIZER;
-
 
107
 
-
 
108
static dev_handle_t last_handle = 0;
94
static dev_handle_t last_handle = 0;
109
 
95
 
110
static dev_handle_t devmap_create_handle(void)
96
static dev_handle_t devmap_create_handle(void)
111
{
97
{
112
    /* TODO: allow reusing old handles after their unregistration
98
    /* TODO: allow reusing old handles after their unregistration
113
     * and implement some version of LRU algorithm
99
     * and implement some version of LRU algorithm, avoid overflow
114
     */
100
     */
115
   
101
   
116
    /* FIXME: overflow */
-
 
117
    futex_down(&create_handle_futex);
-
 
118
    last_handle++;
102
    last_handle++;
119
    futex_up(&create_handle_futex);
-
 
120
   
103
   
121
    return last_handle;
104
    return last_handle;
122
}
105
}
123
 
106
 
124
/** Find device with given name.
107
/** Find device with given name.
Line 129... Line 112...
129
    link_t *item = devices_list.next;
112
    link_t *item = devices_list.next;
130
    devmap_device_t *device = NULL;
113
    devmap_device_t *device = NULL;
131
   
114
   
132
    while (item != &devices_list) {
115
    while (item != &devices_list) {
133
        device = list_get_instance(item, devmap_device_t, devices);
116
        device = list_get_instance(item, devmap_device_t, devices);
134
        if (0 == str_cmp(device->name, name))
117
        if (str_cmp(device->name, name) == 0)
135
            break;
118
            break;
136
        item = item->next;
119
        item = item->next;
137
    }
120
    }
138
   
121
   
139
    if (item == &devices_list)
122
    if (item == &devices_list)
Line 148... Line 131...
148
 * @todo: use hash table
131
 * @todo: use hash table
149
 *
132
 *
150
 */
133
 */
151
static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
134
static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
152
{
135
{
153
    futex_down(&devices_list_futex);
-
 
154
   
-
 
155
    link_t *item = (&devices_list)->next;
136
    link_t *item = (&devices_list)->next;
156
    devmap_device_t *device = NULL;
137
    devmap_device_t *device = NULL;
157
   
138
   
158
    while (item != &devices_list) {
139
    while (item != &devices_list) {
159
        device = list_get_instance(item, devmap_device_t, devices);
140
        device = list_get_instance(item, devmap_device_t, devices);
160
        if (device->handle == handle)
141
        if (device->handle == handle)
161
            break;
142
            break;
162
        item = item->next;
143
        item = item->next;
163
    }
144
    }
164
   
145
   
165
    if (item == &devices_list) {
146
    if (item == &devices_list)
166
        futex_up(&devices_list_futex);
-
 
167
        return NULL;
147
        return NULL;
168
    }
-
 
169
   
148
   
170
    device = list_get_instance(item, devmap_device_t, devices);
149
    device = list_get_instance(item, devmap_device_t, devices);
171
   
150
   
172
    futex_up(&devices_list_futex);
-
 
173
   
-
 
174
    return device;
151
    return device;
175
}
152
}
176
 
153
 
177
/**
154
/**
178
 *
155
 *
Line 247... Line 224...
247
    }
224
    }
248
   
225
   
249
    /*
226
    /*
250
     * Send confirmation to sender and get data into buffer.
227
     * Send confirmation to sender and get data into buffer.
251
     */
228
     */
252
    if (EOK != ipc_data_write_finalize(callid, driver->name, name_size)) {
229
    if (ipc_data_write_finalize(callid, driver->name, name_size) != EOK) {
253
        free(driver->name);
230
        free(driver->name);
254
        free(driver);
231
        free(driver);
255
        ipc_answer_0(iid, EREFUSED);
232
        ipc_answer_0(iid, EREFUSED);
256
        return;
233
        return;
257
    }
234
    }
258
   
235
   
259
    driver->name[name_size] = 0;
236
    driver->name[name_size] = 0;
260
   
237
   
261
    /* Initialize futex for list of devices owned by this driver */
-
 
262
    futex_initialize(&(driver->devices_futex), 1);
-
 
263
   
-
 
264
    /*
238
    /*
265
     * Initialize list of asociated devices
239
     * Initialize list of asociated devices
266
     */
240
     */
267
    list_initialize(&(driver->devices));
241
    list_initialize(&(driver->devices));
268
   
242
   
269
    /*
243
    /*
270
     * Create connection to the driver
244
     * Create connection to the driver
271
     */
245
     */
272
    ipc_call_t call;
246
    ipc_call_t call;
273
    callid = async_get_call(&call);
247
    callid = async_get_call(&call);
274
   
248
   
275
    if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
249
    if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
276
        ipc_answer_0(callid, ENOTSUP);
250
        ipc_answer_0(callid, ENOTSUP);
277
       
251
       
278
        free(driver->name);
252
        free(driver->name);
279
        free(driver);
253
        free(driver);
280
        ipc_answer_0(iid, ENOTSUP);
254
        ipc_answer_0(iid, ENOTSUP);
Line 285... Line 259...
285
   
259
   
286
    ipc_answer_0(callid, EOK);
260
    ipc_answer_0(callid, EOK);
287
   
261
   
288
    list_initialize(&(driver->drivers));
262
    list_initialize(&(driver->drivers));
289
   
263
   
290
    futex_down(&drivers_list_futex);
-
 
291
   
-
 
292
    /* TODO:
264
    /* TODO:
293
     * check that no driver with name equal to driver->name is registered
265
     * check that no driver with name equal to driver->name is registered
294
     */
266
     */
295
   
267
   
296
    /*
268
    /*
297
     * Insert new driver into list of registered drivers
269
     * Insert new driver into list of registered drivers
298
     */
270
     */
299
    list_append(&(driver->drivers), &drivers_list);
271
    list_append(&(driver->drivers), &drivers_list);
300
    futex_up(&drivers_list_futex);
-
 
301
   
272
   
302
    ipc_answer_0(iid, EOK);
273
    ipc_answer_0(iid, EOK);
303
   
274
   
304
    *odriver = driver;
275
    *odriver = driver;
305
}
276
}
Line 312... Line 283...
312
static int devmap_driver_unregister(devmap_driver_t *driver)
283
static int devmap_driver_unregister(devmap_driver_t *driver)
313
{
284
{
314
    if (driver == NULL)
285
    if (driver == NULL)
315
        return EEXISTS;
286
        return EEXISTS;
316
   
287
   
317
    futex_down(&drivers_list_futex);
-
 
318
   
-
 
319
    if (driver->phone != 0)
288
    if (driver->phone != 0)
320
        ipc_hangup(driver->phone);
289
        ipc_hangup(driver->phone);
321
   
290
   
322
    /* Remove it from list of drivers */
291
    /* Remove it from list of drivers */
323
    list_remove(&(driver->drivers));
292
    list_remove(&(driver->drivers));
324
   
293
   
325
    /* Unregister all its devices */
-
 
326
    futex_down(&devices_list_futex);
-
 
327
    futex_down(&(driver->devices_futex));
-
 
328
   
-
 
329
    while (!list_empty(&(driver->devices))) {
294
    while (!list_empty(&(driver->devices))) {
330
        devmap_device_t *device = list_get_instance(driver->devices.next,
295
        devmap_device_t *device = list_get_instance(driver->devices.next,
331
            devmap_device_t, driver_devices);
296
            devmap_device_t, driver_devices);
332
        devmap_device_unregister_core(device);
297
        devmap_device_unregister_core(device);
333
    }
298
    }
334
   
299
   
335
    futex_up(&(driver->devices_futex));
-
 
336
    futex_up(&devices_list_futex);
-
 
337
    futex_up(&drivers_list_futex);
-
 
338
   
-
 
339
    /* free name and driver */
300
    /* free name and driver */
340
    if (driver->name != NULL)
301
    if (driver->name != NULL)
341
        free(driver->name);
302
        free(driver->name);
342
   
303
   
343
    free(driver);
304
    free(driver);
Line 345... Line 306...
345
    return EOK;
306
    return EOK;
346
}
307
}
347
 
308
 
348
 
309
 
349
/** Process pending lookup requests */
310
/** Process pending lookup requests */
350
static void process_pending_lookup()
311
static void process_pending_lookup(void)
351
{
312
{
-
 
313
    async_serialize_start();
-
 
314
   
352
    link_t *cur;
315
    link_t *cur;
353
   
316
   
354
loop:
317
loop:
355
    for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
318
    for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
356
        pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
319
        pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
Line 362... Line 325...
362
        ipc_answer_1(pr->callid, EOK, dev->handle);
325
        ipc_answer_1(pr->callid, EOK, dev->handle);
363
       
326
       
364
        free(pr->name);
327
        free(pr->name);
365
        list_remove(cur);
328
        list_remove(cur);
366
        free(pr);
329
        free(pr);
-
 
330
       
367
        goto loop;
331
        goto loop;
368
    }
332
    }
-
 
333
   
-
 
334
    async_serialize_end();
369
}
335
}
370
 
336
 
371
 
337
 
372
/** Register instance of device
338
/** Register instance of device
373
 *
339
 *
Line 417... Line 383...
417
    device->name[size] = 0;
383
    device->name[size] = 0;
418
   
384
   
419
    list_initialize(&(device->devices));
385
    list_initialize(&(device->devices));
420
    list_initialize(&(device->driver_devices));
386
    list_initialize(&(device->driver_devices));
421
   
387
   
422
    futex_down(&devices_list_futex);
-
 
423
   
-
 
424
    /* Check that device with such name is not already registered */
388
    /* Check that device with such name is not already registered */
425
    if (NULL != devmap_device_find_name(device->name)) {
389
    if (NULL != devmap_device_find_name(device->name)) {
426
        printf(NAME ": Device '%s' already registered\n", device->name);
390
        printf(NAME ": Device '%s' already registered\n", device->name);
427
        futex_up(&devices_list_futex); 
-
 
428
        free(device->name);
391
        free(device->name);
429
        free(device);
392
        free(device);
430
        ipc_answer_0(iid, EEXISTS);
393
        ipc_answer_0(iid, EEXISTS);
431
        return;
394
        return;
432
    }
395
    }
Line 437... Line 400...
437
    device->driver = driver;
400
    device->driver = driver;
438
   
401
   
439
    /* Insert device into list of all devices  */
402
    /* Insert device into list of all devices  */
440
    list_append(&device->devices, &devices_list);
403
    list_append(&device->devices, &devices_list);
441
   
404
   
442
    /* Insert device into list of devices that belog to one driver */
-
 
443
    futex_down(&device->driver->devices_futex);
-
 
444
   
-
 
445
    list_append(&device->driver_devices, &device->driver->devices);
405
    list_append(&device->driver_devices, &device->driver->devices);
446
   
406
   
447
    futex_up(&device->driver->devices_futex);
-
 
448
    futex_up(&devices_list_futex);
-
 
449
   
-
 
450
    ipc_answer_1(iid, EOK, device->handle);
407
    ipc_answer_1(iid, EOK, device->handle);
451
   
-
 
452
    process_pending_lookup();
-
 
453
}
408
}
454
 
409
 
455
/**
410
/**
456
 *
411
 *
457
 */
412
 */
Line 598... Line 553...
598
    /* TODO: send name in response */
553
    /* TODO: send name in response */
599
}
554
}
600
 
555
 
601
static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
556
static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
602
{
557
{
603
    futex_down(&devices_list_futex);
-
 
604
    ipc_answer_1(iid, EOK, list_count(&devices_list));
558
    ipc_answer_1(iid, EOK, list_count(&devices_list));
605
    futex_up(&devices_list_futex);
-
 
606
}
559
}
607
 
560
 
608
static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
561
static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
609
{
562
{
610
    futex_down(&devices_list_futex);
-
 
611
   
-
 
612
    ipc_callid_t callid;
563
    ipc_callid_t callid;
613
    size_t size;
564
    size_t size;
614
    if (!ipc_data_read_receive(&callid, &size)) {
565
    if (!ipc_data_read_receive(&callid, &size)) {
615
        ipc_answer_0(callid, EREFUSED);
566
        ipc_answer_0(callid, EREFUSED);
616
        ipc_answer_0(iid, EREFUSED);
567
        ipc_answer_0(iid, EREFUSED);
Line 621... Line 572...
621
        ipc_answer_0(callid, EINVAL);
572
        ipc_answer_0(callid, EINVAL);
622
        ipc_answer_0(iid, EREFUSED);
573
        ipc_answer_0(iid, EREFUSED);
623
        return;
574
        return;
624
    }
575
    }
625
   
576
   
626
    count_t count = size / sizeof(dev_desc_t);
577
    size_t count = size / sizeof(dev_desc_t);
627
    dev_desc_t *desc = (dev_desc_t *) malloc(size);
578
    dev_desc_t *desc = (dev_desc_t *) malloc(size);
628
    if (desc == NULL) {
579
    if (desc == NULL) {
629
        ipc_answer_0(callid, ENOMEM);
580
        ipc_answer_0(callid, ENOMEM);
630
        ipc_answer_0(iid, EREFUSED);
581
        ipc_answer_0(iid, EREFUSED);
631
        return;
582
        return;
632
    }
583
    }
633
   
584
   
634
    count_t pos = 0;
585
    size_t pos = 0;
635
    link_t *item = devices_list.next;
586
    link_t *item = devices_list.next;
636
   
587
   
637
    while ((item != &devices_list) && (pos < count)) {
588
    while ((item != &devices_list) && (pos < count)) {
638
        devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
589
        devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
639
       
590
       
Line 650... Line 601...
650
        return;
601
        return;
651
    }
602
    }
652
   
603
   
653
    free(desc);
604
    free(desc);
654
   
605
   
655
    futex_up(&devices_list_futex);
-
 
656
   
-
 
657
    ipc_answer_1(iid, EOK, pos);
606
    ipc_answer_1(iid, EOK, pos);
658
}
607
}
659
 
608
 
660
/** Initialize device mapper.
609
/** Initialize device mapper.
661
 *
610
 *
Line 675... Line 624...
675
    }
624
    }
676
   
625
   
677
    list_initialize(&(device->devices));
626
    list_initialize(&(device->devices));
678
    list_initialize(&(device->driver_devices));
627
    list_initialize(&(device->driver_devices));
679
   
628
   
680
    futex_down(&devices_list_futex);
-
 
681
   
-
 
682
    /* Get unique device handle */
629
    /* Get unique device handle */
683
    device->handle = devmap_create_handle();
630
    device->handle = devmap_create_handle();
684
    device->driver = NULL;
631
    device->driver = NULL;
685
   
632
   
686
    /* Insert device into list of all devices  */
633
    /* Insert device into list of all devices  */
687
    list_append(&device->devices, &devices_list);
634
    list_append(&device->devices, &devices_list);
688
   
635
   
689
    futex_up(&devices_list_futex);
-
 
690
   
-
 
691
    return true;
636
    return true;
692
}
637
}
693
 
638
 
694
/** Handle connection with device driver.
639
/** Handle connection with device driver.
695
 *
640
 *
Line 697... Line 642...
697
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
642
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
698
{
643
{
699
    /* Accept connection */
644
    /* Accept connection */
700
    ipc_answer_0(iid, EOK);
645
    ipc_answer_0(iid, EOK);
701
   
646
   
702
    devmap_driver_t *driver = NULL;
647
    devmap_driver_t *driver = NULL;
703
    devmap_driver_register(&driver);
648
    devmap_driver_register(&driver);
704
   
649
   
705
    if (NULL == driver)
650
    if (NULL == driver)
706
        return;
651
        return;
707
   
652
   
708
    bool cont = true;
653
    bool cont = true;
709
    while (cont) {
654
    while (cont) {
710
        ipc_call_t call;
655
        ipc_call_t call;
711
        ipc_callid_t callid = async_get_call(&call);
656
        ipc_callid_t callid = async_get_call(&call);
712
       
657
       
-
 
658
        async_serialize_start();
-
 
659
       
713
        switch (IPC_GET_METHOD(call)) {
660
        switch (IPC_GET_METHOD(call)) {
714
        case IPC_M_PHONE_HUNGUP:
661
        case IPC_M_PHONE_HUNGUP:
715
            cont = false;
662
            cont = false;
716
            /* Exit thread */
663
            async_serialize_end();
717
            continue;
664
            continue;
718
        case DEVMAP_DRIVER_UNREGISTER:
665
        case DEVMAP_DRIVER_UNREGISTER:
719
            if (NULL == driver)
666
            if (NULL == driver)
720
                ipc_answer_0(callid, ENOENT);
667
                ipc_answer_0(callid, ENOENT);
721
            else
668
            else
Line 737... Line 684...
737
            break;
684
            break;
738
        default:
685
        default:
739
            if (!(callid & IPC_CALLID_NOTIFICATION))
686
            if (!(callid & IPC_CALLID_NOTIFICATION))
740
                ipc_answer_0(callid, ENOENT);
687
                ipc_answer_0(callid, ENOENT);
741
        }
688
        }
-
 
689
       
-
 
690
        async_serialize_end();
742
    }
691
    }
743
   
692
   
744
    if (NULL != driver) {
693
    if (NULL != driver) {
745
        /*
694
        /*
746
         * Unregister the device driver and all its devices.
695
         * Unregister the device driver and all its devices.
747
         */
696
         */
-
 
697
       
-
 
698
        async_serialize_start();
-
 
699
       
748
        devmap_driver_unregister(driver);
700
        devmap_driver_unregister(driver);
749
        driver = NULL;
701
        driver = NULL;
-
 
702
       
-
 
703
        async_serialize_end();
750
    }
704
    }
751
}
705
}
752
 
706
 
753
/** Handle connection with device client.
707
/** Handle connection with device client.
754
 *
708
 *
Line 761... Line 715...
761
    bool cont = true;
715
    bool cont = true;
762
    while (cont) {
716
    while (cont) {
763
        ipc_call_t call;
717
        ipc_call_t call;
764
        ipc_callid_t callid = async_get_call(&call);
718
        ipc_callid_t callid = async_get_call(&call);
765
       
719
       
-
 
720
        async_serialize_start();
-
 
721
       
766
        switch (IPC_GET_METHOD(call)) {
722
        switch (IPC_GET_METHOD(call)) {
767
        case IPC_M_PHONE_HUNGUP:
723
        case IPC_M_PHONE_HUNGUP:
768
            cont = false;
724
            cont = false;
769
            /* Exit thread */
725
            async_serialize_end();
770
            continue;
726
            continue;
771
        case DEVMAP_DEVICE_GET_HANDLE:
727
        case DEVMAP_DEVICE_GET_HANDLE:
772
            devmap_get_handle(callid, &call);
728
            devmap_get_handle(callid, &call);
773
            break;
729
            break;
774
        case DEVMAP_DEVICE_GET_NAME:
730
        case DEVMAP_DEVICE_GET_NAME:
Line 782... Line 738...
782
            break;
738
            break;
783
        default:
739
        default:
784
            if (!(callid & IPC_CALLID_NOTIFICATION))
740
            if (!(callid & IPC_CALLID_NOTIFICATION))
785
                ipc_answer_0(callid, ENOENT);
741
                ipc_answer_0(callid, ENOENT);
786
        }
742
        }
-
 
743
       
-
 
744
        async_serialize_end();
787
    }
745
    }
788
}
746
}
789
 
747
 
790
/** Function for handling connections to devmap
748
/** Function for handling connections to devmap
791
 *
749
 *
Line 804... Line 762...
804
        /* Connect client to selected device */
762
        /* Connect client to selected device */
805
        devmap_forward(iid, icall);
763
        devmap_forward(iid, icall);
806
        break;
764
        break;
807
    default:
765
    default:
808
        /* No such interface */
766
        /* No such interface */
809
        ipc_answer_0(iid, ENOENT);
767
        ipc_answer_0(iid, ENOENT);
810
    }
768
    }
811
}
769
}
812
 
770
 
813
/**
771
/**
814
 *
772
 *
Line 820... Line 778...
820
    if (!devmap_init()) {
778
    if (!devmap_init()) {
821
        printf(NAME ": Error while initializing service\n");
779
        printf(NAME ": Error while initializing service\n");
822
        return -1;
780
        return -1;
823
    }
781
    }
824
   
782
   
825
    /* Set a handler of incomming connections */
783
    /* Set a handler of incomming connections and
-
 
784
       pending operations */
-
 
785
    async_set_pending(process_pending_lookup);
826
    async_set_client_connection(devmap_connection);
786
    async_set_client_connection(devmap_connection);
827
   
787
   
828
    /* Register device mapper at naming service */
788
    /* Register device mapper at naming service */
829
    ipcarg_t phonead;
789
    ipcarg_t phonead;
830
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
790
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)