source: mainline/uspace/drv/bus/usb/vhc/connhost.c@ 0cd8089

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0cd8089 was 0cd8089, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

libusbhost: Change usb_device_manager interface.

Use request_address instead of get_free_address.
Explicit USB address can be requested.

  • Property mode set to 100644
File size: 16.6 KB
Line 
1/*
2 * Copyright (c) 2011 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 drvusbvhc
30 * @{
31 */
32/** @file
33 * Host controller interface implementation.
34 */
35#include <assert.h>
36#include <errno.h>
37#include <usb/usb.h>
38#include <usb/ddfiface.h>
39#include <usb/debug.h>
40#include <usbhc_iface.h>
41#include "vhcd.h"
42
43#define GET_VHC_DATA(fun) \
44 ((vhc_data_t *)fun->dev->driver_data)
45#define VHC_DATA(vhc, fun) \
46 vhc_data_t *vhc = GET_VHC_DATA(fun); assert(vhc->magic == 0xdeadbeef)
47
48#define UNSUPPORTED(methodname) \
49 usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \
50 methodname, __FILE__, __LINE__)
51
52/** Found free USB address.
53 *
54 * @param[in] fun Device function the action was invoked on.
55 * @param[in] speed Speed of the device that will get this address.
56 * @param[out] address Non-null pointer where to store the free address.
57 * @return Error code.
58 */
59static int request_address(ddf_fun_t *fun, usb_speed_t speed,
60 usb_address_t *address)
61{
62 VHC_DATA(vhc, fun);
63
64 usb_address_t addr = 1;
65 const int ret = usb_device_manager_request_address(
66 &vhc->dev_manager, &addr, false, USB_SPEED_HIGH);
67 if (ret < 0) {
68 return ret;
69 }
70
71 if (address != NULL) {
72 *address = addr;
73 }
74
75 return EOK;
76}
77
78/** Bind USB address with device devman handle.
79 *
80 * @param[in] fun Device function the action was invoked on.
81 * @param[in] address USB address of the device.
82 * @param[in] handle Devman handle of the device.
83 * @return Error code.
84 */
85static int bind_address(ddf_fun_t *fun,
86 usb_address_t address, devman_handle_t handle)
87{
88 VHC_DATA(vhc, fun);
89 usb_log_debug("Binding handle %" PRIun " to address %d.\n",
90 handle, address);
91 usb_device_manager_bind_address(&vhc->dev_manager, address, handle);
92
93 return EOK;
94}
95
96/** Find device handle by address interface function.
97 *
98 * @param[in] fun DDF function that was called.
99 * @param[in] address Address in question.
100 * @param[out] handle Where to store device handle if found.
101 * @return Error code.
102 */
103static int find_by_address(ddf_fun_t *fun, usb_address_t address,
104 devman_handle_t *handle)
105{
106 VHC_DATA(vhc, fun);
107 return usb_device_manager_get_info_by_address(
108 &vhc->dev_manager, address, handle, NULL);
109}
110
111/** Release previously requested address.
112 *
113 * @param[in] fun Device function the action was invoked on.
114 * @param[in] address USB address to be released.
115 * @return Error code.
116 */
117static int release_address(ddf_fun_t *fun, usb_address_t address)
118{
119 VHC_DATA(vhc, fun);
120 usb_log_debug("Releasing address %d...\n", address);
121 usb_device_manager_release_address(&vhc->dev_manager, address);
122
123 return ENOTSUP;
124}
125
126/** Register endpoint for bandwidth reservation.
127 *
128 * @param[in] fun Device function the action was invoked on.
129 * @param[in] address USB address of the device.
130 * @param[in] speed Endpoint speed (invalid means to use device one).
131 * @param[in] endpoint Endpoint number.
132 * @param[in] transfer_type USB transfer type.
133 * @param[in] direction Endpoint data direction.
134 * @param[in] max_packet_size Max packet size of the endpoint.
135 * @param[in] interval Polling interval.
136 * @return Error code.
137 */
138static int register_endpoint(ddf_fun_t *fun,
139 usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
140 usb_transfer_type_t transfer_type, usb_direction_t direction,
141 size_t max_packet_size, unsigned int interval)
142{
143 VHC_DATA(vhc, fun);
144
145 return usb_endpoint_manager_add_ep(&vhc->ep_manager,
146 address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1, 0,
147 NULL, NULL);
148
149}
150
151/** Unregister endpoint (free some bandwidth reservation).
152 *
153 * @param[in] fun Device function the action was invoked on.
154 * @param[in] address USB address of the device.
155 * @param[in] endpoint Endpoint number.
156 * @param[in] direction Endpoint data direction.
157 * @return Error code.
158 */
159static int unregister_endpoint(ddf_fun_t *fun, usb_address_t address,
160 usb_endpoint_t endpoint, usb_direction_t direction)
161{
162 VHC_DATA(vhc, fun);
163
164 int rc = usb_endpoint_manager_remove_ep(&vhc->ep_manager,
165 address, endpoint, direction, NULL, NULL);
166
167 return rc;
168}
169#if 0
170/** Schedule interrupt out transfer.
171 *
172 * The callback is supposed to be called once the transfer (on the wire) is
173 * complete regardless of the outcome.
174 * However, the callback could be called only when this function returns
175 * with success status (i.e. returns EOK).
176 *
177 * @param[in] fun Device function the action was invoked on.
178 * @param[in] target Target pipe (address and endpoint number) specification.
179 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
180 * by the caller).
181 * @param[in] size Size of the @p data buffer in bytes.
182 * @param[in] callback Callback to be issued once the transfer is complete.
183 * @param[in] arg Pass-through argument to the callback.
184 * @return Error code.
185 */
186static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
187 void *data, size_t size,
188 usbhc_iface_transfer_out_callback_t callback, void *arg)
189{
190 VHC_DATA(vhc, fun);
191
192 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
193 target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_INTERRUPT,
194 fun, arg);
195 if (transfer == NULL) {
196 return ENOMEM;
197 }
198
199 transfer->data_buffer = data;
200 transfer->data_buffer_size = size;
201 transfer->callback_out = callback;
202
203 int rc = vhc_virtdev_add_transfer(vhc, transfer);
204 if (rc != EOK) {
205 free(transfer);
206 return rc;
207 }
208
209 return EOK;
210}
211
212/** Schedule interrupt in transfer.
213 *
214 * The callback is supposed to be called once the transfer (on the wire) is
215 * complete regardless of the outcome.
216 * However, the callback could be called only when this function returns
217 * with success status (i.e. returns EOK).
218 *
219 * @param[in] fun Device function the action was invoked on.
220 * @param[in] target Target pipe (address and endpoint number) specification.
221 * @param[in] data Buffer where to store the data (in USB endianess,
222 * allocated and deallocated by the caller).
223 * @param[in] size Size of the @p data buffer in bytes.
224 * @param[in] callback Callback to be issued once the transfer is complete.
225 * @param[in] arg Pass-through argument to the callback.
226 * @return Error code.
227 */
228static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
229 void *data, size_t size,
230 usbhc_iface_transfer_in_callback_t callback, void *arg)
231{
232 VHC_DATA(vhc, fun);
233
234 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
235 target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_INTERRUPT,
236 fun, arg);
237 if (transfer == NULL) {
238 return ENOMEM;
239 }
240
241 transfer->data_buffer = data;
242 transfer->data_buffer_size = size;
243 transfer->callback_in = callback;
244
245 int rc = vhc_virtdev_add_transfer(vhc, transfer);
246 if (rc != EOK) {
247 free(transfer);
248 return rc;
249 }
250
251 return EOK;
252}
253
254/** Schedule bulk out transfer.
255 *
256 * The callback is supposed to be called once the transfer (on the wire) is
257 * complete regardless of the outcome.
258 * However, the callback could be called only when this function returns
259 * with success status (i.e. returns EOK).
260 *
261 * @param[in] fun Device function the action was invoked on.
262 * @param[in] target Target pipe (address and endpoint number) specification.
263 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
264 * by the caller).
265 * @param[in] size Size of the @p data buffer in bytes.
266 * @param[in] callback Callback to be issued once the transfer is complete.
267 * @param[in] arg Pass-through argument to the callback.
268 * @return Error code.
269 */
270static int bulk_out(ddf_fun_t *fun, usb_target_t target,
271 void *data, size_t size,
272 usbhc_iface_transfer_out_callback_t callback, void *arg)
273{
274 UNSUPPORTED("bulk_out");
275
276 return ENOTSUP;
277}
278
279/** Schedule bulk in transfer.
280 *
281 * The callback is supposed to be called once the transfer (on the wire) is
282 * complete regardless of the outcome.
283 * However, the callback could be called only when this function returns
284 * with success status (i.e. returns EOK).
285 *
286 * @param[in] fun Device function the action was invoked on.
287 * @param[in] target Target pipe (address and endpoint number) specification.
288 * @param[in] data Buffer where to store the data (in USB endianess,
289 * allocated and deallocated by the caller).
290 * @param[in] size Size of the @p data buffer in bytes.
291 * @param[in] callback Callback to be issued once the transfer is complete.
292 * @param[in] arg Pass-through argument to the callback.
293 * @return Error code.
294 */
295static int bulk_in(ddf_fun_t *fun, usb_target_t target,
296 void *data, size_t size,
297 usbhc_iface_transfer_in_callback_t callback, void *arg)
298{
299 UNSUPPORTED("bulk_in");
300
301 return ENOTSUP;
302}
303
304/** Schedule control write transfer.
305 *
306 * The callback is supposed to be called once the transfer (on the wire) is
307 * complete regardless of the outcome.
308 * However, the callback could be called only when this function returns
309 * with success status (i.e. returns EOK).
310 *
311 * @param[in] fun Device function the action was invoked on.
312 * @param[in] target Target pipe (address and endpoint number) specification.
313 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
314 * and deallocated by the caller).
315 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
316 * @param[in] data_buffer Data buffer (in USB endianess, allocated and
317 * deallocated by the caller).
318 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
319 * @param[in] callback Callback to be issued once the transfer is complete.
320 * @param[in] arg Pass-through argument to the callback.
321 * @return Error code.
322 */
323static int control_write(ddf_fun_t *fun, usb_target_t target,
324 void *setup_packet, size_t setup_packet_size,
325 void *data_buffer, size_t data_buffer_size,
326 usbhc_iface_transfer_out_callback_t callback, void *arg)
327{
328 VHC_DATA(vhc, fun);
329
330 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
331 target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_CONTROL,
332 fun, arg);
333 if (transfer == NULL) {
334 return ENOMEM;
335 }
336
337 transfer->setup_buffer = setup_packet;
338 transfer->setup_buffer_size = setup_packet_size;
339 transfer->data_buffer = data_buffer;
340 transfer->data_buffer_size = data_buffer_size;
341 transfer->callback_out = callback;
342
343 int rc = vhc_virtdev_add_transfer(vhc, transfer);
344 if (rc != EOK) {
345 free(transfer);
346 return rc;
347 }
348
349 return EOK;
350}
351
352/** Schedule control read transfer.
353 *
354 * The callback is supposed to be called once the transfer (on the wire) is
355 * complete regardless of the outcome.
356 * However, the callback could be called only when this function returns
357 * with success status (i.e. returns EOK).
358 *
359 * @param[in] fun Device function the action was invoked on.
360 * @param[in] target Target pipe (address and endpoint number) specification.
361 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
362 * and deallocated by the caller).
363 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
364 * @param[in] data_buffer Buffer where to store the data (in USB endianess,
365 * allocated and deallocated by the caller).
366 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
367 * @param[in] callback Callback to be issued once the transfer is complete.
368 * @param[in] arg Pass-through argument to the callback.
369 * @return Error code.
370 */
371static int control_read(ddf_fun_t *fun, usb_target_t target,
372 void *setup_packet, size_t setup_packet_size,
373 void *data_buffer, size_t data_buffer_size,
374 usbhc_iface_transfer_in_callback_t callback, void *arg)
375{
376 VHC_DATA(vhc, fun);
377
378 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
379 target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_CONTROL,
380 fun, arg);
381 if (transfer == NULL) {
382 return ENOMEM;
383 }
384
385 transfer->setup_buffer = setup_packet;
386 transfer->setup_buffer_size = setup_packet_size;
387 transfer->data_buffer = data_buffer;
388 transfer->data_buffer_size = data_buffer_size;
389 transfer->callback_in = callback;
390
391 int rc = vhc_virtdev_add_transfer(vhc, transfer);
392 if (rc != EOK) {
393 free(transfer);
394 return rc;
395 }
396
397 return EOK;
398}
399#endif
400static int usb_read(ddf_fun_t *fun, usb_target_t target, uint64_t setup_buffer,
401 uint8_t *data_buffer, size_t data_buffer_size,
402 usbhc_iface_transfer_in_callback_t callback, void *arg)
403{
404 VHC_DATA(vhc, fun);
405
406 endpoint_t *ep = usb_endpoint_manager_find_ep(&vhc->ep_manager,
407 target.address, target.endpoint, USB_DIRECTION_IN);
408 if (ep == NULL) {
409 return ENOENT;
410 }
411 const usb_transfer_type_t transfer_type = ep->transfer_type;
412
413
414 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
415 target.endpoint, USB_DIRECTION_IN, transfer_type,
416 fun, arg);
417 if (transfer == NULL) {
418 return ENOMEM;
419 }
420 if (transfer_type == USB_TRANSFER_CONTROL) {
421 transfer->setup_buffer = malloc(sizeof(uint64_t));
422 assert(transfer->setup_buffer);
423 memcpy(transfer->setup_buffer, &setup_buffer, sizeof(uint64_t));
424 transfer->setup_buffer_size = sizeof(uint64_t);
425 }
426 transfer->data_buffer = data_buffer;
427 transfer->data_buffer_size = data_buffer_size;
428 transfer->callback_in = callback;
429
430 int rc = vhc_virtdev_add_transfer(vhc, transfer);
431 if (rc != EOK) {
432 if (transfer->setup_buffer != NULL) {
433 free(transfer->setup_buffer);
434 }
435 free(transfer);
436 return rc;
437 }
438
439 return EOK;
440}
441
442static int usb_write(ddf_fun_t *fun, usb_target_t target, uint64_t setup_buffer,
443 const uint8_t *data_buffer, size_t data_buffer_size,
444 usbhc_iface_transfer_out_callback_t callback, void *arg)
445{
446 VHC_DATA(vhc, fun);
447
448 endpoint_t *ep = usb_endpoint_manager_find_ep(&vhc->ep_manager,
449 target.address, target.endpoint, USB_DIRECTION_OUT);
450 if (ep == NULL) {
451 return ENOENT;
452 }
453 const usb_transfer_type_t transfer_type = ep->transfer_type;
454
455
456 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
457 target.endpoint, USB_DIRECTION_OUT, transfer_type,
458 fun, arg);
459 if (transfer == NULL) {
460 return ENOMEM;
461 }
462 if (transfer_type == USB_TRANSFER_CONTROL) {
463 transfer->setup_buffer = malloc(sizeof(uint64_t));
464 assert(transfer->setup_buffer);
465 memcpy(transfer->setup_buffer, &setup_buffer, sizeof(uint64_t));
466 transfer->setup_buffer_size = sizeof(uint64_t);
467 }
468 transfer->data_buffer = (void*)data_buffer;
469 transfer->data_buffer_size = data_buffer_size;
470 transfer->callback_out = callback;
471
472 int rc = vhc_virtdev_add_transfer(vhc, transfer);
473 if (rc != EOK) {
474 free(transfer->setup_buffer);
475 free(transfer);
476 return rc;
477 }
478
479 return EOK;
480}
481
482static int tell_address(ddf_fun_t *fun, usb_address_t *address)
483{
484 UNSUPPORTED("tell_address");
485
486 return ENOTSUP;
487}
488
489static int usb_iface_get_hc_handle_rh_impl(ddf_fun_t *root_hub_fun,
490 devman_handle_t *handle)
491{
492 VHC_DATA(vhc, root_hub_fun);
493
494 *handle = vhc->hc_fun->handle;
495
496 return EOK;
497}
498
499static int tell_address_rh(ddf_fun_t *root_hub_fun, usb_address_t *address)
500{
501 VHC_DATA(vhc, root_hub_fun);
502
503 devman_handle_t handle = root_hub_fun->handle;
504
505 usb_log_debug("tell_address_rh(handle=%" PRIun ")\n", handle);
506 const usb_address_t addr =
507 usb_device_manager_find_address(&vhc->dev_manager, handle);
508 if (addr < 0) {
509 return addr;
510 } else {
511 *address = addr;
512 return EOK;
513 }
514}
515
516usbhc_iface_t vhc_iface = {
517 .request_address = request_address,
518 .bind_address = bind_address,
519 .find_by_address = find_by_address,
520 .release_address = release_address,
521
522 .register_endpoint = register_endpoint,
523 .unregister_endpoint = unregister_endpoint,
524
525 .write = usb_write,
526 .read = usb_read,
527};
528
529usb_iface_t vhc_usb_iface = {
530 .get_hc_handle = usb_iface_get_hc_handle_hc_impl,
531 .get_my_address = tell_address
532};
533
534usb_iface_t rh_usb_iface = {
535 .get_hc_handle = usb_iface_get_hc_handle_rh_impl,
536 .get_my_address = tell_address_rh
537};
538
539
540/**
541 * @}
542 */
Note: See TracBrowser for help on using the repository browser.