Subversion Repositories HelenOS

Rev

Rev 4524 | Rev 4570 | 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. #include <assert.h>
  49.  
  50. #define NAME  "devmap"
  51.  
  52. /** Representation of device driver.
  53.  *
  54.  * Each driver is responsible for a set of devices.
  55.  *
  56.  */
  57. typedef struct {
  58.     /** Pointers to previous and next drivers in linked list */
  59.     link_t drivers;
  60.     /** Pointer to the linked list of devices controlled by this driver */
  61.     link_t devices;
  62.     /** Phone asociated with this driver */
  63.     ipcarg_t phone;
  64.     /** Device driver name */
  65.     char *name;
  66.     /** Fibril mutex for list of devices owned by this driver */
  67.     fibril_mutex_t devices_mutex;
  68. } devmap_driver_t;
  69.  
  70. /** Info about registered device
  71.  *
  72.  */
  73. typedef struct {
  74.     /** Pointer to the previous and next device in the list of all devices */
  75.     link_t devices;
  76.     /** Pointer to the previous and next device in the list of devices
  77.         owned by one driver */
  78.     link_t driver_devices;
  79.     /** Unique device identifier  */
  80.     dev_handle_t handle;
  81.     /** Device name */
  82.     char *name;
  83.     /** Device driver handling this device */
  84.     devmap_driver_t *driver;
  85. } devmap_device_t;
  86.  
  87. /** Pending lookup structure. */
  88. typedef struct {
  89.     link_t link;
  90.     char *name;              /**< Device name */
  91.     ipc_callid_t callid;     /**< Call ID waiting for the lookup */
  92. } pending_req_t;
  93.  
  94. LIST_INITIALIZE(devices_list);
  95. LIST_INITIALIZE(drivers_list);
  96. LIST_INITIALIZE(pending_req);
  97.  
  98. static bool pending_new_dev = false;
  99. static FIBRIL_CONDVAR_INITIALIZE(pending_cv);
  100.  
  101. /* Locking order:
  102.  *  drivers_list_mutex
  103.  *  devices_list_mutex
  104.  *  (devmap_driver_t *)->devices_mutex
  105.  *  create_handle_mutex
  106.  **/
  107.  
  108. static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
  109. static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
  110. static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
  111.  
  112. static dev_handle_t last_handle = 0;
  113.  
  114. static dev_handle_t devmap_create_handle(void)
  115. {
  116.     /* TODO: allow reusing old handles after their unregistration
  117.      * and implement some version of LRU algorithm, avoid overflow
  118.      */
  119.    
  120.     fibril_mutex_lock(&create_handle_mutex);
  121.     last_handle++;
  122.     fibril_mutex_unlock(&create_handle_mutex);
  123.    
  124.     return last_handle;
  125. }
  126.  
  127. /** Find device with given name.
  128.  *
  129.  */
  130. static devmap_device_t *devmap_device_find_name(const char *name)
  131. {
  132.     link_t *item = devices_list.next;
  133.     devmap_device_t *device = NULL;
  134.    
  135.     while (item != &devices_list) {
  136.         device = list_get_instance(item, devmap_device_t, devices);
  137.         if (str_cmp(device->name, name) == 0)
  138.             break;
  139.         item = item->next;
  140.     }
  141.    
  142.     if (item == &devices_list)
  143.         return NULL;
  144.    
  145.     device = list_get_instance(item, devmap_device_t, devices);
  146.     return device;
  147. }
  148.  
  149. /** Find device with given handle.
  150.  *
  151.  * @todo: use hash table
  152.  *
  153.  */
  154. static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
  155. {
  156.     fibril_mutex_lock(&devices_list_mutex);
  157.    
  158.     link_t *item = (&devices_list)->next;
  159.     devmap_device_t *device = NULL;
  160.    
  161.     while (item != &devices_list) {
  162.         device = list_get_instance(item, devmap_device_t, devices);
  163.         if (device->handle == handle)
  164.             break;
  165.         item = item->next;
  166.     }
  167.    
  168.     if (item == &devices_list) {
  169.         fibril_mutex_unlock(&devices_list_mutex);
  170.         return NULL;
  171.     }
  172.    
  173.     device = list_get_instance(item, devmap_device_t, devices);
  174.    
  175.     fibril_mutex_unlock(&devices_list_mutex);
  176.    
  177.     return device;
  178. }
  179.  
  180. /**
  181.  * Unregister device and free it. It's assumed that driver's device list is
  182.  * already locked.
  183.  */
  184. static int devmap_device_unregister_core(devmap_device_t *device)
  185. {
  186.     list_remove(&(device->devices));
  187.     list_remove(&(device->driver_devices));
  188.    
  189.     free(device->name);
  190.     free(device);
  191.    
  192.     return EOK;
  193. }
  194.  
  195. /**
  196.  * Read info about new driver and add it into linked list of registered
  197.  * drivers.
  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.     fibril_mutex_lock(&devices_list_mutex);
  355.     while (!pending_new_dev)
  356.         fibril_condvar_wait(&pending_cv, &devices_list_mutex);
  357. rescan:
  358.     for (cur = pending_req.next; cur != &pending_req; cur = cur->next) {
  359.         pending_req_t *pr = list_get_instance(cur, pending_req_t, link);
  360.        
  361.         const devmap_device_t *dev = devmap_device_find_name(pr->name);
  362.         if (!dev)
  363.             continue;
  364.        
  365.         ipc_answer_1(pr->callid, EOK, dev->handle);
  366.        
  367.         free(pr->name);
  368.         list_remove(cur);
  369.         free(pr);
  370.        
  371.         goto rescan;
  372.     }
  373.     pending_new_dev = false;
  374.     fibril_mutex_unlock(&devices_list_mutex);
  375.     goto loop;
  376. }
  377.  
  378.  
  379. /** Register instance of device
  380.  *
  381.  */
  382. static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
  383.     devmap_driver_t *driver)
  384. {
  385.     if (driver == NULL) {
  386.         ipc_answer_0(iid, EREFUSED);
  387.         return;
  388.     }
  389.    
  390.     /* Create new device entry */
  391.     devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
  392.     if (device == NULL) {
  393.         ipc_answer_0(iid, ENOMEM);
  394.         return;
  395.     }
  396.    
  397.     /* Get device name */
  398.     ipc_callid_t callid;
  399.     size_t size;
  400.     if (!ipc_data_write_receive(&callid, &size)) {
  401.         free(device);
  402.         ipc_answer_0(iid, EREFUSED);
  403.         return;
  404.     }
  405.    
  406.     if (size > DEVMAP_NAME_MAXLEN) {
  407.         free(device);
  408.         ipc_answer_0(callid, EINVAL);
  409.         ipc_answer_0(iid, EREFUSED);
  410.         return;
  411.     }
  412.    
  413.     /* +1 for terminating \0 */
  414.     device->name = (char *) malloc(size + 1);
  415.    
  416.     if (device->name == NULL) {
  417.         free(device);
  418.         ipc_answer_0(callid, ENOMEM);
  419.         ipc_answer_0(iid, EREFUSED);
  420.         return;
  421.     }
  422.    
  423.     ipc_data_write_finalize(callid, device->name, size);
  424.     device->name[size] = 0;
  425.    
  426.     list_initialize(&(device->devices));
  427.     list_initialize(&(device->driver_devices));
  428.    
  429.     fibril_mutex_lock(&devices_list_mutex);
  430.    
  431.     /* Check that device with such name is not already registered */
  432.     if (NULL != devmap_device_find_name(device->name)) {
  433.         printf(NAME ": Device '%s' already registered\n", device->name);
  434.         fibril_mutex_unlock(&devices_list_mutex);
  435.         free(device->name);
  436.         free(device);
  437.         ipc_answer_0(iid, EEXISTS);
  438.         return;
  439.     }
  440.    
  441.     /* Get unique device handle */
  442.     device->handle = devmap_create_handle();
  443.    
  444.     device->driver = driver;
  445.    
  446.     /* Insert device into list of all devices  */
  447.     list_append(&device->devices, &devices_list);
  448.    
  449.     /* Insert device into list of devices that belog to one driver */
  450.     fibril_mutex_lock(&device->driver->devices_mutex);
  451.    
  452.     list_append(&device->driver_devices, &device->driver->devices);
  453.    
  454.     fibril_mutex_unlock(&device->driver->devices_mutex);
  455.     pending_new_dev = true;
  456.     fibril_condvar_signal(&pending_cv);
  457.     fibril_mutex_unlock(&devices_list_mutex);
  458.    
  459.     ipc_answer_1(iid, EOK, device->handle);
  460. }
  461.  
  462. /**
  463.  *
  464.  */
  465. static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
  466.     devmap_driver_t *driver)
  467. {
  468.     /* TODO */
  469.     return EOK;
  470. }
  471.  
  472. /** Connect client to the device.
  473.  *
  474.  * Find device driver owning requested device and forward
  475.  * the message to it.
  476.  *
  477.  */
  478. static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
  479. {
  480.     /*
  481.      * Get handle from request
  482.      */
  483.     dev_handle_t handle = IPC_GET_ARG2(*call);
  484.     devmap_device_t *dev = devmap_device_find_handle(handle);
  485.    
  486.     if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
  487.         ipc_answer_0(callid, ENOENT);
  488.         return;
  489.     }
  490.    
  491.     ipc_forward_fast(callid, dev->driver->phone, dev->handle,
  492.         IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
  493. }
  494.  
  495. /** Find handle for device instance identified by name.
  496.  *
  497.  * In answer will be send EOK and device handle in arg1 or a error
  498.  * code from errno.h.
  499.  *
  500.  */
  501. static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
  502. {
  503.     /*
  504.      * Wait for incoming message with device name (but do not
  505.      * read the name itself until the buffer is allocated).
  506.      */
  507.     ipc_callid_t callid;
  508.     size_t size;
  509.     if (!ipc_data_write_receive(&callid, &size)) {
  510.         ipc_answer_0(callid, EREFUSED);
  511.         ipc_answer_0(iid, EREFUSED);
  512.         return;
  513.     }
  514.    
  515.     if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
  516.         ipc_answer_0(callid, EINVAL);
  517.         ipc_answer_0(iid, EREFUSED);
  518.         return;
  519.     }
  520.    
  521.     /*
  522.      * Allocate buffer for device name.
  523.      */
  524.     char *name = (char *) malloc(size + 1);
  525.     if (name == NULL) {
  526.         ipc_answer_0(callid, ENOMEM);
  527.         ipc_answer_0(iid, EREFUSED);
  528.         return;
  529.     }
  530.    
  531.     /*
  532.      * Send confirmation to sender and get data into buffer.
  533.      */
  534.     ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
  535.     if (retval != EOK) {
  536.         ipc_answer_0(iid, EREFUSED);
  537.         free(name);
  538.         return;
  539.     }
  540.     name[size] = '\0';
  541.    
  542.     fibril_mutex_lock(&devices_list_mutex);
  543.  
  544.     /*
  545.      * Find device name in linked list of known devices.
  546.      */
  547.     const devmap_device_t *dev = devmap_device_find_name(name);
  548.    
  549.     /*
  550.      * Device was not found.
  551.      */
  552.     if (dev == NULL) {
  553.         if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
  554.             /* Blocking lookup, add to pending list */
  555.             pending_req_t *pr = (pending_req_t *) malloc(sizeof(pending_req_t));
  556.             if (!pr) {
  557.                 fibril_mutex_unlock(&devices_list_mutex);
  558.                 ipc_answer_0(iid, ENOMEM);
  559.                 free(name);
  560.                 return;
  561.             }
  562.            
  563.             pr->name = name;
  564.             pr->callid = iid;
  565.             list_append(&pr->link, &pending_req);
  566.             fibril_mutex_unlock(&devices_list_mutex);
  567.             return;
  568.         }
  569.        
  570.         ipc_answer_0(iid, ENOENT);
  571.         free(name);
  572.         fibril_mutex_unlock(&devices_list_mutex);
  573.         return;
  574.     }
  575.     fibril_mutex_unlock(&devices_list_mutex);
  576.    
  577.     ipc_answer_1(iid, EOK, dev->handle);
  578.     free(name);
  579. }
  580.  
  581. /** Find name of device identified by id and send it to caller.
  582.  *
  583.  */
  584. static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
  585. {
  586.     const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
  587.    
  588.     /*
  589.      * Device not found.
  590.      */
  591.     if (device == NULL) {
  592.         ipc_answer_0(iid, ENOENT);
  593.         return;
  594.     }
  595.    
  596.     ipc_answer_0(iid, EOK);
  597.    
  598.     size_t name_size = str_size(device->name);
  599.    
  600.     /* FIXME:
  601.      * We have no channel from DEVMAP to client, therefore
  602.      * sending must be initiated by client.
  603.      *
  604.      * int rc = ipc_data_write_send(phone, device->name, name_size);
  605.      * if (rc != EOK) {
  606.      *     async_wait_for(req, NULL);
  607.      *     return rc;
  608.      * }
  609.      */
  610.    
  611.     /* TODO: send name in response */
  612. }
  613.  
  614. static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
  615. {
  616.     fibril_mutex_lock(&devices_list_mutex);
  617.     ipc_answer_1(iid, EOK, list_count(&devices_list));
  618.     fibril_mutex_unlock(&devices_list_mutex);
  619. }
  620.  
  621. static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
  622. {
  623.     fibril_mutex_lock(&devices_list_mutex);
  624.    
  625.     ipc_callid_t callid;
  626.     size_t size;
  627.     if (!ipc_data_read_receive(&callid, &size)) {
  628.         ipc_answer_0(callid, EREFUSED);
  629.         ipc_answer_0(iid, EREFUSED);
  630.         return;
  631.     }
  632.    
  633.     if ((size % sizeof(dev_desc_t)) != 0) {
  634.         ipc_answer_0(callid, EINVAL);
  635.         ipc_answer_0(iid, EREFUSED);
  636.         return;
  637.     }
  638.    
  639.     size_t count = size / sizeof(dev_desc_t);
  640.     dev_desc_t *desc = (dev_desc_t *) malloc(size);
  641.     if (desc == NULL) {
  642.         ipc_answer_0(callid, ENOMEM);
  643.         ipc_answer_0(iid, EREFUSED);
  644.         return;
  645.     }
  646.    
  647.     size_t pos = 0;
  648.     link_t *item = devices_list.next;
  649.    
  650.     while ((item != &devices_list) && (pos < count)) {
  651.         devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
  652.        
  653.         desc[pos].handle = device->handle;
  654.         str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
  655.         pos++;
  656.         item = item->next;
  657.     }
  658.    
  659.     ipcarg_t retval = ipc_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
  660.     if (retval != EOK) {
  661.         ipc_answer_0(iid, EREFUSED);
  662.         free(desc);
  663.         return;
  664.     }
  665.    
  666.     free(desc);
  667.    
  668.     fibril_mutex_unlock(&devices_list_mutex);
  669.    
  670.     ipc_answer_1(iid, EOK, pos);
  671. }
  672.  
  673. /** Initialize device mapper.
  674.  *
  675.  *
  676.  */
  677. static bool devmap_init(void)
  678. {
  679.     /* Create NULL device entry */
  680.     devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
  681.     if (device == NULL)
  682.         return false;
  683.    
  684.     device->name = str_dup("null");
  685.     if (device->name == NULL) {
  686.         free(device);
  687.         return false;
  688.     }
  689.    
  690.     list_initialize(&(device->devices));
  691.     list_initialize(&(device->driver_devices));
  692.    
  693.     fibril_mutex_lock(&devices_list_mutex);
  694.    
  695.     /* Get unique device handle */
  696.     device->handle = devmap_create_handle();
  697.     device->driver = NULL;
  698.    
  699.     /* Insert device into list of all devices  */
  700.     list_append(&device->devices, &devices_list);
  701.    
  702.     fibril_mutex_unlock(&devices_list_mutex);
  703.    
  704.     return true;
  705. }
  706.  
  707. /** Handle connection with device driver.
  708.  *
  709.  */
  710. static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
  711. {
  712.     /* Accept connection */
  713.     ipc_answer_0(iid, EOK);
  714.    
  715.     devmap_driver_t *driver = NULL;
  716.     devmap_driver_register(&driver);
  717.    
  718.     if (NULL == driver)
  719.         return;
  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_DRIVER_UNREGISTER:
  731.             if (NULL == driver)
  732.                 ipc_answer_0(callid, ENOENT);
  733.             else
  734.                 ipc_answer_0(callid, EOK);
  735.             break;
  736.         case DEVMAP_DEVICE_REGISTER:
  737.             /* Register one instance of device */
  738.             devmap_device_register(callid, &call, driver);
  739.             break;
  740.         case DEVMAP_DEVICE_UNREGISTER:
  741.             /* Remove instance of device identified by handler */
  742.             devmap_device_unregister(callid, &call, driver);
  743.             break;
  744.         case DEVMAP_DEVICE_GET_HANDLE:
  745.             devmap_get_handle(callid, &call);
  746.             break;
  747.         case DEVMAP_DEVICE_GET_NAME:
  748.             devmap_get_name(callid, &call);
  749.             break;
  750.         default:
  751.             if (!(callid & IPC_CALLID_NOTIFICATION))
  752.                 ipc_answer_0(callid, ENOENT);
  753.         }
  754.     }
  755.    
  756.     if (NULL != driver) {
  757.         /*
  758.          * Unregister the device driver and all its devices.
  759.          */
  760.         devmap_driver_unregister(driver);
  761.         driver = NULL;
  762.     }
  763. }
  764.  
  765. /** Handle connection with device client.
  766.  *
  767.  */
  768. static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
  769. {
  770.     /* Accept connection */
  771.     ipc_answer_0(iid, EOK);
  772.    
  773.     bool cont = true;
  774.     while (cont) {
  775.         ipc_call_t call;
  776.         ipc_callid_t callid = async_get_call(&call);
  777.        
  778.         switch (IPC_GET_METHOD(call)) {
  779.         case IPC_M_PHONE_HUNGUP:
  780.             cont = false;
  781.             continue;
  782.         case DEVMAP_DEVICE_GET_HANDLE:
  783.             devmap_get_handle(callid, &call);
  784.             break;
  785.         case DEVMAP_DEVICE_GET_NAME:
  786.             devmap_get_name(callid, &call);
  787.             break;
  788.         case DEVMAP_DEVICE_GET_COUNT:
  789.             devmap_get_count(callid, &call);
  790.             break;
  791.         case DEVMAP_DEVICE_GET_DEVICES:
  792.             devmap_get_devices(callid, &call);
  793.             break;
  794.         default:
  795.             if (!(callid & IPC_CALLID_NOTIFICATION))
  796.                 ipc_answer_0(callid, ENOENT);
  797.         }
  798.     }
  799. }
  800.  
  801. /** Function for handling connections to devmap
  802.  *
  803.  */
  804. static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
  805. {
  806.     /* Select interface */
  807.     switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
  808.     case DEVMAP_DRIVER:
  809.         devmap_connection_driver(iid, icall);
  810.         break;
  811.     case DEVMAP_CLIENT:
  812.         devmap_connection_client(iid, icall);
  813.         break;
  814.     case DEVMAP_CONNECT_TO_DEVICE:
  815.         /* Connect client to selected device */
  816.         devmap_forward(iid, icall);
  817.         break;
  818.     default:
  819.         /* No such interface */
  820.         ipc_answer_0(iid, ENOENT);
  821.     }
  822. }
  823.  
  824. /**
  825.  *
  826.  */
  827. int main(int argc, char *argv[])
  828. {
  829.     printf(NAME ": HelenOS Device Mapper\n");
  830.    
  831.     if (!devmap_init()) {
  832.         printf(NAME ": Error while initializing service\n");
  833.         return -1;
  834.     }
  835.    
  836.     /* Set a handler of incomming connections */
  837.     async_set_client_connection(devmap_connection);
  838.  
  839.     /* Create a fibril for handling pending device lookups */
  840.     fid_t fid = fibril_create(process_pending_lookup, NULL);
  841.     assert(fid);
  842.     fibril_add_ready(fid);
  843.    
  844.     /* Register device mapper at naming service */
  845.     ipcarg_t phonead;
  846.     if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
  847.         return -1;
  848.    
  849.     printf(NAME ": Accepting connections\n");
  850.     async_manager();
  851.    
  852.     /* Never reached */
  853.     return 0;
  854. }
  855.  
  856. /**
  857.  * @}
  858.  */
  859.