// ACPI nhcMethod Source Code
//
// NHC allows you to add one or more new ACPI methods to the operating system.
// With this powerful capacity of NHC you can add new or missing features to the operating system ACPI.
//
// Note: To test the nhcMethods please use the NHC ACPI Object Explorer.
//       To use and call the nhcMethods please use the NHC ACPI Control System.
//
// Info: Please add the source code only inside a method. Source code outside a method will be ignored.
//       To use acpi objects from the system acpi it is necessary to define it first with the External() keyword.


Method (SMCR, 2, NotSerialized)                 // Read data from the Apple System Management Controller (SMC)
{                                               // ===========================================================
                                                // Arg0 = Apple SMC Key
                                                // Arg1 = Data Length (1 to 4)
                                                // ---------------------------
                                                // Result0 = result status (0 = OK)
                                                // Result1 = result value

   
// 0. Definition for the I/O Port access of the Apple SMC
    //
    OperationRegion(SMCF, SystemIO, 0x300, 0x01)
   
Field(SMCF, ByteAcc, NoLock, Preserve)
   
{
        SMCD
, 8,                                // Data Port used by Apple SMC
    }

   
// 1. Definition of the result package
    //
    Name (RES_, Package (0x02)
   
{
       
0xFFFFFFFF,                             // result status (-1) -> 0 = OK
        0x00                                    // result value
    })

   
// 2. Send the read command to the SMC
    //
    Store(WCMD(0x10), Local0)                   // send read command (0x10) to the SMC
    If(LEqual(Local0, 1))                       // check status
    {
       
Store (0xFFFFFFFE, Index (RES_, 0))     // set ERROR ID (-2)
        Return (RES_)                           // ERROR -> send read command
    }

   
// 3. Send the Apple SMC Key
    //
    Store(0, Local5)                            // init loop
    While(LLess(Local5, 4))                     // loop 4 times (0 to 3)
    {
       
Multiply(Local5, 8, Local1)             // actual shift amount (0, 8, 16, 24)
        ShiftRight(Arg0, Local1, Local0)        // get the actual byte to send
        Store(Local0, SMCD)                     // send the key byte to the SMC Data Port
        If(LEqual(WSTA(0x04), 1))               // wait until the SMC Command Port is ready
        {
           
Store (0xFFFFFFFD, Index (RES_, 0)) // set ERROR ID (-3)
            Return (RES_)                       // ERROR -> send the Key
        }
       
Increment(Local5)                       // set to the next byte position
    }

   
// 4. Send the data length to the SMC
    //
    Store(Arg1, SMCD)                           // send the data length to read to the SMC Data Port

   
// 5. Read the data from SMC
    //
    Store(0, Local1)                            // Init result
    Store(0, Local5)                            // Init loop
    While(LLess(Local5, Arg1))                  // loop "data length" times
    {
       
If(LEqual(WSTA(0x05), 1))               // wait until the SMC Command Port is ready
        {
           
Store (0xFFFFFFFC, Index (RES_, 0)) // Set ERROR ID (-4)
            Return (RES_)                       // ERROR -> send the Key
        }
       
Store(SMCD, Local0)                     // receive data byte
        Multiply(Local5, 8, Local6)             // actual shift amount (0, 8, 16, 24)
        ShiftLeft(Local0, Local6, Local0)       // move the data byte to the right bit position in the result register
        Or(Local0, Local1, Local1)              // add data byte to the result register
        Increment(Local5)                       // set to the next byte position
    }

   
// 6. Return the package
    //
    Store (0, Index (RES_, 0))                  // set OK status
    Store (Local1, Index (RES_, 1))             // set result value
    Return (RES_)                               // return result
}

