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

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

libusbhost: Store bandwidth in endpoint structure.

Remove redundant node_t tructure and use endpoint_t directly.

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