Changeset b4b534ac in mainline for uspace/lib/drv/generic/remote_usb.c
- Timestamp:
- 2016-07-22T08:24:47Z (9 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f76d2c2
- Parents:
- 5b18137 (diff), 8351f9a4 (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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/remote_usb.c
r5b18137 rb4b534ac 35 35 36 36 #include <async.h> 37 #include <macros.h> 37 38 #include <errno.h> 38 #include < macros.h>39 #include <devman.h> 39 40 40 41 #include "usb_iface.h" 41 42 #include "ddf/driver.h" 42 43 44 45 usb_dev_session_t *usb_dev_connect(devman_handle_t handle) 46 { 47 return devman_device_connect(handle, IPC_FLAG_BLOCKING); 48 } 49 50 usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev) 51 { 52 return devman_parent_device_connect(ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING); 53 } 54 55 void usb_dev_disconnect(usb_dev_session_t *sess) 56 { 57 if (sess) 58 async_hangup(sess); 59 } 60 43 61 typedef enum { 44 IPC_M_USB_GET_MY_ADDRESS,45 62 IPC_M_USB_GET_MY_INTERFACE, 46 IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, 63 IPC_M_USB_GET_MY_DEVICE_HANDLE, 64 IPC_M_USB_RESERVE_DEFAULT_ADDRESS, 65 IPC_M_USB_RELEASE_DEFAULT_ADDRESS, 66 IPC_M_USB_DEVICE_ENUMERATE, 67 IPC_M_USB_DEVICE_REMOVE, 68 IPC_M_USB_REGISTER_ENDPOINT, 69 IPC_M_USB_UNREGISTER_ENDPOINT, 70 IPC_M_USB_READ, 71 IPC_M_USB_WRITE, 47 72 } usb_iface_funcs_t; 48 49 /** Tell USB address assigned to device.50 * @param exch Vaid IPC exchange51 * @param address Pointer to address storage place.52 * @return Error code.53 *54 * Exch param is an open communication to device implementing usb_iface.55 */56 int usb_get_my_address(async_exch_t *exch, usb_address_t *address)57 {58 if (!exch)59 return EBADMEM;60 sysarg_t addr;61 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),62 IPC_M_USB_GET_MY_ADDRESS, &addr);63 64 if (ret == EOK && address != NULL)65 *address = (usb_address_t) addr;66 return ret;67 }68 73 69 74 /** Tell interface number given device can use. … … 85 90 } 86 91 87 /** Tell devman handle of device host controller.92 /** Tell devman handle of the usb device function. 88 93 * @param[in] exch IPC communication exchange 89 * @param[out] h c_handle devman handle of the HC used by the target device.94 * @param[out] handle devman handle of the HC used by the target device. 90 95 * @return Error code. 91 96 */ 92 int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle) 93 { 94 if (!exch) 95 return EBADMEM; 96 devman_handle_t h; 97 int usb_get_my_device_handle(async_exch_t *exch, devman_handle_t *handle) 98 { 99 devman_handle_t h = 0; 97 100 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE), 98 IPC_M_USB_GET_ HOST_CONTROLLER_HANDLE, &h);99 if (ret == EOK && h c_handle)100 *h c_handle = (devman_handle_t)h;101 IPC_M_USB_GET_MY_DEVICE_HANDLE, &h); 102 if (ret == EOK && handle) 103 *handle = (devman_handle_t)h; 101 104 return ret; 102 105 } 103 106 104 105 static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 107 /** Reserve default USB address. 108 * @param[in] exch IPC communication exchange 109 * @param[in] speed Communication speed of the newly attached device 110 * @return Error code. 111 */ 112 int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed) 113 { 114 if (!exch) 115 return EBADMEM; 116 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 117 IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed); 118 } 119 120 /** Release default USB address. 121 * @param[in] exch IPC communication exchange 122 * @return Error code. 123 */ 124 int usb_release_default_address(async_exch_t *exch) 125 { 126 if (!exch) 127 return EBADMEM; 128 return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 129 IPC_M_USB_RELEASE_DEFAULT_ADDRESS); 130 } 131 132 /** Trigger USB device enumeration 133 * @param[in] exch IPC communication exchange 134 * @param[out] handle Identifier of the newly added device (if successful) 135 * @return Error code. 136 */ 137 int usb_device_enumerate(async_exch_t *exch, unsigned port) 138 { 139 if (!exch) 140 return EBADMEM; 141 const int ret = async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 142 IPC_M_USB_DEVICE_ENUMERATE, port); 143 return ret; 144 } 145 146 /** Trigger USB device enumeration 147 * @param[in] exch IPC communication exchange 148 * @param[in] handle Identifier of the device 149 * @return Error code. 150 */ 151 int usb_device_remove(async_exch_t *exch, unsigned port) 152 { 153 if (!exch) 154 return EBADMEM; 155 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 156 IPC_M_USB_DEVICE_REMOVE, port); 157 } 158 159 int static_assert[sizeof(sysarg_t) >= 4 ? 1 : -1]; 160 typedef union { 161 uint8_t arr[sizeof(sysarg_t)]; 162 sysarg_t arg; 163 } pack8_t; 164 165 int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 166 usb_transfer_type_t type, usb_direction_t direction, 167 size_t mps, unsigned packets, unsigned interval) 168 { 169 if (!exch) 170 return EBADMEM; 171 pack8_t pack; 172 pack.arr[0] = type; 173 pack.arr[1] = direction; 174 pack.arr[2] = interval; 175 pack.arr[3] = packets; 176 177 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 178 IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps); 179 180 } 181 182 int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 183 usb_direction_t direction) 184 { 185 if (!exch) 186 return EBADMEM; 187 return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 188 IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction); 189 } 190 191 int usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup, 192 void *data, size_t size, size_t *rec_size) 193 { 194 if (!exch) 195 return EBADMEM; 196 197 if (size == 0 && setup == 0) 198 return EOK; 199 200 /* Make call identifying target USB device and type of transfer. */ 201 aid_t opening_request = async_send_4(exch, 202 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint, 203 (setup & UINT32_MAX), (setup >> 32), NULL); 204 205 if (opening_request == 0) { 206 return ENOMEM; 207 } 208 209 /* Retrieve the data. */ 210 ipc_call_t data_request_call; 211 aid_t data_request = 212 async_data_read(exch, data, size, &data_request_call); 213 214 if (data_request == 0) { 215 // FIXME: How to let the other side know that we want to abort? 216 async_forget(opening_request); 217 return ENOMEM; 218 } 219 220 /* Wait for the answer. */ 221 sysarg_t data_request_rc; 222 sysarg_t opening_request_rc; 223 async_wait_for(data_request, &data_request_rc); 224 async_wait_for(opening_request, &opening_request_rc); 225 226 if (data_request_rc != EOK) { 227 /* Prefer the return code of the opening request. */ 228 if (opening_request_rc != EOK) { 229 return (int) opening_request_rc; 230 } else { 231 return (int) data_request_rc; 232 } 233 } 234 if (opening_request_rc != EOK) { 235 return (int) opening_request_rc; 236 } 237 238 *rec_size = IPC_GET_ARG2(data_request_call); 239 return EOK; 240 } 241 242 int usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup, 243 const void *data, size_t size) 244 { 245 if (!exch) 246 return EBADMEM; 247 248 if (size == 0 && setup == 0) 249 return EOK; 250 251 aid_t opening_request = async_send_5(exch, 252 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size, 253 (setup & UINT32_MAX), (setup >> 32), NULL); 254 255 if (opening_request == 0) { 256 return ENOMEM; 257 } 258 259 /* Send the data if any. */ 260 if (size > 0) { 261 const int ret = async_data_write_start(exch, data, size); 262 if (ret != EOK) { 263 async_forget(opening_request); 264 return ret; 265 } 266 } 267 268 /* Wait for the answer. */ 269 sysarg_t opening_request_rc; 270 async_wait_for(opening_request, &opening_request_rc); 271 272 return (int) opening_request_rc; 273 } 274 106 275 static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 107 static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 276 static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 277 static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 278 static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 279 static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 280 static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 281 static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 282 static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 283 static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 284 static void remote_usb_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 108 285 109 286 /** Remote USB interface operations. */ 110 287 static const remote_iface_func_ptr_t remote_usb_iface_ops [] = { 111 [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,112 288 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface, 113 [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle, 289 [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle, 290 [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address, 291 [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address, 292 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate, 293 [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove, 294 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint, 295 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint, 296 [IPC_M_USB_READ] = remote_usb_read, 297 [IPC_M_USB_WRITE] = remote_usb_write, 114 298 }; 115 299 … … 118 302 const remote_iface_t remote_usb_iface = { 119 303 .method_count = ARRAY_SIZE(remote_usb_iface_ops), 120 .methods = remote_usb_iface_ops 304 .methods = remote_usb_iface_ops, 121 305 }; 122 123 124 void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,125 ipc_callid_t callid, ipc_call_t *call)126 {127 const usb_iface_t *usb_iface = (usb_iface_t *) iface;128 129 if (usb_iface->get_my_address == NULL) {130 async_answer_0(callid, ENOTSUP);131 return;132 }133 134 usb_address_t address;135 const int ret = usb_iface->get_my_address(fun, &address);136 if (ret != EOK) {137 async_answer_0(callid, ret);138 } else {139 async_answer_1(callid, EOK, address);140 }141 }142 306 143 307 void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface, … … 160 324 } 161 325 162 void remote_usb_get_ hc_handle(ddf_fun_t *fun, void *iface,326 void remote_usb_get_my_device_handle(ddf_fun_t *fun, void *iface, 163 327 ipc_callid_t callid, ipc_call_t *call) 164 328 { 165 329 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 166 330 167 if (usb_iface->get_ hc_handle == NULL) {331 if (usb_iface->get_my_device_handle == NULL) { 168 332 async_answer_0(callid, ENOTSUP); 169 333 return; … … 171 335 172 336 devman_handle_t handle; 173 const int ret = usb_iface->get_ hc_handle(fun, &handle);337 const int ret = usb_iface->get_my_device_handle(fun, &handle); 174 338 if (ret != EOK) { 175 339 async_answer_0(callid, ret); … … 178 342 async_answer_1(callid, EOK, (sysarg_t) handle); 179 343 } 344 345 void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface, 346 ipc_callid_t callid, ipc_call_t *call) 347 { 348 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 349 350 if (usb_iface->reserve_default_address == NULL) { 351 async_answer_0(callid, ENOTSUP); 352 return; 353 } 354 355 usb_speed_t speed = DEV_IPC_GET_ARG1(*call); 356 const int ret = usb_iface->reserve_default_address(fun, speed); 357 async_answer_0(callid, ret); 358 } 359 360 void remote_usb_release_default_address(ddf_fun_t *fun, void *iface, 361 ipc_callid_t callid, ipc_call_t *call) 362 { 363 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 364 365 if (usb_iface->release_default_address == NULL) { 366 async_answer_0(callid, ENOTSUP); 367 return; 368 } 369 370 const int ret = usb_iface->release_default_address(fun); 371 async_answer_0(callid, ret); 372 } 373 374 static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface, 375 ipc_callid_t callid, ipc_call_t *call) 376 { 377 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 378 379 if (usb_iface->device_enumerate == NULL) { 380 async_answer_0(callid, ENOTSUP); 381 return; 382 } 383 384 const unsigned port = DEV_IPC_GET_ARG1(*call); 385 const int ret = usb_iface->device_enumerate(fun, port); 386 async_answer_0(callid, ret); 387 } 388 389 static void remote_usb_device_remove(ddf_fun_t *fun, void *iface, 390 ipc_callid_t callid, ipc_call_t *call) 391 { 392 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 393 394 if (usb_iface->device_remove == NULL) { 395 async_answer_0(callid, ENOTSUP); 396 return; 397 } 398 399 const unsigned port = DEV_IPC_GET_ARG1(*call); 400 const int ret = usb_iface->device_remove(fun, port); 401 async_answer_0(callid, ret); 402 } 403 404 static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface, 405 ipc_callid_t callid, ipc_call_t *call) 406 { 407 usb_iface_t *usb_iface = (usb_iface_t *) iface; 408 409 if (!usb_iface->register_endpoint) { 410 async_answer_0(callid, ENOTSUP); 411 return; 412 } 413 414 const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call); 415 const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)}; 416 const size_t max_packet_size = DEV_IPC_GET_ARG3(*call); 417 418 const usb_transfer_type_t transfer_type = pack.arr[0]; 419 const usb_direction_t direction = pack.arr[1]; 420 unsigned packets = pack.arr[2]; 421 unsigned interval = pack.arr[3]; 422 423 const int ret = usb_iface->register_endpoint(fun, endpoint, 424 transfer_type, direction, max_packet_size, packets, interval); 425 426 async_answer_0(callid, ret); 427 } 428 429 static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface, 430 ipc_callid_t callid, ipc_call_t *call) 431 { 432 usb_iface_t *usb_iface = (usb_iface_t *) iface; 433 434 if (!usb_iface->unregister_endpoint) { 435 async_answer_0(callid, ENOTSUP); 436 return; 437 } 438 439 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call); 440 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call); 441 442 int rc = usb_iface->unregister_endpoint(fun, endpoint, direction); 443 444 async_answer_0(callid, rc); 445 } 446 447 typedef struct { 448 ipc_callid_t caller; 449 ipc_callid_t data_caller; 450 void *buffer; 451 } async_transaction_t; 452 453 static void async_transaction_destroy(async_transaction_t *trans) 454 { 455 if (trans == NULL) { 456 return; 457 } 458 if (trans->buffer != NULL) { 459 free(trans->buffer); 460 } 461 462 free(trans); 463 } 464 465 static async_transaction_t *async_transaction_create(ipc_callid_t caller) 466 { 467 async_transaction_t *trans = malloc(sizeof(async_transaction_t)); 468 if (trans == NULL) { 469 return NULL; 470 } 471 472 trans->caller = caller; 473 trans->data_caller = 0; 474 trans->buffer = NULL; 475 476 return trans; 477 } 478 479 static void callback_out(int outcome, void *arg) 480 { 481 async_transaction_t *trans = arg; 482 483 async_answer_0(trans->caller, outcome); 484 485 async_transaction_destroy(trans); 486 } 487 488 static void callback_in(int outcome, size_t actual_size, void *arg) 489 { 490 async_transaction_t *trans = (async_transaction_t *)arg; 491 492 if (outcome != EOK) { 493 async_answer_0(trans->caller, outcome); 494 if (trans->data_caller) { 495 async_answer_0(trans->data_caller, EINTR); 496 } 497 async_transaction_destroy(trans); 498 return; 499 } 500 501 if (trans->data_caller) { 502 async_data_read_finalize(trans->data_caller, 503 trans->buffer, actual_size); 504 } 505 506 async_answer_0(trans->caller, EOK); 507 508 async_transaction_destroy(trans); 509 } 510 511 void remote_usb_read( 512 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 513 { 514 assert(fun); 515 assert(iface); 516 assert(call); 517 518 const usb_iface_t *usb_iface = iface; 519 520 if (!usb_iface->read) { 521 async_answer_0(callid, ENOTSUP); 522 return; 523 } 524 525 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call); 526 const uint64_t setup = 527 ((uint64_t)DEV_IPC_GET_ARG2(*call)) | 528 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32); 529 530 async_transaction_t *trans = async_transaction_create(callid); 531 if (trans == NULL) { 532 async_answer_0(callid, ENOMEM); 533 return; 534 } 535 536 size_t size = 0; 537 if (!async_data_read_receive(&trans->data_caller, &size)) { 538 async_answer_0(callid, EPARTY); 539 return; 540 } 541 542 trans->buffer = malloc(size); 543 if (trans->buffer == NULL) { 544 async_answer_0(trans->data_caller, ENOMEM); 545 async_answer_0(callid, ENOMEM); 546 async_transaction_destroy(trans); 547 } 548 549 const int rc = usb_iface->read( 550 fun, ep, setup, trans->buffer, size, callback_in, trans); 551 552 if (rc != EOK) { 553 async_answer_0(trans->data_caller, rc); 554 async_answer_0(callid, rc); 555 async_transaction_destroy(trans); 556 } 557 } 558 559 void remote_usb_write( 560 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 561 { 562 assert(fun); 563 assert(iface); 564 assert(call); 565 566 const usb_iface_t *usb_iface = iface; 567 568 if (!usb_iface->write) { 569 async_answer_0(callid, ENOTSUP); 570 return; 571 } 572 573 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call); 574 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call); 575 const uint64_t setup = 576 ((uint64_t)DEV_IPC_GET_ARG3(*call)) | 577 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32); 578 579 async_transaction_t *trans = async_transaction_create(callid); 580 if (trans == NULL) { 581 async_answer_0(callid, ENOMEM); 582 return; 583 } 584 585 size_t size = 0; 586 if (data_buffer_len > 0) { 587 const int rc = async_data_write_accept(&trans->buffer, false, 588 1, data_buffer_len, 0, &size); 589 590 if (rc != EOK) { 591 async_answer_0(callid, rc); 592 async_transaction_destroy(trans); 593 return; 594 } 595 } 596 597 const int rc = usb_iface->write( 598 fun, ep, setup, trans->buffer, size, callback_out, trans); 599 600 if (rc != EOK) { 601 async_answer_0(callid, rc); 602 async_transaction_destroy(trans); 603 } 604 } 180 605 /** 181 606 * @}
Note:
See TracChangeset
for help on using the changeset viewer.