Jump to content

HP DVx ACPI 3.x/4.x Battery Driver (10.6/10.7)


  • Please log in to reply
227 replies to this topic

#1
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 143 posts
  • Gender:Male
  • Location:The Great White North
The following implements an Advanced Configuration and Power Interface (ACPI) based battery manager kernel extension (kext/driver) for laptops. It should work correctly on any laptop that correctly implements the ACPI standard DSDT methods as defined in the Advanced Configuration and Power Interface Specification 4.0a. Reference documents used:
The driver has both generic and HP specific functionality that is configurable and it will probably work on all platforms that properly implement the _BST, _BIF and/or _BIX methods in their DSDT. Therefore, there are several installation methods available:

Generic platforms:
  • ACPI 3.x _BIF method: Configure key "UseExtendedBatteryInformationMethod" to false in Info.plist and install kext.
  • ACPI 4.x _BIX method: Configure key "UseExtendedBatteryInformationMethod" to true in Info.plist and install kext.
  • Ensure your ACPI _BIF, _BIX, _BST methods return data according to the ACPI specification referenced above.
HP DVx platforms:

As the HP _BST method on DVx isn't (IMHO) implemented correctly, DVx owners will also have to implement DSDT edits so that the _BST method returns proper values to the driver in order to calculate the time remaining (to charge or discharge) value. In addition, I have rewritten the _BIF method, created a new _BIX and BBIX (Bigger or Better _BIX) to correctly talk to the Smart Battery Subsystem (SBS) via the System Management Bus (SMBus) via the Embedded Controller (EC). This allows the reading of information from the battery that the HP methods do not include like cycle count, temperature and date of manufacture.

  • To support ACPI 3.x _BIF method: Configure key "UseExtendedBatteryInformationMethod" to false in Info.plist and install kext, Modify DSDT methods UPBS, UPBI and ITOS.
  • To support ACPI 4.x _BIX method: Configure key "UseExtendedBatteryInformationMethod" to true in Info.plist and install kext, Modify DSDT methods UPBS, UPBI, ITOS and add _BIX, UPBX and IVBX methods.
  • To support non-ACPI BBIX method: Configure key "UseExtraBatteryInformationMethod" to true in Info.plist and install kext, Modify DSDT methods UPBS, UPBI and ITOS and add BBIX, UPBG and IVBG methods.
The BBIX method, although non-standard, returns *all* of the battery information available from SBS including temperature and is basically an extension of the _BIX method.

This driver polls the battery state by default every 30 seconds. If you wish to override this value to make the system respond to battery events quicker, you can set "BatteryPollingPeriodOverride" in the Info.plist to the number of seconds between polls.

This was tested on an HP DV8 but will likely work on any DVx model that implements similar DSDT methods. Also, I have tested this on both 32-bit/64-bit kernels and the driver has been compiled to a 10.6 32/64-bit universal (FAT) binary. It will also work on 10.7 Lion provided your DSDT methods are performing 8-bit I/O access to the SMBus if accessed through the EC, See "Optional Step 2d: Lion Support for DVx" section for details.

Step 1: ACPI 3.x/4.x _BST DSDT edit (Common to all optional steps below):

In your DSDT.dsl, locate the BAT0 device and add/replace the following:
// Battery status storage

Name (PBST, Package (0x04)
{
	Zero,			 // 0x00, Battery state
	0xFFFFFFFF,	   // 0x01, Battery present rate
	0xFFFFFFFF,	   // 0x02, Battery remaining capacity
	0x2710			// 0x03, Battery present voltage
})

// Get battery status into PBST

Method (UPBS, 0, NotSerialized)
{
	Store (^^PCI0.LPCB.EC0.MBST, Index (PBST, 0x00))		 // 0x00, Battery state
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0a, RefOf (Local0))  // Current()
	Store (Local0, Index (PBST, 0x01))					  // 0x01, Battery present rate
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0f, RefOf (Local1))  // RemainingCapacity()
	Store (Local1, Index (PBST, 0x02))					  // 0x02, Battery remaining capacity
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x09, RefOf (Local2))  // Voltage()
	Store (Local2, Index (PBST, 0x03))					  // 0x03, Battery present voltage
}

// InValid Battery Status
// Store placeholder battery status in PBST when no battery installed

Method (IVBS, 0, NotSerialized)
{
	Store (Zero, Index (PBST, Zero))		// 0x00, Battery state
	Store (0xFFFFFFFF, Index (PBST, One))   // 0x01, Battery present rate
	Store (0xFFFFFFFF, Index (PBST, 0x02))  // 0x02, Battery remaining capacity
	Store (0x2710, Index (PBST, 0x03))	  // 0x03, Battery present voltage (10000)
}

There is a bug in the HP ITOS() Method used by the optional methods below so locate ITOS() under the Scope(_SB) namespace and replace it with:

// Function: Integer to ASCII/OS String
//
// Arg0 = Integer (DWord) to convert
// Return = Buffer of ASCII representation (Length = 0x5)

Method (ITOS, 1, NotSerialized)
{
	// Buffer to store converted string
	
	Store (Buffer (0x06)
		{
			0x20, 0x20, 0x20, 0x20, 0x20, 0x00
		}, Local0)
	
	// Lookup table for ASCII digit
	
	Store (Buffer (0x11)
		{
			"0123456789ABCDEF"
		}, Local7)
	Store (0x05, Local1)	// Counter
	Store (Zero, Local2)	// Index into Local0 (String)

	While (Local1)
	{
		Decrement (Local1)
		And (ShiftRight (Arg0, ShiftLeft (Local1, 0x02)), 0x0F, Local4) // Get next digit to convert
		GBFE (Local7, Local4, RefOf (Local5))						   // Get ACSII version from Local7 lookup table
		PBFE (Local0, Local2, Local5)								   // Put digit in string buffer
		Increment (Local2)											  // Index++
	}
	Store(Zero, Index(Local0, Local2))  // Ensure string ends with '\0'

	Return (Local0)
}

Optional Step 2a: ACPI 3.x _BIF with SBS information DSDT edit

In your DSDT.dsl, locate the BAT0 device and add/replace the following:
// Battery information storage

Name (PBIF, Package (0x0D)
{
	0x00000001,	  // 0x00, Power Unit
	0xFFFFFFFF,	  // 0x01, Design Capacity
	0xFFFFFFFF,	  // 0x02, Last Full Charge Capacity
	0x00000001,	  // 0x03, Battery technology
	0xFFFFFFFF,	  // 0x04, Design voltage
	0x000000FA,	  // 0x05, Design capacity of warning
	0x00000096,	  // 0x06, Design capacity of low
	0x0000000A,	  // 0x07, Battery capacity gradularity 1
	0x00000019,	  // 0x08, Battery capacity gradularity 2
	" ",			 // 0x09, Model number
	" ",			 // 0x0a, Serial number
	" ",			 // 0x0b, Battery type
	" "			  // 0x0c, OEM Information
})

// Get and store battery information in PBIF