Method (SMCW, 3, NotSerialized)                 // Write data to the Apple System Management Controller (SMC)
{                                               // ==========================================================
                                                // Arg0 = Apple SMC Key
                                                // Arg1 = Data to write
                                                // Arg2 = Data Length (1 to 4)
                                                // ---------------------------
                                                // Result0 = result status (0 = OK)

   
// 0. Definition for the I/O Port access of the Apple SMC
    //
    OperationRegion(SMCF, SystemIO, 0x300, 0x01)
   
Field(SMCF, ByteAcc, NoLock, Preserve)
   
{
        SMCD
, 8,                                // Data Port used by Apple SMC
    }

   
// 1. Send the write command to the SMC
    //
    Store(WCMD(0x11), Local0)                   // send write command (0x11) to the SMC
    If(LEqual(Local0, 1))                       // check status
    {
       
Return (0xFFFFFFFE)                     // ERROR -> send write command (-2)
    }

   
// 2. Send the Apple SMC Key
    //
    Store(0, Local5)                            // init loop
    While(LLess(Local5, 4))                     // loop 4 times
    {
       
Multiply(Local5, 8, Local1)             // actual shift amount (0, 8, 16, 24)
        ShiftRight(Arg0, Local1, Local0)        // get the actual byte to send
        Store(Local0, SMCD)                     // send the key byte to the SMC Data Port
        If(LEqual(WSTA(0x04), 1))               // wait until the SMC Command Port is ready
        {
           
Return (0xFFFFFFFD)                 // ERROR -> send the Key (-3)
        }
        
Increment(Local5)                       // set to the next byte position
    }

   
// 3. Send the data length to the SMC
    //
    Store(Arg2, SMCD)                           // send the data length to write to the SMC Data Port

   
// 4. Write the data to the SMC
    //
    Store(0, Local1)                            // init result
    Store(0, Local5)                            // init loop
    While(LLess(Local5, Arg2))                  // loop "data length" times
    {
       
If(LEqual(WSTA(0x04), 1))               // wait until the SMC Command Port is ready
        {
           
Return (0xFFFFFFFC)                 // ERROR - Read Data (-4)
        }
       
Multiply(Local5, 8, Local6)             // actual shift amount (0, 8, 16, 24)
        ShiftRight(Arg1, Local6, Local0)        // extract the data byte with the right bit position from Arg1
        Store(Local0, SMCD)                     // send data byte
        Increment(Local5)                       // set to the next byte position
    }
   
Return (0)                                  // Return Status OK (write success)
}

Method (WCMD, 1, NotSerialized)                 // Send command to the SMC and wait for the ready status
{                                               // =====================================================
                                                // Arg0 = Command to send

   
// Definition for the I/O Port access of the Apple SMC
    //
    OperationRegion(SMCF, SystemIO, 0x304, 0x01)
   
Field(SMCF, ByteAcc, NoLock, Preserve)
   
{
        SMCC
, 8                                 // Command/Status Port used by Apple SMC
    }

   
// Special treatment of command port - on newer macbooks, it seems necessary
    // to resend the command byte before polling the status again.
    //
    Store(0x40, Local5)                         // start/minimum wait time = 64us (APPLESMC_MIN_WAIT = 0x40)
    While(LLess(Local5, 0x8000))                // wait up to 32ms for the status port (APPLESMC_MAX_WAIT = 0x8000)
    {
       
Store(Arg0, SMCC)                       // send/resend read command to the SMC
        WSMC(Local5)                            // wait (64us or more)
        Store(SMCC, Local0)                     // read SMC command port status
        And(Local0, 0x0F, Local0)               // mask port status value
        If(LEqual(Local0, 0x0C))                // check SMC command port status
        {
           
Return (0)                          // status received (masked with 0x0f) - terminate loop
        }
       
Else
       
{
           
ShiftLeft(Local5, 1, Local5)        // increment wait time
        }
   
}
   
Return (1)                                  // ERROR - TIME OUT
}

Method (WSTA, 1, NotSerialized)                 // Wait Status - wait for the status port to get a certain value
{                                               // =============================================================
                                                // Arg0 = Status

   
// Definition for the I/O Port access of the Apple SMC
    //
    OperationRegion(SMCF, SystemIO, 0x304, 0x01)
   
Field(SMCF, ByteAcc, NoLock, Preserve)
   
{
        SMCC
, 8                                 // Command/Status Port used by Apple SMC
    }

   
// Wait up to 32ms for the status port to get a certain value
    // (masked with 0x0f), returning zero if the value is obtained.
    //
    And(Arg0, 0x0F, Arg0)                       // mask value
    Store(0x40, Local5)                         // start/minimum wait time = 64us (APPLESMC_MIN_WAIT = 0x40)
    While(LLess(Local5, 0x8000))
   
{
        WSMC
(Local5)                            // wait (64us or more)
        Store(SMCC, Local0)                     // read SMC command port status
        And(Local0, 0x0F, Local0)               // mask port status value
        If(LEqual(Local0, Arg0))                // check SMC command port status
        {
           
Return (0)                          // status received (masked with 0x0f) - terminate loop
        }
       
Else
       
{
           
ShiftLeft(Local5, 1, Local5)        // increment wait time
        }
   
}
   
Return (1)                                  // ERROR - TIME OUT
}

