main.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Lenka Trochtova
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 <inttypes.h>
00039 #include <assert.h>
00040 #include <ipc/services.h>
00041 #include <ipc/ns.h>
00042 #include <async.h>
00043 #include <stdio.h>
00044 #include <errno.h>
00045 #include <str_error.h>
00046 #include <bool.h>
00047 #include <fibril_synch.h>
00048 #include <stdlib.h>
00049 #include <str.h>
00050 #include <dirent.h>
00051 #include <fcntl.h>
00052 #include <sys/stat.h>
00053 #include <ctype.h>
00054 #include <io/log.h>
00055 #include <ipc/devman.h>
00056 #include <ipc/driver.h>
00057 #include <thread.h>
00058 #include <devmap.h>
00059 
00060 #include "devman.h"
00061 
00062 #define DRIVER_DEFAULT_STORE  "/drv"
00063 
00064 static driver_list_t drivers_list;
00065 static dev_tree_t device_tree;
00066 static class_list_t class_list;
00067 
00069 static driver_t *devman_driver_register(void)
00070 {
00071         ipc_call_t icall;
00072         ipc_callid_t iid;
00073         driver_t *driver = NULL;
00074 
00075         log_msg(LVL_DEBUG, "devman_driver_register");
00076         
00077         iid = async_get_call(&icall);
00078         if (IPC_GET_IMETHOD(icall) != DEVMAN_DRIVER_REGISTER) {
00079                 async_answer_0(iid, EREFUSED);
00080                 return NULL;
00081         }
00082         
00083         char *drv_name = NULL;
00084         
00085         /* Get driver name. */
00086         int rc = async_data_write_accept((void **) &drv_name, true, 0, 0, 0, 0);
00087         if (rc != EOK) {
00088                 async_answer_0(iid, rc);
00089                 return NULL;
00090         }
00091 
00092         log_msg(LVL_DEBUG, "The `%s' driver is trying to register.",
00093             drv_name);
00094         
00095         /* Find driver structure. */
00096         driver = find_driver(&drivers_list, drv_name);
00097         if (driver == NULL) {
00098                 log_msg(LVL_ERROR, "No driver named `%s' was found.", drv_name);
00099                 free(drv_name);
00100                 drv_name = NULL;
00101                 async_answer_0(iid, ENOENT);
00102                 return NULL;
00103         }
00104         
00105         free(drv_name);
00106         drv_name = NULL;
00107         
00108         fibril_mutex_lock(&driver->driver_mutex);
00109         
00110         if (driver->phone >= 0) {
00111                 /* We already have a connection to the driver. */
00112                 log_msg(LVL_ERROR, "Driver '%s' already started.\n",
00113                     driver->name);
00114                 fibril_mutex_unlock(&driver->driver_mutex);
00115                 async_answer_0(iid, EEXISTS);
00116                 return NULL;
00117         }
00118         
00119         switch (driver->state) {
00120         case DRIVER_NOT_STARTED:
00121                 /* Somebody started the driver manually. */
00122                 log_msg(LVL_NOTE, "Driver '%s' started manually.\n",
00123                     driver->name);
00124                 driver->state = DRIVER_STARTING;
00125                 break;
00126         case DRIVER_STARTING:
00127                 /* The expected case */
00128                 break;
00129         case DRIVER_RUNNING:
00130                 /* Should not happen since we do not have a connected phone */
00131                 assert(false);
00132         }
00133         
00134         /* Create connection to the driver. */
00135         log_msg(LVL_DEBUG, "Creating connection to the `%s' driver.",
00136             driver->name);
00137         ipc_call_t call;
00138         ipc_callid_t callid = async_get_call(&call);
00139         if (IPC_GET_IMETHOD(call) != IPC_M_CONNECT_TO_ME) {
00140                 fibril_mutex_unlock(&driver->driver_mutex);
00141                 async_answer_0(callid, ENOTSUP);
00142                 async_answer_0(iid, ENOTSUP);
00143                 return NULL;
00144         }
00145         
00146         /* Remember driver's phone. */
00147         driver->phone = IPC_GET_ARG5(call);
00148         
00149         fibril_mutex_unlock(&driver->driver_mutex);
00150         
00151         log_msg(LVL_NOTE, 
00152             "The `%s' driver was successfully registered as running.",
00153             driver->name);
00154         
00155         async_answer_0(callid, EOK);
00156         async_answer_0(iid, EOK);
00157         
00158         return driver;
00159 }
00160 
00167 static int devman_receive_match_id(match_id_list_t *match_ids)
00168 {
00169         match_id_t *match_id = create_match_id();
00170         ipc_callid_t callid;
00171         ipc_call_t call;
00172         int rc = 0;
00173         
00174         callid = async_get_call(&call);
00175         if (DEVMAN_ADD_MATCH_ID != IPC_GET_IMETHOD(call)) {
00176                 log_msg(LVL_ERROR, 
00177                     "Invalid protocol when trying to receive match id.");
00178                 async_answer_0(callid, EINVAL); 
00179                 delete_match_id(match_id);
00180                 return EINVAL;
00181         }
00182         
00183         if (match_id == NULL) {
00184                 log_msg(LVL_ERROR, "Failed to allocate match id.");
00185                 async_answer_0(callid, ENOMEM);
00186                 return ENOMEM;
00187         }
00188         
00189         async_answer_0(callid, EOK);
00190         
00191         match_id->score = IPC_GET_ARG1(call);
00192         
00193         char *match_id_str;
00194         rc = async_data_write_accept((void **) &match_id_str, true, 0, 0, 0, 0);
00195         match_id->id = match_id_str;
00196         if (rc != EOK) {
00197                 delete_match_id(match_id);
00198                 log_msg(LVL_ERROR, "Failed to receive match id string: %s.",
00199                     str_error(rc));
00200                 return rc;
00201         }
00202         
00203         list_append(&match_id->link, &match_ids->ids);
00204         
00205         log_msg(LVL_DEBUG, "Received match id `%s', score %d.",
00206             match_id->id, match_id->score);
00207         return rc;
00208 }
00209 
00217 static int devman_receive_match_ids(sysarg_t match_count,
00218     match_id_list_t *match_ids)
00219 {
00220         int ret = EOK;
00221         size_t i;
00222         
00223         for (i = 0; i < match_count; i++) {
00224                 if (EOK != (ret = devman_receive_match_id(match_ids)))
00225                         return ret;
00226         }
00227         return ret;
00228 }
00229 
00230 static int assign_driver_fibril(void *arg)
00231 {
00232         dev_node_t *dev_node = (dev_node_t *) arg;
00233         assign_driver(dev_node, &drivers_list, &device_tree);
00234         return EOK;
00235 }
00236 
00241 static void devman_add_function(ipc_callid_t callid, ipc_call_t *call)
00242 {
00243         fun_type_t ftype = (fun_type_t) IPC_GET_ARG1(*call);
00244         devman_handle_t dev_handle = IPC_GET_ARG2(*call);
00245         sysarg_t match_count = IPC_GET_ARG3(*call);
00246         dev_tree_t *tree = &device_tree;
00247         
00248         fibril_rwlock_write_lock(&tree->rwlock);
00249 
00250         dev_node_t *dev = NULL;
00251         dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
00252         
00253         if (pdev == NULL) {
00254                 fibril_rwlock_write_unlock(&tree->rwlock);
00255                 async_answer_0(callid, ENOENT);
00256                 return;
00257         }
00258         
00259         if (ftype != fun_inner && ftype != fun_exposed) {
00260                 /* Unknown function type */
00261                 log_msg(LVL_ERROR, 
00262                     "Unknown function type %d provided by driver.",
00263                     (int) ftype);
00264 
00265                 fibril_rwlock_write_unlock(&tree->rwlock);
00266                 async_answer_0(callid, EINVAL);
00267                 return;
00268         }
00269         
00270         char *fun_name = NULL;
00271         int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
00272         if (rc != EOK) {
00273                 fibril_rwlock_write_unlock(&tree->rwlock);
00274                 async_answer_0(callid, rc);
00275                 return;
00276         }
00277         
00278         /* Check that function with same name is not there already. */
00279         if (find_fun_node_in_device(pdev, fun_name) != NULL) {
00280                 fibril_rwlock_write_unlock(&tree->rwlock);
00281                 async_answer_0(callid, EEXISTS);
00282                 printf(NAME ": Warning, driver tried to register `%s' twice.\n",
00283                     fun_name);
00284                 free(fun_name);
00285                 return;
00286         }
00287 
00288         fun_node_t *fun = create_fun_node();
00289         if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
00290                 fibril_rwlock_write_unlock(&tree->rwlock);
00291                 delete_fun_node(fun);
00292                 async_answer_0(callid, ENOMEM);
00293                 return;
00294         }
00295 
00296         if (ftype == fun_inner) {
00297                 dev = create_dev_node();
00298                 if (dev == NULL) {
00299                         fibril_rwlock_write_unlock(&tree->rwlock);
00300                         delete_fun_node(fun);
00301                         async_answer_0(callid, ENOMEM);
00302                         return;
00303                 }
00304 
00305                 insert_dev_node(tree, dev, fun);
00306         }
00307 
00308         fibril_rwlock_write_unlock(&tree->rwlock);
00309         
00310         log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
00311         
00312         devman_receive_match_ids(match_count, &fun->match_ids);
00313 
00314         if (ftype == fun_inner) {
00315                 assert(dev != NULL);
00316                 /*
00317                  * Try to find a suitable driver and assign it to the device.  We do
00318                  * not want to block the current fibril that is used for processing
00319                  * incoming calls: we will launch a separate fibril to handle the
00320                  * driver assigning. That is because assign_driver can actually include
00321                  * task spawning which could take some time.
00322                  */
00323                 fid_t assign_fibril = fibril_create(assign_driver_fibril, dev);
00324                 if (assign_fibril == 0) {
00325                         /*
00326                          * Fallback in case we are out of memory.
00327                          * Probably not needed as we will die soon anyway ;-).
00328                          */
00329                         (void) assign_driver_fibril(fun);
00330                 } else {
00331                         fibril_add_ready(assign_fibril);
00332                 }
00333         } else {
00334                 devmap_register_tree_function(fun, tree);
00335         }
00336         
00337         /* Return device handle to parent's driver. */
00338         async_answer_1(callid, EOK, fun->handle);
00339 }
00340 
00341 static void devmap_register_class_dev(dev_class_info_t *cli)
00342 {
00343         /* Create devmap path and name for the device. */
00344         char *devmap_pathname = NULL;
00345 
00346         asprintf(&devmap_pathname, "%s/%s%c%s", DEVMAP_CLASS_NAMESPACE,
00347             cli->dev_class->name, DEVMAP_SEPARATOR, cli->dev_name);
00348         if (devmap_pathname == NULL)
00349                 return;
00350         
00351         /*
00352          * Register the device by the device mapper and remember its devmap
00353          * handle.
00354          */
00355         devmap_device_register_with_iface(devmap_pathname,
00356             &cli->devmap_handle, DEVMAN_CONNECT_FROM_DEVMAP);
00357         
00358         /*
00359          * Add device to the hash map of class devices registered by device
00360          * mapper.
00361          */
00362         class_add_devmap_function(&class_list, cli);
00363         
00364         free(devmap_pathname);
00365 }
00366 
00367 static void devman_add_function_to_class(ipc_callid_t callid, ipc_call_t *call)
00368 {
00369         devman_handle_t handle = IPC_GET_ARG1(*call);
00370         
00371         /* Get class name. */
00372         char *class_name;
00373         int rc = async_data_write_accept((void **) &class_name, true,
00374             0, 0, 0, 0);
00375         if (rc != EOK) {
00376                 async_answer_0(callid, rc);
00377                 return;
00378         }       
00379         
00380         fun_node_t *fun = find_fun_node(&device_tree, handle);
00381         if (fun == NULL) {
00382                 async_answer_0(callid, ENOENT);
00383                 return;
00384         }
00385         
00386         dev_class_t *cl = get_dev_class(&class_list, class_name);
00387         dev_class_info_t *class_info = add_function_to_class(fun, cl, NULL);
00388         
00389         /* Register the device's class alias by devmapper. */
00390         devmap_register_class_dev(class_info);
00391         
00392         log_msg(LVL_NOTE, "Function `%s' added to class `%s' as `%s'.",
00393             fun->pathname, class_name, class_info->dev_name);
00394 
00395         async_answer_0(callid, EOK);
00396 }
00397 
00403 static int init_running_drv(void *drv)
00404 {
00405         driver_t *driver = (driver_t *) drv;
00406         
00407         initialize_running_driver(driver, &device_tree);
00408         log_msg(LVL_DEBUG, "The `%s` driver was successfully initialized.",
00409             driver->name);
00410         return 0;
00411 }
00412 
00414 static void devman_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
00415 {
00416         /* Accept the connection. */
00417         async_answer_0(iid, EOK);
00418         
00419         driver_t *driver = devman_driver_register();
00420         if (driver == NULL)
00421                 return;
00422         
00423         /*
00424          * Initialize the driver as running (e.g. pass assigned devices to it)
00425          * in a separate fibril; the separate fibril is used to enable the
00426          * driver to use devman service during the driver's initialization.
00427          */
00428         fid_t fid = fibril_create(init_running_drv, driver);
00429         if (fid == 0) {
00430                 log_msg(LVL_ERROR, "Failed to create initialization fibril " \
00431                     "for driver `%s'.", driver->name);
00432                 return;
00433         }
00434         fibril_add_ready(fid);
00435         
00436         ipc_callid_t callid;
00437         ipc_call_t call;
00438         bool cont = true;
00439         while (cont) {
00440                 callid = async_get_call(&call);
00441                 
00442                 switch (IPC_GET_IMETHOD(call)) {
00443                 case IPC_M_PHONE_HUNGUP:
00444                         cont = false;
00445                         continue;
00446                 case DEVMAN_ADD_FUNCTION:
00447                         devman_add_function(callid, &call);
00448                         break;
00449                 case DEVMAN_ADD_DEVICE_TO_CLASS:
00450                         devman_add_function_to_class(callid, &call);
00451                         break;
00452                 default:
00453                         async_answer_0(callid, EINVAL); 
00454                         break;
00455                 }
00456         }
00457 }
00458 
00461 static void devman_function_get_handle(ipc_callid_t iid, ipc_call_t *icall)
00462 {
00463         char *pathname;
00464         
00465         int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
00466         if (rc != EOK) {
00467                 async_answer_0(iid, rc);
00468                 return;
00469         }
00470         
00471         fun_node_t *fun = find_fun_node_by_path(&device_tree, pathname);
00472         
00473         free(pathname);
00474 
00475         if (fun == NULL) {
00476                 async_answer_0(iid, ENOENT);
00477                 return;
00478         }
00479 
00480         async_answer_1(iid, EOK, fun->handle);
00481 }
00482 
00484 static void devman_function_get_handle_by_class(ipc_callid_t iid,
00485     ipc_call_t *icall)
00486 {
00487         char *classname;
00488         char *devname;
00489 
00490         int rc = async_data_write_accept((void **) &classname, true, 0, 0, 0, 0);
00491         if (rc != EOK) {
00492                 async_answer_0(iid, rc);
00493                 return;
00494         }
00495         rc = async_data_write_accept((void **) &devname, true, 0, 0, 0, 0);
00496         if (rc != EOK) {
00497                 free(classname);
00498                 async_answer_0(iid, rc);
00499                 return;
00500         }
00501 
00502 
00503         fun_node_t *fun = find_fun_node_by_class(&class_list,
00504             classname, devname);
00505 
00506         free(classname);
00507         free(devname);
00508 
00509         if (fun == NULL) {
00510                 async_answer_0(iid, ENOENT);
00511                 return;
00512         }
00513 
00514         async_answer_1(iid, EOK, fun->handle);
00515 }
00516 
00518 static void devman_get_device_path_by_handle(ipc_callid_t iid,
00519     ipc_call_t *icall)
00520 {
00521         devman_handle_t handle = IPC_GET_ARG1(*icall);
00522 
00523         fun_node_t *fun = find_fun_node(&device_tree, handle);
00524         if (fun == NULL) {
00525                 async_answer_0(iid, ENOMEM);
00526                 return;
00527         }
00528 
00529         ipc_callid_t data_callid;
00530         size_t data_len;
00531         if (!async_data_read_receive(&data_callid, &data_len)) {
00532                 async_answer_0(iid, EINVAL);
00533                 return;
00534         }
00535 
00536         void *buffer = malloc(data_len);
00537         if (buffer == NULL) {
00538                 async_answer_0(data_callid, ENOMEM);
00539                 async_answer_0(iid, ENOMEM);
00540                 return;
00541         }
00542 
00543         size_t sent_length = str_size(fun->pathname);
00544         if (sent_length > data_len) {
00545                 sent_length = data_len;
00546         }
00547 
00548         async_data_read_finalize(data_callid, fun->pathname, sent_length);
00549         async_answer_0(iid, EOK);
00550 
00551         free(buffer);
00552 }
00553 
00554 
00556 static void devman_connection_client(ipc_callid_t iid, ipc_call_t *icall)
00557 {
00558         /* Accept connection. */
00559         async_answer_0(iid, EOK);
00560         
00561         bool cont = true;
00562         while (cont) {
00563                 ipc_call_t call;
00564                 ipc_callid_t callid = async_get_call(&call);
00565                 
00566                 switch (IPC_GET_IMETHOD(call)) {
00567                 case IPC_M_PHONE_HUNGUP:
00568                         cont = false;
00569                         continue;
00570                 case DEVMAN_DEVICE_GET_HANDLE:
00571                         devman_function_get_handle(callid, &call);
00572                         break;
00573                 case DEVMAN_DEVICE_GET_HANDLE_BY_CLASS:
00574                         devman_function_get_handle_by_class(callid, &call);
00575                         break;
00576                 case DEVMAN_DEVICE_GET_DEVICE_PATH:
00577                         devman_get_device_path_by_handle(callid, &call);
00578                         break;
00579                 default:
00580                         async_answer_0(callid, ENOENT);
00581                 }
00582         }
00583 }
00584 
00585 static void devman_forward(ipc_callid_t iid, ipc_call_t *icall,
00586     bool drv_to_parent)
00587 {
00588         devman_handle_t handle = IPC_GET_ARG2(*icall);
00589         devman_handle_t fwd_h;
00590         fun_node_t *fun = NULL;
00591         dev_node_t *dev = NULL;
00592         
00593         fun = find_fun_node(&device_tree, handle);
00594         if (fun == NULL)
00595                 dev = find_dev_node(&device_tree, handle);
00596         else
00597                 dev = fun->dev;
00598 
00599         /*
00600          * For a valid function to connect to we need a device. The root
00601          * function, for example, has no device and cannot be connected to.
00602          * This means @c dev needs to be valid regardless whether we are
00603          * connecting to a device or to a function.
00604          */
00605         if (dev == NULL) {
00606                 log_msg(LVL_ERROR, "IPC forwarding failed - no device or "
00607                     "function with handle %" PRIun " was found.", handle);
00608                 async_answer_0(iid, ENOENT);
00609                 return;
00610         }
00611 
00612         if (fun == NULL && !drv_to_parent) {
00613                 log_msg(LVL_ERROR, NAME ": devman_forward error - cannot "
00614                     "connect to handle %" PRIun ", refers to a device.",
00615                     handle);
00616                 async_answer_0(iid, ENOENT);
00617                 return;
00618         }
00619         
00620         driver_t *driver = NULL;
00621         
00622         if (drv_to_parent) {
00623                 /* Connect to parent function of a device (or device function). */
00624                 if (dev->pfun->dev != NULL)
00625                         driver = dev->pfun->dev->drv;
00626                 fwd_h = dev->pfun->handle;
00627         } else if (dev->state == DEVICE_USABLE) {
00628                 /* Connect to the specified function */
00629                 driver = dev->drv;
00630                 assert(driver != NULL);
00631 
00632                 fwd_h = handle;
00633         }
00634         
00635         if (driver == NULL) {
00636                 log_msg(LVL_ERROR, "IPC forwarding refused - " \
00637                     "the device %" PRIun "(%s) is not in usable state.",
00638                     handle, dev->pfun->pathname);
00639                 async_answer_0(iid, ENOENT);
00640                 return;
00641         }
00642         
00643         int method;
00644         if (drv_to_parent)
00645                 method = DRIVER_DRIVER;
00646         else
00647                 method = DRIVER_CLIENT;
00648         
00649         if (driver->phone < 0) {
00650                 log_msg(LVL_ERROR, 
00651                     "Could not forward to driver `%s' (phone is %d).",
00652                     driver->name, (int) driver->phone);
00653                 async_answer_0(iid, EINVAL);
00654                 return;
00655         }
00656 
00657         if (fun != NULL) {
00658                 log_msg(LVL_DEBUG, 
00659                     "Forwarding request for `%s' function to driver `%s'.",
00660                     fun->pathname, driver->name);
00661         } else {
00662                 log_msg(LVL_DEBUG, 
00663                     "Forwarding request for `%s' device to driver `%s'.",
00664                     dev->pfun->pathname, driver->name);
00665         }
00666 
00667         async_forward_fast(iid, driver->phone, method, fwd_h, 0, IPC_FF_NONE);
00668 }
00669 
00672 static void devman_connection_devmapper(ipc_callid_t iid, ipc_call_t *icall)
00673 {
00674         devmap_handle_t devmap_handle = IPC_GET_ARG2(*icall);
00675         fun_node_t *fun;
00676         dev_node_t *dev;
00677 
00678         fun = find_devmap_tree_function(&device_tree, devmap_handle);
00679         if (fun == NULL)
00680                 fun = find_devmap_class_function(&class_list, devmap_handle);
00681         
00682         if (fun == NULL || fun->dev->drv == NULL) {
00683                 async_answer_0(iid, ENOENT);
00684                 return;
00685         }
00686         
00687         dev = fun->dev;
00688         
00689         if (dev->state != DEVICE_USABLE || dev->drv->phone < 0) {
00690                 async_answer_0(iid, EINVAL);
00691                 return;
00692         }
00693         
00694         async_forward_fast(iid, dev->drv->phone, DRIVER_CLIENT, fun->handle, 0,
00695             IPC_FF_NONE);
00696         log_msg(LVL_DEBUG, 
00697             "Forwarding devmapper request for `%s' function to driver `%s'.",
00698             fun->pathname, dev->drv->name);
00699 }
00700 
00702 static void devman_connection(ipc_callid_t iid, ipc_call_t *icall)
00703 {
00704         /* Select interface. */
00705         switch ((sysarg_t) (IPC_GET_ARG1(*icall))) {
00706         case DEVMAN_DRIVER:
00707                 devman_connection_driver(iid, icall);
00708                 break;
00709         case DEVMAN_CLIENT:
00710                 devman_connection_client(iid, icall);
00711                 break;
00712         case DEVMAN_CONNECT_TO_DEVICE:
00713                 /* Connect client to selected device. */
00714                 devman_forward(iid, icall, false);
00715                 break;
00716         case DEVMAN_CONNECT_FROM_DEVMAP:
00717                 /* Someone connected through devmap node. */
00718                 devman_connection_devmapper(iid, icall);
00719                 break;
00720         case DEVMAN_CONNECT_TO_PARENTS_DEVICE:
00721                 /* Connect client to selected device. */
00722                 devman_forward(iid, icall, true);
00723                 break;
00724         default:
00725                 /* No such interface */
00726                 async_answer_0(iid, ENOENT);
00727         }
00728 }
00729 
00731 static bool devman_init(void)
00732 {
00733         log_msg(LVL_DEBUG, "devman_init - looking for available drivers.");
00734         
00735         /* Initialize list of available drivers. */
00736         init_driver_list(&drivers_list);
00737         if (lookup_available_drivers(&drivers_list,
00738             DRIVER_DEFAULT_STORE) == 0) {
00739                 log_msg(LVL_FATAL, "No drivers found.");
00740                 return false;
00741         }
00742 
00743         log_msg(LVL_DEBUG, "devman_init - list of drivers has been initialized.");
00744 
00745         /* Create root device node. */
00746         if (!init_device_tree(&device_tree, &drivers_list)) {
00747                 log_msg(LVL_FATAL, "Failed to initialize device tree.");
00748                 return false;
00749         }
00750 
00751         init_class_list(&class_list);
00752         
00753         /*
00754          * !!! devman_connection ... as the device manager is not a real devmap
00755          * driver (it uses a completely different ipc protocol than an ordinary
00756          * devmap driver) forwarding a connection from client to the devman by
00757          * devmapper would not work.
00758          */
00759         devmap_driver_register(NAME, devman_connection);
00760         
00761         return true;
00762 }
00763 
00764 int main(int argc, char *argv[])
00765 {
00766         printf(NAME ": HelenOS Device Manager\n");
00767 
00768         if (log_init(NAME, LVL_ERROR) != EOK) {
00769                 printf(NAME ": Error initializing logging subsystem.\n");
00770                 return -1;
00771         }
00772 
00773         if (!devman_init()) {
00774                 log_msg(LVL_ERROR, "Error while initializing service.");
00775                 return -1;
00776         }
00777         
00778         /* Set a handler of incomming connections. */
00779         async_set_client_connection(devman_connection);
00780 
00781         /* Register device manager at naming service. */
00782         if (service_register(SERVICE_DEVMAN) != EOK) {
00783                 log_msg(LVL_ERROR, "Failed registering as a service.");
00784                 return -1;
00785         }
00786 
00787         printf(NAME ": Accepting connections.\n");
00788         async_manager();
00789 
00790         /* Never reached. */
00791         return 0;
00792 }
00793 

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