source: mainline/uspace/drv/bus/usb/ohci/hc.c@ 874381a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 874381a was e0a5d4c, checked in by Ondřej Hlavatý <aearsis@…>, 7 years ago

usb: update copyrights

The data was generated by a script, guided manually. If you feel your
name is missing somewhere, please add it!

The semi-automated process was roughly:

1) Changes per file and author (limited to our team) were counted
2) Trivial numbers were thrown away
3) Authors were sorted by lines added to file
4) All previous copyrights were replaced by the newly generated one
5) Hunks changing only year were discarded

It seems that a lot of my copyrights were added. It is due to me being
both sticking my nose everywhere and lazy to update the copyright right
away :)

  • Property mode set to 100644
File size: 17.6 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * Copyright (c) 2018 Ondrej Hlavaty
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup drvusbohcihc
31 * @{
32 */
33/** @file
34 * @brief OHCI Host controller driver routines
35 */
36
37#include <assert.h>
38#include <async.h>
39#include <errno.h>
40#include <macros.h>
41#include <mem.h>
42#include <stdlib.h>
43#include <str_error.h>
44#include <stddef.h>
45#include <stdint.h>
46
47#include <usb/debug.h>
48#include <usb/host/utility.h>
49#include <usb/usb.h>
50
51#include "ohci_bus.h"
52#include "ohci_batch.h"
53
54#include "hc.h"
55
56#define OHCI_USED_INTERRUPTS \
57 (I_SO | I_WDH | I_UE | I_RHSC)
58
59static const irq_pio_range_t ohci_pio_ranges[] = {
60 {
61 .base = 0,
62 .size = sizeof(ohci_regs_t)
63 }
64};
65
66static const irq_cmd_t ohci_irq_commands[] = {
67 {
68 .cmd = CMD_PIO_READ_32,
69 .dstarg = 1,
70 .addr = NULL
71 },
72 {
73 .cmd = CMD_AND,
74 .srcarg = 1,
75 .dstarg = 2,
76 .value = 0
77 },
78 {
79 .cmd = CMD_PREDICATE,
80 .srcarg = 2,
81 .value = 2
82 },
83 {
84 .cmd = CMD_PIO_WRITE_A_32,
85 .srcarg = 1,
86 .addr = NULL
87 },
88 {
89 .cmd = CMD_ACCEPT
90 }
91};
92
93static errno_t hc_init_transfer_lists(hc_t *instance);
94static errno_t hc_init_memory(hc_t *instance);
95
96/** Generate IRQ code.
97 * @param[out] ranges PIO ranges buffer.
98 * @param[in] ranges_size Size of the ranges buffer (bytes).
99 * @param[out] cmds Commands buffer.
100 * @param[in] cmds_size Size of the commands buffer (bytes).
101 * @param[in] hw_res Device's resources.
102 *
103 * @return Error code.
104 */
105errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
106{
107 assert(code);
108 assert(hw_res);
109
110 if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1)
111 return EINVAL;
112
113 const addr_range_t regs = hw_res->mem_ranges.ranges[0];
114
115 if (RNGSZ(regs) < sizeof(ohci_regs_t))
116 return EOVERFLOW;
117
118 code->ranges = malloc(sizeof(ohci_pio_ranges));
119 if (code->ranges == NULL)
120 return ENOMEM;
121
122 code->cmds = malloc(sizeof(ohci_irq_commands));
123 if (code->cmds == NULL) {
124 free(code->ranges);
125 return ENOMEM;
126 }
127
128 code->rangecount = ARRAY_SIZE(ohci_pio_ranges);
129 code->cmdcount = ARRAY_SIZE(ohci_irq_commands);
130
131 memcpy(code->ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
132 code->ranges[0].base = RNGABS(regs);
133
134 memcpy(code->cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
135 ohci_regs_t *registers = (ohci_regs_t *) RNGABSPTR(regs);
136 code->cmds[0].addr = (void *) &registers->interrupt_status;
137 code->cmds[3].addr = (void *) &registers->interrupt_status;
138 OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS);
139
140 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.",
141 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
142
143 *irq = hw_res->irqs.irqs[0];
144 return EOK;
145}
146
147/** Initialize OHCI hc driver structure
148 *
149 * @param[in] instance Memory place for the structure.
150 * @param[in] regs Device's resources
151 * @param[in] interrupts True if w interrupts should be used
152 * @return Error code
153 */
154errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
155{
156 hc_t *instance = hcd_to_hc(hcd);
157 assert(hw_res);
158 if (hw_res->mem_ranges.count != 1 ||
159 hw_res->mem_ranges.ranges[0].size < sizeof(ohci_regs_t))
160 return EINVAL;
161
162 errno_t ret = pio_enable_range(&hw_res->mem_ranges.ranges[0],
163 (void **) &instance->registers);
164 if (ret != EOK) {
165 usb_log_error("Failed to gain access to registers: %s.",
166 str_error(ret));
167 return ret;
168 }
169 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
170 hw_res->mem_ranges.ranges[0].address.absolute,
171 hw_res->mem_ranges.ranges[0].size);
172
173 list_initialize(&instance->pending_endpoints);
174 fibril_mutex_initialize(&instance->guard);
175
176 ret = hc_init_memory(instance);
177 if (ret != EOK) {
178 usb_log_error("Failed to create OHCI memory structures: %s.",
179 str_error(ret));
180 // TODO: We should disable pio access here
181 return ret;
182 }
183
184 return EOK;
185}
186
187/** Safely dispose host controller internal structures
188 *
189 * @param[in] instance Host controller structure to use.
190 */
191int hc_gone(hc_device_t *instance)
192{
193 assert(instance);
194 /* TODO: implement*/
195 return ENOTSUP;
196}
197
198void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
199{
200 assert(instance);
201 assert(ep);
202
203 endpoint_list_t *list = &instance->lists[ep->transfer_type];
204 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
205 assert(list);
206 assert(ohci_ep);
207
208 /* Enqueue ep */
209 switch (ep->transfer_type) {
210 case USB_TRANSFER_CONTROL:
211 OHCI_CLR(instance->registers->control, C_CLE);
212 endpoint_list_add_ep(list, ohci_ep);
213 OHCI_WR(instance->registers->control_current, 0);
214 OHCI_SET(instance->registers->control, C_CLE);
215 break;
216 case USB_TRANSFER_BULK:
217 OHCI_CLR(instance->registers->control, C_BLE);
218 endpoint_list_add_ep(list, ohci_ep);
219 OHCI_WR(instance->registers->bulk_current, 0);
220 OHCI_SET(instance->registers->control, C_BLE);
221 break;
222 case USB_TRANSFER_ISOCHRONOUS:
223 case USB_TRANSFER_INTERRUPT:
224 OHCI_CLR(instance->registers->control, C_PLE | C_IE);
225 endpoint_list_add_ep(list, ohci_ep);
226 OHCI_SET(instance->registers->control, C_PLE | C_IE);
227 break;
228 }
229}
230
231void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep)
232{
233 assert(instance);
234 assert(ep);
235
236 /* Dequeue ep */
237 endpoint_list_t *list = &instance->lists[ep->transfer_type];
238 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
239
240 assert(list);
241 assert(ohci_ep);
242 switch (ep->transfer_type) {
243 case USB_TRANSFER_CONTROL:
244 OHCI_CLR(instance->registers->control, C_CLE);
245 endpoint_list_remove_ep(list, ohci_ep);
246 OHCI_WR(instance->registers->control_current, 0);
247 OHCI_SET(instance->registers->control, C_CLE);
248 break;
249 case USB_TRANSFER_BULK:
250 OHCI_CLR(instance->registers->control, C_BLE);
251 endpoint_list_remove_ep(list, ohci_ep);
252 OHCI_WR(instance->registers->bulk_current, 0);
253 OHCI_SET(instance->registers->control, C_BLE);
254 break;
255 case USB_TRANSFER_ISOCHRONOUS:
256 case USB_TRANSFER_INTERRUPT:
257 OHCI_CLR(instance->registers->control, C_PLE | C_IE);
258 endpoint_list_remove_ep(list, ohci_ep);
259 OHCI_SET(instance->registers->control, C_PLE | C_IE);
260 break;
261 default:
262 break;
263 }
264}
265
266errno_t ohci_hc_status(bus_t *bus_base, uint32_t *status)
267{
268 assert(bus_base);
269 assert(status);
270
271 ohci_bus_t *bus = (ohci_bus_t *) bus_base;
272 hc_t *hc = bus->hc;
273 assert(hc);
274
275 if (hc->registers){
276 *status = OHCI_RD(hc->registers->interrupt_status);
277 OHCI_WR(hc->registers->interrupt_status, *status);
278 }
279 return EOK;
280}
281
282/** Add USB transfer to the schedule.
283 *
284 * @param[in] hcd HCD driver structure.
285 * @param[in] batch Batch representing the transfer.
286 * @return Error code.
287 */
288errno_t ohci_hc_schedule(usb_transfer_batch_t *batch)
289{
290 assert(batch);
291
292 ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(batch->ep);
293 hc_t *hc = bus->hc;
294 assert(hc);
295
296 /* Check for root hub communication */
297 if (batch->target.address == ohci_rh_get_address(&hc->rh)) {
298 usb_log_debug("OHCI root hub request.");
299 return ohci_rh_schedule(&hc->rh, batch);
300 }
301
302 endpoint_t *ep = batch->ep;
303 ohci_endpoint_t * const ohci_ep = ohci_endpoint_get(ep);
304 ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
305 int err;
306
307 if ((err = ohci_transfer_batch_prepare(ohci_batch)))
308 return err;
309
310 fibril_mutex_lock(&hc->guard);
311 if ((err = endpoint_activate_locked(ep, batch))) {
312 fibril_mutex_unlock(&hc->guard);
313 return err;
314 }
315
316 ohci_transfer_batch_commit(ohci_batch);
317 list_append(&ohci_ep->pending_link, &hc->pending_endpoints);
318 fibril_mutex_unlock(&hc->guard);
319
320 /* Control and bulk schedules need a kick to start working */
321 switch (batch->ep->transfer_type)
322 {
323 case USB_TRANSFER_CONTROL:
324 OHCI_SET(hc->registers->command_status, CS_CLF);
325 break;
326 case USB_TRANSFER_BULK:
327 OHCI_SET(hc->registers->command_status, CS_BLF);
328 break;
329 default:
330 break;
331 }
332
333 return EOK;
334}
335
336/** Interrupt handling routine
337 *
338 * @param[in] hcd HCD driver structure.
339 * @param[in] status Value of the status register at the time of interrupt.
340 */
341void ohci_hc_interrupt(bus_t *bus_base, uint32_t status)
342{
343 assert(bus_base);
344
345 ohci_bus_t *bus = (ohci_bus_t *) bus_base;
346 hc_t *hc = bus->hc;
347 assert(hc);
348
349 status = OHCI_RD(status);
350 assert(hc);
351 if ((status & ~I_SF) == 0) /* ignore sof status */
352 return;
353 usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status);
354 if (status & I_RHSC)
355 ohci_rh_interrupt(&hc->rh);
356
357 if (status & I_WDH) {
358 fibril_mutex_lock(&hc->guard);
359 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).", hc->hcca,
360 OHCI_RD(hc->registers->hcca),
361 (void *) addr_to_phys(hc->hcca));
362 usb_log_debug2("Periodic current: %#" PRIx32 ".",
363 OHCI_RD(hc->registers->periodic_current));
364
365 list_foreach_safe(hc->pending_endpoints, current, next) {
366 ohci_endpoint_t *ep
367 = list_get_instance(current, ohci_endpoint_t, pending_link);
368
369 ohci_transfer_batch_t *batch
370 = ohci_transfer_batch_get(ep->base.active_batch);
371 assert(batch);
372
373 if (ohci_transfer_batch_check_completed(batch)) {
374 endpoint_deactivate_locked(&ep->base);
375 list_remove(current);
376 hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset);
377 usb_transfer_batch_finish(&batch->base);
378 }
379 }
380 fibril_mutex_unlock(&hc->guard);
381 }
382
383 if (status & I_UE) {
384 usb_log_fatal("Error like no other!");
385 hc_start(&hc->base);
386 }
387
388}
389
390/** Turn off any (BIOS)driver that might be in control of the device.
391 *
392 * This function implements routines described in chapter 5.1.1.3 of the OHCI
393 * specification (page 40, pdf page 54).
394 *
395 * @param[in] instance OHCI hc driver structure.
396 */
397int hc_gain_control(hc_device_t *hcd)
398{
399 hc_t *instance = hcd_to_hc(hcd);
400
401 usb_log_debug("Requesting OHCI control.");
402 if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
403 /* Turn off legacy emulation, it should be enough to zero
404 * the lowest bit, but it caused problems. Thus clear all
405 * except GateA20 (causes restart on some hw).
406 * See page 145 of the specs for details.
407 */
408 volatile uint32_t *ohci_emulation_reg =
409 (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
410 usb_log_debug("OHCI legacy register %p: %x.",
411 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
412 /* Zero everything but A20State */
413 // TODO: should we ack interrupts before doing this?
414 OHCI_CLR(*ohci_emulation_reg, ~0x100);
415 usb_log_debug(
416 "OHCI legacy register (should be 0 or 0x100) %p: %x.",
417 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
418 }
419
420 /* Interrupt routing enabled => smm driver is active */
421 if (OHCI_RD(instance->registers->control) & C_IR) {
422 usb_log_debug("SMM driver: request ownership change.");
423 // TODO: should we ack interrupts before doing this?
424 OHCI_SET(instance->registers->command_status, CS_OCR);
425 /* Hope that SMM actually knows its stuff or we can hang here */
426 while (OHCI_RD(instance->registers->control) & C_IR) {
427 async_usleep(1000);
428 }
429 usb_log_info("SMM driver: Ownership taken.");
430 C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
431 async_usleep(50000);
432 return EOK;
433 }
434
435 const unsigned hc_status = C_HCFS_GET(instance->registers->control);
436 /* Interrupt routing disabled && status != USB_RESET => BIOS active */
437 if (hc_status != C_HCFS_RESET) {
438 usb_log_debug("BIOS driver found.");
439 if (hc_status == C_HCFS_OPERATIONAL) {
440 usb_log_info("BIOS driver: HC operational.");
441 return EOK;
442 }
443 /* HC is suspended assert resume for 20ms */
444 C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
445 async_usleep(20000);
446 usb_log_info("BIOS driver: HC resumed.");
447 return EOK;
448 }
449
450 /* HC is in reset (hw startup) => no other driver
451 * maintain reset for at least the time specified in USB spec (50 ms)*/
452 usb_log_debug("Host controller found in reset state.");
453 async_usleep(50000);
454 return EOK;
455}
456
457/** OHCI hw initialization routine.
458 *
459 * @param[in] instance OHCI hc driver structure.
460 */
461int hc_start(hc_device_t *hcd)
462{
463 hc_t *instance = hcd_to_hc(hcd);
464 ohci_rh_init(&instance->rh, instance->registers, &instance->guard, "ohci rh");
465
466 /* OHCI guide page 42 */
467 assert(instance);
468 usb_log_debug2("Started hc initialization routine.");
469
470 /* Save contents of fm_interval register */
471 const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
472 usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval);
473
474 /* Reset hc */
475 usb_log_debug2("HC reset.");
476 size_t time = 0;
477 OHCI_WR(instance->registers->command_status, CS_HCR);
478 while (OHCI_RD(instance->registers->command_status) & CS_HCR) {
479 async_usleep(10);
480 time += 10;
481 }
482 usb_log_debug2("HC reset complete in %zu us.", time);
483
484 /* Restore fm_interval */
485 OHCI_WR(instance->registers->fm_interval, fm_interval);
486 assert((OHCI_RD(instance->registers->command_status) & CS_HCR) == 0);
487
488 /* hc is now in suspend state */
489 usb_log_debug2("HC should be in suspend state(%x).",
490 OHCI_RD(instance->registers->control));
491
492 /* Use HCCA */
493 OHCI_WR(instance->registers->hcca, addr_to_phys(instance->hcca));
494
495 /* Use queues */
496 OHCI_WR(instance->registers->bulk_head,
497 instance->lists[USB_TRANSFER_BULK].list_head_pa);
498 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").",
499 instance->lists[USB_TRANSFER_BULK].list_head,
500 instance->lists[USB_TRANSFER_BULK].list_head_pa);
501
502 OHCI_WR(instance->registers->control_head,
503 instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
504 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").",
505 instance->lists[USB_TRANSFER_CONTROL].list_head,
506 instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
507
508 /* Enable queues */
509 OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));
510 usb_log_debug("Queues enabled(%x).",
511 OHCI_RD(instance->registers->control));
512
513 /* Enable interrupts */
514 if (instance->base.irq_cap >= 0) {
515 OHCI_WR(instance->registers->interrupt_enable,
516 OHCI_USED_INTERRUPTS);
517 usb_log_debug("Enabled interrupts: %x.",
518 OHCI_RD(instance->registers->interrupt_enable));
519 OHCI_WR(instance->registers->interrupt_enable, I_MI);
520 }
521
522 /* Set periodic start to 90% */
523 const uint32_t frame_length =
524 (fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK;
525 OHCI_WR(instance->registers->periodic_start,
526 ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT);
527 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).",
528 OHCI_RD(instance->registers->periodic_start),
529 OHCI_RD(instance->registers->periodic_start), frame_length);
530 C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
531 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).",
532 OHCI_RD(instance->registers->control));
533
534 return EOK;
535}
536
537/**
538 * Setup roothub as a virtual hub.
539 */
540int hc_setup_roothub(hc_device_t *hcd)
541{
542 return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
543}
544
545/** Initialize schedule queues
546 *
547 * @param[in] instance OHCI hc driver structure
548 * @return Error code
549 */
550errno_t hc_init_transfer_lists(hc_t *instance)
551{
552 assert(instance);
553#define SETUP_ENDPOINT_LIST(type) \
554do { \
555 const char *name = usb_str_transfer_type(type); \
556 const errno_t ret = endpoint_list_init(&instance->lists[type], name); \
557 if (ret != EOK) { \
558 usb_log_error("Failed to setup %s endpoint list: %s.", \
559 name, str_error(ret)); \
560 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
561 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
562 endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \
563 endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \
564 return ret; \
565 } \
566} while (0)
567
568 SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS);
569 SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT);
570 SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL);
571 SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK);
572#undef SETUP_ENDPOINT_LIST
573 endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT],
574 &instance->lists[USB_TRANSFER_ISOCHRONOUS]);
575
576 return EOK;
577}
578
579/** Initialize memory structures used by the OHCI hcd.
580 *
581 * @param[in] instance OHCI hc driver structure.
582 * @return Error code.
583 */
584errno_t hc_init_memory(hc_t *instance)
585{
586 assert(instance);
587
588 memset(&instance->rh, 0, sizeof(instance->rh));
589 /* Init queues */
590 errno_t ret = hc_init_transfer_lists(instance);
591 if (ret != EOK) {
592 return ret;
593 }
594
595 /*Init HCCA */
596 instance->hcca = hcca_get();
597 if (instance->hcca == NULL)
598 return ENOMEM;
599 usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca);
600
601 for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {
602 hcca_set_int_ep(instance->hcca, i,
603 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
604 }
605 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").",
606 instance->lists[USB_TRANSFER_INTERRUPT].list_head,
607 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
608
609 if ((ret = ohci_bus_init(&instance->bus, instance))) {
610 usb_log_error("HC(%p): Failed to setup bus : %s",
611 instance, str_error(ret));
612 return ret;
613 }
614
615 hc_device_setup(&instance->base, (bus_t *) &instance->bus);
616
617 return EOK;
618}
619
620/**
621 * @}
622 */
Note: See TracBrowser for help on using the repository browser.