devman.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007 Josef Cejka
00003  * Copyright (c) 2009 Jiri Svoboda
00004  * Copyright (c) 2010 Lenka Trochtova
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright
00012  *   notice, this list of conditions and the following disclaimer.
00013  * - Redistributions in binary form must reproduce the above copyright
00014  *   notice, this list of conditions and the following disclaimer in the
00015  *   documentation and/or other materials provided with the distribution.
00016  * - The name of the author may not be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00020  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00021  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00022  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00024  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00028  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00037 #include <str.h>
00038 #include <stdio.h>
00039 #include <ipc/services.h>
00040 #include <ipc/devman.h>
00041 #include <devman.h>
00042 #include <async.h>
00043 #include <fibril_synch.h>
00044 #include <errno.h>
00045 #include <malloc.h>
00046 #include <bool.h>
00047 #include <adt/list.h>
00048 
00049 static int devman_phone_driver = -1;
00050 static int devman_phone_client = -1;
00051 
00052 static FIBRIL_MUTEX_INITIALIZE(devman_phone_mutex);
00053 
00054 int devman_get_phone(devman_interface_t iface, unsigned int flags)
00055 {
00056         switch (iface) {
00057         case DEVMAN_DRIVER:
00058                 fibril_mutex_lock(&devman_phone_mutex);
00059                 if (devman_phone_driver >= 0) {
00060                         fibril_mutex_unlock(&devman_phone_mutex);
00061                         return devman_phone_driver;
00062                 }
00063                 
00064                 if (flags & IPC_FLAG_BLOCKING)
00065                         devman_phone_driver = async_connect_me_to_blocking(
00066                             PHONE_NS, SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
00067                 else
00068                         devman_phone_driver = async_connect_me_to(PHONE_NS,
00069                             SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
00070                 
00071                 fibril_mutex_unlock(&devman_phone_mutex);
00072                 return devman_phone_driver;
00073         case DEVMAN_CLIENT:
00074                 fibril_mutex_lock(&devman_phone_mutex);
00075                 if (devman_phone_client >= 0) {
00076                         fibril_mutex_unlock(&devman_phone_mutex);
00077                         return devman_phone_client;
00078                 }
00079                 
00080                 if (flags & IPC_FLAG_BLOCKING) {
00081                         devman_phone_client = async_connect_me_to_blocking(
00082                             PHONE_NS, SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
00083                 } else {
00084                         devman_phone_client = async_connect_me_to(PHONE_NS,
00085                             SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
00086                 }
00087                 
00088                 fibril_mutex_unlock(&devman_phone_mutex);
00089                 return devman_phone_client;
00090         default:
00091                 return -1;
00092         }
00093 }
00094 
00096 int devman_driver_register(const char *name, async_client_conn_t conn)
00097 {
00098         int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
00099         
00100         if (phone < 0)
00101                 return phone;
00102         
00103         async_serialize_start();
00104         
00105         ipc_call_t answer;
00106         aid_t req = async_send_2(phone, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
00107         
00108         sysarg_t retval = async_data_write_start(phone, name, str_size(name));
00109         if (retval != EOK) {
00110                 async_wait_for(req, NULL);
00111                 async_serialize_end();
00112                 return -1;
00113         }
00114         
00115         async_set_client_connection(conn);
00116         
00117         async_connect_to_me(phone, 0, 0, 0, NULL);
00118         async_wait_for(req, &retval);
00119         
00120         async_serialize_end();
00121         
00122         return retval;
00123 }
00124 
00125 static int devman_send_match_id(int phone, match_id_t *match_id)
00126 {
00127         ipc_call_t answer;
00128 
00129         aid_t req = async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score,
00130             &answer);
00131         int retval = async_data_write_start(phone, match_id->id,
00132             str_size(match_id->id));
00133 
00134         async_wait_for(req, NULL);
00135         return retval;
00136 }
00137 
00138 
00139 static int devman_send_match_ids(int phone, match_id_list_t *match_ids)
00140 {
00141         link_t *link = match_ids->ids.next;
00142         match_id_t *match_id = NULL;
00143         int ret = EOK;
00144 
00145         while (link != &match_ids->ids) {
00146                 match_id = list_get_instance(link, match_id_t, link); 
00147                 ret = devman_send_match_id(phone, match_id);
00148                 if (ret != EOK) {
00149                         return ret;
00150                 }
00151 
00152                 link = link->next;
00153         }
00154 
00155         return ret;
00156 }
00157 
00171 int devman_add_function(const char *name, fun_type_t ftype,
00172     match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
00173 {
00174         int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
00175         int fun_handle;
00176         
00177         if (phone < 0)
00178                 return phone;
00179         
00180         async_serialize_start();
00181         
00182         int match_count = list_count(&match_ids->ids);
00183         ipc_call_t answer;
00184 
00185         aid_t req = async_send_3(phone, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
00186             devh, match_count, &answer);
00187 
00188         sysarg_t retval = async_data_write_start(phone, name, str_size(name));
00189         if (retval != EOK) {
00190                 async_wait_for(req, NULL);
00191                 async_serialize_end();
00192                 return retval;
00193         }
00194         
00195         int match_ids_rc = devman_send_match_ids(phone, match_ids);
00196         
00197         async_wait_for(req, &retval);
00198         
00199         async_serialize_end();
00200         
00201         /* Prefer the answer to DEVMAN_ADD_FUNCTION in case of errors. */
00202         if ((match_ids_rc != EOK) && (retval == EOK)) {
00203                 retval = match_ids_rc;
00204         }
00205 
00206         if (retval == EOK)
00207                 fun_handle = (int) IPC_GET_ARG1(answer);
00208         else
00209                 fun_handle = -1;
00210         
00211         *funh = fun_handle;
00212 
00213         return retval;
00214 }
00215 
00216 int devman_add_device_to_class(devman_handle_t devman_handle,
00217     const char *class_name)
00218 {
00219         int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
00220         
00221         if (phone < 0)
00222                 return phone;
00223         
00224         async_serialize_start();
00225         ipc_call_t answer;
00226         aid_t req = async_send_1(phone, DEVMAN_ADD_DEVICE_TO_CLASS,
00227             devman_handle, &answer);
00228         
00229         sysarg_t retval = async_data_write_start(phone, class_name,
00230             str_size(class_name));
00231         if (retval != EOK) {
00232                 async_wait_for(req, NULL);
00233                 async_serialize_end();
00234                 return retval;
00235         }
00236         
00237         async_wait_for(req, &retval);
00238         async_serialize_end();
00239         
00240         return retval;
00241 }
00242 
00243 void devman_hangup_phone(devman_interface_t iface)
00244 {
00245         switch (iface) {
00246         case DEVMAN_DRIVER:
00247                 if (devman_phone_driver >= 0) {
00248                         async_hangup(devman_phone_driver);
00249                         devman_phone_driver = -1;
00250                 }
00251                 break;
00252         case DEVMAN_CLIENT:
00253                 if (devman_phone_client >= 0) {
00254                         async_hangup(devman_phone_client);
00255                         devman_phone_client = -1;
00256                 }
00257                 break;
00258         default:
00259                 break;
00260         }
00261 }
00262 
00263 int devman_device_connect(devman_handle_t handle, unsigned int flags)
00264 {
00265         int phone;
00266         
00267         if (flags & IPC_FLAG_BLOCKING) {
00268                 phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
00269                     DEVMAN_CONNECT_TO_DEVICE, handle);
00270         } else {
00271                 phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
00272                     DEVMAN_CONNECT_TO_DEVICE, handle);
00273         }
00274         
00275         return phone;
00276 }
00277 
00278 int devman_parent_device_connect(devman_handle_t handle, unsigned int flags)
00279 {
00280         int phone;
00281         
00282         if (flags & IPC_FLAG_BLOCKING) {
00283                 phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
00284                     DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
00285         } else {
00286                 phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
00287                     DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
00288         }
00289         
00290         return phone;
00291 }
00292 
00293 int devman_device_get_handle(const char *pathname, devman_handle_t *handle,
00294     unsigned int flags)
00295 {
00296         int phone = devman_get_phone(DEVMAN_CLIENT, flags);
00297         
00298         if (phone < 0)
00299                 return phone;
00300         
00301         async_serialize_start();
00302         
00303         ipc_call_t answer;
00304         aid_t req = async_send_2(phone, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
00305             &answer);
00306         
00307         sysarg_t retval = async_data_write_start(phone, pathname,
00308             str_size(pathname));
00309         if (retval != EOK) {
00310                 async_wait_for(req, NULL);
00311                 async_serialize_end();
00312                 return retval;
00313         }
00314         
00315         async_wait_for(req, &retval);
00316         
00317         async_serialize_end();
00318         
00319         if (retval != EOK) {
00320                 if (handle != NULL)
00321                         *handle = (devman_handle_t) -1;
00322                 return retval;
00323         }
00324         
00325         if (handle != NULL)
00326                 *handle = (devman_handle_t) IPC_GET_ARG1(answer);
00327         
00328         return retval;
00329 }
00330 
00331 int devman_device_get_handle_by_class(const char *classname,
00332     const char *devname, devman_handle_t *handle, unsigned int flags)
00333 {
00334         int phone = devman_get_phone(DEVMAN_CLIENT, flags);
00335 
00336         if (phone < 0)
00337                 return phone;
00338 
00339         async_serialize_start();
00340 
00341         ipc_call_t answer;
00342         aid_t req = async_send_1(phone, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
00343             flags, &answer);
00344 
00345         sysarg_t retval = async_data_write_start(phone, classname,
00346             str_size(classname));
00347         if (retval != EOK) {
00348                 async_wait_for(req, NULL);
00349                 async_serialize_end();
00350                 return retval;
00351         }
00352         retval = async_data_write_start(phone, devname,
00353             str_size(devname));
00354         if (retval != EOK) {
00355                 async_wait_for(req, NULL);
00356                 async_serialize_end();
00357                 return retval;
00358         }
00359 
00360         async_wait_for(req, &retval);
00361 
00362         async_serialize_end();
00363 
00364         if (retval != EOK) {
00365                 if (handle != NULL)
00366                         *handle = (devman_handle_t) -1;
00367                 return retval;
00368         }
00369 
00370         if (handle != NULL)
00371                 *handle = (devman_handle_t) IPC_GET_ARG1(answer);
00372 
00373         return retval;
00374 }
00375 
00376 int devman_get_device_path(devman_handle_t handle, char *path, size_t path_size)
00377 {
00378         int phone = devman_get_phone(DEVMAN_CLIENT, 0);
00379 
00380         if (phone < 0)
00381                 return phone;
00382 
00383         async_serialize_start();
00384 
00385         ipc_call_t answer;
00386         aid_t req = async_send_1(phone, DEVMAN_DEVICE_GET_DEVICE_PATH,
00387             handle, &answer);
00388 
00389         ipc_call_t data_request_call;
00390         aid_t data_request = async_data_read(phone, path, path_size,
00391             &data_request_call);
00392         if (data_request == 0) {
00393                 async_wait_for(req, NULL);
00394                 async_serialize_end();
00395                 return ENOMEM;
00396         }
00397 
00398         sysarg_t data_request_rc;
00399         sysarg_t opening_request_rc;
00400         async_wait_for(data_request, &data_request_rc);
00401         async_wait_for(req, &opening_request_rc);
00402 
00403         async_serialize_end();
00404 
00405         if (data_request_rc != EOK) {
00406                 /* Prefer the return code of the opening request. */
00407                 if (opening_request_rc != EOK) {
00408                         return (int) opening_request_rc;
00409                 } else {
00410                         return (int) data_request_rc;
00411                 }
00412         }
00413         if (opening_request_rc != EOK) {
00414                 return (int) opening_request_rc;
00415         }
00416 
00417         /* To be on the safe-side. */
00418         path[path_size - 1] = 0;
00419 
00420         size_t transferred_size = IPC_GET_ARG2(data_request_call);
00421 
00422         if (transferred_size >= path_size) {
00423                 return ELIMIT;
00424         }
00425 
00426         /* Terminate the string (trailing 0 not send over IPC). */
00427         path[transferred_size] = 0;
00428 
00429         return EOK;
00430 }
00431 
00432 

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