Changes in uspace/lib/c/generic/devman.c [e72fb34:79ae36dd] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/devman.c
re72fb34 r79ae36dd 36 36 37 37 #include <str.h> 38 #include <stdio.h>39 38 #include <ipc/services.h> 39 #include <ns.h> 40 40 #include <ipc/devman.h> 41 41 #include <devman.h> 42 #include <fibril_synch.h> 42 43 #include <async.h> 43 #include <fibril_synch.h>44 44 #include <errno.h> 45 45 #include <malloc.h> 46 46 #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 48 static FIBRIL_MUTEX_INITIALIZE(devman_driver_block_mutex); 49 static FIBRIL_MUTEX_INITIALIZE(devman_client_block_mutex); 50 51 static FIBRIL_MUTEX_INITIALIZE(devman_driver_mutex); 52 static FIBRIL_MUTEX_INITIALIZE(devman_client_mutex); 53 54 static async_sess_t *devman_driver_block_sess = NULL; 55 static async_sess_t *devman_client_block_sess = NULL; 56 57 static async_sess_t *devman_driver_sess = NULL; 58 static async_sess_t *devman_client_sess = NULL; 59 60 static 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 */ 78 async_exch_t *devman_exchange_begin_blocking(devman_interface_t iface) 55 79 { 56 80 switch (iface) { 57 81 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); 62 92 } 63 93 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); 73 100 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); 78 111 } 79 112 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); 90 119 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 */ 131 async_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 */ 172 void devman_exchange_end(async_exch_t *exch) 173 { 174 async_exchange_end(exch); 93 175 } 94 176 … … 96 178 int devman_driver_register(const char *name, async_client_conn_t conn) 97 179 { 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; 113 191 } 114 192 115 193 async_set_client_connection(conn); 116 194 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 118 199 async_wait_for(req, &retval); 119 120 async_serialize_end();121 122 200 return retval; 123 201 } 124 202 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 */ 217 int 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 233 async_wait_for(req, &retval); 234 if (retval != EOK) { 235 devman_exchange_end(exch); 236 237 if (funh != NULL) 238 *funh = -1; 239 240 return retval; 241 } 242 243 if (funh != NULL) 244 *funh = (int) IPC_GET_ARG1(answer); 245 141 246 link_t *link = match_ids->ids.next; 142 247 match_id_t *match_id = NULL; 143 int ret = EOK; 144 248 145 249 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; 250 match_id = list_get_instance(link, match_id_t, link); 251 252 ipc_call_t answer; 253 aid_t req = async_send_1(exch, DEVMAN_ADD_MATCH_ID, 254 match_id->score, &answer); 255 retval = async_data_write_start(exch, match_id->id, 256 str_size(match_id->id)); 257 if (retval != EOK) { 258 devman_exchange_end(exch); 259 async_wait_for(req, NULL); 260 return retval; 150 261 } 151 262 263 async_wait_for(req, &retval); 264 if (retval != EOK) { 265 devman_exchange_end(exch); 266 return retval; 267 } 268 152 269 link = link->next; 153 270 } 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); 196 197 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 213 return retval; 271 272 devman_exchange_end(exch); 273 return EOK; 214 274 } 215 275 … … 217 277 const char *class_name) 218 278 { 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, 279 async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER); 280 281 ipc_call_t answer; 282 aid_t req = async_send_1(exch, DEVMAN_ADD_DEVICE_TO_CLASS, 227 283 devman_handle, &answer); 228 229 sysarg_t retval = async_data_write_start(phone, class_name, 284 sysarg_t retval = async_data_write_start(exch, class_name, 230 285 str_size(class_name)); 231 if (retval != EOK) { 232 async_wait_for(req, NULL); 233 async_serialize_end(); 286 287 devman_exchange_end(exch); 288 289 if (retval != EOK) { 290 async_wait_for(req, NULL); 234 291 return retval; 235 292 } 236 293 237 294 async_wait_for(req, &retval); 238 async_serialize_end();239 240 295 return retval; 241 296 } 242 297 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; 298 async_sess_t *devman_device_connect(exch_mgmt_t mgmt, devman_handle_t handle, 299 unsigned int flags) 300 { 301 async_sess_t *sess; 302 303 if (flags & IPC_FLAG_BLOCKING) 304 sess = service_connect_blocking(mgmt, SERVICE_DEVMAN, 305 DEVMAN_CONNECT_TO_DEVICE, handle); 306 else 307 sess = service_connect(mgmt, SERVICE_DEVMAN, 308 DEVMAN_CONNECT_TO_DEVICE, handle); 309 310 return sess; 311 } 312 313 async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt, 314 devman_handle_t handle, unsigned int flags) 315 { 316 async_sess_t *sess; 317 318 if (flags & IPC_FLAG_BLOCKING) 319 sess = service_connect_blocking(mgmt, SERVICE_DEVMAN, 320 DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle); 321 else 322 sess = service_connect(mgmt, SERVICE_DEVMAN, 323 DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle); 324 325 return sess; 291 326 } 292 327 … … 294 329 unsigned int flags) 295 330 { 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, 331 async_exch_t *exch; 332 333 if (flags & IPC_FLAG_BLOCKING) 334 exch = devman_exchange_begin_blocking(DEVMAN_CLIENT); 335 else { 336 exch = devman_exchange_begin(DEVMAN_CLIENT); 337 if (exch == NULL) 338 return errno; 339 } 340 341 ipc_call_t answer; 342 aid_t req = async_send_2(exch, DEVMAN_DEVICE_GET_HANDLE, flags, 0, 305 343 &answer); 306 307 sysarg_t retval = async_data_write_start(phone, pathname, 344 sysarg_t retval = async_data_write_start(exch, pathname, 308 345 str_size(pathname)); 309 if (retval != EOK) { 310 async_wait_for(req, NULL); 311 async_serialize_end(); 346 347 devman_exchange_end(exch); 348 349 if (retval != EOK) { 350 async_wait_for(req, NULL); 312 351 return retval; 313 352 } 314 353 315 354 async_wait_for(req, &retval); 316 317 async_serialize_end();318 355 319 356 if (retval != EOK) { 320 357 if (handle != NULL) 321 358 *handle = (devman_handle_t) -1; 359 322 360 return retval; 323 361 } … … 332 370 const char *devname, devman_handle_t *handle, unsigned int flags) 333 371 { 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, 372 async_exch_t *exch; 373 374 if (flags & IPC_FLAG_BLOCKING) 375 exch = devman_exchange_begin_blocking(DEVMAN_CLIENT); 376 else { 377 exch = devman_exchange_begin(DEVMAN_CLIENT); 378 if (exch == NULL) 379 return errno; 380 } 381 382 ipc_call_t answer; 383 aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS, 343 384 flags, &answer); 344 345 sysarg_t retval = async_data_write_start(phone, classname, 385 sysarg_t retval = async_data_write_start(exch, classname, 346 386 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, 387 388 if (retval != EOK) { 389 devman_exchange_end(exch); 390 async_wait_for(req, NULL); 391 return retval; 392 } 393 394 retval = async_data_write_start(exch, devname, 353 395 str_size(devname)); 354 if (retval != EOK) { 355 async_wait_for(req, NULL); 356 async_serialize_end(); 357 return retval; 358 } 359 396 397 devman_exchange_end(exch); 398 399 if (retval != EOK) { 400 async_wait_for(req, NULL); 401 return retval; 402 } 403 360 404 async_wait_for(req, &retval); 361 362 async_serialize_end(); 363 405 364 406 if (retval != EOK) { 365 407 if (handle != NULL) 366 408 *handle = (devman_handle_t) -1; 367 return retval; 368 } 369 409 410 return retval; 411 } 412 370 413 if (handle != NULL) 371 414 *handle = (devman_handle_t) IPC_GET_ARG1(answer); 372 415 373 416 return retval; 374 417 } 375 418 419 int devman_get_device_path(devman_handle_t handle, char *path, size_t path_size) 420 { 421 async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT); 422 if (exch == NULL) 423 return errno; 424 425 ipc_call_t answer; 426 aid_t req = async_send_1(exch, DEVMAN_DEVICE_GET_DEVICE_PATH, 427 handle, &answer); 428 429 ipc_call_t data_request_call; 430 aid_t data_request = async_data_read(exch, path, path_size, 431 &data_request_call); 432 433 devman_exchange_end(exch); 434 435 if (data_request == 0) { 436 async_wait_for(req, NULL); 437 return ENOMEM; 438 } 439 440 sysarg_t data_request_rc; 441 async_wait_for(data_request, &data_request_rc); 442 443 sysarg_t opening_request_rc; 444 async_wait_for(req, &opening_request_rc); 445 446 if (data_request_rc != EOK) { 447 /* Prefer the return code of the opening request. */ 448 if (opening_request_rc != EOK) 449 return (int) opening_request_rc; 450 else 451 return (int) data_request_rc; 452 } 453 454 if (opening_request_rc != EOK) 455 return (int) opening_request_rc; 456 457 /* To be on the safe-side. */ 458 path[path_size - 1] = 0; 459 size_t transferred_size = IPC_GET_ARG2(data_request_call); 460 if (transferred_size >= path_size) 461 return ELIMIT; 462 463 /* Terminate the string (trailing 0 not send over IPC). */ 464 path[transferred_size] = 0; 465 return EOK; 466 } 376 467 377 468 /** @}
Note:
See TracChangeset
for help on using the changeset viewer.