source: mainline/uspace/lib/usb/src/usbdrv.c@ 56fb3732

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

Add USB interface

Only boilerplate code for finding host controller device is physically
attached to is ready.

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