source: mainline/uspace/lib/usbdev/src/pipesio.c@ 365e29e2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 365e29e2 was 365e29e2, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

usb: Use new target packing scheme for IPC.

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