source: mainline/uspace/lib/usb/src/usbdrv.c@ 97e660e

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

Bugfix - missing flags

  • Property mode set to 100644
File size: 11.9 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#include <str_error.h>
39
40/** Information about pending transaction on HC. */
41typedef struct {
42 /** Phone to host controller driver. */
43 int phone;
44 /** Data buffer. */
45 void *buffer;
46 /** Buffer size. */
47 size_t size;
48 /** Storage for actual number of bytes transferred. */
49 size_t *size_transferred;
50 /** Initial call replay data. */
51 ipc_call_t reply;
52 /** Initial call identifier. */
53 aid_t request;
54} transfer_info_t;
55
56/** Connect to host controller the device is physically attached to.
57 *
58 * @param dev Device asking for connection.
59 * @param flags Connection flags (blocking connection).
60 * @return Phone to corresponding HC or error code.
61 */
62int usb_drv_hc_connect(device_t *dev, unsigned int flags)
63{
64 /*
65 * Call parent hub to obtain device handle of respective HC.
66 */
67
68 /*
69 * FIXME: currently we connect always to virtual host controller.
70 */
71 int rc;
72 devman_handle_t handle;
73
74 rc = devman_device_get_handle("/virt/usbhc", &handle, flags);
75 if (rc != EOK) {
76 return rc;
77 }
78
79 int phone = devman_device_connect(handle, flags);
80
81 return phone;
82}
83
84/** Tell USB address assigned to given device.
85 *
86 * @param phone Phone to my HC.
87 * @param dev Device in question.
88 * @return USB address or error code.
89 */
90usb_address_t usb_drv_get_my_address(int phone, device_t *dev)
91{
92 ipcarg_t address;
93 int rc = async_req_2_1(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
94 IPC_M_USBHC_GET_ADDRESS,
95 dev->handle, &address);
96
97 if (rc != EOK) {
98 printf("usb_drv_get_my_address over %d failed: %s\n", phone, str_error(rc));
99 return rc;
100 }
101
102 return (usb_address_t) address;
103}
104
105/** Tell HC to reserve default address.
106 *
107 * @param phone Open phone to host controller driver.
108 * @return Error code.
109 */
110int usb_drv_reserve_default_address(int phone)
111{
112 return async_req_1_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
113 IPC_M_USBHC_RESERVE_DEFAULT_ADDRESS);
114}
115
116/** Tell HC to release default address.
117 *
118 * @param phone Open phone to host controller driver.
119 * @return Error code.
120 */
121int usb_drv_release_default_address(int phone)
122{
123 return async_req_1_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
124 IPC_M_USBHC_RELEASE_DEFAULT_ADDRESS);
125}
126
127/** Ask HC for free address assignment.
128 *
129 * @param phone Open phone to host controller driver.
130 * @return Assigned USB address or negative error code.
131 */
132usb_address_t usb_drv_request_address(int phone)
133{
134 ipcarg_t address;
135 int rc = async_req_1_1(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
136 IPC_M_USBHC_REQUEST_ADDRESS, &address);
137 if (rc != EOK) {
138 return rc;
139 } else {
140 return (usb_address_t) address;
141 }
142}
143
144/** Inform HC about binding address with devman handle.
145 *
146 * @param phone Open phone to host controller driver.
147 * @param address Address to be binded.
148 * @param handle Devman handle of the device.
149 * @return Error code.
150 */
151int usb_drv_bind_address(int phone, usb_address_t address,
152 devman_handle_t handle)
153{
154 int rc = async_req_3_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
155 IPC_M_USBHC_BIND_ADDRESS,
156 address, handle);
157
158 return rc;
159}
160
161/** Inform HC about address release.
162 *
163 * @param phone Open phone to host controller driver.
164 * @param address Address to be released.
165 * @return Error code.
166 */
167int usb_drv_release_address(int phone, usb_address_t address)
168{
169 return async_req_2_0(phone, DEV_IFACE_ID(USBHC_DEV_IFACE),
170 IPC_M_USBHC_RELEASE_ADDRESS, address);
171}
172
173/** Send data to HCD.
174 *
175 * @param phone Phone to HC.
176 * @param method Method used for calling.
177 * @param target Targeted device.
178 * @param buffer Data buffer (NULL to skip data transfer phase).
179 * @param size Buffer size (must be zero when @p buffer is NULL).
180 * @param handle Storage for transaction handle (cannot be NULL).
181 * @return Error status.
182 * @retval EINVAL Invalid parameter.
183 * @retval ENOMEM Not enough memory to complete the operation.
184 */
185static int async_send_buffer(int phone, int method,
186 usb_target_t target,
187 void *buffer, size_t size,
188 usb_handle_t *handle)
189{
190 if (phone < 0) {
191 return EINVAL;
192 }
193
194 if ((buffer == NULL) && (size > 0)) {
195 return EINVAL;
196 }
197
198 if (handle == NULL) {
199 return EINVAL;
200 }
201
202 transfer_info_t *transfer
203 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
204 if (transfer == NULL) {
205 return ENOMEM;
206 }
207
208 transfer->size_transferred = NULL;
209 transfer->buffer = NULL;
210 transfer->size = 0;
211 transfer->phone = phone;
212
213 int rc;
214
215 transfer->request = async_send_4(phone,
216 DEV_IFACE_ID(USBHC_DEV_IFACE),
217 method,
218 target.address, target.endpoint,
219 size,
220 &transfer->reply);
221
222 if (size > 0) {
223 rc = async_data_write_start(phone, buffer, size);
224 if (rc != EOK) {
225 async_wait_for(transfer->request, NULL);
226 return rc;
227 }
228 }
229
230 *handle = (usb_handle_t) transfer;
231
232 return EOK;
233}
234
235/** Prepare data retrieval.
236 *
237 * @param phone Opened phone to HCD.
238 * @param method Method used for calling.
239 * @param target Targeted device.
240 * @param buffer Buffer where to store retrieved data
241 * (NULL to skip data transfer phase).
242 * @param size Buffer size (must be zero when @p buffer is NULL).
243 * @param actual_size Storage where actual number of bytes transferred will
244 * be stored.
245 * @param handle Storage for transaction handle (cannot be NULL).
246 * @return Error status.
247 * @retval EINVAL Invalid parameter.
248 * @retval ENOMEM Not enough memory to complete the operation.
249 */
250static int async_recv_buffer(int phone, int method,
251 usb_target_t target,
252 void *buffer, size_t size, size_t *actual_size,
253 usb_handle_t *handle)
254{
255 if (phone < 0) {
256 return EINVAL;
257 }
258
259 if ((buffer == NULL) && (size > 0)) {
260 return EINVAL;
261 }
262
263 if (handle == NULL) {
264 return EINVAL;
265 }
266
267 transfer_info_t *transfer
268 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
269 if (transfer == NULL) {
270 return ENOMEM;
271 }
272
273 transfer->size_transferred = actual_size;
274 transfer->buffer = buffer;
275 transfer->size = size;
276 transfer->phone = phone;
277
278 transfer->request = async_send_4(phone,
279 DEV_IFACE_ID(USBHC_DEV_IFACE),
280 method,
281 target.address, target.endpoint,
282 size,
283 &transfer->reply);
284
285 *handle = (usb_handle_t) transfer;
286
287 return EOK;
288}
289
290/** Read buffer from HCD.
291 *
292 * @param phone Opened phone to HCD.
293 * @param hash Buffer hash (obtained after completing IN transaction).
294 * @param buffer Buffer where to store data data.
295 * @param size Buffer size.
296 * @param actual_size Storage where actual number of bytes transferred will
297 * be stored.
298 * @return Error status.
299 */
300static int read_buffer_in(int phone, ipcarg_t hash,
301 void *buffer, size_t size, size_t *actual_size)
302{
303 ipc_call_t answer_data;
304 ipcarg_t answer_rc;
305 aid_t req;
306 int rc;
307
308 req = async_send_2(phone,
309 DEV_IFACE_ID(USBHC_DEV_IFACE),
310 IPC_M_USBHC_GET_BUFFER,
311 hash,
312 &answer_data);
313
314 rc = async_data_read_start(phone, buffer, size);
315 if (rc != EOK) {
316 async_wait_for(req, NULL);
317 return EINVAL;
318 }
319
320 async_wait_for(req, &answer_rc);
321 rc = (int)answer_rc;
322
323 if (rc != EOK) {
324 return rc;
325 }
326
327 *actual_size = IPC_GET_ARG1(answer_data);
328
329 return EOK;
330}
331
332/** Blocks caller until given USB transaction is finished.
333 * After the transaction is finished, the user can access all output data
334 * given to initial call function.
335 *
336 * @param handle Transaction handle.
337 * @return Error status.
338 * @retval EOK No error.
339 * @retval EBADMEM Invalid handle.
340 * @retval ENOENT Data buffer associated with transaction does not exist.
341 */
342int usb_drv_async_wait_for(usb_handle_t handle)
343{
344 if (handle == 0) {
345 return EBADMEM;
346 }
347
348 int rc = EOK;
349
350 transfer_info_t *transfer = (transfer_info_t *) handle;
351
352 ipcarg_t answer_rc;
353 async_wait_for(transfer->request, &answer_rc);
354
355 if (answer_rc != EOK) {
356 rc = (int) answer_rc;
357 goto leave;
358 }
359
360 /*
361 * If the buffer is not NULL, we must accept some data.
362 */
363 if ((transfer->buffer != NULL) && (transfer->size > 0)) {
364 /*
365 * The buffer hash identifies the data on the server
366 * side.
367 * We will use it when actually reading-in the data.
368 */
369 ipcarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
370 if (buffer_hash == 0) {
371 rc = ENOENT;
372 goto leave;
373 }
374
375 size_t actual_size;
376 rc = read_buffer_in(transfer->phone, buffer_hash,
377 transfer->buffer, transfer->size, &actual_size);
378
379 if (rc != EOK) {
380 goto leave;
381 }
382
383 if (transfer->size_transferred) {
384 *(transfer->size_transferred) = actual_size;
385 }
386 }
387
388leave:
389 free(transfer);
390
391 return rc;
392}
393
394/** Send interrupt data to device. */
395int usb_drv_async_interrupt_out(int phone, usb_target_t target,
396 void *buffer, size_t size,
397 usb_handle_t *handle)
398{
399 return async_send_buffer(phone,
400 IPC_M_USBHC_INTERRUPT_OUT,
401 target,
402 buffer, size,
403 handle);
404}
405
406/** Request interrupt data from device. */
407int usb_drv_async_interrupt_in(int phone, usb_target_t target,
408 void *buffer, size_t size, size_t *actual_size,
409 usb_handle_t *handle)
410{
411 return async_recv_buffer(phone,
412 IPC_M_USBHC_INTERRUPT_IN,
413 target,
414 buffer, size, actual_size,
415 handle);
416}
417
418/** Start control write transfer. */
419int usb_drv_async_control_write_setup(int phone, usb_target_t target,
420 void *buffer, size_t size,
421 usb_handle_t *handle)
422{
423 return async_send_buffer(phone,
424 IPC_M_USBHC_CONTROL_WRITE_SETUP,
425 target,
426 buffer, size,
427 handle);
428}
429
430/** Send data during control write transfer. */
431int usb_drv_async_control_write_data(int phone, usb_target_t target,
432 void *buffer, size_t size,
433 usb_handle_t *handle)
434{
435 return async_send_buffer(phone,
436 IPC_M_USBHC_CONTROL_WRITE_DATA,
437 target,
438 buffer, size,
439 handle);
440}
441
442/** Finalize control write transfer. */
443int usb_drv_async_control_write_status(int phone, usb_target_t target,
444 usb_handle_t *handle)
445{
446 return async_recv_buffer(phone,
447 IPC_M_USBHC_CONTROL_WRITE_STATUS,
448 target,
449 NULL, 0, NULL,
450 handle);
451}
452
453/** Start control read transfer. */
454int usb_drv_async_control_read_setup(int phone, usb_target_t target,
455 void *buffer, size_t size,
456 usb_handle_t *handle)
457{
458 return async_send_buffer(phone,
459 IPC_M_USBHC_CONTROL_READ_SETUP,
460 target,
461 buffer, size,
462 handle);
463}
464
465/** Read data during control read transfer. */
466int usb_drv_async_control_read_data(int phone, usb_target_t target,
467 void *buffer, size_t size, size_t *actual_size,
468 usb_handle_t *handle)
469{
470 return async_recv_buffer(phone,
471 IPC_M_USBHC_CONTROL_READ_DATA,
472 target,
473 buffer, size, actual_size,
474 handle);
475}
476
477/** Finalize control read transfer. */
478int usb_drv_async_control_read_status(int phone, usb_target_t target,
479 usb_handle_t *handle)
480{
481 return async_send_buffer(phone,
482 IPC_M_USBHC_CONTROL_READ_STATUS,
483 target,
484 NULL, 0,
485 handle);
486}
487
488/**
489 * @}
490 */
Note: See TracBrowser for help on using the repository browser.