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

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

Max packet size actually sent over IPC

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