Jump to content

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


gsly
 Share

229 posts in this topic

Recommended Posts

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 

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.

 

AppleACPIBatteryManager_20110802_release.zip

AppleACPIBatteryManager_20110802_debug.zip

 

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.

 

AppleSmartBatteryManager_20110802_release.zip

AppleSmartBatteryManager_20110802_debug.zip

 

Source code: https://github.com/gsly/OS-X-ACPI-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.

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

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 ^^

Link to comment
Share on other sites

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 :)

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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.insanelymac.com/forum/index.php...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.

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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)

Link to comment
Share on other sites

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:

 

post-60978-1312586734_thumb.png

 

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

Link to comment
Share on other sites

post-60978-1312586734_thumb.png

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:

bat.dsl.zip

 

Thanks again!

Link to comment
Share on other sites

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:

bat.dsl.zip

 

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
	}
}

Link to comment
Share on other sites

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?? :|

Link to comment
Share on other sites

hi gsly bcc9 post dsdt solution for lion.

i try to use it but i can not figure out. plz can you check it

http://www.insanelymac.com/forum/index.php...p;#entry1737541

I have seen his post and I've been doing some testing related to this as well as looking into the changes in AppleACPIPlatform that cause this. Nothing significant to report yet.

Link to comment
Share on other sites

Hi gsly,

finally found time to test your kext with all DSDT code you posted on my dv9000 machine, everything works very nicely, thank you very much for all your work and sharing.

For some reason coconut battery ver. 2.7 doesn't work for me, ver 2.6.6 works fine, but I'm not really bothered as I'm not using this program anyway.

More important for me would be if your kext could have ability to put computer to sleep on low battery: for example on 5% battery level while is on battery power would tell to system (terminal command):

osascript -e 'tell application "System Events" to sleep'

possible ?

Thanks again

swavek

 

EDIT: AppleSmartBatteryManager.kext solved coconut 2.7 and iStat battery info issue

EDIT2: BatteryMon.app by KWS here does the job for me.

Link to comment
Share on other sites

Very good job, congrats! :(

 

I have some ideas how to bypass Lion ACPI EC SMBus stuff, we might need to implement a fake SMB0 device and put there the SMRD method as Apple does with the hope it will not block it...

AFAIK I can test only on Lion DP1, dunno how diff is ACPIPlatform b/w DP1 and GM.

 

L.E. Tested and is not/will not work ever on Lion.

I even tested latest apple code from mbair and it prints same errors when debug=0xffff, so the code is still there for other OS but not Lion.

Only thing they care is to find the SMB0 device with 0x0f status, rest is driver job...

 

It is a very good solution for Snow but that's it, as far I can see Apple will not allow anything on SMBus within ACPI, or they rushed things, or the plan was to break it.

 

So, that return us to the original driver fix, :)

Link to comment
Share on other sites

Hi I tried you next and now it show in system info but although it show time left of batteryon menu it shows 0% left

 

this is system info

 

Battery Information:

 

Model Information:

Serial Number: Unknown-Unknown

Charge Information:

Charge Remaining (mAh): 2960

Fully Charged: No

Charging: No

Full Charge Capacity (mAh): 0

Health Information:

Cycle Count: 0

Condition: Normal

Battery Installed: Yes

Amperage (mA): -1712

Voltage (mV): 10838

 

System Power Settings:

 

AC Power:

System Sleep Timer (Minutes): 0

Disk Sleep Timer (Minutes): 0

Display Sleep Timer (Minutes): 24

Automatic Restart on Power Loss: Yes

Wake on Clamshell Open: Yes

Wake on LAN: Yes

Display Sleep Uses Dim: Yes

PrioritizeNetworkReachabilityOverSleep: 0

RestartAfterKernelPanic: 157680000

Battery Power:

System Sleep Timer (Minutes): 10

Disk Sleep Timer (Minutes): 0

Display Sleep Timer (Minutes): 10

Wake on Clamshell Open: Yes

Current Power Source: Yes

Display Sleep Uses Dim: Yes

Reduce Brightness: Yes

RestartAfterKernelPanic: 157680000

 

Hardware Configuration:

 

UPS Installed: No

 

AC Charger Information:

 

Connected: No

Charging: No

 

where should Iput the fix in my dsdt????

 

 

I tried a few time with your fix and bbc9 ones but I get error all the time

At least is an improvement getting info in system profiler ;)

 

An update change kext infoplist to false now showing percentage but lost system info

 

At least coconut and istat show battery info

Link to comment
Share on other sites

 Share

×
×
  • Create New...