Go to page

Go to page

Moderator

Because the battery hardware in PCs is not compatible with Apple SMbus hardware, we use ACPI to access battery state when running OS X on laptops. Generally I recommend you use ACPIBatteryManager.kext, available here: https://github.com/RehabMan/OS-X-ACPI-Battery-Driver

Later releases of AppleACPIPlatform are unable to correctly access fields within the EC (embedded controller). This causes problems for ACPIBatteryManager as the various ACPI methods for battery fail (_BIF, _STA, _BST, etc). Although it is possible to use an older version of AppleACPIPlatform (from Snow Leopard), it is desirable to use the latest version of AppleACPIPlatform because with computers that have Ivy Bridge CPUs it enables native power management for those computers. To use the latest version, DSDT must be changed to comply with the limitations of Apple's AppleACPIPlatform.

In particular, any fields in the EC larger than 8-bit, must be changed to be accessed 8-bits at one time. This includes 16, 32, 64, and larger fields.

In order to match your DSDT with a patch, it is often necessary to understand how the patches are made in the first place, so you know what to look for in your DSDT and can match what you see with the patches already available. A patch set that has a high ratio of changes to patches, creates no errors, and appears to patch all fields that need to be patched is likely a match.

*** Note: Do not use DSDT Editor or any program other than MaciASL. I do not test my patches with DSDT Editor. I test only with MaciASL.

Other relevant DSDT patches

In addition to the multi-byte EC fields, there are a few other DSDT issues that can affect battery status. These particular problems are not specific to battery status, but they are usually noticed for the first time when trying to implement battery status.

