Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/devman.c

    re72fb34 re6211f8  
    3636
    3737#include <str.h>
    38 #include <stdio.h>
    3938#include <ipc/services.h>
     39#include <ns.h>
    4040#include <ipc/devman.h>
    4141#include <devman.h>
     42#include <fibril_synch.h>
    4243#include <async.h>
    43 #include <fibril_synch.h>
    4444#include <errno.h>
    4545#include <malloc.h>
    4646#include <bool.h>
    47 #include <adt/list.h>
    48 
    49 static int devman_phone_driver = -1;
    50 static int devman_phone_client = -1;
    51 
    52 static FIBRIL_MUTEX_INITIALIZE(devman_phone_mutex);
    53 
    54 int devman_get_phone(devman_interface_t iface, unsigned int flags)
     47
     48static FIBRIL_MUTEX_INITIALIZE(devman_driver_block_mutex);
     49static FIBRIL_MUTEX_INITIALIZE(devman_client_block_mutex);
     50
     51static FIBRIL_MUTEX_INITIALIZE(devman_driver_mutex);
     52static FIBRIL_MUTEX_INITIALIZE(devman_client_mutex);
     53
     54static async_sess_t *devman_driver_block_sess = NULL;
     55static async_sess_t *devman_client_block_sess = NULL;
     56
     57static async_sess_t *devman_driver_sess = NULL;
     58static async_sess_t *devman_client_sess = NULL;
     59
     60static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
     61    async_sess_t **dst)
     62{
     63        fibril_mutex_lock(mtx);
     64       
     65        if ((*dst == NULL) && (src != NULL))
     66                *dst = src;
     67       
     68        fibril_mutex_unlock(mtx);
     69}
     70
     71/** Start an async exchange on the devman session (blocking).
     72 *
     73 * @param iface Device manager interface to choose
     74 *
     75 * @return New exchange.
     76 *
     77 */
     78async_exch_t *devman_exchange_begin_blocking(devman_interface_t iface)
    5579{
    5680        switch (iface) {
    5781        case DEVMAN_DRIVER:
    58                 fibril_mutex_lock(&devman_phone_mutex);
    59                 if (devman_phone_driver >= 0) {
    60                         fibril_mutex_unlock(&devman_phone_mutex);
    61                         return devman_phone_driver;
     82                fibril_mutex_lock(&devman_driver_block_mutex);
     83               
     84                while (devman_driver_block_sess == NULL) {
     85                        clone_session(&devman_driver_mutex, devman_driver_sess,
     86                            &devman_driver_block_sess);
     87                       
     88                        if (devman_driver_block_sess == NULL)
     89                                devman_driver_block_sess =
     90                                    service_connect_blocking(EXCHANGE_SERIALIZE,
     91                                    SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
    6292                }
    6393               
    64                 if (flags & IPC_FLAG_BLOCKING)
    65                         devman_phone_driver = async_connect_me_to_blocking(
    66                             PHONE_NS, SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
    67                 else
    68                         devman_phone_driver = async_connect_me_to(PHONE_NS,
    69                             SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
    70                
    71                 fibril_mutex_unlock(&devman_phone_mutex);
    72                 return devman_phone_driver;
     94                fibril_mutex_unlock(&devman_driver_block_mutex);
     95               
     96                clone_session(&devman_driver_mutex, devman_driver_block_sess,
     97                    &devman_driver_sess);
     98               
     99                return async_exchange_begin(devman_driver_block_sess);
    73100        case DEVMAN_CLIENT:
    74                 fibril_mutex_lock(&devman_phone_mutex);
    75                 if (devman_phone_client >= 0) {
    76                         fibril_mutex_unlock(&devman_phone_mutex);
    77                         return devman_phone_client;
     101                fibril_mutex_lock(&devman_client_block_mutex);
     102               
     103                while (devman_client_block_sess == NULL) {
     104                        clone_session(&devman_client_mutex, devman_client_sess,
     105                            &devman_client_block_sess);
     106                       
     107                        if (devman_client_block_sess == NULL)
     108                                devman_client_block_sess =
     109                                    service_connect_blocking(EXCHANGE_SERIALIZE,
     110                                    SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
    78111                }
    79112               
    80                 if (flags & IPC_FLAG_BLOCKING) {
    81                         devman_phone_client = async_connect_me_to_blocking(
    82                             PHONE_NS, SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
    83                 } else {
    84                         devman_phone_client = async_connect_me_to(PHONE_NS,
    85                             SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
    86                 }
    87                
    88                 fibril_mutex_unlock(&devman_phone_mutex);
    89                 return devman_phone_client;
     113                fibril_mutex_unlock(&devman_client_block_mutex);
     114               
     115                clone_session(&devman_client_mutex, devman_client_block_sess,
     116                    &devman_client_sess);
     117               
     118                return async_exchange_begin(devman_client_block_sess);
    90119        default:
    91                 return -1;
    92         }
     120                return NULL;
     121        }
     122}
     123
     124/** Start an async exchange on the devman session.
     125 *
     126 * @param iface Device manager interface to choose
     127 *
     128 * @return New exchange.
     129 *
     130 */
     131async_exch_t *devman_exchange_begin(devman_interface_t iface)
     132{
     133        switch (iface) {
     134        case DEVMAN_DRIVER:
     135                fibril_mutex_lock(&devman_driver_mutex);
     136               
     137                if (devman_driver_sess == NULL)
     138                        devman_driver_sess =
     139                            service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAN,
     140                            DEVMAN_DRIVER, 0);
     141               
     142                fibril_mutex_unlock(&devman_driver_mutex);
     143               
     144                if (devman_driver_sess == NULL)
     145                        return NULL;
     146               
     147                return async_exchange_begin(devman_driver_sess);
     148        case DEVMAN_CLIENT:
     149                fibril_mutex_lock(&devman_client_mutex);
     150               
     151                if (devman_client_sess == NULL)
     152                        devman_client_sess =
     153                            service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAN,
     154                            DEVMAN_CLIENT, 0);
     155               
     156                fibril_mutex_unlock(&devman_client_mutex);
     157               
     158                if (devman_client_sess == NULL)
     159                        return NULL;
     160               
     161                return async_exchange_begin(devman_client_sess);
     162        default:
     163                return NULL;
     164        }
     165}
     166
     167/** Finish an async exchange on the devman session.
     168 *
     169 * @param exch Exchange to be finished.
     170 *
     171 */
     172void devman_exchange_end(async_exch_t *exch)
     173{
     174        async_exchange_end(exch);
    93175}
    94176
     
    96178int devman_driver_register(const char *name, async_client_conn_t conn)
    97179{
    98         int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
    99        
    100         if (phone < 0)
    101                 return phone;
    102        
    103         async_serialize_start();
    104        
    105         ipc_call_t answer;
    106         aid_t req = async_send_2(phone, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
    107        
    108         sysarg_t retval = async_data_write_start(phone, name, str_size(name));
    109         if (retval != EOK) {
    110                 async_wait_for(req, NULL);
    111                 async_serialize_end();
    112                 return -1;
     180        async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
     181       
     182        ipc_call_t answer;
     183        aid_t req = async_send_2(exch, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
     184        sysarg_t retval = async_data_write_start(exch, name, str_size(name));
     185       
     186        devman_exchange_end(exch);
     187       
     188        if (retval != EOK) {
     189                async_wait_for(req, NULL);
     190                return retval;
    113191        }
    114192       
    115193        async_set_client_connection(conn);
    116194       
    117         async_connect_to_me(phone, 0, 0, 0, NULL);
     195        exch = devman_exchange_begin(DEVMAN_DRIVER);
     196        async_connect_to_me(exch, 0, 0, 0, NULL);
     197        devman_exchange_end(exch);
     198       
    118199        async_wait_for(req, &retval);
    119        
    120         async_serialize_end();
    121        
    122200        return retval;
    123201}
    124202
    125 static int devman_send_match_id(int phone, match_id_t *match_id)
    126 {
    127         ipc_call_t answer;
    128 
    129         aid_t req = async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score,
    130             &answer);
    131         int retval = async_data_write_start(phone, match_id->id,
    132             str_size(match_id->id));
    133 
    134         async_wait_for(req, NULL);
    135         return retval;
    136 }
    137 
    138 
    139 static int devman_send_match_ids(int phone, match_id_list_t *match_ids)
    140 {
     203/** Add function to a device.
     204 *
     205 * Request devman to add a new function to the specified device owned by
     206 * this driver task.
     207 *
     208 * @param name      Name of the new function
     209 * @param ftype     Function type, fun_inner or fun_exposed
     210 * @param match_ids Match IDs (should be empty for fun_exposed)
     211 * @param devh      Devman handle of the device
     212 * @param funh      Place to store handle of the new function
     213 *
     214 * @return EOK on success or negative error code.
     215 *
     216 */
     217int devman_add_function(const char *name, fun_type_t ftype,
     218    match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
     219{
     220        int match_count = list_count(&match_ids->ids);
     221        async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
     222       
     223        ipc_call_t answer;
     224        aid_t req = async_send_3(exch, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
     225            devh, match_count, &answer);
     226        sysarg_t retval = async_data_write_start(exch, name, str_size(name));
     227        if (retval != EOK) {
     228                devman_exchange_end(exch);
     229                async_wait_for(req, NULL);
     230                return retval;
     231        }
     232       
    141233        link_t *link = match_ids->ids.next;
    142234        match_id_t *match_id = NULL;
    143         int ret = EOK;
    144 
     235       
    145236        while (link != &match_ids->ids) {
    146                 match_id = list_get_instance(link, match_id_t, link);
    147                 ret = devman_send_match_id(phone, match_id);
    148                 if (ret != EOK) {
    149                         return ret;
     237                match_id = list_get_instance(link, match_id_t, link);
     238               
     239                ipc_call_t answer2;
     240                aid_t req2 = async_send_1(exch, DEVMAN_ADD_MATCH_ID,
     241                    match_id->score, &answer2);
     242                retval = async_data_write_start(exch, match_id->id,
     243                    str_size(match_id->id));
     244                if (retval != EOK) {
     245                        devman_exchange_end(exch);
     246                        async_wait_for(req2, NULL);
     247                        async_wait_for(req, NULL);
     248                        return retval;
    150249                }
    151 
     250               
     251                async_wait_for(req2, &retval);
     252                if (retval != EOK) {
     253                        devman_exchange_end(exch);
     254                        async_wait_for(req, NULL);
     255                        return retval;
     256                }
     257               
    152258                link = link->next;
    153259        }
    154 
    155         return ret;
    156 }
    157 
    158 /** Add function to a device.
    159  *
    160  * Request devman to add a new function to the specified device owned by
    161  * this driver task.
    162  *
    163  * @param name          Name of the new function
    164  * @param ftype         Function type, fun_inner or fun_exposed
    165  * @param match_ids     Match IDs (should be empty for fun_exposed)
    166  * @param devh          Devman handle of the device
    167  * @param funh          Place to store handle of the new function
    168  *
    169  * @return              EOK on success or negative error code.
    170  */
    171 int devman_add_function(const char *name, fun_type_t ftype,
    172     match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
    173 {
    174         int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
    175         int fun_handle;
    176        
    177         if (phone < 0)
    178                 return phone;
    179        
    180         async_serialize_start();
    181        
    182         int match_count = list_count(&match_ids->ids);
    183         ipc_call_t answer;
    184 
    185         aid_t req = async_send_3(phone, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
    186             devh, match_count, &answer);
    187 
    188         sysarg_t retval = async_data_write_start(phone, name, str_size(name));
    189         if (retval != EOK) {
    190                 async_wait_for(req, NULL);
    191                 async_serialize_end();
    192                 return retval;
    193         }
    194        
    195         int match_ids_rc = devman_send_match_ids(phone, match_ids);
     260       
     261        devman_exchange_end(exch);
    196262       
    197263        async_wait_for(req, &retval);
    198        
    199         async_serialize_end();
    200        
    201         /* Prefer the answer to DEVMAN_ADD_FUNCTION in case of errors. */
    202         if ((match_ids_rc != EOK) && (retval == EOK)) {
    203                 retval = match_ids_rc;
    204         }
    205 
    206         if (retval == EOK)
    207                 fun_handle = (int) IPC_GET_ARG1(answer);
    208         else
    209                 fun_handle = -1;
    210        
    211         *funh = fun_handle;
    212 
     264        if (retval == EOK) {
     265                if (funh != NULL)
     266                        *funh = (int) IPC_GET_ARG1(answer);
     267        } else {
     268                if (funh != NULL)
     269                        *funh = -1;
     270        }
     271       
    213272        return retval;
    214273}
     
    217276    const char *class_name)
    218277{
    219         int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
    220        
    221         if (phone < 0)
    222                 return phone;
    223        
    224         async_serialize_start();
    225         ipc_call_t answer;
    226         aid_t req = async_send_1(phone, DEVMAN_ADD_DEVICE_TO_CLASS,
     278        async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
     279       
     280        ipc_call_t answer;
     281        aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CLASS,
    227282            devman_handle, &answer);
    228        
    229         sysarg_t retval = async_data_write_start(phone, class_name,
     283        sysarg_t retval = async_data_write_start(exch, class_name,
    230284            str_size(class_name));
    231         if (retval != EOK) {
    232                 async_wait_for(req, NULL);
    233                 async_serialize_end();
     285       
     286        devman_exchange_end(exch);
     287       
     288        if (retval != EOK) {
     289                async_wait_for(req, NULL);
    234290                return retval;
    235291        }
    236292       
    237293        async_wait_for(req, &retval);
    238         async_serialize_end();
    239        
    240294        return retval;
    241295}
    242296
    243 void devman_hangup_phone(devman_interface_t iface)
    244 {
    245         switch (iface) {
    246         case DEVMAN_DRIVER:
    247                 if (devman_phone_driver >= 0) {
    248                         async_hangup(devman_phone_driver);
    249                         devman_phone_driver = -1;
    250                 }
    251                 break;
    252         case DEVMAN_CLIENT:
    253                 if (devman_phone_client >= 0) {
    254                         async_hangup(devman_phone_client);
    255                         devman_phone_client = -1;
    256                 }
    257                 break;
    258         default:
    259                 break;
    260         }
    261 }
    262 
    263 int devman_device_connect(devman_handle_t handle, unsigned int flags)
    264 {
    265         int phone;
    266        
    267         if (flags & IPC_FLAG_BLOCKING) {
    268                 phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
    269                     DEVMAN_CONNECT_TO_DEVICE, handle);
    270         } else {
    271                 phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
    272                     DEVMAN_CONNECT_TO_DEVICE, handle);
    273         }
    274        
    275         return phone;
    276 }
    277 
    278 int devman_parent_device_connect(devman_handle_t handle, unsigned int flags)
    279 {
    280         int phone;
    281        
    282         if (flags & IPC_FLAG_BLOCKING) {
    283                 phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
    284                     DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
    285         } else {
    286                 phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
    287                     DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
    288         }
    289        
    290         return phone;
     297async_sess_t *devman_device_connect(exch_mgmt_t mgmt, devman_handle_t handle,
     298    unsigned int flags)
     299{
     300        async_sess_t *sess;
     301       
     302        if (flags & IPC_FLAG_BLOCKING)
     303                sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
     304                            DEVMAN_CONNECT_TO_DEVICE, handle);
     305        else
     306                sess = service_connect(mgmt, SERVICE_DEVMAN,
     307                            DEVMAN_CONNECT_TO_DEVICE, handle);
     308       
     309        return sess;
     310}
     311
     312async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt,
     313    devman_handle_t handle, unsigned int flags)
     314{
     315        async_sess_t *sess;
     316       
     317        if (flags & IPC_FLAG_BLOCKING)
     318                sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
     319                            DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
     320        else
     321                sess = service_connect(mgmt, SERVICE_DEVMAN,
     322                            DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
     323       
     324        return sess;
    291325}
    292326
     
    294328    unsigned int flags)
    295329{
    296         int phone = devman_get_phone(DEVMAN_CLIENT, flags);
    297        
    298         if (phone < 0)
    299                 return phone;
    300        
    301         async_serialize_start();
    302        
    303         ipc_call_t answer;
    304         aid_t req = async_send_2(phone, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
     330        async_exch_t *exch;
     331       
     332        if (flags & IPC_FLAG_BLOCKING)
     333                exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
     334        else {
     335                exch = devman_exchange_begin(DEVMAN_CLIENT);
     336                if (exch == NULL)
     337                        return errno;
     338        }
     339       
     340        ipc_call_t answer;
     341        aid_t req = async_send_2(exch, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
    305342            &answer);
    306        
    307         sysarg_t retval = async_data_write_start(phone, pathname,
     343        sysarg_t retval = async_data_write_start(exch, pathname,
    308344            str_size(pathname));
    309         if (retval != EOK) {
    310                 async_wait_for(req, NULL);
    311                 async_serialize_end();
     345       
     346        devman_exchange_end(exch);
     347       
     348        if (retval != EOK) {
     349                async_wait_for(req, NULL);
    312350                return retval;
    313351        }
    314352       
    315353        async_wait_for(req, &retval);
    316        
    317         async_serialize_end();
    318354       
    319355        if (retval != EOK) {
    320356                if (handle != NULL)
    321357                        *handle = (devman_handle_t) -1;
     358               
    322359                return retval;
    323360        }
     
    332369    const char *devname, devman_handle_t *handle, unsigned int flags)
    333370{
    334         int phone = devman_get_phone(DEVMAN_CLIENT, flags);
    335 
    336         if (phone < 0)
    337                 return phone;
    338 
    339         async_serialize_start();
    340 
    341         ipc_call_t answer;
    342         aid_t req = async_send_1(phone, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
     371        async_exch_t *exch;
     372       
     373        if (flags & IPC_FLAG_BLOCKING)
     374                exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
     375        else {
     376                exch = devman_exchange_begin(DEVMAN_CLIENT);
     377                if (exch == NULL)
     378                        return errno;
     379        }
     380       
     381        ipc_call_t answer;
     382        aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
    343383            flags, &answer);
    344 
    345         sysarg_t retval = async_data_write_start(phone, classname,
     384        sysarg_t retval = async_data_write_start(exch, classname,
    346385            str_size(classname));
    347         if (retval != EOK) {
    348                 async_wait_for(req, NULL);
    349                 async_serialize_end();
    350                 return retval;
    351         }
    352         retval = async_data_write_start(phone, devname,
     386       
     387        if (retval != EOK) {
     388                devman_exchange_end(exch);
     389                async_wait_for(req, NULL);
     390                return retval;
     391        }
     392       
     393        retval = async_data_write_start(exch, devname,
    353394            str_size(devname));
    354         if (retval != EOK) {
    355                 async_wait_for(req, NULL);
    356                 async_serialize_end();
    357                 return retval;
    358         }
    359 
     395       
     396        devman_exchange_end(exch);
     397       
     398        if (retval != EOK) {
     399                async_wait_for(req, NULL);
     400                return retval;
     401        }
     402       
    360403        async_wait_for(req, &retval);
    361 
    362         async_serialize_end();
    363 
     404       
    364405        if (retval != EOK) {
    365406                if (handle != NULL)
    366407                        *handle = (devman_handle_t) -1;
    367                 return retval;
    368         }
    369 
     408               
     409                return retval;
     410        }
     411       
    370412        if (handle != NULL)
    371413                *handle = (devman_handle_t) IPC_GET_ARG1(answer);
    372 
     414       
    373415        return retval;
    374416}
    375417
     418int devman_get_device_path(devman_handle_t handle, char *path, size_t path_size)
     419{
     420        async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
     421        if (exch == NULL)
     422                return errno;
     423       
     424        ipc_call_t answer;
     425        aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_DEVICE_PATH,
     426            handle, &answer);
     427       
     428        ipc_call_t data_request_call;
     429        aid_t data_request = async_data_read(exch, path, path_size,
     430            &data_request_call);
     431       
     432        devman_exchange_end(exch);
     433       
     434        if (data_request == 0) {
     435                async_wait_for(req, NULL);
     436                return ENOMEM;
     437        }
     438       
     439        sysarg_t data_request_rc;
     440        async_wait_for(data_request, &data_request_rc);
     441       
     442        sysarg_t opening_request_rc;
     443        async_wait_for(req, &opening_request_rc);
     444       
     445        if (data_request_rc != EOK) {
     446                /* Prefer the return code of the opening request. */
     447                if (opening_request_rc != EOK)
     448                        return (int) opening_request_rc;
     449                else
     450                        return (int) data_request_rc;
     451        }
     452       
     453        if (opening_request_rc != EOK)
     454                return (int) opening_request_rc;
     455       
     456        /* To be on the safe-side. */
     457        path[path_size - 1] = 0;
     458        size_t transferred_size = IPC_GET_ARG2(data_request_call);
     459        if (transferred_size >= path_size)
     460                return ELIMIT;
     461       
     462        /* Terminate the string (trailing 0 not send over IPC). */
     463        path[transferred_size] = 0;
     464        return EOK;
     465}
    376466
    377467/** @}
Note: See TracChangeset for help on using the changeset viewer.