Changes in uspace/lib/c/generic/devman.c [8b1e15ac:45059d6b] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/devman.c
r8b1e15ac r45059d6b 1 1 /* 2 2 * Copyright (c) 2007 Josef Cejka 3 * Copyright (c) 20 09Jiri Svoboda3 * Copyright (c) 2011 Jiri Svoboda 4 4 * Copyright (c) 2010 Lenka Trochtova 5 5 * All rights reserved. … … 35 35 */ 36 36 37 #include <adt/list.h> 37 38 #include <str.h> 38 #include <stdio.h>39 39 #include <ipc/services.h> 40 #include <ns.h> 40 41 #include <ipc/devman.h> 41 42 #include <devman.h> 43 #include <fibril_synch.h> 42 44 #include <async.h> 43 #include <fibril_synch.h>44 45 #include <errno.h> 45 46 #include <malloc.h> 46 47 #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 49 static FIBRIL_MUTEX_INITIALIZE(devman_driver_block_mutex); 50 static FIBRIL_MUTEX_INITIALIZE(devman_client_block_mutex); 51 52 static FIBRIL_MUTEX_INITIALIZE(devman_driver_mutex); 53 static FIBRIL_MUTEX_INITIALIZE(devman_client_mutex); 54 55 static async_sess_t *devman_driver_block_sess = NULL; 56 static async_sess_t *devman_client_block_sess = NULL; 57 58 static async_sess_t *devman_driver_sess = NULL; 59 static async_sess_t *devman_client_sess = NULL; 60 61 static 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 */ 79 async_exch_t *devman_exchange_begin_blocking(devman_interface_t iface) 55 80 { 56 81 switch (iface) { 57 82 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); 62 93 } 63 94 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); 73 101 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); 78 112 } 79 113 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); 90 120 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 */ 132 async_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 */ 173 void devman_exchange_end(async_exch_t *exch) 174 { 175 async_exchange_end(exch); 93 176 } 94 177 … … 96 179 int devman_driver_register(const char *name, async_client_conn_t conn) 97 180 { 98 int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING); 99 100 if (phone < 0) 101 return phone; 102 103 async_serialize_start(); 181 async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER); 104 182 105 183 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)); 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 109 189 if (retval != EOK) { 110 190 async_wait_for(req, NULL); 111 async_serialize_end(); 112 return -1; 191 return retval; 113 192 } 114 193 115 194 async_set_client_connection(conn); 116 195 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, conn, NULL); 198 devman_exchange_end(exch); 199 118 200 async_wait_for(req, &retval); 119 120 async_serialize_end();121 122 201 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 printf("Driver failed to send match id, error %d\n",150 ret);151 return ret;152 }153 154 link = link->next;155 }156 157 return ret;158 202 } 159 203 … … 163 207 * this driver task. 164 208 * 165 * @param name Name of the new function 166 * @param ftype Function type, fun_inner or fun_exposed 167 * @param match_ids Match IDs (should be empty for fun_exposed) 168 * @param devh Devman handle of the device 169 * @param funh Place to store handle of the new function 170 * 171 * @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 * 172 217 */ 173 218 int devman_add_function(const char *name, fun_type_t ftype, 174 219 match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh) 175 220 { 176 int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);177 int fun_handle;178 179 if (phone < 0)180 return phone;181 182 async_serialize_start();183 184 221 int match_count = list_count(&match_ids->ids); 222 async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER); 223 185 224 ipc_call_t answer; 186 187 aid_t req = async_send_3(phone, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype, 225 aid_t req = async_send_3(exch, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype, 188 226 devh, match_count, &answer); 189 190 sysarg_t retval = async_data_write_start(phone, name, str_size(name)); 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); 260 261 async_wait_for(req, &retval); 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 270 return retval; 271 } 272 273 int devman_add_device_to_category(devman_handle_t devman_handle, 274 const char *cat_name) 275 { 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_CATEGORY, 280 devman_handle, &answer); 281 sysarg_t retval = async_data_write_start(exch, cat_name, 282 str_size(cat_name)); 283 284 devman_exchange_end(exch); 285 191 286 if (retval != EOK) { 192 287 async_wait_for(req, NULL); 193 async_serialize_end(); 194 return retval; 195 } 196 197 devman_send_match_ids(phone, match_ids); 288 return retval; 289 } 198 290 199 291 async_wait_for(req, &retval); 200 201 async_serialize_end(); 202 203 if (retval == EOK) 204 fun_handle = (int) IPC_GET_ARG1(answer); 292 return retval; 293 } 294 295 async_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); 205 303 else 206 fun_handle = -1; 207 208 *funh = fun_handle; 209 210 return retval; 211 } 212 213 int devman_add_device_to_class(devman_handle_t devman_handle, 214 const char *class_name) 215 { 216 int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING); 217 218 if (phone < 0) 219 return phone; 220 221 async_serialize_start(); 304 sess = service_connect(mgmt, SERVICE_DEVMAN, 305 DEVMAN_CONNECT_TO_DEVICE, handle); 306 307 return sess; 308 } 309 310 /** Remove function from device. 311 * 312 * Request devman to remove function owned by this driver task. 313 * @param funh Devman handle of the function 314 * 315 * @return EOK on success or negative error code. 316 */ 317 int devman_remove_function(devman_handle_t funh) 318 { 319 async_exch_t *exch; 320 sysarg_t retval; 321 322 exch = devman_exchange_begin_blocking(DEVMAN_DRIVER); 323 retval = async_req_1_0(exch, DEVMAN_REMOVE_FUNCTION, (sysarg_t) funh); 324 devman_exchange_end(exch); 325 326 return (int) retval; 327 } 328 329 async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt, 330 devman_handle_t handle, unsigned int flags) 331 { 332 async_sess_t *sess; 333 334 if (flags & IPC_FLAG_BLOCKING) 335 sess = service_connect_blocking(mgmt, SERVICE_DEVMAN, 336 DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle); 337 else 338 sess = service_connect(mgmt, SERVICE_DEVMAN, 339 DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle); 340 341 return sess; 342 } 343 344 int devman_fun_get_handle(const char *pathname, devman_handle_t *handle, 345 unsigned int flags) 346 { 347 async_exch_t *exch; 348 349 if (flags & IPC_FLAG_BLOCKING) 350 exch = devman_exchange_begin_blocking(DEVMAN_CLIENT); 351 else { 352 exch = devman_exchange_begin(DEVMAN_CLIENT); 353 if (exch == NULL) 354 return ENOMEM; 355 } 356 222 357 ipc_call_t answer; 223 aid_t req = async_send_1(phone, DEVMAN_ADD_DEVICE_TO_CLASS, 224 devman_handle, &answer); 225 226 sysarg_t retval = async_data_write_start(phone, class_name, 227 str_size(class_name)); 358 aid_t req = async_send_2(exch, DEVMAN_DEVICE_GET_HANDLE, flags, 0, 359 &answer); 360 sysarg_t retval = async_data_write_start(exch, pathname, 361 str_size(pathname)); 362 363 devman_exchange_end(exch); 364 228 365 if (retval != EOK) { 229 366 async_wait_for(req, NULL); 230 async_serialize_end();231 367 return retval; 232 368 } 233 369 234 370 async_wait_for(req, &retval); 235 async_serialize_end();236 237 return retval;238 }239 240 void devman_hangup_phone(devman_interface_t iface)241 {242 switch (iface) {243 case DEVMAN_DRIVER:244 if (devman_phone_driver >= 0) {245 async_hangup(devman_phone_driver);246 devman_phone_driver = -1;247 }248 break;249 case DEVMAN_CLIENT:250 if (devman_phone_client >= 0) {251 async_hangup(devman_phone_client);252 devman_phone_client = -1;253 }254 break;255 default:256 break;257 }258 }259 260 int devman_device_connect(devman_handle_t handle, unsigned int flags)261 {262 int phone;263 264 if (flags & IPC_FLAG_BLOCKING) {265 phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,266 DEVMAN_CONNECT_TO_DEVICE, handle);267 } else {268 phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,269 DEVMAN_CONNECT_TO_DEVICE, handle);270 }271 272 return phone;273 }274 275 int devman_parent_device_connect(devman_handle_t handle, unsigned int flags)276 {277 int phone;278 279 if (flags & IPC_FLAG_BLOCKING) {280 phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,281 DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);282 } else {283 phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,284 DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);285 }286 287 return phone;288 }289 290 int devman_device_get_handle(const char *pathname, devman_handle_t *handle,291 unsigned int flags)292 {293 int phone = devman_get_phone(DEVMAN_CLIENT, flags);294 295 if (phone < 0)296 return phone;297 298 async_serialize_start();299 300 ipc_call_t answer;301 aid_t req = async_send_2(phone, DEVMAN_DEVICE_GET_HANDLE, flags, 0,302 &answer);303 304 sysarg_t retval = async_data_write_start(phone, pathname,305 str_size(pathname));306 if (retval != EOK) {307 async_wait_for(req, NULL);308 async_serialize_end();309 return retval;310 }311 312 async_wait_for(req, &retval);313 314 async_serialize_end();315 371 316 372 if (retval != EOK) { 317 373 if (handle != NULL) 318 374 *handle = (devman_handle_t) -1; 375 319 376 return retval; 320 377 } … … 326 383 } 327 384 385 static int devman_get_str_internal(sysarg_t method, sysarg_t arg1, char *buf, 386 size_t buf_size) 387 { 388 async_exch_t *exch; 389 ipc_call_t dreply; 390 size_t act_size; 391 sysarg_t dretval; 392 393 exch = devman_exchange_begin_blocking(LOC_PORT_CONSUMER); 394 395 ipc_call_t answer; 396 aid_t req = async_send_1(exch, method, arg1, &answer); 397 aid_t dreq = async_data_read(exch, buf, buf_size - 1, &dreply); 398 async_wait_for(dreq, &dretval); 399 400 devman_exchange_end(exch); 401 402 if (dretval != EOK) { 403 async_wait_for(req, NULL); 404 return dretval; 405 } 406 407 sysarg_t retval; 408 async_wait_for(req, &retval); 409 410 if (retval != EOK) 411 return retval; 412 413 act_size = IPC_GET_ARG2(dreply); 414 assert(act_size <= buf_size - 1); 415 buf[act_size] = '\0'; 416 417 return EOK; 418 } 419 420 int devman_fun_get_path(devman_handle_t handle, char *buf, size_t buf_size) 421 { 422 return devman_get_str_internal(DEVMAN_FUN_GET_PATH, handle, buf, 423 buf_size); 424 } 425 426 int devman_fun_get_name(devman_handle_t handle, char *buf, size_t buf_size) 427 { 428 return devman_get_str_internal(DEVMAN_FUN_GET_NAME, handle, buf, 429 buf_size); 430 } 431 432 static int devman_get_handles_once(sysarg_t method, sysarg_t arg1, 433 devman_handle_t *handle_buf, size_t buf_size, size_t *act_size) 434 { 435 async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_CLIENT); 436 437 ipc_call_t answer; 438 aid_t req = async_send_1(exch, method, arg1, &answer); 439 int rc = async_data_read_start(exch, handle_buf, buf_size); 440 441 devman_exchange_end(exch); 442 443 if (rc != EOK) { 444 async_wait_for(req, NULL); 445 return rc; 446 } 447 448 sysarg_t retval; 449 async_wait_for(req, &retval); 450 451 if (retval != EOK) { 452 return retval; 453 } 454 455 *act_size = IPC_GET_ARG1(answer); 456 return EOK; 457 } 458 459 /** Get list of handles. 460 * 461 * Returns an allocated array of handles. 462 * 463 * @param method IPC method 464 * @param arg1 IPC argument 1 465 * @param data Place to store pointer to array of handles 466 * @param count Place to store number of handles 467 * @return EOK on success or negative error code 468 */ 469 static int devman_get_handles_internal(sysarg_t method, sysarg_t arg1, 470 devman_handle_t **data, size_t *count) 471 { 472 devman_handle_t *handles; 473 size_t act_size; 474 size_t alloc_size; 475 int rc; 476 477 *data = NULL; 478 act_size = 0; /* silence warning */ 479 480 rc = devman_get_handles_once(method, arg1, NULL, 0, 481 &act_size); 482 if (rc != EOK) 483 return rc; 484 485 alloc_size = act_size; 486 handles = malloc(alloc_size); 487 if (handles == NULL) 488 return ENOMEM; 489 490 while (true) { 491 rc = devman_get_handles_once(method, arg1, handles, alloc_size, 492 &act_size); 493 if (rc != EOK) 494 return rc; 495 496 if (act_size <= alloc_size) 497 break; 498 499 alloc_size *= 2; 500 free(handles); 501 502 handles = malloc(alloc_size); 503 if (handles == NULL) 504 return ENOMEM; 505 } 506 507 *count = act_size / sizeof(devman_handle_t); 508 *data = handles; 509 return EOK; 510 } 511 512 int devman_fun_get_child(devman_handle_t funh, devman_handle_t *devh) 513 { 514 async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT); 515 if (exch == NULL) 516 return ENOMEM; 517 518 sysarg_t retval = async_req_1_1(exch, DEVMAN_FUN_GET_CHILD, 519 funh, devh); 520 521 devman_exchange_end(exch); 522 return (int) retval; 523 } 524 525 int devman_dev_get_functions(devman_handle_t devh, devman_handle_t **funcs, 526 size_t *count) 527 { 528 return devman_get_handles_internal(DEVMAN_DEV_GET_FUNCTIONS, 529 devh, funcs, count); 530 } 531 532 int devman_fun_sid_to_handle(service_id_t sid, devman_handle_t *handle) 533 { 534 async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT); 535 if (exch == NULL) 536 return ENOMEM; 537 538 sysarg_t retval = async_req_1_1(exch, DEVMAN_FUN_SID_TO_HANDLE, 539 sid, handle); 540 541 devman_exchange_end(exch); 542 return (int) retval; 543 } 328 544 329 545 /** @}
Note:
See TracChangeset
for help on using the changeset viewer.