// SSDT-BATC.dsl
//
// Based on https://github.com/RehabMan/OS-X-ACPI-Battery-Driver/blob/master/SSDT-BATC.dsl
//
// An SSDT to combine two batteries into one
// initial work/testing by ag6952563 (with assistance by RehabMan)
// finalize into generic SSDT by RehabMan
// some code cleanup/optimization/and bug fixing by RehabMan
// modifications to work VirtualSMC SMCBatteryManager by armenio
// add _BIX (easy, following the original code from RehabMan) by armenio
//
// OS X support for multiple batteries is a bit buggy.
// This SSDT can be used to combine two batteries into one,
// avoiding the bugs.
//
// It may need modification depending on the ACPI path of your
// existing battery objects.
//

// IMPORTANT:
//
// To use this SSDT, you must also patch any Notify for either BAT0 or BAT1
// objects.
//
// The Notify is used to tell the system when a battery is removed or added.
//
// Any code:
//   Notify (...BAT0, ...)
//         -or
//   Notify (...BAT1, ...)
//
// Must be changed to:
//   Notify (...BATC, ...)
//
// Refer to Dual Battery Support.md for patching details
//

DefinitionBlock ("", "SSDT", 2, "ACDT", "BATC", 0x00000000)
{
    External (_SB_.PCI0.LPCB.EC, DeviceObj)
    External (_SB_.PCI0.LPCB.EC.BAT0, DeviceObj)
    External (_SB_.PCI0.LPCB.EC.BAT0._BIF, MethodObj)
    External (_SB_.PCI0.LPCB.EC.BAT0._BIX, MethodObj)
    External (_SB_.PCI0.LPCB.EC.BAT0._BST, MethodObj)
    External (_SB_.PCI0.LPCB.EC.BAT0._HID, IntObj)
    External (_SB_.PCI0.LPCB.EC.BAT0._STA, MethodObj)
    External (_SB_.PCI0.LPCB.EC.BAT1, DeviceObj)
    External (_SB_.PCI0.LPCB.EC.BAT1._BIF, MethodObj)
    External (_SB_.PCI0.LPCB.EC.BAT1._BIX, MethodObj)
    External (_SB_.PCI0.LPCB.EC.BAT1._BST, MethodObj)
    External (_SB_.PCI0.LPCB.EC.BAT1._HID, IntObj)
    External (_SB_.PCI0.LPCB.EC.BAT1._STA, MethodObj)

    Scope (\_SB.PCI0.LPCB.EC)
    {
        Device (BATC)
        {
            Name (_HID, EisaId ("PNP0C0A"))
            Name (_UID, 0x02)

            Method (_INI)
            {
                If (_OSI ("Darwin"))
                {
                    // disable original battery objects by setting invalid _HID
                    ^^BAT0._HID = 0
                    ^^BAT1._HID = 0
                }
            }

            Method (_STA)
            {
                If (_OSI ("Darwin"))
                {
                    // call original _STA for BAT0 and BAT1
                    // result is bitwise OR between them
                    Return (^^BAT0._STA () | ^^BAT1._STA ())
                }
                Else
                {
                    Return (Zero)
                }
            }

            Method (_BIF)
            {
                // Local0 BAT0._BIF
                // Local1 BAT1._BIF
                // Local2 BAT0._STA
                // Local3 BAT1._STA
                // Local4/Local5 scratch

                // gather and validate data from BAT0
                Local0 = ^^BAT0._BIF ()
                Local2 = ^^BAT0._STA ()
                If (0x1f == Local2)
                {
                    // check for invalid design capacity
                    Local4 = DerefOf (Local0 [1])
                    If (!Local4 || Ones == Local4) { Local2 = 0; }
                    // check for invalid last full charge capacity
                    Local4 = DerefOf (Local0 [2])
                    If (!Local4 || Ones == Local4) { Local2 = 0; }
                    // check for invalid design voltage
                    Local4 = DerefOf (Local0 [4])
                    If (!Local4 || Ones == Local4) { Local2 = 0; }
                }
                // gather and validate data from BAT1
                Local1 = ^^BAT1._BIF ()
                Local3 = ^^BAT1._STA ()
                If (0x1f == Local3)
                {
                    // check for invalid design capacity
                    Local4 = DerefOf (Local1 [1])
                    If (!Local4 || Ones == Local4) { Local3 = 0; }
                    // check for invalid last full charge capacity
                    Local4 = DerefOf (Local1 [2])
                    If (!Local4 || Ones == Local4) { Local3 = 0; }
                    // check for invalid design voltage
                    Local4 = DerefOf (Local1 [4])
                    If (!Local4 || Ones == Local4) { Local3 = 0; }
                }
                // find primary and secondary battery
                If (0x1f != Local2 && 0x1f == Local3)
                {
                    // make primary use BAT1 data
                    Local0 = Local1 // BAT1._BIF result
                    Local2 = Local3 // BAT1._STA result
                    Local3 = 0  // no secondary battery
                }
                // combine batteries into Local0 result if possible
                If (0x1f == Local2 && 0x1f == Local3)
                {
                    // _BIF 0 Power Unit - leave BAT0 value
                    // _BIF 1 Design Capacity - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [1])
                    Local5 = DerefOf (Local1 [1])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [1] = Local4 + Local5
                    }
                    // _BIF 2 Last Full Charge Capacity - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [2])
                    Local5 = DerefOf (Local1 [2])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [2] = Local4 + Local5
                    }
                    // _BIF 3 Battery Technology - leave BAT0 value
                    // _BIF 4 Design Voltage - average between BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [4])
                    Local5 = DerefOf (Local1 [4])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [4] = (Local4 + Local5) / 2
                    }
                    // _BIF 5 Design Capacity of Warning - add BAT0 and BAT1 values
                    Local0 [5] = DerefOf (Local0 [5]) + DerefOf (Local1 [5])
                    // _BIF 6 Design Capacity of Low - add BAT0 and BAT1 values
                    Local0 [6] = DerefOf (Local0 [6]) + DerefOf (Local1 [6])
                    // _BIF 7 Battery Capacity Granularity 1 - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [7])
                    Local5 = DerefOf (Local1 [7])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [7] = Local4 + Local5
                    }
                    // _BIF 8 Battery Capacity Granularity 2 - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [8])
                    Local5 = DerefOf (Local1 [8])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [8] = Local4 + Local5
                    }
                    // _BIF 9 Model Number - concatenate BAT0 and BAT1 values
                    Local0 [0x09] = Concatenate (Concatenate (DerefOf (Local0 [0x09]), " / "), DerefOf (Local1 [0x09]))
                    // _BIF a Serial Number - concatenate BAT0 and BAT1 values
                    Local0 [0x0a] = Concatenate (Concatenate (DerefOf (Local0 [0x0a]), " / "), DerefOf (Local1 [0x0a]))
                    // _BIF b Battery Type - concatenate BAT0 and BAT1 values
                    Local0 [0x0b] = Concatenate (Concatenate (DerefOf (Local0 [0x0b]), " / "), DerefOf (Local1 [0x0b]))
                    // _BIF c OEM Information - concatenate BAT0 and BAT1 values
                    Local0 [0x0c] = Concatenate (Concatenate (DerefOf (Local0 [0x0c]), " / "), DerefOf (Local1 [0x0c]))
                }

                Return (Local0)
            } // _BIF

            Method (_BIX)
            {
                // Local0 BAT0._BIX
                // Local1 BAT1._BIX
                // Local2 BAT0._STA
                // Local3 BAT1._STA
                // Local4/Local5 scratch

                // gather and validate data from BAT0
                Local0 = ^^BAT0._BIX ()
                Local2 = ^^BAT0._STA ()
                If (0x1f == Local2)
                {
                    // check for invalid design capacity
                    Local4 = DerefOf (Local0 [2])
                    If (!Local4 || Ones == Local4) { Local2 = 0; }
                    // check for invalid last full charge capacity
                    Local4 = DerefOf (Local0 [3])
                    If (!Local4 || Ones == Local4) { Local2 = 0; }
                    // check for invalid design voltage
                    Local4 = DerefOf (Local0 [5])
                    If (!Local4 || Ones == Local4) { Local2 = 0; }
                }
                // gather and validate data from BAT1
                Local1 = ^^BAT1._BIX ()
                Local3 = ^^BAT1._STA ()
                If (0x1f == Local3)
                {
                    // check for invalid design capacity
                    Local4 = DerefOf (Local1 [2])
                    If (!Local4 || Ones == Local4) { Local3 = 0; }
                    // check for invalid last full charge capacity
                    Local4 = DerefOf (Local1 [3])
                    If (!Local4 || Ones == Local4) { Local3 = 0; }
                    // check for invalid design voltage
                    Local4 = DerefOf (Local1 [5])
                    If (!Local4 || Ones == Local4) { Local3 = 0; }
                }
                // find primary and secondary battery
                If (0x1f != Local2 && 0x1f == Local3)
                {
                    // make primary use BAT1 data
                    Local0 = Local1 // BAT1._BIX result
                    Local2 = Local3 // BAT1._STA result
                    Local3 = 0  // no secondary battery
                }
                // combine batteries into Local0 result if possible
                If (0x1f == Local2 && 0x1f == Local3)
                {
                    // _BIX 0 Revision - leave BAT0 value
                    // _BIX 1 Power Unit - leave BAT0 value
                    // _BIX 2 Design Capacity - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [2])
                    Local5 = DerefOf (Local1 [2])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [2] = Local4 + Local5
                    }
                    // _BIX 3 Last Full Charge Capacity - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [3])
                    Local5 = DerefOf (Local1 [3])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [3] = Local4 + Local5
                    }
                    // _BIX 4 Battery Technology - leave BAT0 value
                    // _BIX 5 Design Voltage - average between BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [5])
                    Local5 = DerefOf (Local1 [5])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [5] = (Local4 + Local5) / 2
                    }
                    // _BIX 6 Design Capacity of Warning - add BAT0 and BAT1 values
                    Local0 [6] = DerefOf (Local0 [6]) + DerefOf (Local1 [6])
                    // _BIX 7 Design Capacity of Low - add BAT0 and BAT1 values
                    Local0 [7] = DerefOf (Local0 [7]) + DerefOf (Local1 [7])
                    // _BIX 8 Cycle Count - average between BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [8])
                    Local5 = DerefOf (Local1 [8])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [8] = (Local4 + Local5) / 2
                    }
                    // _BIX 9 Measurement Accuracy - average between BAT0 and BAT1 values
                    Local0 [9] = (DerefOf (Local0 [9]) + DerefOf (Local1 [9])) / 2
                    // _BIX 0xa Max Sampling Time - average between BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [0xa])
                    Local5 = DerefOf (Local1 [0xa])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [0xa] = (Local4 + Local5) / 2
                    }
                    // _BIX 0xb Min Sampling Time - average between BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [0xb])
                    Local5 = DerefOf (Local1 [0xb])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [0xb] = (Local4 + Local5) / 2
                    }
                    // _BIX 0xc Max Averaging Interval - average between BAT0 and BAT1 values
                    Local0 [0xc] = (DerefOf (Local0 [0xc]) + DerefOf (Local1 [0xc])) / 2
                    // _BIX 0xd Min Averaging Interval - average between BAT0 and BAT1 values
                    Local0 [0xd] = (DerefOf (Local0 [0xd]) + DerefOf (Local1 [0xd])) / 2
                    // _BIX 0xe Battery Capacity Granularity 1 - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [0xe])
                    Local5 = DerefOf (Local1 [0xe])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [0xe] = Local4 + Local5
                    }
                    // _BIX 0xf Battery Capacity Granularity 2 - add BAT0 and BAT1 values
                    Local4 = DerefOf (Local0 [0xf])
                    Local5 = DerefOf (Local1 [0xf])
                    If (0xffffffff != Local4 && 0xffffffff != Local5)
                    {
                        Local0 [0xf] = Local4 + Local5
                    }
                    // _BIX 10 Model Number - concatenate BAT0 and BAT1 values
                    Local0 [0x10] = Concatenate (Concatenate (DerefOf (Local0 [0x10]), " / "), DerefOf (Local1 [0x10]))
                    // _BIX 11 Serial Number - concatenate BAT0 and BAT1 values
                    Local0 [0x11] = Concatenate (Concatenate (DerefOf (Local0 [0x11]), " / "), DerefOf (Local1 [0x11]))
                    // _BIX 12 Battery Type - concatenate BAT0 and BAT1 values
                    Local0 [0x12] = Concatenate (Concatenate (DerefOf (Local0 [0x12]), " / "), DerefOf (Local1 [0x12]))
                    // _BIX 13 OEM Information - concatenate BAT0 and BAT1 values
                    Local0 [0x13] = Concatenate (Concatenate (DerefOf (Local0 [0x13]), " / "), DerefOf (Local1 [0x13]))
                    // _BIX 14 Battery Swapping Capability - leave BAT0 value for now
                }
                Return (Local0)
            } // _BIX

            Method (_BST)
            {
                // Local0 BAT0._BST
                // Local1 BAT1._BST
                // Local2 BAT0._STA
                // Local3 BAT1._STA
                // Local4/Local5 scratch

                // gather battery data from BAT0
                Local0 = ^^BAT0._BST ()
                Local2 = ^^BAT0._STA ()
                If (0x1f == Local2)
                {
                    // check for invalid remaining capacity
                    Local4 = DerefOf (Local0 [2])
                    If (!Local4 || Ones == Local4) { Local2 = 0; }
                }
                // gather battery data from BAT1
                Local1 = ^^BAT1._BST ()
                Local3 = ^^BAT1._STA ()
                If (0x1f == Local3)
                {
                    // check for invalid remaining capacity
                    Local4 = DerefOf (Local1 [2])
                    If (!Local4 || Ones == Local4) { Local3 = 0; }
                }
                // find primary and secondary battery
                If (0x1f != Local2 && 0x1f == Local3)
                {
                    // make primary use BAT1 data
                    Local0 = Local1 // BAT1._BST result
                    Local2 = Local3 // BAT1._STA result
                    Local3 = 0  // no secondary battery
                }
                // combine batteries into Local0 result if possible
                If (0x1f == Local2 && 0x1f == Local3)
                {
                    // _BST 0 - Battery State - if one battery is charging, then charging, else discharging
                    Local4 = DerefOf (Local0 [0])
                    Local5 = DerefOf (Local1 [0])
                    If (Local4 != Local5)
                    {
                        If (Local4 == 2 || Local5 == 2)
                        {
                            // 2 = charging
                            Local0 [0] = 2
                        }
                        ElseIf (Local4 == 1 || Local5 == 1)
                        {
                            // 1 = discharging
                            Local0 [0] = 1
                        }
                        ElseIf (Local4 == 3 || Local5 == 3)
                        {
                            Local0 [0] = 3
                        }
                        ElseIf (Local4 == 4 || Local5 == 4)
                        {
                            // critical
                            Local0 [0] = 4
                        }
                        ElseIf (Local4 == 5 || Local5 == 5)
                        {
                            // critical and discharging
                            Local0 [0] = 5
                        }
                        // if none of the above, just leave as BAT0 is
                    }

                    // _BST 1 - Battery Present Rate - add BAT0 and BAT1 values
                    Local0 [1] = DerefOf (Local0 [1]) + DerefOf (Local1 [1])
                    // _BST 2 - Battery Remaining Capacity - add BAT0 and BAT1 values
                    Local0 [2] = DerefOf (Local0 [2]) + DerefOf (Local1 [2])
                    // _BST 3 - Battery Present Voltage - average between BAT0 and BAT1 values
                    Local0 [3] = (DerefOf (Local0 [3]) + DerefOf (Local1 [3])) / 2
                }
                Return (Local0)
            } // _BST
        } // BATC
    } // Scope (...)
}
//EOF