Changes in uspace/lib/drv/generic/remote_usbhc.c [1d758fc:b7fd2a0] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/drv/generic/remote_usbhc.c
r1d758fc rb7fd2a0 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 #include <as.h>42 40 43 41 #include "usbhc_iface.h" 44 42 #include "ddf/driver.h" 45 43 46 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 */ 47 86 typedef enum { 48 IPC_M_USB_DEFAULT_ADDRESS_RESERVATION, 49 IPC_M_USB_DEVICE_ENUMERATE, 50 IPC_M_USB_DEVICE_REMOVE, 51 IPC_M_USB_REGISTER_ENDPOINT, 52 IPC_M_USB_UNREGISTER_ENDPOINT, 53 IPC_M_USB_TRANSFER, 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 errno_t usbhc_reserve_default_address(async_exch_t *exch) 98 errno_t 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 exchange 70 * 71 * @return Error code. 72 */ 73 errno_t usbhc_release_default_address(async_exch_t *exch) 104 105 if (size == 0 && setup == 0) 106 return EOK; 107 108 const usb_target_t target = 109 {{ .address = address, .endpoint = endpoint }}; 110 111 /* Make call identifying target USB device and type of transfer. */ 112 aid_t opening_request = async_send_4(exch, 113 DEV_IFACE_ID(USBHC_DEV_IFACE), 114 IPC_M_USBHC_READ, target.packed, 115 (setup & UINT32_MAX), (setup >> 32), NULL); 116 117 if (opening_request == 0) { 118 return ENOMEM; 119 } 120 121 /* Retrieve the data. */ 122 ipc_call_t data_request_call; 123 aid_t data_request = 124 async_data_read(exch, data, size, &data_request_call); 125 126 if (data_request == 0) { 127 // FIXME: How to let the other side know that we want to abort? 128 async_forget(opening_request); 129 return ENOMEM; 130 } 131 132 /* Wait for the answer. */ 133 errno_t data_request_rc; 134 errno_t opening_request_rc; 135 async_wait_for(data_request, &data_request_rc); 136 async_wait_for(opening_request, &opening_request_rc); 137 138 if (data_request_rc != EOK) { 139 /* Prefer the return code of the opening request. */ 140 if (opening_request_rc != EOK) { 141 return (errno_t) opening_request_rc; 142 } else { 143 return (errno_t) data_request_rc; 144 } 145 } 146 if (opening_request_rc != EOK) { 147 return (errno_t) opening_request_rc; 148 } 149 150 *rec_size = IPC_GET_ARG2(data_request_call); 151 return EOK; 152 } 153 154 errno_t usbhc_write(async_exch_t *exch, usb_address_t address, 155 usb_endpoint_t endpoint, uint64_t setup, const void *data, size_t size) 74 156 { 75 157 if (!exch) 76 158 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 enumeration 82 * 83 * @param[in] exch IPC communication exchange 84 * @param[in] port Port number at which the device is attached 85 * @param[in] speed Communication speed of the newly attached device 86 * 87 * @return Error code. 88 */ 89 errno_t usbhc_device_enumerate(async_exch_t *exch, unsigned port, usb_speed_t speed) 90 { 91 if (!exch) 92 return EBADMEM; 93 const errno_t 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 enumeration 99 * 100 * @param[in] exch IPC communication exchange 101 * @param[in] handle Identifier of the device 102 * 103 * @return Error code. 104 * 105 */ 106 errno_t 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 errno_t 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); 159 160 if (size == 0 && setup == 0) 161 return EOK; 162 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, 168 (setup & UINT32_MAX), (setup >> 32), NULL); 125 169 126 170 if (opening_request == 0) { … … 128 172 } 129 173 130 errno_t 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 errno_t opening_request_rc; 138 async_wait_for(opening_request, &opening_request_rc); 139 140 if (opening_request_rc) 141 return (errno_t) 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 errno_t 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 errno_t 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 errno_t opening_request_rc; 175 async_wait_for(opening_request, &opening_request_rc); 176 177 return (errno_t) opening_request_rc; 178 } 179 180 /** 181 * Issue a USB transfer with a data contained in memory area. That area is 182 * temporarily shared with the HC. 183 */ 184 errno_t usbhc_transfer(async_exch_t *exch, 185 const usbhc_iface_transfer_request_t *req, size_t *transferred) 186 { 187 if (transferred) 188 *transferred = 0; 189 190 if (!exch) 191 return EBADMEM; 192 193 ipc_call_t call; 194 195 aid_t opening_request = async_send_1(exch, DEV_IFACE_ID(USBHC_DEV_IFACE), 196 IPC_M_USB_TRANSFER, &call); 197 198 if (opening_request == 0) 199 return ENOMEM; 200 201 const errno_t ret = async_data_write_start(exch, req, sizeof(*req)); 202 if (ret != EOK) { 203 async_forget(opening_request); 204 return ret; 205 } 206 207 /* Share the data, if any. */ 208 if (req->size > 0) { 209 unsigned flags = (req->dir == USB_DIRECTION_IN) 210 ? AS_AREA_WRITE : AS_AREA_READ; 211 212 const errno_t ret = async_share_out_start(exch, req->buffer.virt, flags); 174 /* Send the data if any. */ 175 if (size > 0) { 176 const errno_t ret = async_data_write_start(exch, data, size); 213 177 if (ret != EOK) { 214 178 async_forget(opening_request); … … 221 185 async_wait_for(opening_request, &opening_request_rc); 222 186 223 if (transferred)224 *transferred = IPC_GET_ARG1(call);225 226 187 return (errno_t) opening_request_rc; 227 188 } 228 189 229 static void remote_usbhc_default_address_reservation(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 230 static void remote_usbhc_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 231 static void remote_usbhc_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 232 static void remote_usbhc_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 233 static void remote_usbhc_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *); 234 static void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call); 235 236 /** Remote USB interface operations. */ 237 static const remote_iface_func_ptr_t remote_usbhc_iface_ops [] = { 238 [IPC_M_USB_DEFAULT_ADDRESS_RESERVATION] = remote_usbhc_default_address_reservation, 239 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usbhc_device_enumerate, 240 [IPC_M_USB_DEVICE_REMOVE] = remote_usbhc_device_remove, 241 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usbhc_register_endpoint, 242 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usbhc_unregister_endpoint, 243 [IPC_M_USB_TRANSFER] = remote_usbhc_transfer, 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, 244 197 }; 245 198 246 /** Remote USB interface structure.199 /** Remote USB host controller interface structure. 247 200 */ 248 201 const remote_iface_t remote_usbhc_iface = { 249 202 .method_count = ARRAY_SIZE(remote_usbhc_iface_ops), 250 .methods = remote_usbhc_iface_ops ,203 .methods = remote_usbhc_iface_ops 251 204 }; 252 205 253 206 typedef struct { 254 207 ipc_callid_t caller; 255 usbhc_iface_transfer_request_t request; 208 ipc_callid_t data_caller; 209 void *buffer; 256 210 } async_transaction_t; 257 211 258 void remote_usbhc_default_address_reservation(ddf_fun_t *fun, void *iface, 259 ipc_callid_t callid, ipc_call_t *call) 260 { 261 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 262 263 if (usbhc_iface->default_address_reservation == NULL) { 264 async_answer_0(callid, ENOTSUP); 265 return; 266 } 267 268 const bool reserve = IPC_GET_ARG2(*call); 269 const errno_t ret = usbhc_iface->default_address_reservation(fun, reserve); 270 async_answer_0(callid, ret); 271 } 272 273 274 static void remote_usbhc_device_enumerate(ddf_fun_t *fun, void *iface, 275 ipc_callid_t callid, ipc_call_t *call) 276 { 277 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 278 279 if (usbhc_iface->device_enumerate == NULL) { 280 async_answer_0(callid, ENOTSUP); 281 return; 282 } 283 284 const unsigned port = DEV_IPC_GET_ARG1(*call); 285 usb_speed_t speed = DEV_IPC_GET_ARG2(*call); 286 const errno_t ret = usbhc_iface->device_enumerate(fun, port, speed); 287 async_answer_0(callid, ret); 288 } 289 290 static void remote_usbhc_device_remove(ddf_fun_t *fun, void *iface, 291 ipc_callid_t callid, ipc_call_t *call) 292 { 293 const usbhc_iface_t *usbhc_iface = (usbhc_iface_t *) iface; 294 295 if (usbhc_iface->device_remove == NULL) { 296 async_answer_0(callid, ENOTSUP); 297 return; 298 } 299 300 const unsigned port = DEV_IPC_GET_ARG1(*call); 301 const errno_t ret = usbhc_iface->device_remove(fun, port); 302 async_answer_0(callid, ret); 303 } 304 305 static void remote_usbhc_register_endpoint(ddf_fun_t *fun, void *iface, 306 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(errno_t 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(errno_t 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) 307 271 { 308 272 assert(fun); … … 310 274 assert(call); 311 275 312 const usbhc_iface_t * usbhc_iface = iface;313 314 if (! usbhc_iface->register_endpoint) {276 const usbhc_iface_t *hc_iface = iface; 277 278 if (!hc_iface->read) { 315 279 async_answer_0(callid, ENOTSUP); 316 280 return; 317 281 } 318 282 319 usb_endpoint_descriptors_t ep_desc; 320 ipc_callid_t data_callid; 321 size_t len; 322 323 if (!async_data_write_receive(&data_callid, &len) 324 || len != sizeof(ep_desc)) { 325 async_answer_0(callid, EINVAL); 326 return; 327 } 328 async_data_write_finalize(data_callid, &ep_desc, sizeof(ep_desc)); 329 330 usb_pipe_desc_t pipe_desc; 331 332 const errno_t rc = usbhc_iface->register_endpoint(fun, &pipe_desc, &ep_desc); 333 async_answer_0(callid, rc); 334 335 if (!async_data_read_receive(&data_callid, &len) 336 || len != sizeof(pipe_desc)) { 337 return; 338 } 339 async_data_read_finalize(data_callid, &pipe_desc, sizeof(pipe_desc)); 340 } 341 342 static void remote_usbhc_unregister_endpoint(ddf_fun_t *fun, void *iface, 343 ipc_callid_t callid, ipc_call_t *call) 283 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) }; 284 const uint64_t setup = 285 ((uint64_t)DEV_IPC_GET_ARG2(*call)) | 286 (((uint64_t)DEV_IPC_GET_ARG3(*call)) << 32); 287 288 async_transaction_t *trans = async_transaction_create(callid); 289 if (trans == NULL) { 290 async_answer_0(callid, ENOMEM); 291 return; 292 } 293 294 size_t size = 0; 295 if (!async_data_read_receive(&trans->data_caller, &size)) { 296 async_answer_0(callid, EPARTY); 297 return; 298 } 299 300 trans->buffer = malloc(size); 301 if (trans->buffer == NULL) { 302 async_answer_0(trans->data_caller, ENOMEM); 303 async_answer_0(callid, ENOMEM); 304 async_transaction_destroy(trans); 305 return; 306 } 307 308 const errno_t rc = hc_iface->read( 309 fun, target, setup, trans->buffer, size, callback_in, trans); 310 311 if (rc != EOK) { 312 async_answer_0(trans->data_caller, rc); 313 async_answer_0(callid, rc); 314 async_transaction_destroy(trans); 315 } 316 } 317 318 void remote_usbhc_write( 319 ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 344 320 { 345 321 assert(fun); … … 347 323 assert(call); 348 324 349 const usbhc_iface_t * usbhc_iface = iface;350 351 if (! usbhc_iface->unregister_endpoint) {325 const usbhc_iface_t *hc_iface = iface; 326 327 if (!hc_iface->write) { 352 328 async_answer_0(callid, ENOTSUP); 353 329 return; 354 330 } 355 331 356 usb_pipe_desc_t pipe_desc; 357 ipc_callid_t data_callid; 358 size_t len; 359 360 if (!async_data_write_receive(&data_callid, &len) 361 || len != sizeof(pipe_desc)) { 362 async_answer_0(callid, EINVAL); 363 return; 364 } 365 async_data_write_finalize(data_callid, &pipe_desc, sizeof(pipe_desc)); 366 367 const errno_t rc = usbhc_iface->unregister_endpoint(fun, &pipe_desc); 368 async_answer_0(callid, rc); 369 } 370 371 static void async_transaction_destroy(async_transaction_t *trans) 372 { 373 if (trans == NULL) { 374 return; 375 } 376 if (trans->request.buffer.virt != NULL) { 377 as_area_destroy(trans->request.buffer.virt); 378 } 379 380 free(trans); 381 } 382 383 static async_transaction_t *async_transaction_create(ipc_callid_t caller) 384 { 385 async_transaction_t *trans = calloc(1, sizeof(async_transaction_t)); 386 387 if (trans != NULL) 388 trans->caller = caller; 389 390 return trans; 391 } 392 393 static errno_t transfer_finished(void *arg, errno_t error, size_t transferred_size) 394 { 395 async_transaction_t *trans = arg; 396 const errno_t err = async_answer_1(trans->caller, error, transferred_size); 397 async_transaction_destroy(trans); 398 return err; 399 } 400 401 static errno_t receive_memory_buffer(async_transaction_t *trans) 402 { 403 assert(trans); 404 assert(trans->request.size > 0); 405 406 const size_t required_size = trans->request.offset + trans->request.size; 407 const unsigned required_flags = 408 (trans->request.dir == USB_DIRECTION_IN) 409 ? AS_AREA_WRITE : AS_AREA_READ; 410 411 errno_t err; 412 ipc_callid_t data_callid; 413 size_t size; 414 unsigned flags; 415 416 if (!async_share_out_receive(&data_callid, &size, &flags)) 417 return EPARTY; 418 419 if (size < required_size || (flags & required_flags) != required_flags) { 420 async_answer_0(data_callid, EINVAL); 421 return EINVAL; 422 } 423 424 if ((err = async_share_out_finalize(data_callid, &trans->request.buffer.virt))) 425 return err; 426 427 /* 428 * As we're going to get physical addresses of the mapping, we must make 429 * sure the memory is actually mapped. We must do it right now, because 430 * the area might be read-only or write-only, and we may be unsure 431 * later. 432 */ 433 if (flags & AS_AREA_READ) { 434 char foo = 0; 435 volatile const char *buf = trans->request.buffer.virt + trans->request.offset; 436 for (size_t i = 0; i < size; i += PAGE_SIZE) 437 foo += buf[i]; 438 } else { 439 volatile char *buf = trans->request.buffer.virt + trans->request.offset; 440 for (size_t i = 0; i < size; i += PAGE_SIZE) 441 buf[i] = 0xff; 442 } 443 444 return EOK; 445 } 446 447 void remote_usbhc_transfer(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) 448 { 449 assert(fun); 450 assert(iface); 451 assert(call); 452 453 const usbhc_iface_t *usbhc_iface = iface; 454 455 if (!usbhc_iface->transfer) { 456 async_answer_0(callid, ENOTSUP); 457 return; 458 } 332 const usb_target_t target = { .packed = DEV_IPC_GET_ARG1(*call) }; 333 const size_t data_buffer_len = DEV_IPC_GET_ARG2(*call); 334 const uint64_t setup = 335 ((uint64_t)DEV_IPC_GET_ARG3(*call)) | 336 (((uint64_t)DEV_IPC_GET_ARG4(*call)) << 32); 459 337 460 338 async_transaction_t *trans = async_transaction_create(callid); … … 464 342 } 465 343 466 errno_t err = EPARTY; 467 468 ipc_callid_t data_callid; 469 size_t len; 470 if (!async_data_write_receive(&data_callid, &len) 471 || len != sizeof(trans->request)) { 472 async_answer_0(data_callid, EINVAL); 473 goto err; 474 } 475 476 if ((err = async_data_write_finalize(data_callid, 477 &trans->request, sizeof(trans->request)))) 478 goto err; 479 480 if (trans->request.size > 0) { 481 if ((err = receive_memory_buffer(trans))) 482 goto err; 483 } else { 484 /* The value was valid on the other side, for us, its garbage. */ 485 trans->request.buffer.virt = NULL; 486 } 487 488 if ((err = usbhc_iface->transfer(fun, &trans->request, 489 &transfer_finished, trans))) 490 goto err; 491 492 /* The call will be answered asynchronously by the callback. */ 493 return; 494 495 err: 496 async_answer_0(callid, err); 497 async_transaction_destroy(trans); 498 } 499 344 size_t size = 0; 345 if (data_buffer_len > 0) { 346 const errno_t rc = async_data_write_accept(&trans->buffer, false, 347 1, USB_MAX_PAYLOAD_SIZE, 348 0, &size); 349 350 if (rc != EOK) { 351 async_answer_0(callid, rc); 352 async_transaction_destroy(trans); 353 return; 354 } 355 } 356 357 const errno_t rc = hc_iface->write( 358 fun, target, setup, trans->buffer, size, callback_out, trans); 359 360 if (rc != EOK) { 361 async_answer_0(callid, rc); 362 async_transaction_destroy(trans); 363 } 364 } 500 365 /** 501 366 * @}
Note:
See TracChangeset
for help on using the changeset viewer.