Subversion Repositories HelenOS

Rev

Rev 4327 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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