Subversion Repositories HelenOS

Rev

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