source: mainline/uspace/lib/usb/usbdrv.c@ 91db50ac

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 91db50ac 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: 7.7 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 driver (implementation).
34 */
35#include "usbdrv.h"
36#include <usb_iface.h>
37#include <errno.h>
38
39/** Information about pending transaction on HC. */
40typedef struct {
41 /** Phone to host controller driver. */
42 int phone;
43 /** Data buffer. */
44 void *buffer;
45 /** Buffer size. */
46 size_t size;
47 /** Storage for actual number of bytes transferred. */
48 size_t *size_transferred;
49 /** Initial call replay data. */
50 ipc_call_t reply;
51 /** Initial call identifier. */
52 aid_t request;
53} transfer_info_t;
54
55/** Connect to host controller the device is physically attached to.
56 *
57 * @param handle Device handle.
58 * @param flags Connection flags (blocking connection).
59 * @return Phone to corresponding HC or error code.
60 */
61int usb_drv_hc_connect(device_t *dev, unsigned int flags)
62{
63 /*
64 * Call parent hub to obtain device handle of respective HC.
65 */
66 return ENOTSUP;
67}
68
69/** Send data to HCD.
70 *
71 * @param phone Phone to HC.
72 * @param method Method used for calling.
73 * @param endpoint Device endpoint.
74 * @param buffer Data buffer (NULL to skip data transfer phase).
75 * @param size Buffer size (must be zero when @p buffer is NULL).
76 * @param handle Storage for transaction handle (cannot be NULL).
77 * @return Error status.
78 * @retval EINVAL Invalid parameter.
79 * @retval ENOMEM Not enough memory to complete the operation.
80 */
81static int async_send_buffer(int phone, int method,
82 usb_endpoint_t endpoint,
83 void *buffer, size_t size,
84 usb_handle_t *handle)
85{
86 if (phone < 0) {
87 return EINVAL;
88 }
89
90 if ((buffer == NULL) && (size > 0)) {
91 return EINVAL;
92 }
93
94 if (handle == NULL) {
95 return EINVAL;
96 }
97
98 transfer_info_t *transfer
99 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
100 if (transfer == NULL) {
101 return ENOMEM;
102 }
103
104 transfer->size_transferred = NULL;
105 transfer->buffer = NULL;
106 transfer->size = 0;
107 transfer->phone = phone;
108
109 int rc;
110
111 transfer->request = async_send_3(phone,
112 DEV_IFACE_ID(USB_DEV_IFACE),
113 method,
114 endpoint,
115 size,
116 &transfer->reply);
117
118 if (size > 0) {
119 rc = async_data_write_start(phone, buffer, size);
120 if (rc != EOK) {
121 async_wait_for(transfer->request, NULL);
122 return rc;
123 }
124 }
125
126 *handle = (usb_handle_t) transfer;
127
128 return EOK;
129}
130
131/** Prepare data retrieval.
132 *
133 * @param phone Opened phone to HCD.
134 * @param method Method used for calling.
135 * @param endpoint Device endpoint.
136 * @param buffer Buffer where to store retrieved data
137 * (NULL to skip data transfer phase).
138 * @param size Buffer size (must be zero when @p buffer is NULL).
139 * @param actual_size Storage where actual number of bytes transferred will
140 * be stored.
141 * @param handle Storage for transaction handle (cannot be NULL).
142 * @return Error status.
143 * @retval EINVAL Invalid parameter.
144 * @retval ENOMEM Not enough memory to complete the operation.
145 */
146static int async_recv_buffer(int phone, int method,
147 usb_endpoint_t endpoint,
148 void *buffer, size_t size, size_t *actual_size,
149 usb_handle_t *handle)
150{
151 if (phone < 0) {
152 return EINVAL;
153 }
154
155 if ((buffer == NULL) && (size > 0)) {
156 return EINVAL;
157 }
158
159 if (handle == NULL) {
160 return EINVAL;
161 }
162
163 transfer_info_t *transfer
164 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
165 if (transfer == NULL) {
166 return ENOMEM;
167 }
168
169 transfer->size_transferred = actual_size;
170 transfer->buffer = buffer;
171 transfer->size = size;
172 transfer->phone = phone;
173
174 transfer->request = async_send_3(phone,
175 DEV_IFACE_ID(USB_DEV_IFACE),
176 method,
177 endpoint,
178 size,
179 &transfer->reply);
180
181 *handle = (usb_handle_t) transfer;
182
183 return EOK;
184}
185
186/** Read buffer from HCD.
187 *
188 * @param phone Opened phone to HCD.
189 * @param hash Buffer hash (obtained after completing IN transaction).
190 * @param buffer Buffer where to store data data.
191 * @param size Buffer size.
192 * @param actual_size Storage where actual number of bytes transferred will
193 * be stored.
194 * @return Error status.
195 */
196static int read_buffer_in(int phone, ipcarg_t hash,
197 void *buffer, size_t size, size_t *actual_size)
198{
199 ipc_call_t answer_data;
200 ipcarg_t answer_rc;
201 aid_t req;
202 int rc;
203
204 req = async_send_2(phone,
205 DEV_IFACE_ID(USB_DEV_IFACE),
206 IPC_M_USB_GET_BUFFER,
207 hash,
208 &answer_data);
209
210 rc = async_data_read_start(phone, buffer, size);
211 if (rc != EOK) {
212 async_wait_for(req, NULL);
213 return EINVAL;
214 }
215
216 async_wait_for(req, &answer_rc);
217 rc = (int)answer_rc;
218
219 if (rc != EOK) {
220 return rc;
221 }
222
223 *actual_size = IPC_GET_ARG1(answer_data);
224
225 return EOK;
226}
227
228/** Blocks caller until given USB transaction is finished.
229 * After the transaction is finished, the user can access all output data
230 * given to initial call function.
231 *
232 * @param handle Transaction handle.
233 * @return Error status.
234 * @retval EOK No error.
235 * @retval EBADMEM Invalid handle.
236 * @retval ENOENT Data buffer associated with transaction does not exist.
237 */
238int usb_drv_async_wait_for(usb_handle_t handle)
239{
240 if (handle == 0) {
241 return EBADMEM;
242 }
243
244 int rc = EOK;
245
246 transfer_info_t *transfer = (transfer_info_t *) handle;
247
248 ipcarg_t answer_rc;
249 async_wait_for(transfer->request, &answer_rc);
250
251 if (answer_rc != EOK) {
252 rc = (int) answer_rc;
253 goto leave;
254 }
255
256 /*
257 * If the buffer is not NULL, we must accept some data.
258 */
259 if ((transfer->buffer != NULL) && (transfer->size > 0)) {
260 /*
261 * The buffer hash identifies the data on the server
262 * side.
263 * We will use it when actually reading-in the data.
264 */
265 ipcarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
266 if (buffer_hash == 0) {
267 rc = ENOENT;
268 goto leave;
269 }
270
271 size_t actual_size;
272 rc = read_buffer_in(transfer->phone, buffer_hash,
273 transfer->buffer, transfer->size, &actual_size);
274
275 if (rc != EOK) {
276 goto leave;
277 }
278
279 if (transfer->size_transferred) {
280 *(transfer->size_transferred) = actual_size;
281 }
282 }
283
284leave:
285 free(transfer);
286
287 return rc;
288}
289
290/** Send interrupt data to device. */
291int usb_drv_async_interrupt_out(int phone, usb_endpoint_t endpoint,
292 void *buffer, size_t size,
293 usb_handle_t *handle)
294{
295 return async_send_buffer(phone,
296 IPC_M_USB_INTERRUPT_OUT,
297 endpoint,
298 buffer, size,
299 handle);
300}
301
302/** Request interrupt data from device. */
303int usb_drv_async_interrupt_in(int phone, usb_endpoint_t endpoint,
304 void *buffer, size_t size, size_t *actual_size,
305 usb_handle_t *handle)
306{
307 return async_recv_buffer(phone,
308 IPC_M_USB_INTERRUPT_IN,
309 endpoint,
310 buffer, size, actual_size,
311 handle);
312}
313
314/**
315 * @}
316 */
Note: See TracBrowser for help on using the repository browser.