Subversion Repositories HelenOS

Rev

Rev 4327 | 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.
4153 mejdrech 31
 * @brief HelenOS device mapper.
2547 cejka 32
 * @{
4153 mejdrech 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>
4581 mejdrech 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
 
4153 mejdrech 49
#define NAME  "devmap"
2547 cejka 50
 
4581 mejdrech 51
/** Representation of device driver.
52
 *
53
 * Each driver is responsible for a set of devices.
54
 *
55
 */
4153 mejdrech 56
typedef struct {
4581 mejdrech 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
    /** Fibril mutex for list of devices owned by this driver */
66
    fibril_mutex_t devices_mutex;
67
} devmap_driver_t;
2555 cejka 68
 
4581 mejdrech 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
 
2594 cejka 86
LIST_INITIALIZE(devices_list);
87
LIST_INITIALIZE(drivers_list);
2555 cejka 88
 
4153 mejdrech 89
/* Locking order:
4581 mejdrech 90
 *  drivers_list_mutex
91
 *  devices_list_mutex
92
 *  (devmap_driver_t *)->devices_mutex
93
 *  create_handle_mutex
2594 cejka 94
 **/
95
 
4581 mejdrech 96
static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
97
static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv);
98
static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
99
static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
2594 cejka 100
 
4581 mejdrech 101
static dev_handle_t last_handle = 0;
102
 
103
static dev_handle_t devmap_create_handle(void)
2594 cejka 104
{
105
    /* TODO: allow reusing old handles after their unregistration
4581 mejdrech 106
     * and implement some version of LRU algorithm, avoid overflow
4153 mejdrech 107
     */
108
 
4581 mejdrech 109
    fibril_mutex_lock(&create_handle_mutex);
110
    last_handle++;
111
    fibril_mutex_unlock(&create_handle_mutex);
4153 mejdrech 112
 
4581 mejdrech 113
    return last_handle;
2594 cejka 114
}
115
 
116
/** Find device with given name.
117
 *
118
 */
119
static devmap_device_t *devmap_device_find_name(const char *name)
2555 cejka 120
{
4153 mejdrech 121
    link_t *item = devices_list.next;
2594 cejka 122
    devmap_device_t *device = NULL;
4153 mejdrech 123
 
2594 cejka 124
    while (item != &devices_list) {
125
        device = list_get_instance(item, devmap_device_t, devices);
4581 mejdrech 126
        if (str_cmp(device->name, name) == 0)
2594 cejka 127
            break;
128
        item = item->next;
129
    }
4153 mejdrech 130
 
3080 decky 131
    if (item == &devices_list)
2594 cejka 132
        return NULL;
4153 mejdrech 133
 
2594 cejka 134
    device = list_get_instance(item, devmap_device_t, devices);
135
    return device;
136
}
137
 
138
/** Find device with given handle.
4153 mejdrech 139
 *
2594 cejka 140
 * @todo: use hash table
4153 mejdrech 141
 *
2594 cejka 142
 */
4581 mejdrech 143
static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
2594 cejka 144
{
4581 mejdrech 145
    fibril_mutex_lock(&devices_list_mutex);
4153 mejdrech 146
 
147
    link_t *item = (&devices_list)->next;
2594 cejka 148
    devmap_device_t *device = NULL;
149
 
150
    while (item != &devices_list) {
151
        device = list_get_instance(item, devmap_device_t, devices);
4153 mejdrech 152
        if (device->handle == handle)
2594 cejka 153
            break;
154
        item = item->next;
155
    }
4153 mejdrech 156
 
2594 cejka 157
    if (item == &devices_list) {
4581 mejdrech 158
        fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 159
        return NULL;
160
    }
4153 mejdrech 161
 
2594 cejka 162
    device = list_get_instance(item, devmap_device_t, devices);
163
 
4581 mejdrech 164
    fibril_mutex_unlock(&devices_list_mutex);
4153 mejdrech 165
 
2594 cejka 166
    return device;
167
}
168
 
2598 jermar 169
/**
170
 * Unregister device and free it. It's assumed that driver's device list is
171
 * already locked.
2594 cejka 172
 */
