Changes in uspace/lib/drv/generic/remote_usb.c [4e732f1a:7f80313] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/remote_usb.c
r4e732f1a 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 static_assert[sizeof(sysarg_t) >= 4 ? 1 : -1]; 164 typedef union { 165 uint8_t arr[sizeof(sysarg_t)]; 166 sysarg_t arg; 167 } pack8_t; 168 169 int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 170 usb_transfer_type_t type, usb_direction_t direction, 171 size_t mps, unsigned packets, unsigned interval) 172 { 173 if (!exch) 174 return EBADMEM; 175 pack8_t pack; 176 pack.arr[0] = type; 177 pack.arr[1] = direction; 178 pack.arr[2] = interval; 179 pack.arr[3] = packets; 180 181 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 182 IPC_M_USB_REGISTER_ENDPOINT, endpoint, pack.arg, mps); 183 184 } 185 186 int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint, 187 usb_direction_t direction) 188 { 189 if (!exch) 190 return EBADMEM; 191 return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE), 192 IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction); 193 } 194 195 int usb_read(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup, 196 void *data, size_t size, size_t *rec_size) 197 { 198 if (!exch) 199 return EBADMEM; 200 201 if (size == 0 && setup == 0) 202 return EOK; 203 204 /* Make call identifying target USB device and type of transfer. */ 205 aid_t opening_request = async_send_4(exch, 206 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_READ, endpoint, 207 (setup & UINT32_MAX), (setup >> 32), NULL); 208 209 if (opening_request == 0) { 210 return ENOMEM; 211 } 212 213 /* Retrieve the data. */ 214 ipc_call_t data_request_call; 215 aid_t data_request = 216 async_data_read(exch, data, size, &data_request_call); 217 218 if (data_request == 0) { 219 // FIXME: How to let the other side know that we want to abort? 220 async_forget(opening_request); 221 return ENOMEM; 222 } 223 224 /* Wait for the answer. */ 225 sysarg_t data_request_rc; 226 sysarg_t opening_request_rc; 227 async_wait_for(data_request, &data_request_rc); 228 async_wait_for(opening_request, &opening_request_rc); 229 230 if (data_request_rc != EOK) { 231 /* Prefer the return code of the opening request. */ 232 if (opening_request_rc != EOK) { 233 return (int) opening_request_rc; 234 } else { 235 return (int) data_request_rc; 236 } 237 } 238 if (opening_request_rc != EOK) { 239 return (int) opening_request_rc; 240 } 241 242 *rec_size = IPC_GET_ARG2(data_request_call); 243 return EOK; 244 } 245 246 int usb_write(async_exch_t *exch, usb_endpoint_t endpoint, uint64_t setup, 247 const void *data, size_t size) 248 { 249 if (!exch) 250 return EBADMEM; 251 252 if (size == 0 && setup == 0) 253 return EOK; 254 255 aid_t opening_request = async_send_5(exch, 256 DEV_IFACE_ID(USB_DEV_IFACE), IPC_M_USB_WRITE, endpoint, size, 257 (setup & UINT32_MAX), (setup >> 32), NULL); 258 259 if (opening_request == 0) { 260 return ENOMEM; 261 } 262 263 /* Send the data if any. */ 264 if (size > 0) { 265 const int ret = async_data_write_start(exch, data, size); 266 if (ret != EOK) { 267 async_forget(opening_request); 268 return ret; 269 } 270 } 271 272 /* Wait for the answer. */ 273 sysarg_t opening_request_rc; 274 async_wait_for(opening_request, &opening_request_rc); 275 276 return (int) opening_request_rc; 277 } 278 105 static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 279 106 static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 280 static void remote_usb_get_my_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 281 static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 282 static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 283 static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 284 static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 285 static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 286 static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 287 static void remote_usb_read(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 288 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 *); 289 108 290 109 /** Remote USB interface operations. */ 291 110 static const remote_iface_func_ptr_t remote_usb_iface_ops [] = { 111 [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address, 292 112 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface, 293 [IPC_M_USB_GET_MY_DEVICE_HANDLE] = remote_usb_get_my_device_handle, 294 [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address, 295 [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address, 296 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate, 297 [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove, 298 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint, 299 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint, 300 [IPC_M_USB_READ] = remote_usb_read, 301 [IPC_M_USB_WRITE] = remote_usb_write, 113 [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle, 302 114 }; 303 115 … … 306 118 const remote_iface_t remote_usb_iface = { 307 119 .method_count = ARRAY_SIZE(remote_usb_iface_ops), 308 .methods = remote_usb_iface_ops ,120 .methods = remote_usb_iface_ops 309 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 } 310 142 311 143 void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface, … … 328 160 } 329 161 330 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, 331 163 ipc_callid_t callid, ipc_call_t *call) 332 164 { 333 165 const usb_iface_t *usb_iface = (usb_iface_t *) iface; 334 166 335 if (usb_iface->get_ my_device_handle == NULL) {167 if (usb_iface->get_hc_handle == NULL) { 336 168 async_answer_0(callid, ENOTSUP); 337 169 return; … … 339 171 340 172 devman_handle_t handle; 341 const int ret = usb_iface->get_ my_device_handle(fun, &handle);173 const int ret = usb_iface->get_hc_handle(fun, &handle); 342 174 if (ret != EOK) { 343 175 async_answer_0(callid, ret); … … 346 178 async_answer_1(callid, EOK, (sysarg_t) handle); 347 179 } 348 349 void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,350 ipc_callid_t callid, ipc_call_t *call)351 {352 const usb_iface_t *usb_iface = (usb_iface_t *) iface;353 354 if (usb_iface->reserve_default_address == NULL) {355 async_answer_0(callid, ENOTSUP);356 return;357 }358 359 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);360 const int ret = usb_iface->reserve_default_address(fun, speed);361 async_answer_0(callid, ret);362 }363 364 void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,365 ipc_callid_t callid, ipc_call_t *call)366 {367 const usb_iface_t *usb_iface = (usb_iface_t *) iface;368 369 if (usb_iface->release_default_address == NULL) {370 async_answer_0(callid, ENOTSUP);371 return;372 }373 374 const int ret = usb_iface->release_default_address(fun);375 async_answer_0(callid, ret);376 }377 378 static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,379 ipc_callid_t callid, ipc_call_t *call)380 {381 const usb_iface_t *usb_iface = (usb_iface_t *) iface;382 383 if (usb_iface->device_enumerate == NULL) {384 async_answer_0(callid, ENOTSUP);385 return;386 }387 388 const unsigned port = DEV_IPC_GET_ARG1(*call);389 const int ret = usb_iface->device_enumerate(fun, port);390 async_answer_0(callid, ret);391 }392 393 static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,394 ipc_callid_t callid, ipc_call_t *call)395 {396 const usb_iface_t *usb_iface = (usb_iface_t *) iface;397 398 if (usb_iface->device_remove == NULL) {399 async_answer_0(callid, ENOTSUP);400 return;401 }402 403 const unsigned port = DEV_IPC_GET_ARG1(*call);404 const int ret = usb_iface->device_remove(fun, port);405 async_answer_0(callid, ret);406 }407 408 static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,409 ipc_callid_t callid, ipc_call_t *call)410 {411 usb_iface_t *usb_iface = (usb_iface_t *) iface;412 413 if (!usb_iface->register_endpoint) {414 async_answer_0(callid, ENOTSUP);415 return;416 }417 418 const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);419 const pack8_t pack = { .arg = DEV_IPC_GET_ARG2(*call)};420 const size_t max_packet_size = DEV_IPC_GET_ARG3(*call);421 422 const usb_transfer_type_t transfer_type = pack.arr[0];423 const usb_direction_t direction = pack.arr[1];424 unsigned packets = pack.arr[2];425 unsigned interval = pack.arr[3];426 427 const int ret = usb_iface->register_endpoint(fun, endpoint,428 transfer_type, direction, max_packet_size, packets, interval);429 430 async_answer_0(callid, ret);431 }432 433 static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,434 ipc_callid_t callid, ipc_call_t *call)435 {436 usb_iface_t *usb_iface = (usb_iface_t *) iface;437 438 if (!usb_iface->unregister_endpoint) {439 async_answer_0(callid, ENOTSUP);440 return;441 }442 443 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);444 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);445 446 int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);447 448 async_answer_0(callid, rc);449 }450 451 typedef struct {452 ipc_callid_t caller;453 ipc_callid_t data_caller;454 void *buffer;455 } async_transaction_t;456 457 static void async_transaction_destroy(async_transaction_t *trans)458 {459 if (trans == NULL) {460 return;461 }462 if (trans->buffer != NULL) {463 free(trans->buffer);464 }465 466 free(trans);467 }468 469 static async_transaction_t *async_transaction_create(ipc_callid_t caller)470 {471 async_transaction_t *trans = malloc(sizeof(async_transaction_t));472 if (trans == NULL) {473 return NULL;474 }475 476 trans->caller = caller;477 trans->data_caller = 0;478 trans->buffer = NULL;479 480 return trans;481 }482 483 static void callback_out(int outcome, void *arg)484 {485 async_transaction_t *trans = arg;486 487 async_answer_0(trans->caller, outcome);488 489 async_transaction_destroy(trans);490 }491 492 static void callback_in(int outcome, size_t actual_size, void *arg)493 {494 async_transaction_t *trans = (async_transaction_t *)arg;495 496 if (outcome != EOK) {497 async_answer_0(trans->caller, outcome);498 if (trans->data_caller) {499 async_answer_0(trans->data_caller, EINTR);500 }501 async_transaction_destroy(trans);502 return;503 }504 505 if (trans->data_caller) {506 async_data_read_finalize(trans->data_caller,507 trans->buffer, actual_size);508 }509 510 async_answer_0(trans->caller, EOK);511 512 async_transaction_destroy(trans);513 }514 515 void remote_usb_read(516 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)517 {518 assert(fun);519 assert(iface);520 assert(call);521 522 const usb_iface_t *usb_iface = iface;523 524 if (!usb_iface->read) {525 async_answer_0(callid, ENOTSUP);526 return;527 }528 529 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);530 const uint64_t setup =531 ((uint64_t)DEV_IPC_GET_ARG2(*call)) |532 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32);533 534 async_transaction_t *trans = async_transaction_create(callid);535 if (trans == NULL) {536 async_answer_0(callid, ENOMEM);537 return;538 }539 540 size_t size = 0;541 if (!async_data_read_receive(&trans->data_caller, &size)) {542 async_answer_0(callid, EPARTY);543 return;544 }545 546 trans->buffer = malloc(size);547 if (trans->buffer == NULL) {548 async_answer_0(trans->data_caller, ENOMEM);549 async_answer_0(callid, ENOMEM);550 async_transaction_destroy(trans);551 }552 553 const int rc = usb_iface->read(554 fun, ep, setup, trans->buffer, size, callback_in, trans);555 556 if (rc != EOK) {557 async_answer_0(trans->data_caller, rc);558 async_answer_0(callid, rc);559 async_transaction_destroy(trans);560 }561 }562 563 void remote_usb_write(564 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call)565 {566 assert(fun);567 assert(iface);568 assert(call);569 570 const usb_iface_t *usb_iface = iface;571 572 if (!usb_iface->write) {573 async_answer_0(callid, ENOTSUP);574 return;575 }576 577 const usb_endpoint_t ep = DEV_IPC_GET_ARG1(*call);578 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call);579 const uint64_t setup =580 ((uint64_t)DEV_IPC_GET_ARG3(*call)) |581 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32);582 583 async_transaction_t *trans = async_transaction_create(callid);584 if (trans == NULL) {585 async_answer_0(callid, ENOMEM);586 return;587 }588 589 size_t size = 0;590 if (data_buffer_len > 0) {591 const int rc = async_data_write_accept(&trans->buffer, false,592 1, data_buffer_len, 0, &size);593 594 if (rc != EOK) {595 async_answer_0(callid, rc);596 async_transaction_destroy(trans);597 return;598 }599 }600 601 const int rc = usb_iface->write(602 fun, ep, setup, trans->buffer, size, callback_out, trans);603 604 if (rc != EOK) {605 async_answer_0(callid, rc);606 async_transaction_destroy(trans);607 }608 }609 180 /** 610 181 * @}
Note:
See TracChangeset
for help on using the changeset viewer.