source: mainline/uspace/lib/usb/src/pipesio.c@ 5e168be1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5e168be1 was 77223f8, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Client does not send max packet size

Let's pretend this commit appeared about 10 revisions earlier ;-).

  • Property mode set to 100644
File size: 14.1 KB
RevLine 
[dc04868]1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libusb
30 * @{
31 */
32/** @file
33 * Input and output functions (reads and writes) on endpoint pipes.
34 *
35 * Note on synchronousness of the operations: there is ABSOLUTELY NO
36 * guarantee that a call to particular function will not trigger a fibril
37 * switch.
[47c573a]38 *
39 * Note about the implementation: the transfer requests are always divided
40 * into two functions.
41 * The outer one does checking of input parameters (e.g. that session was
42 * already started, buffers are not NULL etc), while the inner one
43 * (with _no_checks suffix) does the actual IPC (it checks for IPC errors,
44 * obviously).
[dc04868]45 */
46#include <usb/usb.h>
47#include <usb/pipes.h>
48#include <errno.h>
49#include <assert.h>
[47c573a]50#include <usbhc_iface.h>
[a546687]51#include "pipepriv.h"
[d5ac90f]52
[47c573a]53/** Request an in transfer, no checking of input parameters.
54 *
55 * @param[in] pipe Pipe used for the transfer.
56 * @param[out] buffer Buffer where to store the data.
57 * @param[in] size Size of the buffer (in bytes).
58 * @param[out] size_transfered Number of bytes that were actually transfered.
59 * @return Error code.
60 */
[3954a63b]61static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
[47c573a]62 void *buffer, size_t size, size_t *size_transfered)
63{
64 /*
65 * Get corresponding IPC method.
66 * In future, replace with static array of mappings
67 * transfer type -> method.
68 */
69 usbhc_iface_funcs_t ipc_method;
70 switch (pipe->transfer_type) {
71 case USB_TRANSFER_INTERRUPT:
72 ipc_method = IPC_M_USBHC_INTERRUPT_IN;
73 break;
[0a46c41e]74 case USB_TRANSFER_BULK:
75 ipc_method = IPC_M_USBHC_BULK_IN;
76 break;
[47c573a]77 default:
78 return ENOTSUP;
79 }
80
[d5ac90f]81 /* Ensure serialization over the phone. */
[d48fcc0]82 pipe_start_transaction(pipe);
[d5ac90f]83
[47c573a]84 /*
85 * Make call identifying target USB device and type of transfer.
86 */
[77223f8]87 aid_t opening_request = async_send_3(pipe->hc_phone,
[47c573a]88 DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
89 pipe->wire->address, pipe->endpoint_no,
90 NULL);
91 if (opening_request == 0) {
[d48fcc0]92 pipe_end_transaction(pipe);
[47c573a]93 return ENOMEM;
94 }
[dc04868]95
[47c573a]96 /*
97 * Retrieve the data.
98 */
99 ipc_call_t data_request_call;
100 aid_t data_request = async_data_read(pipe->hc_phone, buffer, size,
101 &data_request_call);
102
[d5ac90f]103 /*
104 * Since now on, someone else might access the backing phone
105 * without breaking the transfer IPC protocol.
106 */
[d48fcc0]107 pipe_end_transaction(pipe);
[d5ac90f]108
[47c573a]109 if (data_request == 0) {
110 /*
111 * FIXME:
112 * How to let the other side know that we want to abort?
113 */
114 async_wait_for(opening_request, NULL);
115 return ENOMEM;
[dc04868]116 }
117
[47c573a]118 /*
119 * Wait for the answer.
120 */
121 sysarg_t data_request_rc;
122 sysarg_t opening_request_rc;
123 async_wait_for(data_request, &data_request_rc);
124 async_wait_for(opening_request, &opening_request_rc);
125
126 if (data_request_rc != EOK) {
[d473c6b]127 /* Prefer the return code of the opening request. */
128 if (opening_request_rc != EOK) {
129 return (int) opening_request_rc;
130 } else {
131 return (int) data_request_rc;
132 }
[47c573a]133 }
134 if (opening_request_rc != EOK) {
135 return (int) opening_request_rc;
136 }
137
138 *size_transfered = IPC_GET_ARG2(data_request_call);
139
140 return EOK;
141}
142
[dc04868]143
144/** Request a read (in) transfer on an endpoint pipe.
145 *
146 * @param[in] pipe Pipe used for the transfer.
147 * @param[out] buffer Buffer where to store the data.
148 * @param[in] size Size of the buffer (in bytes).
149 * @param[out] size_transfered Number of bytes that were actually transfered.
150 * @return Error code.
151 */
[3954a63b]152int usb_pipe_read(usb_pipe_t *pipe,
[dc04868]153 void *buffer, size_t size, size_t *size_transfered)
154{
155 assert(pipe);
156
[47c573a]157 if (buffer == NULL) {
[a546687]158 return EINVAL;
[47c573a]159 }
160
161 if (size == 0) {
162 return EINVAL;
163 }
164
[dc04868]165 if (pipe->direction != USB_DIRECTION_IN) {
166 return EBADF;
167 }
168
[47c573a]169 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
170 return EBADF;
171 }
172
[dc04868]173 int rc;
[a546687]174 rc = pipe_add_ref(pipe);
175 if (rc != EOK) {
176 return rc;
177 }
178
179
180 size_t act_size = 0;
[dc04868]181
[3954a63b]182 rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
[a546687]183
184 pipe_drop_ref(pipe);
185
[47c573a]186 if (rc != EOK) {
187 return rc;
188 }
189
190 if (size_transfered != NULL) {
191 *size_transfered = act_size;
192 }
193
194 return EOK;
195}
196
197
198
199
200/** Request an out transfer, no checking of input parameters.
201 *
202 * @param[in] pipe Pipe used for the transfer.
203 * @param[in] buffer Buffer with data to transfer.
204 * @param[in] size Size of the buffer (in bytes).
205 * @return Error code.
206 */
[3954a63b]207static int usb_pipe_write_no_check(usb_pipe_t *pipe,
[47c573a]208 void *buffer, size_t size)
209{
210 /*
211 * Get corresponding IPC method.
212 * In future, replace with static array of mappings
213 * transfer type -> method.
214 */
215 usbhc_iface_funcs_t ipc_method;
[dc04868]216 switch (pipe->transfer_type) {
217 case USB_TRANSFER_INTERRUPT:
[47c573a]218 ipc_method = IPC_M_USBHC_INTERRUPT_OUT;
[dc04868]219 break;
[0a46c41e]220 case USB_TRANSFER_BULK:
221 ipc_method = IPC_M_USBHC_BULK_OUT;
222 break;
[dc04868]223 default:
[47c573a]224 return ENOTSUP;
[dc04868]225 }
226
[d5ac90f]227 /* Ensure serialization over the phone. */
[d48fcc0]228 pipe_start_transaction(pipe);
[d5ac90f]229
[47c573a]230 /*
231 * Make call identifying target USB device and type of transfer.
232 */
[77223f8]233 aid_t opening_request = async_send_3(pipe->hc_phone,
[47c573a]234 DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
235 pipe->wire->address, pipe->endpoint_no,
236 NULL);
237 if (opening_request == 0) {
[d48fcc0]238 pipe_end_transaction(pipe);
[47c573a]239 return ENOMEM;
240 }
241
242 /*
243 * Send the data.
244 */
245 int rc = async_data_write_start(pipe->hc_phone, buffer, size);
[d5ac90f]246
247 /*
248 * Since now on, someone else might access the backing phone
249 * without breaking the transfer IPC protocol.
250 */
[d48fcc0]251 pipe_end_transaction(pipe);
[d5ac90f]252
[567d002]253 if (rc != EOK) {
[47c573a]254 async_wait_for(opening_request, NULL);
[567d002]255 return rc;
256 }
257
[47c573a]258 /*
259 * Wait for the answer.
260 */
261 sysarg_t opening_request_rc;
262 async_wait_for(opening_request, &opening_request_rc);
[567d002]263
[47c573a]264 return (int) opening_request_rc;
[dc04868]265}
266
[567d002]267/** Request a write (out) transfer on an endpoint pipe.
[dc04868]268 *
269 * @param[in] pipe Pipe used for the transfer.
270 * @param[in] buffer Buffer with data to transfer.
271 * @param[in] size Size of the buffer (in bytes).
272 * @return Error code.
273 */
[3954a63b]274int usb_pipe_write(usb_pipe_t *pipe,
[567d002]275 void *buffer, size_t size)
[dc04868]276{
277 assert(pipe);
278
[47c573a]279 if (buffer == NULL) {
280 return EINVAL;
281 }
282
283 if (size == 0) {
284 return EINVAL;
285 }
286
[dc04868]287 if (pipe->direction != USB_DIRECTION_OUT) {
288 return EBADF;
289 }
290
[47c573a]291 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
292 return EBADF;
293 }
[dc04868]294
[a546687]295 int rc;
296
297 rc = pipe_add_ref(pipe);
298 if (rc != EOK) {
299 return rc;
300 }
301
302 rc = usb_pipe_write_no_check(pipe, buffer, size);
303
304 pipe_drop_ref(pipe);
[47c573a]305
306 return rc;
307}
308
309
310/** Request a control read transfer, no checking of input parameters.
311 *
312 * @param[in] pipe Pipe used for the transfer.
313 * @param[in] setup_buffer Buffer with the setup packet.
314 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
315 * @param[out] data_buffer Buffer for incoming data.
316 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
317 * @param[out] data_transfered_size Number of bytes that were actually
318 * transfered during the DATA stage.
319 * @return Error code.
320 */
[3954a63b]321static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
[47c573a]322 void *setup_buffer, size_t setup_buffer_size,
323 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
324{
[d5ac90f]325 /* Ensure serialization over the phone. */
[d48fcc0]326 pipe_start_transaction(pipe);
[d5ac90f]327
[47c573a]328 /*
329 * Make call identifying target USB device and control transfer type.
330 */
[77223f8]331 aid_t opening_request = async_send_3(pipe->hc_phone,
[47c573a]332 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_READ,
333 pipe->wire->address, pipe->endpoint_no,
334 NULL);
335 if (opening_request == 0) {
336 return ENOMEM;
[dc04868]337 }
338
[47c573a]339 /*
340 * Send the setup packet.
341 */
342 int rc = async_data_write_start(pipe->hc_phone,
343 setup_buffer, setup_buffer_size);
[567d002]344 if (rc != EOK) {
[d48fcc0]345 pipe_end_transaction(pipe);
[47c573a]346 async_wait_for(opening_request, NULL);
[567d002]347 return rc;
348 }
349
[47c573a]350 /*
351 * Retrieve the data.
352 */
353 ipc_call_t data_request_call;
354 aid_t data_request = async_data_read(pipe->hc_phone,
355 data_buffer, data_buffer_size,
356 &data_request_call);
[d5ac90f]357
358 /*
359 * Since now on, someone else might access the backing phone
360 * without breaking the transfer IPC protocol.
361 */
[d48fcc0]362 pipe_end_transaction(pipe);
[d5ac90f]363
364
[47c573a]365 if (data_request == 0) {
366 async_wait_for(opening_request, NULL);
367 return ENOMEM;
368 }
[567d002]369
[47c573a]370 /*
371 * Wait for the answer.
372 */
373 sysarg_t data_request_rc;
374 sysarg_t opening_request_rc;
375 async_wait_for(data_request, &data_request_rc);
376 async_wait_for(opening_request, &opening_request_rc);
377
378 if (data_request_rc != EOK) {
[d473c6b]379 /* Prefer the return code of the opening request. */
380 if (opening_request_rc != EOK) {
381 return (int) opening_request_rc;
382 } else {
383 return (int) data_request_rc;
384 }
[47c573a]385 }
386 if (opening_request_rc != EOK) {
387 return (int) opening_request_rc;
388 }
[dc04868]389
[47c573a]390 *data_transfered_size = IPC_GET_ARG2(data_request_call);
391
392 return EOK;
393}
[dc04868]394
[567d002]395/** Request a control read transfer on an endpoint pipe.
[dc04868]396 *
397 * This function encapsulates all three stages of a control transfer.
398 *
399 * @param[in] pipe Pipe used for the transfer.
400 * @param[in] setup_buffer Buffer with the setup packet.
401 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
402 * @param[out] data_buffer Buffer for incoming data.
403 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
404 * @param[out] data_transfered_size Number of bytes that were actually
405 * transfered during the DATA stage.
406 * @return Error code.
407 */
[3954a63b]408int usb_pipe_control_read(usb_pipe_t *pipe,
[dc04868]409 void *setup_buffer, size_t setup_buffer_size,
[567d002]410 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
[dc04868]411{
412 assert(pipe);
413
[47c573a]414 if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
415 return EINVAL;
416 }
417
418 if ((data_buffer == NULL) || (data_buffer_size == 0)) {
419 return EINVAL;
420 }
421
[dc04868]422 if ((pipe->direction != USB_DIRECTION_BOTH)
423 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
424 return EBADF;
425 }
426
[a546687]427 int rc;
428
429 rc = pipe_add_ref(pipe);
430 if (rc != EOK) {
431 return rc;
432 }
433
[47c573a]434 size_t act_size = 0;
[a546687]435 rc = usb_pipe_control_read_no_check(pipe,
[dc04868]436 setup_buffer, setup_buffer_size,
[47c573a]437 data_buffer, data_buffer_size, &act_size);
[567d002]438
[a546687]439 pipe_drop_ref(pipe);
440
[567d002]441 if (rc != EOK) {
442 return rc;
443 }
444
[47c573a]445 if (data_transfered_size != NULL) {
446 *data_transfered_size = act_size;
447 }
[dc04868]448
[47c573a]449 return EOK;
[dc04868]450}
451
452
[47c573a]453/** Request a control write transfer, no checking of input parameters.
454 *
455 * @param[in] pipe Pipe used for the transfer.
456 * @param[in] setup_buffer Buffer with the setup packet.
457 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
458 * @param[in] data_buffer Buffer with data to be sent.
459 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
460 * @return Error code.
461 */
[3954a63b]462static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
[47c573a]463 void *setup_buffer, size_t setup_buffer_size,
464 void *data_buffer, size_t data_buffer_size)
465{
[d5ac90f]466 /* Ensure serialization over the phone. */
[d48fcc0]467 pipe_start_transaction(pipe);
[d5ac90f]468
[47c573a]469 /*
470 * Make call identifying target USB device and control transfer type.
471 */
[77223f8]472 aid_t opening_request = async_send_4(pipe->hc_phone,
[47c573a]473 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_WRITE,
474 pipe->wire->address, pipe->endpoint_no,
475 data_buffer_size,
476 NULL);
477 if (opening_request == 0) {
[d48fcc0]478 pipe_end_transaction(pipe);
[47c573a]479 return ENOMEM;
480 }
481
482 /*
483 * Send the setup packet.
484 */
485 int rc = async_data_write_start(pipe->hc_phone,
486 setup_buffer, setup_buffer_size);
487 if (rc != EOK) {
[d48fcc0]488 pipe_end_transaction(pipe);
[47c573a]489 async_wait_for(opening_request, NULL);
490 return rc;
491 }
492
493 /*
494 * Send the data (if any).
495 */
496 if (data_buffer_size > 0) {
497 rc = async_data_write_start(pipe->hc_phone,
498 data_buffer, data_buffer_size);
[d5ac90f]499
500 /* All data sent, pipe can be released. */
[d48fcc0]501 pipe_end_transaction(pipe);
[d5ac90f]502
[47c573a]503 if (rc != EOK) {
504 async_wait_for(opening_request, NULL);
505 return rc;
506 }
[d5ac90f]507 } else {
508 /* No data to send, we can release the pipe for others. */
[d48fcc0]509 pipe_end_transaction(pipe);
[47c573a]510 }
511
512 /*
513 * Wait for the answer.
514 */
515 sysarg_t opening_request_rc;
516 async_wait_for(opening_request, &opening_request_rc);
517
518 return (int) opening_request_rc;
519}
520
[567d002]521/** Request a control write transfer on an endpoint pipe.
[dc04868]522 *
523 * This function encapsulates all three stages of a control transfer.
524 *
525 * @param[in] pipe Pipe used for the transfer.
526 * @param[in] setup_buffer Buffer with the setup packet.
527 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
528 * @param[in] data_buffer Buffer with data to be sent.
529 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
530 * @return Error code.
531 */
[3954a63b]532int usb_pipe_control_write(usb_pipe_t *pipe,
[dc04868]533 void *setup_buffer, size_t setup_buffer_size,
[567d002]534 void *data_buffer, size_t data_buffer_size)
[dc04868]535{
536 assert(pipe);
537
[47c573a]538 if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
539 return EINVAL;
540 }
541
542 if ((data_buffer == NULL) && (data_buffer_size > 0)) {
543 return EINVAL;
544 }
545
546 if ((data_buffer != NULL) && (data_buffer_size == 0)) {
547 return EINVAL;
548 }
549
[dc04868]550 if ((pipe->direction != USB_DIRECTION_BOTH)
551 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
552 return EBADF;
553 }
554
[a546687]555 int rc;
556
557 rc = pipe_add_ref(pipe);
558 if (rc != EOK) {
559 return rc;
560 }
561
562 rc = usb_pipe_control_write_no_check(pipe,
[47c573a]563 setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
[567d002]564
[a546687]565 pipe_drop_ref(pipe);
566
[567d002]567 return rc;
[dc04868]568}
569
570
571/**
572 * @}
573 */
Note: See TracBrowser for help on using the repository browser.