Changes in uspace/lib/drv/generic/remote_usbhc.c [db51a6a6:25a179e] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/remote_usbhc.c
rdb51a6a6 r25a179e 1 1 /* 2 * Copyright (c) 2010 Vojtech Horky2 * Copyright (c) 2010-2011 Vojtech Horky 3 3 * Copyright (c) 2011 Jan Vesely 4 * Copyright (c) 2017 Ondrej Hlavaty5 4 * All rights reserved. 6 5 * … … 36 35 37 36 #include <async.h> 37 #include <errno.h> 38 #include <assert.h> 38 39 #include <macros.h> 39 #include <errno.h>40 #include <devman.h>41 40 42 41 #include "usbhc_iface.h" 43 42 #include "ddf/driver.h" 44 43 45 44 #define USB_MAX_PAYLOAD_SIZE 1020 45 46 /** IPC methods for communication with HC through DDF interface. 47 * 48 * Notes for async methods: 49 * 50 * Methods for sending data to device (OUT transactions) 51 * - e.g. IPC_M_USBHC_INTERRUPT_OUT - 52 * always use the same semantics: 53 * - first, IPC call with given method is made 54 * - argument #1 is target address 55 * - argument #2 is target endpoint 56 * - argument #3 is max packet size of the endpoint 57 * - this call is immediately followed by IPC data write (from caller) 58 * - the initial call (and the whole transaction) is answer after the 59 * transaction is scheduled by the HC and acknowledged by the device 60 * or immediately after error is detected 61 * - the answer carries only the error code 62 * 63 * Methods for retrieving data from device (IN transactions) 64 * - e.g. IPC_M_USBHC_INTERRUPT_IN - 65 * also use the same semantics: 66 * - first, IPC call with given method is made 67 * - argument #1 is target address 68 * - argument #2 is target endpoint 69 * - this call is immediately followed by IPC data read (async version) 70 * - the call is not answered until the device returns some data (or until 71 * error occurs) 72 * 73 * Some special methods (NO-DATA transactions) do not send any data. These 74 * might behave as both OUT or IN transactions because communication parts 75 * where actual buffers are exchanged are omitted. 76 ** 77 * For all these methods, wrap functions exists. Important rule: functions 78 * for IN transactions have (as parameters) buffers where retrieved data 79 * will be stored. These buffers must be already allocated and shall not be 80 * touch until the transaction is completed 81 * (e.g. not before calling usb_wait_for() with appropriate handle). 82 * OUT transactions buffers can be freed immediately after call is dispatched 83 * (i.e. after return from wrapping function). 84 * 85 */ 46 86 typedef enum { 47 IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, 48 IPC_M_USB_DEVICE_ENUMERATE, 49 IPC_M_USB_DEVICE_REMOVE, 50 IPC_M_USB_REGISTER_ENDPOINT, 51 IPC_M_USB_UNREGISTER_ENDPOINT, 52 IPC_M_USB_READ, 53 IPC_M_USB_WRITE, 87 /** Get data from device. 88 * See explanation at usb_iface_funcs_t (IN transaction). 89 */ 90 IPC_M_USBHC_READ, 91 92 /** Send data to device. 93 * See explanation at usb_iface_funcs_t (OUT transaction). 94 */ 95 IPC_M_USBHC_WRITE, 54 96 } usbhc_iface_funcs_t; 55 97 56 /** Reserve default USB address. 57 * @param[in] exch IPC communication exchange 58 * @return Error code. 59 */ 60 int usbhc_reserve_default_address(async_exch_t *exch) 98 int usbhc_read(async_exch_t *exch, usb_address_t address, 99 usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size, 100 size_t *rec_size) 61 101 { 62 102 if (!exch) 63 103 return EBADMEM; 64 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, true);65 }66 67 /** Release default USB address.68 *69 * @param[in] exch IPC communication exchange70 *71 * @return Error code.72 */73 int usbhc_release_default_address(async_exch_t *exch)74 {75 if (!exch)76 return EBADMEM;77 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, false);78 }79 80 /**81 * Trigger USB device enumeration82 *83 * @param[in] exch IPC communication exchange84 * @param[in] port Port number at which the device is attached85 * @param[in] speed Communication speed of the newly attached device86 *87 * @return Error code.88 */89 int usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed)90 {91 if (!exch)92 return EBADMEM;93 const int ret = async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),94 IPC_M_USB_DEVICE_ENUMERATE, port, speed);95 return ret;96 }97 98 /** Trigger USB device enumeration99 *100 * @param[in] exch IPC communication exchange101 * @param[in] handle Identifier of the device102 *103 * @return Error code.104 *105 */106 int usbhc_device_remove(async_exch_t *exch, unsigned port)107 {108 if (!exch)109 return EBADMEM;110 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),111 IPC_M_USB_DEVICE_REMOVE, port);112 }113 114 int usbhc_register_endpoint(async_exch_t *exch, usb_pipe_desc_t *pipe_desc,115 const usb_endpoint_descriptors_t *desc)116 {117 if (!exch)118 return EBADMEM;119 120 if (!desc)121 return EINVAL;122 123 aid_t opening_request = async_send_1(exch,124 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_REGISTER_ENDPOINT, NULL);125 126 if (opening_request == 0) {127 return ENOMEM;128 }129 130 int ret = async_data_write_start(exch, desc, sizeof(*desc));131 if (ret != EOK) {132 async_forget(opening_request);133 return ret;134 }135 136 /* Wait for the answer. */137 sysarg_t opening_request_rc;138 async_wait_for(opening_request, &opening_request_rc);139 140 if (opening_request_rc)141 return (int) opening_request_rc;142 143 usb_pipe_desc_t dest;144 ret = async_data_read_start(exch, &dest, sizeof(dest));145 if (ret != EOK) {146 return ret;147 }148 149 if (pipe_desc)150 *pipe_desc = dest;151 152 return EOK;153 }154 155 int usbhc_unregister_endpoint(async_exch_t *exch, const usb_pipe_desc_t *pipe_desc)156 {157 if (!exch)158 return EBADMEM;159 160 aid_t opening_request = async_send_1(exch,161 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_UNREGISTER_ENDPOINT, NULL);162 163 if (opening_request == 0) {164 return ENOMEM;165 }166 167 const int ret = async_data_write_start(exch, pipe_desc, sizeof(*pipe_desc));168 if (ret != EOK) {169 async_forget(opening_request);170 return ret;171 }172 173 /* Wait for the answer. */174 sysarg_t opening_request_rc;175 async_wait_for(opening_request, &opening_request_rc);176 177 return (int) opening_request_rc;178 }179 180 int usbhc_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup,181 void *data, size_t size, size_t *rec_size)182 {183 if (!exch)184 return EBADMEM;185 104 186 105 if (size == 0 && setup == 0) 187 106 return EOK; 188 107 108 const usb_target_t target = 109 {{ .address = address, .endpoint = endpoint }}; 110 189 111 /* Make call identifying target USB device and type of transfer. */ 190 112 aid_t opening_request = async_send_4(exch, 191 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_READ, endpoint, 113 DEV_IFACE_ID(USBHC_DEV_IFACE), 114 IPC_M_USBHC_READ, target.packed, 192 115 (setup & UINT32_MAX), (setup >> 32), NULL); 193 116 … … 208 131 209 132 /* Wait for the answer. */ 210 sysarg_t data_request_rc;211 sysarg_t opening_request_rc;133 int data_request_rc; 134 int opening_request_rc; 212 135 async_wait_for(data_request, &data_request_rc); 213 136 async_wait_for(opening_request, &opening_request_rc); … … 229 152 } 230 153 231 int usbhc_write(async_exch_t *exch, usb_ endpoint_t endpoint, uint64_t setup,232 const void *data, size_t size)154 int usbhc_write(async_exch_t *exch, usb_address_t address, 155 usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size) 233 156 { 234 157 if (!exch) … … 238 161 return EOK; 239 162 240 aid_t opening_request = async_send_5(exch, 241 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size, 163 const usb_target_t target = 164 {{ .address = address, .endpoint = endpoint }}; 165 166 aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 167 IPC_M_USBHC_WRITE, target.packed, size, 242 168 (setup & UINT32_MAX), (setup >> 32), NULL); 243 169 … … 256 182 257 183 /* Wait for the answer. */ 258 sysarg_t opening_request_rc;184 int opening_request_rc; 259 185 async_wait_for(opening_request, &opening_request_rc); 260 186 … … 262 188 } 263 189 264 static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 265 static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 266 static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 267 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 268 static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 269 static void remote_usbhc_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 270 static void remote_usbhc_write(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 271 272 /** Remote USB interface operations. */ 273 static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = { 274 [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation, 275 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate, 276 [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove, 277 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint, 278 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint, 279 [IPC_M_USB_READ] = remote_usbhc_read, 280 [IPC_M_USB_WRITE] = remote_usbhc_write, 190 static void remote_usbhc_read(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 191 static void remote_usbhc_write(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 192 193 /** Remote USB host controller interface operations. */ 194 static const remote_iface_func_ptr_t remote_usbhc_iface_ops[] = { 195 [IPC_M_USBHC_READ] = remote_usbhc_read, 196 [IPC_M_USBHC_WRITE] = remote_usbhc_write, 281 197 }; 282 198 283 /** Remote USB interface structure.199 /** Remote USB host controller interface structure. 284 200 */ 285 201 const remote_iface_t remote_usbhc_iface = { 286 202 .method_count = ARRAY_SIZE(remote_usbhc_iface_ops), 287 .methods = remote_usbhc_iface_ops ,203 .methods = remote_usbhc_iface_ops 288 204 }; 289 205 … … 294 210 } async_transaction_t; 295 211 296 void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface, 297 ipc_callid_t callid, ipc_call_t *call) 298 { 299 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 300 301 if (usbhc_iface->default_address_reservation == NULL) { 302 async_answer_0(callid, ENOTSUP); 303 return; 304 } 305 306 const bool reserve = IPC_GET_ARG2(*call); 307 const int ret = usbhc_iface->default_address_reservation(fun, reserve); 308 async_answer_0(callid, ret); 309 } 310 311 312 static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface, 313 ipc_callid_t callid, ipc_call_t *call) 314 { 315 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 316 317 if (usbhc_iface->device_enumerate == NULL) { 318 async_answer_0(callid, ENOTSUP); 319 return; 320 } 321 322 const unsigned port = DEV_IPC_GET_ARG1(*call); 323 usb_speed_t speed = DEV_IPC_GET_ARG2(*call); 324 const int ret = usbhc_iface->device_enumerate(fun, port, speed); 325 async_answer_0(callid, ret); 326 } 327 328 static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface, 329 ipc_callid_t callid, ipc_call_t *call) 330 { 331 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 332 333 if (usbhc_iface->device_remove == NULL) { 334 async_answer_0(callid, ENOTSUP); 335 return; 336 } 337 338 const unsigned port = DEV_IPC_GET_ARG1(*call); 339 const int ret = usbhc_iface->device_remove(fun, port); 340 async_answer_0(callid, ret); 341 } 342 343 static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface, 344 ipc_callid_t callid, ipc_call_t *call) 212 static void async_transaction_destroy(async_transaction_t *trans) 213 { 214 if (trans == NULL) 215 return; 216 217 if (trans->buffer != NULL) 218 free(trans->buffer); 219 220 free(trans); 221 } 222 223 static async_transaction_t *async_transaction_create(ipc_callid_t caller) 224 { 225 async_transaction_t *trans = malloc(sizeof(async_transaction_t)); 226 if (trans == NULL) { 227 return NULL; 228 } 229 230 trans->caller = caller; 231 trans->data_caller = 0; 232 trans->buffer = NULL; 233 234 return trans; 235 } 236 237 static void callback_out(int outcome, void *arg) 238 { 239 async_transaction_t *trans = arg; 240 241 async_answer_0(trans->caller, outcome); 242 243 async_transaction_destroy(trans); 244 } 245 246 static void callback_in(int outcome, size_t actual_size, void *arg) 247 { 248 async_transaction_t *trans = (async_transaction_t *)arg; 249 250 if (outcome != EOK) { 251 async_answer_0(trans->caller, outcome); 252 if (trans->data_caller) { 253 async_answer_0(trans->data_caller, EINTR); 254 } 255 async_transaction_destroy(trans); 256 return; 257 } 258 259 if (trans->data_caller) { 260 async_data_read_finalize(trans->data_caller, 261 trans->buffer, actual_size); 262 } 263 264 async_answer_0(trans->caller, EOK); 265 266 async_transaction_destroy(trans); 267 } 268 269 void remote_usbhc_read( 270 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 345 271 { 346 272 assert(fun); … … 348 274 assert(call); 349 275 350 const usbhc_iface_t * usbhc_iface = iface;351 352 if (! usbhc_iface->register_endpoint) {276 const usbhc_iface_t *hc_iface = iface; 277 278 if (!hc_iface->read) { 353 279 async_answer_0(callid, ENOTSUP); 354 280 return; 355 281 } 356 282 357 usb_endpoint_descriptors_t ep_desc; 358 ipc_callid_t data_callid; 359 size_t len; 360 361 if (!async_data_write_receive(&data_callid, &len) 362 || len != sizeof(ep_desc)) { 363 async_answer_0(callid, EINVAL); 364 return; 365 } 366 async_data_write_finalize(data_callid, &ep_desc, sizeof(ep_desc)); 367 368 usb_pipe_desc_t pipe_desc; 369 370 const int rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc); 371 async_answer_0(callid, rc); 372 373 if (!async_data_read_receive(&data_callid, &len) 374 || len != sizeof(pipe_desc)) { 375 return; 376 } 377 async_data_read_finalize(data_callid, &pipe_desc, sizeof(pipe_desc)); 378 } 379 380 static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface, 381 ipc_callid_t callid, ipc_call_t *call) 382 { 383 assert(fun); 384 assert(iface); 385 assert(call); 386 387 const usbhc_iface_t *usbhc_iface = iface; 388 389 if (!usbhc_iface->unregister_endpoint) { 390 async_answer_0(callid, ENOTSUP); 391 return; 392 } 393 394 usb_pipe_desc_t pipe_desc; 395 ipc_callid_t data_callid; 396 size_t len; 397 398 if (!async_data_write_receive(&data_callid, &len) 399 || len != sizeof(pipe_desc)) { 400 async_answer_0(callid, EINVAL); 401 return; 402 } 403 async_data_write_finalize(data_callid, &pipe_desc, sizeof(pipe_desc)); 404 405 const int rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc); 406 async_answer_0(callid, rc); 407 } 408 409 static void async_transaction_destroy(async_transaction_t *trans) 410 { 411 if (trans == NULL) { 412 return; 413 } 414 if (trans->buffer != NULL) { 415 free(trans->buffer); 416 } 417 418 free(trans); 419 } 420 421 static async_transaction_t *async_transaction_create(ipc_callid_t caller) 422 { 423 async_transaction_t *trans = malloc(sizeof(async_transaction_t)); 424 if (trans == NULL) { 425 return NULL; 426 } 427 428 trans->caller = caller; 429 trans->data_caller = 0; 430 trans->buffer = NULL; 431 432 return trans; 433 } 434 435 static int callback_out(void *arg, int error, size_t transferred_size) 436 { 437 async_transaction_t *trans = arg; 438 439 const int err = async_answer_0(trans->caller, error); 440 441 async_transaction_destroy(trans); 442 443 return err; 444 } 445 446 static int callback_in(void *arg, int error, size_t transferred_size) 447 { 448 async_transaction_t *trans = arg; 449 450 if (trans->data_caller) { 451 if (error == EOK) { 452 error = async_data_read_finalize(trans->data_caller, 453 trans->buffer, transferred_size); 454 } else { 455 async_answer_0(trans->data_caller, EINTR); 456 } 457 } 458 459 const int err = async_answer_0(trans->caller, error); 460 async_transaction_destroy(trans); 461 return err; 462 } 463 464 void remote_usbhc_read( 465 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 466 { 467 assert(fun); 468 assert(iface); 469 assert(call); 470 471 const usbhc_iface_t *usbhc_iface = iface; 472 473 if (!usbhc_iface->read) { 474 async_answer_0(callid, ENOTSUP); 475 return; 476 } 477 478 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call); 283 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) }; 479 284 const uint64_t setup = 480 285 ((uint64_t)DEV_IPC_GET_ARG2(*call)) | … … 490 295 if (!async_data_read_receive(&trans->data_caller, &size)) { 491 296 async_answer_0(callid, EPARTY); 492 async_transaction_destroy(trans);493 297 return; 494 298 } … … 502 306 } 503 307 504 const usb_target_t target = {{ 505 /* .address is initialized by read itself */ 506 .endpoint = ep, 507 }}; 508 509 const int rc = usbhc_iface->read( 308 const int rc = hc_iface->read( 510 309 fun, target, setup, trans->buffer, size, callback_in, trans); 511 310 … … 524 323 assert(call); 525 324 526 const usbhc_iface_t * usbhc_iface = iface;527 528 if (! usbhc_iface->write) {325 const usbhc_iface_t *hc_iface = iface; 326 327 if (!hc_iface->write) { 529 328 async_answer_0(callid, ENOTSUP); 530 329 return; 531 330 } 532 331 533 const usb_ endpoint_t ep = DEV_IPC_GET_ARG1(*call);332 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) }; 534 333 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call); 535 334 const uint64_t setup = … … 546 345 if (data_buffer_len > 0) { 547 346 const int rc = async_data_write_accept(&trans->buffer, false, 548 1, data_buffer_len, 0, &size); 347 1, USB_MAX_PAYLOAD_SIZE, 348 0, &size); 549 349 550 350 if (rc != EOK) { … … 555 355 } 556 356 557 const usb_target_t target = {{ 558 /* .address is initialized by write itself */ 559 .endpoint = ep, 560 /* streams are not given by the API call yet */ 561 .stream = 0, 562 }}; 563 564 const int rc = usbhc_iface->write( 357 const int rc = hc_iface->write( 565 358 fun, target, setup, trans->buffer, size, callback_out, trans); 566 359
Note:
See TracChangeset
for help on using the changeset viewer.