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

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

Pipe API independent of the old one

The low IPC level was copied from the old API, modified and also
fortified.

This is a first step towards complete removal of the old API.

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