Subversion Repositories HelenOS

Rev

Rev 4458 | Rev 4540 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2547 cejka 1
/*
2
 * Copyright (c) 2007 Josef Cejka
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
29
/**
30
 * @defgroup devmap Device mapper.
4009 decky 31
 * @brief HelenOS device mapper.
2547 cejka 32
 * @{
4009 decky 33
 */
2547 cejka 34
 
35
/** @file
36
 */
37
 
38
#include <ipc/services.h>
39
#include <ipc/ns.h>
40
#include <async.h>
41
#include <stdio.h>
42
#include <errno.h>
2555 cejka 43
#include <bool.h>
4524 decky 44
#include <fibril_sync.h>
2594 cejka 45
#include <stdlib.h>
46
#include <string.h>
3080 decky 47
#include <ipc/devmap.h>
2547 cejka 48
 
4009 decky 49
#define NAME  "devmap"
2547 cejka 50
 
4416 decky 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;
4524 decky 65
    /** Fibril mutex for list of devices owned by this driver */
66
    fibril_mutex_t devices_mutex;
4416 decky 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
 
4009 decky 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;
2555 cejka 92
 
2594 cejka 93
LIST_INITIALIZE(devices_list);
94
LIST_INITIALIZE(drivers_list);
4009 decky 95
LIST_INITIALIZE(pending_req);
2555 cejka 96
 
4524 decky 97
/* Locking order:
98
 *  drivers_list_mutex
99
 *  devices_list_mutex
100
 *  (devmap_driver_t *)->devices_mutex
101
 *  create_handle_mutex
102
 **/
103
 
104
static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
105
static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
106
static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
107
 
4416 decky 108
static dev_handle_t last_handle = 0;
109
 
110
static dev_handle_t devmap_create_handle(void)
2594 cejka 111
{
112
    /* TODO: allow reusing old handles after their unregistration
4458 decky 113
     * and implement some version of LRU algorithm, avoid overflow
4009 decky 114
     */
115
 
4524 decky 116
    fibril_mutex_lock(&create_handle_mutex);
4416 decky 117
    last_handle++;
4524 decky 118
    fibril_mutex_unlock(&create_handle_mutex);
4009 decky 119
 
4416 decky 120
    return last_handle;
2594 cejka 121
}
122
 
123
/** Find device with given name.
124
 *
125
 */
126
static devmap_device_t *devmap_device_find_name(const char *name)
2555 cejka 127
{
4009 decky 128
    link_t *item = devices_list.next;
2594 cejka 129
    devmap_device_t *device = NULL;
4009 decky 130
 
2594 cejka 131
    while (item != &devices_list) {
132
        device = list_get_instance(item, devmap_device_t, devices);
4458 decky 133
        if (str_cmp(device->name, name) == 0)
2594 cejka 134
            break;
135
        item = item->next;
136
    }
4009 decky 137
 
3080 decky 138
    if (item == &devices_list)
2594 cejka 139
        return NULL;
4009 decky 140
 
2594 cejka 141
    device = list_get_instance(item, devmap_device_t, devices);
142
    return device;
143
}
144
 
145
/** Find device with given handle.
4009 decky 146
 *
2594 cejka 147
 * @todo: use hash table
4009 decky 148
 *
2594 cejka 149
 */
4416 decky 150
static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
2594 cejka 151
{
4524 decky 152
    fibril_mutex_lock(&devices_list_mutex);
153
 
4009 decky 154
    link_t *item = (&devices_list)->next;
2594 cejka 155
    devmap_device_t *device = NULL;
156
 
157
    while (item != &devices_list) {
158
        device = list_get_instance(item, devmap_device_t, devices);
4009 decky 159
        if (device->handle == handle)
2594 cejka 160
            break;
161
        item = item->next;
162
    }
4009 decky 163
 
4524 decky 164
    if (item == &devices_list) {
165
        fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 166
        return NULL;
4524 decky 167
    }
4009 decky 168
 
2594 cejka 169
    device = list_get_instance(item, devmap_device_t, devices);
170
 
4524 decky 171
    fibril_mutex_unlock(&devices_list_mutex);
172
 
2594 cejka 173
    return device;
174
}
175
 
