/*++

Copyright (c) 1998  Microsoft Corporation

Module Name:

    smbbattp.h

Abstract:

    Smart Battery Class Driver Header File

Author:

    Ken Reneris

Environment:

Notes:


Revision History:


--*/

#ifndef FAR
#define FAR
#endif

#include <ntddk.h>
#include <wmilib.h>
#include <batclass.h>
#include <acpiioct.h>
#include <smbus.h>

//
// Debugging
//

#define DEBUG   DBG

#if DEBUG
    extern ULONG SMBBattDebug;

    #define BattPrint(l,m)    if(l & SMBBattDebug) DbgPrint m
#else
    #define BattPrint(l,m)
#endif

#define BAT_TRACE       0x00000400
#define BAT_STATE       0x00000200
#define BAT_IRPS        0x00000100

#define BAT_IO          0x00000040
#define BAT_DATA        0x00000020
#define BAT_ALARM       0x00000010

#define BAT_NOTE        0x00000008
#define BAT_WARN        0x00000004
#define BAT_ERROR       0x00000002
#define BAT_BIOS_ERROR  0x00000001


//
// Driver supports the following class driver version
//

#define SMB_BATTERY_MAJOR_VERSION           0x0001
#define SMB_BATTERY_MINOR_VERSION           0x0000

//
// Smart battery device driver tag for memory allocations: "BatS"
//

#define SMB_BATTERY_TAG 'StaB'

//
// Globals
//
extern UNICODE_STRING GlobalRegistryPath;

//
// Remove Lock parameters for checked builds
//

#define REMOVE_LOCK_MAX_LOCKED_MINUTES 1
#define REMOVE_LOCK_HIGH_WATER_MARK 64


//
// Driver Device Names (FDO)
//
#define         BatterySubsystemName    L"\\Device\\SmartBatterySubsystem"
#define         SmbBattDeviceName       L"\\Device\\SmartBattery"

//
// Query ID Names
//

#define         SubSystemIdentifier     L"SMBUS\\SMBBATT"
#define         BatteryInstance         L"Battery"

#define         HidSmartBattery         L"SMBBATT\\SMART_BATTERY"


//
// Structure for input from private Ioctls to read from devices on smbus
//

typedef struct {
    UCHAR       Address;
    UCHAR       Command;
    union {
        USHORT      Block [2];
        ULONG       Ulong;
    } Data;
} SMBBATT_DATA_STRUCT, *PSMBBATT_DATA_STRUCT;

typedef union {
    USHORT Block [2];
    ULONG Ulong;
} _SMBBATT_DATA_STRUCT_UNION;

#define SMBBATT_DATA_STRUCT_SIZE sizeof (SMBBATT_DATA_STRUCT) - sizeof (_SMBBATT_DATA_STRUCT_UNION)

//
// Private Ioctls for test engines
//

#define IOCTL_SMBBATT_DATA      \
        CTL_CODE(FILE_DEVICE_BATTERY, 0x100, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)


//
// Definitions for the selector state lookup table
//

typedef struct  {
    UCHAR       BatteryIndex;
    BOOLEAN     ReverseLogic;

} SELECTOR_STATE_LOOKUP;


extern const SELECTOR_STATE_LOOKUP SelectorBits [];
extern const SELECTOR_STATE_LOOKUP SelectorBits4 [];


//
// Definitions for control method names neede by the smart battery
//

#define SMBATT_SBS_METHOD   (ULONG) ('SBS_')    // control method "_SBS"
#define SMBATT_GLK_METHOD   (ULONG) ('KLG_')    // control method "_GLK"


//
// Definitions for some string lengths
//

#define MAX_DEVICE_NAME_LENGTH  100
#define MAX_CHEMISTRY_LENGTH    4


//
// Maximum number of smart batteries supported by this driver
//

#define MAX_SMART_BATTERIES_SUPPORTED   4


//
// Types for the FDOs hnadled by this driver:
//  Smart battery subsystem FDO
//  Smart Battery FDO
//  Smart battery PDO
//

typedef enum {
    SmbTypeSubsystem,
    SmbTypeBattery,
    SmbTypePdo
} SMB_FDO_TYPE;


//
// SMB Host Controller Device object extenstion
//