Method (UPBI, 0, NotSerialized)
{
	Store (0x01, Index (PBIF, 0x00))						// 0x00, Power Unit
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x18, RefOf (Local0))  // DesignCapacity() - WORD - unsigned int
	Store (Local0, Index (PBIF, 0x01))					  // 0x01, Design Capacity
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x10, RefOf (Local1))  // FullChargeCapacity() - WORD - unsigned int
	Store (Local1, Index (PBIF, 0x02))					  // 0x02, Last Full Charge Capacity
	Store (0x01, Index (PBIF, 0x03))						// 0x03, Battery technology
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x19, RefOf (Local2))  // DesignVoltage() - WORD - unsigned int
	Store (Local2, Index (PBIF, 0x04))					  // 0x04, Design voltage
	Store (0xFA, Index (PBIF, 0x05))						// 0x05, Design capacity of warning
	Store (0x96, Index (PBIF, 0x06))						// 0x06, Design capacity of low
	Store (0x0A, Index (PBIF, 0x07))						// 0x07, Battery capacity gradularity 1
	Store (0x19, Index (PBIF, 0x08))						// 0x08, Battery capacity gradularity 2
	^^PCI0.LPCB.EC0.SMRD (0x0B, 0x16, 0x21, RefOf (Local3))  // DeviceName() - BLOCK - string
	Store (Local3, Index (PBIF, 0x09))					  // 0x09, Model number
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x1c, RefOf (Local4))  // SerialNumber() - WORD - unsigned int
	Store (ITOS (ToBCD (Local4)), Index (PBIF, 0x0a))	   // 0x0a, Serial number
	^^PCI0.LPCB.EC0.SMRD (0x0B, 0x16, 0x22, RefOf (Local5))  // DeviceChemistry() - BLOCK - string
	Store (Local5, Index (PBIF, 0x0b))					  // 0x0b, Battery type
	^^PCI0.LPCB.EC0.SMRD (0x0B, 0x16, 0x20, RefOf (Local6))  // ManufacturerName() - BLOCK - string
	Store (Local6, Index (PBIF, 0x0c))					  // 0x0c, OEM Information
}

// InValid Battery Information
// Store placeholder battery information in PBIF when no battery installed

Method (IVBI, 0, NotSerialized)
{
	Store (0x00000001, Index (PBIF, Zero))  // 0x00, Power Unit
	Store (0xFFFFFFFF, Index (PBIF, One))   // 0x01, Design Capacity
	Store (0xFFFFFFFF, Index (PBIF, 0x02))  // 0x02, Last Full Charge Capacity
	Store (0x00000001, Index (PBIF, 0x03))  // 0x03, Battery technology
	Store (0xFFFFFFFF, Index (PBIF, 0x04))  // 0x04, Design voltage
	Store (0x000000FA, Index (PBIF, 0x05))  // 0x05, Design capacity of warning
	Store (0x00000096, Index (PBIF, 0x06))  // 0x06, Design capacity of low
	Store (0x0000000A, Index (PBIF, 0x07))  // 0x07, Battery capacity gradularity 1
	Store (0x00000019, Index (PBIF, 0x08))  // 0x08, Battery capacity gradularity 2
	Store ("Bad", Index (PBIF, 0x09))	   // 0x09, Model number
	Store ("Bad", Index (PBIF, 0x0A))	   // 0x0a, Serial number
	Store ("Bad", Index (PBIF, 0x0B))	   // 0x0b, Battery type
	Store ("Bad", Index (PBIF, 0x0C))	   // 0x0c, OEM Information
}

Optional Step 2b: ACPI 4.x _BIX with SBS information DSDT edit

In your DSDT.dsl, locate the BAT0 device and add/replace the following:
// Battery information extended (ACPI 4.0)

Name (PBIX, Package (0x14)
{
	0x00000001,	 // 0x00, Revision //Integer
	0x00000001,	 // 0x01, Power Unit //Integer (DWORD)
	0xFFFFFFFF,	 // 0x02, Design Capacity //Integer (DWORD)
	0xFFFFFFFF,	 // 0x03, Last Full Charge Capacity //Integer (DWORD)
	0x00000001,	 // 0x04, Battery Technology //Integer (DWORD)
	0xFFFFFFFF,	 // 0x05, Design Voltage //Integer (DWORD)
	0x000000FA,	 // 0x06, Design Capacity of Warning //Integer (DWORD)
	0x00000096,	 // 0x07, Design Capacity of Low //Integer (DWORD)
	0x00000000,	 // 0x08, Cycle Count //Integer (DWORD)
	0x00100000,	 // 0x09, Measurement Accuracy //Integer (DWORD)
	0xFFFFFFFF,	 // 0x0a, Max Sampling Time //Integer (DWORD)
	0xFFFFFFFF,	 // 0x0b, Min Sampling Time //Integer (DWORD)
	0xFFFFFFFF,	 // 0x0c, Max Averaging Interval //Integer (DWORD)
	0xFFFFFFFF,	 // 0x0d, Min Averaging Interval //Integer (DWORD)
	0x0000000A,	 // 0x0e, Battery Capacity Granularity 1 //Integer (DWORD)
	0x00000019,	 // 0x0f, Battery Capacity Granularity 2 //Integer (DWORD)
	" ",			// 0x10, Model Number //String (ASCIIZ)
	" ",			// 0x11, Serial Number //String (ASCIIZ)
	" ",			// 0x12, Battery Type //String (ASCIIZ)
	" "			 // 0x13, OEM Information //String (ASCIIZ)
})

// Return battery extended information in PBIX

Method (_BIX, 0, NotSerialized)
{
	If (ECON)
	{
		If (^^PCI0.LPCB.EC0.MBTS)
		{
			UPBX () // Return battery information
		}
		Else
		{
			IVBX () // No battery, return placeholder info
		}
	}
	Else
	{
		IVBX () // No battery, return placeholder info
	}

	Return (PBIX)
}

// Get and store battery extended information in PBIX

Method (UPBX, 0, NotSerialized)
{
	Store (0x00, Index (PBIX, 0x00))						// 0x01, Revision
	Store (0x01, Index (PBIX, 0x01))						// 0x01, Power Unit
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x18, RefOf (Local0))  // DesignCapacity() - WORD - unsigned int
	Store (Local0, Index (PBIX, 0x02))					  // 0x02, Design Capacity
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x10, RefOf (Local1))  // FullChargeCapacity() - WORD - unsigned int
	Store (Local1, Index (PBIX, 0x03))					  // 0x03, Last Full Charge Capacity
	Store (0x01, Index (PBIX, 0x04))						// 0x04, Battery technology
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x19, RefOf (Local2))  // DesignVoltage() - WORD - unsigned int
	Store (Local2, Index (PBIX, 0x05))					  // 0x05, Design voltage
	Store (0xFA, Index (PBIX, 0x06))						// 0x06, Design capacity of warning
	Store (0x96, Index (PBIX, 0x07))						// 0x07, Design capacity of low
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x17, RefOf (Local0))  // CycleCount() - WORD - unsigned int
	Store (Local0, Index (PBIX, 0x08))					  // 0x08, Cycle Count
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0c, RefOf (Local0))  // MaxError() - WORD - unsigned int
	Multiply (Local0, 0x1000, Index (PBIX, 0x09))		   // 0x09, Measurement Accuracy
	Store (0xFFFFFFFF, Index (PBIX, 0x0a))				  // 0x0a, Max Sampling Time
	Store (0xFFFFFFFF, Index (PBIX, 0x0b))				  // 0x0b, Min Sampling Time
	Store (0x0000EA60, Index (PBIX, 0x0c))				  // 0x0c, Max Averaging Interval
	Store (0x0000EA60, Index (PBIX, 0x0d))				  // 0x0d, Min Averaging Interval
	Store (0x0A, Index (PBIX, 0x0e))						// 0x0e, Battery capacity gradularity 1
	Store (0x19, Index (PBIX, 0x0f))						// 0x0f, Battery capacity gradularity 2
	^^PCI0.LPCB.EC0.SMRD (0x0B, 0x16, 0x21, RefOf (Local3))  // DeviceName() - BLOCK - string
	Store (Local3, Index (PBIX, 0x10))					  // 0x10, Model number
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x1c, RefOf (Local4))  // SerialNumber() - WORD - unsigned int
	Store (ITOS (ToBCD (Local4)), Index (PBIX, 0x11))	   // 0x11, Serial number
	^^PCI0.LPCB.EC0.SMRD (0x0B, 0x16, 0x22, RefOf (Local5))  // DeviceChemistry() - BLOCK - string
	Store (Local5, Index (PBIX, 0x12))					  // 0x12, Battery type
	^^PCI0.LPCB.EC0.SMRD (0x0B, 0x16, 0x20, RefOf (Local6))  // ManufacturerName() - BLOCK - string
	Store (Local6, Index (PBIX, 0x13))					  // 0x0c, OEM Information
}