2598 jermar 176
/**
4009 decky 177
 *
2598 jermar 178
 * Unregister device and free it. It's assumed that driver's device list is
179
 * already locked.
4009 decky 180
 *
2594 cejka 181
 */
182
static int devmap_device_unregister_core(devmap_device_t *device)
183
{
184
    list_remove(&(device->devices));
185
    list_remove(&(device->driver_devices));
4009 decky 186
 
187
    free(device->name);
2594 cejka 188
    free(device);
4009 decky 189
 
2594 cejka 190
    return EOK;
191
}
192
 
2598 jermar 193
/**
4009 decky 194
 *
2598 jermar 195
 * Read info about new driver and add it into linked list of registered
196
 * drivers.
4009 decky 197
 *
2594 cejka 198
 */
199
static void devmap_driver_register(devmap_driver_t **odriver)
200
{
201
    *odriver = NULL;
2555 cejka 202
 
4009 decky 203
    ipc_call_t icall;
204
    ipc_callid_t iid = async_get_call(&icall);
205
 
2594 cejka 206
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
2619 jermar 207
        ipc_answer_0(iid, EREFUSED);
2594 cejka 208
        return;
4009 decky 209
    }
210
 
211
    devmap_driver_t *driver = (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
212
 
213
    if (driver == NULL) {
2619 jermar 214
        ipc_answer_0(iid, ENOMEM);
2594 cejka 215
        return;
2555 cejka 216
    }
4009 decky 217
 
218
    /*
2594 cejka 219
     * Get driver name
220
     */
4009 decky 221
    ipc_callid_t callid;
222
    size_t name_size;
2676 jermar 223
    if (!ipc_data_write_receive(&callid, &name_size)) {
2594 cejka 224
        free(driver);
2619 jermar 225
        ipc_answer_0(callid, EREFUSED);
226
        ipc_answer_0(iid, EREFUSED);
2594 cejka 227
        return;
2555 cejka 228
    }
4009 decky 229
 
2594 cejka 230
    if (name_size > DEVMAP_NAME_MAXLEN) {
231
        free(driver);
2619 jermar 232
        ipc_answer_0(callid, EINVAL);
233
        ipc_answer_0(iid, EREFUSED);
2594 cejka 234
        return;
235
    }
4009 decky 236
 
2594 cejka 237
    /*
238
     * Allocate buffer for device name.
239
     */
4009 decky 240
    driver->name = (char *) malloc(name_size + 1);
241
    if (driver->name == NULL) {
2594 cejka 242
        free(driver);
2619 jermar 243
        ipc_answer_0(callid, ENOMEM);
244
        ipc_answer_0(iid, EREFUSED);
2594 cejka 245
        return;
4009 decky 246
    }
247
 
2594 cejka 248
    /*
249
     * Send confirmation to sender and get data into buffer.
250
     */
4458 decky 251
    if (ipc_data_write_finalize(callid, driver->name, name_size) != EOK) {
2594 cejka 252
        free(driver->name);
253
        free(driver);
2619 jermar 254
        ipc_answer_0(iid, EREFUSED);
2594 cejka 255
        return;
256
    }
4009 decky 257
 
2594 cejka 258
    driver->name[name_size] = 0;
4009 decky 259
 
4524 decky 260
    /* Initialize mutex for list of devices owned by this driver */
261
    fibril_mutex_initialize(&driver->devices_mutex);
262
 
4009 decky 263
    /*
2594 cejka 264
     * Initialize list of asociated devices
2619 jermar 265
     */
4524 decky 266
    list_initialize(&driver->devices);
4009 decky 267
 
268
    /*
4458 decky 269
     * Create connection to the driver
2594 cejka 270
     */
4009 decky 271
    ipc_call_t call;
2594 cejka 272
    callid = async_get_call(&call);
4009 decky 273
 
4458 decky 274
    if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
2619 jermar 275
        ipc_answer_0(callid, ENOTSUP);
2594 cejka 276
 
277
        free(driver->name);
278
        free(driver);
2619 jermar 279
        ipc_answer_0(iid, ENOTSUP);
2594 cejka 280
        return;
281
    }
