source: mainline/uspace/srv/devmap/devmap.c@ 0da4e41

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0da4e41 was 0da4e41, checked in by Jakub Jermar <jakub@…>, 16 years ago

ipc_data_*() and ipc_share_*(), respectively, should be renamed to
async_data_*() and async_share_*(), respectively, because these functions are
using the async framework.

  • Property mode set to 100644
File size: 19.5 KB
RevLine 
[13125d3]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.
[6519d6f]31 * @brief HelenOS device mapper.
[13125d3]32 * @{
[6519d6f]33 */
[13125d3]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>
[07e4a3c]43#include <bool.h>
[fc02cc41]44#include <fibril_sync.h>
[798f364]45#include <stdlib.h>
46#include <string.h>
[21c5d41]47#include <ipc/devmap.h>
[13125d3]48
[7fcb74c]49#define NAME "devmap"
50#define NULL_DEVICES 256
[13125d3]51
[cb41a5e]52/** Representation of device driver.
53 *
54 * Each driver is responsible for a set of devices.
55 *
56 */
57typedef 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;
[fc02cc41]66 /** Fibril mutex for list of devices owned by this driver */
67 fibril_mutex_t devices_mutex;
[cb41a5e]68} devmap_driver_t;
69
70/** Info about registered device
71 *
72 */
73typedef 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
[798f364]87LIST_INITIALIZE(devices_list);
88LIST_INITIALIZE(drivers_list);
[c07af37]89
[fc02cc41]90/* Locking order:
91 * drivers_list_mutex
92 * devices_list_mutex
93 * (devmap_driver_t *)->devices_mutex
94 * create_handle_mutex
95 **/
96
97static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
[1cab2f41]98static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv);
[fc02cc41]99static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
100static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
[7fcb74c]101static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex);
[fc02cc41]102
[cb41a5e]103static dev_handle_t last_handle = 0;
[7fcb74c]104static devmap_device_t *null_devices[NULL_DEVICES];
[cb41a5e]105
106static dev_handle_t devmap_create_handle(void)
[798f364]107{
108 /* TODO: allow reusing old handles after their unregistration
[5d0e461]109 * and implement some version of LRU algorithm, avoid overflow
[6519d6f]110 */
111
[fc02cc41]112 fibril_mutex_lock(&create_handle_mutex);
[cb41a5e]113 last_handle++;
[fc02cc41]114 fibril_mutex_unlock(&create_handle_mutex);
[6519d6f]115
[cb41a5e]116 return last_handle;
[13125d3]117}
118
[798f364]119/** Find device with given name.
120 *
121 */
122static devmap_device_t *devmap_device_find_name(const char *name)
[07e4a3c]123{
[6519d6f]124 link_t *item = devices_list.next;
[798f364]125 devmap_device_t *device = NULL;
[6519d6f]126
[798f364]127 while (item != &devices_list) {
128 device = list_get_instance(item, devmap_device_t, devices);
[5d0e461]129 if (str_cmp(device->name, name) == 0)
[798f364]130 break;
131 item = item->next;
132 }
[6519d6f]133
[21c5d41]134 if (item == &devices_list)
[798f364]135 return NULL;
[6519d6f]136
[798f364]137 device = list_get_instance(item, devmap_device_t, devices);
138 return device;
139}
140
141/** Find device with given handle.
[6519d6f]142 *
[798f364]143 * @todo: use hash table
[6519d6f]144 *
[798f364]145 */
[cb41a5e]146static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
[798f364]147{
[fc02cc41]148 fibril_mutex_lock(&devices_list_mutex);
149
[6519d6f]150 link_t *item = (&devices_list)->next;
[798f364]151 devmap_device_t *device = NULL;
152
153 while (item != &devices_list) {
154 device = list_get_instance(item, devmap_device_t, devices);
[6519d6f]155 if (device->handle == handle)
[798f364]156 break;
157 item = item->next;
158 }
[6519d6f]159
[fc02cc41]160 if (item == &devices_list) {
161 fibril_mutex_unlock(&devices_list_mutex);
[798f364]162 return NULL;
[fc02cc41]163 }
[6519d6f]164
[798f364]165 device = list_get_instance(item, devmap_device_t, devices);
166
[fc02cc41]167 fibril_mutex_unlock(&devices_list_mutex);
168
[798f364]169 return device;
170}
171
[7f3e3e7]172/**
173 * Unregister device and free it. It's assumed that driver's device list is
174 * already locked.
[798f364]175 */
176static int devmap_device_unregister_core(devmap_device_t *device)
177{
178 list_remove(&(device->devices));
179 list_remove(&(device->driver_devices));
[6519d6f]180
181 free(device->name);
[798f364]182 free(device);
[6519d6f]183
[798f364]184 return EOK;
185}
186
[7f3e3e7]187/**
188 * Read info about new driver and add it into linked list of registered
189 * drivers.
[798f364]190 */
191static void devmap_driver_register(devmap_driver_t **odriver)
192{
193 *odriver = NULL;
[07e4a3c]194
[6519d6f]195 ipc_call_t icall;
196 ipc_callid_t iid = async_get_call(&icall);
197
[798f364]198 if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
[b74959bd]199 ipc_answer_0(iid, EREFUSED);
[798f364]200 return;
[6519d6f]201 }
202
203 devmap_driver_t *driver = (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
204
205 if (driver == NULL) {
[b74959bd]206 ipc_answer_0(iid, ENOMEM);
[798f364]207 return;
[07e4a3c]208 }
[6519d6f]209
210 /*
[798f364]211 * Get driver name
212 */
[6519d6f]213 ipc_callid_t callid;
214 size_t name_size;
[0da4e41]215 if (!async_data_write_receive(&callid, &name_size)) {
[798f364]216 free(driver);
[b74959bd]217 ipc_answer_0(callid, EREFUSED);
218 ipc_answer_0(iid, EREFUSED);
[798f364]219 return;
[07e4a3c]220 }
[6519d6f]221
[798f364]222 if (name_size > DEVMAP_NAME_MAXLEN) {
223 free(driver);
[b74959bd]224 ipc_answer_0(callid, EINVAL);
225 ipc_answer_0(iid, EREFUSED);
[798f364]226 return;
227 }
[6519d6f]228
[798f364]229 /*
230 * Allocate buffer for device name.
231 */
[6519d6f]232 driver->name = (char *) malloc(name_size + 1);
233 if (driver->name == NULL) {
[798f364]234 free(driver);
[b74959bd]235 ipc_answer_0(callid, ENOMEM);
236 ipc_answer_0(iid, EREFUSED);
[798f364]237 return;
[6519d6f]238 }
239
[798f364]240 /*
241 * Send confirmation to sender and get data into buffer.
242 */
[0da4e41]243 if (async_data_write_finalize(callid, driver->name, name_size) != EOK) {
[798f364]244 free(driver->name);
245 free(driver);
[b74959bd]246 ipc_answer_0(iid, EREFUSED);
[798f364]247 return;
248 }
[6519d6f]249
[798f364]250 driver->name[name_size] = 0;
[6519d6f]251
[fc02cc41]252 /* Initialize mutex for list of devices owned by this driver */
253 fibril_mutex_initialize(&driver->devices_mutex);
254
[6519d6f]255 /*
[798f364]256 * Initialize list of asociated devices
[b74959bd]257 */
[fc02cc41]258 list_initialize(&driver->devices);
[6519d6f]259
260 /*
[5d0e461]261 * Create connection to the driver
[798f364]262 */
[6519d6f]263 ipc_call_t call;
[798f364]264 callid = async_get_call(&call);
[6519d6f]265
[5d0e461]266 if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
[b74959bd]267 ipc_answer_0(callid, ENOTSUP);
[798f364]268
269 free(driver->name);
270 free(driver);
[b74959bd]271 ipc_answer_0(iid, ENOTSUP);
[798f364]272 return;
273 }
[6519d6f]274
[38c706cc]275 driver->phone = IPC_GET_ARG5(call);
[798f364]276
[b74959bd]277 ipc_answer_0(callid, EOK);
[798f364]278
279 list_initialize(&(driver->drivers));
[6519d6f]280
[fc02cc41]281 fibril_mutex_lock(&drivers_list_mutex);
282
[7f3e3e7]283 /* TODO:
284 * check that no driver with name equal to driver->name is registered
285 */
[6519d6f]286
287 /*
[798f364]288 * Insert new driver into list of registered drivers
289 */
290 list_append(&(driver->drivers), &drivers_list);
[fc02cc41]291 fibril_mutex_unlock(&drivers_list_mutex);
[798f364]292
[b74959bd]293 ipc_answer_0(iid, EOK);
[6519d6f]294
[798f364]295 *odriver = driver;
[07e4a3c]296}
297
[6519d6f]298/**
299 * Unregister device driver, unregister all its devices and free driver
[b74959bd]300 * structure.
[6519d6f]301 *
[798f364]302 */
303static int devmap_driver_unregister(devmap_driver_t *driver)
[07e4a3c]304{
[6519d6f]305 if (driver == NULL)
[798f364]306 return EEXISTS;
[21c5d41]307
[fc02cc41]308 fibril_mutex_lock(&drivers_list_mutex);
309
[cb41a5e]310 if (driver->phone != 0)
311 ipc_hangup(driver->phone);
[798f364]312
[cb41a5e]313 /* Remove it from list of drivers */
[798f364]314 list_remove(&(driver->drivers));
[6519d6f]315
[fc02cc41]316 /* Unregister all its devices */
317 fibril_mutex_lock(&devices_list_mutex);
318 fibril_mutex_lock(&driver->devices_mutex);
319
[798f364]320 while (!list_empty(&(driver->devices))) {
[6519d6f]321 devmap_device_t *device = list_get_instance(driver->devices.next,
[7f3e3e7]322 devmap_device_t, driver_devices);
[798f364]323 devmap_device_unregister_core(device);
324 }
325
[fc02cc41]326 fibril_mutex_unlock(&driver->devices_mutex);
327 fibril_mutex_unlock(&devices_list_mutex);
328 fibril_mutex_unlock(&drivers_list_mutex);
329
[798f364]330 /* free name and driver */
[cb41a5e]331 if (driver->name != NULL)
[798f364]332 free(driver->name);
[6519d6f]333
[798f364]334 free(driver);
[6519d6f]335
[07e4a3c]336 return EOK;
337}
338
[798f364]339/** Register instance of device
340 *
341 */
342static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]343 devmap_driver_t *driver)
[07e4a3c]344{
[6519d6f]345 if (driver == NULL) {
[b74959bd]346 ipc_answer_0(iid, EREFUSED);
[798f364]347 return;
348 }
349
350 /* Create new device entry */
[6519d6f]351 devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
352 if (device == NULL) {
[b74959bd]353 ipc_answer_0(iid, ENOMEM);
[798f364]354 return;
355 }
356
357 /* Get device name */
[6519d6f]358 ipc_callid_t callid;
359 size_t size;
[0da4e41]360 if (!async_data_write_receive(&callid, &size)) {
[798f364]361 free(device);
[b74959bd]362 ipc_answer_0(iid, EREFUSED);
[798f364]363 return;
364 }
[6519d6f]365
[798f364]366 if (size > DEVMAP_NAME_MAXLEN) {
367 free(device);
[b74959bd]368 ipc_answer_0(callid, EINVAL);
369 ipc_answer_0(iid, EREFUSED);
[798f364]370 return;
371 }
[21c5d41]372
373 /* +1 for terminating \0 */
374 device->name = (char *) malloc(size + 1);
[6519d6f]375
376 if (device->name == NULL) {
[798f364]377 free(device);
[b74959bd]378 ipc_answer_0(callid, ENOMEM);
379 ipc_answer_0(iid, EREFUSED);
[798f364]380 return;
[07e4a3c]381 }
[798f364]382
[0da4e41]383 async_data_write_finalize(callid, device->name, size);
[798f364]384 device->name[size] = 0;
[6519d6f]385
[798f364]386 list_initialize(&(device->devices));
387 list_initialize(&(device->driver_devices));
[6519d6f]388
[fc02cc41]389 fibril_mutex_lock(&devices_list_mutex);
390
[798f364]391 /* Check that device with such name is not already registered */
392 if (NULL != devmap_device_find_name(device->name)) {
[21c5d41]393 printf(NAME ": Device '%s' already registered\n", device->name);
[fc02cc41]394 fibril_mutex_unlock(&devices_list_mutex);
[798f364]395 free(device->name);
396 free(device);
[b74959bd]397 ipc_answer_0(iid, EEXISTS);
[798f364]398 return;
[07e4a3c]399 }
[6519d6f]400
[798f364]401 /* Get unique device handle */
[6519d6f]402 device->handle = devmap_create_handle();
403
[798f364]404 device->driver = driver;
[07e4a3c]405
[798f364]406 /* Insert device into list of all devices */
[b74959bd]407 list_append(&device->devices, &devices_list);
[6519d6f]408
[fc02cc41]409 /* Insert device into list of devices that belog to one driver */
410 fibril_mutex_lock(&device->driver->devices_mutex);
411
[b74959bd]412 list_append(&device->driver_devices, &device->driver->devices);
[798f364]413
[fc02cc41]414 fibril_mutex_unlock(&device->driver->devices_mutex);
[1cab2f41]415 fibril_condvar_broadcast(&devices_list_cv);
[fc02cc41]416 fibril_mutex_unlock(&devices_list_mutex);
417
[b74959bd]418 ipc_answer_1(iid, EOK, device->handle);
[07e4a3c]419}
420
[798f364]421/**
422 *
423 */
424static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]425 devmap_driver_t *driver)
[07e4a3c]426{
[798f364]427 /* TODO */
[07e4a3c]428 return EOK;
429}
[13125d3]430
[798f364]431/** Connect client to the device.
[6519d6f]432 *
[798f364]433 * Find device driver owning requested device and forward
434 * the message to it.
[6519d6f]435 *
[798f364]436 */
437static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
438{
439 /*
440 * Get handle from request
441 */
[cb41a5e]442 dev_handle_t handle = IPC_GET_ARG2(*call);
[6519d6f]443 devmap_device_t *dev = devmap_device_find_handle(handle);
444
[cb41a5e]445 if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
[b74959bd]446 ipc_answer_0(callid, ENOENT);
[798f364]447 return;
[6519d6f]448 }
449
[cb41a5e]450 ipc_forward_fast(callid, dev->driver->phone, dev->handle,
[b61d47d]451 IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
[798f364]452}
453
454/** Find handle for device instance identified by name.
[6519d6f]455 *
[798f364]456 * In answer will be send EOK and device handle in arg1 or a error
[6519d6f]457 * code from errno.h.
458 *
[798f364]459 */
460static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
461{
[6519d6f]462 /*
[798f364]463 * Wait for incoming message with device name (but do not
464 * read the name itself until the buffer is allocated).
465 */
[6519d6f]466 ipc_callid_t callid;
467 size_t size;
[0da4e41]468 if (!async_data_write_receive(&callid, &size)) {
[b74959bd]469 ipc_answer_0(callid, EREFUSED);
470 ipc_answer_0(iid, EREFUSED);
[798f364]471 return;
472 }
[6519d6f]473
474 if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
[b74959bd]475 ipc_answer_0(callid, EINVAL);
476 ipc_answer_0(iid, EREFUSED);
[798f364]477 return;
478 }
[6519d6f]479
[798f364]480 /*
481 * Allocate buffer for device name.
482 */
[cb41a5e]483 char *name = (char *) malloc(size + 1);
[6519d6f]484 if (name == NULL) {
[b74959bd]485 ipc_answer_0(callid, ENOMEM);
486 ipc_answer_0(iid, EREFUSED);
[798f364]487 return;
[6519d6f]488 }
489
[798f364]490 /*
491 * Send confirmation to sender and get data into buffer.
492 */
[0da4e41]493 ipcarg_t retval = async_data_write_finalize(callid, name, size);
[6519d6f]494 if (retval != EOK) {
[b74959bd]495 ipc_answer_0(iid, EREFUSED);
[6519d6f]496 free(name);
[798f364]497 return;
498 }
[6519d6f]499 name[size] = '\0';
500
[c07af37]501 fibril_mutex_lock(&devices_list_mutex);
[1cab2f41]502 const devmap_device_t *dev;
503recheck:
[c07af37]504
[798f364]505 /*
[1cab2f41]506 * Find device name in the list of known devices.
[798f364]507 */
[1cab2f41]508 dev = devmap_device_find_name(name);
[6519d6f]509
[798f364]510 /*
511 * Device was not found.
512 */
[6519d6f]513 if (dev == NULL) {
514 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
[1cab2f41]515 /* Blocking lookup */
516 fibril_condvar_wait(&devices_list_cv,
517 &devices_list_mutex);
518 goto recheck;
[6519d6f]519 }
520
[b74959bd]521 ipc_answer_0(iid, ENOENT);
[6519d6f]522 free(name);
[c07af37]523 fibril_mutex_unlock(&devices_list_mutex);
[798f364]524 return;
525 }
[c07af37]526 fibril_mutex_unlock(&devices_list_mutex);
[6519d6f]527
[b74959bd]528 ipc_answer_1(iid, EOK, dev->handle);
[6519d6f]529 free(name);
[798f364]530}
531
[6519d6f]532/** Find name of device identified by id and send it to caller.
[798f364]533 *
534 */
[cb41a5e]535static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
[798f364]536{
[6519d6f]537 const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
538
[798f364]539 /*
540 * Device not found.
541 */
[6519d6f]542 if (device == NULL) {
[b74959bd]543 ipc_answer_0(iid, ENOENT);
[798f364]544 return;
545 }
[6519d6f]546
547 ipc_answer_0(iid, EOK);
548
549 /* FIXME:
550 * We have no channel from DEVMAP to client, therefore
551 * sending must be initiated by client.
552 *
[a405563]553 * size_t name_size = str_size(device->name);
554 *
[0da4e41]555 * int rc = async_data_write_send(phone, device->name, name_size);
[6519d6f]556 * if (rc != EOK) {
557 * async_wait_for(req, NULL);
558 * return rc;
559 * }
560 */
561
[798f364]562 /* TODO: send name in response */
563}
564
[cb41a5e]565static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
566{
[fc02cc41]567 fibril_mutex_lock(&devices_list_mutex);
[cb41a5e]568 ipc_answer_1(iid, EOK, list_count(&devices_list));
[fc02cc41]569 fibril_mutex_unlock(&devices_list_mutex);
[cb41a5e]570}
571
572static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
573{
[fc02cc41]574 fibril_mutex_lock(&devices_list_mutex);
575
[cb41a5e]576 ipc_callid_t callid;
577 size_t size;
[0da4e41]578 if (!async_data_read_receive(&callid, &size)) {
[cb41a5e]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
[5d0e461]590 size_t count = size / sizeof(dev_desc_t);
[cb41a5e]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
[5d0e461]598 size_t pos = 0;
[cb41a5e]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
[0da4e41]610 ipcarg_t retval = async_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
[cb41a5e]611 if (retval != EOK) {
612 ipc_answer_0(iid, EREFUSED);
613 free(desc);
614 return;
615 }
616
617 free(desc);
618
[fc02cc41]619 fibril_mutex_unlock(&devices_list_mutex);
620
[cb41a5e]621 ipc_answer_1(iid, EOK, pos);
622}
623
[7fcb74c]624static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall)
[cb41a5e]625{
[7fcb74c]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
[cb41a5e]644 /* Create NULL device entry */
645 devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
[7fcb74c]646 if (device == NULL) {
647 fibril_mutex_unlock(&null_devices_mutex);
648 ipc_answer_0(iid, ENOMEM);
649 return;
650 }
[cb41a5e]651
[7fcb74c]652 char null[DEVMAP_NAME_MAXLEN];
653 snprintf(null, DEVMAP_NAME_MAXLEN, "null%u", i);
654
655 device->name = str_dup(null);
[cb41a5e]656 if (device->name == NULL) {
[7fcb74c]657 fibril_mutex_unlock(&null_devices_mutex);
[cb41a5e]658 free(device);
[7fcb74c]659 ipc_answer_0(iid, ENOMEM);
660 return;
[cb41a5e]661 }
662
663 list_initialize(&(device->devices));
664 list_initialize(&(device->driver_devices));
665
[fc02cc41]666 fibril_mutex_lock(&devices_list_mutex);
667
[cb41a5e]668 /* Get unique device handle */
669 device->handle = devmap_create_handle();
670 device->driver = NULL;
671
[7fcb74c]672 /* Insert device into list of all devices
673 and into null devices array */
[cb41a5e]674 list_append(&device->devices, &devices_list);
[7fcb74c]675 null_devices[i] = device;
[cb41a5e]676
[fc02cc41]677 fibril_mutex_unlock(&devices_list_mutex);
[7fcb74c]678 fibril_mutex_unlock(&null_devices_mutex);
679
680 ipc_answer_1(iid, EOK, (ipcarg_t) i);
681}
682
683static 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 */
706static 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);
[fc02cc41]715
[cb41a5e]716 return true;
717}
718
[798f364]719/** Handle connection with device driver.
[13125d3]720 *
721 */
[21c5d41]722static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
[13125d3]723{
[6519d6f]724 /* Accept connection */
725 ipc_answer_0(iid, EOK);
726
[5d0e461]727 devmap_driver_t *driver = NULL;
[798f364]728 devmap_driver_register(&driver);
[6519d6f]729
[21c5d41]730 if (NULL == driver)
[798f364]731 return;
732
[6519d6f]733 bool cont = true;
[07e4a3c]734 while (cont) {
[6519d6f]735 ipc_call_t call;
736 ipc_callid_t callid = async_get_call(&call);
737
738 switch (IPC_GET_METHOD(call)) {
[13125d3]739 case IPC_M_PHONE_HUNGUP:
[07e4a3c]740 cont = false;
[6519d6f]741 continue;
[798f364]742 case DEVMAP_DRIVER_UNREGISTER:
[6519d6f]743 if (NULL == driver)
[b74959bd]744 ipc_answer_0(callid, ENOENT);
[6519d6f]745 else
[b74959bd]746 ipc_answer_0(callid, EOK);
[07e4a3c]747 break;
[798f364]748 case DEVMAP_DEVICE_REGISTER:
749 /* Register one instance of device */
750 devmap_device_register(callid, &call, driver);
[07e4a3c]751 break;
[798f364]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:
[cb41a5e]760 devmap_get_name(callid, &call);
[798f364]761 break;
762 default:
[6519d6f]763 if (!(callid & IPC_CALLID_NOTIFICATION))
[b74959bd]764 ipc_answer_0(callid, ENOENT);
[798f364]765 }
766 }
767
[7fcb74c]768 if (driver != NULL) {
[6519d6f]769 /*
[b74959bd]770 * Unregister the device driver and all its devices.
771 */
[798f364]772 devmap_driver_unregister(driver);
773 driver = NULL;
774 }
775}
776
777/** Handle connection with device client.
778 *
779 */
[21c5d41]780static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
[798f364]781{
[6519d6f]782 /* Accept connection */
783 ipc_answer_0(iid, EOK);
784
[798f364]785 bool cont = true;
786 while (cont) {
[6519d6f]787 ipc_call_t call;
788 ipc_callid_t callid = async_get_call(&call);
789
790 switch (IPC_GET_METHOD(call)) {
[798f364]791 case IPC_M_PHONE_HUNGUP:
[07e4a3c]792 cont = false;
[6519d6f]793 continue;
[798f364]794 case DEVMAP_DEVICE_GET_HANDLE:
[6519d6f]795 devmap_get_handle(callid, &call);
[07e4a3c]796 break;
[798f364]797 case DEVMAP_DEVICE_GET_NAME:
798 devmap_get_name(callid, &call);
[13125d3]799 break;
[7fcb74c]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;
[cb41a5e]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;
[13125d3]812 default:
[6519d6f]813 if (!(callid & IPC_CALLID_NOTIFICATION))
[b74959bd]814 ipc_answer_0(callid, ENOENT);
[13125d3]815 }
816 }
817}
818
[6519d6f]819/** Function for handling connections to devmap
[798f364]820 *
821 */
[21c5d41]822static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
[798f364]823{
[21c5d41]824 /* Select interface */
825 switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
[7f3e3e7]826 case DEVMAP_DRIVER:
827 devmap_connection_driver(iid, icall);
828 break;
829 case DEVMAP_CLIENT:
830 devmap_connection_client(iid, icall);
831 break;
[b61d47d]832 case DEVMAP_CONNECT_TO_DEVICE:
[21c5d41]833 /* Connect client to selected device */
[b61d47d]834 devmap_forward(iid, icall);
835 break;
[7f3e3e7]836 default:
[6519d6f]837 /* No such interface */
[5d0e461]838 ipc_answer_0(iid, ENOENT);
[798f364]839 }
840}
[13125d3]841
[798f364]842/**
843 *
844 */
[13125d3]845int main(int argc, char *argv[])
846{
[21c5d41]847 printf(NAME ": HelenOS Device Mapper\n");
848
[cb41a5e]849 if (!devmap_init()) {
[21c5d41]850 printf(NAME ": Error while initializing service\n");
[13125d3]851 return -1;
852 }
[21c5d41]853
[c07af37]854 /* Set a handler of incomming connections */
[798f364]855 async_set_client_connection(devmap_connection);
[7fcb74c]856
[7f3e3e7]857 /* Register device mapper at naming service */
[6519d6f]858 ipcarg_t phonead;
[38c706cc]859 if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
[13125d3]860 return -1;
861
[21c5d41]862 printf(NAME ": Accepting connections\n");
[13125d3]863 async_manager();
[6519d6f]864
[13125d3]865 /* Never reached */
866 return 0;
867}
868
869/**
870 * @}
871 */
Note: See TracBrowser for help on using the repository browser.