source: mainline/uspace/drv/vhc/connhost.c@ df25ab6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since df25ab6 was df25ab6, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

All HC drivers supports "get handle by address"

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