4009 decky 282
 
2637 cejka 283
    driver->phone = IPC_GET_ARG5(call);
2594 cejka 284
 
2619 jermar 285
    ipc_answer_0(callid, EOK);
2594 cejka 286
 
287
    list_initialize(&(driver->drivers));
288
 
4524 decky 289
    fibril_mutex_lock(&drivers_list_mutex);
290
 
2598 jermar 291
    /* TODO:
292
     * check that no driver with name equal to driver->name is registered
293
     */
4009 decky 294
 
295
    /*
2594 cejka 296
     * Insert new driver into list of registered drivers
297
     */
298
    list_append(&(driver->drivers), &drivers_list);
4524 decky 299
    fibril_mutex_unlock(&drivers_list_mutex);
2594 cejka 300
 
2619 jermar 301
    ipc_answer_0(iid, EOK);
4009 decky 302
 
2594 cejka 303
    *odriver = driver;
2555 cejka 304
}
305
 
4009 decky 306
/**
307
 * Unregister device driver, unregister all its devices and free driver
2619 jermar 308
 * structure.
4009 decky 309
 *
2594 cejka 310
 */
311
static int devmap_driver_unregister(devmap_driver_t *driver)
2555 cejka 312
{
4009 decky 313
    if (driver == NULL)
2594 cejka 314
        return EEXISTS;
3080 decky 315
 
4524 decky 316
    fibril_mutex_lock(&drivers_list_mutex);
317
 
4416 decky 318
    if (driver->phone != 0)
319
        ipc_hangup(driver->phone);
2594 cejka 320
 
4416 decky 321
    /* Remove it from list of drivers */
2594 cejka 322
    list_remove(&(driver->drivers));
4009 decky 323
 
4524 decky 324
    /* Unregister all its devices */
325
    fibril_mutex_lock(&devices_list_mutex);
326
    fibril_mutex_lock(&driver->devices_mutex);
327
 
2594 cejka 328
    while (!list_empty(&(driver->devices))) {
4009 decky 329
        devmap_device_t *device = list_get_instance(driver->devices.next,
2598 jermar 330
            devmap_device_t, driver_devices);
2594 cejka 331
        devmap_device_unregister_core(device);
332
    }
333
 
4524 decky 334
    fibril_mutex_unlock(&driver->devices_mutex);
335
    fibril_mutex_unlock(&devices_list_mutex);
336
    fibril_mutex_unlock(&drivers_list_mutex);
337
 
2594 cejka 338
    /* free name and driver */
4416 decky 339
    if (driver->name != NULL)
2594 cejka 340
        free(driver->name);
4009 decky 341
 
2594 cejka 342
    free(driver);
4009 decky 343
 
2555 cejka 344
    return EOK;
345
}
346
 
2594 cejka 347
 
4009 decky 348
/** Process pending lookup requests */
4458 decky 349
static void process_pending_lookup(void)
4009 decky 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);
4458 decky 366
 
4009 decky 367
        goto loop;
368
    }
369
}
370
 
371
 
2594 cejka 372
/** Register instance of device
373
 *
374
 */
375
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
2619 jermar 376
    devmap_driver_t *driver)