The battery code may depend on having a recognized version of Windows as the host OS. To fix, apply "OS Check Fix" from the laptop DSDT patch repository. This will cause the DSDT to take the same actions as it would when running "Windows 2006" You can change the patch to effect different selections (eg. "Windows 2012".

Another common problem is the fact that OS X's ACPI implementation has difficulty with Mutex objects declared with a non-zero SyncLevel (for more info read the ACPI spec). To fix, apply "Fix Mutex with non-zero SyncLevel" from the laptop DSDT patch repository.

Skills Required

DSDT is a "program." As such, it is helpful to have some programming/computer skills when modifying it. Also, DSDT patches themselves have their own language (described briefly in the MaciASL wiki, available at here: http://sourceforge.net/projects/maciasl/). Finally, the patches themselves are basically scoped regular expression search/replace, so it is helpful to understand regular expressions (regex). Familiarity with compilers, compiler errors, and an ability to determine what the compiler is telling you about errors in the code is also useful.

It is not the purpose of this guide to teach you basic programming skills, regular expressions, or the ACPI language.

The patching process

I use a rather 'mechanical' process to patching DSDT for battery status. I simply look for the parts that OS X finds offensive and mechanically convert it. I don't try too hard to determine what sections of the code are actually going to execute, I just convert everything that I see.

To follow along, download the example DSDT from this post and follow along. This particular example DSDT is for an HP Envy 14. The final, complete patch, is available from my patch repo as "HP Envy 14."

First start by identifing the areas of the DSDT that are likely to need changes. Load the DSDT into MaciASL and search for 'EmbeddedControl'. There can be several 'EmbeddedControl' sections in a single DSDT, each with field declarations attached to it.

So, I always start out looking for 'embeddedcontrol' in order to find this declaration.

In the example DSDT, you will find this single EC region:

Code:

OperationRegion (ECF2, EmbeddedControl, Zero, 0xFF)

The above code defines a 255 byte EC region.

We know it is called ECF2, so now we want to search for 'Field (ECF2'. As you can see in the example DSDT, there is only one Field definition referring to this region. Sometimes there are many.

The Field definition describes a breakdown of that 255 byte EC region above. You can tell it is related because the name ECF2 is referred to by the Field. Think of this as a structure (struct for C programmers) into the EC.

The next step is to examine the items in the Field definition, looking for items which are larger than 8-bit. For example, the first field declared is BDN0, 56:

Code:

Field (ECF2, ByteAcc, Lock, Preserve)
{
Offset (0x10),
BDN0, 56,
...

It is a 56-bit field. Larger than 8-bit and if it is accessed in the DSDT, the code there will need edits as will the definition of this field. In the example DSDT, if you search the rest of the DSDT for "BDN0", you will find:

Code:

Store (BDN0, BDN)

This is intended to store the value at BDN0 (in the EC) into BDN. When fields larger than 32-bit are accessed, they are accessed as type Buffer. Fields 32-bit or under are accessed as Integers. This is important to realize as you change the code. Buffers are a bit more work to change. Also, realize this code is "reading" from the EC. Reads and writes must be handled differently.

So, for this particular line of code, the goal is to read this 56-bit field (7 bytes) 8-bits at time into a buffer, so the resulting buffer can be stored into BDN. We will get back to how this is accomplished later, for now let's explore the rest of the fields in this EC.

Looking through the rest of the the EC, we look for all fields larger than 8-bit, and for each one, search the rest of the DSDT to see if they are accessed. It is common that some fields are not accessed and for those we don't have to do anything. So, the next field we see is BMN0:

Code:

BMN0, 32,

If we search the DSDT for 'BMN0' we find only this declaration, so it is not accessed. We can ignore this one. Same with BMN4. BCT0, on the other hand, is 128 bit and is accessed, much like BDN0:

As you can see, there are quite a few fields in this DSDT that need work, and all of various sizes. 16-bit, 32-bit, 56-bit and 128-bit.

Fields sized 16-bit and 32-bit

Fields that are 16-bit and 32-bit are the easiest to deal with, so let's start there. Let's take for example, the first 16-bit field in the list above, BDC0. What we want to do is change this field so it is broken into two peices (low-byte, high-byte). To do that we need to come up with a 4-character name that does not conflict with any other names in the DSDT. It is often easy to remove the first letter and use the following three.

That patch says, look at the code in a device with label H_EC, search for "BDC0,<spaces>16," and replace it with "DC00,8,DC01,8," This effectively breaks the field into two parts. If you apply this patch, and attempt to compile the modified DSDT, you will get errors because the code is still accessing BDC0. These errors actually help us identify what code needs to change:

Such optimizations can only be made by using your brain, and generally it is not worth it. The goal here is to come up with an automated method of fixing this code and not to attempt to use our brain too much as we could introduce bugs into the code if we change it too drastically. Also, this kind of code is rare (I have only seen it only in two DSDTs out of more than 20 that I've written patches for).

Now that you understand how to deal with 16-bit registers, it is probably easiest to just convert all of them. Here is the comprehensive patch for the 16-bit EC fields:

Next we need to determine the offsets within the EC that these fields are placed. Keep in mind the sizes are in bits, but the offsets are in bytes. The offsets I have in the comments below are in hex. See if you can come up with the same numbers.

"RECB" stands for "Read EC Buffer". It takes two parameters indicating the offset within the EC and the size in bits of the field you wish to read. The size in bits must be a multiple of eight (8). The code does not check.

These helper methods must be defined in the EC device, in the case of this DSDT, named H_EC:

Code:

Device (H_EC)
{
Name (_HID, EisaId ("PNP0C09"))

You will need to change the patches that create RECB/RE1B if the name of your EC device is different. Common names are EC, EC0, and as in this example H_EC.

To handle the first case of BCT0, we want to do the equivalent of this:

Code:

Store(RECB(0x30,128), CTN)

The 0x30 is the offset of the BTC0 field (now called BCTX) and the 128 is the number of bits.

In this case, the BCT0 access cannot be replaced with a call to RECB. It is a write, not a read. WECB must be used instead.

Code:

WECB(0x30,128, Local0)

The first two parameters to WECB are the same as those to RECB (offset and size of the EC field). The third parameter (Arg2) is the value that should be written to the EC field. In this case it is the original source of the Store (the first parameter to Store)... Local0.

Store is not the only AML opcode that can write. Just as Store is not the only AML opcode that can read. Just as an example, consider Add:

Code:

Add(X, Y, Z)

The example above reads from X, reads from Y, performs an addition... and writes the result to Z.

When you're not sure what an AML opcode does, read the ACPI spec. It is fully documented there, but outside the scope of this post.

The existing laptop repo is a good source of example and information. There are numerous WECB/RECB examples in the existing patches in the laptop repo.

Logic bug with charging/discharging status (AC adapter detection)

Some DSDTs suffer from a logic bug where at the point of 100% capacity (fully charged battery), an incorrect status is returned from _BST. This mostly affects certain ASUS laptops, but also a few others.

Also, post EFI/Clover folder as ZIP (press F4 at main Clover screen before collecting). Please eliminate 'themes' directory, especially if you have an overabundance of themes installed. Provide only EFI/Clover, not the entire EFI folder.

Also post output of:

Code:

sudo touch /System/Library/Extensions && sudo kextcache -u /

Compress all files as ZIP. Do not use external links. Attach all files using site attachments only.

Contributing

If you do come up with a patch for your battery methods, you are encouraged to contribute to my patch repository, so please share your patch along with information about your computer, so I can add the patch to my laptop DSDT patch repository. Please provide both the text file containing the patches and the native DSDT (so I'm able to review the patches against the native DSDT). I will not add patches to the repository unless I can review the patches as they apply to the native DSDT.

In the example, mine differs from the one you wrote... Now as I've said before, I'm no programmer. However, I'm going to attempt this, and maybe search for some courses in this programming language if it's completely necessary.

The example shows:

OperationRegion (ECF2, EmbeddedControl, Zero, 0xFF)

Mine shows:

OperationRegion (ECMM, EmbeddedControl, Zero, 0X0100)

Should I just continue? Does this matter? I'm not sure if it will change things. This is the only location that "EmbeddedControl" shows up when I do a search through my dsdt.aml file.

I've also noticed that in your guide, all the 4-character lines end in #s (i.e. BCT0, BDN1, etc). Mine are mostly all letters, and the only ones with #s have the # in the second place (i.e. B0ST, B0CC).

Moderator

In the example, mine differs from the one you wrote... Now as I've said before, I'm no programmer. However, I'm going to attempt this, and maybe search for some courses in this programming language if it's completely necessary.

The example shows:

OperationRegion (ECF2, EmbeddedControl, Zero, 0xFF)

Mine shows:

OperationRegion (ECMM, EmbeddedControl, Zero, 0X0100)

Should I just continue? Does this matter? I'm not sure if it will change things. This is the only location that "EmbeddedControl" shows up when I do a search through my dsdt.aml file.

I've also noticed that in your guide, all the 4-character lines end in #s (i.e. BCT0, BDN1, etc). Mine are mostly all letters, and the only ones with #s have the # in the second place (i.e. B0ST, B0CC).

Moderator

I've also noticed that in your guide, all the 4-character lines end in #s (i.e. BCT0, BDN1, etc). Mine are mostly all letters, and the only ones with #s have the # in the second place (i.e. B0ST, B0CC).