//
// Cached battery info
//

typedef struct {
    ULONG                       Tag;
    UCHAR                       Valid;
    BATTERY_INFORMATION         Info;
    UCHAR                       ManufacturerNameLength;
    UCHAR                       ManufacturerName[SMB_MAX_DATA_SIZE];
    UCHAR                       DeviceNameLength;
    UCHAR                       DeviceName[SMB_MAX_DATA_SIZE];
    BATTERY_MANUFACTURE_DATE    ManufacturerDate;
    ULONG                       SerialNumber;

    ULONG                       PowerState;
    ULONG                       Capacity;
    ULONG                       VoltageScale;
    ULONG                       CurrentScale;
    ULONG                       PowerScale;
} STATIC_BAT_INFO, *PSTATIC_BAT_INFO;

#define VALID_TAG_DATA      0x01            // manufacturer, device, serial #
#define VALID_MODE          0x02
#define VALID_OTHER         0x04
#define VALID_CYCLE_COUNT   0x08
#define VALID_SANITY_CHECK  0x10
#define VALID_TAG           0x80

#define VALID_ALL           0x1F            // (does not include tag)


//
// Selector information structure
//

typedef struct _BATTERY_SELECTOR {
    //
    // Addressing and command information.  This can change based whether or
    // not the selector is stand alone or part of the charger.
    //

    UCHAR               SelectorAddress;
    UCHAR               SelectorStateCommand;
    UCHAR               SelectorPresetsCommand;
    UCHAR               SelectorInfoCommand;

    //
    // Mutex to keep only one person talking with the selector at a time
    //

    FAST_MUTEX          Mutex;

    //
    // Cached information.  We will get notifications when these change.
    //

    ULONG               SelectorState;
    ULONG               SelectorPresets;
    ULONG               SelectorInfo;
} BATTERY_SELECTOR, *PBATTERY_SELECTOR;



typedef struct {
    ULONG               Setting;
    ULONG               Skip;
    LONG                Delta;
    LONG                AllowedFudge;
} BAT_ALARM_INFO, *PBAT_ALARM_INFO;


typedef struct {
    UCHAR               Address;
    USHORT              Data;
    LIST_ENTRY          Alarms;
} SMB_ALARM_ENTRY, *PSMB_ALARM_ENTRY;


//
// Non-pagable device extension for smart battery FDO
// (Created by IoCreateDevice SMB_NP_BATT for each battery)
//

typedef struct {
    SMB_FDO_TYPE        SmbBattFdoType;     // Device object type
    IO_REMOVE_LOCK      RemoveLock;

    //
    // All elements above this point must be identical in
    // SMB_NP_BATT, SMB_BATT_SUBSYSTEM, and SMB_BATT_PDO structures.
    //

    FAST_MUTEX          Mutex;              // lets either battery OR subsystem
                                            //   have access to batt
    PVOID               Class;              // Battery Class handle
    struct _SMB_BATT    *Batt;              // Battery pageable extension
    PDEVICE_OBJECT      LowerDevice;        // Battery Subsystem PDO
    WMILIB_CONTEXT      WmiLibContext;
} SMB_NP_BATT, *PSMB_NP_BATT;

//
// Pagable device extension for smart battery FDO
// (Allocated Extra Memory for device information)
//

typedef struct _SMB_BATT {

    //
    //
    //

    PSMB_NP_BATT        NP;                 // Battery device object extension
    PDEVICE_OBJECT      DeviceObject;       // Battery Fdo
    PDEVICE_OBJECT      PDO;                // Battery Pdo


    // SMB host controller

    PDEVICE_OBJECT      SmbHcFdo;           // SM bus Fdo

    //
    // Selector
    //

    PBATTERY_SELECTOR   Selector;           // Selector for battery

    //
    // For handling multiple batteries
    //

    BOOLEAN             SelectorPresent;
    ULONG               SelectorBitPosition;

    //
    // Battery
    //

    ULONG               TagCount;           // Tag for next battery
    STATIC_BAT_INFO     Info;
    BAT_ALARM_INFO      AlarmLow;
} SMB_BATT, *PSMB_BATT;


//
// Device extension for the smart battery subsystem FDO
// (Created by first AddDevice command from ACPI PDO)
//