2555 cejka 377
{
4009 decky 378
    if (driver == NULL) {
2619 jermar 379
        ipc_answer_0(iid, EREFUSED);
2594 cejka 380
        return;
381
    }
382
 
383
    /* Create new device entry */
4009 decky 384
    devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
385
    if (device == NULL) {
2619 jermar 386
        ipc_answer_0(iid, ENOMEM);
2594 cejka 387
        return;
388
    }
389
 
390
    /* Get device name */
4009 decky 391
    ipc_callid_t callid;
392
    size_t size;
2676 jermar 393
    if (!ipc_data_write_receive(&callid, &size)) {
2594 cejka 394
        free(device);
2619 jermar 395
        ipc_answer_0(iid, EREFUSED);
2594 cejka 396
        return;
397
    }
4009 decky 398
 
2594 cejka 399
    if (size > DEVMAP_NAME_MAXLEN) {
400
        free(device);
2619 jermar 401
        ipc_answer_0(callid, EINVAL);
402
        ipc_answer_0(iid, EREFUSED);
2594 cejka 403
        return;
404
    }
3080 decky 405
 
406
    /* +1 for terminating \0 */
407
    device->name = (char *) malloc(size + 1);
4009 decky 408
 
409
    if (device->name == NULL) {
2594 cejka 410
        free(device);
2619 jermar 411
        ipc_answer_0(callid, ENOMEM);
412
        ipc_answer_0(iid, EREFUSED);
2594 cejka 413
        return;
2555 cejka 414
    }
2594 cejka 415
 
2678 jermar 416
    ipc_data_write_finalize(callid, device->name, size);
2594 cejka 417
    device->name[size] = 0;
4009 decky 418
 
2594 cejka 419
    list_initialize(&(device->devices));
420
    list_initialize(&(device->driver_devices));
4009 decky 421
 
4524 decky 422
    fibril_mutex_lock(&devices_list_mutex);
423
 
2594 cejka 424
    /* Check that device with such name is not already registered */
425
    if (NULL != devmap_device_find_name(device->name)) {
3080 decky 426
        printf(NAME ": Device '%s' already registered\n", device->name);
4524 decky 427
        fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 428
        free(device->name);
429
        free(device);
2619 jermar 430
        ipc_answer_0(iid, EEXISTS);
2594 cejka 431
        return;
2555 cejka 432
    }
4009 decky 433
 
2594 cejka 434
    /* Get unique device handle */
4009 decky 435
    device->handle = devmap_create_handle();
436
 
2594 cejka 437
    device->driver = driver;
2555 cejka 438
 
2594 cejka 439
    /* Insert device into list of all devices  */
2619 jermar 440
    list_append(&device->devices, &devices_list);
4009 decky 441
 
4524 decky 442
    /* Insert device into list of devices that belog to one driver */
443
    fibril_mutex_lock(&device->driver->devices_mutex);
444
 
2619 jermar 445
    list_append(&device->driver_devices, &device->driver->devices);
2594 cejka 446
 
4524 decky 447
    fibril_mutex_unlock(&device->driver->devices_mutex);
448
    fibril_mutex_unlock(&devices_list_mutex);
449
 
2619 jermar 450
    ipc_answer_1(iid, EOK, device->handle);
2555 cejka 451
}
452
 
2594 cejka 453
/**
454
 *
455
 */
456
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
2619 jermar 457
    devmap_driver_t *driver)
2555 cejka 458
{
2594 cejka 459
    /* TODO */
2555 cejka 460
    return EOK;
461
}
462
 
2594 cejka 463
/** Connect client to the device.
4009 decky 464
 *
2594 cejka 465
 * Find device driver owning requested device and forward
466
 * the message to it.
4009 decky 467
 *
2547 cejka 468
 */
2594 cejka 469
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
470
{
471
    /*
472
     * Get handle from request
473
     */
4416 decky 474
    dev_handle_t handle = IPC_GET_ARG2(*call);
4009 decky 475
    devmap_device_t *dev = devmap_device_find_handle(handle);
476
 
4416 decky 477
    if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
2619 jermar 478
        ipc_answer_0(callid, ENOENT);
2594 cejka 479
        return;
4009 decky 480
    }
481
 
4416 decky 482
    ipc_forward_fast(callid, dev->driver->phone, dev->handle,
2635 cejka 483
        IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
2594 cejka 484
}
485
 
486
/** Find handle for device instance identified by name.
4009 decky 487
 *
2594 cejka 488
 * In answer will be send EOK and device handle in arg1 or a error
4009 decky 489
 * code from errno.h.
490
 *
2594 cejka 491
 */
