Subversion Repositories HelenOS

Rev

Rev 4524 | Rev 4570 | 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>
4540 jermar 48
#include <assert.h>
2547 cejka 49
 
4009 decky 50
#define NAME  "devmap"
2547 cejka 51
 
4416 decky 52
/** Representation of device driver.
53
 *
54
 * Each driver is responsible for a set of devices.
55
 *
56
 */
57
typedef struct {
58
	/** Pointers to previous and next drivers in linked list */
59
	link_t drivers;
60
	/** Pointer to the linked list of devices controlled by this driver */
61
	link_t devices;
62
	/** Phone asociated with this driver */
63
	ipcarg_t phone;
64
	/** Device driver name */
65
	char *name;
4524 decky 66
	/** Fibril mutex for list of devices owned by this driver */
67
	fibril_mutex_t devices_mutex;
4416 decky 68
} devmap_driver_t;
69
 
70
/** Info about registered device
71
 *
72
 */
73
typedef struct {
74
	/** Pointer to the previous and next device in the list of all devices */
75
	link_t devices;
76
	/** Pointer to the previous and next device in the list of devices
77
	    owned by one driver */
78
	link_t driver_devices;
79
	/** Unique device identifier  */
80
	dev_handle_t handle;
81
	/** Device name */
82
	char *name;
83
	/** Device driver handling this device */
84
	devmap_driver_t *driver;
85
} devmap_device_t;
86
 
4009 decky 87
/** Pending lookup structure. */
88
typedef struct {
89
	link_t link;
90
	char *name;              /**< Device name */
91
	ipc_callid_t callid;     /**< Call ID waiting for the lookup */
92
} pending_req_t;
2555 cejka 93
 
2594 cejka 94
LIST_INITIALIZE(devices_list);
95
LIST_INITIALIZE(drivers_list);
4009 decky 96
LIST_INITIALIZE(pending_req);
2555 cejka 97
 
4540 jermar 98
static bool pending_new_dev = false;
99
static FIBRIL_CONDVAR_INITIALIZE(pending_cv);
100
 
4524 decky 101
/* Locking order:
102
 *  drivers_list_mutex
103
 *  devices_list_mutex
104
 *  (devmap_driver_t *)->devices_mutex
105
 *  create_handle_mutex
106
 **/
107
 
108
static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
109
static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
110
static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
111
 
4416 decky 112
static dev_handle_t last_handle = 0;
113
 
114
static dev_handle_t devmap_create_handle(void)
2594 cejka 115
{
116
	/* TODO: allow reusing old handles after their unregistration
4458 decky 117
	 * and implement some version of LRU algorithm, avoid overflow
4009 decky 118
	 */
119
 
4524 decky 120
	fibril_mutex_lock(&create_handle_mutex);
4416 decky 121
	last_handle++;
4524 decky 122
	fibril_mutex_unlock(&create_handle_mutex);
4009 decky 123
 
4416 decky 124
	return last_handle;
2594 cejka 125
}
126
 
127
/** Find device with given name.
128
 *
129
 */
130
static devmap_device_t *devmap_device_find_name(const char *name)
2555 cejka 131
{
4009 decky 132
	link_t *item = devices_list.next;
2594 cejka 133
	devmap_device_t *device = NULL;
4009 decky 134
 
2594 cejka 135
	while (item != &devices_list) {
136
		device = list_get_instance(item, devmap_device_t, devices);
4458 decky 137
		if (str_cmp(device->name, name) == 0)
2594 cejka 138
			break;
139
		item = item->next;
140
	}
4009 decky 141
 
3080 decky 142
	if (item == &devices_list)
2594 cejka 143
		return NULL;
4009 decky 144
 
2594 cejka 145
	device = list_get_instance(item, devmap_device_t, devices);
146
	return device;
147
}
148
 
149
/** Find device with given handle.
4009 decky 150
 *
2594 cejka 151
 * @todo: use hash table
4009 decky 152
 *
2594 cejka 153
 */