173
static int devmap_device_unregister_core(devmap_device_t *device)
174
{
175
    list_remove(&(device->devices));
176
    list_remove(&(device->driver_devices));
4153 mejdrech 177
 
178
    free(device->name);
2594 cejka 179
    free(device);
4153 mejdrech 180
 
2594 cejka 181
    return EOK;
182
}
183
 
2598 jermar 184
/**
185
 * Read info about new driver and add it into linked list of registered
186
 * drivers.
2594 cejka 187
 */
188
static void devmap_driver_register(devmap_driver_t **odriver)
189
{
190
    *odriver = NULL;
2555 cejka 191
 
4153 mejdrech 192
    ipc_call_t icall;
193
    ipc_callid_t iid = async_get_call(&icall);
194
 
2594 cejka 195
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
2619 jermar 196
        ipc_answer_0(iid, EREFUSED);
2594 cejka 197
        return;
4153 mejdrech 198
    }
199
 
200
    devmap_driver_t *driver = (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
201
 
202
    if (driver == NULL) {
2619 jermar 203
        ipc_answer_0(iid, ENOMEM);
2594 cejka 204
        return;
2555 cejka 205
    }
4153 mejdrech 206
 
207
    /*
2594 cejka 208
     * Get driver name
209
     */
4153 mejdrech 210
    ipc_callid_t callid;
211
    size_t name_size;
2676 jermar 212
    if (!ipc_data_write_receive(&callid, &name_size)) {
2594 cejka 213
        free(driver);
2619 jermar 214
        ipc_answer_0(callid, EREFUSED);
215
        ipc_answer_0(iid, EREFUSED);
2594 cejka 216
        return;
2555 cejka 217
    }
4153 mejdrech 218
 
2594 cejka 219
    if (name_size > DEVMAP_NAME_MAXLEN) {
220
        free(driver);
2619 jermar 221
        ipc_answer_0(callid, EINVAL);
222
        ipc_answer_0(iid, EREFUSED);
2594 cejka 223
        return;
224
    }
4153 mejdrech 225
 
2594 cejka 226
    /*
227
     * Allocate buffer for device name.
228
     */
4153 mejdrech 229
    driver->name = (char *) malloc(name_size + 1);
230
    if (driver->name == NULL) {
2594 cejka 231
        free(driver);
2619 jermar 232
        ipc_answer_0(callid, ENOMEM);
233
        ipc_answer_0(iid, EREFUSED);
2594 cejka 234
        return;
4153 mejdrech 235
    }
236
 
2594 cejka 237
    /*
238
     * Send confirmation to sender and get data into buffer.
239
     */
4581 mejdrech 240
    if (ipc_data_write_finalize(callid, driver->name, name_size) != EOK) {
2594 cejka 241
        free(driver->name);
242
        free(driver);
2619 jermar 243
        ipc_answer_0(iid, EREFUSED);
2594 cejka 244
        return;
245
    }
4153 mejdrech 246
 
2594 cejka 247
    driver->name[name_size] = 0;
4153 mejdrech 248
 
4581 mejdrech 249
    /* Initialize mutex for list of devices owned by this driver */
250
    fibril_mutex_initialize(&driver->devices_mutex);
4153 mejdrech 251
 
252
    /*
2594 cejka 253
     * Initialize list of asociated devices
2619 jermar 254
     */
4581 mejdrech 255
    list_initialize(&driver->devices);
4153 mejdrech 256
 
257
    /*
4581 mejdrech 258
     * Create connection to the driver
2594 cejka 259
     */
4153 mejdrech 260
    ipc_call_t call;
2594 cejka 261
    callid = async_get_call(&call);
4153 mejdrech 262
 
4581 mejdrech 263
    if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
2619 jermar 264
        ipc_answer_0(callid, ENOTSUP);
2594 cejka 265
 
266
        free(driver->name);
267
        free(driver);
2619 jermar 268
        ipc_answer_0(iid, ENOTSUP);
2594 cejka 269
        return;
270
    }
4153 mejdrech 271
 
2637 cejka 272
    driver->phone = IPC_GET_ARG5(call);