// InValid Battery eXtended Information
// Store placeholder battery status in PBIX when no battery installed

Method (IVBX, 0, NotSerialized)
{
	Store (0x00000000, Index (PBIX, 0x00)) // 0x00, Revision
	Store (0x00000001, Index (PBIX, 0x01)) // 0x01, Power Unit
	Store (0xFFFFFFFF, Index (PBIX, 0x02)) // 0x02, Design Capacity
	Store (0xFFFFFFFF, Index (PBIX, 0x03)) // 0x03, Last Full Charge Capacity
	Store (0x00000001, Index (PBIX, 0x04)) // 0x04, Battery technology
	Store (0xFFFFFFFF, Index (PBIX, 0x05)) // 0x05, Design voltage
	Store (0x000000FA, Index (PBIX, 0x06)) // 0x06, Design capacity of warning
	Store (0x00000096, Index (PBIX, 0x07)) // 0x07, Design capacity of low
	Store (0x00000000, Index (PBIX, 0x08)) // 0x08, Cycle Count
	Store (0x00100000, Index (PBIX, 0x09)) // 0x09, Measurement Accuracy
	Store (0xFFFFFFFF, Index (PBIX, 0x0a)) // 0x0a, Max Sampling Time
	Store (0xFFFFFFFF, Index (PBIX, 0x0b)) // 0x0b, Min Sampling Time
	Store (0x0000EA60, Index (PBIX, 0x0c)) // 0x0c, Max Averaging Interval
	Store (0x0000EA60, Index (PBIX, 0x0d)) // 0x0d, Min Averaging Interval
	Store (0x0000000A, Index (PBIX, 0x0e)) // 0x0e, Battery capacity gradularity 1
	Store (0x00000019, Index (PBIX, 0x0f)) // 0x0f, Battery capacity gradularity 2
	Store ("Bad", Index (PBIX, 0x10))	  // 0x10, Model number
	Store ("Bad", Index (PBIX, 0x11))	  // 0x11, Serial number
	Store ("Bad", Index (PBIX, 0x12))	  // 0x12, Battery type
	Store ("Bad", Index (PBIX, 0x13))	  // 0x0c, OEM Information
}

Optional Step 2c: BBIX with all SBS information DSDT edit

In your DSDT.dsl, locate the BAT0 device and add/replace the following:
// Battery information - Non-standard stuff OSX will use

Name (PBIG, Package (0x10)
{
	0x00000000, // 0x00, ManufacturerAccess() - WORD - ?
	0x00000000, // 0x01, BatteryMode() - WORD - unsigned int
	0xFFFFFFFF, // 0x02, AtRateTimeToFull() - WORD - unsigned int (min)
	0xFFFFFFFF, // 0x03, AtRateTimeToEmpty() - WORD - unsigned int (min)
	0x00000000, // 0x04, Temperature() - WORD - unsigned int (0.1K)
	0x00000000, // 0x05, Voltage() - WORD - unsigned int (mV)
	0x00000000, // 0x06, Current() - WORD - signed int (mA)
	0x00000000, // 0x07, AverageCurrent() - WORD - signed int (mA)
	0x00000000, // 0x08, RelativeStateOfCharge() - WORD - unsigned int (%)
	0x00000000, // 0x09, AbsoluteStateOfCharge() - WORD - unsigned int (%)
	0x00000000, // 0x0a, RemaingingCapacity() - WORD - unsigned int (mAh or 10mWh)
	0xFFFFFFFF, // 0x0b, RunTimeToEmpty() - WORD - unsigned int (min)
	0xFFFFFFFF, // 0x0c, AverageTimeToEmpty() - WORD - unsigned int (min)
	0xFFFFFFFF, // 0x0d, AverageTimeToFull() - WORD - unsigned int (min)
	0x00000000, // 0x0e, ManufactureDate() - WORD - unsigned int (packed date)
	" "		 // 0x0f, ManufacturerData() - BLOCK - Unknown
})

// Return battery extra information in PBIG

Method (BBIX, 0, NotSerialized)
{
	If (ECON)
	{
		If (^^PCI0.LPCB.EC0.MBTS)
		{
			UPBG () // Return battery information
		}
		Else
		{
			IVBG () // No battery, return placeholder info
		}
	}
	Else
	{
		IVBG () // No battery, return placeholder info
	}

	Return (PBIG)
}

// Get and store battery extra information in PBIG

Method (UPBG, 0, NotSerialized)
{
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x00, RefOf (Local0))  // ManufacturerAccess() - WORD - ?
	Store (Local0, Index (PBIG, 0x00))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x03, RefOf (Local0))  // BatteryMode() - WORD - unsigned int
	Store (Local0, Index (PBIG, 0x01))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x05, RefOf (Local0))  // AtRateTimeToFull() - WORD - unsigned int (min)
	Store (Local0, Index (PBIG, 0x02))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x06, RefOf (Local0))  // AtRateTimeToEmpty() - WORD - unsigned int (min)
	Store (Local0, Index (PBIG, 0x03))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x08, RefOf (Local0))  // Temperature() - WORD - unsigned int (0.1K)
	Store (Local0, Index (PBIG, 0x04))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x09, RefOf (Local0))  // Voltage() - WORD - unsigned int (mV)
	Store (Local0, Index (PBIG, 0x05))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0a, RefOf (Local0))  // Current() - WORD - signed int (mA)
	Store (Local0, Index (PBIG, 0x06))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0b, RefOf (Local0))  // AverageCurrent() - WORD - signed int (mA)
	Store (Local0, Index (PBIG, 0x07))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0d, RefOf (Local0))  // RelativeStateOfCharge() - WORD - unsigned int (%)
	Store (Local0, Index (PBIG, 0x08))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0e, RefOf (Local0))  // AbsoluteStateOfCharge() - WORD - unsigned int (%)
	Store (Local0, Index (PBIG, 0x09))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x0f, RefOf (Local0))  // RemaingingCapacity() - WORD - unsigned int (mAh or 10mWh)
	Store (Local0, Index (PBIG, 0x0A))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x11, RefOf (Local0))  // RunTimeToEmpty() - WORD - unsigned int (min)
	Store (Local0, Index (PBIG, 0x0B))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x12, RefOf (Local0))  // AverageTimeToEmpty() - WORD - unsigned int (min)
	Store (Local0, Index (PBIG, 0x0C))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x13, RefOf (Local0))  // AverageTimeToFull() - WORD - unsigned int (min)
	Store (Local0, Index (PBIG, 0x0D))
	^^PCI0.LPCB.EC0.SMRD (0x09, 0x16, 0x1b, RefOf (Local0))  // ManufactureDate() - WORD - unsigned int (packed date)
	Store (Local0, Index (PBIG, 0x0E))
	^^PCI0.LPCB.EC0.SMRD (0x0B, 0x16, 0x23, RefOf (Local0))  // ManufacturerData() - BLOCK - Unknown
	Store (Local0, Index (PBIG, 0x0F))
}