4416 decky 154
static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
2594 cejka 155
{
4524 decky 156
	fibril_mutex_lock(&devices_list_mutex);
157
 
4009 decky 158
	link_t *item = (&devices_list)->next;
2594 cejka 159
	devmap_device_t *device = NULL;
160
 
161
	while (item != &devices_list) {
162
		device = list_get_instance(item, devmap_device_t, devices);
4009 decky 163
		if (device->handle == handle)
2594 cejka 164
			break;
165
		item = item->next;
166
	}
4009 decky 167
 
4524 decky 168
	if (item == &devices_list) {
169
		fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 170
		return NULL;
4524 decky 171
	}
4009 decky 172
 
2594 cejka 173
	device = list_get_instance(item, devmap_device_t, devices);
174
 
4524 decky 175
	fibril_mutex_unlock(&devices_list_mutex);
176
 
2594 cejka 177
	return device;
178
}
179
 
2598 jermar 180
/**
181
 * Unregister device and free it. It's assumed that driver's device list is
182
 * already locked.
2594 cejka 183
 */
184
static int devmap_device_unregister_core(devmap_device_t *device)
185
{
186
	list_remove(&(device->devices));
187
	list_remove(&(device->driver_devices));
4009 decky 188
 
189
	free(device->name);
2594 cejka 190
	free(device);
4009 decky 191
 
2594 cejka 192
	return EOK;
193
}
194
 
2598 jermar 195
/**
196
 * Read info about new driver and add it into linked list of registered
197
 * drivers.
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;
4540 jermar 352
 
4009 decky 353
loop:
4540 jermar 354
	fibril_mutex_lock(&devices_list_mutex);
355
	while (!pending_new_dev)
356
		fibril_condvar_wait(&pending_cv, &devices_list_mutex);
357
rescan:
4009 decky 358
	for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
359
		pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
360
 
361
		const devmap_device_t *dev = devmap_device_find_name(pr->name);
362
		if (!dev)
363
			continue;
364
 
365
		ipc_answer_1(pr->callid, EOK, dev->handle);
366
 
367
		free(pr->name);
368
		list_remove(cur);
369
		free(pr);
4458 decky 370
 
4540 jermar 371
		goto rescan;
4009 decky 372
	}
4540 jermar 373
	pending_new_dev = false;
374
	fibril_mutex_unlock(&devices_list_mutex);
375
	goto loop;
4009 decky 376
}
377
 
378
 
2594 cejka 379
/** Register instance of device
380
 *
381
 */
382
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
2619 jermar 383
    devmap_driver_t *driver)