2594 cejka 273
 
2619 jermar 274
    ipc_answer_0(callid, EOK);
2594 cejka 275
 
276
    list_initialize(&(driver->drivers));
277
 
4581 mejdrech 278
    fibril_mutex_lock(&drivers_list_mutex);
4153 mejdrech 279
 
2598 jermar 280
    /* TODO:
281
     * check that no driver with name equal to driver->name is registered
282
     */
4153 mejdrech 283
 
284
    /*
2594 cejka 285
     * Insert new driver into list of registered drivers
286
     */
287
    list_append(&(driver->drivers), &drivers_list);
4581 mejdrech 288
    fibril_mutex_unlock(&drivers_list_mutex);
2594 cejka 289
 
2619 jermar 290
    ipc_answer_0(iid, EOK);
4153 mejdrech 291
 
2594 cejka 292
    *odriver = driver;
2555 cejka 293
}
294
 
4153 mejdrech 295
/**
296
 * Unregister device driver, unregister all its devices and free driver
2619 jermar 297
 * structure.
4153 mejdrech 298
 *
2594 cejka 299
 */
300
static int devmap_driver_unregister(devmap_driver_t *driver)
2555 cejka 301
{
4153 mejdrech 302
    if (driver == NULL)
2594 cejka 303
        return EEXISTS;
3080 decky 304
 
4581 mejdrech 305
    fibril_mutex_lock(&drivers_list_mutex);
4153 mejdrech 306
 
4581 mejdrech 307
    if (driver->phone != 0)
308
        ipc_hangup(driver->phone);
2594 cejka 309
 
4581 mejdrech 310
    /* Remove it from list of drivers */
2594 cejka 311
    list_remove(&(driver->drivers));
4153 mejdrech 312
 
4581 mejdrech 313
    /* Unregister all its devices */
314
    fibril_mutex_lock(&devices_list_mutex);
315
    fibril_mutex_lock(&driver->devices_mutex);
2594 cejka 316
 
317
    while (!list_empty(&(driver->devices))) {
4153 mejdrech 318
        devmap_device_t *device = list_get_instance(driver->devices.next,
2598 jermar 319
            devmap_device_t, driver_devices);
2594 cejka 320
        devmap_device_unregister_core(device);
321
    }
322
 
4581 mejdrech 323
    fibril_mutex_unlock(&driver->devices_mutex);
324
    fibril_mutex_unlock(&devices_list_mutex);
325
    fibril_mutex_unlock(&drivers_list_mutex);
4153 mejdrech 326
 
2594 cejka 327
    /* free name and driver */
4581 mejdrech 328
    if (driver->name != NULL)
2594 cejka 329
        free(driver->name);
4153 mejdrech 330
 
2594 cejka 331
    free(driver);
4153 mejdrech 332
 
2555 cejka 333
    return EOK;
334
}
335
 
2594 cejka 336
/** Register instance of device
337
 *
338
 */
339
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
2619 jermar 340
    devmap_driver_t *driver)