// InValid battery extra information
// Store placeholder battery extra information in PBIG when no battery is installed

Method (IVBG, 0, NotSerialized)
{
	Store (0x00000000, Index (PBIG, 0x00)) // 0x00, ManufacturerAccess() - WORD - ?
	Store (0x00000000, Index (PBIG, 0x01)) // 0x01, BatteryMode() - WORD - unsigned int
	Store (0xFFFFFFFF, Index (PBIG, 0x02)) // 0x02, AtRateTimeToFull() - WORD - unsigned int (min)
	Store (0xFFFFFFFF, Index (PBIG, 0x03)) // 0x03, AtRateTimeToEmpty() - WORD - unsigned int (min)
	Store (0x00000000, Index (PBIG, 0x04)) // 0x04, Temperature() - WORD - unsigned int (0.1K)
	Store (0x00000000, Index (PBIG, 0x05)) // 0x05, Voltage() - WORD - unsigned int (mV)
	Store (0x00000000, Index (PBIG, 0x06)) // 0x06, Current() - WORD - signed int (mA)
	Store (0x00000000, Index (PBIG, 0x07)) // 0x07, AverageCurrent() - WORD - signed int (mA)
	Store (0x00000000, Index (PBIG, 0x08)) // 0x08, RelativeStateOfCharge() - WORD - unsigned int (%)
	Store (0x00000000, Index (PBIG, 0x09)) // 0x09, AbsoluteStateOfCharge() - WORD - unsigned int (%)
	Store (0x00000000, Index (PBIG, 0x0a)) // 0x0a, RemaingingCapacity() - WORD - unsigned int (mAh or 10mWh)
	Store (0xFFFFFFFF, Index (PBIG, 0x0b)) // 0x0b, RunTimeToEmpty() - WORD - unsigned int (min)
	Store (0xFFFFFFFF, Index (PBIG, 0x0c)) // 0x0c, AverageTimeToEmpty() - WORD - unsigned int (min)
	Store (0xFFFFFFFF, Index (PBIG, 0x0d)) // 0x0d, AverageTimeToFull() - WORD - unsigned int (min)
	Store (0x00000000, Index (PBIG, 0x0e)) // 0x0e, ManufactureDate() - WORD - unsigned int (packed date)
	Store (" ", Index (PBIG, 0x0f))		// 0x0f, ManufacturerData() - BLOCK - Unknown
}

Optional Step 2d: Lion Support for DVx

Due to stricter ACPI Machine Language (AML) parsing in the AppleACPIPlatform.kext in 10.7 Lion, it appears that any registers in the EC operation region (address space) must be accessed with 8-bit (byte) references. On my DV8, the SMBus that talks to the SBS is wired into the EC and therefore we must access these registers with 8-bit references even though the SMBus standard does provide for 16-bit (Word) access, etc.

The HP DSDT uses two methods under the EC device to read and write the SMBus, SMRD() and SMWR(). I re-wrote the parts of these methods that did Word and Block (string) I/O to do the same thing via bytes so that the AppleACPIPlatform AML parser would not throw an exception. The first thing we need is a new big-old-ugly field definition for accessing the 32 bytes (256 bits) of SMBus data registers. We need to know the offset of these registers, so looking at the Field definition for EmbeddedController operation region we see:

// Embedded controller I/O Registers
// SMBus mapped at offset 0x00