2555 cejka 384
{
4009 decky 385
	if (driver == NULL) {
2619 jermar 386
		ipc_answer_0(iid, EREFUSED);
2594 cejka 387
		return;
388
	}
389
 
390
	/* Create new device entry */
4009 decky 391
	devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
392
	if (device == NULL) {
2619 jermar 393
		ipc_answer_0(iid, ENOMEM);
2594 cejka 394
		return;
395
	}
396
 
397
	/* Get device name */
4009 decky 398
	ipc_callid_t callid;
399
	size_t size;
2676 jermar 400
	if (!ipc_data_write_receive(&callid, &size)) {
2594 cejka 401
		free(device);
2619 jermar 402
		ipc_answer_0(iid, EREFUSED);
2594 cejka 403
		return;
404
	}
4009 decky 405
 
2594 cejka 406
	if (size > DEVMAP_NAME_MAXLEN) {
407
		free(device);
2619 jermar 408
		ipc_answer_0(callid, EINVAL);
409
		ipc_answer_0(iid, EREFUSED);
2594 cejka 410
		return;
411
	}
3080 decky 412
 
413
	/* +1 for terminating \0 */
414
	device->name = (char *) malloc(size + 1);
4009 decky 415
 
416
	if (device->name == NULL) {
2594 cejka 417
		free(device);
2619 jermar 418
		ipc_answer_0(callid, ENOMEM);
419
		ipc_answer_0(iid, EREFUSED);
2594 cejka 420
		return;
2555 cejka 421
	}
2594 cejka 422
 
2678 jermar 423
	ipc_data_write_finalize(callid, device->name, size);
2594 cejka 424
	device->name[size] = 0;
4009 decky 425
 
2594 cejka 426
	list_initialize(&(device->devices));
427
	list_initialize(&(device->driver_devices));
4009 decky 428
 
4524 decky 429
	fibril_mutex_lock(&devices_list_mutex);
430
 
2594 cejka 431
	/* Check that device with such name is not already registered */
432
	if (NULL != devmap_device_find_name(device->name)) {
3080 decky 433
		printf(NAME ": Device '%s' already registered\n", device->name);
4524 decky 434
		fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 435
		free(device->name);
436
		free(device);
2619 jermar 437
		ipc_answer_0(iid, EEXISTS);
2594 cejka 438
		return;
2555 cejka 439
	}
4009 decky 440
 
2594 cejka 441
	/* Get unique device handle */
4009 decky 442
	device->handle = devmap_create_handle();
443
 
2594 cejka 444
	device->driver = driver;
2555 cejka 445
 
2594 cejka 446
	/* Insert device into list of all devices  */
2619 jermar 447
	list_append(&device->devices, &devices_list);
4009 decky 448
 
4524 decky 449
	/* Insert device into list of devices that belog to one driver */
450
	fibril_mutex_lock(&device->driver->devices_mutex);
451
 
2619 jermar 452
	list_append(&device->driver_devices, &device->driver->devices);
2594 cejka 453
 
4524 decky 454
	fibril_mutex_unlock(&device->driver->devices_mutex);
4540 jermar 455
	pending_new_dev = true;
456
	fibril_condvar_signal(&pending_cv);
4524 decky 457
	fibril_mutex_unlock(&devices_list_mutex);
458
 
2619 jermar 459
	ipc_answer_1(iid, EOK, device->handle);
2555 cejka 460
}
461
 
2594 cejka 462
/**
463
 *
464
 */
465
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall, 
2619 jermar 466
    devmap_driver_t *driver)
2555 cejka 467
{
2594 cejka 468
	/* TODO */
2555 cejka 469
	return EOK;
470
}
471
 
2594 cejka 472
/** Connect client to the device.
4009 decky 473
 *
2594 cejka 474
 * Find device driver owning requested device and forward
475
 * the message to it.
4009 decky 476
 *
2547 cejka 477
 */
2594 cejka 478
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
479
{
480
	/*
481
	 * Get handle from request
482
	 */
4416 decky 483
	dev_handle_t handle = IPC_GET_ARG2(*call);
4009 decky 484
	devmap_device_t *dev = devmap_device_find_handle(handle);
485
 
4416 decky 486
	if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
2619 jermar 487
		ipc_answer_0(callid, ENOENT);
2594 cejka 488
		return;
4009 decky 489
	}
490
 
4416 decky 491
	ipc_forward_fast(callid, dev->driver->phone, dev->handle,
2635 cejka 492
	    IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
2594 cejka 493
}
494
 
495
/** Find handle for device instance identified by name.
4009 decky 496
 *
2594 cejka 497
 * In answer will be send EOK and device handle in arg1 or a error
4009 decky 498
 * code from errno.h.
499
 *
2594 cejka 500
 */
501
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
502
{
4009 decky 503
	/*
2594 cejka 504
	 * Wait for incoming message with device name (but do not
505
	 * read the name itself until the buffer is allocated).
506
	 */
4009 decky 507
	ipc_callid_t callid;
508
	size_t size;
509
	if (!ipc_data_write_receive(&callid, &size)) {
2619 jermar 510
		ipc_answer_0(callid, EREFUSED);
511
		ipc_answer_0(iid, EREFUSED);
2594 cejka 512
		return;
513
	}
4009 decky 514
 
515
	if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
2619 jermar 516
		ipc_answer_0(callid, EINVAL);
517
		ipc_answer_0(iid, EREFUSED);
2594 cejka 518
		return;
519
	}
4009 decky 520
 
2594 cejka 521
	/*
522
	 * Allocate buffer for device name.
523
	 */
4416 decky 524
	char *name = (char *) malloc(size + 1);