2555 cejka 341
{
4153 mejdrech 342
    if (driver == NULL) {
2619 jermar 343
        ipc_answer_0(iid, EREFUSED);
2594 cejka 344
        return;
345
    }
346
 
347
    /* Create new device entry */
4153 mejdrech 348
    devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
349
    if (device == NULL) {
2619 jermar 350
        ipc_answer_0(iid, ENOMEM);
2594 cejka 351
        return;
352
    }
353
 
354
    /* Get device name */
4153 mejdrech 355
    ipc_callid_t callid;
356
    size_t size;
2676 jermar 357
    if (!ipc_data_write_receive(&callid, &size)) {
2594 cejka 358
        free(device);
2619 jermar 359
        ipc_answer_0(iid, EREFUSED);
2594 cejka 360
        return;
361
    }
4153 mejdrech 362
 
2594 cejka 363
    if (size > DEVMAP_NAME_MAXLEN) {
364
        free(device);
2619 jermar 365
        ipc_answer_0(callid, EINVAL);
366
        ipc_answer_0(iid, EREFUSED);
2594 cejka 367
        return;
368
    }
3080 decky 369
 
370
    /* +1 for terminating \0 */
371
    device->name = (char *) malloc(size + 1);
4153 mejdrech 372
 
373
    if (device->name == NULL) {
2594 cejka 374
        free(device);
2619 jermar 375
        ipc_answer_0(callid, ENOMEM);
376
        ipc_answer_0(iid, EREFUSED);
2594 cejka 377
        return;
2555 cejka 378
    }
2594 cejka 379
 
2678 jermar 380
    ipc_data_write_finalize(callid, device->name, size);
2594 cejka 381
    device->name[size] = 0;
4153 mejdrech 382
 
2594 cejka 383
    list_initialize(&(device->devices));
384
    list_initialize(&(device->driver_devices));
4153 mejdrech 385
 
4581 mejdrech 386
    fibril_mutex_lock(&devices_list_mutex);
4153 mejdrech 387
 
2594 cejka 388
    /* Check that device with such name is not already registered */
389
    if (NULL != devmap_device_find_name(device->name)) {
3080 decky 390
        printf(NAME ": Device '%s' already registered\n", device->name);
4581 mejdrech 391
        fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 392
        free(device->name);
393
        free(device);
2619 jermar 394
        ipc_answer_0(iid, EEXISTS);
2594 cejka 395
        return;
2555 cejka 396
    }
4153 mejdrech 397
 
2594 cejka 398
    /* Get unique device handle */
4153 mejdrech 399
    device->handle = devmap_create_handle();
400
 
2594 cejka 401
    device->driver = driver;
2555 cejka 402
 
2594 cejka 403
    /* Insert device into list of all devices  */
2619 jermar 404
    list_append(&device->devices, &devices_list);
4153 mejdrech 405
 
2594 cejka 406
    /* Insert device into list of devices that belog to one driver */
4581 mejdrech 407
    fibril_mutex_lock(&device->driver->devices_mutex);
2594 cejka 408
 
2619 jermar 409
    list_append(&device->driver_devices, &device->driver->devices);
2594 cejka 410
 
4581 mejdrech 411
    fibril_mutex_unlock(&device->driver->devices_mutex);
412
    fibril_condvar_broadcast(&devices_list_cv);
413
    fibril_mutex_unlock(&devices_list_mutex);
4153 mejdrech 414
 
2619 jermar 415
    ipc_answer_1(iid, EOK, device->handle);
2555 cejka 416
}
417
 
2594 cejka 418
/**
419
 *
420
 */
421
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
2619 jermar 422
    devmap_driver_t *driver)
2555 cejka 423
{
2594 cejka 424
    /* TODO */
2555 cejka 425
    return EOK;
426
}
427
 
2594 cejka 428
/** Connect client to the device.
4153 mejdrech 429
 *
2594 cejka 430
 * Find device driver owning requested device and forward
431
 * the message to it.
4153 mejdrech 432
 *
2547 cejka 433
 */
2594 cejka 434
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
435
{
436
    /*
437
     * Get handle from request
438
     */
4581 mejdrech 439
    dev_handle_t handle = IPC_GET_ARG2(*call);
4153 mejdrech 440
    devmap_device_t *dev = devmap_device_find_handle(handle);
441
 
4581 mejdrech 442
    if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
2619 jermar 443
        ipc_answer_0(callid, ENOENT);
2594 cejka 444
        return;
4153 mejdrech 445
    }
446
 
4581 mejdrech 447
    ipc_forward_fast(callid, dev->driver->phone, dev->handle,
2635 cejka 448
        IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
2594 cejka 449
}
450
 
451
/** Find handle for device instance identified by name.
4153 mejdrech 452
 *
2594 cejka 453
 * In answer will be send EOK and device handle in arg1 or a error
4153 mejdrech 454
 * code from errno.h.
455
 *
2594 cejka 456
 */
