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

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

Add address reservation to USBHC interface in DDF

Any USB driver that needs to assign new USB address shall ask its HC
for it. When using default USB address (address 0), it must inform
HC about it as HC is the only element able to provide serialization.

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