Subversion Repositories HelenOS

Rev

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