Changeset c028b22 in mainline for uspace/lib/c/generic/devman.c


Ignore:
Timestamp:
2011-07-08T17:01:01Z (13 years ago)
Author:
Martin Sucha <sucha14@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
cc1a727
Parents:
4e36219 (diff), 026793d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes

File:
1 edited

Legend:

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

    r4e36219 rc028b22  
    3535 */
    3636
     37#include <adt/list.h>
    3738#include <str.h>
    38 #include <stdio.h>
    3939#include <ipc/services.h>
     40#include <ns.h>
    4041#include <ipc/devman.h>
    4142#include <devman.h>
     43#include <fibril_synch.h>
    4244#include <async.h>
    43 #include <fibril_synch.h>
    4445#include <errno.h>
    4546#include <malloc.h>
    4647#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)
     48
     49static FIBRIL_MUTEX_INITIALIZE(devman_driver_block_mutex);
     50static FIBRIL_MUTEX_INITIALIZE(devman_client_block_mutex);
     51
     52static FIBRIL_MUTEX_INITIALIZE(devman_driver_mutex);
     53static FIBRIL_MUTEX_INITIALIZE(devman_client_mutex);
     54
     55static async_sess_t *devman_driver_block_sess = NULL;
     56static async_sess_t *devman_client_block_sess = NULL;
     57
     58static async_sess_t *devman_driver_sess = NULL;
     59static async_sess_t *devman_client_sess = NULL;
     60
     61static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
     62    async_sess_t **dst)
     63{
     64        fibril_mutex_lock(mtx);
     65       
     66        if ((*dst == NULL) && (src != NULL))
     67                *dst = src;
     68       
     69        fibril_mutex_unlock(mtx);
     70}
     71
     72/** Start an async exchange on the devman session (blocking).
     73 *
     74 * @param iface Device manager interface to choose
     75 *
     76 * @return New exchange.
     77 *
     78 */
     79async_exch_t *devman_exchange_begin_blocking(devman_interface_t iface)
    5580{
    5681        switch (iface) {
    5782        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;
     83                fibril_mutex_lock(&devman_driver_block_mutex);
     84               
     85                while (devman_driver_block_sess == NULL) {
     86                        clone_session(&devman_driver_mutex, devman_driver_sess,
     87                            &devman_driver_block_sess);
     88                       
     89                        if (devman_driver_block_sess == NULL)
     90                                devman_driver_block_sess =
     91                                    service_connect_blocking(EXCHANGE_SERIALIZE,
     92                                    SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
    6293                }
    6394               
    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;
     95                fibril_mutex_unlock(&devman_driver_block_mutex);
     96               
     97                clone_session(&devman_driver_mutex, devman_driver_block_sess,
     98                    &devman_driver_sess);
     99               
     100                return async_exchange_begin(devman_driver_block_sess);
    73101        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;
     102                fibril_mutex_lock(&devman_client_block_mutex);
     103               
     104                while (devman_client_block_sess == NULL) {
     105                        clone_session(&devman_client_mutex, devman_client_sess,
     106                            &devman_client_block_sess);
     107                       
     108                        if (devman_client_block_sess == NULL)
     109                                devman_client_block_sess =
     110                                    service_connect_blocking(EXCHANGE_SERIALIZE,
     111                                    SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
    78112                }
    79113               
    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;
     114                fibril_mutex_unlock(&devman_client_block_mutex);
     115               
     116                clone_session(&devman_client_mutex, devman_client_block_sess,
     117                    &devman_client_sess);
     118               
     119                return async_exchange_begin(devman_client_block_sess);
    90120        default:
    91                 return -1;
    92         }
     121                return NULL;
     122        }
     123}
     124
     125/** Start an async exchange on the devman session.
     126 *
     127 * @param iface Device manager interface to choose
     128 *
     129 * @return New exchange.
     130 *
     131 */
     132async_exch_t *devman_exchange_begin(devman_interface_t iface)
     133{
     134        switch (iface) {
     135        case DEVMAN_DRIVER:
     136                fibril_mutex_lock(&devman_driver_mutex);
     137               
     138                if (devman_driver_sess == NULL)
     139                        devman_driver_sess =
     140                            service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAN,
     141                            DEVMAN_DRIVER, 0);
     142               
     143                fibril_mutex_unlock(&devman_driver_mutex);
     144               
     145                if (devman_driver_sess == NULL)
     146                        return NULL;
     147               
     148                return async_exchange_begin(devman_driver_sess);
     149        case DEVMAN_CLIENT:
     150                fibril_mutex_lock(&devman_client_mutex);
     151               
     152                if (devman_client_sess == NULL)
     153                        devman_client_sess =
     154                            service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAN,
     155                            DEVMAN_CLIENT, 0);
     156               
     157                fibril_mutex_unlock(&devman_client_mutex);
     158               
     159                if (devman_client_sess == NULL)
     160                        return NULL;
     161               
     162                return async_exchange_begin(devman_client_sess);
     163        default:
     164                return NULL;
     165        }
     166}
     167
     168/** Finish an async exchange on the devman session.
     169 *
     170 * @param exch Exchange to be finished.
     171 *
     172 */
     173void devman_exchange_end(async_exch_t *exch)
     174{
     175        async_exchange_end(exch);
    93176}
    94177
     
    96179int devman_driver_register(const char *name, async_client_conn_t conn)
    97180{
    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;
     181        async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
     182       
     183        ipc_call_t answer;
     184        aid_t req = async_send_2(exch, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
     185        sysarg_t retval = async_data_write_start(exch, name, str_size(name));
     186       
     187        devman_exchange_end(exch);
     188       
     189        if (retval != EOK) {
     190                async_wait_for(req, NULL);
     191                return retval;
    113192        }
    114193       
    115194        async_set_client_connection(conn);
    116195       
    117         async_connect_to_me(phone, 0, 0, 0, NULL);
     196        exch = devman_exchange_begin(DEVMAN_DRIVER);
     197        async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
     198        devman_exchange_end(exch);
     199       
    118200        async_wait_for(req, &retval);
    119        
    120         async_serialize_end();
    121        
    122201        return retval;
    123 }
    124 
    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 {
    141         link_t *link = match_ids->ids.next;
    142         match_id_t *match_id = NULL;
    143         int ret = EOK;
    144 
    145         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;
    150                 }
    151 
    152                 link = link->next;
    153         }
    154 
    155         return ret;
    156202}
    157203
     
    161207 * this driver task.
    162208 *
    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.
     209 * @param name      Name of the new function
     210 * @param ftype     Function type, fun_inner or fun_exposed
     211 * @param match_ids Match IDs (should be empty for fun_exposed)
     212 * @param devh      Devman handle of the device
     213 * @param funh      Place to store handle of the new function
     214 *
     215 * @return EOK on success or negative error code.
     216 *
    170217 */
    171218int devman_add_function(const char *name, fun_type_t ftype,
    172219    match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
    173220{
    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        
    182221        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,
     222        async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
     223       
     224        ipc_call_t answer;
     225        aid_t req = async_send_3(exch, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
    186226            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);
     227        sysarg_t retval = async_data_write_start(exch, name, str_size(name));
     228        if (retval != EOK) {
     229                devman_exchange_end(exch);
     230                async_wait_for(req, NULL);
     231                return retval;
     232        }
     233       
     234        match_id_t *match_id = NULL;
     235       
     236        list_foreach(match_ids->ids, link) {
     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;
     249                }
     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        }
     258       
     259        devman_exchange_end(exch);
    196260       
    197261        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 
     262        if (retval == EOK) {
     263                if (funh != NULL)
     264                        *funh = (int) IPC_GET_ARG1(answer);
     265        } else {
     266                if (funh != NULL)
     267                        *funh = -1;
     268        }
     269       
    213270        return retval;
    214271}
     
    217274    const char *class_name)
    218275{
    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,
     276        async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
     277       
     278        ipc_call_t answer;
     279        aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CLASS,
    227280            devman_handle, &answer);
    228        
    229         sysarg_t retval = async_data_write_start(phone, class_name,
     281        sysarg_t retval = async_data_write_start(exch, class_name,
    230282            str_size(class_name));
    231         if (retval != EOK) {
    232                 async_wait_for(req, NULL);
    233                 async_serialize_end();
     283       
     284        devman_exchange_end(exch);
     285       
     286        if (retval != EOK) {
     287                async_wait_for(req, NULL);
    234288                return retval;
    235289        }
    236290       
    237291        async_wait_for(req, &retval);
    238         async_serialize_end();
    239        
    240292        return retval;
    241293}
    242294
    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;
     295async_sess_t *devman_device_connect(exch_mgmt_t mgmt, devman_handle_t handle,
     296    unsigned int flags)
     297{
     298        async_sess_t *sess;
     299       
     300        if (flags & IPC_FLAG_BLOCKING)
     301                sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
     302                            DEVMAN_CONNECT_TO_DEVICE, handle);
     303        else
     304                sess = service_connect(mgmt, SERVICE_DEVMAN,
     305                            DEVMAN_CONNECT_TO_DEVICE, handle);
     306       
     307        return sess;
     308}
     309
     310async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt,
     311    devman_handle_t handle, unsigned int flags)
     312{
     313        async_sess_t *sess;
     314       
     315        if (flags & IPC_FLAG_BLOCKING)
     316                sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
     317                            DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
     318        else
     319                sess = service_connect(mgmt, SERVICE_DEVMAN,
     320                            DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
     321       
     322        return sess;
    291323}
    292324
     
    294326    unsigned int flags)
    295327{
    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,
     328        async_exch_t *exch;
     329       
     330        if (flags & IPC_FLAG_BLOCKING)
     331                exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
     332        else {
     333                exch = devman_exchange_begin(DEVMAN_CLIENT);
     334                if (exch == NULL)
     335                        return errno;
     336        }
     337       
     338        ipc_call_t answer;
     339        aid_t req = async_send_2(exch, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
    305340            &answer);
    306        
    307         sysarg_t retval = async_data_write_start(phone, pathname,
     341        sysarg_t retval = async_data_write_start(exch, pathname,
    308342            str_size(pathname));
    309         if (retval != EOK) {
    310                 async_wait_for(req, NULL);
    311                 async_serialize_end();
     343       
     344        devman_exchange_end(exch);
     345       
     346        if (retval != EOK) {
     347                async_wait_for(req, NULL);
    312348                return retval;
    313349        }
    314350       
    315351        async_wait_for(req, &retval);
    316        
    317         async_serialize_end();
    318352       
    319353        if (retval != EOK) {
    320354                if (handle != NULL)
    321355                        *handle = (devman_handle_t) -1;
     356               
    322357                return retval;
    323358        }
     
    332367    const char *devname, devman_handle_t *handle, unsigned int flags)
    333368{
    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,
     369        async_exch_t *exch;
     370       
     371        if (flags & IPC_FLAG_BLOCKING)
     372                exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
     373        else {
     374                exch = devman_exchange_begin(DEVMAN_CLIENT);
     375                if (exch == NULL)
     376                        return errno;
     377        }
     378       
     379        ipc_call_t answer;
     380        aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
    343381            flags, &answer);
    344 
    345         sysarg_t retval = async_data_write_start(phone, classname,
     382        sysarg_t retval = async_data_write_start(exch, classname,
    346383            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,
     384       
     385        if (retval != EOK) {
     386                devman_exchange_end(exch);
     387                async_wait_for(req, NULL);
     388                return retval;
     389        }
     390       
     391        retval = async_data_write_start(exch, devname,
    353392            str_size(devname));
    354         if (retval != EOK) {
    355                 async_wait_for(req, NULL);
    356                 async_serialize_end();
    357                 return retval;
    358         }
    359 
     393       
     394        devman_exchange_end(exch);
     395       
     396        if (retval != EOK) {
     397                async_wait_for(req, NULL);
     398                return retval;
     399        }
     400       
    360401        async_wait_for(req, &retval);
    361 
    362         async_serialize_end();
    363 
     402       
    364403        if (retval != EOK) {
    365404                if (handle != NULL)
    366405                        *handle = (devman_handle_t) -1;
    367                 return retval;
    368         }
    369 
     406               
     407                return retval;
     408        }
     409       
    370410        if (handle != NULL)
    371411                *handle = (devman_handle_t) IPC_GET_ARG1(answer);
    372 
     412       
    373413        return retval;
    374414}
    375415
     416int devman_get_device_path(devman_handle_t handle, char *path, size_t path_size)
     417{
     418        async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
     419        if (exch == NULL)
     420                return errno;
     421       
     422        ipc_call_t answer;
     423        aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_DEVICE_PATH,
     424            handle, &answer);
     425       
     426        ipc_call_t data_request_call;
     427        aid_t data_request = async_data_read(exch, path, path_size,
     428            &data_request_call);
     429       
     430        devman_exchange_end(exch);
     431       
     432        if (data_request == 0) {
     433                async_wait_for(req, NULL);
     434                return ENOMEM;
     435        }
     436       
     437        sysarg_t data_request_rc;
     438        async_wait_for(data_request, &data_request_rc);
     439       
     440        sysarg_t opening_request_rc;
     441        async_wait_for(req, &opening_request_rc);
     442       
     443        if (data_request_rc != EOK) {
     444                /* Prefer the return code of the opening request. */
     445                if (opening_request_rc != EOK)
     446                        return (int) opening_request_rc;
     447                else
     448                        return (int) data_request_rc;
     449        }
     450       
     451        if (opening_request_rc != EOK)
     452                return (int) opening_request_rc;
     453       
     454        /* To be on the safe-side. */
     455        path[path_size - 1] = 0;
     456        size_t transferred_size = IPC_GET_ARG2(data_request_call);
     457        if (transferred_size >= path_size)
     458                return ELIMIT;
     459       
     460        /* Terminate the string (trailing 0 not send over IPC). */
     461        path[transferred_size] = 0;
     462        return EOK;
     463}
    376464
    377465/** @}
Note: See TracChangeset for help on using the changeset viewer.