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

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

Add binding of USB address and devman handle to usbhc iface

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