4009 decky 525
	if (name == NULL) {
2619 jermar 526
		ipc_answer_0(callid, ENOMEM);
527
		ipc_answer_0(iid, EREFUSED);
2594 cejka 528
		return;
4009 decky 529
	}
530
 
2594 cejka 531
	/*
532
	 * Send confirmation to sender and get data into buffer.
533
	 */
4009 decky 534
	ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
535
	if (retval != EOK) {
2619 jermar 536
		ipc_answer_0(iid, EREFUSED);
4009 decky 537
		free(name);
2594 cejka 538
		return;
539
	}
4009 decky 540
	name[size] = '\0';
541
 
4540 jermar 542
	fibril_mutex_lock(&devices_list_mutex);
543
 
2594 cejka 544
	/*
545
	 * Find device name in linked list of known devices.
546
	 */
4009 decky 547
	const devmap_device_t *dev = devmap_device_find_name(name);
548
 
2594 cejka 549
	/*
550
	 * Device was not found.
551
	 */
4009 decky 552
	if (dev == NULL) {
553
		if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
554
			/* Blocking lookup, add to pending list */
555
			pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
556
			if (!pr) {
4540 jermar 557
				fibril_mutex_unlock(&devices_list_mutex);
4009 decky 558
				ipc_answer_0(iid, ENOMEM);
559
				free(name);
560
				return;
561
			}
562
 
563
			pr->name = name;
564
			pr->callid = iid;
565
			list_append(&pr->link, &pending_req);
4540 jermar 566
			fibril_mutex_unlock(&devices_list_mutex);
4009 decky 567
			return;
568
		}
569
 
2619 jermar 570
		ipc_answer_0(iid, ENOENT);
4009 decky 571
		free(name);
4540 jermar 572
		fibril_mutex_unlock(&devices_list_mutex);
2594 cejka 573
		return;
574
	}
4540 jermar 575
	fibril_mutex_unlock(&devices_list_mutex);
4009 decky 576
 
2619 jermar 577
	ipc_answer_1(iid, EOK, dev->handle);
4009 decky 578
	free(name);
2594 cejka 579
}
580
 
4009 decky 581
/** Find name of device identified by id and send it to caller.
2594 cejka 582
 *
583
 */
4416 decky 584
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 585
{
4009 decky 586
	const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
587
 
2594 cejka 588
	/*
589
	 * Device not found.
590
	 */
4009 decky 591
	if (device == NULL) {
2619 jermar 592
		ipc_answer_0(iid, ENOENT);
2594 cejka 593
		return;
4009 decky 594
	}
595
 
2619 jermar 596
	ipc_answer_0(iid, EOK);
4009 decky 597
 
4264 svoboda 598
	size_t name_size = str_size(device->name);
4009 decky 599
 
600
	/* FIXME:
601
	 * We have no channel from DEVMAP to client, therefore
602
	 * sending must be initiated by client.
603
	 *
604
	 * int rc = ipc_data_write_send(phone, device->name, name_size);
605
	 * if (rc != EOK) {
606
	 *     async_wait_for(req, NULL);
607
	 *     return rc;
608
	 * }
609
	 */
610
 
2594 cejka 611
	/* TODO: send name in response */
612
}
613
 
4416 decky 614
static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
615
{
4524 decky 616
	fibril_mutex_lock(&devices_list_mutex);
4416 decky 617
	ipc_answer_1(iid, EOK, list_count(&devices_list));
4524 decky 618
	fibril_mutex_unlock(&devices_list_mutex);
4416 decky 619
}
620
 
