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

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

libusbdev: Merge implementations of control and non-control _no_check read/write.

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