OperationRegion (ERAM, EmbeddedControl, Zero, 0xFF)
Field (ERAM, ByteAcc, Lock, Preserve)
{
	SMPR,   8,				  // SMBus Protocol Register
	SMST,   8,				  // SMBus Status Register
	SMAD,   8,				  // SMBus Address Register
	SMCM,   8,				  // SMBus Command Register
	SMD0,   256,				// SMBus Data Register[0-31] ( 32 byte buffer)
	BCNT,   8,				  // SMBus Block Count Register
	SMAA,   8,				  // SMBus Alarm Address Register
	SAD0,   8,				  // SMBus Alarm Data Register[0]
	SAD1,   8,				  // SMBus Alarm Data Register[1]
	...
So we can see the SMBus Data Register starts at offset 0x04, so under the EC device add:
// Define 8-bit fields for accessing SMBus data registers [0-31]

Field (ERAM, ByteAcc, Lock, Preserve)
{
			Offset (0x04),
	SM00,   8,
	SM01,   8,
	SM02,   8,
	SM03,   8,
	SM04,   8,
	SM05,   8,
	SM06,   8,
	SM07,   8,
	SM08,   8,
	SM09,   8,
	SM10,   8,
	SM11,   8,
	SM12,   8,
	SM13,   8,
	SM14,   8,
	SM15,   8,
	SM16,   8,
	SM17,   8,
	SM18,   8,
	SM19,   8,
	SM20,   8,
	SM21,   8,
	SM22,   8,
	SM23,   8,
	SM24,   8,
	SM25,   8,
	SM26,   8,
	SM27,   8,
	SM28,   8,
	SM29,   8,
	SM30,   8,
	SM31,   8
}
Ya, its ugly, but it works. I'm sure this can be done using an index into the field but I need to research this more. Also under the EC device, replace the SMRD and SMWR methods with these:
// SMBus Read
// See ACPI Spec, section "12.9 SMBus Host Controller Interface via Embedded Controller"
//
// Arg0 = Protocol to use
// Arg1 = Slave address to read from
// Arg2 = Command to send to slave
// Arg3 = Return data pointer
//
// Returns SMBus status (although no caller is checking the status for other than kIOSMBusStatusOK <img src='http://www.insanelymac.com/forum/public/style_emoticons/<#EMO_DIR#>/sad.png' class='bbc_emoticon' alt=':(' />

Method (SMRD, 4, NotSerialized)
{
	If (LNot (ECON))
	{
		Return (0x17)				   // No embedded controller! (kIOSMBusStatusDeviceAccessDenied)
	}

	If (LNotEqual (Arg0, 0x07))		 // kIOSMBusProtocolReadByte
	{
		If (LNotEqual (Arg0, 0x09))	 // kIOSMBusProtocolReadWord
		{
			If (LNotEqual (Arg0, 0x0B)) // kIOSMBusProtocolReadBlock
			{
				Return (0x19)		   // kIOSMBusStatusHostUnsupportedProtocol
			}
		}
	}
	
	Acquire (MUT0, 0xFFFF)			  // Lock SMBus
	Store (0x04, Local0)				// Try 3 times
	While (LGreater (Local0, One))
	{
		And (SMST, 0x40, SMST)				  // Clear status (Don't clear Alarm bit!)
		Store (Arg2, SMCM)					  // Command
		Store (Arg1, SMAD)					  // Address
		Store (Arg0, SMPR)					  // Protocol
		Store (Zero, Local3)					// Timeout counter
		While (LNot (And (SMST, 0xBF, Local1))) // Is command done? (not Alarm!)
		{
			Sleep (0x02)						// nope, nap
			Increment (Local3)				  // count nap
			If (LEqual (Local3, 0x32))		  // count = 50?
			{
				And (SMST, 0x40, SMST)		  // Send command again!
				Store (Arg2, SMCM)
				Store (Arg1, SMAD)
				Store (Arg0, SMPR)
				Store (Zero, Local3)			// reset counter
			}
		}

		If (LEqual (Local1, 0x80))		  // Is command DONE?
		{
			Store (Zero, Local0)			// Yup, exit retry loop
		}
		Else
		{
			Decrement (Local0)			  // Nope, another round please!
		}
	}
	
	If (Local0)								 // After 3 attempts, something is FUBAR
	{
		Store (And (Local1, 0x1F), Local0)	  // Return SMBus status error
	}
	Else										// Command worked, return data
	{
		If (LEqual (Arg0, 0x07))				// kIOSMBusProtocolReadByte
		{
			Store (SM00, Arg3)				  // Byte Output
		}

		If (LEqual (Arg0, 0x09))				// kIOSMBusProtocolReadWord
		{
			Store (SM00, Local4)				// Low byte (Word)
			Store (SM01, Local5)				// High byte (Word)
			ShiftLeft (Local5, 0x08, Local5)	// Move high byte into place
			Or (Local4, Local5, Local6)		 // Add low byte
			Store (Local6, Arg3)				// Return word
		}

		If (LEqual (Arg0, 0x0B))						// kIOSMBusProtocolReadBlock
		{
			Store (And (BCNT, 0x1F) , Local3)		   // Get block count of data (bits0-4 or 01xf)
			Increment (Local3)						  // Add one to data count (for '\0')
			Store (Buffer (Local3) { "" }, Local4)	  // Create an empty buffer of data count + 1
			Decrement (Local3)						  // Size of data
			Store (Zero, Local5)						// Index into buffer

			While (LGreater (Local3, Local5))		   // More data to copy?
			{
				If (LEqual (Local5, 0x00)) { Store (SM00, Local6) }	 // Get byte of data
				If (LEqual (Local5, 0x01)) { Store (SM01, Local6) }
				If (LEqual (Local5, 0x02)) { Store (SM02, Local6) }
				If (LEqual (Local5, 0x03)) { Store (SM03, Local6) }
				If (LEqual (Local5, 0x04)) { Store (SM04, Local6) }
				If (LEqual (Local5, 0x05)) { Store (SM05, Local6) }
				If (LEqual (Local5, 0x06)) { Store (SM06, Local6) }
				If (LEqual (Local5, 0x07)) { Store (SM07, Local6) }
				If (LEqual (Local5, 0x08)) { Store (SM08, Local6) }
				If (LEqual (Local5, 0x09)) { Store (SM09, Local6) }
				
				If (LEqual (Local5, 0x0A)) { Store (SM10, Local6) }
				If (LEqual (Local5, 0x0B)) { Store (SM11, Local6) }
				If (LEqual (Local5, 0x0C)) { Store (SM12, Local6) }
				If (LEqual (Local5, 0x0D)) { Store (SM13, Local6) }
				If (LEqual (Local5, 0x0E)) { Store (SM14, Local6) }
				If (LEqual (Local5, 0x0F)) { Store (SM15, Local6) }
				If (LEqual (Local5, 0x10)) { Store (SM16, Local6) }
				If (LEqual (Local5, 0x11)) { Store (SM17, Local6) }
				If (LEqual (Local5, 0x12)) { Store (SM18, Local6) }
				If (LEqual (Local5, 0x13)) { Store (SM19, Local6) }
				
				If (LEqual (Local5, 0x14)) { Store (SM20, Local6) }
				If (LEqual (Local5, 0x15)) { Store (SM21, Local6) }
				If (LEqual (Local5, 0x16)) { Store (SM22, Local6) }
				If (LEqual (Local5, 0x17)) { Store (SM23, Local6) }
				If (LEqual (Local5, 0x18)) { Store (SM24, Local6) }
				If (LEqual (Local5, 0x19)) { Store (SM25, Local6) }
				If (LEqual (Local5, 0x1A)) { Store (SM26, Local6) }
				If (LEqual (Local5, 0x1B)) { Store (SM27, Local6) }
				If (LEqual (Local5, 0x1C)) { Store (SM28, Local6) }
				If (LEqual (Local5, 0x1D)) { Store (SM29, Local6) }
				
				If (LEqual (Local5, 0x1E)) { Store (SM30, Local6) }
				If (LEqual (Local5, 0x1F)) { Store (SM31, Local6) }
				
				PBFE (Local4, Local5, Local6)   // Store byte in buffer
				Increment (Local5)			  // Next!
			}

			PBFE (Local4, Local5, Zero)		 // Finish buffer with '\0' or 0x00
			Store (Local4, Arg3)				// Return buffer/block
		}
	}

	Release (MUT0)	  // Release SMBus lock
	Return (Local0)	 // Return 0 (OK)
}

// SMBus Write
// See ACPI Spec, section "12.9 SMBus Host Controller Interface via Embedded Controller"
//
// Arg0 = Protocol to use
// Arg1 = Slave address to write to
// Arg2 = Command to send to slave
// Arg3 = Pointer to data to write

Method (SMWR, 4, NotSerialized)
{
	If (LNot (ECON))
	{
		Return (0x17)   // No embedded controller! (kIOSMBusStatusDeviceAccessDenied)
	}

	If (LNotEqual (Arg0, 0x06))			 // kIOSMBusProtocolWriteByte
	{
		If (LNotEqual (Arg0, 0x08))		 // kIOSMBusProtocolWriteWord
		{
			If (LNotEqual (Arg0, 0x0A))	 // kIOSMBusProtocolWriteBlock
			{
				Return (0x19)			   // kIOSMBusStatusHostUnsupportedProtocol
			}
		}
	}

	Acquire (MUT0, 0xFFFF)				  // Lock SMBus
	Store (0x04, Local0)					// 3 tries
	While (LGreater (Local0, One))
	{
		If (LEqual (Arg0, 0x06))
		{
			Store (Arg3, SM00)			  // Byte to write
		}

		If (LEqual (Arg0, 0x08))			  
		{
			Store (Arg3, Local6)				// Word to write
			And (Local6, 0xFF, Local4)		  // Low byte
			ShiftRight (Local6, 0x08, Local5)   // High byte
			Store (Local4, SM00)				// Low byte (Word)
			Store (Local5, SM01)				// High byte (Word)
		}

		If (LEqual (Arg0, 0x0A))
		{
			Store (SizeOf (Arg3), Local3)	   // Get buffer/block/string size
			And (Local3, 0x1F, Local3)		  // Limit to 32 bytes!
			Store (Arg3, Local4)				// Buffer/block/string pointer
			Store (Zero, Local5)				// Index into buffer
			
			While (LGreater (Local3, Local5))   // More data to copy?
			{
				GBFE (Local4, Local5, RefOf (Local6))   // Get byte from buffer
				
				If (LEqual (Local5, 0x00)) { Store (Local6, SM00) } // Write byte of data
				If (LEqual (Local5, 0x01)) { Store (Local6, SM01) }
				If (LEqual (Local5, 0x02)) { Store (Local6, SM02) }
				If (LEqual (Local5, 0x03)) { Store (Local6, SM03) }
				If (LEqual (Local5, 0x04)) { Store (Local6, SM04) }
				If (LEqual (Local5, 0x05)) { Store (Local6, SM05) }
				If (LEqual (Local5, 0x06)) { Store (Local6, SM06) }
				If (LEqual (Local5, 0x07)) { Store (Local6, SM07) }
				If (LEqual (Local5, 0x08)) { Store (Local6, SM08) }
				If (LEqual (Local5, 0x09)) { Store (Local6, SM09) }
				
				If (LEqual (Local5, 0x0A)) { Store (Local6, SM10) }
				If (LEqual (Local5, 0x0B)) { Store (Local6, SM11) }
				If (LEqual (Local5, 0x0C)) { Store (Local6, SM12) }
				If (LEqual (Local5, 0x0D)) { Store (Local6, SM13) }
				If (LEqual (Local5, 0x0E)) { Store (Local6, SM14) }
				If (LEqual (Local5, 0x0F)) { Store (Local6, SM15) }
				If (LEqual (Local5, 0x10)) { Store (Local6, SM16) }
				If (LEqual (Local5, 0x11)) { Store (Local6, SM17) }
				If (LEqual (Local5, 0x12)) { Store (Local6, SM18) }
				If (LEqual (Local5, 0x13)) { Store (Local6, SM19) }
				
				If (LEqual (Local5, 0x14)) { Store (Local6, SM20) }
				If (LEqual (Local5, 0x15)) { Store (Local6, SM21) }
				If (LEqual (Local5, 0x16)) { Store (Local6, SM22) }
				If (LEqual (Local5, 0x17)) { Store (Local6, SM23) }
				If (LEqual (Local5, 0x18)) { Store (Local6, SM24) }
				If (LEqual (Local5, 0x19)) { Store (Local6, SM25) }
				If (LEqual (Local5, 0x1A)) { Store (Local6, SM26) }
				If (LEqual (Local5, 0x1B)) { Store (Local6, SM27) }
				If (LEqual (Local5, 0x1C)) { Store (Local6, SM28) }
				If (LEqual (Local5, 0x1D)) { Store (Local6, SM29) }
				
				If (LEqual (Local5, 0x1E)) { Store (Local6, SM30) }
				If (LEqual (Local5, 0x1F)) { Store (Local6, SM31) }
				
				Increment (Local5)			  // Next!
			}
			Store (And (Local3, 0x1F), BCNT)	// Store block count (limit to 32!)
		}

		And (SMST, 0x40, SMST)				  // Don't clear Alarm bit!
		Store (Arg2, SMCM)					  // Command
		Store (Arg1, SMAD)					  // Address
		Store (Arg0, SMPR)					  // Protocol
		Store (Zero, Local3)					// timeout counter
		While (LNot (And (SMST, 0xBF, Local1))) // Is command done? (not Alarm!)
		{
			Sleep (0x02)						// nap
			Increment (Local3)				  // count
			If (LEqual (Local3, 0x32))		  // count = 50?
			{
				And (SMST, 0x40, SMST)		  // Send command again!
				Store (Arg2, SMCM)
				Store (Arg1, SMAD)
				Store (Arg0, SMPR)
				Store (Zero, Local3)
			}
		}

		If (LEqual (Local1, 0x80))			  // Command DONE?
		{
			Store (Zero, Local0)				// Yup, exit retry loop
		}
		Else
		{
			Decrement (Local0)				  // Another round!
		}
	}

	If (Local0)								 // If we tried 3 times, FUBAR!
	{
		Store (And (Local1, 0x1F), Local0)	  // Return error
	}

	Release (MUT0)	  // Release SMBus lock
	Return (Local0)	 // Return 0 (OK)
}

Compile the DSDT and install as usual.

Step 3: Install Driver

Install the kext in /Extra/Extensions, set the permissions and options in Info.plust, rebuild your kext cache. Reboot.

There are two zip files below, a debug and release version. The debug version outputs messages to kernel.log and the release version does not, otherwise they are identical.

Attached File  AppleACPIBatteryManager_20110802_release.zip   36.85KB   474 downloads
Attached File  AppleACPIBatteryManager_20110802_debug.zip   44.63KB   108 downloads

The following two drivers are identical to the above versions except the driver classes and kext have been renamed to the same as Apple's Smart Battery Manager and therefore allows some 3rd party application such as iStat Menus and coconutBattery to work.

Attached File  AppleSmartBatteryManager_20110802_release.zip   36.83KB   730 downloads
Attached File  AppleSmartBatteryManager_20110802_debug.zip   44.62KB   181 downloads

Source code: https://github.com/g...-Battery-Driver

Change Log

2012-05-08
  • Added source code link
2011-09-25
  • Added reference document links
  • Reordered this change log so latest changes are at the top
2011-09-21
  • Added "Optional Step 2d: Lion Support for DVx" section.
2011-08-05
  • Renamed drivers classes to allow compatibility with some 3rd party battery information application.
  • Added new driver binaries for 2011.0802 release.
2011-08-04
  • Updated DSDT code in posting with stock EC0 device name.
2011-08-02
  • Added ACPI 4.x support.
  • Added non-standard support for temperature.
  • Compiled with XCode 4.
  • Lots of debugging.


#2
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 116 posts
  • Gender:Male
  • Location:Krakow, Poland
Heeey! AWESOME :) Thanks gsly, you're THE man!
I will test now :wacko: and give feedback soon. One question. Will this work on 10.7?

