source: mainline/uspace/lib/usb/src/pipes.c@ 2a11192

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

Fix phone leakage

  • Property mode set to 100644
File size: 14.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 * Communication between device drivers and host controller driver.
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 * The initialization functions may actually involve contacting some other
39 * task, starting/ending a session might involve asynchronous IPC and since
40 * the transfer functions uses IPC, asynchronous nature of them is obvious.
41 * The pseudo synchronous versions for the transfers internally call the
42 * asynchronous ones and so fibril switch is possible in them as well.
43 */
44#include <usb/usb.h>
45#include <usb/pipes.h>
46#include <errno.h>
47#include <assert.h>
48#include <usb/usbdrv.h>
49
50#define _PREPARE_TARGET(varname, pipe) \
51 usb_target_t varname = { \
52 .address = (pipe)->wire->address, \
53 .endpoint = (pipe)->endpoint_no \
54 }
55
56/** Initialize connection to USB device.
57 *
58 * @param connection Connection structure to be initialized.
59 * @param device Generic device backing the USB device.
60 * @return Error code.
61 */
62int usb_device_connection_initialize_from_device(
63 usb_device_connection_t *connection, device_t *device)
64{
65 assert(connection);
66 assert(device);
67
68 int rc;
69 devman_handle_t hc_handle;
70 usb_address_t my_address;
71
72 rc = usb_drv_find_hc(device, &hc_handle);
73 if (rc != EOK) {
74 return rc;
75 }
76
77 int hc_phone = devman_device_connect(hc_handle, 0);
78 if (hc_phone < 0) {
79 return hc_phone;
80 }
81
82 my_address = usb_drv_get_my_address(hc_phone, device);
83 if (my_address < 0) {
84 rc = my_address;
85 goto leave;
86 }
87
88 rc = usb_device_connection_initialize(connection,
89 hc_handle, my_address);
90
91leave:
92 ipc_hangup(hc_phone);
93 return rc;
94}
95
96/** Initialize connection to USB device.
97 *
98 * @param connection Connection structure to be initialized.
99 * @param host_controller_handle Devman handle of host controller device is
100 * connected to.
101 * @param device_address Device USB address.
102 * @return Error code.
103 */
104int usb_device_connection_initialize(usb_device_connection_t *connection,
105 devman_handle_t host_controller_handle, usb_address_t device_address)
106{
107 assert(connection);
108
109 if ((device_address < 0) || (device_address >= USB11_ADDRESS_MAX)) {
110 return EINVAL;
111 }
112
113 connection->hc_handle = host_controller_handle;
114 connection->address = device_address;
115
116 return EOK;
117}
118
119/** Initialize USB endpoint pipe.
120 *
121 * @param pipe Endpoint pipe to be initialized.
122 * @param connection Connection to the USB device backing this pipe (the wire).
123 * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15).
124 * @param transfer_type Transfer type (e.g. interrupt or bulk).
125 * @param direction Endpoint direction (in/out).
126 * @return Error code.
127 */
128int usb_endpoint_pipe_initialize(usb_endpoint_pipe_t *pipe,
129 usb_device_connection_t *connection, usb_endpoint_t endpoint_no,
130 usb_transfer_type_t transfer_type, usb_direction_t direction)
131{
132 assert(pipe);
133 assert(connection);
134
135 pipe->wire = connection;
136 pipe->hc_phone = -1;
137 pipe->endpoint_no = endpoint_no;
138 pipe->transfer_type = transfer_type;
139 pipe->direction = direction;
140
141 return EOK;
142}
143
144
145/** Initialize USB endpoint pipe as the default zero control pipe.
146 *
147 * @param pipe Endpoint pipe to be initialized.
148 * @param connection Connection to the USB device backing this pipe (the wire).
149 * @return Error code.
150 */
151int usb_endpoint_pipe_initialize_default_control(usb_endpoint_pipe_t *pipe,
152 usb_device_connection_t *connection)
153{
154 assert(pipe);
155 assert(connection);
156
157 int rc = usb_endpoint_pipe_initialize(pipe, connection,
158 0, USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH);
159
160 return rc;
161}
162
163
164/** Start a session on the endpoint pipe.
165 *
166 * A session is something inside what any communication occurs.
167 * It is expected that sessions would be started right before the transfer
168 * and ended - see usb_endpoint_pipe_end_session() - after the last
169 * transfer.
170 * The reason for this is that session actually opens some communication
171 * channel to the host controller (or to the physical hardware if you
172 * wish) and thus it involves acquiring kernel resources.
173 * Since they are limited, sessions shall not be longer than strictly
174 * necessary.
175 *
176 * @param pipe Endpoint pipe to start the session on.
177 * @return Error code.
178 */
179int usb_endpoint_pipe_start_session(usb_endpoint_pipe_t *pipe)
180{
181 assert(pipe);
182
183 if (pipe->hc_phone >= 0) {
184 return EBUSY;
185 }
186
187 int phone = devman_device_connect(pipe->wire->hc_handle, 0);
188 if (phone < 0) {
189 return phone;
190 }
191
192 pipe->hc_phone = phone;
193
194 return EOK;
195}
196
197
198/** Ends a session on the endpoint pipe.
199 *
200 * @see usb_endpoint_pipe_start_session
201 *
202 * @param pipe Endpoint pipe to end the session on.
203 * @return Error code.
204 */
205int usb_endpoint_pipe_end_session(usb_endpoint_pipe_t *pipe)
206{
207 assert(pipe);
208
209 if (pipe->hc_phone < 0) {
210 return ENOENT;
211 }
212
213 int rc = ipc_hangup(pipe->hc_phone);
214 if (rc != EOK) {
215 return rc;
216 }
217
218 pipe->hc_phone = -1;
219
220 return EOK;
221}
222
223
224/** Request a read (in) transfer on an endpoint pipe.
225 *
226 * @param[in] pipe Pipe used for the transfer.
227 * @param[out] buffer Buffer where to store the data.
228 * @param[in] size Size of the buffer (in bytes).
229 * @param[out] size_transfered Number of bytes that were actually transfered.
230 * @return Error code.
231 */
232int usb_endpoint_pipe_read(usb_endpoint_pipe_t *pipe,
233 void *buffer, size_t size, size_t *size_transfered)
234{
235 assert(pipe);
236
237 int rc;
238 usb_handle_t handle;
239
240 rc = usb_endpoint_pipe_async_read(pipe, buffer, size, size_transfered,
241 &handle);
242 if (rc != EOK) {
243 return rc;
244 }
245
246 rc = usb_endpoint_pipe_wait_for(pipe, handle);
247 return rc;
248}
249
250/** Request a write (out) transfer on an endpoint pipe.
251 *
252 * @param[in] pipe Pipe used for the transfer.
253 * @param[in] buffer Buffer with data to transfer.
254 * @param[in] size Size of the buffer (in bytes).
255 * @return Error code.
256 */
257int usb_endpoint_pipe_write(usb_endpoint_pipe_t *pipe,
258 void *buffer, size_t size)
259{
260 assert(pipe);
261
262 int rc;
263 usb_handle_t handle;
264
265 rc = usb_endpoint_pipe_async_write(pipe, buffer, size, &handle);
266 if (rc != EOK) {
267 return rc;
268 }
269
270 rc = usb_endpoint_pipe_wait_for(pipe, handle);
271 return rc;
272}
273
274
275/** Request a control read transfer on an endpoint pipe.
276 *
277 * This function encapsulates all three stages of a control transfer.
278 *
279 * @param[in] pipe Pipe used for the transfer.
280 * @param[in] setup_buffer Buffer with the setup packet.
281 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
282 * @param[out] data_buffer Buffer for incoming data.
283 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
284 * @param[out] data_transfered_size Number of bytes that were actually
285 * transfered during the DATA stage.
286 * @return Error code.
287 */
288int usb_endpoint_pipe_control_read(usb_endpoint_pipe_t *pipe,
289 void *setup_buffer, size_t setup_buffer_size,
290 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
291{
292 assert(pipe);
293
294 int rc;
295 usb_handle_t handle;
296
297 rc = usb_endpoint_pipe_async_control_read(pipe,
298 setup_buffer, setup_buffer_size,
299 data_buffer, data_buffer_size, data_transfered_size,
300 &handle);
301 if (rc != EOK) {
302 return rc;
303 }
304
305 rc = usb_endpoint_pipe_wait_for(pipe, handle);
306 return rc;
307}
308
309
310/** Request a control write transfer on an endpoint pipe.
311 *
312 * This function encapsulates all three stages of a control transfer.
313 *
314 * @param[in] pipe Pipe used for the transfer.
315 * @param[in] setup_buffer Buffer with the setup packet.
316 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
317 * @param[in] data_buffer Buffer with data to be sent.
318 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
319 * @return Error code.
320 */
321int usb_endpoint_pipe_control_write(usb_endpoint_pipe_t *pipe,
322 void *setup_buffer, size_t setup_buffer_size,
323 void *data_buffer, size_t data_buffer_size)
324{
325 assert(pipe);
326
327 int rc;
328 usb_handle_t handle;
329
330 rc = usb_endpoint_pipe_async_control_write(pipe,
331 setup_buffer, setup_buffer_size,
332 data_buffer, data_buffer_size,
333 &handle);
334 if (rc != EOK) {
335 return rc;
336 }
337
338 rc = usb_endpoint_pipe_wait_for(pipe, handle);
339 return rc;
340}
341
342
343/** Request a read (in) transfer on an endpoint pipe (asynchronous version).
344 *
345 * @param[in] pipe Pipe used for the transfer.
346 * @param[out] buffer Buffer where to store the data.
347 * @param[in] size Size of the buffer (in bytes).
348 * @param[out] size_transfered Number of bytes that were actually transfered.
349 * @param[out] handle Handle of the transfer.
350 * @return Error code.
351 */
352int usb_endpoint_pipe_async_read(usb_endpoint_pipe_t *pipe,
353 void *buffer, size_t size, size_t *size_transfered,
354 usb_handle_t *handle)
355{
356 assert(pipe);
357
358 if (pipe->hc_phone < 0) {
359 return EBADF;
360 }
361
362 if (pipe->direction != USB_DIRECTION_IN) {
363 return EBADF;
364 }
365
366 int rc;
367 _PREPARE_TARGET(target, pipe);
368
369 switch (pipe->transfer_type) {
370 case USB_TRANSFER_INTERRUPT:
371 rc = usb_drv_async_interrupt_in(pipe->hc_phone, target,
372 buffer, size, size_transfered, handle);
373 break;
374 case USB_TRANSFER_CONTROL:
375 rc = EBADF;
376 break;
377 default:
378 rc = ENOTSUP;
379 break;
380 }
381
382 return rc;
383}
384
385
386/** Request a write (out) transfer on an endpoint pipe (asynchronous version).
387 *
388 * @param[in] pipe Pipe used for the transfer.
389 * @param[in] buffer Buffer with data to transfer.
390 * @param[in] size Size of the buffer (in bytes).
391 * @param[out] handle Handle of the transfer.
392 * @return Error code.
393 */
394int usb_endpoint_pipe_async_write(usb_endpoint_pipe_t *pipe,
395 void *buffer, size_t size,
396 usb_handle_t *handle)
397{
398 assert(pipe);
399
400 if (pipe->hc_phone < 0) {
401 return EBADF;
402 }
403
404 if (pipe->direction != USB_DIRECTION_OUT) {
405 return EBADF;
406 }
407
408 int rc;
409 _PREPARE_TARGET(target, pipe);
410
411 switch (pipe->transfer_type) {
412 case USB_TRANSFER_INTERRUPT:
413 rc = usb_drv_async_interrupt_out(pipe->hc_phone, target,
414 buffer, size, handle);
415 break;
416 case USB_TRANSFER_CONTROL:
417 rc = EBADF;
418 break;
419 default:
420 rc = ENOTSUP;
421 break;
422 }
423
424 return rc;
425}
426
427
428/** Request a control read transfer on an endpoint pipe (asynchronous version).
429 *
430 * This function encapsulates all three stages of a control transfer.
431 *
432 * @param[in] pipe Pipe used for the transfer.
433 * @param[in] setup_buffer Buffer with the setup packet.
434 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
435 * @param[out] data_buffer Buffer for incoming data.
436 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
437 * @param[out] data_transfered_size Number of bytes that were actually
438 * transfered during the DATA stage.
439 * @param[out] handle Handle of the transfer.
440 * @return Error code.
441 */
442int usb_endpoint_pipe_async_control_read(usb_endpoint_pipe_t *pipe,
443 void *setup_buffer, size_t setup_buffer_size,
444 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size,
445 usb_handle_t *handle)
446{
447 assert(pipe);
448
449 if (pipe->hc_phone < 0) {
450 return EBADF;
451 }
452
453 if ((pipe->direction != USB_DIRECTION_BOTH)
454 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
455 return EBADF;
456 }
457
458 int rc;
459 _PREPARE_TARGET(target, pipe);
460
461 rc = usb_drv_async_control_read(pipe->hc_phone, target,
462 setup_buffer, setup_buffer_size,
463 data_buffer, data_buffer_size, data_transfered_size,
464 handle);
465
466 return rc;
467}
468
469
470/** Request a control write transfer on an endpoint pipe (asynchronous version).
471 *
472 * This function encapsulates all three stages of a control transfer.
473 *
474 * @param[in] pipe Pipe used for the transfer.
475 * @param[in] setup_buffer Buffer with the setup packet.
476 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
477 * @param[in] data_buffer Buffer with data to be sent.
478 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
479 * @param[out] handle Handle of the transfer.
480 * @return Error code.
481 */
482int usb_endpoint_pipe_async_control_write(usb_endpoint_pipe_t *pipe,
483 void *setup_buffer, size_t setup_buffer_size,
484 void *data_buffer, size_t data_buffer_size,
485 usb_handle_t *handle)
486{
487 assert(pipe);
488
489 if (pipe->hc_phone < 0) {
490 return EBADF;
491 }
492
493 if ((pipe->direction != USB_DIRECTION_BOTH)
494 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
495 return EBADF;
496 }
497
498 int rc;
499 _PREPARE_TARGET(target, pipe);
500
501 rc = usb_drv_async_control_write(pipe->hc_phone, target,
502 setup_buffer, setup_buffer_size,
503 data_buffer, data_buffer_size,
504 handle);
505
506 return rc;
507}
508
509/** Wait for transfer completion.
510 *
511 * The function blocks the caller fibril until the transfer associated
512 * with given @p handle is completed.
513 *
514 * @param[in] pipe Pipe the transfer executed on.
515 * @param[in] handle Transfer handle.
516 * @return Error code.
517 */
518int usb_endpoint_pipe_wait_for(usb_endpoint_pipe_t *pipe, usb_handle_t handle)
519{
520 return usb_drv_async_wait_for(handle);
521}
522
523
524/**
525 * @}
526 */
Note: See TracBrowser for help on using the repository browser.