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

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

Handle pending lookups using only one fibril.

  • Property mode set to 100644
File size: 19.3 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>
[c07af37]48#include <assert.h>
[13125d3]49
[6519d6f]50#define NAME "devmap"
[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
[6519d6f]87/** Pending lookup structure. */
88typedef 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;
[07e4a3c]93
[798f364]94LIST_INITIALIZE(devices_list);
95LIST_INITIALIZE(drivers_list);
[6519d6f]96LIST_INITIALIZE(pending_req);
[798f364]97
[c07af37]98static bool pending_new_dev = false;
99static FIBRIL_CONDVAR_INITIALIZE(pending_cv);
100
[fc02cc41]101/* Locking order:
102 * drivers_list_mutex
103 * devices_list_mutex
104 * (devmap_driver_t *)->devices_mutex
105 * create_handle_mutex
106 **/
107
108static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
109static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
110static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
111
[cb41a5e]112static dev_handle_t last_handle = 0;
113
114static dev_handle_t devmap_create_handle(void)
[798f364]115{
116 /* TODO: allow reusing old handles after their unregistration
[5d0e461]117 * and implement some version of LRU algorithm, avoid overflow
[6519d6f]118 */
119
[fc02cc41]120 fibril_mutex_lock(&create_handle_mutex);
[cb41a5e]121 last_handle++;
[fc02cc41]122 fibril_mutex_unlock(&create_handle_mutex);
[6519d6f]123
[cb41a5e]124 return last_handle;
[13125d3]125}
126
[798f364]127/** Find device with given name.
128 *
129 */
130static devmap_device_t *devmap_device_find_name(const char *name)
[07e4a3c]131{
[6519d6f]132 link_t *item = devices_list.next;
[798f364]133 devmap_device_t *device = NULL;
[6519d6f]134
[798f364]135 while (item != &devices_list) {
136 device = list_get_instance(item, devmap_device_t, devices);
[5d0e461]137 if (str_cmp(device->name, name) == 0)
[798f364]138 break;
139 item = item->next;
140 }
[6519d6f]141
[21c5d41]142 if (item == &devices_list)
[798f364]143 return NULL;
[6519d6f]144
[798f364]145 device = list_get_instance(item, devmap_device_t, devices);
146 return device;
147}
148
149/** Find device with given handle.
[6519d6f]150 *
[798f364]151 * @todo: use hash table
[6519d6f]152 *
[798f364]153 */
[cb41a5e]154static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
[798f364]155{
[fc02cc41]156 fibril_mutex_lock(&devices_list_mutex);
157
[6519d6f]158 link_t *item = (&devices_list)->next;
[798f364]159 devmap_device_t *device = NULL;
160
161 while (item != &devices_list) {
162 device = list_get_instance(item, devmap_device_t, devices);
[6519d6f]163 if (device->handle == handle)
[798f364]164 break;
165 item = item->next;
166 }
[6519d6f]167
[fc02cc41]168 if (item == &devices_list) {
169 fibril_mutex_unlock(&devices_list_mutex);
[798f364]170 return NULL;
[fc02cc41]171 }
[6519d6f]172
[798f364]173 device = list_get_instance(item, devmap_device_t, devices);
174
[fc02cc41]175 fibril_mutex_unlock(&devices_list_mutex);
176
[798f364]177 return device;
178}
179
[7f3e3e7]180/**
181 * Unregister device and free it. It's assumed that driver's device list is
182 * already locked.
[798f364]183 */
184static int devmap_device_unregister_core(devmap_device_t *device)
185{
186 list_remove(&(device->devices));
187 list_remove(&(device->driver_devices));
[6519d6f]188
189 free(device->name);
[798f364]190 free(device);
[6519d6f]191
[798f364]192 return EOK;
193}
194
[7f3e3e7]195/**
196 * Read info about new driver and add it into linked list of registered
197 * drivers.
[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;
[c07af37]352
[6519d6f]353loop:
[c07af37]354 fibril_mutex_lock(&devices_list_mutex);
355 while (!pending_new_dev)
356 fibril_condvar_wait(&pending_cv, &devices_list_mutex);
357rescan:
[6519d6f]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);
[5d0e461]370
[c07af37]371 goto rescan;
[6519d6f]372 }
[c07af37]373 pending_new_dev = false;
374 fibril_mutex_unlock(&devices_list_mutex);
375 goto loop;
[6519d6f]376}
377
378
[798f364]379/** Register instance of device
380 *
381 */
382static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]383 devmap_driver_t *driver)
[07e4a3c]384{
[6519d6f]385 if (driver == NULL) {
[b74959bd]386 ipc_answer_0(iid, EREFUSED);
[798f364]387 return;
388 }
389
390 /* Create new device entry */
[6519d6f]391 devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
392 if (device == NULL) {
[b74959bd]393 ipc_answer_0(iid, ENOMEM);
[798f364]394 return;
395 }
396
397 /* Get device name */
[6519d6f]398 ipc_callid_t callid;
399 size_t size;
[3115355]400 if (!ipc_data_write_receive(&callid, &size)) {
[798f364]401 free(device);
[b74959bd]402 ipc_answer_0(iid, EREFUSED);
[798f364]403 return;
404 }
[6519d6f]405
[798f364]406 if (size > DEVMAP_NAME_MAXLEN) {
407 free(device);
[b74959bd]408 ipc_answer_0(callid, EINVAL);
409 ipc_answer_0(iid, EREFUSED);
[798f364]410 return;
411 }
[21c5d41]412
413 /* +1 for terminating \0 */
414 device->name = (char *) malloc(size + 1);
[6519d6f]415
416 if (device->name == NULL) {
[798f364]417 free(device);
[b74959bd]418 ipc_answer_0(callid, ENOMEM);
419 ipc_answer_0(iid, EREFUSED);
[798f364]420 return;
[07e4a3c]421 }
[798f364]422
[215e375]423 ipc_data_write_finalize(callid, device->name, size);
[798f364]424 device->name[size] = 0;
[6519d6f]425
[798f364]426 list_initialize(&(device->devices));
427 list_initialize(&(device->driver_devices));
[6519d6f]428
[fc02cc41]429 fibril_mutex_lock(&devices_list_mutex);
430
[798f364]431 /* Check that device with such name is not already registered */
432 if (NULL != devmap_device_find_name(device->name)) {
[21c5d41]433 printf(NAME ": Device '%s' already registered\n", device->name);
[fc02cc41]434 fibril_mutex_unlock(&devices_list_mutex);
[798f364]435 free(device->name);
436 free(device);
[b74959bd]437 ipc_answer_0(iid, EEXISTS);
[798f364]438 return;
[07e4a3c]439 }
[6519d6f]440
[798f364]441 /* Get unique device handle */
[6519d6f]442 device->handle = devmap_create_handle();
443
[798f364]444 device->driver = driver;
[07e4a3c]445
[798f364]446 /* Insert device into list of all devices */
[b74959bd]447 list_append(&device->devices, &devices_list);
[6519d6f]448
[fc02cc41]449 /* Insert device into list of devices that belog to one driver */
450 fibril_mutex_lock(&device->driver->devices_mutex);
451
[b74959bd]452 list_append(&device->driver_devices, &device->driver->devices);
[798f364]453
[fc02cc41]454 fibril_mutex_unlock(&device->driver->devices_mutex);
[c07af37]455 pending_new_dev = true;
456 fibril_condvar_signal(&pending_cv);
[fc02cc41]457 fibril_mutex_unlock(&devices_list_mutex);
458
[b74959bd]459 ipc_answer_1(iid, EOK, device->handle);
[07e4a3c]460}
461
[798f364]462/**
463 *
464 */
465static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
[b74959bd]466 devmap_driver_t *driver)
[07e4a3c]467{
[798f364]468 /* TODO */
[07e4a3c]469 return EOK;
470}
[13125d3]471
[798f364]472/** Connect client to the device.
[6519d6f]473 *
[798f364]474 * Find device driver owning requested device and forward
475 * the message to it.
[6519d6f]476 *
[798f364]477 */
478static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
479{
480 /*
481 * Get handle from request
482 */
[cb41a5e]483 dev_handle_t handle = IPC_GET_ARG2(*call);
[6519d6f]484 devmap_device_t *dev = devmap_device_find_handle(handle);
485
[cb41a5e]486 if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
[b74959bd]487 ipc_answer_0(callid, ENOENT);
[798f364]488 return;
[6519d6f]489 }
490
[cb41a5e]491 ipc_forward_fast(callid, dev->driver->phone, dev->handle,
[b61d47d]492 IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
[798f364]493}
494
495/** Find handle for device instance identified by name.
[6519d6f]496 *
[798f364]497 * In answer will be send EOK and device handle in arg1 or a error
[6519d6f]498 * code from errno.h.
499 *
[798f364]500 */
501static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
502{
[6519d6f]503 /*
[798f364]504 * Wait for incoming message with device name (but do not
505 * read the name itself until the buffer is allocated).
506 */
[6519d6f]507 ipc_callid_t callid;
508 size_t size;
509 if (!ipc_data_write_receive(&callid, &size)) {
[b74959bd]510 ipc_answer_0(callid, EREFUSED);
511 ipc_answer_0(iid, EREFUSED);
[798f364]512 return;
513 }
[6519d6f]514
515 if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
[b74959bd]516 ipc_answer_0(callid, EINVAL);
517 ipc_answer_0(iid, EREFUSED);
[798f364]518 return;
519 }
[6519d6f]520
[798f364]521 /*
522 * Allocate buffer for device name.
523 */
[cb41a5e]524 char *name = (char *) malloc(size + 1);
[6519d6f]525 if (name == NULL) {
[b74959bd]526 ipc_answer_0(callid, ENOMEM);
527 ipc_answer_0(iid, EREFUSED);
[798f364]528 return;
[6519d6f]529 }
530
[798f364]531 /*
532 * Send confirmation to sender and get data into buffer.
533 */
[6519d6f]534 ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
535 if (retval != EOK) {
[b74959bd]536 ipc_answer_0(iid, EREFUSED);
[6519d6f]537 free(name);
[798f364]538 return;
539 }
[6519d6f]540 name[size] = '\0';
541
[c07af37]542 fibril_mutex_lock(&devices_list_mutex);
543
[798f364]544 /*
545 * Find device name in linked list of known devices.
546 */
[6519d6f]547 const devmap_device_t *dev = devmap_device_find_name(name);
548
[798f364]549 /*
550 * Device was not found.
551 */
[6519d6f]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) {
[c07af37]557 fibril_mutex_unlock(&devices_list_mutex);
[6519d6f]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);
[c07af37]566 fibril_mutex_unlock(&devices_list_mutex);
[6519d6f]567 return;
568 }
569
[b74959bd]570 ipc_answer_0(iid, ENOENT);
[6519d6f]571 free(name);
[c07af37]572 fibril_mutex_unlock(&devices_list_mutex);
[798f364]573 return;
574 }
[c07af37]575 fibril_mutex_unlock(&devices_list_mutex);
[6519d6f]576
[b74959bd]577 ipc_answer_1(iid, EOK, dev->handle);
[6519d6f]578 free(name);
[798f364]579}
580
[6519d6f]581/** Find name of device identified by id and send it to caller.
[798f364]582 *
583 */
[cb41a5e]584static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
[798f364]585{
[6519d6f]586 const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
587
[798f364]588 /*
589 * Device not found.
590 */
[6519d6f]591 if (device == NULL) {
[b74959bd]592 ipc_answer_0(iid, ENOENT);
[798f364]593 return;
594 }
[6519d6f]595
596 ipc_answer_0(iid, EOK);
597
[92fd52d7]598 size_t name_size = str_size(device->name);
[6519d6f]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
[798f364]611 /* TODO: send name in response */
612}
613
[cb41a5e]614static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
615{
[fc02cc41]616 fibril_mutex_lock(&devices_list_mutex);
[cb41a5e]617 ipc_answer_1(iid, EOK, list_count(&devices_list));
[fc02cc41]618 fibril_mutex_unlock(&devices_list_mutex);
[cb41a5e]619}
620
621static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
622{
[fc02cc41]623 fibril_mutex_lock(&devices_list_mutex);
624
[cb41a5e]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
[5d0e461]639 size_t count = size / sizeof(dev_desc_t);
[cb41a5e]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
[5d0e461]647 size_t pos = 0;
[cb41a5e]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
[fc02cc41]668 fibril_mutex_unlock(&devices_list_mutex);
669
[cb41a5e]670 ipc_answer_1(iid, EOK, pos);
671}
672
673/** Initialize device mapper.
674 *
675 *
676 */
[c07af37]677static bool devmap_init(void)
[cb41a5e]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
[fc02cc41]693 fibril_mutex_lock(&devices_list_mutex);
694
[cb41a5e]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
[fc02cc41]702 fibril_mutex_unlock(&devices_list_mutex);
703
[cb41a5e]704 return true;
705}
706
[798f364]707/** Handle connection with device driver.
[13125d3]708 *
709 */
[21c5d41]710static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
[13125d3]711{
[6519d6f]712 /* Accept connection */
713 ipc_answer_0(iid, EOK);
714
[5d0e461]715 devmap_driver_t *driver = NULL;
[798f364]716 devmap_driver_register(&driver);
[6519d6f]717
[21c5d41]718 if (NULL == driver)
[798f364]719 return;
720
[6519d6f]721 bool cont = true;
[07e4a3c]722 while (cont) {
[6519d6f]723 ipc_call_t call;
724 ipc_callid_t callid = async_get_call(&call);
725
726 switch (IPC_GET_METHOD(call)) {
[13125d3]727 case IPC_M_PHONE_HUNGUP:
[07e4a3c]728 cont = false;
[6519d6f]729 continue;
[798f364]730 case DEVMAP_DRIVER_UNREGISTER:
[6519d6f]731 if (NULL == driver)
[b74959bd]732 ipc_answer_0(callid, ENOENT);
[6519d6f]733 else
[b74959bd]734 ipc_answer_0(callid, EOK);
[07e4a3c]735 break;
[798f364]736 case DEVMAP_DEVICE_REGISTER:
737 /* Register one instance of device */
738 devmap_device_register(callid, &call, driver);
[07e4a3c]739 break;
[798f364]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:
[cb41a5e]748 devmap_get_name(callid, &call);
[798f364]749 break;
750 default:
[6519d6f]751 if (!(callid & IPC_CALLID_NOTIFICATION))
[b74959bd]752 ipc_answer_0(callid, ENOENT);
[798f364]753 }
754 }
755
756 if (NULL != driver) {
[6519d6f]757 /*
[b74959bd]758 * Unregister the device driver and all its devices.
759 */
[798f364]760 devmap_driver_unregister(driver);
761 driver = NULL;
762 }
763}
764
765/** Handle connection with device client.
766 *
767 */
[21c5d41]768static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
[798f364]769{
[6519d6f]770 /* Accept connection */
771 ipc_answer_0(iid, EOK);
772
[798f364]773 bool cont = true;
774 while (cont) {
[6519d6f]775 ipc_call_t call;
776 ipc_callid_t callid = async_get_call(&call);
777
778 switch (IPC_GET_METHOD(call)) {
[798f364]779 case IPC_M_PHONE_HUNGUP:
[07e4a3c]780 cont = false;
[6519d6f]781 continue;
[798f364]782 case DEVMAP_DEVICE_GET_HANDLE:
[6519d6f]783 devmap_get_handle(callid, &call);
[07e4a3c]784 break;
[798f364]785 case DEVMAP_DEVICE_GET_NAME:
786 devmap_get_name(callid, &call);
[13125d3]787 break;
[cb41a5e]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;
[13125d3]794 default:
[6519d6f]795 if (!(callid & IPC_CALLID_NOTIFICATION))
[b74959bd]796 ipc_answer_0(callid, ENOENT);
[13125d3]797 }
798 }
799}
800
[6519d6f]801/** Function for handling connections to devmap
[798f364]802 *
803 */
[21c5d41]804static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
[798f364]805{
[21c5d41]806 /* Select interface */
807 switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
[7f3e3e7]808 case DEVMAP_DRIVER:
809 devmap_connection_driver(iid, icall);
810 break;
811 case DEVMAP_CLIENT:
812 devmap_connection_client(iid, icall);
813 break;
[b61d47d]814 case DEVMAP_CONNECT_TO_DEVICE:
[21c5d41]815 /* Connect client to selected device */
[b61d47d]816 devmap_forward(iid, icall);
817 break;
[7f3e3e7]818 default:
[6519d6f]819 /* No such interface */
[5d0e461]820 ipc_answer_0(iid, ENOENT);
[798f364]821 }
822}
[13125d3]823
[798f364]824/**
825 *
826 */
[13125d3]827int main(int argc, char *argv[])
828{
[21c5d41]829 printf(NAME ": HelenOS Device Mapper\n");
830
[cb41a5e]831 if (!devmap_init()) {
[21c5d41]832 printf(NAME ": Error while initializing service\n");
[13125d3]833 return -1;
834 }
[21c5d41]835
[c07af37]836 /* Set a handler of incomming connections */
[798f364]837 async_set_client_connection(devmap_connection);
[c07af37]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);
[6519d6f]843
[7f3e3e7]844 /* Register device mapper at naming service */
[6519d6f]845 ipcarg_t phonead;
[38c706cc]846 if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
[13125d3]847 return -1;
848
[21c5d41]849 printf(NAME ": Accepting connections\n");
[13125d3]850 async_manager();
[6519d6f]851
[13125d3]852 /* Never reached */
853 return 0;
854}
855
856/**
857 * @}
858 */
Note: See TracBrowser for help on using the repository browser.