:dev:

#3
buoo

buoo

    The Prodigal Son

  • Moderators
  • 4,541 posts
  • Gender:Male
  • Location:Italy
A long time has passed since the last time I heard a project like this. I have to say that there are few solutions for the laptop batteries.
I'll try it as soon as possible!

Thanks ^^

#4
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 143 posts
  • Gender:Male
  • Location:The Great White North

Heeey! AWESOME :) Thanks gsly, you're THE man!
I will test now :wacko: and give feedback soon. One question. Will this work on 10.7?

:dev:

I have not tested it on 10.7 yet. I wanted to get this release out before I get into 10.7 support/changes. I've been able to install 10.7 but I have a bit more work to get it working the same as my 10.6.8 install, but I'll be working on that in the next week or so after which I'll see if the code can be adapted to 10.7 or if I need to switch to Plan B :)

#5
manmal

manmal

    InsanelyMac Sage

  • Members
  • PipPipPipPipPipPip
  • 441 posts

I have not tested it on 10.7 yet. I wanted to get this release out before I get into 10.7 support/changes. I've been able to install 10.7 but I have a bit more work to get it working the same as my 10.6.8 install, but I'll be working on that in the next week or so after which I'll see if the code can be adapted to 10.7 or if I need to switch to Plan B :)


Thank you very very much glsy for this new driver !!

A couple questions :

1) Which fixes did you apply for your dv8 (expecially for step2)? 2a+2b+2c or just one of them ? Which is the one you consider the best for dv8? 2a,2b or 2c, in case you have to choose just one of such fixes you posted?

2) Does the new driver provide a "method" to put dv8 on sleep (or hibernate mode) when battery goes under a certain percentage, like in true macs (without powering it on and sleep again when near to zero)? I have a macbookpro and it gives the first advice when it is about 10% and puts it in sleep mode automatically when lower than 5% . If you need something to test on my mbp15 just let me know...

Mal

PS: Would you share your updated dv8 dsdt.aml, just for "learning" purpose to see what did you apply and so on?

#6
Peter_sm

Peter_sm

    InsanelyMac Sage

  • Members
  • PipPipPipPipPip
  • 281 posts
Hi,

There is a great DSDT for DV8 where sound and brightness/video is updated for LION in this post
http://www.insanelym...p...t&p=1727179

//Peter

#7
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 116 posts
  • Gender:Male
  • Location:Krakow, Poland
I had to change all the PCI0.LPCB.EC references to PCI0.LPCB.EC0.
And unfortunately it does not work on Lion at this state. I will try my backup 10.6 system.

EDIT:
Works nicely on 10.6, great job! Waiting for the 10.7 update :D

#8
JBraddock

JBraddock

    Ph.D (Can) in Human Rights

  • Members
  • PipPipPipPipPipPipPip
  • 549 posts
  • Location:UK
Nicely done gsly :hysterical: I can't wait to test this on Lion.

Thanks,

#9
MacKonsti

MacKonsti

    InsanelyMac Geek

  • Members
  • PipPipPipPip
  • 233 posts
  • Gender:Male
  • Location:Muppet Show
Guys, it this kext only restricted to HP laptops? What about netbooks? I was thinking of installing it on my Dell Mini 10v but I know for a fact that the battery DSDT section is more messy that the code posted by gsly.

