📄 appleusbohci.cpp
字号:
/* * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */#include <libkern/OSByteOrder.h>extern "C" {#include <kern/clock.h>}#include <IOKit/IOFilterInterruptEventSource.h>#include <IOKit/IOMemoryCursor.h>#include <IOKit/IOMessage.h>#include <IOKit/pccard/IOPCCard.h>#include <IOKit/usb/USB.h>#include <IOKit/usb/IOUSBLog.h>#include "AppleUSBOHCI.h"#include "AppleUSBOHCIMemoryBlocks.h"#define DEBUGGING_LEVEL 0 // 1 = low; 2 = high; 3 = extreme#define super IOUSBController#define NUM_BUFFER_PAGES 9 // 54#define NUM_TDS 255 // 1500#define NUM_EDS 256 // 1500#define NUM_ITDS 192 // 1300// TDs per page == 85// EDs per page == 128// ITDs per page == 64static int GetEDType(AppleOHCIEndpointDescriptorPtr pED);extern void print_td(AppleOHCIGeneralTransferDescriptorPtr pTD);extern void print_itd(AppleOHCIIsochTransferDescriptorPtr x);OSDefineMetaClassAndStructors(AppleUSBOHCI, IOUSBController)bool AppleUSBOHCI::init(OSDictionary * propTable){ if (!super::init(propTable)) return false; _ohciBusState = kOHCIBusStateOff; _ohciAvailable = true; _intLock = IOLockAlloc(); if (!_intLock) return(false); _wdhLock = IOSimpleLockAlloc(); if (!_wdhLock) return(false); _uimInitialized = false; // Initialize our consumer and producer counts. // _producerCount = 1; _consumerCount = 1; return (true);}boolAppleUSBOHCI::start( IOService * provider ){ UInt32 ext1; USBLog(5,"+%s[%p]::start", getName(), this); if( !super::start(provider)) return false; // super::start sets _device or it fails initForPM(_device); // Set our initial time for root hub inactivity // clock_get_uptime(&_lastCheckedTime); USBLog(5,"-%s[%p]::start", getName(), this); return true;}void AppleUSBOHCI::SetVendorInfo(void){ OSData *vendProp, *deviceProp, *revisionProp; // get this chips vendID, deviceID, revisionID vendProp = (OSData *) _device->getProperty( "vendor-id" ); if (vendProp) _vendorID = *((UInt32 *) vendProp->getBytesNoCopy()); deviceProp = (OSData *) _device->getProperty( "device-id" ); if (deviceProp) _deviceID = *((UInt32 *) deviceProp->getBytesNoCopy()); revisionProp = (OSData *) _device->getProperty( "revision-id" ); if (revisionProp) _revisionID = *((UInt32 *) revisionProp->getBytesNoCopy());}IOReturn AppleUSBOHCI::UIMInitialize(IOService * provider){ IOReturn err = kIOReturnSuccess; UInt32 lvalue; IOPhysicalAddress hcDoneHead; USBLog(5,"%s[%p]: initializing UIM", getName(), this); _device = OSDynamicCast(IOPCIDevice, provider); if(_device == NULL) return kIOReturnBadArgument; do { if (!(_deviceBase = provider->mapDeviceMemoryWithIndex(0))) { USBError(1,"%s[%p]: unable to get device memory", getName(), this); break; } USBLog(3, "%s: config @ %lx (%lx)", getName(), (long)_deviceBase->getVirtualAddress(), _deviceBase->getPhysicalAddress()); SetVendorInfo(); // Set up a filter interrupt source (this process both primary (thru filter function) and secondary (thru action function) // interrupts. // _filterInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this, AppleUSBOHCI::InterruptHandler, AppleUSBOHCI::PrimaryInterruptFilter, provider ); if ( !_filterInterruptSource ) { USBError(1,"%s[%p]: unable to get filterInterruptEventSource", getName(), this); break; } err = _workLoop->addEventSource(_filterInterruptSource); if ( err != kIOReturnSuccess ) { USBError(1,"%s[%p]: unable to add filter event source: 0x%x", getName(), this, err); break; } _genCursor = IONaturalMemoryCursor::withSpecification(PAGE_SIZE, PAGE_SIZE); if(!_genCursor) break; _isoCursor = IONaturalMemoryCursor::withSpecification(kUSBMaxIsocFrameReqCount, kUSBMaxIsocFrameReqCount); if(!_isoCursor) break; /* * Initialize my data and the hardware */ _errataBits = GetErrataBits(_vendorID, _deviceID, _revisionID); if (_errataBits & kErrataLucentSuspendResume) { OSData *suspendProp; UInt32 portBitmap = 0; // We need to check to see if there are ports that we really should suspend // suspendProp = (OSData *) provider->getProperty( "AAPL,SuspendablePorts" ); if (suspendProp) { // Only allow suspend on certain ports // portBitmap = *((UInt32 *) suspendProp->getBytesNoCopy()); _disablePortsBitmap = (0xffffffff & (~portBitmap)); } else _disablePortsBitmap = (0xffffffff); } USBLog(5,"%s: errata bits=%lx", getName(), _errataBits); _pageSize = PAGE_SIZE; _pOHCIRegisters = (OHCIRegistersPtr) _deviceBase->getVirtualAddress();#if (DEBUGGING_LEVEL > 2) dumpRegs();#endif // enable the card lvalue = _device->configRead32(cwCommand); _device->configWrite32(cwCommand, (lvalue & 0xffff0000) | (cwCommandEnableBusMaster | cwCommandEnableMemorySpace)); // Check to see if the hcDoneHead is not NULL. If so, then we need to reset the controller // hcDoneHead = USBToHostLong(_pOHCIRegisters->hcDoneHead); if ( hcDoneHead != NULL ) { USBError(1,"%s[%p]::UIMInitialize Non-NULL hcDoneHead: %p", getName(), this, hcDoneHead ); // Reset it now // _pOHCIRegisters->hcCommandStatus = USBToHostLong(kOHCIHcCommandStatus_HCR); // Reset OHCI IOSleep(3); } _pOHCIRegisters->hcControlCurrentED = 0; _pOHCIRegisters->hcControlHeadED = 0; IOSync(); // Set up HCCA. _pHCCA = (Ptr) IOMallocContiguous(kHCCAsize, kHCCAalignment, &_hccaPhysAddr); if (!_pHCCA) { USBError(1,"%s[%p]: Unable to allocate memory (2)", getName(), this); err = kIOReturnNoMemory; break; } OSWriteLittleInt32(&_pOHCIRegisters->hcHCCA, 0, _hccaPhysAddr); IOSync(); // Set the HC to write the donehead to the HCCA, and enable interrupts _pOHCIRegisters->hcInterruptStatus = USBToHostLong(kOHCIHcInterrupt_WDH); IOSync(); // Enable the interrupt delivery. _workLoop->enableAllInterrupts(); _rootHubFuncAddress = 1; // set up Interrupt transfer tree if ((err = IsochronousInitialize())) break; if ((err = InterruptInitialize())) break; if ((err = BulkInitialize())) break; if ((err = ControlInitialize())) break; // Set up hcFmInterval. UInt32 hcFSMPS; // in register hcFmInterval UInt32 hcFI; // in register hcFmInterval UInt32 hcPS; // in register hcPeriodicStart hcFI = USBToHostLong(_pOHCIRegisters->hcFmInterval) & kOHCIHcFmInterval_FI; // this formula is from the OHCI spec, section 5.4 hcFSMPS = ((((hcFI-kOHCIMax_OverHead) * 6)/7) << kOHCIHcFmInterval_FSMPSPhase); hcPS = (hcFI * 9) / 10; // per spec- 90% _pOHCIRegisters->hcFmInterval = HostToUSBLong(hcFI | hcFSMPS); _pOHCIRegisters->hcPeriodicStart = HostToUSBLong(hcPS); IOSync(); // Work around the Philips part which does weird things when a device is plugged in at boot // if (_errataBits & kErrataNeedsPortPowerOff) { USBError(1, "%s[%p]::UIMInitialize error, turning off power to ports to clear", getName(), this); OHCIRootHubPower(0 /* kOff */); // No need to turn the power back on here, the reset does that anyway. } // Just so we all start from the same place, reset the OHCI. _pOHCIRegisters->hcControl = HostToUSBLong ((kOHCIFunctionalState_Reset << kOHCIHcControl_HCFSPhase)); IOSync(); // Set OHCI to operational state and enable processing of control list. _pOHCIRegisters->hcControl = HostToUSBLong ((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_CLE | kOHCIHcControl_BLE | kOHCIHcControl_PLE | kOHCIHcControl_IE); IOSync(); // Initialize the Root Hub registers if (_errataBits & kErrataDisableOvercurrent) _pOHCIRegisters->hcRhDescriptorA |= USBToHostLong(kOHCIHcRhDescriptorA_NOCP); _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); // should be SRWE which should be identical to DRWE IOSync(); OHCIRootHubPower(1 /* kOn */); // enable interrupts _pOHCIRegisters->hcInterruptEnable = HostToUSBLong (kOHCIHcInterrupt_MIE | kOHCIDefaultInterrupts); IOSync(); if (_errataBits & kErrataLSHSOpti) OptiLSHSFix(); _uimInitialized = true; return(kIOReturnSuccess); } while (false); USBError(1, "%s[%p]::UIMInitialize error(%x)", getName(), this, err); UIMFinalize(); if (_filterInterruptSource) { _filterInterruptSource->release(); _filterInterruptSource = NULL; } return(err);}IOReturn AppleUSBOHCI::UIMFinalize(void){ USBLog (3, "%s[%p]: @ %lx (%lx)(shutting down HW)",getName(),this, (long)_deviceBase->getVirtualAddress(), _deviceBase->getPhysicalAddress()); // Disable the interrupt delivery // _workLoop->disableAllInterrupts(); // If we are NOT being terminated, then talk to the OHCI controller and // set up all the registers to be off // if ( !isInactive() ) { // Disable All OHCI Interrupts _pOHCIRegisters->hcInterruptDisable = HostToUSBLong(kOHCIHcInterrupt_MIE); IOSync(); // Place the USB bus into the Reset State _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Reset << kOHCIHcControl_HCFSPhase)); IOSync(); // need to wait at least 1ms here IOSleep(2); // Take away the controllers ability be a bus master. _device->configWrite32(cwCommand, cwCommandEnableMemorySpace); // Clear all Processing Registers _pOHCIRegisters->hcHCCA = 0; _pOHCIRegisters->hcControlHeadED = 0; _pOHCIRegisters->hcControlCurrentED = 0; _pOHCIRegisters->hcBulkHeadED = 0; _pOHCIRegisters->hcBulkCurrentED = 0; IOSync(); // turn off the global power // FIXME check for per-port vs. Global power control OHCIRootHubPower(0 /* kOff */); // go ahead and reset the controller _pOHCIRegisters->hcCommandStatus = HostToUSBLong(kOHCIHcCommandStatus_HCR); // Reset OHCI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -