Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/devmap/devmap.c

    ra405563 r63e0bdd  
    4242#include <errno.h>
    4343#include <bool.h>
    44 #include <fibril_sync.h>
     44#include <fibril_synch.h>
    4545#include <stdlib.h>
    46 #include <string.h>
     46#include <str.h>
    4747#include <ipc/devmap.h>
     48#include <assert.h>
    4849
    4950#define NAME          "devmap"
     
    6162        link_t devices;
    6263        /** Phone asociated with this driver */
    63         ipcarg_t phone;
     64        sysarg_t phone;
    6465        /** Device driver name */
    6566        char *name;
     
    6768        fibril_mutex_t devices_mutex;
    6869} devmap_driver_t;
     70
     71/** Info about registered namespaces
     72 *
     73 */
     74typedef struct {
     75        /** Pointer to the previous and next device in the list of all namespaces */
     76        link_t namespaces;
     77        /** Unique namespace identifier */
     78        devmap_handle_t handle;
     79        /** Namespace name */
     80        char *name;
     81        /** Reference count */
     82        size_t refcnt;
     83} devmap_namespace_t;
    6984
    7085/** Info about registered device
     
    7792            owned by one driver */
    7893        link_t driver_devices;
    79         /** Unique device identifier  */
    80         dev_handle_t handle;
     94        /** Unique device identifier */
     95        devmap_handle_t handle;
     96        /** Device namespace */
     97        devmap_namespace_t *namespace;
    8198        /** Device name */
    8299        char *name;
    83100        /** Device driver handling this device */
    84101        devmap_driver_t *driver;
     102        /** Use this interface when forwarding to driver. */
     103        sysarg_t forward_interface;
    85104} devmap_device_t;
    86105
    87106LIST_INITIALIZE(devices_list);
     107LIST_INITIALIZE(namespaces_list);
    88108LIST_INITIALIZE(drivers_list);
    89109
     
    101121static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex);
    102122
    103 static dev_handle_t last_handle = 0;
     123static devmap_handle_t last_handle = 0;
    104124static devmap_device_t *null_devices[NULL_DEVICES];
    105125
    106 static dev_handle_t devmap_create_handle(void)
     126/*
     127 * Dummy list for null devices. This is necessary so that null devices can
     128 * be used just as any other devices, e.g. in devmap_device_unregister_core().
     129 */
     130static LIST_INITIALIZE(dummy_null_driver_devices);
     131
     132static devmap_handle_t devmap_create_handle(void)
    107133{
    108134        /* TODO: allow reusing old handles after their unregistration
     
    117143}
    118144
    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)
     145/** Convert fully qualified device name to namespace and device name.
     146 *
     147 * A fully qualified device name can be either a plain device name
     148 * (then the namespace is considered to be an empty string) or consist
     149 * of two components separated by a slash. No more than one slash
     150 * is allowed.
     151 *
     152 */
     153static bool devmap_fqdn_split(const char *fqdn, char **ns_name, char **name)
     154{
     155        size_t cnt = 0;
     156        size_t slash_offset = 0;
     157        size_t slash_after = 0;
     158       
     159        size_t offset = 0;
     160        size_t offset_prev = 0;
     161        wchar_t c;
     162       
     163        while ((c = str_decode(fqdn, &offset, STR_NO_LIMIT)) != 0) {
     164                if (c == '/') {
     165                        cnt++;
     166                        slash_offset = offset_prev;
     167                        slash_after = offset;
     168                }
     169                offset_prev = offset;
     170        }
     171       
     172        /* More than one slash */
     173        if (cnt > 1)
     174                return false;
     175       
     176        /* No slash -> namespace is empty */
     177        if (cnt == 0) {
     178                *ns_name = str_dup("");
     179                if (*ns_name == NULL)
     180                        return false;
     181               
     182                *name = str_dup(fqdn);
     183                if (*name == NULL) {
     184                        free(*ns_name);
     185                        return false;
     186                }
     187               
     188                if (str_cmp(*name, "") == 0) {
     189                        free(*name);
     190                        free(*ns_name);
     191                        return false;
     192                }
     193               
     194                return true;
     195        }
     196       
     197        /* Exactly one slash */
     198        *ns_name = str_ndup(fqdn, slash_offset);
     199        if (*ns_name == NULL)
     200                return false;
     201       
     202        *name = str_dup(fqdn + slash_after);
     203        if (*name == NULL) {
     204                free(*ns_name);
     205                return false;
     206        }
     207       
     208        if (str_cmp(*name, "") == 0) {
     209                free(*name);
     210                free(*ns_name);
     211                return false;
     212        }
     213       
     214        return true;
     215}
     216
     217/** Find namespace with given name. */
     218static devmap_namespace_t *devmap_namespace_find_name(const char *name)
     219{
     220        link_t *item;
     221       
     222        assert(fibril_mutex_is_locked(&devices_list_mutex));
     223       
     224        for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
     225                devmap_namespace_t *namespace =
     226                    list_get_instance(item, devmap_namespace_t, namespaces);
     227                if (str_cmp(namespace->name, name) == 0)
     228                        return namespace;
     229        }
     230       
     231        return NULL;
     232}
     233
     234/** Find namespace with given handle.
     235 *
     236 * @todo: use hash table
     237 *
     238 */
     239static devmap_namespace_t *devmap_namespace_find_handle(devmap_handle_t handle)
     240{
     241        link_t *item;
     242       
     243        assert(fibril_mutex_is_locked(&devices_list_mutex));
     244       
     245        for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
     246                devmap_namespace_t *namespace =
     247                    list_get_instance(item, devmap_namespace_t, namespaces);
     248                if (namespace->handle == handle)
     249                        return namespace;
     250        }
     251       
     252        return NULL;
     253}
     254
     255/** Find device with given name. */
     256static devmap_device_t *devmap_device_find_name(const char *ns_name,
     257    const char *name)
     258{
     259        link_t *item;
     260       
     261        assert(fibril_mutex_is_locked(&devices_list_mutex));
     262       
     263        for (item = devices_list.next; item != &devices_list; item = item->next) {
     264                devmap_device_t *device =
     265                    list_get_instance(item, devmap_device_t, devices);
     266                if ((str_cmp(device->namespace->name, ns_name) == 0)
     267                    && (str_cmp(device->name, name) == 0))
     268                        return device;
     269        }
     270       
     271        return NULL;
     272}
     273
     274/** Find device with given handle.
     275 *
     276 * @todo: use hash table
     277 *
     278 */
     279static devmap_device_t *devmap_device_find_handle(devmap_handle_t handle)
     280{
     281        link_t *item;
     282       
     283        assert(fibril_mutex_is_locked(&devices_list_mutex));
     284       
     285        for (item = devices_list.next; item != &devices_list; item = item->next) {
     286                devmap_device_t *device =
     287                    list_get_instance(item, devmap_device_t, devices);
     288                if (device->handle == handle)
     289                        return device;
     290        }
     291       
     292        return NULL;
     293}
     294
     295/** Create a namespace (if not already present). */
     296static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
     297{
     298        devmap_namespace_t *namespace;
     299       
     300        assert(fibril_mutex_is_locked(&devices_list_mutex));
     301       
     302        namespace = devmap_namespace_find_name(ns_name);
     303        if (namespace != NULL)
     304                return namespace;
     305       
     306        namespace = (devmap_namespace_t *) malloc(sizeof(devmap_namespace_t));
     307        if (namespace == NULL)
    135308                return NULL;
    136309       
    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);
     310        namespace->name = str_dup(ns_name);
     311        if (namespace->name == NULL) {
     312                free(namespace);
    162313                return NULL;
    163314        }
    164315       
    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 {
     316        namespace->handle = devmap_create_handle();
     317        namespace->refcnt = 0;
     318       
     319        /*
     320         * Insert new namespace into list of registered namespaces
     321         */
     322        list_append(&(namespace->namespaces), &namespaces_list);
     323       
     324        return namespace;
     325}
     326
     327/** Destroy a namespace (if it is no longer needed). */
     328static void devmap_namespace_destroy(devmap_namespace_t *namespace)
     329{
     330        assert(fibril_mutex_is_locked(&devices_list_mutex));
     331
     332        if (namespace->refcnt == 0) {
     333                list_remove(&(namespace->namespaces));
     334               
     335                free(namespace->name);
     336                free(namespace);
     337        }
     338}
     339
     340/** Increase namespace reference count by including device. */
     341static void devmap_namespace_addref(devmap_namespace_t *namespace,
     342    devmap_device_t *device)
     343{
     344        assert(fibril_mutex_is_locked(&devices_list_mutex));
     345
     346        device->namespace = namespace;
     347        namespace->refcnt++;
     348}
     349
     350/** Decrease namespace reference count. */
     351static void devmap_namespace_delref(devmap_namespace_t *namespace)
     352{
     353        assert(fibril_mutex_is_locked(&devices_list_mutex));
     354
     355        namespace->refcnt--;
     356        devmap_namespace_destroy(namespace);
     357}
     358
     359/** Unregister device and free it. */
     360static void devmap_device_unregister_core(devmap_device_t *device)
     361{
     362        assert(fibril_mutex_is_locked(&devices_list_mutex));
     363
     364        devmap_namespace_delref(device->namespace);
    178365        list_remove(&(device->devices));
    179366        list_remove(&(device->driver_devices));
     
    181368        free(device->name);
    182369        free(device);
    183        
    184         return EOK;
    185370}
    186371
     
    189374 * drivers.
    190375 */
    191 static void devmap_driver_register(devmap_driver_t **odriver)
    192 {
    193         *odriver = NULL;
    194        
     376static devmap_driver_t *devmap_driver_register(void)
     377{
    195378        ipc_call_t icall;
    196379        ipc_callid_t iid = async_get_call(&icall);
    197380       
    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        
     381        if (IPC_GET_IMETHOD(icall) != DEVMAP_DRIVER_REGISTER) {
     382                async_answer_0(iid, EREFUSED);
     383                return NULL;
     384        }
     385       
     386        devmap_driver_t *driver =
     387            (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
    205388        if (driver == NULL) {
    206                 ipc_answer_0(iid, ENOMEM);
    207                 return;
     389                async_answer_0(iid, ENOMEM);
     390                return NULL;
    208391        }
    209392       
     
    211394         * Get driver name
    212395         */
    213         ipc_callid_t callid;
    214         size_t name_size;
    215         if (!ipc_data_write_receive(&callid, &name_size)) {
     396        int rc = async_data_write_accept((void **) &driver->name, true, 0,
     397            DEVMAP_NAME_MAXLEN, 0, NULL);
     398        if (rc != EOK) {
    216399                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;
     400                async_answer_0(iid, rc);
     401                return NULL;
    227402        }
    228403       
    229404        /*
    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) {
     405         * Create connection to the driver
     406         */
     407        ipc_call_t call;
     408        ipc_callid_t callid = async_get_call(&call);
     409       
     410        if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
    244411                free(driver->name);
    245412                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 */
     413                async_answer_0(callid, ENOTSUP);
     414                async_answer_0(iid, ENOTSUP);
     415                return NULL;
     416        }
     417       
     418        driver->phone = IPC_GET_ARG5(call);
     419        async_answer_0(callid, EOK);
     420       
     421        /*
     422         * Initialize mutex for list of devices
     423         * owned by this driver
     424         */
    253425        fibril_mutex_initialize(&driver->devices_mutex);
    254426       
     
    257429         */
    258430        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));
     431
     432        link_initialize(&driver->drivers);
    280433       
    281434        fibril_mutex_lock(&drivers_list_mutex);
    282435       
    283436        /* TODO:
    284          * check that no driver with name equal to driver->name is registered
     437         * Check that no driver with name equal to
     438         * driver->name is registered
    285439         */
    286440       
     
    291445        fibril_mutex_unlock(&drivers_list_mutex);
    292446       
    293         ipc_answer_0(iid, EOK);
    294        
    295         *odriver = driver;
     447        async_answer_0(iid, EOK);
     448       
     449        return driver;
    296450}
    297451
     
    309463       
    310464        if (driver->phone != 0)
    311                 ipc_hangup(driver->phone);
     465                async_hangup(driver->phone);
    312466       
    313467        /* Remove it from list of drivers */
     
    328482        fibril_mutex_unlock(&drivers_list_mutex);
    329483       
    330         /* free name and driver */
     484        /* Free name and driver */
    331485        if (driver->name != NULL)
    332486                free(driver->name);
     
    344498{
    345499        if (driver == NULL) {
    346                 ipc_answer_0(iid, EREFUSED);
     500                async_answer_0(iid, EREFUSED);
    347501                return;
    348502        }
    349503       
    350504        /* Create new device entry */
    351         devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
     505        devmap_device_t *device =
     506            (devmap_device_t *) malloc(sizeof(devmap_device_t));
    352507        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)) {
     508                async_answer_0(iid, ENOMEM);
     509                return;
     510        }
     511       
     512        /* Set the interface, if any. */
     513        device->forward_interface = IPC_GET_ARG1(*icall);
     514
     515        /* Get fqdn */
     516        char *fqdn;
     517        int rc = async_data_write_accept((void **) &fqdn, true, 0,
     518            DEVMAP_NAME_MAXLEN, 0, NULL);
     519        if (rc != EOK) {
    361520                free(device);
    362                 ipc_answer_0(iid, EREFUSED);
    363                 return;
    364         }
    365        
    366         if (size > DEVMAP_NAME_MAXLEN) {
     521                async_answer_0(iid, rc);
     522                return;
     523        }
     524       
     525        char *ns_name;
     526        if (!devmap_fqdn_split(fqdn, &ns_name, &device->name)) {
     527                free(fqdn);
    367528                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));
     529                async_answer_0(iid, EINVAL);
     530                return;
     531        }
     532       
     533        free(fqdn);
    388534       
    389535        fibril_mutex_lock(&devices_list_mutex);
    390536       
    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);
     537        devmap_namespace_t *namespace = devmap_namespace_create(ns_name);
     538        free(ns_name);
     539        if (namespace == NULL) {
    394540                fibril_mutex_unlock(&devices_list_mutex);
    395541                free(device->name);
    396542                free(device);
    397                 ipc_answer_0(iid, EEXISTS);
     543                async_answer_0(iid, ENOMEM);
     544                return;
     545        }
     546       
     547        link_initialize(&device->devices);
     548        link_initialize(&device->driver_devices);
     549       
     550        /* Check that device is not already registered */
     551        if (devmap_device_find_name(namespace->name, device->name) != NULL) {
     552                printf("%s: Device '%s/%s' already registered\n", NAME,
     553                    device->namespace->name, device->name);
     554                devmap_namespace_destroy(namespace);
     555                fibril_mutex_unlock(&devices_list_mutex);
     556                free(device->name);
     557                free(device);
     558                async_answer_0(iid, EEXISTS);
    398559                return;
    399560        }
     
    401562        /* Get unique device handle */
    402563        device->handle = devmap_create_handle();
    403        
     564
     565        devmap_namespace_addref(namespace, device);
    404566        device->driver = driver;
    405567       
     
    416578        fibril_mutex_unlock(&devices_list_mutex);
    417579       
    418         ipc_answer_1(iid, EOK, device->handle);
     580        async_answer_1(iid, EOK, device->handle);
    419581}
    420582
     
    437599static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
    438600{
     601        fibril_mutex_lock(&devices_list_mutex);
     602       
    439603        /*
    440604         * Get handle from request
    441605         */
    442         dev_handle_t handle = IPC_GET_ARG2(*call);
     606        devmap_handle_t handle = IPC_GET_ARG2(*call);
    443607        devmap_device_t *dev = devmap_device_find_handle(handle);
    444608       
    445609        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);
     610                fibril_mutex_unlock(&devices_list_mutex);
     611                async_answer_0(callid, ENOENT);
     612                return;
     613        }
     614       
     615        if (dev->forward_interface == 0) {
     616                async_forward_fast(callid, dev->driver->phone,
     617                    dev->handle, 0, 0,
     618                    IPC_FF_NONE);
     619        } else {
     620                async_forward_fast(callid, dev->driver->phone,
     621                    dev->forward_interface, dev->handle, 0,
     622                    IPC_FF_NONE);
     623        }
     624       
     625        fibril_mutex_unlock(&devices_list_mutex);
    452626}
    453627
     
    458632 *
    459633 */
    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';
     634static void devmap_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
     635{
     636        char *fqdn;
     637       
     638        /* Get fqdn */
     639        int rc = async_data_write_accept((void **) &fqdn, true, 0,
     640            DEVMAP_NAME_MAXLEN, 0, NULL);
     641        if (rc != EOK) {
     642                async_answer_0(iid, rc);
     643                return;
     644        }
     645       
     646        char *ns_name;
     647        char *name;
     648        if (!devmap_fqdn_split(fqdn, &ns_name, &name)) {
     649                free(fqdn);
     650                async_answer_0(iid, EINVAL);
     651                return;
     652        }
     653       
     654        free(fqdn);
    500655       
    501656        fibril_mutex_lock(&devices_list_mutex);
    502657        const devmap_device_t *dev;
     658       
    503659recheck:
    504 
     660       
    505661        /*
    506662         * Find device name in the list of known devices.
    507663         */
    508         dev = devmap_device_find_name(name);
     664        dev = devmap_device_find_name(ns_name, name);
    509665       
    510666        /*
     
    519675                }
    520676               
    521                 ipc_answer_0(iid, ENOENT);
     677                async_answer_0(iid, ENOENT);
     678                free(ns_name);
    522679                free(name);
    523680                fibril_mutex_unlock(&devices_list_mutex);
    524681                return;
    525682        }
     683       
     684        async_answer_1(iid, EOK, dev->handle);
     685       
    526686        fibril_mutex_unlock(&devices_list_mutex);
    527        
    528         ipc_answer_1(iid, EOK, dev->handle);
     687        free(ns_name);
    529688        free(name);
    530689}
    531690
    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));
     691/** Find handle for namespace identified by name.
     692 *
     693 * In answer will be send EOK and device handle in arg1 or a error
     694 * code from errno.h.
     695 *
     696 */
     697static void devmap_namespace_get_handle(ipc_callid_t iid, ipc_call_t *icall)
     698{
     699        char *name;
     700       
     701        /* Get device name */
     702        int rc = async_data_write_accept((void **) &name, true, 0,
     703            DEVMAP_NAME_MAXLEN, 0, NULL);
     704        if (rc != EOK) {
     705                async_answer_0(iid, rc);
     706                return;
     707        }
     708       
     709        fibril_mutex_lock(&devices_list_mutex);
     710        const devmap_namespace_t *namespace;
     711       
     712recheck:
    538713       
    539714        /*
    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)
     715         * Find namespace name in the list of known namespaces.
     716         */
     717        namespace = devmap_namespace_find_name(name);
     718       
     719        /*
     720         * Namespace was not found.
     721         */
     722        if (namespace == NULL) {
     723                if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
     724                        /* Blocking lookup */
     725                        fibril_condvar_wait(&devices_list_cv,
     726                            &devices_list_mutex);
     727                        goto recheck;
     728                }
     729               
     730                async_answer_0(iid, ENOENT);
     731                free(name);
     732                fibril_mutex_unlock(&devices_list_mutex);
     733                return;
     734        }
     735       
     736        async_answer_1(iid, EOK, namespace->handle);
     737       
     738        fibril_mutex_unlock(&devices_list_mutex);
     739        free(name);
     740}
     741
     742static void devmap_handle_probe(ipc_callid_t iid, ipc_call_t *icall)
    566743{
    567744        fibril_mutex_lock(&devices_list_mutex);
    568         ipc_answer_1(iid, EOK, list_count(&devices_list));
     745       
     746        devmap_namespace_t *namespace =
     747            devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
     748        if (namespace == NULL) {
     749                devmap_device_t *dev =
     750                    devmap_device_find_handle(IPC_GET_ARG1(*icall));
     751                if (dev == NULL)
     752                        async_answer_1(iid, EOK, DEV_HANDLE_NONE);
     753                else
     754                        async_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
     755        } else
     756                async_answer_1(iid, EOK, DEV_HANDLE_NAMESPACE);
     757       
    569758        fibril_mutex_unlock(&devices_list_mutex);
    570759}
    571760
    572 static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
     761static void devmap_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
    573762{
    574763        fibril_mutex_lock(&devices_list_mutex);
    575        
     764        async_answer_1(iid, EOK, list_count(&namespaces_list));
     765        fibril_mutex_unlock(&devices_list_mutex);
     766}
     767
     768static void devmap_get_device_count(ipc_callid_t iid, ipc_call_t *icall)
     769{
     770        fibril_mutex_lock(&devices_list_mutex);
     771       
     772        devmap_namespace_t *namespace =
     773            devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
     774        if (namespace == NULL)
     775                async_answer_0(iid, EEXISTS);
     776        else
     777                async_answer_1(iid, EOK, namespace->refcnt);
     778       
     779        fibril_mutex_unlock(&devices_list_mutex);
     780}
     781
     782static void devmap_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
     783{
    576784        ipc_callid_t callid;
    577785        size_t size;
    578         if (!ipc_data_read_receive(&callid, &size)) {
    579                 ipc_answer_0(callid, EREFUSED);
    580                 ipc_answer_0(iid, EREFUSED);
     786        if (!async_data_read_receive(&callid, &size)) {
     787                async_answer_0(callid, EREFUSED);
     788                async_answer_0(iid, EREFUSED);
    581789                return;
    582790        }
    583791       
    584792        if ((size % sizeof(dev_desc_t)) != 0) {
    585                 ipc_answer_0(callid, EINVAL);
    586                 ipc_answer_0(iid, EREFUSED);
    587                 return;
    588         }
     793                async_answer_0(callid, EINVAL);
     794                async_answer_0(iid, EINVAL);
     795                return;
     796        }
     797       
     798        fibril_mutex_lock(&devices_list_mutex);
    589799       
    590800        size_t count = size / sizeof(dev_desc_t);
     801        if (count != list_count(&namespaces_list)) {
     802                fibril_mutex_unlock(&devices_list_mutex);
     803                async_answer_0(callid, EOVERFLOW);
     804                async_answer_0(iid, EOVERFLOW);
     805                return;
     806        }
     807       
    591808        dev_desc_t *desc = (dev_desc_t *) malloc(size);
    592809        if (desc == NULL) {
    593                 ipc_answer_0(callid, ENOMEM);
    594                 ipc_answer_0(iid, EREFUSED);
    595                 return;
    596         }
    597        
     810                fibril_mutex_unlock(&devices_list_mutex);
     811                async_answer_0(callid, ENOMEM);
     812                async_answer_0(iid, ENOMEM);
     813                return;
     814        }
     815       
     816        link_t *item;
    598817        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);
     818        for (item = namespaces_list.next; item != &namespaces_list;
     819            item = item->next) {
     820                devmap_namespace_t *namespace =
     821                    list_get_instance(item, devmap_namespace_t, namespaces);
    603822               
    604                 desc[pos].handle = device->handle;
    605                 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
     823                desc[pos].handle = namespace->handle;
     824                str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
    606825                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         }
     826        }
     827       
     828        sysarg_t retval = async_data_read_finalize(callid, desc, size);
    616829       
    617830        free(desc);
    618        
    619831        fibril_mutex_unlock(&devices_list_mutex);
    620832       
    621         ipc_answer_1(iid, EOK, pos);
     833        async_answer_0(iid, retval);
     834}
     835
     836static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
     837{
     838        /* FIXME: Use faster algorithm which can make better use
     839           of namespaces */
     840       
     841        ipc_callid_t callid;
     842        size_t size;
     843        if (!async_data_read_receive(&callid, &size)) {
     844                async_answer_0(callid, EREFUSED);
     845                async_answer_0(iid, EREFUSED);
     846                return;
     847        }
     848       
     849        if ((size % sizeof(dev_desc_t)) != 0) {
     850                async_answer_0(callid, EINVAL);
     851                async_answer_0(iid, EINVAL);
     852                return;
     853        }
     854       
     855        fibril_mutex_lock(&devices_list_mutex);
     856       
     857        devmap_namespace_t *namespace =
     858            devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
     859        if (namespace == NULL) {
     860                fibril_mutex_unlock(&devices_list_mutex);
     861                async_answer_0(callid, ENOENT);
     862                async_answer_0(iid, ENOENT);
     863                return;
     864        }
     865       
     866        size_t count = size / sizeof(dev_desc_t);
     867        if (count != namespace->refcnt) {
     868                fibril_mutex_unlock(&devices_list_mutex);
     869                async_answer_0(callid, EOVERFLOW);
     870                async_answer_0(iid, EOVERFLOW);
     871                return;
     872        }
     873       
     874        dev_desc_t *desc = (dev_desc_t *) malloc(size);
     875        if (desc == NULL) {
     876                fibril_mutex_unlock(&devices_list_mutex);
     877                async_answer_0(callid, ENOMEM);
     878                async_answer_0(iid, EREFUSED);
     879                return;
     880        }
     881       
     882        link_t *item;
     883        size_t pos = 0;
     884        for (item = devices_list.next; item != &devices_list; item = item->next) {
     885                devmap_device_t *device =
     886                    list_get_instance(item, devmap_device_t, devices);
     887               
     888                if (device->namespace == namespace) {
     889                        desc[pos].handle = device->handle;
     890                        str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
     891                        pos++;
     892                }
     893        }
     894       
     895        sysarg_t retval = async_data_read_finalize(callid, desc, size);
     896       
     897        free(desc);
     898        fibril_mutex_unlock(&devices_list_mutex);
     899       
     900        async_answer_0(iid, retval);
    622901}
    623902
     
    638917        if (!fnd) {
    639918                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));
     919                async_answer_0(iid, ENOMEM);
     920                return;
     921        }
     922       
     923        char null[DEVMAP_NAME_MAXLEN];
     924        snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
     925       
     926        char *dev_name = str_dup(null);
     927        if (dev_name == NULL) {
     928                fibril_mutex_unlock(&null_devices_mutex);
     929                async_answer_0(iid, ENOMEM);
     930                return;
     931        }
     932       
     933        devmap_device_t *device =
     934            (devmap_device_t *) malloc(sizeof(devmap_device_t));
    646935        if (device == NULL) {
    647936                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) {
     937                async_answer_0(iid, ENOMEM);
     938                return;
     939        }
     940       
     941        fibril_mutex_lock(&devices_list_mutex);
     942       
     943        devmap_namespace_t *namespace = devmap_namespace_create("null");
     944        if (namespace == NULL) {
     945                fibril_mutex_lock(&devices_list_mutex);
    657946                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);
     947                async_answer_0(iid, ENOMEM);
     948                return;
     949        }
     950       
     951        link_initialize(&device->devices);
     952        link_initialize(&device->driver_devices);
    667953       
    668954        /* Get unique device handle */
     
    670956        device->driver = NULL;
    671957       
    672         /* Insert device into list of all devices
    673            and into null devices array */
     958        devmap_namespace_addref(namespace, device);
     959        device->name = dev_name;
     960       
     961        /*
     962         * Insert device into list of all devices and into null devices array.
     963         * Insert device into a dummy list of null driver's devices so that it
     964         * can be safely removed later.
     965         */
    674966        list_append(&device->devices, &devices_list);
     967        list_append(&device->driver_devices, &dummy_null_driver_devices);
    675968        null_devices[i] = device;
    676969       
     
    678971        fibril_mutex_unlock(&null_devices_mutex);
    679972       
    680         ipc_answer_1(iid, EOK, (ipcarg_t) i);
     973        async_answer_1(iid, EOK, (sysarg_t) i);
    681974}
    682975
    683976static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
    684977{
     978        sysarg_t i = IPC_GET_ARG1(*icall);
     979        if (i >= NULL_DEVICES) {
     980                async_answer_0(iid, ELIMIT);
     981                return;
     982        }
     983       
    685984        fibril_mutex_lock(&null_devices_mutex);
    686985       
    687         ipcarg_t i = IPC_GET_ARG1(*icall);
    688        
    689986        if (null_devices[i] == NULL) {
    690                 ipc_answer_0(iid, ENOENT);
    691                 return;
    692         }
    693        
     987                fibril_mutex_unlock(&null_devices_mutex);
     988                async_answer_0(iid, ENOENT);
     989                return;
     990        }
     991       
     992        fibril_mutex_lock(&devices_list_mutex);
    694993        devmap_device_unregister_core(null_devices[i]);
     994        fibril_mutex_unlock(&devices_list_mutex);
     995       
    695996        null_devices[i] = NULL;
    696997       
    697998        fibril_mutex_unlock(&null_devices_mutex);
    698        
    699         ipc_answer_0(iid, EOK);
     999        async_answer_0(iid, EOK);
    7001000}
    7011001
     
    7231023{
    7241024        /* 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)
     1025        async_answer_0(iid, EOK);
     1026       
     1027        devmap_driver_t *driver = devmap_driver_register();
     1028        if (driver == NULL)
    7311029                return;
    7321030       
     
    7361034                ipc_callid_t callid = async_get_call(&call);
    7371035               
    738                 switch (IPC_GET_METHOD(call)) {
     1036                switch (IPC_GET_IMETHOD(call)) {
    7391037                case IPC_M_PHONE_HUNGUP:
    7401038                        cont = false;
     
    7421040                case DEVMAP_DRIVER_UNREGISTER:
    7431041                        if (NULL == driver)
    744                                 ipc_answer_0(callid, ENOENT);
     1042                                async_answer_0(callid, ENOENT);
    7451043                        else
    746                                 ipc_answer_0(callid, EOK);
     1044                                async_answer_0(callid, EOK);
    7471045                        break;
    7481046                case DEVMAP_DEVICE_REGISTER:
     
    7551053                        break;
    7561054                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);
     1055                        devmap_device_get_handle(callid, &call);
     1056                        break;
     1057                case DEVMAP_NAMESPACE_GET_HANDLE:
     1058                        devmap_namespace_get_handle(callid, &call);
    7611059                        break;
    7621060                default:
    763                         if (!(callid & IPC_CALLID_NOTIFICATION))
    764                                 ipc_answer_0(callid, ENOENT);
     1061                        async_answer_0(callid, ENOENT);
    7651062                }
    7661063        }
     
    7811078{
    7821079        /* Accept connection */
    783         ipc_answer_0(iid, EOK);
     1080        async_answer_0(iid, EOK);
    7841081       
    7851082        bool cont = true;
     
    7881085                ipc_callid_t callid = async_get_call(&call);
    7891086               
    790                 switch (IPC_GET_METHOD(call)) {
     1087                switch (IPC_GET_IMETHOD(call)) {
    7911088                case IPC_M_PHONE_HUNGUP:
    7921089                        cont = false;
    7931090                        continue;
    7941091                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:
     1092                        devmap_device_get_handle(callid, &call);
     1093                        break;
     1094                case DEVMAP_NAMESPACE_GET_HANDLE:
     1095                        devmap_namespace_get_handle(callid, &call);
     1096                        break;
     1097                case DEVMAP_HANDLE_PROBE:
     1098                        devmap_handle_probe(callid, &call);
     1099                        break;
     1100                case DEVMAP_NULL_CREATE:
    8011101                        devmap_null_create(callid, &call);
    8021102                        break;
    803                 case DEVMAP_DEVICE_NULL_DESTROY:
     1103                case DEVMAP_NULL_DESTROY:
    8041104                        devmap_null_destroy(callid, &call);
    8051105                        break;
    806                 case DEVMAP_DEVICE_GET_COUNT:
    807                         devmap_get_count(callid, &call);
    808                         break;
    809                 case DEVMAP_DEVICE_GET_DEVICES:
     1106                case DEVMAP_GET_NAMESPACE_COUNT:
     1107                        devmap_get_namespace_count(callid, &call);
     1108                        break;
     1109                case DEVMAP_GET_DEVICE_COUNT:
     1110                        devmap_get_device_count(callid, &call);
     1111                        break;
     1112                case DEVMAP_GET_NAMESPACES:
     1113                        devmap_get_namespaces(callid, &call);
     1114                        break;
     1115                case DEVMAP_GET_DEVICES:
    8101116                        devmap_get_devices(callid, &call);
    8111117                        break;
    8121118                default:
    813                         if (!(callid & IPC_CALLID_NOTIFICATION))
    814                                 ipc_answer_0(callid, ENOENT);
     1119                        async_answer_0(callid, ENOENT);
    8151120                }
    8161121        }
     
    8231128{
    8241129        /* Select interface */
    825         switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
     1130        switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
    8261131        case DEVMAP_DRIVER:
    8271132                devmap_connection_driver(iid, icall);
     
    8361141        default:
    8371142                /* No such interface */
    838                 ipc_answer_0(iid, ENOENT);
     1143                async_answer_0(iid, ENOENT);
    8391144        }
    8401145}
     
    8451150int main(int argc, char *argv[])
    8461151{
    847         printf(NAME ": HelenOS Device Mapper\n");
     1152        printf("%s: HelenOS Device Mapper\n", NAME);
    8481153       
    8491154        if (!devmap_init()) {
    850                 printf(NAME ": Error while initializing service\n");
     1155                printf("%s: Error while initializing service\n", NAME);
    8511156                return -1;
    8521157        }
     
    8561161       
    8571162        /* Register device mapper at naming service */
    858         ipcarg_t phonead;
    859         if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
     1163        if (service_register(SERVICE_DEVMAP) != EOK)
    8601164                return -1;
    8611165       
    862         printf(NAME ": Accepting connections\n");
     1166        printf("%s: Accepting connections\n", NAME);
    8631167        async_manager();
    8641168       
     
    8671171}
    8681172
    869 /** 
     1173/**
    8701174 * @}
    8711175 */
Note: See TracChangeset for help on using the changeset viewer.