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

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

usb_pipe_start_long_transfer returns void (#196)

  • Property mode set to 100644
File size: 14.7 KB
Line 
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.
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).
45 */
46#include <usb/usb.h>
47#include <usb/pipes.h>
48#include <errno.h>
49#include <assert.h>
50#include <usbhc_iface.h>
51#include <usb/request.h>
52#include "pipepriv.h"
53
54/** Request an in transfer, no checking of input parameters.
55 *
56 * @param[in] pipe Pipe used for the transfer.
57 * @param[out] buffer Buffer where to store the data.
58 * @param[in] size Size of the buffer (in bytes).
59 * @param[out] size_transfered Number of bytes that were actually transfered.
60 * @return Error code.
61 */
62static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
63 void *buffer, size_t size, size_t *size_transfered)
64{
65 /*
66 * Get corresponding IPC method.
67 * In future, replace with static array of mappings
68 * transfer type -> method.
69 */
70 usbhc_iface_funcs_t ipc_method;
71 switch (pipe->transfer_type) {
72 case USB_TRANSFER_INTERRUPT:
73 ipc_method = IPC_M_USBHC_INTERRUPT_IN;
74 break;
75 case USB_TRANSFER_BULK:
76 ipc_method = IPC_M_USBHC_BULK_IN;
77 break;
78 default:
79 return ENOTSUP;
80 }
81
82 /* Ensure serialization over the phone. */
83 pipe_start_transaction(pipe);
84
85 /*
86 * Make call identifying target USB device and type of transfer.
87 */
88 aid_t opening_request = async_send_3(pipe->hc_phone,
89 DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
90 pipe->wire->address, pipe->endpoint_no,
91 NULL);
92 if (opening_request == 0) {
93 pipe_end_transaction(pipe);
94 return ENOMEM;
95 }
96
97 /*
98 * Retrieve the data.
99 */
100 ipc_call_t data_request_call;
101 aid_t data_request = async_data_read(pipe->hc_phone, buffer, size,
102 &data_request_call);
103
104 /*
105 * Since now on, someone else might access the backing phone
106 * without breaking the transfer IPC protocol.
107 */
108 pipe_end_transaction(pipe);
109
110 if (data_request == 0) {
111 /*
112 * FIXME:
113 * How to let the other side know that we want to abort?
114 */
115 async_wait_for(opening_request, NULL);
116 return ENOMEM;
117 }
118
119 /*
120 * Wait for the answer.
121 */
122 sysarg_t data_request_rc;
123 sysarg_t opening_request_rc;
124 async_wait_for(data_request, &data_request_rc);
125 async_wait_for(opening_request, &opening_request_rc);
126
127 if (data_request_rc != EOK) {
128 /* Prefer the return code of the opening request. */
129 if (opening_request_rc != EOK) {
130 return (int) opening_request_rc;
131 } else {
132 return (int) data_request_rc;
133 }
134 }
135 if (opening_request_rc != EOK) {
136 return (int) opening_request_rc;
137 }
138
139 *size_transfered = IPC_GET_ARG2(data_request_call);
140
141 return EOK;
142}
143
144
145/** Request a read (in) transfer on an endpoint pipe.
146 *
147 * @param[in] pipe Pipe used for the transfer.
148 * @param[out] buffer Buffer where to store the data.
149 * @param[in] size Size of the buffer (in bytes).
150 * @param[out] size_transfered Number of bytes that were actually transfered.
151 * @return Error code.
152 */
153int usb_pipe_read(usb_pipe_t *pipe,
154 void *buffer, size_t size, size_t *size_transfered)
155{
156 assert(pipe);
157
158 if (buffer == NULL) {
159 return EINVAL;
160 }
161
162 if (size == 0) {
163 return EINVAL;
164 }
165
166 if (pipe->direction != USB_DIRECTION_IN) {
167 return EBADF;
168 }
169
170 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
171 return EBADF;
172 }
173
174 int rc;
175 rc = pipe_add_ref(pipe, false);
176 if (rc != EOK) {
177 return rc;
178 }
179
180
181 size_t act_size = 0;
182
183 rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
184
185 pipe_drop_ref(pipe);
186
187 if (rc != EOK) {
188 return rc;
189 }
190
191 if (size_transfered != NULL) {
192 *size_transfered = act_size;
193 }
194
195 return EOK;
196}
197
198
199
200
201/** Request an out transfer, no checking of input parameters.
202 *
203 * @param[in] pipe Pipe used for the transfer.
204 * @param[in] buffer Buffer with data to transfer.
205 * @param[in] size Size of the buffer (in bytes).
206 * @return Error code.
207 */
208static int usb_pipe_write_no_check(usb_pipe_t *pipe,
209 void *buffer, size_t size)
210{
211 /*
212 * Get corresponding IPC method.
213 * In future, replace with static array of mappings
214 * transfer type -> method.
215 */
216 usbhc_iface_funcs_t ipc_method;
217 switch (pipe->transfer_type) {
218 case USB_TRANSFER_INTERRUPT:
219 ipc_method = IPC_M_USBHC_INTERRUPT_OUT;
220 break;
221 case USB_TRANSFER_BULK:
222 ipc_method = IPC_M_USBHC_BULK_OUT;
223 break;
224 default:
225 return ENOTSUP;
226 }
227
228 /* Ensure serialization over the phone. */
229 pipe_start_transaction(pipe);
230
231 /*
232 * Make call identifying target USB device and type of transfer.
233 */
234 aid_t opening_request = async_send_3(pipe->hc_phone,
235 DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
236 pipe->wire->address, pipe->endpoint_no,
237 NULL);
238 if (opening_request == 0) {
239 pipe_end_transaction(pipe);
240 return ENOMEM;
241 }
242
243 /*
244 * Send the data.
245 */
246 int rc = async_data_write_start(pipe->hc_phone, buffer, size);
247
248 /*
249 * Since now on, someone else might access the backing phone
250 * without breaking the transfer IPC protocol.
251 */
252 pipe_end_transaction(pipe);
253
254 if (rc != EOK) {
255 async_wait_for(opening_request, NULL);
256 return rc;
257 }
258
259 /*
260 * Wait for the answer.
261 */
262 sysarg_t opening_request_rc;
263 async_wait_for(opening_request, &opening_request_rc);
264
265 return (int) opening_request_rc;
266}
267
268/** Request a write (out) transfer on an endpoint pipe.
269 *
270 * @param[in] pipe Pipe used for the transfer.
271 * @param[in] buffer Buffer with data to transfer.
272 * @param[in] size Size of the buffer (in bytes).
273 * @return Error code.
274 */
275int usb_pipe_write(usb_pipe_t *pipe,
276 void *buffer, size_t size)
277{
278 assert(pipe);
279
280 if (buffer == NULL) {
281 return EINVAL;
282 }
283
284 if (size == 0) {
285 return EINVAL;
286 }
287
288 if (pipe->direction != USB_DIRECTION_OUT) {
289 return EBADF;
290 }
291
292 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
293 return EBADF;
294 }
295
296 int rc;
297
298 rc = pipe_add_ref(pipe, false);
299 if (rc != EOK) {
300 return rc;
301 }
302
303 rc = usb_pipe_write_no_check(pipe, buffer, size);
304
305 pipe_drop_ref(pipe);
306
307 return rc;
308}
309
310/** Try to clear endpoint halt of default control pipe.
311 *
312 * @param pipe Pipe for control endpoint zero.
313 */
314static void clear_self_endpoint_halt(usb_pipe_t *pipe)
315{
316 assert(pipe != NULL);
317
318 if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
319 return;
320 }
321
322
323 /* Prevent indefinite recursion. */
324 pipe->auto_reset_halt = false;
325 usb_request_clear_endpoint_halt(pipe, 0);
326 pipe->auto_reset_halt = true;
327}
328
329
330/** Request a control read transfer, no checking of input parameters.
331 *
332 * @param[in] pipe Pipe used for the transfer.
333 * @param[in] setup_buffer Buffer with the setup packet.
334 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
335 * @param[out] data_buffer Buffer for incoming data.
336 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
337 * @param[out] data_transfered_size Number of bytes that were actually
338 * transfered during the DATA stage.
339 * @return Error code.
340 */
341static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
342 void *setup_buffer, size_t setup_buffer_size,
343 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
344{
345 /* Ensure serialization over the phone. */
346 pipe_start_transaction(pipe);
347
348 /*
349 * Make call identifying target USB device and control transfer type.
350 */
351 aid_t opening_request = async_send_3(pipe->hc_phone,
352 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_READ,
353 pipe->wire->address, pipe->endpoint_no,
354 NULL);
355 if (opening_request == 0) {
356 return ENOMEM;
357 }
358
359 /*
360 * Send the setup packet.
361 */
362 int rc = async_data_write_start(pipe->hc_phone,
363 setup_buffer, setup_buffer_size);
364 if (rc != EOK) {
365 pipe_end_transaction(pipe);
366 async_wait_for(opening_request, NULL);
367 return rc;
368 }
369
370 /*
371 * Retrieve the data.
372 */
373 ipc_call_t data_request_call;
374 aid_t data_request = async_data_read(pipe->hc_phone,
375 data_buffer, data_buffer_size,
376 &data_request_call);
377
378 /*
379 * Since now on, someone else might access the backing phone
380 * without breaking the transfer IPC protocol.
381 */
382 pipe_end_transaction(pipe);
383
384
385 if (data_request == 0) {
386 async_wait_for(opening_request, NULL);
387 return ENOMEM;
388 }
389
390 /*
391 * Wait for the answer.
392 */
393 sysarg_t data_request_rc;
394 sysarg_t opening_request_rc;
395 async_wait_for(data_request, &data_request_rc);
396 async_wait_for(opening_request, &opening_request_rc);
397
398 if (data_request_rc != EOK) {
399 /* Prefer the return code of the opening request. */
400 if (opening_request_rc != EOK) {
401 return (int) opening_request_rc;
402 } else {
403 return (int) data_request_rc;
404 }
405 }
406 if (opening_request_rc != EOK) {
407 return (int) opening_request_rc;
408 }
409
410 *data_transfered_size = IPC_GET_ARG2(data_request_call);
411
412 return EOK;
413}
414
415/** Request a control read transfer on an endpoint pipe.
416 *
417 * This function encapsulates all three stages of a control transfer.
418 *
419 * @param[in] pipe Pipe used for the transfer.
420 * @param[in] setup_buffer Buffer with the setup packet.
421 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
422 * @param[out] data_buffer Buffer for incoming data.
423 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
424 * @param[out] data_transfered_size Number of bytes that were actually
425 * transfered during the DATA stage.
426 * @return Error code.
427 */
428int usb_pipe_control_read(usb_pipe_t *pipe,
429 void *setup_buffer, size_t setup_buffer_size,
430 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
431{
432 assert(pipe);
433
434 if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
435 return EINVAL;
436 }
437
438 if ((data_buffer == NULL) || (data_buffer_size == 0)) {
439 return EINVAL;
440 }
441
442 if ((pipe->direction != USB_DIRECTION_BOTH)
443 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
444 return EBADF;
445 }
446
447 int rc;
448
449 rc = pipe_add_ref(pipe, false);
450 if (rc != EOK) {
451 return rc;
452 }
453
454 size_t act_size = 0;
455 rc = usb_pipe_control_read_no_check(pipe,
456 setup_buffer, setup_buffer_size,
457 data_buffer, data_buffer_size, &act_size);
458
459 if (rc == ESTALL) {
460 clear_self_endpoint_halt(pipe);
461 }
462
463 pipe_drop_ref(pipe);
464
465 if (rc != EOK) {
466 return rc;
467 }
468
469 if (data_transfered_size != NULL) {
470 *data_transfered_size = act_size;
471 }
472
473 return EOK;
474}
475
476
477/** Request a control write transfer, no checking of input parameters.
478 *
479 * @param[in] pipe Pipe used for the transfer.
480 * @param[in] setup_buffer Buffer with the setup packet.
481 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
482 * @param[in] data_buffer Buffer with data to be sent.
483 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
484 * @return Error code.
485 */
486static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
487 void *setup_buffer, size_t setup_buffer_size,
488 void *data_buffer, size_t data_buffer_size)
489{
490 /* Ensure serialization over the phone. */
491 pipe_start_transaction(pipe);
492
493 /*
494 * Make call identifying target USB device and control transfer type.
495 */
496 aid_t opening_request = async_send_4(pipe->hc_phone,
497 DEV_IFACE_ID(USBHC_DEV_IFACE), IPC_M_USBHC_CONTROL_WRITE,
498 pipe->wire->address, pipe->endpoint_no,
499 data_buffer_size,
500 NULL);
501 if (opening_request == 0) {
502 pipe_end_transaction(pipe);
503 return ENOMEM;
504 }
505
506 /*
507 * Send the setup packet.
508 */
509 int rc = async_data_write_start(pipe->hc_phone,
510 setup_buffer, setup_buffer_size);
511 if (rc != EOK) {
512 pipe_end_transaction(pipe);
513 async_wait_for(opening_request, NULL);
514 return rc;
515 }
516
517 /*
518 * Send the data (if any).
519 */
520 if (data_buffer_size > 0) {
521 rc = async_data_write_start(pipe->hc_phone,
522 data_buffer, data_buffer_size);
523
524 /* All data sent, pipe can be released. */
525 pipe_end_transaction(pipe);
526
527 if (rc != EOK) {
528 async_wait_for(opening_request, NULL);
529 return rc;
530 }
531 } else {
532 /* No data to send, we can release the pipe for others. */
533 pipe_end_transaction(pipe);
534 }
535
536 /*
537 * Wait for the answer.
538 */
539 sysarg_t opening_request_rc;
540 async_wait_for(opening_request, &opening_request_rc);
541
542 return (int) opening_request_rc;
543}
544
545/** Request a control write transfer on an endpoint pipe.
546 *
547 * This function encapsulates all three stages of a control transfer.
548 *
549 * @param[in] pipe Pipe used for the transfer.
550 * @param[in] setup_buffer Buffer with the setup packet.
551 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
552 * @param[in] data_buffer Buffer with data to be sent.
553 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
554 * @return Error code.
555 */
556int usb_pipe_control_write(usb_pipe_t *pipe,
557 void *setup_buffer, size_t setup_buffer_size,
558 void *data_buffer, size_t data_buffer_size)
559{
560 assert(pipe);
561
562 if ((setup_buffer == NULL) || (setup_buffer_size == 0)) {
563 return EINVAL;
564 }
565
566 if ((data_buffer == NULL) && (data_buffer_size > 0)) {
567 return EINVAL;
568 }
569
570 if ((data_buffer != NULL) && (data_buffer_size == 0)) {
571 return EINVAL;
572 }
573
574 if ((pipe->direction != USB_DIRECTION_BOTH)
575 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
576 return EBADF;
577 }
578
579 int rc;
580
581 rc = pipe_add_ref(pipe, false);
582 if (rc != EOK) {
583 return rc;
584 }
585
586 rc = usb_pipe_control_write_no_check(pipe,
587 setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
588
589 if (rc == ESTALL) {
590 clear_self_endpoint_halt(pipe);
591 }
592
593 pipe_drop_ref(pipe);
594
595 return rc;
596}
597
598
599/**
600 * @}
601 */
Note: See TracBrowser for help on using the repository browser.