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

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

libusbdev: Use shared hc_connection for pipes.

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