typedef struct _SMB_BATT_SUBSYSTEM {
    SMB_FDO_TYPE        SmbBattFdoType;     // Device object type
    IO_REMOVE_LOCK      RemoveLock;

    //
    // All elements above this point must be identical in
    // SMB_NP_BATT, SMB_BATT_SUBSYSTEM, and SMB_BATT_PDO structures.
    //

    PVOID               SmbAlarmHandle;     // handle for SmbAlarm registration

    PDEVICE_OBJECT      LowerDevice;        // Subsystem PDO
    PDEVICE_OBJECT      DeviceObject;       // Subsystem FDO
    PDEVICE_OBJECT      SmbHcFdo;           // SMBus Fdo

    ULONG               NumberOfBatteries;  // Number of batteries supported
    BOOLEAN             SelectorPresent;    // Is there a selector present

    PBATTERY_SELECTOR   Selector;           // Selector specific info

    //
    // Stuff for handling the SMB alarms for the smart battery subsystem
    //

    LIST_ENTRY          AlarmList;
    KSPIN_LOCK          AlarmListLock;
    PIO_WORKITEM        WorkerThread;       // WORK_QUEUE to get worker thread
    ULONG               WorkerActive;

    //
    // Keep a list of the battery PDOs I "discover"
    //

    PDEVICE_OBJECT      BatteryPdoList[MAX_SMART_BATTERIES_SUPPORTED];
} SMB_BATT_SUBSYSTEM, *PSMB_BATT_SUBSYSTEM;


//
// Device extension for the smart battery PDOs
// (Created by IoCreateDevice SMB_BATT_PDO for each battery)
//

typedef struct _SMB_BATT_PDO {
    SMB_FDO_TYPE        SmbBattFdoType;     // Device object type
    IO_REMOVE_LOCK      RemoveLock;

    //
    // All elements above this point must be identical in
    // SMB_NP_BATT, SMB_BATT_SUBSYSTEM, and SMB_BATT_PDO structures.
    //

    PDEVICE_OBJECT      DeviceObject;       // Battery PDO
    PDEVICE_OBJECT      Fdo;                // Battery FDO layered on top of PDO
    PDEVICE_OBJECT      SubsystemFdo;       // Smart Battery subsystem FDO
    ULONG               BatteryNumber;      // Used by subsystem during battery
                                            //   FDO init
} SMB_BATT_PDO, *PSMB_BATT_PDO;


//
// SMBus Smart battery addresses and registers
//

#define SMB_HOST_ADDRESS     0x8            // Address on bus (10H)
#define SMB_CHARGER_ADDRESS  0x9            // Address on bus (12H)
#define SMB_SELECTOR_ADDRESS 0xa            // Address on bus (14H)
#define SMB_BATTERY_ADDRESS  0xb            // Address on bus (16H)
#define SMB_ALERT_ADDRESS    0xc            // Address on bus (18H)

//
// Smart Battery command codes
//

#define BAT_REMAINING_CAPACITY_ALARM        0x01        // word
#define BAT_REMAINING_TIME_ALARM            0x02        // word
#define BAT_BATTERY_MODE                    0x03        // word
#define BAT_AT_RATE                         0x04        // word
#define BAT_RATE_TIME_TO_FULL               0x05        // word
#define BAT_RATE_TIME_TO_EMPTY              0x06        // word
#define BAT_RATE_OK                         0x07        // word
#define BAT_TEMPERATURE                     0x08        // word
#define BAT_VOLTAGE                         0x09        // word
#define BAT_CURRENT                         0x0a        // word
#define BAT_AVERAGE_CURRENT                 0x0b        // word
#define BAT_MAX_ERROR                       0x0c        // word
#define BAT_RELATIVE_STATE_OF_CHARGE        0x0d        // word
#define BAT_ABSOLUTE_STATE_OF_CHARGE        0x0e        // word
#define BAT_REMAINING_CAPACITY              0x0f        // word
#define BAT_FULL_CHARGE_CAPACITY            0x10        // word
#define BAT_RUN_TO_EMPTY                    0x11        // word
#define BAT_AVERAGE_TIME_TO_EMPTY           0x12        // word
#define BAT_AVERAGE_TIME_TO_FULL            0x13        // word
#define BAT_STATUS                          0x16        // word
#define BAT_CYCLE_COUNT                     0x17        // word
#define BAT_DESIGN_CAPACITY                 0x18        // word
#define BAT_DESIGN_VOLTAGE                  0x19        // word
#define BAT_SPECITICATION_INFO              0x1a        // word
#define BAT_MANUFACTURER_DATE               0x1b        // word
#define BAT_SERIAL_NUMBER                   0x1c        // word
#define BAT_MANUFACTURER_NAME               0x20        // block
#define BAT_DEVICE_NAME                     0x21        // block
#define BAT_CHEMISTRY                       0x22        // block
#define BAT_MANUFACTURER_DATA               0x23        // block

