Changes in uspace/lib/drv/generic/remote_usb.c [0918382f:7f80313] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/remote_usb.c
r0918382f r7f80313 35 35 36 36 #include <async.h> 37 #include <errno.h> 37 38 #include <macros.h> 38 #include <errno.h>39 #include <devman.h>40 39 41 40 #include "usb_iface.h" 42 41 #include "ddf/driver.h" 43 42 43 typedef enum { 44 IPC_M_USB_GET_MY_ADDRESS, 45 IPC_M_USB_GET_MY_INTERFACE, 46 IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, 47 } usb_iface_funcs_t; 44 48 45 usb_dev_session_t *usb_dev_connect(devman_handle_t handle) 49 /** Tell USB address assigned to device. 50 * @param exch Vaid IPC exchange 51 * @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) 46 57 { 47 return devman_device_connect(EXCHANGE_PARALLEL, handle, IPC_FLAG_BLOCKING); 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; 48 67 } 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 with54 // devman_parent_device_connect55 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 65 typedef enum {66 IPC_M_USB_GET_MY_INTERFACE,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,76 } usb_iface_funcs_t;77 68 78 69 /** Tell interface number given device can use. … … 94 85 } 95 86 96 /** Tell devman handle of the usb device function.87 /** Tell devman handle of device host controller. 97 88 * @param[in] exch IPC communication exchange 98 * @param[out] h andle devman handle of the HC used by the target device.89 * @param[out] hc_handle devman handle of the HC used by the target device. 99 90 * @return Error code. 100 91 */ 101 int usb_get_ my_device_handle(async_exch_t *exch, devman_handle_t *handle)92 int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle) 102 93 { 103 devman_handle_t h = 0; 94 if (!exch) 95 return EBADMEM; 96 devman_handle_t h; 104 97 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE), 105 IPC_M_USB_GET_ MY_DEVICE_HANDLE, &h);106 if (ret == EOK && h andle)107 *h andle = (devman_handle_t)h;98 IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h); 99 if (ret == EOK && hc_handle) 100 *hc_handle = (devman_handle_t)h; 108 101 return ret; 109 102 } 110 103 111 /** Reserve default USB address.112 * @param[in] exch IPC communication exchange113 * @param[in] speed Communication speed of the newly attached device114 * @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 104 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 static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 271 106 static void remote_usb_get_my_interface(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 static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 281 108 282 109 /** Remote USB interface operations. */ 283 static remote_iface_func_ptr_t remote_usb_iface_ops [] = { 110 static const remote_iface_func_ptr_t remote_usb_iface_ops [] = { 111 [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address, 284 112 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface, 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 [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle, 294 114 }; 295 115 296 116 /** Remote USB interface structure. 297 117 */ 298 remote_iface_t remote_usb_iface = {118 const remote_iface_t remote_usb_iface = { 299 119 .method_count = ARRAY_SIZE(remote_usb_iface_ops), 300 .methods = remote_usb_iface_ops ,120 .methods = remote_usb_iface_ops 301 121 }; 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 } 302 142 303 143 void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface, … … 320 160 } 321 161 322 void remote_usb_get_ my_device_handle(ddf_fun_t *fun, void *iface,162 void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface, 323 163 ipc_callid_t callid, ipc_call_t *call) 324 164 { 325 165 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 326 166 327 if (usb_iface->get_ my_device_handle == NULL) {167 if (usb_iface->get_hc_handle == NULL) { 328 168 async_answer_0(callid, ENOTSUP); 329 169 return; … … 331 171 332 172 devman_handle_t handle; 333 const int ret = usb_iface->get_ my_device_handle(fun, &handle);173 const int ret = usb_iface->get_hc_handle(fun, &handle); 334 174 if (ret != EOK) { 335 175 async_answer_0(callid, ret); … … 338 178 async_answer_1(callid, EOK, (sysarg_t) handle); 339 179 } 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_DATA2424 #undef _INIT_FROM_LOW_DATA2425 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 }608 180 /** 609 181 * @}
Note:
See TracChangeset
for help on using the changeset viewer.