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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 15f3c3f was 5203e256, checked in by Martin Decky <martin@…>, 14 years ago

keep the drivers source tree tidy by using logical subdirectories

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