//
// Battery Mode Definitions
//

#define CAPACITY_WATTS_MODE                 0x8000

//
// Battery Scale Factors
//

#define BSCALE_FACTOR_0         1
#define BSCALE_FACTOR_1         10
#define BSCALE_FACTOR_2         100
#define BSCALE_FACTOR_3         1000

#define BATTERY_VSCALE_MASK     0x0f00
#define BATTERY_IPSCALE_MASK    0xf000

#define BATTERY_VSCALE_SHIFT    8
#define BATTERY_IPSCALE_SHIFT   12


//
// Selector command codes
//

#define SELECTOR_SELECTOR_STATE             0x01        // word
#define SELECTOR_SELECTOR_PRESETS           0x02        // word
#define SELECTOR_SELECTOR_INFO              0x04        // word

//
// Selector Equates
//

#define SELECTOR_SHIFT_CHARGE                   4
#define SELECTOR_SHIFT_POWER                    8
#define SELECTOR_SHIFT_COM                      12

#define SELECTOR_STATE_PRESENT_MASK             0x000F
#define SELECTOR_STATE_CHARGE_MASK              0x00F0
#define SELECTOR_STATE_POWER_BY_MASK            0x0F00
#define SELECTOR_STATE_SMB_MASK                 0xF000

#define SELECTOR_SET_COM_MASK                   0x0FFF
#define SELECTOR_SET_POWER_BY_MASK              0xF0FF
#define SELECTOR_SET_CHARGE_MASK                0xFF0F

#define BATTERY_A_PRESENT                       0x0001
#define BATTERY_B_PRESENT                       0x0002
#define BATTERY_C_PRESENT                       0x0004
#define BATTERY_D_PRESENT                       0x0008

#define SELECTOR_STATE_PRESENT_CHANGE           0x1
#define SELECTOR_STATE_CHARGE_CHANGE            0x2
#define SELECTOR_STATE_POWER_BY_CHANGE          0x4
#define SELECTOR_STATE_SMB_CHANGE               0x8

#define SELECTOR_PRESETS_OKTOUSE_MASK           0x000F
#define SELECTOR_PRESETS_USENEXT_MASK           0x00F0

#define SELECTOR_SHIFT_USENEXT                  4

#define SELECTOR_INFO_SUPPORT_MASK              0x000F
#define SELECTOR_INFO_SPEC_REVISION_MASK        0x00F0
#define SELECTOR_INFO_CHARGING_INDICATOR_BIT    0x0100

#define SELECTOR_SHIFT_REVISION                 4

//
// Charger command codes
//

#define CHARGER_SPEC_INFO                   0x11        // word
#define CHARGER_MODE                        0x12        // word
#define CHARGER_STATUS                      0x13        // word
#define CHARGER_CHARGING_CURRENT            0x14        // word
#define CHARGER_CHARGING_VOLTAGE            0x15        // word
#define CHARGER_ALARM_WARNING               0x16        // word

#define CHARGER_SELECTOR_COMMANDS           0x20

#define CHARGER_SELECTOR_STATE              CHARGER_SELECTOR_COMMANDS | \
                                            SELECTOR_SELECTOR_STATE
#define CHARGER_SELECTOR_PRESETS            CHARGER_SELECTOR_COMMANDS | \
                                            SELECTOR_SELECTOR_PRESETS
#define CHARGER_SELECTOR_INFO               CHARGER_SELECTOR_COMMANDS | \
                                            SELECTOR_SELECTOR_INFO

