source: mainline/uspace/drv/ohci/iface.c@ 391d55b

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

OHCI bandwidth

  • Property mode set to 100644
File size: 17.3 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/** @addtogroup drvusbohci
29 * @{
30 */
31/** @file
32 * USB-HC interface implementation.
33 */
34#include <ddf/driver.h>
35#include <errno.h>
36
37#include <usb/debug.h>
38
39#include "iface.h"
40#include "hc.h"
41
42#define UNSUPPORTED(methodname) \
43 usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \
44 methodname, __FILE__, __LINE__)
45
46/** Reserve default address.
47 *
48 * This function may block the caller.
49 *
50 * @param[in] fun Device function the action was invoked on.
51 * @param[in] speed Speed of the device for which the default address is
52 * reserved.
53 * @return Error code.
54 */
55static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed)
56{
57 assert(fun);
58 hc_t *hc = fun_to_hc(fun);
59 assert(hc);
60 usb_log_debug("Default address request with speed %d.\n", speed);
61 usb_device_keeper_reserve_default_address(&hc->manager, speed);
62 return EOK;
63}
64/*----------------------------------------------------------------------------*/
65/** Release default address.
66 *
67 * @param[in] fun Device function the action was invoked on.
68 * @return Error code.
69 */
70static int release_default_address(ddf_fun_t *fun)
71{
72 assert(fun);
73 hc_t *hc = fun_to_hc(fun);
74 assert(hc);
75 usb_log_debug("Default address release.\n");
76 usb_device_keeper_release_default_address(&hc->manager);
77 return EOK;
78}
79/*----------------------------------------------------------------------------*/
80/** Found free USB address.
81 *
82 * @param[in] fun Device function the action was invoked on.
83 * @param[in] speed Speed of the device that will get this address.
84 * @param[out] address Non-null pointer where to store the free address.
85 * @return Error code.
86 */
87static int request_address(
88 ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
89{
90 assert(fun);
91 hc_t *hc = fun_to_hc(fun);
92 assert(hc);
93 assert(address);
94
95 usb_log_debug("Address request with speed %d.\n", speed);
96 *address = device_keeper_get_free_address(&hc->manager, speed);
97 usb_log_debug("Address request with result: %d.\n", *address);
98 if (*address <= 0)
99 return *address;
100 return EOK;
101}
102/*----------------------------------------------------------------------------*/
103/** Bind USB address with device devman handle.
104 *
105 * @param[in] fun Device function the action was invoked on.
106 * @param[in] address USB address of the device.
107 * @param[in] handle Devman handle of the device.
108 * @return Error code.
109 */
110static int bind_address(
111 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
112{
113 assert(fun);
114 hc_t *hc = fun_to_hc(fun);
115 assert(hc);
116 usb_log_debug("Address bind %d-%d.\n", address, handle);
117 usb_device_keeper_bind(&hc->manager, address, handle);
118 return EOK;
119}
120/*----------------------------------------------------------------------------*/
121/** Release previously requested address.
122 *
123 * @param[in] fun Device function the action was invoked on.
124 * @param[in] address USB address to be released.
125 * @return Error code.
126 */
127static int release_address(ddf_fun_t *fun, usb_address_t address)
128{
129 assert(fun);
130 hc_t *hc = fun_to_hc(fun);
131 assert(hc);
132 usb_log_debug("Address release %d.\n", address);
133 usb_device_keeper_release(&hc->manager, address);
134 return EOK;
135}
136/*----------------------------------------------------------------------------*/
137/** Register endpoint for bandwidth reservation.
138 *
139 * @param[in] fun Device function the action was invoked on.
140 * @param[in] address USB address of the device.
141 * @param[in] endpoint Endpoint number.
142 * @param[in] transfer_type USB transfer type.
143 * @param[in] direction Endpoint data direction.
144 * @param[in] max_packet_size Max packet size of the endpoint.
145 * @param[in] interval Polling interval.
146 * @return Error code.
147 */
148static int register_endpoint(
149 ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
150 usb_transfer_type_t transfer_type, usb_direction_t direction,
151 size_t max_packet_size, unsigned int interval)
152{
153 assert(fun);
154 hc_t *hc = fun_to_hc(fun);
155 assert(hc);
156 if (address == hc->rh.address)
157 return EOK;
158 const usb_speed_t speed =
159 usb_device_keeper_get_speed(&hc->manager, address);
160 const size_t size = max_packet_size;
161 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
162 address, endpoint, usb_str_transfer_type(transfer_type),
163 usb_str_speed(speed), direction, size, max_packet_size, interval);
164 return bandwidth_reserve(&hc->bandwidth, address, endpoint, direction,
165 speed, transfer_type, max_packet_size, size, interval);
166}
167/*----------------------------------------------------------------------------*/
168/** Unregister endpoint (free some bandwidth reservation).
169 *
170 * @param[in] fun Device function the action was invoked on.
171 * @param[in] address USB address of the device.
172 * @param[in] endpoint Endpoint number.
173 * @param[in] direction Endpoint data direction.
174 * @return Error code.
175 */
176static int unregister_endpoint(
177 ddf_fun_t *fun, usb_address_t address,
178 usb_endpoint_t endpoint, usb_direction_t direction)
179{
180 assert(fun);
181 hc_t *hc = fun_to_hc(fun);
182 assert(hc);
183 usb_log_debug("Unregister endpoint %d:%d %d.\n",
184 address, endpoint, direction);
185 return bandwidth_release(&hc->bandwidth, address, endpoint, direction);
186
187 return ENOTSUP;
188}
189/*----------------------------------------------------------------------------*/
190/** Schedule interrupt out transfer.
191 *
192 * The callback is supposed to be called once the transfer (on the wire) is
193 * complete regardless of the outcome.
194 * However, the callback could be called only when this function returns
195 * with success status (i.e. returns EOK).
196 *
197 * @param[in] fun Device function the action was invoked on.
198 * @param[in] target Target pipe (address and endpoint number) specification.
199 * @param[in] max_packet_size Max packet size for the transfer.
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(
208 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
209 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
210{
211 assert(fun);
212 hc_t *hc = fun_to_hc(fun);
213 assert(hc);
214 usb_speed_t speed =
215 usb_device_keeper_get_speed(&hc->manager, target.address);
216
217 usb_log_debug("Interrupt OUT %d:%d %zu(%zu).\n",
218 target.address, target.endpoint, size, max_packet_size);
219
220 usb_transfer_batch_t *batch =
221 batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size,
222 speed, data, size, NULL, 0, NULL, callback, arg, &hc->manager);
223 if (!batch)
224 return ENOMEM;
225 batch_interrupt_out(batch);
226 const int ret = hc_schedule(hc, batch);
227 if (ret != EOK) {
228 batch_dispose(batch);
229 }
230 return ret;
231}
232/*----------------------------------------------------------------------------*/
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] max_packet_size Max packet size for the transfer.
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(
251 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
252 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
253{
254 assert(fun);
255 hc_t *hc = fun_to_hc(fun);
256 assert(hc);
257 usb_speed_t speed =
258 usb_device_keeper_get_speed(&hc->manager, target.address);
259 usb_log_debug("Interrupt IN %d:%d %zu(%zu).\n",
260 target.address, target.endpoint, size, max_packet_size);
261
262 usb_transfer_batch_t *batch =
263 batch_get(fun, target, USB_TRANSFER_INTERRUPT, max_packet_size,
264 speed, data, size, NULL, 0, callback, NULL, arg, &hc->manager);
265 if (!batch)
266 return ENOMEM;
267 batch_interrupt_in(batch);
268 const int ret = hc_schedule(hc, batch);
269 if (ret != EOK) {
270 batch_dispose(batch);
271 }
272 return ret;
273}
274/*----------------------------------------------------------------------------*/
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] max_packet_size Max packet size for the transfer.
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(
293 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
294 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
295{
296 assert(fun);
297 hc_t *hc = fun_to_hc(fun);
298 assert(hc);
299 usb_speed_t speed =
300 usb_device_keeper_get_speed(&hc->manager, target.address);
301
302 usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n",
303 target.address, target.endpoint, size, max_packet_size);
304
305 usb_transfer_batch_t *batch =
306 batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed,
307 data, size, NULL, 0, NULL, callback, arg, &hc->manager);
308 if (!batch)
309 return ENOMEM;
310 batch_bulk_out(batch);
311 const int ret = hc_schedule(hc, batch);
312 if (ret != EOK) {
313 batch_dispose(batch);
314 }
315 return ret;
316}
317/*----------------------------------------------------------------------------*/
318/** Schedule bulk in transfer.
319 *
320 * The callback is supposed to be called once the transfer (on the wire) is
321 * complete regardless of the outcome.
322 * However, the callback could be called only when this function returns
323 * with success status (i.e. returns EOK).
324 *
325 * @param[in] fun Device function the action was invoked on.
326 * @param[in] target Target pipe (address and endpoint number) specification.
327 * @param[in] max_packet_size Max packet size for the transfer.
328 * @param[in] data Buffer where to store the data (in USB endianess,
329 * allocated and deallocated by the caller).
330 * @param[in] size Size of the @p data buffer in bytes.
331 * @param[in] callback Callback to be issued once the transfer is complete.
332 * @param[in] arg Pass-through argument to the callback.
333 * @return Error code.
334 */
335static int bulk_in(
336 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size, void *data,
337 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
338{
339 assert(fun);
340 hc_t *hc = fun_to_hc(fun);
341 assert(hc);
342 usb_speed_t speed =
343 usb_device_keeper_get_speed(&hc->manager, target.address);
344 usb_log_debug("Bulk IN %d:%d %zu(%zu).\n",
345 target.address, target.endpoint, size, max_packet_size);
346
347 usb_transfer_batch_t *batch =
348 batch_get(fun, target, USB_TRANSFER_BULK, max_packet_size, speed,
349 data, size, NULL, 0, callback, NULL, arg, &hc->manager);
350 if (!batch)
351 return ENOMEM;
352 batch_bulk_in(batch);
353 const int ret = hc_schedule(hc, batch);
354 if (ret != EOK) {
355 batch_dispose(batch);
356 }
357 return ret;
358}
359/*----------------------------------------------------------------------------*/
360/** Schedule control write transfer.
361 *
362 * The callback is supposed to be called once the transfer (on the wire) is
363 * complete regardless of the outcome.
364 * However, the callback could be called only when this function returns
365 * with success status (i.e. returns EOK).
366 *
367 * @param[in] fun Device function the action was invoked on.
368 * @param[in] target Target pipe (address and endpoint number) specification.
369 * @param[in] max_packet_size Max packet size for the transfer.
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 Data buffer (in USB endianess, allocated and
374 * 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_write(
381 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
382 void *setup_data, size_t setup_size, void *data, size_t size,
383 usbhc_iface_transfer_out_callback_t callback, void *arg)
384{
385 assert(fun);
386 hc_t *hc = fun_to_hc(fun);
387 assert(hc);
388 usb_speed_t speed =
389 usb_device_keeper_get_speed(&hc->manager, target.address);
390 usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n",
391 speed, target.address, target.endpoint, size, max_packet_size);
392
393 if (setup_size != 8)
394 return EINVAL;
395
396 usb_transfer_batch_t *batch =
397 batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size,
398 speed, data, size, setup_data, setup_size, NULL, callback, arg,
399 &hc->manager);
400 if (!batch)
401 return ENOMEM;
402 usb_device_keeper_reset_if_need(&hc->manager, target, setup_data);
403 batch_control_write(batch);
404 const int ret = hc_schedule(hc, batch);
405 if (ret != EOK) {
406 batch_dispose(batch);
407 }
408 return ret;
409}
410/*----------------------------------------------------------------------------*/
411/** Schedule control read transfer.
412 *
413 * The callback is supposed to be called once the transfer (on the wire) is
414 * complete regardless of the outcome.
415 * However, the callback could be called only when this function returns
416 * with success status (i.e. returns EOK).
417 *
418 * @param[in] fun Device function the action was invoked on.
419 * @param[in] target Target pipe (address and endpoint number) specification.
420 * @param[in] max_packet_size Max packet size for the transfer.
421 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
422 * and deallocated by the caller).
423 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
424 * @param[in] data_buffer Buffer where to store the data (in USB endianess,
425 * allocated and deallocated by the caller).
426 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
427 * @param[in] callback Callback to be issued once the transfer is complete.
428 * @param[in] arg Pass-through argument to the callback.
429 * @return Error code.
430 */
431static int control_read(
432 ddf_fun_t *fun, usb_target_t target, size_t max_packet_size,
433 void *setup_data, size_t setup_size, void *data, size_t size,
434 usbhc_iface_transfer_in_callback_t callback, void *arg)
435{
436 assert(fun);
437 hc_t *hc = fun_to_hc(fun);
438 assert(hc);
439 usb_speed_t speed =
440 usb_device_keeper_get_speed(&hc->manager, target.address);
441
442 usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n",
443 speed, target.address, target.endpoint, size, max_packet_size);
444 usb_transfer_batch_t *batch =
445 batch_get(fun, target, USB_TRANSFER_CONTROL, max_packet_size,
446 speed, data, size, setup_data, setup_size, callback, NULL, arg,
447 &hc->manager);
448 if (!batch)
449 return ENOMEM;
450 batch_control_read(batch);
451 const int ret = hc_schedule(hc, batch);
452 if (ret != EOK) {
453 batch_dispose(batch);
454 }
455 return ret;
456}
457/*----------------------------------------------------------------------------*/
458/** Host controller interface implementation for OHCI. */
459usbhc_iface_t hc_iface = {
460 .reserve_default_address = reserve_default_address,
461 .release_default_address = release_default_address,
462 .request_address = request_address,
463 .bind_address = bind_address,
464 .release_address = release_address,
465
466 .register_endpoint = register_endpoint,
467 .unregister_endpoint = unregister_endpoint,
468
469 .interrupt_out = interrupt_out,
470 .interrupt_in = interrupt_in,
471
472 .bulk_out = bulk_out,
473 .bulk_in = bulk_in,
474
475 .control_write = control_write,
476 .control_read = control_read,
477};
478
479/**
480 * @}
481 */
Note: See TracBrowser for help on using the repository browser.