void FakeSMCDevice::ioWrite8( UInt16 offset, UInt8 value, IOMemoryMap * map ) { UInt16 base = 0; IODelay(10); if (map) base = map->getPhysicalAddress(); if((base+offset) == APPLESMC_DATA_PORT) applesmc_io_data_writeb(status, base+offset, value); if((base+offset) == APPLESMC_CMD_PORT) applesmc_io_cmd_writeb(status, base+offset,value); // outb( base + offset, value ); // if(((base+offset) != APPLESMC_DATA_PORT) && ((base+offset) != APPLESMC_CMD_PORT)) IOLog("iowrite8 to port %x.\n", base+offset); //HWSensorsDebugLog("iowrite8 called"); }
// // Wait up to waittime seconds for the status bits to be set. // // Note that this spins, and should be avoided when possible. // bool self::waitStatusBits(UInt32 bits, int waittime) { UInt32 status_reg = 0; int i; for (i = 0; i < (waittime * 100); i++) { status_reg = getStatusReg(); if ((status_reg & bits) == bits) return(true); IODelay(10000); } debug(2, "timed out waiting for status bits 0x%08x, have status 0x%08x", (uint)bits, (uint)status_reg); return(false); }
WLCard:: WLCard(void* ioBase, void* klBase, IOService* parent) : _ioBase(ioBase), _keyLargoBase(klBase), _interrupts(0), _isEnabled(false), _parent(parent) { _powerOn(); IODelay(200 * 1000); _reset(); /* * Get firmware vendor and version */ WLIdentity ident; if (getIdentity(&ident) != kIOReturnSuccess) { WLLogErr("WLCard::WLCard: Couldn't read card identity\n"); return; } WLLogNotice("WLCard: Firmware vendor %d, variant %d, version %d.%d\n", ident.vendor, ident.variant, ident.major, ident.minor); WLHardwareAddress macAddr; if (getHardwareAddress(&macAddr) != kIOReturnSuccess) { WLLogErr("WLCard::WLCard: Couldn't read MAC address\n"); return; } _workLoop = _parent->getWorkLoop(); if (!_workLoop) { WLLogErr("WLCard::WLCard: Failed to create workloop.\n"); return; } _timedSendSource = IOTimerEventSource::timerEventSource(_parent, &WLCard::_myTimeoutHandler); if (!_timedSendSource) { WLLogErr("WLCard::WLCard: Failed to create timer event source.\n"); return; } if (_workLoop->addEventSource(_timedSendSource) != kIOReturnSuccess) { WLLogErr("WLCard::WLCard: Failed to register timer event source.\n"); return; } }
UInt64 CLASS::GetMicroFrameNumber(void) { uint64_t counter1, counter2; uint32_t sts, mfIndex, count; sts = Read32Reg(&_pXHCIOperationalRegisters->USBSts); if (m_invalid_regspace || (sts & XHCI_STS_HCH)) return 0ULL; /* * TBD: For 32-bit compile, access to _millsecondCounter * is non-atomic, here vs FilterEventRing. */ for (count = 0U; count < 2U; ++count) { if (count) IODelay(126U); counter1 = _millsecondCounter; mfIndex = Read32Reg(&_pXHCIRuntimeRegisters->MFIndex); counter2 = _millsecondCounter; if (m_invalid_regspace) return 0ULL; if (counter1 != counter2) { /* * Note: This can only happen if a primary * interrupt takes place between readings, * so use the 2nd reading and assume * MFIndex 0. */ return counter2 << 3; } mfIndex &= XHCI_MFINDEX_MASK; if (mfIndex) break; /* * Note: XHCI allows controllers to halt the * clock if no device is connected. Some, * such as the Renesas uPD720200a don't * generate timer interrupts when no device * is connected initially. No need to delay. */ if (!counter1) break; } return (counter1 << 3) + mfIndex; }
UInt32 AppleGenericPCATADriver::scanForDrives( void ) { UInt32 unitsFound; DLOG("%s::%s( %p )\n", getName(), __FUNCTION__, this); *_tfAltSDevCReg = mATADCRReset; IODelay( 100 ); *_tfAltSDevCReg = 0x0; IOSleep( 10 ); unitsFound = super::scanForDrives(); *_tfSDHReg = 0x00; // Initialize device selection to device 0. return unitsFound; }
void IOPlatformExpert::sleepKernel(void) { #if 0 long cnt; boolean_t intState; intState = ml_set_interrupts_enabled(false); for (cnt = 0; cnt < 10000; cnt++) { IODelay(1000); } ml_set_interrupts_enabled(intState); #else // PE_initialize_console(0, kPEDisableScreen); IOCPUSleepKernel(); // PE_initialize_console(0, kPEEnableScreen); #endif }
int nouveau_therm_fan_rpm_get(struct nouveau_device *device) { u32 cycles, cur, prev, stop = THERM_FAN_SENSE_CYCLES * 4 + 1; u64 start, interval; if (device->fan_tach.func != DCB_GPIO_UNUSED) { /* Time a complete rotation and extrapolate to RPM: * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ start = ptimer_read(); prev = device->gpio_get(device, 0, device->fan_tach.func, device->fan_tach.line); cycles = 0; do { IODelay(750); /* supports 0 < rpm < 7500 */ cur = device->gpio_get(device, 0, device->fan_tach.func, device->fan_tach.line); if (prev != cur) { if (!start) start = ptimer_read(); cycles++; prev = cur; } interval = ptimer_read() - start; } while (cycles < stop && interval < 500000000); if (interval) { return (int)(((u64)60000000000ULL * (((u64)cycles - 1) / 4)) / interval); } else return -EIO; } nv_debug(device, "DCB_GPIO_FAN_SENSE func not found\n"); return -EIO; }
void udelay(unsigned int microseconds) { // Spin delay for a number of microseconds IODelay(microseconds); }
void xf86usleep(unsigned long usec) //unsigned long usec; { IODelay(usec); }
IOReturn WLCard::_powerOn() { /* * Magic monkey mojo gleamed from OpenBSD sources */ /* * XXX: ??? */ UInt32 x; x = getKLRegister32(0x40); x |= 0x4; setKLRegister32(0x40, x); /* * Enable card slot. */ setKLRegister(0x6a + 0x0f, 5); IODelay(10 * 1000); setKLRegister(0x6a + 0x0f, 4); IODelay(10 * 1000); /* * XXX: ??? */ x = getKLRegister32(0x40); x &= ~0x8000000; setKLRegister32(0x40, x); IODelay(10); setKLRegister(0x58 + 0xb, 0); IODelay(10); setKLRegister(0x58 + 0xa, 0x28); IODelay(10); setKLRegister(0x58 + 0xd, 0x28); IODelay(10); setKLRegister(0x6a + 0xd, 0x28); IODelay(10); setKLRegister(0x6a + 0xe, 0x28); IODelay(10); setKLRegister32(0x1c000, 0); IODelay(1 * 1000); /* * Initialize the card. */ setKLRegister32(0x1a3e0, 0x41); IODelay(10); x = getKLRegister32(0x40); x |= 0x8000000; setKLRegister32(0x40, x); IODelay(100 * 1000); return kIOReturnSuccess; }
// Reset and enable the port IOReturn AppleUSBUHCI::RHResetPort(int port) { UInt16 value; int i; USBLog(3, "AppleUSBUHCI[%p]::RHResetPort %d", this, port); port--; // convert 1-based to 0-based. value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; WritePortStatus(port, value | kUHCI_PORTSC_RESET); /* Assert RESET for 50ms */ IOSleep(50); value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; WritePortStatus(port, value & ~kUHCI_PORTSC_RESET); IODelay(10); value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; WritePortStatus(port, value | kUHCI_PORTSC_PED); for (i=10; i>0; i--) { IOSleep(10); value = ReadPortStatus(port); if ((value & kUHCI_PORTSC_CCS) == 0) { /* No device connected; don't enter reset state. */ //USBLog(5, "%s[%p]: no device connected, not entering reset state"); return kIOReturnNotResponding; break; } if (value & (kUHCI_PORTSC_PEDC | kUHCI_PORTSC_CSC)) { /* Change bits detected. Clear them and continue waiting. */ WritePortStatus(port, (value & kUHCI_PORTSC_MASK) | (kUHCI_PORTSC_PEDC | kUHCI_PORTSC_CSC)); continue; } if (value & kUHCI_PORTSC_PED) { /* Port successfully enabled. */ break; } } if (i == 0) { USBLog(5, "AppleUSBUHCI[%p]: reset port FAILED", this); return kIOReturnNotResponding; } // Remember that we were reset _portWasReset[port] = true; USBLog(5, "AppleUSBUHCI[%p]: reset port succeeded", this); return kIOReturnSuccess; }
UInt32 AppleIntelICHxSATA::scanForDrives( void ) { UInt32 unitsFound; // Try real hard to reset the port(s) and attached devices. for ( int loopMs = 0; loopMs <= 3000; loopMs += 10 ) { if ( (loopMs % 1000) == 0 ) { for ( UInt32 i = 0; i < _provider->getMaxDriveUnits(); i++ ) _provider->setSerialATAPortEnableForDrive( i, false ); IOSleep( 20 ); for ( UInt32 i = 0; i < _provider->getMaxDriveUnits(); i++ ) _provider->setSerialATAPortEnableForDrive( i, true ); IOSleep( 20 ); *_tfAltSDevCReg = mATADCRReset; // ATA reset IODelay( 100 ); *_tfAltSDevCReg = 0x0; } if ( (*_tfStatusCmdReg & mATABusy) == 0x00 ) break; IOSleep( 10 ); } // ICH5 does offer a device present flag for each SATA port. This // information can be used to speed up boot by reducing unnecessary // bus scanning when no devices are present. In addition, the port // can be disabled to reduce power usage. For now we still use the // standard bus scanning implementation in IOATAController. unitsFound = IOPCIATA::scanForDrives(); // Fixup discrepancies between the results from ATA bus scanning, // and the SATA device present status. for ( UInt32 unit = 0; unit < kMaxDrives; unit++ ) { if ( _devInfo[unit].type != kUnknownATADeviceType && ( unit >= _provider->getMaxDriveUnits() || _provider->getSerialATAPortPresentStatusForDrive( unit ) == false ) ) { // Detected a device, but SATA reports that no device are // present on the port. Trust SATA since if the device was // detected then surely the port present bit would be set. _devInfo[unit].type = kUnknownATADeviceType; } } // Turn off unused SATA ports. for ( UInt32 unit = 0; unit < _provider->getMaxDriveUnits(); unit++ ) { if ( _devInfo[unit].type == kUnknownATADeviceType ) { _provider->setSerialATAPortEnableForDrive( unit, false ); } } return unitsFound; }
void UniNEnet::stopPHY() { UInt32 val32; UInt16 i, val16; ELG( fWOL, fPHYType, '-Phy', "UniNEnet::stopPHY" ); if ( !fBuiltin || (fPHYType == 0) ) return; if ( fWOL == false ) { // disabling MIF interrupts on the 5201 is explicit if ( fPHYType == 0x5201 ) miiWriteWord( 0x0000, MII_BCM5201_INTERRUPT ); } /* Turn off PHY status-change polling to prevent immediate wakeup: */ val32 = READ_REGISTER( MIFConfiguration ); val32 &= ~kMIFConfiguration_Poll_Enable; WRITE_REGISTER( MIFConfiguration, val32 ); if ( fWOL ) { // For multicast filtering these bits must be enabled WRITE_REGISTER( RxMACConfiguration, kRxMACConfiguration_Hash_Filter_Enable | kRxMACConfiguration_Strip_FCS | kRxMACConfiguration_Rx_Mac_Enable ); UInt16 *p16; p16 = (UInt16*)myAddress.bytes; WRITE_REGISTER( WOLMagicMatch[ 2 ], p16[ 0 ] ); // enet address WRITE_REGISTER( WOLMagicMatch[ 1 ], p16[ 1 ] ); WRITE_REGISTER( WOLMagicMatch[ 0 ], p16[ 2 ] ); WRITE_REGISTER( WOLPatternMatchCount, kWOLPatternMatchCount_M | kWOLPatternMatchCount_N ); val32 = kWOLWakeupCSR_Magic_Wakeup_Enable; // Assume GMII if ( !(fXIFConfiguration & kXIFConfiguration_GMIIMODE) ) val32 |= kWOLWakeupCSR_Mode_MII; // NG - indicate non GMII WRITE_REGISTER( WOLWakeupCSR, val32 ); } else { WRITE_REGISTER( RxMACConfiguration, 0 ); IOSleep( 4 ); // it takes time for enable bit to clear } WRITE_REGISTER( TxMACConfiguration, 0 ); WRITE_REGISTER( XIFConfiguration, 0 ); fTxConfiguration &= ~kTxConfiguration_Tx_DMA_Enable; WRITE_REGISTER( TxConfiguration, fTxConfiguration ); fRxConfiguration &= ~kRxConfiguration_Rx_DMA_Enable; WRITE_REGISTER( RxConfiguration, fRxConfiguration ); if ( !fWOL ) { // this doesn't power down stuff, but if we don't hit it then we can't // superisolate the transceiver WRITE_REGISTER( SoftwareReset, kSoftwareReset_TX | kSoftwareReset_RX ); i = 0; do { IODelay( 10 ); if ( i++ >= 100 ) { ALRT( 0, val32, 'Sft-', "UniNEnet::stopPHY - timeout on SoftwareReset" ); break; } val32 = READ_REGISTER( SoftwareReset ); } while ( (val32 & (kSoftwareReset_TX | kSoftwareReset_RX)) != 0 ); WRITE_REGISTER( TxMACSoftwareResetCommand, kTxMACSoftwareResetCommand_Reset ); WRITE_REGISTER( RxMACSoftwareResetCommand, kRxMACSoftwareResetCommand_Reset ); // This is what actually turns off the LINK LED switch ( fPHYType ) { case 0x5400: case 0x5401: #if 0 // The 5400 has read/write privilege on this bit, // but 5201 is read-only. miiWriteWord( MII_CONTROL_POWERDOWN, MII_CONTROL ); #endif break; case 0x5221: // 1: enable shadow mode registers in 5221 (0x1A-0x1E) miiReadWord( &val16, MII_BCM5221_TestRegister ); miiWriteWord( val16 | MII_BCM5221_ShadowRegEnableBit, MII_BCM5221_TestRegister ); // 2: Force IDDQ mode for max power savings // remember..after setting IDDQ mode we have to "hard" reset // the PHY in order to access it. miiReadWord( &val16, MII_BCM5221_AuxiliaryMode4 ); miiWriteWord( val16 | MII_BCM5221_SetIDDQMode, MII_BCM5221_AuxiliaryMode4 ); break; case 0x5241: // 1: enable shadow register mode miiReadWord( &val16, MII_BCM5221_TestRegister ); miiWriteWord( val16 | MII_BCM5221_ShadowRegEnableBit, MII_BCM5221_TestRegister ); // 2: Set standby power bit miiReadWord( &val16, MII_BCM5221_AuxiliaryMode4 ); miiWriteWord( val16 | MII_BCM5241_StandbyPowerMode, MII_BCM5221_AuxiliaryMode4 ); break; case 0x5201: #if 0 miiReadWord( &val16, MII_BCM5201_AUXMODE2 ); miiWriteWord( val16 & ~MII_BCM5201_AUXMODE2_LOWPOWER, MII_BCM5201_AUXMODE2 ); #endif miiWriteWord( MII_BCM5201_MULTIPHY_SUPERISOLATE, MII_BCM5201_MULTIPHY ); break; case 0x5411: case 0x5421: default: miiWriteWord( MII_CONTROL_POWERDOWN, MII_CONTROL ); break; }/* end SWITCH on PHY type */ /* Put the MDIO pins into a benign state. */ /* Note that the management regs in the PHY will be inaccessible. */ /* This is to guarantee max power savings on Powerbooks and */ /* to eliminate damage to Broadcom PHYs. */ WRITE_REGISTER( MIFConfiguration, kMIFConfiguration_BB_Mode ); // bit bang mode WRITE_REGISTER( MIFBitBangClock, 0x0000 ); WRITE_REGISTER( MIFBitBangData, 0x0000 ); WRITE_REGISTER( MIFBitBangOutputEnable, 0x0000 ); WRITE_REGISTER( XIFConfiguration, kXIFConfiguration_GMIIMODE | kXIFConfiguration_MII_Int_Loopback ); val32 = READ_REGISTER( XIFConfiguration ); /// ??? make sure it takes. }// end of non-WOL case return; }/* end stopPHY */
bool AppleMacIO::selfTest( void ) { IODBDMADescriptor *dmaDescriptors; UInt32 dmaDescriptorsPhys; UInt32 i; UInt32 status; IODBDMADescriptor *dmaDesc; IOBufferMemoryDescriptor *buffer; volatile IODBDMAChannelRegisters *ioBaseDMA; bool ok = false; enum { kTestChannel = 0x8000 }; ioBaseDMA = (volatile IODBDMAChannelRegisters *) (((UInt32)fMemory->getVirtualAddress()) + kTestChannel ); do { buffer = IOBufferMemoryDescriptor::withCapacity(page_size, kIODirectionOutIn, true); dmaDescriptors = (IODBDMADescriptor*)buffer->getBytesNoCopy(); if (!dmaDescriptors) continue; if ( (UInt32)dmaDescriptors & (page_size - 1) ) { IOLog("AppleMacIO::%s() - DMA Descriptor memory not page aligned!!", __FUNCTION__); continue; } bzero( dmaDescriptors, page_size ); IODBDMAReset( ioBaseDMA ); dmaDesc = dmaDescriptors; IOMakeDBDMADescriptor( dmaDesc, kdbdmaNop, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchNever, kdbdmaWaitNever, 0, 0 ); dmaDesc++; dmaDescriptorsPhys = (UInt32) (buffer->getPhysicalSegment(0, NULL, 0)); IOMakeDBDMADescriptorDep( dmaDesc, kdbdmaStoreQuad, kdbdmaKeySystem, kdbdmaIntNever, kdbdmaBranchNever, kdbdmaWaitNever, 4, dmaDescriptorsPhys+16*sizeof(IODBDMADescriptor), 0x12345678 ); dmaDesc++; IOMakeDBDMADescriptor( dmaDesc, kdbdmaStop, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchNever, kdbdmaWaitNever, 0, 0 ); for ( i = 0; (!ok) && (i < 3); i++ ) { dmaDescriptors[16].operation = 0; IOSetDBDMACommandPtr( ioBaseDMA, dmaDescriptorsPhys ); IODBDMAContinue( ioBaseDMA ); IODelay( 200 ); status = IOGetDBDMAChannelStatus( ioBaseDMA ); if ( ((status & kdbdmaActive) == 0) && ((status & kdbdmaDead) == 0) && (OSReadSwapInt32( &dmaDescriptors[16].operation, 0 ) == 0x12345678 )) ok = true; } IODBDMAReset( ioBaseDMA ); } while (false); if (buffer) buffer->release(); return ok; }
/*-----------------------------------------------------------------------------* * This routine initializes the script engine's register block. * *-----------------------------------------------------------------------------*/ bool Sym8xxSCSIController::Sym8xxInitChip() { UInt32 i; /* * Reset the script engine */ Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, RST ); IODelay( 25 ); Sym8xxWriteRegs( chipBaseAddr, ISTAT, ISTAT_SIZE, ISTAT_INIT ); /* * Load our canned register values into the script engine */ for ( i = 0; i < sizeof(Sym8xxInitRegs)/sizeof(ChipInitRegs); i++ ) { Sym8xxWriteRegs( chipBaseAddr, Sym8xxInitRegs[i].regNum, Sym8xxInitRegs[i].regSize, Sym8xxInitRegs[i].regValue ); IODelay( 10 ); } /* * For hardware implementations that have a 40Mhz SCLK input, we enable the chip's on-board * clock doubler to bring the clock rate upto 80Mhz which is required for Ultra-SCSI timings. */ if ( chipClockRate == CLK_40MHz ) { /* * Clock doubler setup for 875 (rev 3 and above). */ /* set clock doubler enabler bit */ Sym8xxWriteRegs( chipBaseAddr, STEST1, STEST1_SIZE, STEST1_INIT | DBLEN); IODelay(30); /* halt scsi clock */ Sym8xxWriteRegs( chipBaseAddr, STEST3, STEST3_SIZE, STEST3_INIT | HSC ); IODelay(10); Sym8xxWriteRegs( chipBaseAddr, SCNTL3, SCNTL3_SIZE, SCNTL3_INIT_875); IODelay(10); /* set clock doubler select bit */ Sym8xxWriteRegs( chipBaseAddr, STEST1, STEST1_SIZE, STEST1_INIT | DBLEN | DBLSEL); IODelay(10); /* clear hold on scsi clock */ Sym8xxWriteRegs( chipBaseAddr, STEST3, STEST3_SIZE, STEST3_INIT); } /* * Set our host-adapter ID in the script engine's registers */ initiatorID = kHostAdapterSCSIId; if ( initiatorID > 7 ) { Sym8xxWriteRegs( chipBaseAddr, RESPID1, RESPID1_SIZE, 1 << (initiatorID-8)); } else { Sym8xxWriteRegs( chipBaseAddr, RESPID0, RESPID0_SIZE, 1 << initiatorID); } Sym8xxWriteRegs( chipBaseAddr, SCID, SCID_SIZE, SCID_INIT | initiatorID ); return true; }
/* * Solaris delay is in ticks (hz) and Darwin uses microsecs * 1 HZ is 10 milliseconds */ void osx_delay(int ticks) { IODelay(ticks * 10000); }
/* * performExternalWordTransaction * * Called by AppleSmartBatteryManagerUserClient */ IOReturn AppleSmartBatteryManager::performExternalTransaction( void *in, void *out, IOByteCount inSize, IOByteCount *outSize) { uint16_t i; uint16_t retryAttempts = 0; IOSMBusTransaction newTransaction; IOReturn transactionSuccess; EXSMBUSInputStruct *inSMBus = (EXSMBUSInputStruct *)in; EXSMBUSOutputStruct *outSMBus = (EXSMBUSOutputStruct *)out; if (!inSMBus || !outSMBus) return kIOReturnBadArgument; /* Attempt up to 5 transactions if we get failures */ do { bzero(&newTransaction, sizeof(IOSMBusTransaction)); // Input: bus address if (kSMBusAppleDoublerAddr == inSMBus->batterySelector || kSMBusBatteryAddr == inSMBus->batterySelector || kSMBusManagerAddr == inSMBus->batterySelector || kSMBusChargerAddr == inSMBus->batterySelector) { newTransaction.address = inSMBus->batterySelector; } else { if (0 == inSMBus->batterySelector) { newTransaction.address = kSMBusBatteryAddr; } else { newTransaction.address = kSMBusManagerAddr; } } // Input: command newTransaction.command = inSMBus->address; // Input: Read/Write Word/Block switch (inSMBus->type) { case kEXWriteWord: newTransaction.protocol = kIOSMBusProtocolWriteWord; newTransaction.sendDataCount = 2; break; case kEXReadWord: newTransaction.protocol = kIOSMBusProtocolReadWord; newTransaction.sendDataCount = 0; break; case kEXWriteBlock: newTransaction.protocol = kIOSMBusProtocolWriteBlock; // rdar://5433060 workaround for SMC SMBus blockCount bug // For block writes, clients always increment inByteCount +1 // greater than the actual byte count. // We decrement it here for IOSMBusController. newTransaction.sendDataCount = inSMBus->inByteCount - 1; break; case kEXReadBlock: newTransaction.protocol = kIOSMBusProtocolReadBlock; newTransaction.sendDataCount = 0; break; case kEXWriteByte: newTransaction.protocol = kIOSMBusProtocolWriteByte; newTransaction.sendDataCount = 1; break; case kEXReadByte: newTransaction.protocol = kIOSMBusProtocolReadByte; newTransaction.sendDataCount = 0; break; case kEXSendByte: newTransaction.protocol = kIOSMBusProtocolSendByte; newTransaction.sendDataCount = 0; break; default: return kIOReturnBadArgument; } // Input: copy data into transaction // only need to copy data for write operations if ((kIOSMBusProtocolWriteWord == newTransaction.protocol) || (kIOSMBusProtocolWriteBlock == newTransaction.protocol)) { for(i = 0; i<MAX_SMBUS_DATA_SIZE; i++) { newTransaction.sendData[i] = inSMBus->inBuf[i]; } } if (inSMBus->flags & kEXFlagRetry) { if (retryAttempts >= kMaxRetries) { // Don't read off the end of the table... retryAttempts = kMaxRetries - 1; } // If this is a retry-on-failure, spin for a few microseconds IODelay( retryDelaysTable[retryAttempts] ); } fManagerGate->runAction( (IOCommandGate::Action)OSMemberFunctionCast( IOCommandGate::Action, this, &AppleSmartBatteryManager::performExternalTransactionGated), (void *)&newTransaction, (void *)&transactionSuccess, NULL, NULL); /* Output: status */ if ((kIOReturnSuccess == transactionSuccess) && (kIOSMBusStatusOK == newTransaction.status)) { outSMBus->status = kIOReturnSuccess; } else { switch (newTransaction.status) { case kIOSMBusStatusUnknownFailure: case kIOSMBusStatusDeviceAddressNotAcknowledged: case kIOSMBusStatusDeviceError: case kIOSMBusStatusDeviceCommandAccessDenied: case kIOSMBusStatusUnknownHostError: outSMBus->status = kIOReturnNoDevice; break; case kIOSMBusStatusTimeout: case kIOSMBusStatusBusy: outSMBus->status = kIOReturnTimeout; break; case kIOSMBusStatusHostUnsupportedProtocol: outSMBus->status = kIOReturnUnsupported; break; default: outSMBus->status = kIOReturnInternalError; break; } } /* Retry this transaction if we received a failure */ } while ((inSMBus->flags & kEXFlagRetry) && (outSMBus->status != kIOReturnSuccess) && (++retryAttempts < kMaxRetries)); /* Output: read word/read block results */ if (((kIOSMBusProtocolReadWord == newTransaction.protocol) || (kIOSMBusProtocolReadBlock == newTransaction.protocol) || (kIOSMBusProtocolReadByte == newTransaction.protocol)) && (kIOSMBusStatusOK == newTransaction.status)) { outSMBus->outByteCount = newTransaction.receiveDataCount; for(i = 0; i<outSMBus->outByteCount; i++) { outSMBus->outBuf[i] = newTransaction.receiveData[i]; } } return kIOReturnSuccess; }