/*---------------------------------------------------------*\
| MSIRGBController.cpp                                      |
|                                                           |
|   Driver for MSI-RGB motherboard                          |
|                                                           |
|   Logic adapted from https://github.com/nagisa/msi-rgb    |
|                                                           |
|   Adam Honse (CalcProgrammer1)                11 Feb 2020 |
|                                                           |
|   This file is part of the OpenRGB project                |
|   SPDX-License-Identifier: GPL-2.0-or-later               |
\*---------------------------------------------------------*/

#include "MSIRGBController.h"
#include "dmiinfo.h"
#include "super_io.h"

MSIRGBController::MSIRGBController(int sioaddr, bool invert, std::string dev_name)
{
    msi_sioaddr = sioaddr;
    name        = dev_name;

    /*-----------------------------------------------------*\
    | This setup step isn't well documented                 |
    | Without this, pulsing does not work                   |
    \*-----------------------------------------------------*/
    superio_outb(msi_sioaddr, SIO_REG_LOGDEV, 0x09);

    int val_at_2c = superio_inb(msi_sioaddr, 0x2C);

    val_at_2c &= 0b11110111;
    val_at_2c |= 0b00010000;

    superio_outb(msi_sioaddr, 0x2C, val_at_2c);

    /*-----------------------------------------------------*\
    | Set logical device register to RGB controller         |
    \*-----------------------------------------------------*/
    superio_outb(msi_sioaddr, SIO_REG_LOGDEV, MSI_SIO_LOGDEV_RGB);

    /*-----------------------------------------------------*\
    | Test if RGB is enabled.  If it is not, enable it.     |
    \*-----------------------------------------------------*/
    int enable = superio_inb(msi_sioaddr, MSI_SIO_RGB_REG_ENABLE);

    if((enable & MSI_SIO_RGB_ENABLE_MASK) != MSI_SIO_RGB_ENABLE_MASK)
    {
        superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_ENABLE, 0xE0);
    }

    /*-----------------------------------------------------*\
    | Lighting enabled, no pulsing or blinking              |
    \*-----------------------------------------------------*/
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_CFG_1, 0x00);

    /*--------------------------------------------------------------*\
    | Header on, pulse deactivated, colors inverted depending on DMI |
    \*--------------------------------------------------------------*/
    unsigned char ff_val = 0b11100010;

    if (invert)
    {
        ff_val |= 0b00011100;
    }

    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_CFG_3, ff_val);
    /*-----------------------------------------------------------*\
    | This seems to be related to some rainbow mode. Deactivated  |
    \*-----------------------------------------------------------*/
    superio_outb(msi_sioaddr, 0xFD, 0x00);
}

MSIRGBController::~MSIRGBController()
{

}

std::string MSIRGBController::GetDeviceLocation()
{
    char hex[12];
    snprintf(hex, sizeof(hex), "0x%X", msi_sioaddr);
    return("SIO: " + std::string(hex));
}

std::string MSIRGBController::GetDeviceName()
{
    return(name);
}

void MSIRGBController::SetColor(unsigned char red, unsigned char green, unsigned char blue)
{
    /*-----------------------------------------------------*\
    | The MSI RGB controller uses 4 bits per color rather   |
    | than 8.  Shift the values by 4 so that the 4 most     |
    | significant bits of each color are the new color value|
    \*-----------------------------------------------------*/
    red     = red >> 4;
    green   = green >> 4;
    blue    = blue >> 4;

    /*-----------------------------------------------------*\
    | Set logical device register to RGB controller         |
    \*-----------------------------------------------------*/
    superio_outb(msi_sioaddr, SIO_REG_LOGDEV, MSI_SIO_LOGDEV_RGB);

    /*-----------------------------------------------------*\
    | Write the colors to the color sequence registers      |
    | Only static mode is supported right now - all colors  |
    | are the same.                                         |
    \*-----------------------------------------------------*/
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_RED_1_0, (red | (red << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_RED_3_2, (red | (red << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_RED_5_4, (red | (red << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_RED_7_6, (red | (red << 4)));

    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_GREEN_1_0, (green | (green << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_GREEN_3_2, (green | (green << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_GREEN_5_4, (green | (green << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_GREEN_7_6, (green | (green << 4)));

    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_BLUE_1_0, (blue | (blue << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_BLUE_3_2, (blue | (blue << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_BLUE_5_4, (blue | (blue << 4)));
    superio_outb(msi_sioaddr, MSI_SIO_RGB_REG_BLUE_7_6, (blue | (blue << 4)));
}
