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

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

Rename usb_endpoint_pipe_*() ⇒ usb_pipe_*()

No change in functionality.

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