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

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

libusbhost: endpoint_t uses get/destroy pair, instead of init/destroy.

endpoint_init always returned EOK, thus allocation could be moved in.
Also, it makes no sense to create this structures on stack.

  • Property mode set to 100644
File size: 14.7 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 = device_keeper_get_free_address(&vhc->dev_keeper,
65 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_keeper_bind(&vhc->dev_keeper, 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 bool found =
107 usb_device_keeper_find_by_address(&vhc->dev_keeper, address, handle);
108 return found ? EOK : ENOENT;
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_keeper_release(&vhc->dev_keeper, 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 /* TODO: Use usb_endpoint_manager_add_ep */
144 VHC_DATA(vhc, fun);
145
146 endpoint_t *ep = endpoint_get(
147 address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1);
148 if (ep == NULL) {
149 return ENOMEM;
150 }
151
152 int rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
153 if (rc != EOK) {
154 endpoint_destroy(ep);
155 return rc;
156 }
157
158 return EOK;
159}
160
161/** Unregister endpoint (free some bandwidth reservation).
162 *
163 * @param[in] fun Device function the action was invoked on.
164 * @param[in] address USB address of the device.
165 * @param[in] endpoint Endpoint number.
166 * @param[in] direction Endpoint data direction.
167 * @return Error code.
168 */
169static int unregister_endpoint(ddf_fun_t *fun, usb_address_t address,
170 usb_endpoint_t endpoint, usb_direction_t direction)
171{
172 VHC_DATA(vhc, fun);
173
174 endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
175 address, endpoint, direction, NULL);
176 if (ep == NULL) {
177 return ENOENT;
178 }
179
180 int rc = usb_endpoint_manager_unregister_ep(&vhc->ep_manager,
181 address, endpoint, direction);
182
183 return rc;
184}
185
186/** Schedule interrupt out transfer.
187 *
188 * The callback is supposed to be called once the transfer (on the wire) is
189 * complete regardless of the outcome.
190 * However, the callback could be called only when this function returns
191 * with success status (i.e. returns EOK).
192 *
193 * @param[in] fun Device function the action was invoked on.
194 * @param[in] target Target pipe (address and endpoint number) specification.
195 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
196 * by the caller).
197 * @param[in] size Size of the @p data buffer in bytes.
198 * @param[in] callback Callback to be issued once the transfer is complete.
199 * @param[in] arg Pass-through argument to the callback.
200 * @return Error code.
201 */
202static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
203 void *data, size_t size,
204 usbhc_iface_transfer_out_callback_t callback, void *arg)
205{
206 VHC_DATA(vhc, fun);
207
208 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
209 target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_INTERRUPT,
210 fun, arg);
211 if (transfer == NULL) {
212 return ENOMEM;
213 }
214
215 transfer->data_buffer = data;
216 transfer->data_buffer_size = size;
217 transfer->callback_out = callback;
218
219 int rc = vhc_virtdev_add_transfer(vhc, transfer);
220 if (rc != EOK) {
221 free(transfer);
222 return rc;
223 }
224
225 return EOK;
226}
227
228/** Schedule interrupt in transfer.
229 *
230 * The callback is supposed to be called once the transfer (on the wire) is
231 * complete regardless of the outcome.
232 * However, the callback could be called only when this function returns
233 * with success status (i.e. returns EOK).
234 *
235 * @param[in] fun Device function the action was invoked on.
236 * @param[in] target Target pipe (address and endpoint number) specification.
237 * @param[in] data Buffer where to store the data (in USB endianess,
238 * allocated and deallocated by the caller).
239 * @param[in] size Size of the @p data buffer in bytes.
240 * @param[in] callback Callback to be issued once the transfer is complete.
241 * @param[in] arg Pass-through argument to the callback.
242 * @return Error code.
243 */
244static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
245 void *data, size_t size,
246 usbhc_iface_transfer_in_callback_t callback, void *arg)
247{
248 VHC_DATA(vhc, fun);
249
250 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
251 target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_INTERRUPT,
252 fun, arg);
253 if (transfer == NULL) {
254 return ENOMEM;
255 }
256
257 transfer->data_buffer = data;
258 transfer->data_buffer_size = size;
259 transfer->callback_in = callback;
260
261 int rc = vhc_virtdev_add_transfer(vhc, transfer);
262 if (rc != EOK) {
263 free(transfer);
264 return rc;
265 }
266
267 return EOK;
268}
269
270/** Schedule bulk out transfer.
271 *
272 * The callback is supposed to be called once the transfer (on the wire) is
273 * complete regardless of the outcome.
274 * However, the callback could be called only when this function returns
275 * with success status (i.e. returns EOK).
276 *
277 * @param[in] fun Device function the action was invoked on.
278 * @param[in] target Target pipe (address and endpoint number) specification.
279 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
280 * by the caller).
281 * @param[in] size Size of the @p data buffer in bytes.
282 * @param[in] callback Callback to be issued once the transfer is complete.
283 * @param[in] arg Pass-through argument to the callback.
284 * @return Error code.
285 */
286static int bulk_out(ddf_fun_t *fun, usb_target_t target,
287 void *data, size_t size,
288 usbhc_iface_transfer_out_callback_t callback, void *arg)
289{
290 UNSUPPORTED("bulk_out");
291
292 return ENOTSUP;
293}
294
295/** Schedule bulk in transfer.
296 *
297 * The callback is supposed to be called once the transfer (on the wire) is
298 * complete regardless of the outcome.
299 * However, the callback could be called only when this function returns
300 * with success status (i.e. returns EOK).
301 *
302 * @param[in] fun Device function the action was invoked on.
303 * @param[in] target Target pipe (address and endpoint number) specification.
304 * @param[in] data Buffer where to store the data (in USB endianess,
305 * allocated and deallocated by the caller).
306 * @param[in] size Size of the @p data buffer in bytes.
307 * @param[in] callback Callback to be issued once the transfer is complete.
308 * @param[in] arg Pass-through argument to the callback.
309 * @return Error code.
310 */
311static int bulk_in(ddf_fun_t *fun, usb_target_t target,
312 void *data, size_t size,
313 usbhc_iface_transfer_in_callback_t callback, void *arg)
314{
315 UNSUPPORTED("bulk_in");
316
317 return ENOTSUP;
318}
319
320/** Schedule control write transfer.
321 *
322 * The callback is supposed to be called once the transfer (on the wire) is
323 * complete regardless of the outcome.
324 * However, the callback could be called only when this function returns
325 * with success status (i.e. returns EOK).
326 *
327 * @param[in] fun Device function the action was invoked on.
328 * @param[in] target Target pipe (address and endpoint number) specification.
329 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
330 * and deallocated by the caller).
331 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
332 * @param[in] data_buffer Data buffer (in USB endianess, allocated and
333 * deallocated by the caller).
334 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
335 * @param[in] callback Callback to be issued once the transfer is complete.
336 * @param[in] arg Pass-through argument to the callback.
337 * @return Error code.
338 */
339static int control_write(ddf_fun_t *fun, usb_target_t target,
340 void *setup_packet, size_t setup_packet_size,
341 void *data_buffer, size_t data_buffer_size,
342 usbhc_iface_transfer_out_callback_t callback, void *arg)
343{
344 VHC_DATA(vhc, fun);
345
346 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
347 target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_CONTROL,
348 fun, arg);
349 if (transfer == NULL) {
350 return ENOMEM;
351 }
352
353 transfer->setup_buffer = setup_packet;
354 transfer->setup_buffer_size = setup_packet_size;
355 transfer->data_buffer = data_buffer;
356 transfer->data_buffer_size = data_buffer_size;
357 transfer->callback_out = callback;
358
359 int rc = vhc_virtdev_add_transfer(vhc, transfer);
360 if (rc != EOK) {
361 free(transfer);
362 return rc;
363 }
364
365 return EOK;
366}
367
368/** Schedule control read transfer.
369 *
370 * The callback is supposed to be called once the transfer (on the wire) is
371 * complete regardless of the outcome.
372 * However, the callback could be called only when this function returns
373 * with success status (i.e. returns EOK).
374 *
375 * @param[in] fun Device function the action was invoked on.
376 * @param[in] target Target pipe (address and endpoint number) specification.
377 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
378 * and deallocated by the caller).
379 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
380 * @param[in] data_buffer Buffer where to store the data (in USB endianess,
381 * allocated and deallocated by the caller).
382 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
383 * @param[in] callback Callback to be issued once the transfer is complete.
384 * @param[in] arg Pass-through argument to the callback.
385 * @return Error code.
386 */
387static int control_read(ddf_fun_t *fun, usb_target_t target,
388 void *setup_packet, size_t setup_packet_size,
389 void *data_buffer, size_t data_buffer_size,
390 usbhc_iface_transfer_in_callback_t callback, void *arg)
391{
392 VHC_DATA(vhc, fun);
393
394 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
395 target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_CONTROL,
396 fun, arg);
397 if (transfer == NULL) {
398 return ENOMEM;
399 }
400
401 transfer->setup_buffer = setup_packet;
402 transfer->setup_buffer_size = setup_packet_size;
403 transfer->data_buffer = data_buffer;
404 transfer->data_buffer_size = data_buffer_size;
405 transfer->callback_in = callback;
406
407 int rc = vhc_virtdev_add_transfer(vhc, transfer);
408 if (rc != EOK) {
409 free(transfer);
410 return rc;
411 }
412
413 return EOK;
414}
415
416static int tell_address(ddf_fun_t *fun, devman_handle_t handle,
417 usb_address_t *address)
418{
419 UNSUPPORTED("tell_address");
420
421 return ENOTSUP;
422}
423
424static int usb_iface_get_hc_handle_rh_impl(ddf_fun_t *root_hub_fun,
425 devman_handle_t *handle)
426{
427 VHC_DATA(vhc, root_hub_fun);
428
429 *handle = vhc->hc_fun->handle;
430
431 return EOK;
432}
433
434static int tell_address_rh(ddf_fun_t *root_hub_fun, devman_handle_t handle,
435 usb_address_t *address)
436{
437 VHC_DATA(vhc, root_hub_fun);
438
439 if (handle == 0) {
440 handle = root_hub_fun->handle;
441 }
442
443 usb_log_debug("tell_address_rh(handle=%" PRIun ")\n", handle);
444 usb_address_t addr = usb_device_keeper_find(&vhc->dev_keeper, handle);
445 if (addr < 0) {
446 return addr;
447 } else {
448 *address = addr;
449 return EOK;
450 }
451}
452
453usbhc_iface_t vhc_iface = {
454 .request_address = request_address,
455 .bind_address = bind_address,
456 .find_by_address = find_by_address,
457 .release_address = release_address,
458
459 .register_endpoint = register_endpoint,
460 .unregister_endpoint = unregister_endpoint,
461
462 .interrupt_out = interrupt_out,
463 .interrupt_in = interrupt_in,
464
465 .bulk_in = bulk_in,
466 .bulk_out = bulk_out,
467
468 .control_write = control_write,
469 .control_read = control_read
470};
471
472usb_iface_t vhc_usb_iface = {
473 .get_hc_handle = usb_iface_get_hc_handle_hc_impl,
474 .get_address = tell_address
475};
476
477usb_iface_t rh_usb_iface = {
478 .get_hc_handle = usb_iface_get_hc_handle_rh_impl,
479 .get_address = tell_address_rh
480};
481
482
483/**
484 * @}
485 */
Note: See TracBrowser for help on using the repository browser.