/*++

Copyright (c) 2000  Microsoft Corporation

Module Name:

    smbali.c

Abstract:

    SMB Host Controller Driver for ALI chipset

Author:

    Michael Hills

Environment:

Notes:


Revision History:

--*/
#include <wdm.h>
#include <smbus.h>
#include <devioctl.h>
#include <acpiioct.h>
#include <initguid.h>
#include <wdmguid.h>


//
// Debuging
//
#if DBG
    extern ULONG SmbAliDebug;
    #define SmbPrint(l,m) if(l & SmbAliDebug) DbgPrint m
#else
    #define SmbPrint(l,m)
#endif

#define SMB_IO_RESULT   0x00002000
#define SMB_STATS       0x00001000
#define SMB_ALARM       0x00000800
#define SMB_IO_REQUEST  0x00000400
#define SMB_DATA        0x00000200
#define SMB_IO          0x00000100
#define SMB_TRACE       0x00000010
#define SMB_BUS_ERROR   0x00000002
#define SMB_ERROR       0x00000001

//#define USE_IO_DELAY

#ifdef USE_IO_DELAY
    VOID SmbDelay(VOID);
    #define SMBDELAY SmbDelay ()
#else
    #define SMBDELAY
#endif

// The follow constants are based on 10,000,000 / sec <OR> 100ns time units.
#define MICROSECONDS    (10)
#define MILLISECONDS    (1000*MICROSECONDS)
#define SECONDS         (1000*MILLISECONDS)


#define SMB_ALI_MAJOR_VERSION 1
#define SMB_ALI_MINOR_VERSION 1

extern LARGE_INTEGER SmbIoPollRate;
extern ULONG SmbIoInitTimeOut;
extern ULONG SmbIoCompleteTimeOut;
extern LARGE_INTEGER SmbAlertPollRate;

typedef enum {
    SmbIoIdle,
    SmbIoComplete
} SMB_ALI_IO_STATE;

#define SMB_ALI_IO_RESOURCE_LENGTH 0x40

typedef struct {
    UCHAR   Address;
    UCHAR   Command;
    UCHAR   Protocol;
    BOOLEAN ValidData;
    USHORT   LastData;
} SMB_ALI_POLL_ENTRY, *PSMB_ALI_POL_ENTRY;

typedef struct {

    PUCHAR SmbBaseIo;  // Base IoAddress

    SMB_ALI_IO_STATE IoState;
    ACPI_INTERFACE_STANDARD AcpiInterfaces;
    PIO_WORKITEM    WorkItem;

    PIO_WORKITEM    InitWorker;
    KDPC            InitDpc;
    KTIMER          InitTimer;
    ULONG           InitTimeOut;

    PIO_WORKITEM    CompleteWorker;
    KDPC            CompleteDpc;
    KTIMER          CompleteTimer;
    ULONG           CompleteTimeOut;

    PIO_WORKITEM    PollWorker;
    KEVENT          PollWorkerActive;
    KDPC            PollDpc;
    KTIMER          PollTimer;
    PSMB_ALI_POL_ENTRY  PollList;
    ULONG           PollListCount;

    ULONG           InternalRetries;

} SMB_ALI_DATA, *PSMB_ALI_DATA;

//
// ALI SMBus control registers and bits
//

#define SMB_STS_REG (AliData->SmbBaseIo + 0)
#define SMB_STS_ALERT_STS	0x01	//(1 << 0)
#define SMB_STS_IDLE_STS	0x04	//(1 << 2) // Bus is idle
#define SMB_STS_SMB_IDX_CLR 0x04	//(1 << 2) // Write SMB Index clear.
#define SMB_STS_HOST_BSY	0x08	//(1 << 3) // Bus is busy - do not issue another bus cycle if this is set
#define SMB_STS_SCI_I_STS	0x10	//(1 << 4) // command completed
#define SMB_STS_DRV_ERR		0x20	//(1<<5)
#define SMB_STS_BUS_ERR		0x40	//(1<<6)
#define SMB_STS_FAILED		0x80	//(1<<7)
#define SMB_STS_CLEAR		0xf1
#define SMB_STS_ERRORS		0xe0

