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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d8b275d 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
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 "pipepriv.h"
52
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 */
61static int usb_pipe_read_no_checks(usb_pipe_t *pipe,
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;
74 case USB_TRANSFER_BULK:
75 ipc_method = IPC_M_USBHC_BULK_IN;
76 break;
77 default:
78 return ENOTSUP;
79 }
80
81 /* Ensure serialization over the phone. */
82 pipe_start_transaction(pipe);
83
84 /*
85 * Make call identifying target USB device and type of transfer.
86 */
87 aid_t opening_request = async_send_3(pipe->hc_phone,
88 DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
89 pipe->wire->address, pipe->endpoint_no,
90 NULL);
91 if (opening_request == 0) {
92 pipe_end_transaction(pipe);
93 return ENOMEM;
94 }
95
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
103 /*
104 * Since now on, someone else might access the backing phone
105 * without breaking the transfer IPC protocol.
106 */
107 pipe_end_transaction(pipe);
108
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;
116 }
117
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) {
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 }
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
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 */
152int usb_pipe_read(usb_pipe_t *pipe,
153 void *buffer, size_t size, size_t *size_transfered)
154{
155 assert(pipe);
156
157 if (buffer == NULL) {
158 return EINVAL;
159 }
160
161 if (size == 0) {
162 return EINVAL;
163 }
164
165 if (pipe->direction != USB_DIRECTION_IN) {
166 return EBADF;
167 }
168
169 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
170 return EBADF;
171 }
172
173 int rc;
174 rc = pipe_add_ref(pipe);
175 if (rc != EOK) {
176 return rc;
177 }
178
179
180 size_t act_size = 0;
181
182 rc = usb_pipe_read_no_checks(pipe, buffer, size, &act_size);
183
184 pipe_drop_ref(pipe);
185
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 */
207static int usb_pipe_write_no_check(usb_pipe_t *pipe,
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;
216 switch (pipe->transfer_type) {
217 case USB_TRANSFER_INTERRUPT:
218 ipc_method = IPC_M_USBHC_INTERRUPT_OUT;
219 break;
220 case USB_TRANSFER_BULK:
221 ipc_method = IPC_M_USBHC_BULK_OUT;
222 break;
223 default:
224 return ENOTSUP;
225 }
226
227 /* Ensure serialization over the phone. */
228 pipe_start_transaction(pipe);
229
230 /*
231 * Make call identifying target USB device and type of transfer.
232 */
233 aid_t opening_request = async_send_3(pipe->hc_phone,
234 DEV_IFACE_ID(USBHC_DEV_IFACE), ipc_method,
235 pipe->wire->address, pipe->endpoint_no,
236 NULL);
237 if (opening_request == 0) {
238 pipe_end_transaction(pipe);
239 return ENOMEM;
240 }
241
242 /*
243 * Send the data.
244 */
245 int rc = async_data_write_start(pipe->hc_phone, buffer, size);
246
247 /*
248 * Since now on, someone else might access the backing phone
249 * without breaking the transfer IPC protocol.
250 */
251 pipe_end_transaction(pipe);
252
253 if (rc != EOK) {
254 async_wait_for(opening_request, NULL);
255 return rc;
256 }
257
258 /*
259 * Wait for the answer.
260 */
261 sysarg_t opening_request_rc;
262 async_wait_for(opening_request, &opening_request_rc);
263
264 return (int) opening_request_rc;
265}
266
267/** Request a write (out) transfer on an endpoint pipe.
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 */
274int usb_pipe_write(usb_pipe_t *pipe,
275 void *buffer, size_t size)
276{
277 assert(pipe);
278
279 if (buffer == NULL) {
280 return EINVAL;
281 }
282
283 if (size == 0) {
284 return EINVAL;
285 }
286
287 if (pipe->direction != USB_DIRECTION_OUT) {
288 return EBADF;
289 }
290
291 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
292 return EBADF;
293 }
294
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);
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 */
321static int usb_pipe_control_read_no_check(usb_pipe_t *pipe,
322 void *setup_buffer, size_t setup_buffer_size,
323 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
324{
325 /* Ensure serialization over the phone. */
326 pipe_start_transaction(pipe);
327
328 /*
329 * Make call identifying target USB device and control transfer type.
330 */
331 aid_t opening_request = async_send_3(pipe->hc_phone,
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;
337 }
338
339 /*
340 * Send the setup packet.
341 */
342 int rc = async_data_write_start(pipe->hc_phone,
343 setup_buffer, setup_buffer_size);
344 if (rc != EOK) {
345 pipe_end_transaction(pipe);
346 async_wait_for(opening_request, NULL);
347 return rc;
348 }
349
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);
357
358 /*
359 * Since now on, someone else might access the backing phone
360 * without breaking the transfer IPC protocol.
361 */
362 pipe_end_transaction(pipe);
363
364
365 if (data_request == 0) {
366 async_wait_for(opening_request, NULL);
367 return ENOMEM;
368 }
369
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) {
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 }
385 }
386 if (opening_request_rc != EOK) {
387 return (int) opening_request_rc;
388 }
389
390 *data_transfered_size = IPC_GET_ARG2(data_request_call);
391
392 return EOK;
393}
394
395/** Request a control read transfer on an endpoint pipe.
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 */
408int usb_pipe_control_read(usb_pipe_t *pipe,
409 void *setup_buffer, size_t setup_buffer_size,
410 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
411{
412 assert(pipe);
413
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
422 if ((pipe->direction != USB_DIRECTION_BOTH)
423 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
424 return EBADF;
425 }
426
427 int rc;
428
429 rc = pipe_add_ref(pipe);
430 if (rc != EOK) {
431 return rc;
432 }
433
434 size_t act_size = 0;
435 rc = usb_pipe_control_read_no_check(pipe,
436 setup_buffer, setup_buffer_size,
437 data_buffer, data_buffer_size, &act_size);
438
439 pipe_drop_ref(pipe);
440
441 if (rc != EOK) {
442 return rc;
443 }
444
445 if (data_transfered_size != NULL) {
446 *data_transfered_size = act_size;
447 }
448
449 return EOK;
450}
451
452
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 */
462static int usb_pipe_control_write_no_check(usb_pipe_t *pipe,
463 void *setup_buffer, size_t setup_buffer_size,
464 void *data_buffer, size_t data_buffer_size)
465{
466 /* Ensure serialization over the phone. */
467 pipe_start_transaction(pipe);
468
469 /*
470 * Make call identifying target USB device and control transfer type.
471 */
472 aid_t opening_request = async_send_4(pipe->hc_phone,
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) {
478 pipe_end_transaction(pipe);
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) {
488 pipe_end_transaction(pipe);
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);
499
500 /* All data sent, pipe can be released. */
501 pipe_end_transaction(pipe);
502
503 if (rc != EOK) {
504 async_wait_for(opening_request, NULL);
505 return rc;
506 }
507 } else {
508 /* No data to send, we can release the pipe for others. */
509 pipe_end_transaction(pipe);
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
521/** Request a control write transfer on an endpoint pipe.
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 */
532int usb_pipe_control_write(usb_pipe_t *pipe,
533 void *setup_buffer, size_t setup_buffer_size,
534 void *data_buffer, size_t data_buffer_size)
535{
536 assert(pipe);
537
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
550 if ((pipe->direction != USB_DIRECTION_BOTH)
551 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
552 return EBADF;
553 }
554
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,
563 setup_buffer, setup_buffer_size, data_buffer, data_buffer_size);
564
565 pipe_drop_ref(pipe);
566
567 return rc;
568}
569
570
571/**
572 * @}
573 */
Note: See TracBrowser for help on using the repository browser.