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

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

libusbhost: Make interfaces more symmetric.

Make usb_endpoint_manager interface easier to use and understand.
Move ep removal hook pointer from endpoint_t to hcd_t.

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