source: mainline/uspace/srv/devmap/devmap.c@ 1cab2f41

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

Do not use the pending mechanism in devmap.

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