//
// Charger Status Definitions
//

#define CHARGER_STATUS_BATTERY_PRESENT_BIT  0x4000
#define CHARGER_STATUS_AC_PRESENT_BIT       0x8000

//
// Charger Specification Info Definitions
//

#define CHARGER_SELECTOR_SUPPORT_BIT        0x0010

//
// SelectorState ReverseLogic Equates
//

#define INVALID         0xFF


#define BATTERY_A       0x00
#define BATTERY_B       0x01
#define BATTERY_C       0x02
#define BATTERY_D       0x03

#define MULTIBATT_AB    0x04
#define MULTIBATT_AC    0x08
#define MULTIBATT_BC    0x09
#define MULTIBATT_ABC   0x24

#define BATTERY_NONE    0xFF

// word to byte helpers

#define WORD_MSB_SHIFT  8
#define WORD_LSB_MASK   0xFF


//
// Function Prototypes
//

VOID
SmbBattLockDevice (
    IN PSMB_BATT        SmbBatt
);


VOID
SmbBattUnlockDevice (
    IN PSMB_BATT        SmbBatt
);


VOID
SmbBattRequest (
    IN PSMB_BATT        SmbBatt,
    IN PSMB_REQUEST     SmbReq
);


NTSTATUS
SmbBattSynchronousRequest (
    IN PDEVICE_OBJECT   DeviceObject,
    IN PIRP             Irp,
    IN PVOID            Context
);


VOID
SmbBattRB(
    IN PSMB_BATT        SmbBatt,
    IN UCHAR            SmbCmd,
    OUT PUCHAR          Buffer,
    OUT PUCHAR          BufferLength
);


VOID
SmbBattRW(
    IN PSMB_BATT        SmbBatt,
    IN UCHAR            SmbCmd,
    OUT PULONG          Result
);


VOID
SmbBattRSW(
    IN PSMB_BATT        SmbBatt,
    IN UCHAR            SmbCmd,
    OUT PLONG           Result
);


VOID
SmbBattWW(
    IN PSMB_BATT        SmbBatt,
    IN UCHAR            SmbCmd,
    IN ULONG            Data
);


UCHAR
SmbBattGenericRW(
    IN PDEVICE_OBJECT   SmbHcFdo,
    IN UCHAR            Address,
    IN UCHAR            SmbCmd,
    OUT PULONG          Result
);


UCHAR
SmbBattGenericWW(
    IN PDEVICE_OBJECT   SmbHcFdo,
    IN UCHAR            Address,
    IN UCHAR            SmbCmd,
    IN ULONG            Data
);


VOID
SmbBattGenericRequest (
    IN PDEVICE_OBJECT   SmbHcFdo,
    IN PSMB_REQUEST     SmbReq
);


VOID
SmbBattAlarm (
    IN PVOID            Context,
    IN UCHAR            Address,
    IN USHORT           Data
);


BOOLEAN
SmbBattVerifyStaticInfo (
    IN PSMB_BATT        SmbBatt,
    IN ULONG            BatteryTag
);


NTSTATUS
SmbBattPowerDispatch(
    IN PDEVICE_OBJECT   Fdo,
    IN PIRP             Irp
);


NTSTATUS
SmbBattPnpDispatch(
    IN PDEVICE_OBJECT   Fdo,
    IN PIRP             Irp
);


NTSTATUS
SmbBattRegisterForAlarm(
    IN PDEVICE_OBJECT   Fdo
);


NTSTATUS
SmbBattUnregisterForAlarm(
    IN PDEVICE_OBJECT   Fdo
);


NTSTATUS
SmbBattSetSelectorComm (
    IN  PSMB_BATT   SmbBatt,
    OUT PULONG      OldSelectorState
);


NTSTATUS
SmbBattResetSelectorComm (
    IN PSMB_BATT    SmbBatt,
    IN ULONG        OldSelectorState
);


NTSTATUS
SmbGetSBS (
    IN PULONG           NumberOfBatteries,
    IN PBOOLEAN         SelectorPresent,
    IN PDEVICE_OBJECT   LowerDevice
);


NTSTATUS
SmbGetGLK (
    IN PBOOLEAN         GlobalLockRequired,
    IN PDEVICE_OBJECT   LowerDevice
);


