source: mainline/uspace/lib/usb/src/pipes.c@ 52fb76e

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

Bare initialization of device connection struct

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