492
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
493
{
4009 decky 494
    /*
2594 cejka 495
     * Wait for incoming message with device name (but do not
496
     * read the name itself until the buffer is allocated).
497
     */
4009 decky 498
    ipc_callid_t callid;
499
    size_t size;
500
    if (!ipc_data_write_receive(&callid, &size)) {
2619 jermar 501
        ipc_answer_0(callid, EREFUSED);
502
        ipc_answer_0(iid, EREFUSED);
2594 cejka 503
        return;
504
    }
4009 decky 505
 
506
    if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
2619 jermar 507
        ipc_answer_0(callid, EINVAL);
508
        ipc_answer_0(iid, EREFUSED);
2594 cejka 509
        return;
510
    }
4009 decky 511
 
2594 cejka 512
    /*
513
     * Allocate buffer for device name.
514
     */
4416 decky 515
    char *name = (char *) malloc(size + 1);
4009 decky 516
    if (name == NULL) {
2619 jermar 517
        ipc_answer_0(callid, ENOMEM);
518
        ipc_answer_0(iid, EREFUSED);
2594 cejka 519
        return;
4009 decky 520
    }
521
 
2594 cejka 522
    /*
523
     * Send confirmation to sender and get data into buffer.
524
     */
4009 decky 525
    ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
526
    if (retval != EOK) {
2619 jermar 527
        ipc_answer_0(iid, EREFUSED);
4009 decky 528
        free(name);
2594 cejka 529
        return;
530
    }
4009 decky 531
    name[size] = '\0';
532
 
2594 cejka 533
    /*
534
     * Find device name in linked list of known devices.
535
     */
4009 decky 536
    const devmap_device_t *dev = devmap_device_find_name(name);
537
 
2594 cejka 538
    /*
539
     * Device was not found.
540
     */
4009 decky 541
    if (dev == NULL) {
542
        if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
543
            /* Blocking lookup, add to pending list */
544
            pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
545
            if (!pr) {
546
                ipc_answer_0(iid, ENOMEM);
547
                free(name);
548
                return;
549
            }
550
 
551
            pr->name = name;
552
            pr->callid = iid;
553
            list_append(&pr->link, &pending_req);
554
            return;
555
        }
556
 
2619 jermar 557
        ipc_answer_0(iid, ENOENT);
4009 decky 558
        free(name);
2594 cejka 559
        return;
560
    }
4009 decky 561
 
2619 jermar 562
    ipc_answer_1(iid, EOK, dev->handle);
4009 decky 563
    free(name);
2594 cejka 564
}
565
 
4009 decky 566
/** Find name of device identified by id and send it to caller.
2594 cejka 567
 *
568
 */
4416 decky 569
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 570
{
4009 decky 571
    const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
572
 
2594 cejka 573
    /*
574
     * Device not found.
575
     */
4009 decky 576
    if (device == NULL) {
2619 jermar 577
        ipc_answer_0(iid, ENOENT);
2594 cejka 578
        return;
4009 decky 579
    }
580
 
2619 jermar 581
    ipc_answer_0(iid, EOK);
4009 decky 582
 
4264 svoboda 583
    size_t name_size = str_size(device->name);
4009 decky 584
 
585
    /* FIXME:
586
     * We have no channel from DEVMAP to client, therefore
587
     * sending must be initiated by client.
588
     *
589
     * int rc = ipc_data_write_send(phone, device->name, name_size);
590
     * if (rc != EOK) {
591
     *     async_wait_for(req, NULL);
592
     *     return rc;
593
     * }
594
     */
595
 
2594 cejka 596
    /* TODO: send name in response */
597
}
598
 
4416 decky 599
static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
600
{
4524 decky 601
    fibril_mutex_lock(&devices_list_mutex);
4416 decky 602
    ipc_answer_1(iid, EOK, list_count(&devices_list));
4524 decky 603
    fibril_mutex_unlock(&devices_list_mutex);
4416 decky 604
}
605
 
