source: mainline/uspace/lib/usbdev/src/pipes.c@ ab5ea5b5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ab5ea5b5 was 47dfb34, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

libusbdev: Implement pipe long transfers.

  • Property mode set to 100644
File size: 9.7 KB
RevLine 
[6865243c]1/*
2 * Copyright (c) 2011 Vojtech Horky
[bd575647]3 * Copyright (c) 2011 Jan Vesely
[6865243c]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
[160b75e]29/** @addtogroup libusbdev
[6865243c]30 * @{
31 */
32/** @file
[dc04868]33 * USB endpoint pipes miscellaneous functions.
[6865243c]34 */
[357a302]35#include <usb_iface.h>
[bd575647]36#include <usb/dev/pipes.h>
[023a902]37#include <usb/dev/request.h>
[6865243c]38#include <errno.h>
[43f698b]39#include <assert.h>
[563fb40]40
[27a0012]41/** Tell USB interface assigned to given device.
42 *
43 * @param device Device in question.
[56bdd9a4]44 * @return Error code (ENOTSUP means any).
[27a0012]45 */
[8e5ce07]46int usb_device_get_assigned_interface(const ddf_dev_t *device)
[27a0012]47{
[7fc260ff]48 assert(device);
[79ae36dd]49 async_sess_t *parent_sess =
[9f7276d]50 devman_parent_device_connect(EXCHANGE_ATOMIC, device->handle,
[27a0012]51 IPC_FLAG_BLOCKING);
[79ae36dd]52 if (!parent_sess)
[56bdd9a4]53 return ENOMEM;
54
[79ae36dd]55 async_exch_t *exch = async_exchange_begin(parent_sess);
[56bdd9a4]56 if (!exch) {
57 async_hangup(parent_sess);
58 return ENOMEM;
59 }
60
61 int iface_no;
62 const int ret = usb_get_my_interface(exch, &iface_no);
63
64 return ret == EOK ? iface_no : ret;
[27a0012]65}
[023a902]66/*----------------------------------------------------------------------------*/
[e9ce696]67/** Prepare pipe for a long transfer.
68 *
69 * By a long transfer is mean transfer consisting of several
70 * requests to the HC.
71 * Calling such function is optional and it has positive effect of
72 * improved performance because IPC session is initiated only once.
73 *
74 * @param pipe Pipe over which the transfer will happen.
75 * @return Error code.
76 */
[47dfb34]77int usb_pipe_start_long_transfer(usb_pipe_t *pipe)
[e9ce696]78{
[47dfb34]79 assert(pipe);
80 assert(pipe->wire);
81 assert(pipe->wire->hc_connection);
82 return usb_hc_connection_open(pipe->wire->hc_connection);
[e9ce696]83}
[023a902]84/*----------------------------------------------------------------------------*/
[e9ce696]85/** Terminate a long transfer on a pipe.
86 *
87 * @see usb_pipe_start_long_transfer
88 *
89 * @param pipe Pipe where to end the long transfer.
90 */
[47dfb34]91int usb_pipe_end_long_transfer(usb_pipe_t *pipe)
[e9ce696]92{
[47dfb34]93 assert(pipe);
94 assert(pipe->wire);
95 assert(pipe->wire->hc_connection);
96 return usb_hc_connection_close(pipe->wire->hc_connection);
[e9ce696]97}
[023a902]98/*----------------------------------------------------------------------------*/
99/** Request an in transfer, no checking of input parameters.
100 *
101 * @param[in] pipe Pipe used for the transfer.
102 * @param[out] buffer Buffer where to store the data.
103 * @param[in] size Size of the buffer (in bytes).
104 * @param[out] size_transfered Number of bytes that were actually transfered.
105 * @return Error code.
106 */
107static int usb_pipe_read_no_check(usb_pipe_t *pipe, uint64_t setup,
108 void *buffer, size_t size, size_t *size_transfered)
109{
110 /* Isochronous transfer are not supported (yet) */
111 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
112 pipe->transfer_type != USB_TRANSFER_BULK &&
113 pipe->transfer_type != USB_TRANSFER_CONTROL)
114 return ENOTSUP;
115
116 return usb_hc_control_read(pipe->wire->hc_connection,
117 pipe->wire->address, pipe->endpoint_no, setup, buffer, size,
118 size_transfered);
119}
120/*----------------------------------------------------------------------------*/
121/** Request an out transfer, no checking of input parameters.
122 *
123 * @param[in] pipe Pipe used for the transfer.
124 * @param[in] buffer Buffer with data to transfer.
125 * @param[in] size Size of the buffer (in bytes).
126 * @return Error code.
127 */
128static int usb_pipe_write_no_check(usb_pipe_t *pipe, uint64_t setup,
129 const void *buffer, size_t size)
130{
131 /* Only interrupt and bulk transfers are supported */
132 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
133 pipe->transfer_type != USB_TRANSFER_BULK &&
134 pipe->transfer_type != USB_TRANSFER_CONTROL)
135 return ENOTSUP;
[e9ce696]136
[023a902]137 return usb_hc_control_write(pipe->wire->hc_connection,
138 pipe->wire->address, pipe->endpoint_no, setup, buffer, size);
139}
140/*----------------------------------------------------------------------------*/
141/** Try to clear endpoint halt of default control pipe.
142 *
143 * @param pipe Pipe for control endpoint zero.
144 */
145static void clear_self_endpoint_halt(usb_pipe_t *pipe)
146{
147 assert(pipe != NULL);
148
149 if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
150 return;
151 }
152
153
154 /* Prevent infinite recursion. */
155 pipe->auto_reset_halt = false;
156 usb_request_clear_endpoint_halt(pipe, 0);
157 pipe->auto_reset_halt = true;
158}
159/*----------------------------------------------------------------------------*/
160/** Request a control read transfer on an endpoint pipe.
161 *
162 * This function encapsulates all three stages of a control transfer.
163 *
164 * @param[in] pipe Pipe used for the transfer.
165 * @param[in] setup_buffer Buffer with the setup packet.
166 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
167 * @param[out] data_buffer Buffer for incoming data.
168 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
169 * @param[out] data_transfered_size Number of bytes that were actually
170 * transfered during the DATA stage.
171 * @return Error code.
172 */
173int usb_pipe_control_read(usb_pipe_t *pipe,
174 const void *setup_buffer, size_t setup_buffer_size,
175 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
176{
177 assert(pipe);
178
179 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
180 return EINVAL;
181 }
182
183 if ((data_buffer == NULL) || (data_buffer_size == 0)) {
184 return EINVAL;
185 }
186
187 if ((pipe->direction != USB_DIRECTION_BOTH)
188 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
189 return EBADF;
190 }
191
192 uint64_t setup_packet;
193 memcpy(&setup_packet, setup_buffer, 8);
194
195 size_t act_size = 0;
196 const int rc = usb_pipe_read_no_check(pipe, setup_packet,
197 data_buffer, data_buffer_size, &act_size);
198
199 if (rc == ESTALL) {
200 clear_self_endpoint_halt(pipe);
201 }
202
203 if (rc == EOK && data_transfered_size != NULL) {
204 *data_transfered_size = act_size;
205 }
206
207 return rc;
208}
209/*----------------------------------------------------------------------------*/
210/** Request a control write transfer on an endpoint pipe.
211 *
212 * This function encapsulates all three stages of a control transfer.
213 *
214 * @param[in] pipe Pipe used for the transfer.
215 * @param[in] setup_buffer Buffer with the setup packet.
216 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
217 * @param[in] data_buffer Buffer with data to be sent.
218 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
219 * @return Error code.
220 */
221int usb_pipe_control_write(usb_pipe_t *pipe,
222 const void *setup_buffer, size_t setup_buffer_size,
223 const void *data_buffer, size_t data_buffer_size)
224{
225 assert(pipe);
226
227 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
228 return EINVAL;
229 }
230
231 if ((data_buffer == NULL) && (data_buffer_size > 0)) {
232 return EINVAL;
233 }
234
235 if ((data_buffer != NULL) && (data_buffer_size == 0)) {
236 return EINVAL;
237 }
238
239 if ((pipe->direction != USB_DIRECTION_BOTH)
240 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
241 return EBADF;
242 }
243
244 uint64_t setup_packet;
245 memcpy(&setup_packet, setup_buffer, 8);
246
247 const int rc = usb_pipe_write_no_check(pipe, setup_packet,
248 data_buffer, data_buffer_size);
249
250 if (rc == ESTALL) {
251 clear_self_endpoint_halt(pipe);
252 }
253
254 return rc;
255}
256/*----------------------------------------------------------------------------*/
257/** Request a read (in) transfer on an endpoint pipe.
258 *
259 * @param[in] pipe Pipe used for the transfer.
260 * @param[out] buffer Buffer where to store the data.
261 * @param[in] size Size of the buffer (in bytes).
262 * @param[out] size_transfered Number of bytes that were actually transfered.
263 * @return Error code.
264 */
265int usb_pipe_read(usb_pipe_t *pipe,
266 void *buffer, size_t size, size_t *size_transfered)
267{
268 assert(pipe);
269
270 if (buffer == NULL) {
271 return EINVAL;
272 }
273
274 if (size == 0) {
275 return EINVAL;
276 }
277
278 if (pipe->direction != USB_DIRECTION_IN) {
279 return EBADF;
280 }
281
282 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
283 return EBADF;
284 }
285
286 size_t act_size = 0;
287 const int rc = usb_pipe_read_no_check(pipe, 0, buffer, size, &act_size);
288
289
290 if (rc == EOK && size_transfered != NULL) {
291 *size_transfered = act_size;
292 }
293
294 return rc;
295}
296/*----------------------------------------------------------------------------*/
297/** Request a write (out) transfer on an endpoint pipe.
298 *
299 * @param[in] pipe Pipe used for the transfer.
300 * @param[in] buffer Buffer with data to transfer.
301 * @param[in] size Size of the buffer (in bytes).
302 * @return Error code.
303 */
304int usb_pipe_write(usb_pipe_t *pipe, const void *buffer, size_t size)
305{
306 assert(pipe);
307
308 if (buffer == NULL || size == 0) {
309 return EINVAL;
310 }
311
312 if (pipe->direction != USB_DIRECTION_OUT) {
313 return EBADF;
314 }
315
316 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
317 return EBADF;
318 }
319
320 return usb_pipe_write_no_check(pipe, 0, buffer, size);
321}
[6865243c]322/**
323 * @}
324 */
Note: See TracBrowser for help on using the repository browser.