Subversion Repositories HelenOS

Rev

Rev 4591 | Details | Compare with Previous | Last modification | View Log | RSS feed

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