621
static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
622
{
4524 decky 623
	fibril_mutex_lock(&devices_list_mutex);
624
 
4416 decky 625
	ipc_callid_t callid;
626
	size_t size;
627
	if (!ipc_data_read_receive(&callid, &size)) {
628
		ipc_answer_0(callid, EREFUSED);
629
		ipc_answer_0(iid, EREFUSED);
630
		return;
631
	}
632
 
633
	if ((size % sizeof(dev_desc_t)) != 0) {
634
		ipc_answer_0(callid, EINVAL);
635
		ipc_answer_0(iid, EREFUSED);
636
		return;
637
	}
638
 
4458 decky 639
	size_t count = size / sizeof(dev_desc_t);
4416 decky 640
	dev_desc_t *desc = (dev_desc_t *) malloc(size);
641
	if (desc == NULL) {
642
		ipc_answer_0(callid, ENOMEM);
643
		ipc_answer_0(iid, EREFUSED);
644
		return;
645
	}
646
 
4458 decky 647
	size_t pos = 0;
4416 decky 648
	link_t *item = devices_list.next;
649
 
650
	while ((item != &devices_list) && (pos < count)) {
651
		devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
652
 
653
		desc[pos].handle = device->handle;
654
		str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
655
		pos++;
656
		item = item->next;
657
	}
658
 
659
	ipcarg_t retval = ipc_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
660
	if (retval != EOK) {
661
		ipc_answer_0(iid, EREFUSED);
662
		free(desc);
663
		return;
664
	}
665
 
666
	free(desc);
667
 
4524 decky 668
	fibril_mutex_unlock(&devices_list_mutex);
669
 
4416 decky 670
	ipc_answer_1(iid, EOK, pos);
671
}
672
 
673
/** Initialize device mapper.
674
 *
675
 *
676
 */
4540 jermar 677
static bool devmap_init(void)
4416 decky 678
{
679
	/* Create NULL device entry */
680
	devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
681
	if (device == NULL)
682
		return false;
683
 
684
	device->name = str_dup("null");
685
	if (device->name == NULL) {
686
		free(device);
687
		return false;
688
	}
689
 
690
	list_initialize(&(device->devices));
691
	list_initialize(&(device->driver_devices));
692
 
4524 decky 693
	fibril_mutex_lock(&devices_list_mutex);
694
 
4416 decky 695
	/* Get unique device handle */
696
	device->handle = devmap_create_handle();
697
	device->driver = NULL;
698
 
699
	/* Insert device into list of all devices  */
700
	list_append(&device->devices, &devices_list);
701
 
4524 decky 702
	fibril_mutex_unlock(&devices_list_mutex);
703
 
4416 decky 704
	return true;
705
}
706
 
2594 cejka 707
/** Handle connection with device driver.
708
 *
709
 */
3080 decky 710
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
2547 cejka 711
{
4009 decky 712
	/* Accept connection */
713
	ipc_answer_0(iid, EOK);
714
 
4458 decky 715
	devmap_driver_t *driver = NULL;
2594 cejka 716
	devmap_driver_register(&driver);
4009 decky 717
 
3080 decky 718
	if (NULL == driver)
2594 cejka 719
		return;
720
 
4009 decky 721
	bool cont = true;
2555 cejka 722
	while (cont) {
4009 decky 723
		ipc_call_t call;
724
		ipc_callid_t callid = async_get_call(&call);
725
 
726
		switch (IPC_GET_METHOD(call)) {
2547 cejka 727
		case IPC_M_PHONE_HUNGUP:
2555 cejka 728
			cont = false;
4009 decky 729
			continue;
2594 cejka 730
		case DEVMAP_DRIVER_UNREGISTER:
4009 decky 731
			if (NULL == driver)
2619 jermar 732
				ipc_answer_0(callid, ENOENT);
4009 decky 733
			else
2619 jermar 734
				ipc_answer_0(callid, EOK);
2555 cejka 735
			break;
2594 cejka 736
		case DEVMAP_DEVICE_REGISTER:
737
			/* Register one instance of device */
738
			devmap_device_register(callid, &call, driver);
2555 cejka 739
			break;
2594 cejka 740
		case DEVMAP_DEVICE_UNREGISTER:
741
			/* Remove instance of device identified by handler */
742
			devmap_device_unregister(callid, &call, driver);
743
			break;
744
		case DEVMAP_DEVICE_GET_HANDLE:
745
			devmap_get_handle(callid, &call);
746
			break;
747
		case DEVMAP_DEVICE_GET_NAME:
4416 decky 748
			devmap_get_name(callid, &call);
2594 cejka 749
			break;
750
		default:
4009 decky 751
			if (!(callid & IPC_CALLID_NOTIFICATION))
2619 jermar 752
				ipc_answer_0(callid, ENOENT);
2594 cejka 753
		}
754
	}
755
 
756
	if (NULL != driver) {
4009 decky 757
		/*
2619 jermar 758
		 * Unregister the device driver and all its devices.
759
		 */
2594 cejka 760
		devmap_driver_unregister(driver);
761
		driver = NULL;
762
	}
763
}
764
 
