Subversion Repositories HelenOS

Rev

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