source: mainline/uspace/lib/usb/hcd.c@ 7034be15

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

USB driver to HC communication uses DDF interfaces

Started work on using interfaces on the background of communication
between HC and USB driver. However, for driver developers, this will
be hidden completely.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*
2 * Copyright (c) 2010 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 usb
30 * @{
31 */
32/** @file
33 * @brief USB Host Controller Driver (implementation).
34 */
35#include "hcd.h"
36#include <devmap.h>
37#include <stdlib.h>
38#include <fcntl.h>
39#include <vfs/vfs.h>
40#include <errno.h>
41
42/** Information about pending transaction on HC. */
43typedef struct {
44 /** Phone to host controller driver. */
45 int phone;
46 /** Data buffer. */
47 void *buffer;
48 /** Buffer size. */
49 size_t size;
50 /** Storage for actual number of bytes transferred. */
51 size_t *size_transferred;
52 /** Initial call replay data. */
53 ipc_call_t reply;
54 /** Initial call identifier. */
55 aid_t request;
56} transfer_info_t;
57
58#define NAMESPACE "usb"
59
60
61/** Create necessary phones for communicating with HCD.
62 * This function wraps following calls:
63 * -# open <code>/dev/usb/<i>hcd_path</i></code> for reading
64 * -# access phone of file opened in previous step
65 * -# return the (outgoing) phone
66 *
67 * @warning This function is wrapper for several actions and therefore
68 * it is not possible - in case of error - to determine at which point
69 * error occurred.
70 *
71 * @param hcd_path HCD identification under devfs
72 * (without <code>/dev/usb/</code>).
73 * @return Phone for communicating with HCD or error code from errno.h.
74 */
75int usb_hcd_connect(const char * hcd_path)
76{
77 char dev_path[DEVMAP_NAME_MAXLEN + 1];
78 snprintf(dev_path, DEVMAP_NAME_MAXLEN,
79 "/dev/%s/%s", NAMESPACE, hcd_path);
80
81 int fd = open(dev_path, O_RDONLY);
82 if (fd < 0) {
83 return fd;
84 }
85
86 int hcd_phone = fd_phone(fd);
87
88 if (hcd_phone < 0) {
89 return hcd_phone;
90 }
91
92 return hcd_phone;
93}
94
95/** Send data to HCD.
96 *
97 * @param phone Opened phone to HCD.
98 * @param method Method used for calling.
99 * @param target Target device.
100 * @param buffer Data buffer (NULL to skip data transfer phase).
101 * @param size Buffer size (must be zero when @p buffer is NULL).
102 * @param handle Storage for transaction handle (cannot be NULL).
103 * @return Error status.
104 * @retval EINVAL Invalid parameter.
105 * @retval ENOMEM Not enough memory to complete the operation.
106 */
107static int async_send_buffer(int phone, int method,
108 usb_target_t target,
109 void *buffer, size_t size,
110 usb_handle_t *handle)
111{
112 if (phone < 0) {
113 return EINVAL;
114 }
115
116 if ((buffer == NULL) && (size > 0)) {
117 return EINVAL;
118 }
119
120 if (handle == NULL) {
121 return EINVAL;
122 }
123
124 transfer_info_t *transfer
125 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
126 if (transfer == NULL) {
127 return ENOMEM;
128 }
129
130 transfer->size_transferred = NULL;
131 transfer->buffer = NULL;
132 transfer->size = 0;
133 transfer->phone = phone;
134
135 int rc;
136
137 transfer->request = async_send_3(phone,
138 method,
139 target.address, target.endpoint,
140 size,
141 &transfer->reply);
142
143 if (size > 0) {
144 rc = async_data_write_start(phone, buffer, size);
145 if (rc != EOK) {
146 async_wait_for(transfer->request, NULL);
147 return rc;
148 }
149 }
150
151 *handle = (usb_handle_t) transfer;
152
153 return EOK;
154}
155
156/** Prepare data retrieval.
157 *
158 * @param phone Opened phone to HCD.
159 * @param method Method used for calling.
160 * @param target Target device.
161 * @param buffer Buffer where to store retrieved data
162 * (NULL to skip data transfer phase).
163 * @param size Buffer size (must be zero when @p buffer is NULL).
164 * @param actual_size Storage where actual number of bytes transferred will
165 * be stored.
166 * @param handle Storage for transaction handle (cannot be NULL).
167 * @return Error status.
168 * @retval EINVAL Invalid parameter.
169 * @retval ENOMEM Not enough memory to complete the operation.
170 */
171static int async_recv_buffer(int phone, int method,
172 usb_target_t target,
173 void *buffer, size_t size, size_t *actual_size,
174 usb_handle_t *handle)
175{
176 if (phone < 0) {
177 return EINVAL;
178 }
179
180 if ((buffer == NULL) && (size > 0)) {
181 return EINVAL;
182 }
183
184 if (handle == NULL) {
185 return EINVAL;
186 }
187
188 transfer_info_t *transfer
189 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
190 if (transfer == NULL) {
191 return ENOMEM;
192 }
193
194 transfer->size_transferred = actual_size;
195 transfer->buffer = buffer;
196 transfer->size = size;
197 transfer->phone = phone;
198
199 transfer->request = async_send_3(phone,
200 method,
201 target.address, target.endpoint,
202 size,
203 &transfer->reply);
204
205 *handle = (usb_handle_t) transfer;
206
207 return EOK;
208}
209
210/** Read buffer from HCD.
211 *
212 * @param phone Opened phone to HCD.
213 * @param hash Buffer hash (obtained after completing IN transaction).
214 * @param buffer Buffer where to store data data.
215 * @param size Buffer size.
216 * @param actual_size Storage where actual number of bytes transferred will
217 * be stored.
218 * @return Error status.
219 */
220static int read_buffer_in(int phone, ipcarg_t hash,
221 void *buffer, size_t size, size_t *actual_size)
222{
223 ipc_call_t answer_data;
224 ipcarg_t answer_rc;
225 aid_t req;
226 int rc;
227
228 req = async_send_1(phone,
229 IPC_M_USB_HCD_GET_BUFFER_ASYNC,
230 hash,
231 &answer_data);
232
233 rc = async_data_read_start(phone, buffer, size);
234 if (rc != EOK) {
235 async_wait_for(req, NULL);
236 return EINVAL;
237 }
238
239 async_wait_for(req, &answer_rc);
240 rc = (int)answer_rc;
241
242 if (rc != EOK) {
243 return rc;
244 }
245
246 *actual_size = IPC_GET_ARG1(answer_data);
247
248 return EOK;
249}
250
251/** Blocks caller until given USB transaction is finished.
252 * After the transaction is finished, the user can access all output data
253 * given to initial call function.
254 *
255 * @param handle Transaction handle.
256 * @return Error status.
257 * @retval EOK No error.
258 * @retval EBADMEM Invalid handle.
259 * @retval ENOENT Data buffer associated with transaction does not exist.
260 */
261int usb_hcd_async_wait_for(usb_handle_t handle)
262{
263 if (handle == 0) {
264 return EBADMEM;
265 }
266
267 int rc = EOK;
268
269 transfer_info_t *transfer = (transfer_info_t *) handle;
270
271 ipcarg_t answer_rc;
272 async_wait_for(transfer->request, &answer_rc);
273
274 if (answer_rc != EOK) {
275 rc = (int) answer_rc;
276 goto leave;
277 }
278
279 /*
280 * If the buffer is not NULL, we must accept some data.
281 */
282 if ((transfer->buffer != NULL) && (transfer->size > 0)) {
283 /*
284 * The buffer hash identifies the data on the server
285 * side.
286 * We will use it when actually reading-in the data.
287 */
288 ipcarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
289 if (buffer_hash == 0) {
290 rc = ENOENT;
291 goto leave;
292 }
293
294 size_t actual_size;
295 rc = read_buffer_in(transfer->phone, buffer_hash,
296 transfer->buffer, transfer->size, &actual_size);
297
298 if (rc != EOK) {
299 goto leave;
300 }
301
302 if (transfer->size_transferred) {
303 *(transfer->size_transferred) = actual_size;
304 }
305 }
306
307leave:
308 free(transfer);
309
310 return rc;
311}
312
313/** Send interrupt data to device. */
314int usb_hcd_async_transfer_interrupt_out(int hcd_phone,
315 usb_target_t target,
316 void *buffer, size_t size,
317 usb_handle_t *handle)
318{
319 return async_send_buffer(hcd_phone,
320 IPC_M_USB_HCD_INTERRUPT_OUT_ASYNC,
321 target,
322 buffer, size,
323 handle);
324}
325
326/** Request interrupt data from device. */
327int usb_hcd_async_transfer_interrupt_in(int hcd_phone,
328 usb_target_t target,
329 void *buffer, size_t size, size_t *actual_size,
330 usb_handle_t *handle)
331{
332 return async_recv_buffer(hcd_phone,
333 IPC_M_USB_HCD_INTERRUPT_IN_ASYNC,
334 target,
335 buffer, size, actual_size,
336 handle);
337}
338
339/** Start WRITE control transfer. */
340int usb_hcd_async_transfer_control_write_setup(int hcd_phone,
341 usb_target_t target,
342 void *buffer, size_t size,
343 usb_handle_t *handle)
344{
345 return async_send_buffer(hcd_phone,
346 IPC_M_USB_HCD_CONTROL_WRITE_SETUP_ASYNC,
347 target,
348 buffer, size,
349 handle);
350}
351
352/** Send data during WRITE control transfer. */
353int usb_hcd_async_transfer_control_write_data(int hcd_phone,
354 usb_target_t target,
355 void *buffer, size_t size,
356 usb_handle_t *handle)
357{
358 return async_send_buffer(hcd_phone,
359 IPC_M_USB_HCD_CONTROL_WRITE_DATA_ASYNC,
360 target,
361 buffer, size,
362 handle);
363}
364
365/** Terminate WRITE control transfer. */
366int usb_hcd_async_transfer_control_write_status(int hcd_phone,
367 usb_target_t target,
368 usb_handle_t *handle)
369{
370 return async_recv_buffer(hcd_phone,
371 IPC_M_USB_HCD_CONTROL_WRITE_STATUS_ASYNC,
372 target,
373 NULL, 0, NULL,
374 handle);
375}
376
377/** Start READ control transfer. */
378int usb_hcd_async_transfer_control_read_setup(int hcd_phone,
379 usb_target_t target,
380 void *buffer, size_t size,
381 usb_handle_t *handle)
382{
383 return async_send_buffer(hcd_phone,
384 IPC_M_USB_HCD_CONTROL_READ_SETUP_ASYNC,
385 target,
386 buffer, size,
387 handle);
388}
389
390/** Request data during READ control transfer. */
391int usb_hcd_async_transfer_control_read_data(int hcd_phone,
392 usb_target_t target,
393 void *buffer, size_t size, size_t *actual_size,
394 usb_handle_t *handle)
395{
396 return async_recv_buffer(hcd_phone,
397 IPC_M_USB_HCD_CONTROL_READ_DATA_ASYNC,
398 target,
399 buffer, size, actual_size,
400 handle);
401}
402
403/** Terminate READ control transfer. */
404int usb_hcd_async_transfer_control_read_status(int hcd_phone,
405 usb_target_t target,
406 usb_handle_t *handle)
407{
408 return async_send_buffer(hcd_phone,
409 IPC_M_USB_HCD_CONTROL_READ_STATUS_ASYNC,
410 target,
411 NULL, 0,
412 handle);
413}
414
415/**
416 * @}
417 */
Note: See TracBrowser for help on using the repository browser.