Method (WSMC, 1, NotSerialized)                 // Wait for SMC - delay method for the SMC access
{                                               // ================================================
                                                // Arg0 = delay time in microseconds

   
// For very short delays (1 to 100 microseconds) we must use Stall.
    // The resolution of sleep is not accurate enought. For delays longer than 100 microseconds we must use Sleep.
    //
    If(LLessEqual(Arg0, 100))
   
{
       
Stall(Arg0)                             // usec delay
    }
   
Else
   
{
       
Divide(Arg0, 100, Local1, Local0)       // split the delay time
        While(LGreater(Local0, 0))
       
{
           
Stall(100)                          // usec delay
            Decrement(Local0)
       
}
       
Stall(Local1)                           // consider also the remainder of the division
    }
}

Method (SR16, 1, NotSerialized)                 // Read text from the Apple System Management Controller (SMC)
{                                               // ===========================================================
                                                // Arg0 = Apple SMC Key
                                                // ---------------------------
                                                // Result0 = result status (0 = OK)
                                                // Result1 - Result4 = text (char[16])

   
// 0. Definition for the I/O Port access of the Apple SMC
    //
    OperationRegion(SMCF, SystemIO, 0x300, 0x01)
   
Field(SMCF, ByteAcc, NoLock, Preserve)
   
{
        SMCD
, 8,                                // Data Port used by Apple SMC
    }

   
// 1. Definition of the result package
    //
    Name (RES_, Package (0x5)
   
{
       
0xFFFFFFFF,                             // result status (-1) -> 0 = OK
        0x00000000,                             // result byte 1-4
        0x00000000,                             // result byte 5-8
        0x00000000,                             // result byte 9-12
        0x00000000,                             // result byte 13-16
    })

   
// 2. Send the read command to the SMC
    //
    Store(WCMD(0x10), Local0)                   // send read command (0x10) to the SMC
    If(LEqual(Local0, 1))                       // check status
    {
       
Store (0xFFFFFFFE, Index (RES_, 0))     // set ERROR ID (-2)
        Return (RES_)                           // ERROR -> send read command
    }

   
// 3. Send the Apple SMC Key
    //
    Store(0, Local5)                            // init loop
    While(LLess(Local5, 4))                     // loop 4 times
    {
       
Multiply(Local5, 8, Local1)             // actual shift amount (0, 8, 16, 24)
        ShiftRight(Arg0, Local1, Local0)        // get the actual byte to send
        Store(Local0, SMCD)                     // send the key byte to the SMC Data Port
        If(LEqual(WSTA(0x04), 1))               // wait until the SMC Command Port is ready
        {
           
Store (0xFFFFFFFD, Index (RES_, 0)) // set ERROR ID (-3)
            Return (RES_)                       // ERROR -> send the Key
        }
       
Increment(Local5)                       // set to the next byte position
    }

   
// 4. Send the data length to the SMC
    //
    Store(16, SMCD)                           // send the data length to read to the SMC Data Port

   
// 5. Fill the package with data
    //
    Store(0, Local7)                            // Init the package Index
    While(LLess(Local7, 4))                     // Loop 4 times (0 to 3)
    {
       
// 6. Read the data from SMC
        //
        Store(0, Local1)                            // Init result
        Store(0, Local5)                            // Init 4 times loop
        While(LLess(Local5, 4))                     // loop 4 times (0 to 3)
        {
           
If(LEqual(WSTA(0x05), 1))               // wait until the SMC Command Port is ready
            {
               
Store (0xFFFFFFFC, Index (RES_, 0)) // Set ERROR ID (-4)
                Return (RES_)                       // ERROR -> send the Key
            }
           
Store(SMCD, Local0)                     // receive data byte
            Multiply(Local5, 8, Local6)             // actual shift amount (0, 8, 16, 24)
            ShiftLeft(Local0, Local6, Local0)       // move the data byte to the right bit position in the result register
            Or(Local0,Local1,Local1)                // add data byte to the result register
            //
            Increment(Local5)                       // set to the next byte position
        }

       
// 7. Store received data in the package
        //
        Increment(Local7)                       // Set to the next position in the package
        Store (Local1, Index (RES_, Local7))    // Set result value in the package
    }

   
// 8. Return the package
    //
    Store (0, Index (RES_, 0))                  // set OK status
    Return (RES_)                               // return result
}