NTSTATUS
SmbBattCreatePdos(
    IN PDEVICE_OBJECT   SubsystemFdo
);


NTSTATUS
SmbBattBuildDeviceRelations(
    IN  PSMB_BATT_SUBSYSTEM SubsystemExt,
    IN  PDEVICE_RELATIONS   *DeviceRelations
);


NTSTATUS
SmbBattQueryDeviceRelations(
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP            Irp
);


NTSTATUS
SmbBattRemoveDevice(
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP            Irp
);


NTSTATUS
SmbBattQueryId(
    IN  PDEVICE_OBJECT  Pdo,
    IN  PIRP            Irp
);


NTSTATUS
SmbBattQueryCapabilities(
    IN  PDEVICE_OBJECT  Pdo,
    IN  PIRP            Irp
);


SmbBattBuildSelectorStruct(
    IN PDEVICE_OBJECT   SubsystemFdo
);


VOID
SmbBattWorkerThread (
    IN PDEVICE_OBJECT   Fdo,
    IN PVOID            Context
);


VOID
SmbBattLockSelector (
    IN PBATTERY_SELECTOR    Selector
);


VOID
SmbBattUnlockSelector (
    IN PBATTERY_SELECTOR    Selector
);


ULONG
SmbBattGetSelectorDeltas (
    IN ULONG            OriginalSelectorState,
    IN ULONG            NewSelectorState
);


VOID
SmbBattProcessPresentChanges (
    IN PSMB_BATT_SUBSYSTEM  SubsystemExt,
    IN ULONG                OriginalSelectorState,
    IN ULONG                NewSelectorState
);

VOID
SmbBattProcessChargeChange (
    IN PSMB_BATT_SUBSYSTEM  SubsystemExt,
    IN ULONG                OriginalSelectorState,
    IN ULONG                NewSelectorState
);


VOID
SmbBattProcessPowerByChange (
    IN PSMB_BATT_SUBSYSTEM  SubsystemExt,
    IN ULONG                OriginalSelectorState,
    IN ULONG                NewSelectorState
);


VOID
SmbBattNotifyClassDriver (
    IN PSMB_BATT_SUBSYSTEM  SubsystemExt,
    IN ULONG                BatteryIndex
);

#if DEBUG
NTSTATUS
SmbBattDirectDataAccess (
    IN PSMB_NP_BATT         DeviceExtension,
    IN PSMBBATT_DATA_STRUCT IoBuffer,
    IN ULONG                InputLen,
    IN ULONG                OutputLen
);
#endif


VOID
SmbBattProcessChargerAlarm (
    IN PSMB_BATT_SUBSYSTEM  SubsystemExt,
    IN ULONG                ChargerStatus
);

NTSTATUS
SmbBattSetInformation (
    IN PVOID                            Context,
    IN ULONG                            BatteryTag,
    IN BATTERY_SET_INFORMATION_LEVEL    Level,
    IN PVOID Buffer                     OPTIONAL
);


UCHAR
SmbBattIndex (
    IN PBATTERY_SELECTOR    Selector,
    IN ULONG                SelectorNibble,
    IN UCHAR                SimultaneousIndex
);

BOOLEAN
SmbBattReverseLogic (
    IN PBATTERY_SELECTOR    Selector,
    IN ULONG                SelectorNibble
);

extern BOOLEAN   SmbBattUseGlobalLock;

NTSTATUS
SmbBattAcquireGlobalLock (
    IN  PDEVICE_OBJECT LowerDeviceObject,
    OUT PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER GlobalLock
);

NTSTATUS
SmbBattReleaseGlobalLock (
    IN PDEVICE_OBJECT LowerDeviceObject,
    IN PACPI_MANIPULATE_GLOBAL_LOCK_BUFFER GlobalLock
);

NTSTATUS
SmbBattSystemControl(
    IN  PDEVICE_OBJECT  DeviceObject,
    IN  PIRP            Irp
);

NTSTATUS
SmbBattWmiRegistration(
    PSMB_NP_BATT SmbNPBatt
);

NTSTATUS
SmbBattWmiDeRegistration(
    PSMB_NP_BATT SmbNPBatt
);