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