Changes in uspace/lib/drv/generic/remote_usbhc.c [272f46f8:bbce2c2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/remote_usbhc.c
r272f46f8 rbbce2c2 1 1 /* 2 2 * Copyright (c) 2010-2011 Vojtech Horky 3 * Copyright (c) 2011 Jan Vesely4 3 * All rights reserved. 5 4 * … … 43 42 #define USB_MAX_PAYLOAD_SIZE 1020 44 43 45 /** IPC methods for communication with HC through DDF interface.46 *47 * Notes for async methods:48 *49 * Methods for sending data to device (OUT transactions)50 * - e.g. IPC_M_USBHC_INTERRUPT_OUT -51 * always use the same semantics:52 * - first, IPC call with given method is made53 * - argument #1 is target address54 * - argument #2 is target endpoint55 * - argument #3 is max packet size of the endpoint56 * - this call is immediately followed by IPC data write (from caller)57 * - the initial call (and the whole transaction) is answer after the58 * transaction is scheduled by the HC and acknowledged by the device59 * or immediately after error is detected60 * - the answer carries only the error code61 *62 * Methods for retrieving data from device (IN transactions)63 * - e.g. IPC_M_USBHC_INTERRUPT_IN -64 * also use the same semantics:65 * - first, IPC call with given method is made66 * - argument #1 is target address67 * - argument #2 is target endpoint68 * - this call is immediately followed by IPC data read (async version)69 * - the call is not answered until the device returns some data (or until70 * error occurs)71 *72 * Some special methods (NO-DATA transactions) do not send any data. These73 * might behave as both OUT or IN transactions because communication parts74 * where actual buffers are exchanged are omitted.75 **76 * For all these methods, wrap functions exists. Important rule: functions77 * for IN transactions have (as parameters) buffers where retrieved data78 * will be stored. These buffers must be already allocated and shall not be79 * touch until the transaction is completed80 * (e.g. not before calling usb_wait_for() with appropriate handle).81 * OUT transactions buffers can be freed immediately after call is dispatched82 * (i.e. after return from wrapping function).83 *84 */85 typedef enum {86 /** Asks for address assignment by host controller.87 * Answer:88 * - ELIMIT - host controller run out of address89 * - EOK - address assigned90 * Answer arguments:91 * - assigned address92 *93 * The address must be released by via IPC_M_USBHC_RELEASE_ADDRESS.94 */95 IPC_M_USBHC_REQUEST_ADDRESS,96 97 /** Bind USB address with devman handle.98 * Parameters:99 * - USB address100 * - devman handle101 * Answer:102 * - EOK - address binded103 * - ENOENT - address is not in use104 */105 IPC_M_USBHC_BIND_ADDRESS,106 107 /** Get handle binded with given USB address.108 * Parameters109 * - USB address110 * Answer:111 * - EOK - address binded, first parameter is the devman handle112 * - ENOENT - address is not in use at the moment113 */114 IPC_M_USBHC_GET_HANDLE_BY_ADDRESS,115 116 /** Release address in use.117 * Arguments:118 * - address to be released119 * Answer:120 * - ENOENT - address not in use121 * - EPERM - trying to release default USB address122 */123 IPC_M_USBHC_RELEASE_ADDRESS,124 125 /** Register endpoint attributes at host controller.126 * This is used to reserve portion of USB bandwidth.127 * When speed is invalid, speed of the device is used.128 * Parameters:129 * - USB address + endpoint number130 * - packed as ADDR << 16 + EP131 * - speed + transfer type + direction132 * - packed as ( SPEED << 8 + TYPE ) << 8 + DIR133 * - maximum packet size + interval (in milliseconds)134 * - packed as MPS << 16 + INT135 * Answer:136 * - EOK - reservation successful137 * - ELIMIT - not enough bandwidth to satisfy the request138 */139 IPC_M_USBHC_REGISTER_ENDPOINT,140 141 /** Revert endpoint registration.142 * Parameters:143 * - USB address144 * - endpoint number145 * - data direction146 * Answer:147 * - EOK - endpoint unregistered148 * - ENOENT - unknown endpoint149 */150 IPC_M_USBHC_UNREGISTER_ENDPOINT,151 152 /** Get data from device.153 * See explanation at usb_iface_funcs_t (IN transaction).154 */155 IPC_M_USBHC_READ,156 157 /** Send data to device.158 * See explanation at usb_iface_funcs_t (OUT transaction).159 */160 IPC_M_USBHC_WRITE,161 } usbhc_iface_funcs_t;162 163 int usbhc_request_address(async_exch_t *exch, usb_address_t *address,164 bool strict, usb_speed_t speed)165 {166 if (!exch || !address)167 return EINVAL;168 sysarg_t new_address;169 const int ret = async_req_4_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),170 IPC_M_USBHC_REQUEST_ADDRESS, *address, strict, speed, &new_address);171 if (ret == EOK)172 *address = (usb_address_t)new_address;173 return ret;174 }175 /*----------------------------------------------------------------------------*/176 int usbhc_bind_address(async_exch_t *exch, usb_address_t address,177 devman_handle_t handle)178 {179 if (!exch)180 return EINVAL;181 return async_req_3_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),182 IPC_M_USBHC_BIND_ADDRESS, address, handle);183 }184 /*----------------------------------------------------------------------------*/185 int usbhc_get_handle(async_exch_t *exch, usb_address_t address,186 devman_handle_t *handle)187 {188 if (!exch)189 return EINVAL;190 sysarg_t h;191 const int ret = async_req_2_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),192 IPC_M_USBHC_GET_HANDLE_BY_ADDRESS, address, &h);193 if (ret == EOK && handle)194 *handle = (devman_handle_t)h;195 return ret;196 }197 /*----------------------------------------------------------------------------*/198 int usbhc_release_address(async_exch_t *exch, usb_address_t address)199 {200 if (!exch)201 return EINVAL;202 return async_req_2_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),203 IPC_M_USBHC_RELEASE_ADDRESS, address);204 }205 /*----------------------------------------------------------------------------*/206 int usbhc_register_endpoint(async_exch_t *exch, usb_address_t address,207 usb_endpoint_t endpoint, usb_transfer_type_t type,208 usb_direction_t direction, size_t mps, unsigned interval)209 {210 if (!exch)211 return EINVAL;212 const usb_target_t target =213 {{ .address = address, .endpoint = endpoint }};214 #define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))215 216 return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),217 IPC_M_USBHC_REGISTER_ENDPOINT, target.packed,218 _PACK2(type, direction), _PACK2(mps, interval));219 220 #undef _PACK2221 }222 /*----------------------------------------------------------------------------*/223 int usbhc_unregister_endpoint(async_exch_t *exch, usb_address_t address,224 usb_endpoint_t endpoint, usb_direction_t direction)225 {226 if (!exch)227 return EINVAL;228 return async_req_4_0(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),229 IPC_M_USBHC_UNREGISTER_ENDPOINT, address, endpoint, direction);230 }231 /*----------------------------------------------------------------------------*/232 int usbhc_read(async_exch_t *exch, usb_address_t address,233 usb_endpoint_t endpoint, uint64_t setup, void *data, size_t size,234 size_t *rec_size)235 {236 if (size == 0 && setup == 0)237 return EOK;238 239 if (!exch)240 return EINVAL;241 const usb_target_t target =242 {{ .address = address, .endpoint = endpoint }};243 244 /* Make call identifying target USB device and type of transfer. */245 aid_t opening_request = async_send_4(exch,246 DEV_IFACE_ID(USBHC_DEV_IFACE),247 IPC_M_USBHC_READ, target.packed,248 (setup & UINT32_MAX), (setup >> 32), NULL);249 250 if (opening_request == 0) {251 return ENOMEM;252 }253 254 /* Retrieve the data. */255 ipc_call_t data_request_call;256 aid_t data_request =257 async_data_read(exch, data, size, &data_request_call);258 259 if (data_request == 0) {260 // FIXME: How to let the other side know that we want to abort?261 async_wait_for(opening_request, NULL);262 return ENOMEM;263 }264 265 /* Wait for the answer. */266 sysarg_t data_request_rc;267 sysarg_t opening_request_rc;268 async_wait_for(data_request, &data_request_rc);269 async_wait_for(opening_request, &opening_request_rc);270 271 if (data_request_rc != EOK) {272 /* Prefer the return code of the opening request. */273 if (opening_request_rc != EOK) {274 return (int) opening_request_rc;275 } else {276 return (int) data_request_rc;277 }278 }279 if (opening_request_rc != EOK) {280 return (int) opening_request_rc;281 }282 283 *rec_size = IPC_GET_ARG2(data_request_call);284 return EOK;285 }286 /*----------------------------------------------------------------------------*/287 int usbhc_write(async_exch_t *exch, usb_address_t address,288 usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size)289 {290 if (size == 0 && setup == 0)291 return EOK;292 293 if (!exch)294 return EINVAL;295 const usb_target_t target =296 {{ .address = address, .endpoint = endpoint }};297 298 aid_t opening_request = async_send_5(exch, DEV_IFACE_ID(USBHC_DEV_IFACE),299 IPC_M_USBHC_WRITE, target.packed, size,300 (setup & UINT32_MAX), (setup >> 32), NULL);301 302 if (opening_request == 0) {303 return ENOMEM;304 }305 306 /* Send the data if any. */307 if (size > 0) {308 const int ret = async_data_write_start(exch, data, size);309 if (ret != EOK) {310 async_wait_for(opening_request, NULL);311 return ret;312 }313 }314 315 /* Wait for the answer. */316 sysarg_t opening_request_rc;317 async_wait_for(opening_request, &opening_request_rc);318 319 return (int) opening_request_rc;320 }321 /*----------------------------------------------------------------------------*/322 323 44 static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 324 45 static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 325 static void remote_usbhc_ get_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);46 static void remote_usbhc_find_by_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 326 47 static void remote_usbhc_release_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 327 48 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); … … 334 55 static remote_iface_func_ptr_t remote_usbhc_iface_ops[] = { 335 56 [IPC_M_USBHC_REQUEST_ADDRESS] = remote_usbhc_request_address, 57 [IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address, 58 [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_find_by_address, 336 59 [IPC_M_USBHC_RELEASE_ADDRESS] = remote_usbhc_release_address, 337 [IPC_M_USBHC_BIND_ADDRESS] = remote_usbhc_bind_address,338 [IPC_M_USBHC_GET_HANDLE_BY_ADDRESS] = remote_usbhc_get_handle,339 60 340 61 [IPC_M_USBHC_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint, … … 357 78 ipc_callid_t data_caller; 358 79 void *buffer; 80 size_t size; 359 81 } async_transaction_t; 360 82 … … 381 103 trans->data_caller = 0; 382 104 trans->buffer = NULL; 105 trans->size = 0; 383 106 384 107 return trans; 385 108 } 386 /*----------------------------------------------------------------------------*/ 109 387 110 void remote_usbhc_request_address(ddf_fun_t *fun, void *iface, 388 111 ipc_callid_t callid, ipc_call_t *call) 389 112 { 390 const usbhc_iface_t *usb_iface =iface;113 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface; 391 114 392 115 if (!usb_iface->request_address) { … … 395 118 } 396 119 397 usb_address_t address = DEV_IPC_GET_ARG1(*call); 398 const bool strict = DEV_IPC_GET_ARG2(*call); 399 const usb_speed_t speed = DEV_IPC_GET_ARG3(*call); 400 401 const int rc = usb_iface->request_address(fun, &address, strict, speed); 120 usb_speed_t speed = DEV_IPC_GET_ARG1(*call); 121 122 usb_address_t address; 123 int rc = usb_iface->request_address(fun, speed, &address); 402 124 if (rc != EOK) { 403 125 async_answer_0(callid, rc); … … 406 128 } 407 129 } 408 /*----------------------------------------------------------------------------*/ 130 409 131 void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface, 410 132 ipc_callid_t callid, ipc_call_t *call) 411 133 { 412 const usbhc_iface_t *usb_iface =iface;134 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface; 413 135 414 136 if (!usb_iface->bind_address) { … … 417 139 } 418 140 419 const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call); 420 const devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call); 421 422 const int ret = usb_iface->bind_address(fun, address, handle); 423 async_answer_0(callid, ret); 424 } 425 /*----------------------------------------------------------------------------*/ 426 void remote_usbhc_get_handle(ddf_fun_t *fun, void *iface, 427 ipc_callid_t callid, ipc_call_t *call) 428 { 429 const usbhc_iface_t *usb_iface = iface; 430 431 if (!usb_iface->get_handle) { 432 async_answer_0(callid, ENOTSUP); 433 return; 434 } 435 436 const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call); 141 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call); 142 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call); 143 144 int rc = usb_iface->bind_address(fun, address, handle); 145 146 async_answer_0(callid, rc); 147 } 148 149 void remote_usbhc_find_by_address(ddf_fun_t *fun, void *iface, 150 ipc_callid_t callid, ipc_call_t *call) 151 { 152 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface; 153 154 if (!usb_iface->find_by_address) { 155 async_answer_0(callid, ENOTSUP); 156 return; 157 } 158 159 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call); 437 160 devman_handle_t handle; 438 const int ret = usb_iface->get_handle(fun, address, &handle);439 440 if (r et== EOK) {441 async_answer_1(callid, ret, handle);161 int rc = usb_iface->find_by_address(fun, address, &handle); 162 163 if (rc == EOK) { 164 async_answer_1(callid, EOK, handle); 442 165 } else { 443 async_answer_0(callid, r et);444 } 445 } 446 /*----------------------------------------------------------------------------*/ 166 async_answer_0(callid, rc); 167 } 168 } 169 447 170 void remote_usbhc_release_address(ddf_fun_t *fun, void *iface, 448 171 ipc_callid_t callid, ipc_call_t *call) 449 172 { 450 const usbhc_iface_t *usb_iface =iface;173 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface; 451 174 452 175 if (!usb_iface->release_address) { … … 455 178 } 456 179 457 const usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call); 458 459 const int ret = usb_iface->release_address(fun, address); 460 async_answer_0(callid, ret); 461 } 462 /*----------------------------------------------------------------------------*/ 180 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call); 181 182 int rc = usb_iface->release_address(fun, address); 183 184 async_answer_0(callid, rc); 185 } 186 187 463 188 static void callback_out(ddf_fun_t *fun, 464 189 int outcome, void *arg) 465 190 { 466 async_transaction_t *trans = arg;191 async_transaction_t *trans = (async_transaction_t *)arg; 467 192 468 193 async_answer_0(trans->caller, outcome); … … 470 195 async_transaction_destroy(trans); 471 196 } 472 /*----------------------------------------------------------------------------*/ 197 473 198 static void callback_in(ddf_fun_t *fun, 474 199 int outcome, size_t actual_size, void *arg) … … 485 210 } 486 211 212 trans->size = actual_size; 213 487 214 if (trans->data_caller) { 488 215 async_data_read_finalize(trans->data_caller, … … 494 221 async_transaction_destroy(trans); 495 222 } 496 /*----------------------------------------------------------------------------*/ 223 497 224 void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface, 498 225 ipc_callid_t callid, ipc_call_t *call) … … 506 233 507 234 #define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \ 508 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >>16)235 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16) 509 236 #define _INIT_FROM_LOW_DATA2(type, var, arg_no) \ 510 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff) 237 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 16) 238 #define _INIT_FROM_HIGH_DATA3(type, var, arg_no) \ 239 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) / (1 << 16) 240 #define _INIT_FROM_MIDDLE_DATA3(type, var, arg_no) \ 241 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) / (1 << 8)) % (1 << 8) 242 #define _INIT_FROM_LOW_DATA3(type, var, arg_no) \ 243 type var = (type) DEV_IPC_GET_ARG##arg_no(*call) % (1 << 8) 511 244 512 245 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) }; 513 246 514 _INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2); 515 _INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2); 247 _INIT_FROM_HIGH_DATA3(usb_speed_t, speed, 2); 248 _INIT_FROM_MIDDLE_DATA3(usb_transfer_type_t, transfer_type, 2); 249 _INIT_FROM_LOW_DATA3(usb_direction_t, direction, 2); 516 250 517 251 _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3); … … 520 254 #undef _INIT_FROM_HIGH_DATA2 521 255 #undef _INIT_FROM_LOW_DATA2 522 523 int rc = usb_iface->register_endpoint(fun, target.address, 256 #undef _INIT_FROM_HIGH_DATA3 257 #undef _INIT_FROM_MIDDLE_DATA3 258 #undef _INIT_FROM_LOW_DATA3 259 260 int rc = usb_iface->register_endpoint(fun, target.address, speed, 524 261 target.endpoint, transfer_type, direction, max_packet_size, interval); 525 262 … … 572 309 } 573 310 574 size_t size = 0; 575 if (!async_data_read_receive(&trans->data_caller, &size)) { 311 if (!async_data_read_receive(&trans->data_caller, &trans->size)) { 576 312 async_answer_0(callid, EPARTY); 577 313 return; 578 314 } 579 315 580 trans->buffer = malloc( size);316 trans->buffer = malloc(trans->size); 581 317 if (trans->buffer == NULL) { 582 318 async_answer_0(trans->data_caller, ENOMEM); … … 586 322 587 323 const int rc = hc_iface->read( 588 fun, target, setup, trans->buffer, size, callback_in, trans);324 fun, target, setup, trans->buffer, trans->size, callback_in, trans); 589 325 590 326 if (rc != EOK) { … … 594 330 } 595 331 } 596 /*----------------------------------------------------------------------------*/ 332 597 333 void remote_usbhc_write( 598 334 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) … … 621 357 } 622 358 623 size_t size = 0;624 359 if (data_buffer_len > 0) { 625 constint rc = async_data_write_accept(&trans->buffer, false,360 int rc = async_data_write_accept(&trans->buffer, false, 626 361 1, USB_MAX_PAYLOAD_SIZE, 627 0, & size);362 0, &trans->size); 628 363 629 364 if (rc != EOK) { … … 634 369 } 635 370 636 constint rc = hc_iface->write(637 fun, target, setup, trans->buffer, size, callback_out, trans);371 int rc = hc_iface->write( 372 fun, target, setup, trans->buffer, trans->size, callback_out, trans); 638 373 639 374 if (rc != EOK) { … … 642 377 } 643 378 } 379 380 644 381 /** 645 382 * @}
Note:
See TracChangeset
for help on using the changeset viewer.