/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This 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 OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * */ #include #include #include "USBKeyLargo.h" /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define super IOService OSDefineMetaClassAndStructors(USBKeyLargo, IOService); // -------------------------------------------------------------------------- // Method: initForBus // // Purpose: // initialize the driver for a specific bus, so that the driver knows which bus // it is responsable for. bool USBKeyLargo::initForBus(UInt32 busNumber) { setProperty("usb", (UInt64)busNumber, 32); setProperty("IOClass", "USBKeyLargo"); // initialize for Power Management initForPM(getProvider()); return true; } // -------------------------------------------------------------------------- // Method: initForPM // // Purpose: // initialize the driver for power managment and register ourselves with // superclass policy-maker void USBKeyLargo::initForPM (IOService *provider) { PMinit(); // initialize superclass variables provider->joinPMtree(this); // attach into the power management hierarchy // KeyLargo has only 2 power states:: // 0 OFF // 1 all ON // Pwer state fields: // unsigned long version; // version number of this struct // IOPMPowerFlags capabilityFlags; // bits that describe (to interested drivers) the capability of the device in this state // IOPMPowerFlags outputPowerCharacter; // description (to power domain children) of the power provided in this state // IOPMPowerFlags inputPowerRequirement; // description (to power domain parent) of input power required in this state // unsigned long staticPower; // average consumption in milliwatts // unsigned long unbudgetedPower; // additional consumption from separate power supply (mw) // unsigned long powerToAttain; // additional power to attain this state from next lower state (in mw) // unsigned long timeToAttain; // time required to enter this state from next lower state (in microseconds) // unsigned long settleUpTime; // settle time required after entering this state from next lower state (microseconds) // unsigned long timeToLower; // time required to enter next lower state from this one (in microseconds) // unsigned long settleDownTime; // settle time required after entering next lower state from this state (microseconds) // unsigned long powerDomainBudget; // power in mw a domain in this state can deliver to its children // NOTE: all these values are made up since now I do not have areal clue of what to put. #define kNumberOfPowerStates 2 static IOPMPowerState ourPowerStates[kNumberOfPowerStates] = { {1,0,0,0,0,0,0,0,0,0,0,0}, {1,IOPMDeviceUsable,IOPMClockNormal | IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0} }; // register ourselves with ourself as policy-maker if (pm_vars != NULL) registerPowerDriver(this, ourPowerStates, kNumberOfPowerStates); } // Method: setPowerState // // Purpose: IOReturn USBKeyLargo::setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice) { // Do not do anything if the state is inavalid. if (powerStateOrdinal >= kNumberOfPowerStates) return IOPMAckImplied; // Which bus id going to change state ? OSNumber *propertyValue; propertyValue = OSDynamicCast( OSNumber, getProperty("usb")); if (propertyValue == NULL) { return IOPMAckImplied; } if ( powerStateOrdinal == 0 ) { kprintf("USBKeyLargo would be powered off here\n"); turnOffUSB(propertyValue->unsigned32BitValue()); } if ( powerStateOrdinal == 1 ) { kprintf("USBKeyLargo would be powered on here\n"); turnOnUSB(propertyValue->unsigned32BitValue()); } return IOPMAckImplied; } void USBKeyLargo::turnOffUSB(UInt32 busNumber) { UInt32 regTemp; KeyLargo *provider = OSDynamicCast(KeyLargo, getProvider()); if (provider == NULL) { IOLog("USBKeyLargo::turnOffUSB missing provider, can not proceed"); return; } // well, USB requires special timing of the various FCRx register // changes, and should probably be broken out separately. However, // I will hack in the necessary USB changes here. // USB requires the FCR4 bits before any of the other registers are // touched. Since FCR4 is ALL USB, then I moved it to the top of // the programming list regTemp = provider->readRegUInt32(kKeyLargoFCR4); //kprintf("USBKeyLargo::turnOffUSB: FCR4 at beginning %08x\n",regTemp); if (busNumber == 0) { regTemp |= kKeyLargoFCR4USB0SleepBitsSet; regTemp &= ~kKeyLargoFCR4USB0SleepBitsClear; } else { regTemp |= kKeyLargoFCR4USB1SleepBitsSet; regTemp &= ~kKeyLargoFCR4USB1SleepBitsClear; } provider->writeRegUInt32(kKeyLargoFCR4, regTemp); //regTemp = provider->readRegUInt32(kKeyLargoFCR4); //kprintf("USBKeyLargo::turnOffUSB: FCR4 at end %08x\n",regTemp); // WE SHOULD HAVE A 1 MICROSECOND DELAY IN HERE IODelay(1); // Marco changed this from IOSleep because I do not want other threads run at this time // now some stuff in FCR0 which cannot be done all at once // clear the Cell Enable bits for USB (turns off the 48 MHz clocks) regTemp = provider->readRegUInt32(kKeyLargoFCR0); //kprintf("USBKeyLargo::turnOffUSB: FCR0 at beginning %08x\n",regTemp); if (busNumber == 0) { regTemp &= ~kKeyLargoFCR0USB0CellEnable; } else { regTemp &= ~kKeyLargoFCR0USB1CellEnable; } provider->writeRegUInt32(kKeyLargoFCR0, regTemp); //regTemp = provider->readRegUInt32(kKeyLargoFCR0); //kprintf("USBKeyLargo::turnOffUSB: FCR0 at middle %08x\n",regTemp); // NEED A 600 nanosecond delay in here IODelay(1); // Marco changed this from IOSleep because I do not want other threads run at this time // now set the pad suspend bits regTemp = provider->readRegUInt32(kKeyLargoFCR0); if (busNumber == 0) { regTemp |= (kKeyLargoFCR0USB0PadSuspend0 | kKeyLargoFCR0USB0PadSuspend1 ); } else { regTemp |= (kKeyLargoFCR0USB1PadSuspend0 | kKeyLargoFCR0USB1PadSuspend1); } provider->writeRegUInt32(kKeyLargoFCR0, regTemp); //regTemp = provider->readRegUInt32(kKeyLargoFCR0); //kprintf("USBKeyLargo::turnOffUSB: FCR0 at end %08x\n",regTemp); // NEED A 600 nanosecond delay in here IODelay(1); // Marco changed this from IOSleep because I do not want other threads run at this time } void USBKeyLargo::turnOnUSB(UInt32 busNumber) { UInt32 regTemp; KeyLargo *provider = OSDynamicCast(KeyLargo, getProvider()); if (provider == NULL) { IOLog("USBKeyLargo::turnOnUSB missing provider, can not proceed"); return; } // now we clear the individual pad suspend bits // now set the pad suspend bits regTemp = provider->readRegUInt32(kKeyLargoFCR0); if (busNumber == 0) { regTemp &= ~(kKeyLargoFCR0USB0PadSuspend0 | kKeyLargoFCR0USB0PadSuspend1); } else { regTemp &= ~(kKeyLargoFCR0USB1PadSuspend0 | kKeyLargoFCR0USB1PadSuspend1); } provider->writeRegUInt32(kKeyLargoFCR0, regTemp); IODelay(1000); // now we go ahead and turn on the USB cell clocks regTemp = provider->readRegUInt32(kKeyLargoFCR0); if (busNumber == 0) regTemp |= (kKeyLargoFCR0USB0CellEnable); else regTemp |= (kKeyLargoFCR0USB1CellEnable); provider->writeRegUInt32(kKeyLargoFCR0, regTemp); // now turn off the remote wakeup bits regTemp = provider->readRegUInt32(kKeyLargoFCR4); if (busNumber == 0) { regTemp &= ~kKeyLargoFCR4USB0SleepBitsSet; regTemp |= kKeyLargoFCR4USB0SleepBitsClear; } else { regTemp &= ~kKeyLargoFCR4USB1SleepBitsSet; regTemp |= kKeyLargoFCR4USB1SleepBitsClear; } provider->writeRegUInt32(kKeyLargoFCR4, regTemp); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // maxCapabilityForDomainState // // If the power domain is supplying power, the device // can be on. If there is no power it can only be off. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ unsigned long USBKeyLargo::maxCapabilityForDomainState( IOPMPowerFlags domainState ) { if( (domainState & IOPMPowerOn) || (domainState & IOPMSoftSleep) ) return( kNumberOfPowerStates - 1); else return( 0); }