source: mainline/uspace/srv/devmap/devmap.c@ fc02cc41

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fc02cc41 was fc02cc41, checked in by Martin Decky <martin@…>, 16 years ago

get back fine-grained locking (which was removed in commit 4458), but this time with proper fibril synchronization

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