#define SMB_STS_LAST_CMD_COMPLETED 0x14
#define SMB_STS_CLEAR_DONE	0x11

#define SMB_TYP_REG (AliData->SmbBaseIo + 1)
#define SMB_TYP_MASK 0x70
#define SMB_TYP_QUICK 0x00
#define SMB_TYP_SEND 0x10
#define SMB_TYP_BYTE 0x20
#define SMB_TYP_WORD 0x30
#define SMB_TYP_BLOCK 0x40
#define SMB_TYP_PROCESS 0x50
#define SMB_TYP_I2C 0x60
#define SMB_TYP_KILL (1<<2)
#define SMB_TYP_T_OUT_CMD (1<<3)


#define STR_PORT_REG (AliData->SmbBaseIo + 2)
#define STR_PORT_START 0xff

#define DEV_ADDR_REG (AliData->SmbBaseIo + 3)
#define DEV_DATA0_REG (AliData->SmbBaseIo + 4)
#define DEV_DATA1_REG (AliData->SmbBaseIo + 5)
#define BLK_DATA_REG (AliData->SmbBaseIo + 6)
#define SMB_CMD_REG (AliData->SmbBaseIo + 7)



NTSTATUS
DriverEntry (
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    );

NTSTATUS
SmbAliInitializeMiniport (
    IN PSMB_CLASS SmbClass,
    IN PVOID MiniportExtension,
    IN PVOID MiniportContext
    );

NTSTATUS
SmbAliAddDevice (
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT Pdo
    );

NTSTATUS
SmbAliResetDevice (
    IN struct _SMB_CLASS* SmbClass,
    IN PVOID SmbMiniport
    );

VOID
SmbAliStartIo (
    IN struct _SMB_CLASS* SmbClass,
    IN PSMB_ALI_DATA AliData
    );

VOID
SmbAliInitTransactionDpc (
    IN struct _KDPC *Dpc,
    IN struct _SMB_CLASS* SmbClass,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );

VOID
SmbAliInitTransactionWorker (
    IN PDEVICE_OBJECT DeviceObject,
    IN struct _SMB_CLASS* SmbClass
    );

VOID
SmbAliCompleteTransactionDpc (
    IN struct _KDPC *Dpc,
    IN struct _SMB_CLASS* SmbClass,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );

VOID
SmbAliCompleteTransactionWorker (
    IN PDEVICE_OBJECT DeviceObject,
    IN struct _SMB_CLASS* SmbClass
    );

NTSTATUS
SmbAliStopDevice (
    IN struct _SMB_CLASS* SmbClass,
    IN PSMB_ALI_DATA AliData
    );

VOID
SmbAliNotifyHandler (
    IN PVOID                Context,
    IN ULONG                NotifyValue
    );

VOID
SmbAliWorkerThread (
    IN PDEVICE_OBJECT DeviceObject,
    IN PVOID Context
    );

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

BOOLEAN
SmbAliTransactionComplete (
    PSMB_ALI_DATA AliData,
    PUCHAR SmbStatus
    );

BOOLEAN
SmbAliHostBusy (
    PSMB_ALI_DATA AliData
    );

VOID
SmbAliHandleAlert (
    PSMB_ALI_DATA AliData
    );

VOID
SmbAliResetBus (
    PSMB_ALI_DATA AliData
    );

VOID
SmbAliResetHost (
    PSMB_ALI_DATA AliData
    );

VOID
SmbAliStartDevicePolling (
    IN struct _SMB_CLASS* SmbClass
    );

VOID
SmbAliStopDevicePolling (
    IN struct _SMB_CLASS* SmbClass
    );