457
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
458
{
4153 mejdrech 459
    /*
2594 cejka 460
     * Wait for incoming message with device name (but do not
461
     * read the name itself until the buffer is allocated).
462
     */
4153 mejdrech 463
    ipc_callid_t callid;
464
    size_t size;
465
    if (!ipc_data_write_receive(&callid, &size)) {
2619 jermar 466
        ipc_answer_0(callid, EREFUSED);
467
        ipc_answer_0(iid, EREFUSED);
2594 cejka 468
        return;
469
    }
4153 mejdrech 470
 
471
    if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
2619 jermar 472
        ipc_answer_0(callid, EINVAL);
473
        ipc_answer_0(iid, EREFUSED);
2594 cejka 474
        return;
475
    }
4153 mejdrech 476
 
2594 cejka 477
    /*
478
     * Allocate buffer for device name.
479
     */
4581 mejdrech 480
    char *name = (char *) malloc(size + 1);
4153 mejdrech 481
    if (name == NULL) {
2619 jermar 482
        ipc_answer_0(callid, ENOMEM);
483
        ipc_answer_0(iid, EREFUSED);
2594 cejka 484
        return;
4153 mejdrech 485
    }
486
 
2594 cejka 487
    /*
488
     * Send confirmation to sender and get data into buffer.
489
     */
4153 mejdrech 490
    ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
491
    if (retval != EOK) {
2619 jermar 492
        ipc_answer_0(iid, EREFUSED);
4153 mejdrech 493
        free(name);
2594 cejka 494
        return;
495
    }
4153 mejdrech 496
    name[size] = '\0';
497
 
4581 mejdrech 498
    fibril_mutex_lock(&devices_list_mutex);
499
    const devmap_device_t *dev;
500
recheck:
501
 
2594 cejka 502
    /*
4581 mejdrech 503
     * Find device name in the list of known devices.
2594 cejka 504
     */
4581 mejdrech 505
    dev = devmap_device_find_name(name);
4153 mejdrech 506
 
2594 cejka 507
    /*
508
     * Device was not found.
509
     */
4153 mejdrech 510
    if (dev == NULL) {
511
        if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
4581 mejdrech 512
            /* Blocking lookup */
513
            fibril_condvar_wait(&devices_list_cv,
514
                &devices_list_mutex);
515
            goto recheck;
4153 mejdrech 516
        }
517
 
2619 jermar 518
        ipc_answer_0(iid, ENOENT);
4153 mejdrech 519
        free(name);
4581 mejdrech 520
        fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 521
        return;
522
    }
4581 mejdrech 523
    fibril_mutex_unlock(&devices_list_mutex);
4153 mejdrech 524
 
2619 jermar 525
    ipc_answer_1(iid, EOK, dev->handle);
4153 mejdrech 526
    free(name);
2594 cejka 527
}
528
 
4153 mejdrech 529
/** Find name of device identified by id and send it to caller.
2594 cejka 530
 *
531
 */
4581 mejdrech 532
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 533
{
4153 mejdrech 534
    const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
535
 
2594 cejka 536
    /*
537
     * Device not found.
538
     */
4153 mejdrech 539
    if (device == NULL) {
2619 jermar 540
        ipc_answer_0(iid, ENOENT);
2594 cejka 541
        return;
4153 mejdrech 542
    }
543
 
2619 jermar 544
    ipc_answer_0(iid, EOK);
4153 mejdrech 545
 
4327 mejdrech 546
    size_t name_size = str_size(device->name);
4153 mejdrech 547
 
548
    /* FIXME:
549
     * We have no channel from DEVMAP to client, therefore
550
     * sending must be initiated by client.
551
     *
552
     * int rc = ipc_data_write_send(phone, device->name, name_size);
553
     * if (rc != EOK) {
554
     *     async_wait_for(req, NULL);
555
     *     return rc;
556
     * }
557
     */
558
 
2594 cejka 559
    /* TODO: send name in response */
560
}
561
 
4581 mejdrech 562
static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
563
{
564
    fibril_mutex_lock(&devices_list_mutex);
565
    ipc_answer_1(iid, EOK, list_count(&devices_list));
566
    fibril_mutex_unlock(&devices_list_mutex);
567
}
568
 
