/* Set HcControlRegister */ static void ohci_set_ctl(OHCIState *ohci, uint32_t val) { uint32_t old_state; uint32_t new_state; old_state = ohci->ctl & OHCI_CTL_HCFS; ohci->ctl = val; new_state = ohci->ctl & OHCI_CTL_HCFS; /* no state change */ if (old_state == new_state) return; switch (new_state) { case OHCI_USB_OPERATIONAL: ohci_bus_start(ohci); break; case OHCI_USB_SUSPEND: ohci_bus_stop(ohci); DPRINTF("usb-ohci: %s: USB Suspended\n", ohci->name); break; case OHCI_USB_RESUME: DPRINTF("usb-ohci: %s: USB Resume\n", ohci->name); break; case OHCI_USB_RESET: ohci_reset(ohci); DPRINTF("usb-ohci: %s: USB Reset\n", ohci->name); break; } }
hci_t * ohci_init (pcidev_t addr) { int i; hci_t *controller = new_controller (); if (!controller) fatal("Could not create USB controller instance.\n"); controller->instance = malloc (sizeof (ohci_t)); if(!controller->instance) fatal("Not enough memory creating USB controller instance.\n"); controller->start = ohci_start; controller->stop = ohci_stop; controller->reset = ohci_reset; controller->shutdown = ohci_shutdown; controller->bulk = ohci_bulk; controller->control = ohci_control; controller->create_intr_queue = ohci_create_intr_queue; controller->destroy_intr_queue = ohci_destroy_intr_queue; controller->poll_intr_queue = ohci_poll_intr_queue; for (i = 0; i < 128; i++) { controller->devices[i] = 0; } init_device_entry (controller, 0); OHCI_INST (controller)->roothub = controller->devices[0]; controller->bus_address = addr; controller->reg_base = pci_read_config32 (controller->bus_address, 0x10); // OHCI mandates MMIO, so bit 0 is clear OHCI_INST (controller)->opreg = (opreg_t*)phys_to_virt(controller->reg_base); printf("OHCI Version %x.%x\n", (OHCI_INST (controller)->opreg->HcRevision >> 4) & 0xf, OHCI_INST (controller)->opreg->HcRevision & 0xf); if ((OHCI_INST (controller)->opreg->HcControl & HostControllerFunctionalStateMask) == USBReset) { /* cold boot */ OHCI_INST (controller)->opreg->HcControl &= ~RemoteWakeupConnected; OHCI_INST (controller)->opreg->HcFmInterval = (11999 * FrameInterval) | ((((11999 - 210)*6)/7) * FSLargestDataPacket); /* TODO: right value for PowerOnToPowerGoodTime ? */ OHCI_INST (controller)->opreg->HcRhDescriptorA = NoPowerSwitching | NoOverCurrentProtection | (10 * PowerOnToPowerGoodTime); OHCI_INST (controller)->opreg->HcRhDescriptorB = (0 * DeviceRemovable); udelay(100); /* TODO: reset asserting according to USB spec */ } else if ((OHCI_INST (controller)->opreg->HcControl & HostControllerFunctionalStateMask) != USBOperational) { OHCI_INST (controller)->opreg->HcControl = (OHCI_INST (controller)->opreg->HcControl & ~HostControllerFunctionalStateMask) | USBResume; udelay(100); /* TODO: resume time according to USB spec */ } int interval = OHCI_INST (controller)->opreg->HcFmInterval; td_t *periodic_td = memalign(sizeof(*periodic_td), sizeof(*periodic_td)); memset((void*)periodic_td, 0, sizeof(*periodic_td)); for (i=0; i<32; i++) OHCI_INST (controller)->hcca->HccaInterruptTable[i] = virt_to_phys(periodic_td); /* TODO: build HCCA data structures */ OHCI_INST (controller)->opreg->HcCommandStatus = HostControllerReset; udelay (10); /* at most 10us for reset to complete. State must be set to Operational within 2ms (5.1.1.4) */ OHCI_INST (controller)->opreg->HcFmInterval = interval; OHCI_INST (controller)->hcca = memalign(256, 256); memset((void*)OHCI_INST (controller)->hcca, 0, 256); OHCI_INST (controller)->opreg->HcHCCA = virt_to_phys(OHCI_INST (controller)->hcca); OHCI_INST (controller)->opreg->HcControl &= ~IsochronousEnable; // unused by this driver // disable everything, contrary to what OHCI spec says in 5.1.1.4, as we don't need IRQs OHCI_INST (controller)->opreg->HcInterruptEnable = 1<<31; OHCI_INST (controller)->opreg->HcInterruptDisable = ~(1<<31); OHCI_INST (controller)->opreg->HcInterruptStatus = ~0; OHCI_INST (controller)->opreg->HcPeriodicStart = (((OHCI_INST (controller)->opreg->HcFmInterval & FrameIntervalMask) / 10) * 9); OHCI_INST (controller)->opreg->HcControl = (OHCI_INST (controller)->opreg->HcControl & ~HostControllerFunctionalStateMask) | USBOperational; mdelay(100); controller->devices[0]->controller = controller; controller->devices[0]->init = ohci_rh_init; controller->devices[0]->init (controller->devices[0]); ohci_reset (controller); return controller; }