Any means of checking out if this works on other laptops, by a Terminal command for example, before tampering with a nicely-working 10.6.7 system?

Cheers!

#10
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 143 posts
  • Gender:Male
  • Location:The Great White North

1) Which fixes did you apply for your dv8 (expecially for step2)? 2a+2b+2c or just one of them ? Which is the one you consider the best for dv8? 2a,2b or 2c, in case you have to choose just one of such fixes you posted?

Personally, I use the full 2a+2b+2c for testing full functionality. The methods are independent of one another so you can put them all in your DSDT and use what you want.

2) Does the new driver provide a "method" to put dv8 on sleep (or hibernate mode) when battery goes under a certain percentage, like in true macs (without powering it on and sleep again when near to zero)? I have a macbookpro and it gives the first advice when it is about 10% and puts it in sleep mode automatically when lower than 5% . If you need something to test on my mbp15 just let me know...

As mentioned in this http://www.insanelym...p...t&p=1657247 posting, the battery driver provided here (and same as the Apple driver) does not put the system to sleep. It simply supplies power information to the power management layer and its that layer that will issue the "system is going to sleep" message. The problem with auto-sleep is that software can "override" the system request to sleep, but I believe the issue on our hackitoshes is that some drivers are not built to properly respond to the sleep request and hence the power management layer never issues the sleep command as not all of the bits of the system acknowledged and shut themselves down. If you google a bit on the subject, you'll find that real Macs suffer from the same issue, although to a lesser degree. Also, it you look at the power management source code for 10.7, you'll see lots of changes in the PM layer and little in the battery driver which suggests to me that Apple is still trying to fix it :)


I had to change all the PCI0.LPCB.EC references to PCI0.LPCB.EC0.
And unfortunately it does not work on Lion at this state. I will try my backup 10.6 system.

EDIT:
Works nicely on 10.6, great job! Waiting for the 10.7 update :)

Whoops! Thanks NIXin, I forgot I had renamed my EC0 device to EC (same as MacBookPro6,1). I updated the OP with the stock EC0 reference.


Guys, it this kext only restricted to HP laptops? What about netbooks? I was thinking of installing it on my Dell Mini 10v but I know for a fact that the battery DSDT section is more messy that the code posted by gsly.

Follow the Generic Platform instructions. The hardest part of course is to figure out how your system talks to the battery and returns information (SMI/SMM, EC/SMBus, etc) and coding the _BST, _BIF or _BIX methods to return the data in the ACPI defined structure.

#11
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 116 posts
  • Gender:Male
  • Location:Krakow, Poland
How do we read out all the battery information? System profiler shows most of that stuff, but no battery temperature for example.
Also, iStat Pro doesn't see the battery at all ("no battery present").
Again, many thanks gsly, for this great contribution!

#12
JBraddock

JBraddock

    Ph.D (Can) in Human Rights

  • Members
  • PipPipPipPipPipPipPip
  • 549 posts
  • Location:UK

How do we read out all the battery information? System profiler shows most of that stuff, but no battery temperature for example.
Also, iStat Pro doesn't see the battery at all ("no battery present").
Again, many thanks gsly, for this great contribution!

Try this version of iStat.

#13
Fraom

Fraom

    InsanelyMac Geek

  • Members
  • PipPipPipPip
  • 222 posts
  • Gender:Male
It work on hp dv6 AMD ??

#14
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 143 posts
  • Gender:Male
  • Location:The Great White North

How do we read out all the battery information? System profiler shows most of that stuff, but no battery temperature for example.
Also, iStat Pro doesn't see the battery at all ("no battery present").
Again, many thanks gsly, for this great contribution!

iStat and several other tools I looked at do not see the battery as they are hard-coded to look at AppleSmartBatteryManager/AppleSmartBatteryDevice in the IORegistery. As this driver is based on the old Apple ACPI legacy code, the class names are different.

In theory, I should be able to resolve this by renaming the classes to match Apple's current driver. I may do this if I can figure out how to get Xcode's refactor to work (always greyed out when I tried it before)

#15
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 143 posts
  • Gender:Male
  • Location:The Great White North

How do we read out all the battery information? System profiler shows most of that stuff, but no battery temperature for example.
Also, iStat Pro doesn't see the battery at all ("no battery present").
Again, many thanks gsly, for this great contribution!


NIXin/JBraddock, I confirmed my suspicion about just renaming the class files to get some of the 3rd party software to work. XCode's refactoring is {censored} so I had to rename the classes and a LOT of other stuff in the project to enable me to build "AppleSmartBatteryManager" vs. "AppleACPIBatteryManager". After removing the latter and installing the former, I was able to see data in iStat (unhacked) and coconutBattery as you can see:

Attached File  Screen_shot_2011_08_05_at_4.17.25_PM.png   237.57KB   289 downloads

EDIT: Added compiled versions for the renamed driver in original post.

#16
NIXin

NIXin

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 116 posts
  • Gender:Male
  • Location:Krakow, Poland
neat! :) awaiting the 10.7 version then, and it will all be perfect :)

#17
BlackCH

BlackCH

    InsanelyMac Deity

  • Members
  • PipPipPipPipPipPipPipPipPipPip
  • 1,618 posts
  • Gender:Male
  • Location:BCN

Attached File  Screen_shot_2011_08_05_at_4.17.25_PM.png   237.57KB   289 downloads
EDIT: Added compiled versions for the renamed driver in original post.


Hi, thanks for this one!
It works good with iStat, like you said.

Im trying to use some of your code on my dsdt, but I have a different machine (HP 6720s) because in my opinion the original code is not quite right (wrong readings in OSX and windows). If you could share your DSDT so I can compare the different methods would be great. Also if you like to have a look to the bat0 code from my laptop, here it is:
Attached File  bat.dsl.zip   1.59KB   33 downloads

Thanks again!

#18
gsly

gsly

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 143 posts
  • Gender:Male
  • Location:The Great White North

Im trying to use some of your code on my dsdt, but I have a different machine (HP 6720s) because in my opinion the original code is not quite right (wrong readings in OSX and windows). If you could share your DSDT so I can compare the different methods would be great. Also if you like to have a look to the bat0 code from my laptop, here it is:
Attached File  bat.dsl.zip   1.59KB   33 downloads

Thanks again!

My DSDT methods are posted in #1 except for the SMBus access methods and those are standard and specific to my laptop. It looks like your laptop might use SMI/SMM to read the battery information rather than SMBus. I think you might be right about the original code having bugs as I commented what you posted and the C230 method that actually reads the battery status doesn't store the present rate read from the battery, but rather uses it to return a default value?
Device (EC)
----------------------------------------------------------------------

// Is battery installed?
//
// Arg0 = Battery to read?  (Always = 0x01)

Method (C22A, 1, Serialized)
{
	C229 (One)							  // Need to see C229 method!
	Store (C1CD (), Local0)				 // C1CD() = Read battery present/status? (Local0 = 0x00 = No, 0x01 = Yes)
	Store (0x0F, Local1)					// Default is no battery present (Bit 4 of _STA return)
	If (And (Local0, Arg0))				 // Is battery present?
	{
		Store (0x1F, Local1)				// Battery is present/available/etc
	}

	Return (Local1)						 // Return battery status
}

// Read Battery Status
//
// Arg0 = Battery to read?