569
static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
570
{
571
    fibril_mutex_lock(&devices_list_mutex);
572
 
573
    ipc_callid_t callid;
574
    size_t size;
575
    if (!ipc_data_read_receive(&callid, &size)) {
576
        ipc_answer_0(callid, EREFUSED);
577
        ipc_answer_0(iid, EREFUSED);
578
        return;
579
    }
580
 
581
    if ((size % sizeof(dev_desc_t)) != 0) {
582
        ipc_answer_0(callid, EINVAL);
583
        ipc_answer_0(iid, EREFUSED);
584
        return;
585
    }
586
 
587
    size_t count = size / sizeof(dev_desc_t);
588
    dev_desc_t *desc = (dev_desc_t *) malloc(size);
589
    if (desc == NULL) {
590
        ipc_answer_0(callid, ENOMEM);
591
        ipc_answer_0(iid, EREFUSED);
592
        return;
593
    }
594
 
595
    size_t pos = 0;
596
    link_t *item = devices_list.next;
597
 
598
    while ((item != &devices_list) && (pos < count)) {
599
        devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
600
 
601
        desc[pos].handle = device->handle;
602
        str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
603
        pos++;
604
        item = item->next;
605
    }
606
 
607
    ipcarg_t retval = ipc_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
608
    if (retval != EOK) {
609
        ipc_answer_0(iid, EREFUSED);
610
        free(desc);
611
        return;
612
    }
613
 
614
    free(desc);
615
 
616
    fibril_mutex_unlock(&devices_list_mutex);
617
 
618
    ipc_answer_1(iid, EOK, pos);
619
}
620
 
621
/** Initialize device mapper.
622
 *
623
 *
624
 */
625
static bool devmap_init(void)
626
{
627
    /* Create NULL device entry */
628
    devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
629
    if (device == NULL)
630
        return false;
631
 
632
    device->name = str_dup("null");
633
    if (device->name == NULL) {
634
        free(device);
635
        return false;
636
    }
637
 
638
    list_initialize(&(device->devices));
639
    list_initialize(&(device->driver_devices));
640
 
641
    fibril_mutex_lock(&devices_list_mutex);
642
 
643
    /* Get unique device handle */
644
    device->handle = devmap_create_handle();
645
    device->driver = NULL;
646
 
647
    /* Insert device into list of all devices  */
648
    list_append(&device->devices, &devices_list);
649
 
650
    fibril_mutex_unlock(&devices_list_mutex);
651
 
652
    return true;
653
}
654
 
2594 cejka 655
/** Handle connection with device driver.
656
 *
657
 */
3080 decky 658
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
2547 cejka 659
{
4153 mejdrech 660
    /* Accept connection */
661
    ipc_answer_0(iid, EOK);
662
 
4581 mejdrech 663
    devmap_driver_t *driver = NULL;
2594 cejka 664
    devmap_driver_register(&driver);
4153 mejdrech 665
 
3080 decky 666
    if (NULL == driver)
2594 cejka 667
        return;
668
 
4153 mejdrech 669
    bool cont = true;
2555 cejka 670
    while (cont) {
4153 mejdrech 671
        ipc_call_t call;
672
        ipc_callid_t callid = async_get_call(&call);
673
 
674
        switch (IPC_GET_METHOD(call)) {
2547 cejka 675
        case IPC_M_PHONE_HUNGUP:
2555 cejka 676
            cont = false;
4153 mejdrech 677
            continue;
2594 cejka 678
        case DEVMAP_DRIVER_UNREGISTER:
4153 mejdrech 679
            if (NULL == driver)
2619 jermar 680
                ipc_answer_0(callid, ENOENT);
4153 mejdrech 681
            else
2619 jermar 682
                ipc_answer_0(callid, EOK);
2555 cejka 683
            break;
2594 cejka 684
        case DEVMAP_DEVICE_REGISTER:
685
            /* Register one instance of device */
686
            devmap_device_register(callid, &call, driver);
2555 cejka 687
            break;
2594 cejka 688
        case DEVMAP_DEVICE_UNREGISTER:
689
            /* Remove instance of device identified by handler */
690
            devmap_device_unregister(callid, &call, driver);
691
            break;
692
        case DEVMAP_DEVICE_GET_HANDLE:
693
            devmap_get_handle(callid, &call);
694
            break;
695
        case DEVMAP_DEVICE_GET_NAME:
4581 mejdrech 696
            devmap_get_name(callid, &call);
2594 cejka 697
            break;
698
        default:
4153 mejdrech 699
            if (!(callid & IPC_CALLID_NOTIFICATION))
2619 jermar 700
                ipc_answer_0(callid, ENOENT);
2594 cejka 701
        }
702
    }
703
 
704
    if (NULL != driver) {
4153 mejdrech 705
        /*
2619 jermar 706
         * Unregister the device driver and all its devices.
707
         */
2594 cejka 708
        devmap_driver_unregister(driver);
709
        driver = NULL;
710
    }
711
}
712
 
