source: mainline/uspace/lib/usb/src/usbdrv.c@ 62c9661

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

Connecting in HCD in same task in separate function

  • Property mode set to 100644
File size: 10.1 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 <usb/usbdrv.h>
36#include <usbhc_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 dev Device asking for connection.
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
67 /*
68 * FIXME: currently we connect always to virtual host controller.
69 */
70 int rc;
71 devman_handle_t handle;
72
73 rc = devman_device_get_handle("/vhc", &handle, 0);
74 if (rc != EOK) {
75 return rc;
76 }
77
78 int phone = devman_device_connect(handle, 0);
79
80 return phone;
81}
82
83/** Tell USB address assigned to given device.
84 *
85 * @param phone Phone to my HC.
86 * @param dev Device in question.
87 * @return USB address or error code.
88 */
89usb_address_t usb_drv_get_my_address(int phone, device_t *dev)
90{
91 ipcarg_t address;
92 int rc = async_req_1_1(phone, IPC_M_USBHC_GET_ADDRESS,
93 dev->handle, &address);
94
95 if (rc != EOK) {
96 return rc;
97 }
98
99 return (usb_address_t) address;
100}
101
102/** Send data to HCD.
103 *
104 * @param phone Phone to HC.
105 * @param method Method used for calling.
106 * @param target Targeted device.
107 * @param buffer Data buffer (NULL to skip data transfer phase).
108 * @param size Buffer size (must be zero when @p buffer is NULL).
109 * @param handle Storage for transaction handle (cannot be NULL).
110 * @return Error status.
111 * @retval EINVAL Invalid parameter.
112 * @retval ENOMEM Not enough memory to complete the operation.
113 */
114static int async_send_buffer(int phone, int method,
115 usb_target_t target,
116 void *buffer, size_t size,
117 usb_handle_t *handle)
118{
119 if (phone < 0) {
120 return EINVAL;
121 }
122
123 if ((buffer == NULL) && (size > 0)) {
124 return EINVAL;
125 }
126
127 if (handle == NULL) {
128 return EINVAL;
129 }
130
131 transfer_info_t *transfer
132 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
133 if (transfer == NULL) {
134 return ENOMEM;
135 }
136
137 transfer->size_transferred = NULL;
138 transfer->buffer = NULL;
139 transfer->size = 0;
140 transfer->phone = phone;
141
142 int rc;
143
144 transfer->request = async_send_4(phone,
145 DEV_IFACE_ID(USBHC_DEV_IFACE),
146 method,
147 target.address, target.endpoint,
148 size,
149 &transfer->reply);
150
151 if (size > 0) {
152 rc = async_data_write_start(phone, buffer, size);
153 if (rc != EOK) {
154 async_wait_for(transfer->request, NULL);
155 return rc;
156 }
157 }
158
159 *handle = (usb_handle_t) transfer;
160
161 return EOK;
162}
163
164/** Prepare data retrieval.
165 *
166 * @param phone Opened phone to HCD.
167 * @param method Method used for calling.
168 * @param target Targeted device.
169 * @param buffer Buffer where to store retrieved data
170 * (NULL to skip data transfer phase).
171 * @param size Buffer size (must be zero when @p buffer is NULL).
172 * @param actual_size Storage where actual number of bytes transferred will
173 * be stored.
174 * @param handle Storage for transaction handle (cannot be NULL).
175 * @return Error status.
176 * @retval EINVAL Invalid parameter.
177 * @retval ENOMEM Not enough memory to complete the operation.
178 */
179static int async_recv_buffer(int phone, int method,
180 usb_target_t target,
181 void *buffer, size_t size, size_t *actual_size,
182 usb_handle_t *handle)
183{
184 if (phone < 0) {
185 return EINVAL;
186 }
187
188 if ((buffer == NULL) && (size > 0)) {
189 return EINVAL;
190 }
191
192 if (handle == NULL) {
193 return EINVAL;
194 }
195
196 transfer_info_t *transfer
197 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
198 if (transfer == NULL) {
199 return ENOMEM;
200 }
201
202 transfer->size_transferred = actual_size;
203 transfer->buffer = buffer;
204 transfer->size = size;
205 transfer->phone = phone;
206
207 transfer->request = async_send_4(phone,
208 DEV_IFACE_ID(USBHC_DEV_IFACE),
209 method,
210 target.address, target.endpoint,
211 size,
212 &transfer->reply);
213
214 *handle = (usb_handle_t) transfer;
215
216 return EOK;
217}
218
219/** Read buffer from HCD.
220 *
221 * @param phone Opened phone to HCD.
222 * @param hash Buffer hash (obtained after completing IN transaction).
223 * @param buffer Buffer where to store data data.
224 * @param size Buffer size.
225 * @param actual_size Storage where actual number of bytes transferred will
226 * be stored.
227 * @return Error status.
228 */
229static int read_buffer_in(int phone, ipcarg_t hash,
230 void *buffer, size_t size, size_t *actual_size)
231{
232 ipc_call_t answer_data;
233 ipcarg_t answer_rc;
234 aid_t req;
235 int rc;
236
237 req = async_send_2(phone,
238 DEV_IFACE_ID(USBHC_DEV_IFACE),
239 IPC_M_USBHC_GET_BUFFER,
240 hash,
241 &answer_data);
242
243 rc = async_data_read_start(phone, buffer, size);
244 if (rc != EOK) {
245 async_wait_for(req, NULL);
246 return EINVAL;
247 }
248
249 async_wait_for(req, &answer_rc);
250 rc = (int)answer_rc;
251
252 if (rc != EOK) {
253 return rc;
254 }
255
256 *actual_size = IPC_GET_ARG1(answer_data);
257
258 return EOK;
259}
260
261/** Blocks caller until given USB transaction is finished.
262 * After the transaction is finished, the user can access all output data
263 * given to initial call function.
264 *
265 * @param handle Transaction handle.
266 * @return Error status.
267 * @retval EOK No error.
268 * @retval EBADMEM Invalid handle.
269 * @retval ENOENT Data buffer associated with transaction does not exist.
270 */
271int usb_drv_async_wait_for(usb_handle_t handle)
272{
273 if (handle == 0) {
274 return EBADMEM;
275 }
276
277 int rc = EOK;
278
279 transfer_info_t *transfer = (transfer_info_t *) handle;
280
281 ipcarg_t answer_rc;
282 async_wait_for(transfer->request, &answer_rc);
283
284 if (answer_rc != EOK) {
285 rc = (int) answer_rc;
286 goto leave;
287 }
288
289 /*
290 * If the buffer is not NULL, we must accept some data.
291 */
292 if ((transfer->buffer != NULL) && (transfer->size > 0)) {
293 /*
294 * The buffer hash identifies the data on the server
295 * side.
296 * We will use it when actually reading-in the data.
297 */
298 ipcarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
299 if (buffer_hash == 0) {
300 rc = ENOENT;
301 goto leave;
302 }
303
304 size_t actual_size;
305 rc = read_buffer_in(transfer->phone, buffer_hash,
306 transfer->buffer, transfer->size, &actual_size);
307
308 if (rc != EOK) {
309 goto leave;
310 }
311
312 if (transfer->size_transferred) {
313 *(transfer->size_transferred) = actual_size;
314 }
315 }
316
317leave:
318 free(transfer);
319
320 return rc;
321}
322
323/** Send interrupt data to device. */
324int usb_drv_async_interrupt_out(int phone, usb_target_t target,
325 void *buffer, size_t size,
326 usb_handle_t *handle)
327{
328 return async_send_buffer(phone,
329 IPC_M_USBHC_INTERRUPT_OUT,
330 target,
331 buffer, size,
332 handle);
333}
334
335/** Request interrupt data from device. */
336int usb_drv_async_interrupt_in(int phone, usb_target_t target,
337 void *buffer, size_t size, size_t *actual_size,
338 usb_handle_t *handle)
339{
340 return async_recv_buffer(phone,
341 IPC_M_USBHC_INTERRUPT_IN,
342 target,
343 buffer, size, actual_size,
344 handle);
345}
346
347/** Start control write transfer. */
348int usb_drv_async_control_write_setup(int phone, usb_target_t target,
349 void *buffer, size_t size,
350 usb_handle_t *handle)
351{
352 return async_send_buffer(phone,
353 IPC_M_USBHC_CONTROL_WRITE_SETUP,
354 target,
355 buffer, size,
356 handle);
357}
358
359/** Send data during control write transfer. */
360int usb_drv_async_control_write_data(int phone, usb_target_t target,
361 void *buffer, size_t size,
362 usb_handle_t *handle)
363{
364 return async_send_buffer(phone,
365 IPC_M_USBHC_CONTROL_WRITE_DATA,
366 target,
367 buffer, size,
368 handle);
369}
370
371/** Finalize control write transfer. */
372int usb_drv_async_control_write_status(int phone, usb_target_t target,
373 usb_handle_t *handle)
374{
375 return async_recv_buffer(phone,
376 IPC_M_USBHC_CONTROL_WRITE_STATUS,
377 target,
378 NULL, 0, NULL,
379 handle);
380}
381
382/** Start control read transfer. */
383int usb_drv_async_control_read_setup(int phone, usb_target_t target,
384 void *buffer, size_t size,
385 usb_handle_t *handle)
386{
387 return async_send_buffer(phone,
388 IPC_M_USBHC_CONTROL_READ_SETUP,
389 target,
390 buffer, size,
391 handle);
392}
393
394/** Read data during control read transfer. */
395int usb_drv_async_control_read_data(int phone, usb_target_t target,
396 void *buffer, size_t size, size_t *actual_size,
397 usb_handle_t *handle)
398{
399 return async_recv_buffer(phone,
400 IPC_M_USBHC_CONTROL_READ_DATA,
401 target,
402 buffer, size, actual_size,
403 handle);
404}
405
406/** Finalize control read transfer. */
407int usb_drv_async_control_read_status(int phone, usb_target_t target,
408 usb_handle_t *handle)
409{
410 return async_send_buffer(phone,
411 IPC_M_USBHC_CONTROL_READ_STATUS,
412 target,
413 NULL, 0,
414 handle);
415}
416
417/**
418 * @}
419 */
Note: See TracBrowser for help on using the repository browser.