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

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

Add bulk transfers to libusb

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