713
/** Handle connection with device client.
714
 *
715
 */
3080 decky 716
static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 717
{
4153 mejdrech 718
    /* Accept connection */
719
    ipc_answer_0(iid, EOK);
720
 
2594 cejka 721
    bool cont = true;
722
    while (cont) {
4153 mejdrech 723
        ipc_call_t call;
724
        ipc_callid_t callid = async_get_call(&call);
725
 
726
        switch (IPC_GET_METHOD(call)) {
2594 cejka 727
        case IPC_M_PHONE_HUNGUP:
2555 cejka 728
            cont = false;
4153 mejdrech 729
            continue;
2594 cejka 730
        case DEVMAP_DEVICE_GET_HANDLE:
4153 mejdrech 731
            devmap_get_handle(callid, &call);
2555 cejka 732
            break;
2594 cejka 733
        case DEVMAP_DEVICE_GET_NAME:
734
            devmap_get_name(callid, &call);
735
            break;
4581 mejdrech 736
        case DEVMAP_DEVICE_GET_COUNT:
737
            devmap_get_count(callid, &call);
738
            break;
739
        case DEVMAP_DEVICE_GET_DEVICES:
740
            devmap_get_devices(callid, &call);
741
            break;
2547 cejka 742
        default:
4153 mejdrech 743
            if (!(callid & IPC_CALLID_NOTIFICATION))
2619 jermar 744
                ipc_answer_0(callid, ENOENT);
2547 cejka 745
        }
746
    }
2594 cejka 747
}
748
 
4153 mejdrech 749
/** Function for handling connections to devmap
2594 cejka 750
 *
751
 */
3080 decky 752
static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 753
{
3080 decky 754
    /* Select interface */
755
    switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
2598 jermar 756
    case DEVMAP_DRIVER:
757
        devmap_connection_driver(iid, icall);
758
        break;
759
    case DEVMAP_CLIENT:
760
        devmap_connection_client(iid, icall);
761
        break;
2635 cejka 762
    case DEVMAP_CONNECT_TO_DEVICE:
3080 decky 763
        /* Connect client to selected device */
2635 cejka 764
        devmap_forward(iid, icall);
765
        break;
2598 jermar 766
    default:
4153 mejdrech 767
        /* No such interface */
4581 mejdrech 768
        ipc_answer_0(iid, ENOENT);
2594 cejka 769
    }
2547 cejka 770
}
771
 
2594 cejka 772
/**
773
 *
774
 */
2547 cejka 775
int main(int argc, char *argv[])
776
{
3080 decky 777
    printf(NAME ": HelenOS Device Mapper\n");
778
 
4581 mejdrech 779
    if (!devmap_init()) {
3080 decky 780
        printf(NAME ": Error while initializing service\n");
2547 cejka 781
        return -1;
782
    }
3080 decky 783
 
784
    /* Set a handler of incomming connections */
2594 cejka 785
    async_set_client_connection(devmap_connection);
4581 mejdrech 786
 
2598 jermar 787
    /* Register device mapper at naming service */
4153 mejdrech 788
    ipcarg_t phonead;
2637 cejka 789
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
2547 cejka 790
        return -1;
791
 
3080 decky 792
    printf(NAME ": Accepting connections\n");
2547 cejka 793
    async_manager();
4153 mejdrech 794
 
2547 cejka 795
    /* Never reached */
796
    return 0;
797
}
798
 
799
/**
800
 * @}
801
 */