Subversion Repositories HelenOS

Rev

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