status_t OHCI::Start() { TRACE("starting OHCI host controller\n"); uint32 control = _ReadReg(OHCI_CONTROL); if ((control & OHCI_HC_FUNCTIONAL_STATE_MASK) != OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL) { TRACE_ERROR("controller not started (0x%08lx)!\n", control); return B_ERROR; } else TRACE("controller is operational!\n"); fRootHubAddress = AllocateAddress(); fRootHub = new(std::nothrow) OHCIRootHub(RootObject(), fRootHubAddress); if (!fRootHub) { TRACE_ERROR("no memory to allocate root hub\n"); return B_NO_MEMORY; } if (fRootHub->InitCheck() < B_OK) { TRACE_ERROR("root hub failed init check\n"); return B_ERROR; } SetRootHub(fRootHub); TRACE_ALWAYS("successfully started the controller\n"); return BusManager::Start(); }
/*FUNCTION**************************************************************** * * Function Name : ModifyReg * Returned Value : MQX error code * Comments : * Modifies value of register. Bits to set to zero are defined by first * mask, bits to be set to one are defined by second mask. * *END*********************************************************************/ _mqx_int I2C_ModifyReg8(unsigned char address, uint_8 reg, uint_8 clr_mask, uint_8 set_mask) { int ret = 0; uint_8 reg_val = 0; /* Init Channel resource bit map */ GET_I2C_SEM; if(i2c_SetAddress(address) != MQX_OK){ printf("set slave address: Error.\n"); ret = -1;// return -1; goto end_modi8; } if (MQX_OK != _ReadReg(reg, ®_val)) { #ifdef I2C_COMMON_DEBUG printf("_ModifyReg: Error - cannot read from SGTL.\n"); #endif ret = -1;// return -1; goto end_modi8; } reg_val &= clr_mask; reg_val |= set_mask; if (MQX_OK != _WriteReg(reg, reg_val)) { #ifdef I2C_COMMON_DEBUG printf("_ModifyReg: Error - cannot write to SGTL.\n"); #endif ret = -2;// return -2; } end_modi8: PUT_I2C_SEM; return ret; }
int FastGpioOmega::Read(int pinNum, int &value) { unsigned long int regVal; // read the current value of all pins regVal = _ReadReg (REGISTER_IN_OFFSET); // find the value of the specified pin value = _GetBit(regVal, pinNum); return EXIT_SUCCESS; }
int FastGpioOmega::GetDirection(int pinNum, int &bOutput) { unsigned long int regVal; // read the current input and output settings regVal = _ReadReg(REGISTER_OE_OFFSET); if (verbosityLevel > 0) printf("Direction setting read: 0x%08lx\n", regVal); // find the OE for this pin bOutput = _GetBit(regVal, pinNum); return (EXIT_SUCCESS); }
// public functions int FastGpioOmega::SetDirection(int pinNum, int bOutput) { unsigned long int regVal; // read the current input and output settings regVal = _ReadReg(REGISTER_OE_OFFSET); if (verbosityLevel > 0) printf("Direction setting read: 0x%08lx\n", regVal); // set the OE for this pin _SetBit(regVal, pinNum, bOutput); if (verbosityLevel > 0) printf("Direction setting write: 0x%08lx\n", regVal); // write the new register value _WriteReg(REGISTER_OE_OFFSET, regVal); return (EXIT_SUCCESS); }
status_t OHCI::GetPortStatus(uint8 index, usb_port_status *status) { if (index >= fPortCount) { TRACE_ERROR("get port status for invalid port %u\n", index); return B_BAD_INDEX; } status->status = status->change = 0; uint32 portStatus = _ReadReg(OHCI_RH_PORT_STATUS(index)); // status if (portStatus & OHCI_RH_PORTSTATUS_CCS) status->status |= PORT_STATUS_CONNECTION; if (portStatus & OHCI_RH_PORTSTATUS_PES) status->status |= PORT_STATUS_ENABLE; if (portStatus & OHCI_RH_PORTSTATUS_PSS) status->status |= PORT_STATUS_SUSPEND; if (portStatus & OHCI_RH_PORTSTATUS_POCI) status->status |= PORT_STATUS_OVER_CURRENT; if (portStatus & OHCI_RH_PORTSTATUS_PRS) status->status |= PORT_STATUS_RESET; if (portStatus & OHCI_RH_PORTSTATUS_PPS) status->status |= PORT_STATUS_POWER; if (portStatus & OHCI_RH_PORTSTATUS_LSDA) status->status |= PORT_STATUS_LOW_SPEED; // change if (portStatus & OHCI_RH_PORTSTATUS_CSC) status->change |= PORT_STATUS_CONNECTION; if (portStatus & OHCI_RH_PORTSTATUS_PESC) status->change |= PORT_STATUS_ENABLE; if (portStatus & OHCI_RH_PORTSTATUS_PSSC) status->change |= PORT_STATUS_SUSPEND; if (portStatus & OHCI_RH_PORTSTATUS_OCIC) status->change |= PORT_STATUS_OVER_CURRENT; if (portStatus & OHCI_RH_PORTSTATUS_PRSC) status->change |= PORT_STATUS_RESET; TRACE("port %u status 0x%04x change 0x%04x\n", index, status->status, status->change); return B_OK; }
int I2C_ReadRegister8(unsigned char address,unsigned char reg,unsigned char * reg_val) { // note must add mutex when used audio contrl i2c int ret = 0; GET_I2C_SEM; if(i2c_SetAddress(address) != MQX_OK) { printf("set slave address: Error.\n"); ret = -1; goto end_read8; //return 0; } if (MQX_OK != _ReadReg(reg, reg_val)) { //return(0); ret = -1; printf("ReadRegister 8 failed\n"); } end_read8: PUT_I2C_SEM; return ret; }
int32 OHCI::_Interrupt() { static spinlock lock = B_SPINLOCK_INITIALIZER; acquire_spinlock(&lock); uint32 status = 0; uint32 acknowledge = 0; bool finishTransfers = false; int32 result = B_HANDLED_INTERRUPT; // The LSb of done_head is used to inform the HCD that an interrupt // condition exists for both the done list and for another event recorded in // the HcInterruptStatus register. If done_head is 0, then the interrupt // was caused by other than the HccaDoneHead update and the // HcInterruptStatus register needs to be accessed to determine that exact // interrupt cause. If HccDoneHead is nonzero, then a done list update // interrupt is indicated and if the LSb of the Dword is nonzero, then an // additional interrupt event is indicated and HcInterruptStatus should be // checked to determine its cause. uint32 doneHead = fHcca->done_head; if (doneHead != 0) { status = OHCI_WRITEBACK_DONE_HEAD; if (doneHead & OHCI_DONE_INTERRUPTS) status |= _ReadReg(OHCI_INTERRUPT_STATUS) & _ReadReg(OHCI_INTERRUPT_ENABLE); } else { status = _ReadReg(OHCI_INTERRUPT_STATUS) & _ReadReg(OHCI_INTERRUPT_ENABLE) & ~OHCI_WRITEBACK_DONE_HEAD; if (status == 0) { // Nothing to be done (PCI shared interrupt) release_spinlock(&lock); return B_UNHANDLED_INTERRUPT; } } if (status & OHCI_SCHEDULING_OVERRUN) { TRACE_MODULE("scheduling overrun occured\n"); acknowledge |= OHCI_SCHEDULING_OVERRUN; } if (status & OHCI_WRITEBACK_DONE_HEAD) { TRACE_MODULE("transfer descriptors processed\n"); fHcca->done_head = 0; acknowledge |= OHCI_WRITEBACK_DONE_HEAD; result = B_INVOKE_SCHEDULER; finishTransfers = true; } if (status & OHCI_RESUME_DETECTED) { TRACE_MODULE("resume detected\n"); acknowledge |= OHCI_RESUME_DETECTED; } if (status & OHCI_UNRECOVERABLE_ERROR) { TRACE_MODULE_ERROR("unrecoverable error - controller halted\n"); _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); // TODO: clear all pending transfers, reset and resetup the controller } if (status & OHCI_ROOT_HUB_STATUS_CHANGE) { TRACE_MODULE("root hub status change\n"); // Disable the interrupt as it will otherwise be retriggered until the // port has been reset and the change is cleared explicitly. // TODO: renable it once we use status changes instead of polling _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ROOT_HUB_STATUS_CHANGE); acknowledge |= OHCI_ROOT_HUB_STATUS_CHANGE; } if (acknowledge != 0) _WriteReg(OHCI_INTERRUPT_STATUS, acknowledge); release_spinlock(&lock); if (finishTransfers) release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return result; }
OHCI::OHCI(pci_info *info, Stack *stack) : BusManager(stack), fPCIInfo(info), fStack(stack), fOperationalRegisters(NULL), fRegisterArea(-1), fHccaArea(-1), fHcca(NULL), fInterruptEndpoints(NULL), fDummyControl(NULL), fDummyBulk(NULL), fDummyIsochronous(NULL), fFirstTransfer(NULL), fLastTransfer(NULL), fFinishTransfersSem(-1), fFinishThread(-1), fStopFinishThread(false), fProcessingPipe(NULL), fRootHub(NULL), fRootHubAddress(0), fPortCount(0) { if (!fInitOK) { TRACE_ERROR("bus manager failed to init\n"); return; } TRACE("constructing new OHCI host controller driver\n"); fInitOK = false; mutex_init(&fEndpointLock, "ohci endpoint lock"); // enable busmaster and memory mapped access uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_command, 2); command &= ~PCI_command_io; command |= PCI_command_master | PCI_command_memory; sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_command, 2, command); // map the registers uint32 offset = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function, PCI_base_registers, 4); offset &= PCI_address_memory_32_mask; TRACE_ALWAYS("iospace offset: 0x%lx\n", offset); fRegisterArea = map_physical_memory("OHCI memory mapped registers", (void *)offset, B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, (void **)&fOperationalRegisters); if (fRegisterArea < B_OK) { TRACE_ERROR("failed to map register memory\n"); return; } TRACE("mapped operational registers: %p\n", fOperationalRegisters); // Check the revision of the controller, which should be 10h uint32 revision = _ReadReg(OHCI_REVISION) & 0xff; TRACE("version %ld.%ld%s\n", OHCI_REVISION_HIGH(revision), OHCI_REVISION_LOW(revision), OHCI_REVISION_LEGACY(revision) ? ", legacy support" : ""); if (OHCI_REVISION_HIGH(revision) != 1 || OHCI_REVISION_LOW(revision) != 0) { TRACE_ERROR("unsupported OHCI revision\n"); return; } void *hccaPhysicalAddress; fHccaArea = fStack->AllocateArea((void **)&fHcca, &hccaPhysicalAddress, sizeof(ohci_hcca), "USB OHCI Host Controller Communication Area"); if (fHccaArea < B_OK) { TRACE_ERROR("unable to create the HCCA block area\n"); return; } memset(fHcca, 0, sizeof(ohci_hcca)); // Set Up Host controller // Dummy endpoints fDummyControl = _AllocateEndpoint(); if (!fDummyControl) return; fDummyBulk = _AllocateEndpoint(); if (!fDummyBulk) { _FreeEndpoint(fDummyControl); return; } fDummyIsochronous = _AllocateEndpoint(); if (!fDummyIsochronous) { _FreeEndpoint(fDummyControl); _FreeEndpoint(fDummyBulk); return; } // Static endpoints that get linked in the HCCA fInterruptEndpoints = new(std::nothrow) ohci_endpoint_descriptor *[OHCI_STATIC_ENDPOINT_COUNT]; if (!fInterruptEndpoints) { TRACE_ERROR("failed to allocate memory for interrupt endpoints\n"); _FreeEndpoint(fDummyControl); _FreeEndpoint(fDummyBulk); _FreeEndpoint(fDummyIsochronous); return; } for (int32 i = 0; i < OHCI_STATIC_ENDPOINT_COUNT; i++) { fInterruptEndpoints[i] = _AllocateEndpoint(); if (!fInterruptEndpoints[i]) { TRACE_ERROR("failed to allocate interrupt endpoint %ld", i); while (--i >= 0) _FreeEndpoint(fInterruptEndpoints[i]); _FreeEndpoint(fDummyBulk); _FreeEndpoint(fDummyControl); _FreeEndpoint(fDummyIsochronous); return; } } // build flat tree so that at each of the static interrupt endpoints // fInterruptEndpoints[i] == interrupt endpoint for interval 2^i uint32 interval = OHCI_BIGGEST_INTERVAL; uint32 intervalIndex = OHCI_STATIC_ENDPOINT_COUNT - 1; while (interval > 1) { uint32 insertIndex = interval / 2; while (insertIndex < OHCI_BIGGEST_INTERVAL) { fHcca->interrupt_table[insertIndex] = fInterruptEndpoints[intervalIndex]->physical_address; insertIndex += interval; } intervalIndex--; interval /= 2; } // setup the empty slot in the list and linking of all -> first fHcca->interrupt_table[0] = fInterruptEndpoints[0]->physical_address; for (int32 i = 1; i < OHCI_STATIC_ENDPOINT_COUNT; i++) { fInterruptEndpoints[i]->next_physical_endpoint = fInterruptEndpoints[0]->physical_address; fInterruptEndpoints[i]->next_logical_endpoint = fInterruptEndpoints[0]; } // Now link the first endpoint to the isochronous endpoint fInterruptEndpoints[0]->next_physical_endpoint = fDummyIsochronous->physical_address; // Determine in what context we are running (Kindly copied from FreeBSD) uint32 control = _ReadReg(OHCI_CONTROL); if (control & OHCI_INTERRUPT_ROUTING) { TRACE_ALWAYS("smm is in control of the host controller\n"); uint32 status = _ReadReg(OHCI_COMMAND_STATUS); _WriteReg(OHCI_COMMAND_STATUS, status | OHCI_OWNERSHIP_CHANGE_REQUEST); for (uint32 i = 0; i < 100 && (control & OHCI_INTERRUPT_ROUTING); i++) { snooze(1000); control = _ReadReg(OHCI_CONTROL); } if ((control & OHCI_INTERRUPT_ROUTING) != 0) { TRACE_ERROR("smm does not respond. resetting...\n"); _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); snooze(USB_DELAY_BUS_RESET); } else TRACE_ALWAYS("ownership change successful\n"); } else { TRACE("cold started\n"); snooze(USB_DELAY_BUS_RESET); } // This reset should not be necessary according to the OHCI spec, but // without it some controllers do not start. _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); snooze(USB_DELAY_BUS_RESET); // We now own the host controller and the bus has been reset uint32 frameInterval = _ReadReg(OHCI_FRAME_INTERVAL); uint32 intervalValue = OHCI_GET_INTERVAL_VALUE(frameInterval); // Disable interrupts right before we reset _WriteReg(OHCI_COMMAND_STATUS, OHCI_HOST_CONTROLLER_RESET); // Nominal time for a reset is 10 us uint32 reset = 0; for (uint32 i = 0; i < 10; i++) { spin(10); reset = _ReadReg(OHCI_COMMAND_STATUS) & OHCI_HOST_CONTROLLER_RESET; if (reset == 0) break; } if (reset) { TRACE_ERROR("error resetting the host controller (timeout)\n"); return; } // The controller is now in SUSPEND state, we have 2ms to go OPERATIONAL. // Interrupts are disabled. // Set up host controller register _WriteReg(OHCI_HCCA, (uint32)hccaPhysicalAddress); _WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physical_address); _WriteReg(OHCI_BULK_HEAD_ED, (uint32)fDummyBulk->physical_address); // Disable all interrupts _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS); // Switch on desired functional features control = _ReadReg(OHCI_CONTROL); control &= ~(OHCI_CONTROL_BULK_SERVICE_RATIO_MASK | OHCI_ENABLE_LIST | OHCI_HC_FUNCTIONAL_STATE_MASK | OHCI_INTERRUPT_ROUTING); control |= OHCI_ENABLE_LIST | OHCI_CONTROL_BULK_RATIO_1_4 | OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL; // And finally start the controller _WriteReg(OHCI_CONTROL, control); // The controller is now OPERATIONAL. frameInterval = (_ReadReg(OHCI_FRAME_INTERVAL) & OHCI_FRAME_INTERVAL_TOGGLE) ^ OHCI_FRAME_INTERVAL_TOGGLE; frameInterval |= OHCI_FSMPS(intervalValue) | intervalValue; _WriteReg(OHCI_FRAME_INTERVAL, frameInterval); // 90% periodic uint32 periodic = OHCI_PERIODIC(intervalValue); _WriteReg(OHCI_PERIODIC_START, periodic); // Fiddle the No Over Current Protection bit to avoid chip bug uint32 desca = _ReadReg(OHCI_RH_DESCRIPTOR_A); _WriteReg(OHCI_RH_DESCRIPTOR_A, desca | OHCI_RH_NO_OVER_CURRENT_PROTECTION); _WriteReg(OHCI_RH_STATUS, OHCI_RH_LOCAL_POWER_STATUS_CHANGE); snooze(OHCI_ENABLE_POWER_DELAY); _WriteReg(OHCI_RH_DESCRIPTOR_A, desca); // The AMD756 requires a delay before re-reading the register, // otherwise it will occasionally report 0 ports. uint32 numberOfPorts = 0; for (uint32 i = 0; i < 10 && numberOfPorts == 0; i++) { snooze(OHCI_READ_DESC_DELAY); uint32 descriptor = _ReadReg(OHCI_RH_DESCRIPTOR_A); numberOfPorts = OHCI_RH_GET_PORT_COUNT(descriptor); } if (numberOfPorts > OHCI_MAX_PORT_COUNT) numberOfPorts = OHCI_MAX_PORT_COUNT; fPortCount = numberOfPorts; TRACE("port count is %d\n", fPortCount); // Create semaphore the finisher thread will wait for fFinishTransfersSem = create_sem(0, "OHCI Finish Transfers"); if (fFinishTransfersSem < B_OK) { TRACE_ERROR("failed to create semaphore\n"); return; } // Create the finisher service thread fFinishThread = spawn_kernel_thread(_FinishThread, "ohci finish thread", B_URGENT_DISPLAY_PRIORITY, (void *)this); resume_thread(fFinishThread); // Install the interrupt handler TRACE("installing interrupt handler\n"); install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, _InterruptHandler, (void *)this, 0); // Enable interesting interrupts now that the handler is in place _WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_NORMAL_INTERRUPTS | OHCI_MASTER_INTERRUPT_ENABLE); TRACE("OHCI host controller driver constructed\n"); fInitOK = true; }