Subversion Repositories HelenOS

Rev

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