source: mainline/uspace/lib/usbdev/src/pipesio.c@ a045ab1

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

libusbdev: Reorder functions in pipesio.c

  • Property mode set to 100644
File size: 8.8 KB
RevLine 
[dc04868]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
[160b75e]29/** @addtogroup libusbdev
[dc04868]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.
[47c573a]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).
[dc04868]45 */
[79ae36dd]46
[dc04868]47#include <usb/usb.h>
[7d521e24]48#include <usb/dev/pipes.h>
[dc04868]49#include <errno.h>
50#include <assert.h>
[47c573a]51#include <usbhc_iface.h>
[7d521e24]52#include <usb/dev/request.h>
[79ae36dd]53#include <async.h>
[a546687]54#include "pipepriv.h"
[d5ac90f]55
[47c573a]56/** Request an in transfer, no checking of input parameters.
57 *
58 * @param[in] pipe Pipe used for the transfer.
59 * @param[out] buffer Buffer where to store the data.
60 * @param[in] size Size of the buffer (in bytes).
61 * @param[out] size_transfered Number of bytes that were actually transfered.
62 * @return Error code.
63 */
[b4292e7]64static int usb_pipe_read_no_check(usb_pipe_t *pipe, uint64_t setup,
[47c573a]65 void *buffer, size_t size, size_t *size_transfered)
66{
[8969f46]67 /* Isochronous transfer are not supported (yet) */
[365e29e2]68 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
[b4292e7]69 pipe->transfer_type != USB_TRANSFER_BULK &&
70 pipe->transfer_type != USB_TRANSFER_CONTROL)
[365e29e2]71 return ENOTSUP;
72
[8969f46]73 int ret = pipe_add_ref(pipe, false);
74 if (ret != EOK) {
75 return ret;
76 }
77
[d5ac90f]78 /* Ensure serialization over the phone. */
[d48fcc0]79 pipe_start_transaction(pipe);
[79ae36dd]80 async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
[02fc5c4]81 if (!exch) {
[d48fcc0]82 pipe_end_transaction(pipe);
[8969f46]83 pipe_drop_ref(pipe);
[47c573a]84 return ENOMEM;
85 }
[02fc5c4]86
[8969f46]87 ret = usbhc_read(exch, pipe->wire->address, pipe->endpoint_no,
[b4292e7]88 setup, buffer, size, size_transfered);
[79ae36dd]89 async_exchange_end(exch);
[d48fcc0]90 pipe_end_transaction(pipe);
[8969f46]91 pipe_drop_ref(pipe);
[02fc5c4]92 return ret;
[47c573a]93}
94
95/** Request an out transfer, no checking of input parameters.
96 *
97 * @param[in] pipe Pipe used for the transfer.
98 * @param[in] buffer Buffer with data to transfer.
99 * @param[in] size Size of the buffer (in bytes).
100 * @return Error code.
101 */
[b4292e7]102static int usb_pipe_write_no_check(usb_pipe_t *pipe, uint64_t setup,
103 const void *buffer, size_t size)
[47c573a]104{
[365e29e2]105 /* Only interrupt and bulk transfers are supported */
106 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT &&
[b4292e7]107 pipe->transfer_type != USB_TRANSFER_BULK &&
108 pipe->transfer_type != USB_TRANSFER_CONTROL)
[365e29e2]109 return ENOTSUP;
110
[8969f46]111 int ret = pipe_add_ref(pipe, false);
112 if (ret != EOK) {
113 return ret;
114 }
115
[d5ac90f]116 /* Ensure serialization over the phone. */
[d48fcc0]117 pipe_start_transaction(pipe);
[79ae36dd]118 async_exch_t *exch = async_exchange_begin(pipe->hc_sess);
[02fc5c4]119 if (!exch) {
[d48fcc0]120 pipe_end_transaction(pipe);
[8969f46]121 pipe_drop_ref(pipe);
[47c573a]122 return ENOMEM;
123 }
[8969f46]124 ret = usbhc_write(exch, pipe->wire->address, pipe->endpoint_no,
[b4292e7]125 setup, buffer, size);
[79ae36dd]126 async_exchange_end(exch);
[d48fcc0]127 pipe_end_transaction(pipe);
[8969f46]128 pipe_drop_ref(pipe);
[02fc5c4]129 return ret;
[dc04868]130}
131
[fa0f53b]132/** Try to clear endpoint halt of default control pipe.
133 *
134 * @param pipe Pipe for control endpoint zero.
135 */
136static void clear_self_endpoint_halt(usb_pipe_t *pipe)
137{
138 assert(pipe != NULL);
139
140 if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) {
141 return;
142 }
143
144
[b4292e7]145 /* Prevent infinite recursion. */
[fa0f53b]146 pipe->auto_reset_halt = false;
147 usb_request_clear_endpoint_halt(pipe, 0);
148 pipe->auto_reset_halt = true;
149}
150
[567d002]151/** Request a control read transfer on an endpoint pipe.
[dc04868]152 *
153 * This function encapsulates all three stages of a control transfer.
154 *
155 * @param[in] pipe Pipe used for the transfer.
156 * @param[in] setup_buffer Buffer with the setup packet.
157 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
158 * @param[out] data_buffer Buffer for incoming data.
159 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes).
160 * @param[out] data_transfered_size Number of bytes that were actually
161 * transfered during the DATA stage.
162 * @return Error code.
163 */
[3954a63b]164int usb_pipe_control_read(usb_pipe_t *pipe,
[7a05ced0]165 const void *setup_buffer, size_t setup_buffer_size,
[567d002]166 void *data_buffer, size_t data_buffer_size, size_t *data_transfered_size)
[dc04868]167{
168 assert(pipe);
169
[b4292e7]170 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
[47c573a]171 return EINVAL;
172 }
173
174 if ((data_buffer == NULL) || (data_buffer_size == 0)) {
175 return EINVAL;
176 }
177
[dc04868]178 if ((pipe->direction != USB_DIRECTION_BOTH)
179 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
180 return EBADF;
181 }
182
[b4292e7]183 uint64_t setup_packet;
184 memcpy(&setup_packet, setup_buffer, 8);
185
[47c573a]186 size_t act_size = 0;
[8969f46]187 const int rc = usb_pipe_read_no_check(pipe, setup_packet,
[47c573a]188 data_buffer, data_buffer_size, &act_size);
[567d002]189
[fa0f53b]190 if (rc == ESTALL) {
191 clear_self_endpoint_halt(pipe);
192 }
193
[8969f46]194 if (rc == EOK && data_transfered_size != NULL) {
[47c573a]195 *data_transfered_size = act_size;
196 }
[dc04868]197
[8969f46]198 return rc;
[dc04868]199}
200
[567d002]201/** Request a control write transfer on an endpoint pipe.
[dc04868]202 *
203 * This function encapsulates all three stages of a control transfer.
204 *
205 * @param[in] pipe Pipe used for the transfer.
206 * @param[in] setup_buffer Buffer with the setup packet.
207 * @param[in] setup_buffer_size Size of the setup packet (in bytes).
208 * @param[in] data_buffer Buffer with data to be sent.
209 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes).
210 * @return Error code.
211 */
[3954a63b]212int usb_pipe_control_write(usb_pipe_t *pipe,
[3875af65]213 const void *setup_buffer, size_t setup_buffer_size,
214 const void *data_buffer, size_t data_buffer_size)
[dc04868]215{
216 assert(pipe);
217
[b4292e7]218 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) {
[47c573a]219 return EINVAL;
220 }
221
222 if ((data_buffer == NULL) && (data_buffer_size > 0)) {
223 return EINVAL;
224 }
225
226 if ((data_buffer != NULL) && (data_buffer_size == 0)) {
227 return EINVAL;
228 }
229
[dc04868]230 if ((pipe->direction != USB_DIRECTION_BOTH)
231 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) {
232 return EBADF;
233 }
234
[b4292e7]235 uint64_t setup_packet;
236 memcpy(&setup_packet, setup_buffer, 8);
[a546687]237
[8969f46]238 const int rc = usb_pipe_write_no_check(pipe, setup_packet,
[b4292e7]239 data_buffer, data_buffer_size);
[567d002]240
[fa0f53b]241 if (rc == ESTALL) {
242 clear_self_endpoint_halt(pipe);
243 }
244
[567d002]245 return rc;
[dc04868]246}
[3f0ad85a]247
248/** Request a read (in) transfer on an endpoint pipe.
249 *
250 * @param[in] pipe Pipe used for the transfer.
251 * @param[out] buffer Buffer where to store the data.
252 * @param[in] size Size of the buffer (in bytes).
253 * @param[out] size_transfered Number of bytes that were actually transfered.
254 * @return Error code.
255 */
256int usb_pipe_read(usb_pipe_t *pipe,
257 void *buffer, size_t size, size_t *size_transfered)
258{
259 assert(pipe);
260
261 if (buffer == NULL) {
262 return EINVAL;
263 }
264
265 if (size == 0) {
266 return EINVAL;
267 }
268
269 if (pipe->direction != USB_DIRECTION_IN) {
270 return EBADF;
271 }
272
273 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
274 return EBADF;
275 }
276
277 size_t act_size = 0;
278 const int rc = usb_pipe_read_no_check(pipe, 0, buffer, size, &act_size);
279
280
281 if (rc == EOK && size_transfered != NULL) {
282 *size_transfered = act_size;
283 }
284
285 return rc;
286}
287
288/** Request a write (out) transfer on an endpoint pipe.
289 *
290 * @param[in] pipe Pipe used for the transfer.
291 * @param[in] buffer Buffer with data to transfer.
292 * @param[in] size Size of the buffer (in bytes).
293 * @return Error code.
294 */
295int usb_pipe_write(usb_pipe_t *pipe, const void *buffer, size_t size)
296{
297 assert(pipe);
298
299 if (buffer == NULL || size == 0) {
300 return EINVAL;
301 }
302
303 if (pipe->direction != USB_DIRECTION_OUT) {
304 return EBADF;
305 }
306
307 if (pipe->transfer_type == USB_TRANSFER_CONTROL) {
308 return EBADF;
309 }
310
311 return usb_pipe_write_no_check(pipe, 0, buffer, size);
312}
313
[dc04868]314/**
315 * @}
316 */
Note: See TracBrowser for help on using the repository browser.