Subversion Repositories HelenOS

Rev

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