606
static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
607
{
4524 decky 608
    fibril_mutex_lock(&devices_list_mutex);
609
 
4416 decky 610
    ipc_callid_t callid;
611
    size_t size;
612
    if (!ipc_data_read_receive(&callid, &size)) {
613
        ipc_answer_0(callid, EREFUSED);
614
        ipc_answer_0(iid, EREFUSED);
615
        return;
616
    }
617
 
618
    if ((size % sizeof(dev_desc_t)) != 0) {
619
        ipc_answer_0(callid, EINVAL);
620
        ipc_answer_0(iid, EREFUSED);
621
        return;
622
    }
623
 
4458 decky 624
    size_t count = size / sizeof(dev_desc_t);
4416 decky 625
    dev_desc_t *desc = (dev_desc_t *) malloc(size);
626
    if (desc == NULL) {
627
        ipc_answer_0(callid, ENOMEM);
628
        ipc_answer_0(iid, EREFUSED);
629
        return;
630
    }
631
 
4458 decky 632
    size_t pos = 0;
4416 decky 633
    link_t *item = devices_list.next;
634
 
635
    while ((item != &devices_list) && (pos < count)) {
636
        devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
637
 
638
        desc[pos].handle = device->handle;
639
        str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
640
        pos++;
641
        item = item->next;
642
    }
643
 
644
    ipcarg_t retval = ipc_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
645
    if (retval != EOK) {
646
        ipc_answer_0(iid, EREFUSED);
647
        free(desc);
648
        return;
649
    }
650
 
651
    free(desc);
652
 
4524 decky 653
    fibril_mutex_unlock(&devices_list_mutex);
654
 
4416 decky 655
    ipc_answer_1(iid, EOK, pos);
656
}
657
 
658
/** Initialize device mapper.
659
 *
660
 *
661
 */
662
static bool devmap_init()
663
{
664
    /* Create NULL device entry */
665
    devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
666
    if (device == NULL)
667
        return false;
668
 
669
    device->name = str_dup("null");
670
    if (device->name == NULL) {
671
        free(device);
672
        return false;
673
    }
674
 
675
    list_initialize(&(device->devices));
676
    list_initialize(&(device->driver_devices));
677
 
4524 decky 678
    fibril_mutex_lock(&devices_list_mutex);
679
 
4416 decky 680
    /* Get unique device handle */
681
    device->handle = devmap_create_handle();
682
    device->driver = NULL;
683
 
684
    /* Insert device into list of all devices  */
685
    list_append(&device->devices, &devices_list);
686
 
4524 decky 687
    fibril_mutex_unlock(&devices_list_mutex);
688
 
4416 decky 689
    return true;
690
}
691
 
2594 cejka 692
/** Handle connection with device driver.
693
 *
694
 */
3080 decky 695
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
2547 cejka 696
{
4009 decky 697
    /* Accept connection */
698
    ipc_answer_0(iid, EOK);
699
 
4458 decky 700
    devmap_driver_t *driver = NULL;
2594 cejka 701
    devmap_driver_register(&driver);
4009 decky 702
 
3080 decky 703
    if (NULL == driver)
2594 cejka 704
        return;
705
 
4009 decky 706
    bool cont = true;
2555 cejka 707
    while (cont) {
4009 decky 708
        ipc_call_t call;
709
        ipc_callid_t callid = async_get_call(&call);
710
 
711
        switch (IPC_GET_METHOD(call)) {
2547 cejka 712
        case IPC_M_PHONE_HUNGUP:
2555 cejka 713
            cont = false;
4009 decky 714
            continue;
2594 cejka 715
        case DEVMAP_DRIVER_UNREGISTER:
4009 decky 716
            if (NULL == driver)
2619 jermar 717
                ipc_answer_0(callid, ENOENT);
4009 decky 718
            else
2619 jermar 719
                ipc_answer_0(callid, EOK);
2555 cejka 720
            break;
2594 cejka 721
        case DEVMAP_DEVICE_REGISTER:
722
            /* Register one instance of device */
723
            devmap_device_register(callid, &call, driver);
2555 cejka 724
            break;
2594 cejka 725
        case DEVMAP_DEVICE_UNREGISTER:
726
            /* Remove instance of device identified by handler */
727
            devmap_device_unregister(callid, &call, driver);
728
            break;
729
        case DEVMAP_DEVICE_GET_HANDLE:
730
            devmap_get_handle(callid, &call);
731
            break;
732
        case DEVMAP_DEVICE_GET_NAME:
4416 decky 733
            devmap_get_name(callid, &call);
2594 cejka 734
            break;
735
        default:
4009 decky 736
            if (!(callid & IPC_CALLID_NOTIFICATION))
2619 jermar 737
                ipc_answer_0(callid, ENOENT);
2594 cejka 738
        }
739
    }
740
 
741
    if (NULL != driver) {
4009 decky 742
        /*
2619 jermar 743
         * Unregister the device driver and all its devices.
744
         */
2594 cejka 745
        devmap_driver_unregister(driver);
746
        driver = NULL;
747
    }
748
}
749
 
