devmap.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007 Josef Cejka
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <ipc/services.h>
00039 #include <ipc/ns.h>
00040 #include <async.h>
00041 #include <stdio.h>
00042 #include <errno.h>
00043 #include <bool.h>
00044 #include <fibril_synch.h>
00045 #include <stdlib.h>
00046 #include <str.h>
00047 #include <ipc/devmap.h>
00048 #include <assert.h>
00049 
00050 #define NAME          "devmap"
00051 #define NULL_DEVICES  256
00052 
00058 typedef struct {
00060         link_t drivers;
00062         link_t devices;
00064         sysarg_t phone;
00066         char *name;
00068         fibril_mutex_t devices_mutex;
00069 } devmap_driver_t;
00070 
00074 typedef struct {
00076         link_t namespaces;
00078         devmap_handle_t handle;
00080         char *name;
00082         size_t refcnt;
00083 } devmap_namespace_t;
00084 
00088 typedef struct {
00090         link_t devices;
00093         link_t driver_devices;
00095         devmap_handle_t handle;
00097         devmap_namespace_t *namespace;
00099         char *name;
00101         devmap_driver_t *driver;
00103         sysarg_t forward_interface;
00104 } devmap_device_t;
00105 
00106 LIST_INITIALIZE(devices_list);
00107 LIST_INITIALIZE(namespaces_list);
00108 LIST_INITIALIZE(drivers_list);
00109 
00110 /* Locking order:
00111  *  drivers_list_mutex
00112  *  devices_list_mutex
00113  *  (devmap_driver_t *)->devices_mutex
00114  *  create_handle_mutex
00115  **/
00116 
00117 static FIBRIL_MUTEX_INITIALIZE(devices_list_mutex);
00118 static FIBRIL_CONDVAR_INITIALIZE(devices_list_cv);
00119 static FIBRIL_MUTEX_INITIALIZE(drivers_list_mutex);
00120 static FIBRIL_MUTEX_INITIALIZE(create_handle_mutex);
00121 static FIBRIL_MUTEX_INITIALIZE(null_devices_mutex);
00122 
00123 static devmap_handle_t last_handle = 0;
00124 static devmap_device_t *null_devices[NULL_DEVICES];
00125 
00126 /*
00127  * Dummy list for null devices. This is necessary so that null devices can
00128  * be used just as any other devices, e.g. in devmap_device_unregister_core().
00129  */
00130 static LIST_INITIALIZE(dummy_null_driver_devices);
00131 
00132 static devmap_handle_t devmap_create_handle(void)
00133 {
00134         /* TODO: allow reusing old handles after their unregistration
00135          * and implement some version of LRU algorithm, avoid overflow
00136          */
00137         
00138         fibril_mutex_lock(&create_handle_mutex);
00139         last_handle++;
00140         fibril_mutex_unlock(&create_handle_mutex);
00141         
00142         return last_handle;
00143 }
00144 
00153 static bool devmap_fqdn_split(const char *fqdn, char **ns_name, char **name)
00154 {
00155         size_t cnt = 0;
00156         size_t slash_offset = 0;
00157         size_t slash_after = 0;
00158         
00159         size_t offset = 0;
00160         size_t offset_prev = 0;
00161         wchar_t c;
00162         
00163         while ((c = str_decode(fqdn, &offset, STR_NO_LIMIT)) != 0) {
00164                 if (c == '/') {
00165                         cnt++;
00166                         slash_offset = offset_prev;
00167                         slash_after = offset;
00168                 }
00169                 offset_prev = offset;
00170         }
00171         
00172         /* More than one slash */
00173         if (cnt > 1)
00174                 return false;
00175         
00176         /* No slash -> namespace is empty */
00177         if (cnt == 0) {
00178                 *ns_name = str_dup("");
00179                 if (*ns_name == NULL)
00180                         return false;
00181                 
00182                 *name = str_dup(fqdn);
00183                 if (*name == NULL) {
00184                         free(*ns_name);
00185                         return false;
00186                 }
00187                 
00188                 if (str_cmp(*name, "") == 0) {
00189                         free(*name);
00190                         free(*ns_name);
00191                         return false;
00192                 }
00193                 
00194                 return true;
00195         }
00196         
00197         /* Exactly one slash */
00198         *ns_name = str_ndup(fqdn, slash_offset);
00199         if (*ns_name == NULL)
00200                 return false;
00201         
00202         *name = str_dup(fqdn + slash_after);
00203         if (*name == NULL) {
00204                 free(*ns_name);
00205                 return false;
00206         }
00207         
00208         if (str_cmp(*name, "") == 0) {
00209                 free(*name);
00210                 free(*ns_name);
00211                 return false;
00212         }
00213         
00214         return true;
00215 }
00216 
00218 static devmap_namespace_t *devmap_namespace_find_name(const char *name)
00219 {
00220         link_t *item;
00221         
00222         assert(fibril_mutex_is_locked(&devices_list_mutex));
00223         
00224         for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
00225                 devmap_namespace_t *namespace =
00226                     list_get_instance(item, devmap_namespace_t, namespaces);
00227                 if (str_cmp(namespace->name, name) == 0)
00228                         return namespace;
00229         }
00230         
00231         return NULL;
00232 }
00233 
00239 static devmap_namespace_t *devmap_namespace_find_handle(devmap_handle_t handle)
00240 {
00241         link_t *item;
00242         
00243         assert(fibril_mutex_is_locked(&devices_list_mutex));
00244         
00245         for (item = namespaces_list.next; item != &namespaces_list; item = item->next) {
00246                 devmap_namespace_t *namespace =
00247                     list_get_instance(item, devmap_namespace_t, namespaces);
00248                 if (namespace->handle == handle)
00249                         return namespace;
00250         }
00251         
00252         return NULL;
00253 }
00254 
00256 static devmap_device_t *devmap_device_find_name(const char *ns_name,
00257     const char *name)
00258 {
00259         link_t *item;
00260         
00261         assert(fibril_mutex_is_locked(&devices_list_mutex));
00262         
00263         for (item = devices_list.next; item != &devices_list; item = item->next) {
00264                 devmap_device_t *device =
00265                     list_get_instance(item, devmap_device_t, devices);
00266                 if ((str_cmp(device->namespace->name, ns_name) == 0)
00267                     && (str_cmp(device->name, name) == 0))
00268                         return device;
00269         }
00270         
00271         return NULL;
00272 }
00273 
00279 static devmap_device_t *devmap_device_find_handle(devmap_handle_t handle)
00280 {
00281         link_t *item;
00282         
00283         assert(fibril_mutex_is_locked(&devices_list_mutex));
00284         
00285         for (item = devices_list.next; item != &devices_list; item = item->next) {
00286                 devmap_device_t *device =
00287                     list_get_instance(item, devmap_device_t, devices);
00288                 if (device->handle == handle)
00289                         return device;
00290         }
00291         
00292         return NULL;
00293 }
00294 
00296 static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
00297 {
00298         devmap_namespace_t *namespace;
00299         
00300         assert(fibril_mutex_is_locked(&devices_list_mutex));
00301         
00302         namespace = devmap_namespace_find_name(ns_name);
00303         if (namespace != NULL)
00304                 return namespace;
00305         
00306         namespace = (devmap_namespace_t *) malloc(sizeof(devmap_namespace_t));
00307         if (namespace == NULL)
00308                 return NULL;
00309         
00310         namespace->name = str_dup(ns_name);
00311         if (namespace->name == NULL) {
00312                 free(namespace);
00313                 return NULL;
00314         }
00315         
00316         namespace->handle = devmap_create_handle();
00317         namespace->refcnt = 0;
00318         
00319         /*
00320          * Insert new namespace into list of registered namespaces
00321          */
00322         list_append(&(namespace->namespaces), &namespaces_list);
00323         
00324         return namespace;
00325 }
00326 
00328 static void devmap_namespace_destroy(devmap_namespace_t *namespace)
00329 {
00330         assert(fibril_mutex_is_locked(&devices_list_mutex));
00331 
00332         if (namespace->refcnt == 0) {
00333                 list_remove(&(namespace->namespaces));
00334                 
00335                 free(namespace->name);
00336                 free(namespace);
00337         }
00338 }
00339 
00341 static void devmap_namespace_addref(devmap_namespace_t *namespace,
00342     devmap_device_t *device)
00343 {
00344         assert(fibril_mutex_is_locked(&devices_list_mutex));
00345 
00346         device->namespace = namespace;
00347         namespace->refcnt++;
00348 }
00349 
00351 static void devmap_namespace_delref(devmap_namespace_t *namespace)
00352 {
00353         assert(fibril_mutex_is_locked(&devices_list_mutex));
00354 
00355         namespace->refcnt--;
00356         devmap_namespace_destroy(namespace);
00357 }
00358 
00360 static void devmap_device_unregister_core(devmap_device_t *device)
00361 {
00362         assert(fibril_mutex_is_locked(&devices_list_mutex));
00363 
00364         devmap_namespace_delref(device->namespace);
00365         list_remove(&(device->devices));
00366         list_remove(&(device->driver_devices));
00367         
00368         free(device->name);
00369         free(device);
00370 }
00371 
00376 static devmap_driver_t *devmap_driver_register(void)
00377 {
00378         ipc_call_t icall;
00379         ipc_callid_t iid = async_get_call(&icall);
00380         
00381         if (IPC_GET_IMETHOD(icall) != DEVMAP_DRIVER_REGISTER) {
00382                 async_answer_0(iid, EREFUSED);
00383                 return NULL;
00384         }
00385         
00386         devmap_driver_t *driver =
00387             (devmap_driver_t *) malloc(sizeof(devmap_driver_t));
00388         if (driver == NULL) {
00389                 async_answer_0(iid, ENOMEM);
00390                 return NULL;
00391         }
00392         
00393         /*
00394          * Get driver name
00395          */
00396         int rc = async_data_write_accept((void **) &driver->name, true, 0,
00397             DEVMAP_NAME_MAXLEN, 0, NULL);
00398         if (rc != EOK) {
00399                 free(driver);
00400                 async_answer_0(iid, rc);
00401                 return NULL;
00402         }
00403         
00404         /*
00405          * Create connection to the driver
00406          */
00407         ipc_call_t call;
00408         ipc_callid_t callid = async_get_call(&call);
00409         
00410         if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
00411                 free(driver->name);
00412                 free(driver);
00413                 async_answer_0(callid, ENOTSUP);
00414                 async_answer_0(iid, ENOTSUP);
00415                 return NULL;
00416         }
00417         
00418         driver->phone = IPC_GET_ARG5(call);
00419         async_answer_0(callid, EOK);
00420         
00421         /*
00422          * Initialize mutex for list of devices
00423          * owned by this driver
00424          */
00425         fibril_mutex_initialize(&driver->devices_mutex);
00426         
00427         /*
00428          * Initialize list of asociated devices
00429          */
00430         list_initialize(&driver->devices);
00431 
00432         link_initialize(&driver->drivers);
00433         
00434         fibril_mutex_lock(&drivers_list_mutex);
00435         
00436         /* TODO:
00437          * Check that no driver with name equal to
00438          * driver->name is registered
00439          */
00440         
00441         /*
00442          * Insert new driver into list of registered drivers
00443          */
00444         list_append(&(driver->drivers), &drivers_list);
00445         fibril_mutex_unlock(&drivers_list_mutex);
00446         
00447         async_answer_0(iid, EOK);
00448         
00449         return driver;
00450 }
00451 
00457 static int devmap_driver_unregister(devmap_driver_t *driver)
00458 {
00459         if (driver == NULL)
00460                 return EEXISTS;
00461         
00462         fibril_mutex_lock(&drivers_list_mutex);
00463         
00464         if (driver->phone != 0)
00465                 async_hangup(driver->phone);
00466         
00467         /* Remove it from list of drivers */
00468         list_remove(&(driver->drivers));
00469         
00470         /* Unregister all its devices */
00471         fibril_mutex_lock(&devices_list_mutex);
00472         fibril_mutex_lock(&driver->devices_mutex);
00473         
00474         while (!list_empty(&(driver->devices))) {
00475                 devmap_device_t *device = list_get_instance(driver->devices.next,
00476                     devmap_device_t, driver_devices);
00477                 devmap_device_unregister_core(device);
00478         }
00479         
00480         fibril_mutex_unlock(&driver->devices_mutex);
00481         fibril_mutex_unlock(&devices_list_mutex);
00482         fibril_mutex_unlock(&drivers_list_mutex);
00483         
00484         /* Free name and driver */
00485         if (driver->name != NULL)
00486                 free(driver->name);
00487         
00488         free(driver);
00489         
00490         return EOK;
00491 }
00492 
00496 static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
00497     devmap_driver_t *driver)
00498 {
00499         if (driver == NULL) {
00500                 async_answer_0(iid, EREFUSED);
00501                 return;
00502         }
00503         
00504         /* Create new device entry */
00505         devmap_device_t *device =
00506             (devmap_device_t *) malloc(sizeof(devmap_device_t));
00507         if (device == NULL) {
00508                 async_answer_0(iid, ENOMEM);
00509                 return;
00510         }
00511         
00512         /* Set the interface, if any. */
00513         device->forward_interface = IPC_GET_ARG1(*icall);
00514 
00515         /* Get fqdn */
00516         char *fqdn;
00517         int rc = async_data_write_accept((void **) &fqdn, true, 0,
00518             DEVMAP_NAME_MAXLEN, 0, NULL);
00519         if (rc != EOK) {
00520                 free(device);
00521                 async_answer_0(iid, rc);
00522                 return;
00523         }
00524         
00525         char *ns_name;
00526         if (!devmap_fqdn_split(fqdn, &ns_name, &device->name)) {
00527                 free(fqdn);
00528                 free(device);
00529                 async_answer_0(iid, EINVAL);
00530                 return;
00531         }
00532         
00533         free(fqdn);
00534         
00535         fibril_mutex_lock(&devices_list_mutex);
00536         
00537         devmap_namespace_t *namespace = devmap_namespace_create(ns_name);
00538         free(ns_name);
00539         if (namespace == NULL) {
00540                 fibril_mutex_unlock(&devices_list_mutex);
00541                 free(device->name);
00542                 free(device);
00543                 async_answer_0(iid, ENOMEM);
00544                 return;
00545         }
00546         
00547         link_initialize(&device->devices);
00548         link_initialize(&device->driver_devices);
00549         
00550         /* Check that device is not already registered */
00551         if (devmap_device_find_name(namespace->name, device->name) != NULL) {
00552                 printf("%s: Device '%s/%s' already registered\n", NAME,
00553                     namespace->name, device->name);
00554                 devmap_namespace_destroy(namespace);
00555                 fibril_mutex_unlock(&devices_list_mutex);
00556                 free(device->name);
00557                 free(device);
00558                 async_answer_0(iid, EEXISTS);
00559                 return;
00560         }
00561         
00562         /* Get unique device handle */
00563         device->handle = devmap_create_handle();
00564 
00565         devmap_namespace_addref(namespace, device);
00566         device->driver = driver;
00567         
00568         /* Insert device into list of all devices  */
00569         list_append(&device->devices, &devices_list);
00570         
00571         /* Insert device into list of devices that belog to one driver */
00572         fibril_mutex_lock(&device->driver->devices_mutex);
00573         
00574         list_append(&device->driver_devices, &device->driver->devices);
00575         
00576         fibril_mutex_unlock(&device->driver->devices_mutex);
00577         fibril_condvar_broadcast(&devices_list_cv);
00578         fibril_mutex_unlock(&devices_list_mutex);
00579         
00580         async_answer_1(iid, EOK, device->handle);
00581 }
00582 
00586 static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall, 
00587     devmap_driver_t *driver)
00588 {
00589         /* TODO */
00590         return EOK;
00591 }
00592 
00599 static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
00600 {
00601         fibril_mutex_lock(&devices_list_mutex);
00602         
00603         /*
00604          * Get handle from request
00605          */
00606         devmap_handle_t handle = IPC_GET_ARG2(*call);
00607         devmap_device_t *dev = devmap_device_find_handle(handle);
00608         
00609         if ((dev == NULL) || (dev->driver == NULL) || (dev->driver->phone == 0)) {
00610                 fibril_mutex_unlock(&devices_list_mutex);
00611                 async_answer_0(callid, ENOENT);
00612                 return;
00613         }
00614         
00615         if (dev->forward_interface == 0) {
00616                 async_forward_fast(callid, dev->driver->phone,
00617                     dev->handle, 0, 0,
00618                     IPC_FF_NONE);
00619         } else {
00620                 async_forward_fast(callid, dev->driver->phone,
00621                     dev->forward_interface, dev->handle, 0,
00622                     IPC_FF_NONE);
00623         }
00624         
00625         fibril_mutex_unlock(&devices_list_mutex);
00626 }
00627 
00634 static void devmap_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
00635 {
00636         char *fqdn;
00637         
00638         /* Get fqdn */
00639         int rc = async_data_write_accept((void **) &fqdn, true, 0,
00640             DEVMAP_NAME_MAXLEN, 0, NULL);
00641         if (rc != EOK) {
00642                 async_answer_0(iid, rc);
00643                 return;
00644         }
00645         
00646         char *ns_name;
00647         char *name;
00648         if (!devmap_fqdn_split(fqdn, &ns_name, &name)) {
00649                 free(fqdn);
00650                 async_answer_0(iid, EINVAL);
00651                 return;
00652         }
00653         
00654         free(fqdn);
00655         
00656         fibril_mutex_lock(&devices_list_mutex);
00657         const devmap_device_t *dev;
00658         
00659 recheck:
00660         
00661         /*
00662          * Find device name in the list of known devices.
00663          */
00664         dev = devmap_device_find_name(ns_name, name);
00665         
00666         /*
00667          * Device was not found.
00668          */
00669         if (dev == NULL) {
00670                 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
00671                         /* Blocking lookup */
00672                         fibril_condvar_wait(&devices_list_cv,
00673                             &devices_list_mutex);
00674                         goto recheck;
00675                 }
00676                 
00677                 async_answer_0(iid, ENOENT);
00678                 free(ns_name);
00679                 free(name);
00680                 fibril_mutex_unlock(&devices_list_mutex);
00681                 return;
00682         }
00683         
00684         async_answer_1(iid, EOK, dev->handle);
00685         
00686         fibril_mutex_unlock(&devices_list_mutex);
00687         free(ns_name);
00688         free(name);
00689 }
00690 
00697 static void devmap_namespace_get_handle(ipc_callid_t iid, ipc_call_t *icall)
00698 {
00699         char *name;
00700         
00701         /* Get device name */
00702         int rc = async_data_write_accept((void **) &name, true, 0,
00703             DEVMAP_NAME_MAXLEN, 0, NULL);
00704         if (rc != EOK) {
00705                 async_answer_0(iid, rc);
00706                 return;
00707         }
00708         
00709         fibril_mutex_lock(&devices_list_mutex);
00710         const devmap_namespace_t *namespace;
00711         
00712 recheck:
00713         
00714         /*
00715          * Find namespace name in the list of known namespaces.
00716          */
00717         namespace = devmap_namespace_find_name(name);
00718         
00719         /*
00720          * Namespace was not found.
00721          */
00722         if (namespace == NULL) {
00723                 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
00724                         /* Blocking lookup */
00725                         fibril_condvar_wait(&devices_list_cv,
00726                             &devices_list_mutex);
00727                         goto recheck;
00728                 }
00729                 
00730                 async_answer_0(iid, ENOENT);
00731                 free(name);
00732                 fibril_mutex_unlock(&devices_list_mutex);
00733                 return;
00734         }
00735         
00736         async_answer_1(iid, EOK, namespace->handle);
00737         
00738         fibril_mutex_unlock(&devices_list_mutex);
00739         free(name);
00740 }
00741 
00742 static void devmap_handle_probe(ipc_callid_t iid, ipc_call_t *icall)
00743 {
00744         fibril_mutex_lock(&devices_list_mutex);
00745         
00746         devmap_namespace_t *namespace =
00747             devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
00748         if (namespace == NULL) {
00749                 devmap_device_t *dev =
00750                     devmap_device_find_handle(IPC_GET_ARG1(*icall));
00751                 if (dev == NULL)
00752                         async_answer_1(iid, EOK, DEV_HANDLE_NONE);
00753                 else
00754                         async_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
00755         } else
00756                 async_answer_1(iid, EOK, DEV_HANDLE_NAMESPACE);
00757         
00758         fibril_mutex_unlock(&devices_list_mutex);
00759 }
00760 
00761 static void devmap_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
00762 {
00763         fibril_mutex_lock(&devices_list_mutex);
00764         async_answer_1(iid, EOK, list_count(&namespaces_list));
00765         fibril_mutex_unlock(&devices_list_mutex);
00766 }
00767 
00768 static void devmap_get_device_count(ipc_callid_t iid, ipc_call_t *icall)
00769 {
00770         fibril_mutex_lock(&devices_list_mutex);
00771         
00772         devmap_namespace_t *namespace =
00773             devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
00774         if (namespace == NULL)
00775                 async_answer_0(iid, EEXISTS);
00776         else
00777                 async_answer_1(iid, EOK, namespace->refcnt);
00778         
00779         fibril_mutex_unlock(&devices_list_mutex);
00780 }
00781 
00782 static void devmap_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
00783 {
00784         ipc_callid_t callid;
00785         size_t size;
00786         if (!async_data_read_receive(&callid, &size)) {
00787                 async_answer_0(callid, EREFUSED);
00788                 async_answer_0(iid, EREFUSED);
00789                 return;
00790         }
00791         
00792         if ((size % sizeof(dev_desc_t)) != 0) {
00793                 async_answer_0(callid, EINVAL);
00794                 async_answer_0(iid, EINVAL);
00795                 return;
00796         }
00797         
00798         fibril_mutex_lock(&devices_list_mutex);
00799         
00800         size_t count = size / sizeof(dev_desc_t);
00801         if (count != list_count(&namespaces_list)) {
00802                 fibril_mutex_unlock(&devices_list_mutex);
00803                 async_answer_0(callid, EOVERFLOW);
00804                 async_answer_0(iid, EOVERFLOW);
00805                 return;
00806         }
00807         
00808         dev_desc_t *desc = (dev_desc_t *) malloc(size);
00809         if (desc == NULL) {
00810                 fibril_mutex_unlock(&devices_list_mutex);
00811                 async_answer_0(callid, ENOMEM);
00812                 async_answer_0(iid, ENOMEM);
00813                 return;
00814         }
00815         
00816         link_t *item;
00817         size_t pos = 0;
00818         for (item = namespaces_list.next; item != &namespaces_list;
00819             item = item->next) {
00820                 devmap_namespace_t *namespace =
00821                     list_get_instance(item, devmap_namespace_t, namespaces);
00822                 
00823                 desc[pos].handle = namespace->handle;
00824                 str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
00825                 pos++;
00826         }
00827         
00828         sysarg_t retval = async_data_read_finalize(callid, desc, size);
00829         
00830         free(desc);
00831         fibril_mutex_unlock(&devices_list_mutex);
00832         
00833         async_answer_0(iid, retval);
00834 }
00835 
00836 static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
00837 {
00838         /* FIXME: Use faster algorithm which can make better use
00839            of namespaces */
00840         
00841         ipc_callid_t callid;
00842         size_t size;
00843         if (!async_data_read_receive(&callid, &size)) {
00844                 async_answer_0(callid, EREFUSED);
00845                 async_answer_0(iid, EREFUSED);
00846                 return;
00847         }
00848         
00849         if ((size % sizeof(dev_desc_t)) != 0) {
00850                 async_answer_0(callid, EINVAL);
00851                 async_answer_0(iid, EINVAL);
00852                 return;
00853         }
00854         
00855         fibril_mutex_lock(&devices_list_mutex);
00856         
00857         devmap_namespace_t *namespace =
00858             devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
00859         if (namespace == NULL) {
00860                 fibril_mutex_unlock(&devices_list_mutex);
00861                 async_answer_0(callid, ENOENT);
00862                 async_answer_0(iid, ENOENT);
00863                 return;
00864         }
00865         
00866         size_t count = size / sizeof(dev_desc_t);
00867         if (count != namespace->refcnt) {
00868                 fibril_mutex_unlock(&devices_list_mutex);
00869                 async_answer_0(callid, EOVERFLOW);
00870                 async_answer_0(iid, EOVERFLOW);
00871                 return;
00872         }
00873         
00874         dev_desc_t *desc = (dev_desc_t *) malloc(size);
00875         if (desc == NULL) {
00876                 fibril_mutex_unlock(&devices_list_mutex);
00877                 async_answer_0(callid, ENOMEM);
00878                 async_answer_0(iid, EREFUSED);
00879                 return;
00880         }
00881         
00882         link_t *item;
00883         size_t pos = 0;
00884         for (item = devices_list.next; item != &devices_list; item = item->next) {
00885                 devmap_device_t *device =
00886                     list_get_instance(item, devmap_device_t, devices);
00887                 
00888                 if (device->namespace == namespace) {
00889                         desc[pos].handle = device->handle;
00890                         str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
00891                         pos++;
00892                 }
00893         }
00894         
00895         sysarg_t retval = async_data_read_finalize(callid, desc, size);
00896         
00897         free(desc);
00898         fibril_mutex_unlock(&devices_list_mutex);
00899         
00900         async_answer_0(iid, retval);
00901 }
00902 
00903 static void devmap_null_create(ipc_callid_t iid, ipc_call_t *icall)
00904 {
00905         fibril_mutex_lock(&null_devices_mutex);
00906         
00907         unsigned int i;
00908         bool fnd = false;
00909         
00910         for (i = 0; i < NULL_DEVICES; i++) {
00911                 if (null_devices[i] == NULL) {
00912                         fnd = true;
00913                         break;
00914                 }
00915         }
00916         
00917         if (!fnd) {
00918                 fibril_mutex_unlock(&null_devices_mutex);
00919                 async_answer_0(iid, ENOMEM);
00920                 return;
00921         }
00922         
00923         char null[DEVMAP_NAME_MAXLEN];
00924         snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
00925         
00926         char *dev_name = str_dup(null);
00927         if (dev_name == NULL) {
00928                 fibril_mutex_unlock(&null_devices_mutex);
00929                 async_answer_0(iid, ENOMEM);
00930                 return;
00931         }
00932         
00933         devmap_device_t *device =
00934             (devmap_device_t *) malloc(sizeof(devmap_device_t));
00935         if (device == NULL) {
00936                 fibril_mutex_unlock(&null_devices_mutex);
00937                 async_answer_0(iid, ENOMEM);
00938                 return;
00939         }
00940         
00941         fibril_mutex_lock(&devices_list_mutex);
00942         
00943         devmap_namespace_t *namespace = devmap_namespace_create("null");
00944         if (namespace == NULL) {
00945                 fibril_mutex_lock(&devices_list_mutex);
00946                 fibril_mutex_unlock(&null_devices_mutex);
00947                 async_answer_0(iid, ENOMEM);
00948                 return;
00949         }
00950         
00951         link_initialize(&device->devices);
00952         link_initialize(&device->driver_devices);
00953         
00954         /* Get unique device handle */
00955         device->handle = devmap_create_handle();
00956         device->driver = NULL;
00957         
00958         devmap_namespace_addref(namespace, device);
00959         device->name = dev_name;
00960         
00961         /*
00962          * Insert device into list of all devices and into null devices array.
00963          * Insert device into a dummy list of null driver's devices so that it
00964          * can be safely removed later.
00965          */
00966         list_append(&device->devices, &devices_list);
00967         list_append(&device->driver_devices, &dummy_null_driver_devices);
00968         null_devices[i] = device;
00969         
00970         fibril_mutex_unlock(&devices_list_mutex);
00971         fibril_mutex_unlock(&null_devices_mutex);
00972         
00973         async_answer_1(iid, EOK, (sysarg_t) i);
00974 }
00975 
00976 static void devmap_null_destroy(ipc_callid_t iid, ipc_call_t *icall)
00977 {
00978         sysarg_t i = IPC_GET_ARG1(*icall);
00979         if (i >= NULL_DEVICES) {
00980                 async_answer_0(iid, ELIMIT);
00981                 return;
00982         }
00983         
00984         fibril_mutex_lock(&null_devices_mutex);
00985         
00986         if (null_devices[i] == NULL) {
00987                 fibril_mutex_unlock(&null_devices_mutex);
00988                 async_answer_0(iid, ENOENT);
00989                 return;
00990         }
00991         
00992         fibril_mutex_lock(&devices_list_mutex);
00993         devmap_device_unregister_core(null_devices[i]);
00994         fibril_mutex_unlock(&devices_list_mutex);
00995         
00996         null_devices[i] = NULL;
00997         
00998         fibril_mutex_unlock(&null_devices_mutex);
00999         async_answer_0(iid, EOK);
01000 }
01001 
01006 static bool devmap_init(void)
01007 {
01008         fibril_mutex_lock(&null_devices_mutex);
01009         
01010         unsigned int i;
01011         for (i = 0; i < NULL_DEVICES; i++)
01012                 null_devices[i] = NULL;
01013         
01014         fibril_mutex_unlock(&null_devices_mutex);
01015         
01016         return true;
01017 }
01018 
01022 static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
01023 {
01024         /* Accept connection */
01025         async_answer_0(iid, EOK);
01026         
01027         devmap_driver_t *driver = devmap_driver_register();
01028         if (driver == NULL)
01029                 return;
01030         
01031         bool cont = true;
01032         while (cont) {
01033                 ipc_call_t call;
01034                 ipc_callid_t callid = async_get_call(&call);
01035                 
01036                 switch (IPC_GET_IMETHOD(call)) {
01037                 case IPC_M_PHONE_HUNGUP:
01038                         cont = false;
01039                         continue;
01040                 case DEVMAP_DRIVER_UNREGISTER:
01041                         if (NULL == driver)
01042                                 async_answer_0(callid, ENOENT);
01043                         else
01044                                 async_answer_0(callid, EOK);
01045                         break;
01046                 case DEVMAP_DEVICE_REGISTER:
01047                         /* Register one instance of device */
01048                         devmap_device_register(callid, &call, driver);
01049                         break;
01050                 case DEVMAP_DEVICE_UNREGISTER:
01051                         /* Remove instance of device identified by handler */
01052                         devmap_device_unregister(callid, &call, driver);
01053                         break;
01054                 case DEVMAP_DEVICE_GET_HANDLE:
01055                         devmap_device_get_handle(callid, &call);
01056                         break;
01057                 case DEVMAP_NAMESPACE_GET_HANDLE:
01058                         devmap_namespace_get_handle(callid, &call);
01059                         break;
01060                 default:
01061                         async_answer_0(callid, ENOENT);
01062                 }
01063         }
01064         
01065         if (driver != NULL) {
01066                 /*
01067                  * Unregister the device driver and all its devices.
01068                  */
01069                 devmap_driver_unregister(driver);
01070                 driver = NULL;
01071         }
01072 }
01073 
01077 static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
01078 {
01079         /* Accept connection */
01080         async_answer_0(iid, EOK);
01081         
01082         bool cont = true;
01083         while (cont) {
01084                 ipc_call_t call;
01085                 ipc_callid_t callid = async_get_call(&call);
01086                 
01087                 switch (IPC_GET_IMETHOD(call)) {
01088                 case IPC_M_PHONE_HUNGUP:
01089                         cont = false;
01090                         continue;
01091                 case DEVMAP_DEVICE_GET_HANDLE:
01092                         devmap_device_get_handle(callid, &call);
01093                         break;
01094                 case DEVMAP_NAMESPACE_GET_HANDLE:
01095                         devmap_namespace_get_handle(callid, &call);
01096                         break;
01097                 case DEVMAP_HANDLE_PROBE:
01098                         devmap_handle_probe(callid, &call);
01099                         break;
01100                 case DEVMAP_NULL_CREATE:
01101                         devmap_null_create(callid, &call);
01102                         break;
01103                 case DEVMAP_NULL_DESTROY:
01104                         devmap_null_destroy(callid, &call);
01105                         break;
01106                 case DEVMAP_GET_NAMESPACE_COUNT:
01107                         devmap_get_namespace_count(callid, &call);
01108                         break;
01109                 case DEVMAP_GET_DEVICE_COUNT:
01110                         devmap_get_device_count(callid, &call);
01111                         break;
01112                 case DEVMAP_GET_NAMESPACES:
01113                         devmap_get_namespaces(callid, &call);
01114                         break;
01115                 case DEVMAP_GET_DEVICES:
01116                         devmap_get_devices(callid, &call);
01117                         break;
01118                 default:
01119                         async_answer_0(callid, ENOENT);
01120                 }
01121         }
01122 }
01123 
01127 static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
01128 {
01129         /* Select interface */
01130         switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
01131         case DEVMAP_DRIVER:
01132                 devmap_connection_driver(iid, icall);
01133                 break;
01134         case DEVMAP_CLIENT:
01135                 devmap_connection_client(iid, icall);
01136                 break;
01137         case DEVMAP_CONNECT_TO_DEVICE:
01138                 /* Connect client to selected device */
01139                 devmap_forward(iid, icall);
01140                 break;
01141         default:
01142                 /* No such interface */
01143                 async_answer_0(iid, ENOENT);
01144         }
01145 }
01146 
01150 int main(int argc, char *argv[])
01151 {
01152         printf("%s: HelenOS Device Mapper\n", NAME);
01153         
01154         if (!devmap_init()) {
01155                 printf("%s: Error while initializing service\n", NAME);
01156                 return -1;
01157         }
01158         
01159         /* Set a handler of incomming connections */
01160         async_set_client_connection(devmap_connection);
01161         
01162         /* Register device mapper at naming service */
01163         if (service_register(SERVICE_DEVMAP) != EOK)
01164                 return -1;
01165         
01166         printf("%s: Accepting connections\n", NAME);
01167         async_manager();
01168         
01169         /* Never reached */
01170         return 0;
01171 }
01172 

Generated on Thu Jun 2 07:45:46 2011 for HelenOS/USB by  doxygen 1.4.7