765
/** Handle connection with device client.
766
 *
767
 */
3080 decky 768
static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 769
{
4009 decky 770
	/* Accept connection */
771
	ipc_answer_0(iid, EOK);
772
 
2594 cejka 773
	bool cont = true;
774
	while (cont) {
4009 decky 775
		ipc_call_t call;
776
		ipc_callid_t callid = async_get_call(&call);
777
 
778
		switch (IPC_GET_METHOD(call)) {
2594 cejka 779
		case IPC_M_PHONE_HUNGUP:
2555 cejka 780
			cont = false;
4009 decky 781
			continue;
2594 cejka 782
		case DEVMAP_DEVICE_GET_HANDLE:
4009 decky 783
			devmap_get_handle(callid, &call);
2555 cejka 784
			break;
2594 cejka 785
		case DEVMAP_DEVICE_GET_NAME:
786
			devmap_get_name(callid, &call);
787
			break;
4416 decky 788
		case DEVMAP_DEVICE_GET_COUNT:
789
			devmap_get_count(callid, &call);
790
			break;
791
		case DEVMAP_DEVICE_GET_DEVICES:
792
			devmap_get_devices(callid, &call);
793
			break;
2547 cejka 794
		default:
4009 decky 795
			if (!(callid & IPC_CALLID_NOTIFICATION))
2619 jermar 796
				ipc_answer_0(callid, ENOENT);
2547 cejka 797
		}
798
	}
2594 cejka 799
}
800
 
4009 decky 801
/** Function for handling connections to devmap
2594 cejka 802
 *
803
 */
3080 decky 804
static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
2594 cejka 805
{
3080 decky 806
	/* Select interface */
807
	switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
2598 jermar 808
	case DEVMAP_DRIVER:
809
		devmap_connection_driver(iid, icall);
810
		break;
811
	case DEVMAP_CLIENT:
812
		devmap_connection_client(iid, icall);
813
		break;
2635 cejka 814
	case DEVMAP_CONNECT_TO_DEVICE:
3080 decky 815
		/* Connect client to selected device */
2635 cejka 816
		devmap_forward(iid, icall);
817
		break;
2598 jermar 818
	default:
4009 decky 819
		/* No such interface */
4458 decky 820
		ipc_answer_0(iid, ENOENT);
2594 cejka 821
	}
2547 cejka 822
}
823
 
2594 cejka 824
/**
825
 *
826
 */
2547 cejka 827
int main(int argc, char *argv[])
828
{
3080 decky 829
	printf(NAME ": HelenOS Device Mapper\n");
830
 
4416 decky 831
	if (!devmap_init()) {
3080 decky 832
		printf(NAME ": Error while initializing service\n");
2547 cejka 833
		return -1;
834
	}
3080 decky 835
 
4540 jermar 836
	/* Set a handler of incomming connections */
2594 cejka 837
	async_set_client_connection(devmap_connection);
4540 jermar 838
 
839
	/* Create a fibril for handling pending device lookups */
840
	fid_t fid = fibril_create(process_pending_lookup, NULL);
841
	assert(fid);
842
	fibril_add_ready(fid);
4009 decky 843
 
2598 jermar 844
	/* Register device mapper at naming service */
4009 decky 845
	ipcarg_t phonead;
2637 cejka 846
	if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0) 
2547 cejka 847
		return -1;
848
 
3080 decky 849
	printf(NAME ": Accepting connections\n");
2547 cejka 850
	async_manager();
4009 decky 851
 
2547 cejka 852
	/* Never reached */
853
	return 0;
854
}
855
 
856
/** 
857
 * @}
858
 */