750
/** Handle connection with device client.
751
 *
752
 */
3080 decky 753
static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 754
{
4009 decky 755
    /* Accept connection */
756
    ipc_answer_0(iid, EOK);
757
 
2594 cejka 758
    bool cont = true;
759
    while (cont) {
4009 decky 760
        ipc_call_t call;
761
        ipc_callid_t callid = async_get_call(&call);
762
 
763
        switch (IPC_GET_METHOD(call)) {
2594 cejka 764
        case IPC_M_PHONE_HUNGUP:
2555 cejka 765
            cont = false;
4009 decky 766
            continue;
2594 cejka 767
        case DEVMAP_DEVICE_GET_HANDLE:
4009 decky 768
            devmap_get_handle(callid, &call);
2555 cejka 769
            break;
2594 cejka 770
        case DEVMAP_DEVICE_GET_NAME:
771
            devmap_get_name(callid, &call);
772
            break;
4416 decky 773
        case DEVMAP_DEVICE_GET_COUNT:
774
            devmap_get_count(callid, &call);
775
            break;
776
        case DEVMAP_DEVICE_GET_DEVICES:
777
            devmap_get_devices(callid, &call);
778
            break;
2547 cejka 779
        default:
4009 decky 780
            if (!(callid & IPC_CALLID_NOTIFICATION))
2619 jermar 781
                ipc_answer_0(callid, ENOENT);
2547 cejka 782
        }
783
    }
2594 cejka 784
}
785
 
4009 decky 786
/** Function for handling connections to devmap
2594 cejka 787
 *
788
 */
3080 decky 789
static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 790
{
3080 decky 791
    /* Select interface */
792
    switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
2598 jermar 793
    case DEVMAP_DRIVER:
794
        devmap_connection_driver(iid, icall);
795
        break;
796
    case DEVMAP_CLIENT:
797
        devmap_connection_client(iid, icall);
798
        break;
2635 cejka 799
    case DEVMAP_CONNECT_TO_DEVICE:
3080 decky 800
        /* Connect client to selected device */
2635 cejka 801
        devmap_forward(iid, icall);
802
        break;
2598 jermar 803
    default:
4009 decky 804
        /* No such interface */
4458 decky 805
        ipc_answer_0(iid, ENOENT);
2594 cejka 806
    }
2547 cejka 807
}
808
 
2594 cejka 809
/**
810
 *
811
 */
2547 cejka 812
int main(int argc, char *argv[])
813
{
3080 decky 814
    printf(NAME ": HelenOS Device Mapper\n");
815
 
4416 decky 816
    if (!devmap_init()) {
3080 decky 817
        printf(NAME ": Error while initializing service\n");
2547 cejka 818
        return -1;
819
    }
3080 decky 820
 
4458 decky 821
    /* Set a handler of incomming connections and
822
       pending operations */
823
    async_set_pending(process_pending_lookup);
2594 cejka 824
    async_set_client_connection(devmap_connection);
4009 decky 825
 
2598 jermar 826
    /* Register device mapper at naming service */
4009 decky 827
    ipcarg_t phonead;
2637 cejka 828
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
2547 cejka 829
        return -1;
830
 
3080 decky 831
    printf(NAME ": Accepting connections\n");
2547 cejka 832
    async_manager();
4009 decky 833
 
2547 cejka 834
    /* Never reached */
835
    return 0;
836
}
837
 
838
/**
839
 * @}
840
 */