Method (C230, 1, Serialized)
{
	ShiftLeft (One, Zero, Local7)		   // WTF?  Shifting 0x01 left 0x00 bits = 0x01 so why is this not: Store (One, Local7) !
	C229 (One)							  // Need to see C229 method!
	If (LEqual (C22A (Local7), 0x0F))	   // Is battery present?
	{
		Store (Package (0x04)			   // No, return dummy/default info
			{
				Zero, 
				Ones, 
				Ones, 
				Ones
			}, PBST)
		Return (0xFFFFFFFD)				 // Indicate error to caller
	}

	Acquire (C225, 0xFFFF)				  // Acquire exclusive lock
	If (Arg0)
	{
		Store (0xFF, C21C)				  // Trigger to read/update battery?
	}

	Store (C21C, Local0)					// Might be return status
	Release (C225)						  // Release lock
	If (LEqual (And (Local0, Local7), Zero))
	{
		Return (Zero)
	}

	Acquire (C1C8, 0xFFFF)				  // Exclusive lock
	If (ECOK)							   // If Embedded Controller enabled
	{
		Store (Zero, C1DE)				  // Need to see how this is used!
		Store (C1E7, Local0)				// C1E7 = PBST[0x00], Battery state
		Store (C1E8, Local3)				// C1E8 = PBST[0x01], Battery present rate
		Store (C1EA, Index (PBST, 0x02))	// C1EA = PBST[0x02], Battery remaining capacity
		Store (C1EC, Index (PBST, 0x03))	// C1EC = PBST[0x03], Battery present voltage
	}

	Release (C1C8)						  // release lock
	
	// Adjust battery state
	
	If (LEqual (C007 (), One))			  // C007() = Is AC connected?
	{
		And (0xFFFFFFFE, Local0, Local0)	// Flip Bit 0: Battery is discharging
	}
	Else
	{
		And (0xFFFFFFFD, Local0, Local0)	// Flip Bit 1: Battery is charging
	}

	If (And (Local0, One))				  // If battery discharging
	{
		Acquire (C225, 0xFFFF)			  // Exclusive access
		Store (Local7, C222)				// What is C222?  Indicator of "on-battery"?
		Release (C225)					  // 
	}

	// Write battery state
	
	Store (Local0, Index (PBST, Zero))	  // PBST[0x00], Battery state
	
	// Adjust present rate
	
	If (And (Local0, One))				  // If battery discharging
	{
		If (LOr (LLess (Local3, 0x0190), LGreater (Local3, 0x1964)))		// If PresentRate < 400 or PresentRate > 6500
		{
			Store (DerefOf (Index (PBST, One)), Local5)					 // Get previous PresentRate into Local5
			If (LOr (LLess (Local5, 0x0190), LGreater (Local5, 0x1964)))	// If PreviousRate < 400 or PreviousRate > 6500
			{
				Store (0x0D7A, Local3)									  // PresentRate = 3450
			}
			Else
			{
				Store (Local5, Local3)									  // Store PreviousRate in Local3?  WTF?
																			// PresentRate read above never stored/used? 
			}
		}
	}
	
	// Write adjusted rate
	
	Store (Local3, Index (PBST, One))	   // PBST[0x01], Battery present rate
	
	Acquire (C225, 0xFFFF)				  // Exclusive access
	And (C21C, Not (Local7), C21C)		  // C21C = On AC? (opposite of C222)
	Release (C225)						  // release
	Return (Zero)						   // No error to caller
}				

-----------------------------------------------------------------------				
				
Scope (\_SB)
{
	Name (PBIF, Package (0x0D)
		{
			One,		// mAh/mA units
			0x0A28,	 // 2600 mAh
			Ones,	   // Unknown last Full Charge capacity
			One,		// Battery technology, 0x01 = Secondary/Rechargable
			0x2a30,	 // 10800 mV = 10.8 V
			Zero, 
			Zero, 
			0x64, 
			0x64, 
			"Primary", 
			"100000", 
			"LIon", 
			"Hewlett-Packard"
		})
	Name (PBST, Package (0x04)
		{
			Zero,	   // No status
			Zero,	   // No present rate
			0xB010,	 // Remaining capacity = 45072 mAh
			0x40F2	  // Present voltage = 16626 mV
		})
	Name (C21E, One)	// ?
	Name (C21F, Zero)   // ?
	Name (C23E, 0x0F)   // Last battery device status (_STA)
	Name (C2B1, One)	// ?
	
	Device (BAT0) 
	{
		Name (_HID, EisaId ("PNP0C0A"))
		Name (_UID, One)
		Name (_PCL, Package (0x01)
		{
			_SB
		})
		
		// Return battery status
		//
		// Return Value:
		// An Integer containing a device status bitmap:
		// Bit 0 – Set if the device is present.
		// Bit 1 – Set if the device is enabled and decoding its resources.
		// Bit 2 – Set if the device should be shown in the UI.
		// Bit 3 – Set if the device is functioning properly (cleared if device failed its diagnostics).
		// Bit 4 – Set if the battery is present.
		// Bits 5–31 – Reserved (must be cleared).
		
		Method (_STA, 0, NotSerialized)
		{
			Store (^^PCI0.LPCB.EC.C22A (One), Local0)	   // Get status of battery one into Local0
			If (XOr (C23E, Local0))						 // Has battery status changed?
			{
				Store (Local0, C23E)						// Update last battery status
				Store (Local0, Local1)
				If (LNotEqual (Local1, 0x1F))			   // If battery not present/enabled/etc.
				{
					Store (Zero, Local1)
				}
				C1B2 (0xEA3A, Zero, Local1, Zero, Zero)	 // Need to see what this method does
			}
			Return (Local0)								 // Return battery status
		}

		// Return battery information
		
		Method (_BIF, 0, NotSerialized)
		{
			Store (^^PCI0.LPCB.EC.C22C (), Local0)		  // C22C() = Read battery information into Local0
			If (LEqual (Local0, 0xFFFFFFFD))				// If above returns error
			{
				Return (Package (0x0D)					  // Return dummy battery info
				{
					Zero, 
					Ones, 
					Ones, 
					One, 
					Ones, 
					Zero, 
					Zero, 
					Zero, 
					Zero, 
					"", 
					"", 
					"", 
					""
				})
			}
			Else
			{
				Return (PBIF)							   // Return battery info filled in by C22C()
			}
		}
		
		// Return battery information
		
		Method (_BST, 0, NotSerialized)
		{
			Store (C2B1, Local1)							// Get switch status
			If (C2B1)
			{
				Store (Zero, C2B1)						  // Flip the switch (does something else reset C2B1?)
			}
			Store (^^PCI0.LPCB.EC.C230 (Local1), Local0)	// C230() = Reads battery status into PBST
			
			// Above returns a status in Local0 that is never checked! Stupid code monkey...
			// 0x00 = No error
			// 0xFFFFFFFD = Error, no battery present
			
			Return (PBST)								   // Return battery status
		}
	}


#19
g53

g53

    InsanelyMac Protégé

  • Members
  • Pip
  • 1 posts
Hi gsly;

Here is the debug output with your new kext. I run both with true and false set none seems to do the trick.
I am also including my dsdt as it is today.

On Battery, it show 20:00 to discharge time left but 0% if I change time left to percentage

Once again thanks for your help
g53

Attached Files



#20
leanderK

leanderK

    InsanelyMac Protégé

  • Members
  • PipPip
  • 61 posts
I have a strange problem...It works for me with no slider, but after 10-30 minutes I loose connection, Then it shows that no battery is connected. Sometimes after another 10 minuter, but sometimes only seconds It recognizes it again.

Any solution?? :|





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

© 2014 InsanelyMac  |   News  |   Forum  |   Downloads  |   OSx86 Wiki  |   Mac Netbook  |   PHP hosting by CatN  |   Designed by Ed Gain  |   Logo by irfan  |   Privacy Policy