smbus.as [SMBusモジュール]

;*******************************************************************************
; SMBus module Ver1.0a  [2007.09.23]
;  Programmed in HSP Ver3.1 ONION software (http://hsp.tv/)
;   Copyright (C) 2007 by abo, all rights reserved.
;*******************************************************************************

#ifdef __hsp30__
#ifndef __SMBUS__
#define global __SMBUS__

#module "smbus"
;/SiS
;--------+---------+---------+---------+---------+---------+---------+---------+
#deffunc ResetSMBusSiS int SMBadr
    if Io_inp(SMBAdr+2)&3 {
        io_out SMBAdr+3,0x20
        repeat 0xFFFF
            if (Io_inp(SMBAdr+2)&1)=0 : break
        loop
    }
    return

;/SMBusのバイト
;--------+---------+---------+---------+---------+---------+---------+---------+
;  アドレス    : Adr
;  ホストコマンド : Hst
;  データ     : Data
;--------+---------+---------+---------+---------+---------+---------+---------+
#define global ctype GetByteRTM(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,0)
#define global ctype SetByteRTM(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,1)
#define global ctype GetAsusSel(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,2)
#define global ctype SetAsusSel(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,3)
#define global ctype GetByteICS(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,2)
#define global ctype SetByteICS(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,3)
#define global ctype GetAsusSelSiS(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,4)
#define global ctype SetAsusSelSiS(%1,%2,%3,%4,%5) BytePll(%1,%2,%3,%4,%5,5)
#defcfunc BytePll var Data, int SMBusCtl, int SMBadr, int Adr, int Hst, int fMode
    do
;/SMBusの準備確認
; SMBadr   : 0 準備ok
;   0以外はSMBus Errorとして処理

    switch fMode
    case 4  ;GetAsusSelSiS
    case 5  ;SetAsusSelSiS
        ResetSMBusSiS SMBadr
        swbreak
    swend

    repeat 0xFFFF
        tmp=Io_inp(SMBadr)
        if CND((SMBusCtl&0xFFFF)=VidSiS,tmp&0x7F,tmp) : io_out SMBadr,0xFF : else : break
    loop
    if CND((SMBusCtl&0xFFFF)=VidSiS,tmp&0x7F,tmp) : _break          ;SMBus Error

    switch fMode
    case 0  ;/RTMバイトリード
        io_out SMBadr+4,Adr|1           ;アドレス,ライトをセット
        io_out SMBadr+3,Hst             ;ホストコマンドセット
        io_out SMBadr+2,0x4C            ;バイトモードスタート
        swbreak
    case 1  ;/RTMバイトライト
        io_out SMBadr+4,Adr             ;アドレス,ライトをセット
        io_out SMBadr+3,Hst             ;ホストコマンドセット
        io_out SMBadr+6,Data            ;ライトデータ
        io_out SMBadr+2,0x4C            ;バイトモードスタート
        swbreak
    case 2  ;/AsusSelリード
        io_out SMBadr+4,Adr|1           ;アドレス,ライトをセット
        io_out SMBadr+3,Hst             ;ホストコマンドセット
        io_out SMBadr+2,0x48            ;バイトモードスタート
        swbreak
    case 3  ;/AsusSelライト
        io_out SMBadr+4,Adr             ;アドレス,ライトをセット
        io_out SMBadr+3,Hst             ;ホストコマンドセット
        io_out SMBadr+5,Data            ;ライトデータ
        io_out SMBadr+2,0x48            ;バイトモードスタート
        swbreak
    case 4  ;/AsusSelSiSリード
        io_out SMBadr+4,Adr|1           ;アドレス,ライトをセット
        io_out SMBadr+5,Hst             ;ホストコマンドセット
        io_out SMBadr,0                 ;
        io_out SMBadr+3,0x12            ;バイトモードスタート
        swbreak
    case 5  ;/AsusSelSiSライト
        io_out SMBadr+4,Adr             ;アドレス,ライトをセット
        io_out SMBadr+5,Hst             ;ホストコマンドセット
        io_out SMBadr+8,Data            ;ライトデータ
        io_out SMBadr,0                 ;
        io_out SMBadr+3,0x12            ;バイトモードスタート
        swbreak
    swend

;/完了確認
; SMBadr   : bit0 1=Host Busy
;          : bit1 1=全バイト完了 , ライト1でリセット
;          : bit2 1=デバイスエラー
    switch fMode
    case 0  ;/RTMバイトリード
    case 1  ;/RTMバイトライト
    case 2  ;/AsusSelリード
    case 3  ;/AsusSelライト
        repeat 0xFFFF
            tmp=Io_inp(SMBadr)
            if tmp&1 : continue ;20b8
            if ((tmp&3)=2) | (tmp&4) : break
        loop
        if (tmp&4)=0 & (tmp&3)=2 {
            switch fMode
            case 0  ;/RTMバイトリード
                Data=Io_inp(SMBadr+6)
                swbreak
            case 2  ;/AsusSelリード
                Data=Io_inp(SMBadr+5)
                swbreak
            swend
            io_out SMBadr,2             ;完了フラグのリセット
            io_out SMBadr,0xFF : tmp=Io_inp(SMBadr)
        }
        swbreak
    case 4  ;/AsusSelSiSリード
    case 5  ;/AsusSelSiSライト
        repeat 0xFFFF
            tmp=Io_inp(SMBadr)
            if tmp&0x0E : break
        loop
        if (tmp&6)=0 & (tmp&8)!0 {
            switch fMode
            case 4  ;/AsusSelリード
                Data=Io_inp(SMBadr+8)
                swbreak
            swend
            io_out SMBadr,tmp : tmp=Io_inp(SMBadr)          ;完了フラグのリセット
        }
        swbreak
    swend

    until

    return CND((SMBusCtl&0xFFFF)=VidSiS,tmp&0x7F,tmp)

;/SMBusの切替
;--------+---------+---------+---------+---------+---------+---------+---------+
; Asusのお呪い
;  *SMBus_pll : SMBusをPLL-ICにセット
;  *SMBus_rtn : SMBusを元に戻す
;--------+---------+---------+---------+---------+---------+---------+---------+
#defcfunc SMBusP4T533C int SmbPort
    io_out 0x2E,0x87
    io_out 0x2E,0x87
    io_out 0x2E,0x07
    io_out 0x2F,0x09
    io_out 0x2E,0x30
    io_out 0x2F,0x03
    io_out 0x2E,0xF5
    RtnSmbPort=Io_inp(0x2F)                 ;現在値を保存
    io_out 0x2E,0xF5
    io_out 0x2F,RtnSmbPort&0xFC|SmbPort     ;Port値をセット
    io_out 0x2E,0xAA
    return 0

#defcfunc SMBusP4T533 int SMBusCtl, int SMBadr, int SmbPort
    if GetAsusSel(Rtniodt,SMBusCtl,SMBadr,0x5A,0x4E) : return stat  ;SMBus error
    iodt=Rtniodt&0xF8|3
    if SetAsusSel(iodt,SMBusCtl,SMBadr,0x5A,0x4E) : return stat ;SMBus error
    if GetAsusSel(RtnSmbPort,SMBusCtl,SMBadr,0x5A,0x84) : return stat   ;SMBus error
    iodt=RtnSmbPort&0xFC|SmbPort
    if SetAsusSel(iodt,SMBusCtl,SMBadr,0x5A,0x84) : return stat ;SMBus error
    if SetAsusSel(Rtniodt,SMBusCtl,SMBadr,0x5A,0x4E) : return stat  ;SMBus error
    return 0

#defcfunc SMBusP4S333 int SMBusCtl, int SMBadr, int SmbPort
    if GetAsusSelSiS(Rtniodt,SMBusCtl,SMBadr,0x5A,0x4E) : return stat   ;SMBus error
    iodt=Rtniodt&0xF8|3
    if GetAsusSelSiS(RtnSmbPort,SMBusCtl,SMBadr,0x5A,0x84) : return stat    ;SMBus error
    iodt=RtnSmbPort&0xFC|SmbPort
    if SetAsusSelSiS(Rtniodt,SMBusCtl,SMBadr,0x5A,0x4E) : return stat   ;SMBus error
    return 0

#defcfunc SMBusA7M266 int SmbPort
    RtnSmbPort=Io_inp(iGpoAdr@+0x4D)
    io_out iGpoAdr@+0x4D,RtnSmbPort&0xF6|SmbPort
    return 0

#defcfunc SMBusA7S333 int SmbPort
    return 0

#defcfunc SMBusPll int SMBusCtl, int SMBadr, int Asus
    switch Asus
    case 1  ;P4T533
        return SMBusP4T533(SMBusCtl,SMBadr,1)   ;PLL-ICにセレクト
        swbreak
    case 2  ;A7M266
        return SMBusA7M266(8)                   ;PLL-ICにセレクト
        swbreak
    case 3  ;A7V333
        return SMBusP4T533(SMBusCtl,SMBadr,2)   ;PLL-ICにセレクト
        swbreak
    case 4  ;P4S533(/333/8X)
        return SMBusP4S333(SMBusCtl,SMBadr,1)   ;PLL-ICにセレクト
        swbreak
    case 5  ;A7S333
        swbreak
    swend
    return 0

#defcfunc SMBusRtn int SMBusCtl, int SMBadr, int Asus
    switch Asus
    case 1  ;P4T533
    case 3  ;A7V333
        return SMBusP4T533(SMBusCtl,SMBadr,RtnSmbPort&3)    ;前回値にセレクト
        swbreak
    case 2  ;A7M266
        return SMBusA7M266(RtnSmbPort&9)                    ;前回値にセレクト
        swbreak
    case 4  ;P4S533(/333/8X)
        return SMBusP4S333(SMBusCtl,SMBadr,RtnSmbPort&3)    ;前回値にセレクト
        swbreak
    case 5  ;A7S333
        swbreak
    swend
    return 0

;/PLL-ICデータのブロック
;--------+---------+---------+---------+---------+---------+---------+---------+
; PLL-IC ブロック
;  ※tmpが0x40でないときはSMBus Error
;--------+---------+---------+---------+---------+---------+---------+---------+
#define global ctype GetBlockPll(%1,%2,%3,%4) BlockPll(%1,%2,%3,%4,0)
#define global ctype SetBlockPll(%1,%2,%3,%4) BlockPll(%1,%2,%3,%4,1)
#defcfunc BlockPll array CR, int SMBusCtl, int SMBadr, var byte, int fMode
    do
;/SMBusの準備確認
; SMBadr   : 0 準備ok
;   0以外はSMBus Errorとして処理

    switch SMBusCtl&0xFFFF
    case VidIntel
        AuxCtl=Io_inp(SMBadr+0x0D) : io_out SMBadr+0x0D,AuxCtl&0xFD
        swbreak
    case VidSiS
        io_outd CONFIG_ADDRESS,0x80001048 : io_out CONFIG_DATA,Io_inp(CONFIG_DATA)|0x80
        ResetSMBusSiS SMBadr
        swbreak
    swend   

    repeat 0xFFFF
        tmp=Io_inp(SMBadr)
        if CND((SMBusCtl&0xFFFF)=VidSiS,tmp&0x7F,tmp) : io_out SMBadr,0xFF : else : break
    loop
    if CND((SMBusCtl&0xFFFF)=VidSiS,tmp&0x7F,tmp) : _break          ;SMBus Error

    switch fMode
    case 0  ;/ブロックリード
        switch SMBusCtl&0xFFFF
        case VidIntel
            switch SMBusCtl
            case IntelPIIX4SMB
                gosub *GetBlockPIIX4
                swbreak
            default
                gosub *GetBlockICH2
                swbreak
            swend
            swbreak
        case VidVia
        case VidAti
            gosub *GetBlockPIIX4
            swbreak
        case VidSiS
            gosub *GetBlockSiS
            swbreak
        swend   
        swbreak
    case 1  ;/ブロックライト
        switch SMBusCtl&0xFFFF
        case VidIntel
            switch SMBusCtl
            case IntelPIIX4SMB
                gosub *SetBlockPIIX4
                swbreak
            default
                gosub *SetBlockICH2
                swbreak
            swend
            swbreak
        case VidVia
        case VidAti
            gosub *SetBlockPIIX4
            swbreak
        case VidSiS
            gosub *SetBlockSiS
            swbreak
        swend   
        swbreak
    swend

    switch SMBusCtl&0xFFFF
    case VidIntel
    case VidVia
    case VidAti
;/ブロックリードの完了確認
; SMBadrを0x40 準備ok , Depthを設定
; SMBadr   : bit1=1 全バイト完了 , ライト1でリセット
        if (tmp&4)=0 {
            repeat 0xFFFF
                tmp=Io_inp(SMBadr)
                if (tmp&3)=2 : break
                if tmp&0x80 : io_out SMBadr,0x80    ; (DQ965GF)
            loop
            if (tmp&3)!2 :  : _break            ;Devエラー
            io_out SMBadr,0x82              ;完了フラグのリセット
            io_out SMBadr,0xFF : tmp=Io_inp(SMBadr)
        }
        swbreak
    case VidSiS
        if (tmp&6)=0 & (tmp&0x18)!0 : io_out SMBadr,tmp : tmp=Io_inp(SMBadr)
        swbreak
    swend

    switch SMBusCtl&0xFFFF
    case VidIntel
        io_out SMBadr+0x0D,AuxCtl
        swbreak
    case VidSiS
        io_outd CONFIG_ADDRESS,0x80001048 : io_out CONFIG_DATA,Io_inp(CONFIG_DATA)&0x7F
        swbreak
    swend   

    until

    return CND((SMBusCtl&0xFFFF)=VidSiS,tmp&0x7F,tmp)

*GetBlockSiS
    io_out SMBadr+4,0xD3                ;アドレス,リードをセット
    io_out SMBadr+5,0                   ;ホストコマンドセット
    io_out SMBadr+3,0x15                ;ブロックモードスタート
    ; SMBadr   : bit0 1=Host Busy
    ;          : bit1 1=全バイト完了 , ライト1でリセット
    ;          : bit2 1=デバイスエラー
    repeat 0xFFFF
        tmp=Io_inp(SMBadr)
        if tmp&0x1E : break
    loop
;   device error    - 0x02
;   bus collision   - 0x04
    if (tmp&6)=0 & (tmp&0x18)!0 {           ;正常
        byte=Io_inp(SMBadr+7)           ;カウント
        repeat byte
            CR(cnt)=Io_inp(SMBadr+8+(cnt&7))            ;cntバイトをリード
            if (cnt&7)=7 {
                io_out SMBadr,Io_inp(SMBadr)
                if cnt=0x1F | byte=8 : break
                if cnt=0x0F & byte=0x10 : break
                if cnt=0x17 & byte=0x18 : break
                repeat 0xFFFF
                    tmp=Io_inp(SMBadr)
                    if tmp&0x1E : break
                loop
                if tmp&6 : break            ;異常
            }
        loop
    }
    return

*SetBlockSiS
    repeat byte
        if (cnt&7)=0 {
            repeat 8,cnt
              io_out SMBadr+8+(cnt&7),CR(cnt)       ;cntバイトをライト
            loop
            if cnt {
                io_out SMBadr,Io_inp(SMBadr)
            } else {
                io_out SMBadr+4,0xD2                ;アドレス,ライトをセット
                io_out SMBadr+7,byte                ;カウントをセット
                io_out SMBadr+5,0                   ;ホストコマンドセット
                io_out SMBadr+3,0x15                ;ブロックモードスタート
            }
            ; SMBadr   : bit0 1=Host Busy
            ;          : bit1 1=全バイト完了 , ライト1でリセット
            ;          : bit2 1=デバイスエラー
            repeat 0xFFFF
                tmp=Io_inp(SMBadr)
                if tmp&0x1E : break
            loop
;   device error    - 0x02
;   bus collision   - 0x04
            if tmp&6 : break            ;異常
        }
    loop

    return

*GetBlockPIIX4
    io_out SMBadr+4,0xD3                ;アドレス,リードをセット
    io_out SMBadr+3,0                   ;ホストコマンドセット
    io_out SMBadr+2,0x54                ;ブロックモードスタート
    ; SMBadr   : bit0 1=Host Busy
    ;          : bit1 1=全バイト完了 , ライト1でリセット
    ;          : bit2 1=デバイスエラー
    repeat 0xFFFF
        tmp=Io_inp(SMBadr)
        if tmp&1 : continue ;20b8
        if tmp&0x0E : break
    loop
    if (tmp&0x0D)=0 {           ;正常
        byte=Io_inp(SMBadr+5)           ;カウント
        reg=Io_inp(SMBadr+2)            ;内部カウント=0
        repeat byte
            CR(cnt)=Io_inp(SMBadr+7)            ;cntバイトをリード,内部カウント+1
        loop
    }
    return
*GetBlockICH2
    repeat
        if cnt=0 {
            ; SMBadr+4 : bit7-1 SH6アドレス=1101001
            ;  (0xD3)    bit0   リード=1
            ; SMBadr+3 : ホストコマンド 0x00にする
            ; SMBadr+2 : bit6   スタート=1
            ;  (0x54)    bit4-2 ブロック=101
            io_out SMBadr+4,0xD3                ;アドレス,リードをセット
            io_out SMBadr+3,0                   ;ホストコマンドセット
            io_out SMBadr+2,0x54                ;ブロックモードスタート
        } else {
            ; SMBus    : bit7 ライト1で次バイトのリクエスト
            io_out SMBadr,0x80
        }
        repeat 0xFFFF
            tmp=Io_inp(SMBadr)
            if tmp&0x84 : break
        loop
        if tmp&4 : break            ;Devエラー
        if cnt=0 : byte=Io_inp(SMBadr+5)
        CR(cnt)=Io_inp(SMBadr+7)            ;cntバイトをリード
        if cnt=(byte-1) : break
    loop
    return
*SetBlockPIIX4
    reg=Io_inp(SMBadr+2)            ;内部カウント=0
    repeat byte
        io_out SMBadr+7,CR(cnt)     ;cntバイトをライト
    loop
    io_out SMBadr+4,0xd2            ;アドレス,ライトをセット
    io_out SMBadr+3,0               ;ホストコマンドセット
    io_out SMBadr+5,byte            ;カウントセット
    io_out SMBadr+2,0x54            ;ブロックモードスタート
    repeat 0xFFFF
        tmp=Io_inp(SMBadr)
        if tmp&1 : continue ;20b8
        if tmp&0x0E : break
    loop
    return
*SetBlockICH2
    repeat byte
        io_out SMBadr+7,CR(cnt)             ;cntバイトをセット
        if cnt=0 {
            ; SMBadr+4 : bit7-1 SH6アドレス=1101001
            ;  (0xD2)    bit0   ライト=0
            ; SMBadr+3 : ホストコマンド 0x00にする
            ; SMBadr+7 : ライトデータ
            ; SMBadr+2 : bit6   スタート=1
            ;  (0x54)    bit4-2 ブロック=101
            io_out SMBadr+4,0xD2            ;アドレス,ライトをセット
            io_out SMBadr+3,0               ;ホストコマンドセット
            io_out SMBadr+5,byte            ;カウントセット
            io_out SMBadr+2,0x54            ;ブロックモードスタート
        } else {
            ; SMBus    : bit7 ライト1で次バイトのリクエスト
            io_out SMBadr,0x80
        }
        ; SMBus    : bit7 1=バイド送信完了 , ライト1でリセット
        repeat 0xFFFF
            tmp=Io_inp(SMBadr)
            if tmp&0x84 : break
        loop
        if tmp&4 : break                ;Devエラー
    loop
    return

#global

#endif  ; __SMBUS__
#endif  ; __hsp30__

;--------------------------------------------------------------- (EOF) ---------