                name    SSPCIC
                page    60, 132
                title   'SSPCIC'
;******************************************************************************
;*
;*                            File SSPCIC.ASM
;*
;*                        Socket Services PCIC File
;*
;*                           PCIC PCMCIA Functions
;*
;*            Copyright (c) Award Software International Inc., 1994
;*
;*
;******************************************************************************

                include ssmac.inc           ; Macros
                include ssdefs.inc          ; Sockets Services definitions
                include ss_segm.inc         ; Segment definitions
                include ssPCIC.inc          ; PCIC module defs
                include ssmsg.inc           ; Messages

;*****************************************************************************
;*                         --- Segment ResData ---
;*****************************************************************************
sBegin          ResData

;-------------------------------- Adapter Info --------------------------------

; The ADAPTER structure below must be immediately followed by the Power
; Management Table for proper operation of InquireAdapter.

AdapterInfo     CHARTBL {{0000H}, PCIC_SC_IRQSH, PCIC_SC_IRQSL}
PowerTable      dw      PCIC_MAX_PWR_ENTRIES            ; Number of power levels
                PWRENTRY { 00H, VCC OR VPP1 OR VPP2 }   ; Vcc, Vpp1 and Vpp2 - No connect
                PWRENTRY { 21H, VCC OR VPP1 OR VPP2 }   ; Vcc, Vpp1 and Vpp2 -  3.3 VDC
                PWRENTRY { 32H, VCC OR VPP1 OR VPP2 }   ; Vcc, Vpp1 and Vpp2 -  5.0 VDC
                PWRENTRY { 78h, VPP1 OR VPP2 }          ; Vpp1 and Vpp2      - 12.0 VDC
_AdapterInfoLen =       $ - OFFSET AdapterInfo
AdapterInfoLen  dw      _AdapterInfoLen

;--------------------------------- Socket Info --------------------------------

SocketInfo      CHARTBL {{IF_MEMORY OR IF_IO}, PCIC_SK_IRQSH, PCIC_SK_IRQSL}
_SocketInfoLen  =       SIZEOF SocketInfo
SocketInfoLen   dw      _SocketInfoLen

SocketCaps      SKT_CAP {PCIC_SKT_SCI_CAP, PCIC_SKT_SCR_CAP, PCIC_SKT_CI_CAP}               ; AS: Socket capabilities

sEnd            ResData

;*****************************************************************************
;*                         --- Segment ResCode ---
;*****************************************************************************
sBegin          ResCode

;*****************************************************************************
;*                            --- AdjustIndx ---
;*
;*     Purpose: Adjust register number and base port according to the adapter
;*              specific reuirements
;*       Input: AL - Register to access
;*              DX - Suggested adapter base port
;*              BX - Pointer to the adapter data structure
;*      Output: AL - Adjusted value of register to access
;*              DX - Adjusted value of base port
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 30.07.94
;*****************************************************************************
AdjustIndx      PROC    NEAR
        assumes ds, ResData
        assumes es, Nothing
        assumes ss, Nothing

                cmp     (ARGS PTR [BP]).bSocketIdx, 0   ; Socket 0?
                je      @f                  ; Socket 0 is Intel compatible

                add     dx, 2               ; Actually 3E2h
                cmp     (ARGS PTR [BP]).bSocketIdx, 80h ; Socket 2?
                je      @f                  ; Socket 2 starts at index 0 of 3E2

                add     al, 80h             ; Sockets 1 & 3 start at 80h
                add     dx, 2               ; Actually 3E4h
                cmp     (ARGS PTR [BP]).bSocketIdx, 40h ; Socket 1?
                je      @f                  ; Yes, we are done

                add     dx, 2               ; Actually 3E6
@@:             ret
AdjustIndx      ENDP

;*****************************************************************************
;*                              --- GetReg ---
;*
;*     Purpose: Return value from register
;*       Input: AL - Register to read
;*              BX - Pointer to the adapter data structure
;*      Output: AL - Readen value
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 30.07.94
;*****************************************************************************
GetReg          PROC    NEAR
        assumes ds, ResData
        assumes es, Nothing
        assumes ss, Nothing

                push    dx
                mov     dx, (ADP_DATA PTR [BX]).wBasePort
                call    AdjustIndx
                out     dx, al
                _DELAY_

                inc     dx
                in      al, dx
                _DELAY_

                pop     dx
                ret

GetReg          ENDP

;*****************************************************************************
;*                              --- SetReg ---
;*
;*     Purpose: Set register value
;*       Input: AL - register to write
;*              AH - value to write
;*              BX - Pointer to the adapter data structure
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 30.07.94
;*****************************************************************************
SetReg          PROC    NEAR
        assumes ds, ResData
        assumes es, Nothing
        assumes ss, Nothing

                push    dx
                mov     dx, (ADP_DATA PTR [BX]).wBasePort
                call    AdjustIndx
                out     dx, al
                _DELAY_

                inc     dx
                mov     al, ah
                out     dx, al
                _DELAY_

                pop     dx
                ret

SetReg          ENDP

;*****************************************************************************
;*                            --- asSetSktIRQ ---
;*
;*     Purpose: Set New Socket IRQ level
;*       Input: AH - Interface Type, AL - Socket IRQ
;*              SI - Socket number
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 10.06.94
;*****************************************************************************
asSetSktIRQ     PROC    NEAR
                assume  ds:@data, es:Nothing

                push    ax                  ; Save used regs

                test    ah, IF_IO           ; I/O Interface requested?
                mov     ah, PCIC_INTER_CARDIO ; Assume yes
                jnz     @f                  ; Yes, check IRQ_ENABLED condition

                xor     ax, ax              ; Disable Socket IRQ
                jmp     short @f            ; Set IRQ disabled

@@:             test    al, IRQ_ENABLED     ; Interrupt Enabled?
                jnz     @f                  ; Yes, set IRQ enabled

                xor     ah, ah              ; Disable socket IRQ
                                            ; (PCIC_INTER_CARDIO)

@@:             and     al, P_IRQ15         ; Keep IRQ only
                or      ah, al              ; Merge with Interface type

                mov     al, PCIC_INTER
                call    GetReg              ; Read !RESET state

                and     al, PCIC_INTER_RESET ; Clear all other bits

                or      ah, al              ; Leave !RESET as it was!
                mov     al, PCIC_INTER
                CALL    SetReg              ; Set Socket IRQ

                pop     ax                  ; Restore used registers
                ret
asSetSktIRQ     ENDP

;*****************************************************************************
;*                         --- asSetSktInterface ---
;*
;*     Purpose: Set Socket interface type
;*       Input: [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*              SI   - Socket number
;*              AH   - Socket Interface type
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 20.07.94
;*****************************************************************************
asSetSktInterface PROC  NEAR
                assume  ds:@data, es:Nothing

                push    ax
                mov     al, PCIC_INTER
                call    GetReg

                and     al, NOT PCIC_INTER_CARDIO ; Assume memory Interface
                test    ah, IF_MEMORY       ; Assumption correct?
                jnz     @f                  ; Yes, continue

                or      al, PCIC_INTER_CARDIO  ; Set I/O mode

@@:             mov     ah, al
                mov     al, PCIC_INTER
                call    SetReg

                pop     ax
                ret

asSetSktInterface ENDP

;*****************************************************************************
;*                         --- asSetSktMask ---
;*
;*     Purpose: Set Socket Status change interrupt Mask
;*       Input: [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*              SI   - Socket number
;*              AH   - Socket Mask
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 20.07.94
;*****************************************************************************
asSetSktMask    PROC    NEAR
                assume  ds:@data, es:Nothing
                pushx   <ax, cx>

; The Intel Status change bits match to the PCMCIA structure, except the
; fact, that SBM_ bits are located in the upper nibble and PCIC bits in the
; lower nibble

                mov     cl, 4               ; Move mask to the PCIC location
                shr     ah, cl

                mov     al, PCIC_SCINT      ; Get current SC level
                call    GetReg
                and     al, PCIC_SCINT_IRQ  ; AL = SCI level

                or      ah, al              ; Combine with new mask

                mov     al, PCIC_SCINT      ; Set new mask
                call    SetReg

                popx    <cx, ax>
                ret
asSetSktMask    ENDP

;*****************************************************************************
;*                             --- GetPower   ---
;*
;*     Purpose: Return Socket power levels
;*       Input: [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*              SI   - Socket number
;*      Output: ah   - Lower nibble - Vcc Level
;*              al   - Upper nibble - Vpp1 Level, Lower nibble - Vpp2 Level
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 07.06.94
;*****************************************************************************
GetPower        PROC    NEAR

                push    cx

                xor     cx, cx              ; Vcc = Vpp1 = Vpp2 = 0V

                mov     al, PCIC_POWER
                call    GetReg              ; Get Vcc Level

                test    al, PCIC_POWER_VCCMASK
                jnz     @f

                mov     ax, cx
                jmp     short scgp_done

@@:             mov     ah, al              ; Assume 5V Interface
                mov     al, 2

                push    ax
                and     ah, PCIC_POWER_VCCMASK
                cmp     ah, PCIC_POWER_VCC_5V
                pop     ax
                je      @f

                mov     al, 1               ; Switch to 3.3 volts

@@:             mov     ch, al              ; ch - Vcc, ah - PCIC_POWER

                mov     al, 3
                xchg    ah, al              ; al - Vpp1, ah - 12V Index

                and     al, PCIC_POWER_VPPMASK

                cmp     al, PCIC_POWER_VPPEQVCC
                mov     al, ch              ; Assume Vcc
                je      @f

                mov     al, cl              ; cl - 0V
                jb      @f

                mov     al, ah              ; 12V

@@:             mov     ah, al
                mov     cl, 4
                shl     al, cl
                or      al, ah              ; Vpp1 = Vpp2

                mov     ah, ch

scgp_done:      pop     cx

                ret
GetPower        ENDP

;*****************************************************************************
;*                              --- SetVcc   ---
;*
;*     Purpose: Set Vcc Value
;*       Input: [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*              ah   - Lower nibble - Vcc Level
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 20.07.94
;*****************************************************************************
SetVcc          PROC    NEAR

                pushx   <ax, dx>

                mov     dh, ah              ; dh - required Vcc
                mov     dl, 0               ; dl - Vcc = 0V

;--------------------------------- Swith off  ---------------------------------

                mov     al, PCIC_POWER
                call    GetReg

                and     al, NOT PCIC_POWER_VCCMASK      ; Disable Vcc
                mov     ah, al              ; ah - PCIC_POWER w/o Vcc
                xor     al, al

;--------------------------- Switch on, if required ---------------------------

                cmp     dh, dl              ; Switch on?
                je      @f                  ; No, keep off

                mov     al, PCIC_POWER_VCC_5V ; Assume 5V
                cmp     dh, 2               ; Assumption correct?
                je      @f

                mov     al, PCIC_POWER_VCC_3V

@@:             or      ah, al              ; Create Vcc Mask
                mov     al, PCIC_POWER      ; Set to the hardware
		call	SetReg
                popx    <dx, ax>
                ret
SetVcc          ENDP

;*****************************************************************************
;*                              --- SetVpp   ---
;*
;*     Purpose: Set Vpp Value
;*       Input: [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*              al   - Upper nibble - Vpp1 Level, Lower nibble - Vpp2 Level
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 20.07.94
;*****************************************************************************
SetVpp          PROC    NEAR

                pushx   <ax, dx>

                mov     dl, al
                mov     dh, 0               ; dh - Vcc = 0V


;--------------------------------- Switch off  --------------------------------

                mov     al, PCIC_POWER
                call    GetReg                  ; get other bits

                and     al, NOT PCIC_POWER_VPPMASK      ; Disable Vpp
                mov     ah, al              ; ah - PCIC_POWER w/o Vcc
                xor     al, al

;--------------------------- Switch on, if required ---------------------------

                and     dl, 0Fh             ; Anyway Vpp1 == Vpp2...
                cmp     dl, dh              ; Vpp = 0?
                je      @f                  ; Yes, we are done

                mov     al, PCIC_POWER_VPP_12V
                cmp     dl, 3               ; 12.0V?
                je      @f                  ; Yes, set it

                mov     al, PCIC_POWER_VPPEQVCC ; Otherwise Vcc == Vpp

@@:             or      ah, al              ; Create Vpp Mask
                mov     al, PCIC_POWER      ; Set to the hardware
		call	SetReg
                popx    <dx, ax>
                ret
SetVpp          ENDP

;*****************************************************************************
;*                            --- SoftReset   ---
;*
;*     Purpose: Perform Software reset of the socket
;*       Input: [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 20.07.94
;*****************************************************************************
SoftReset       PROC    NEAR
                assume  ds:@data, es:Nothing

                push    ax
                mov     al, PCIC_INTER
                call    GetReg              ; Get current value

                mov     ah, al              ; Turn Reset on
                and     ah, NOT PCIC_INTER_RESET

                mov     al, PCIC_INTER
                call    SetReg

                push    ax
                mov     ax, PCIC_RESET_PULSE
                call    couDelay            ; Wait a decent interval
                pop     ax

                or      ah, PCIC_INTER_RESET
                mov     al, PCIC_INTER
                call    SetReg

                mov     ax, RESET_WAIT      ; Let the card recover
                call    couDelay

                pop     ax

                ret
SoftReset       ENDP

;*****************************************************************************
;*                         --- GetSktChanges ---
;*
;*     Purpose: Return changes on socket since last SetSocket
;*       Input: AL   - Instantaneous socket state
;*              [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*              [SI] - Socket number
;*      Output: AL   - Changes of socket state
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 21.01.94
;*****************************************************************************
GetSktChanges   PROC   NEAR
                assume  ds:@data, es:Nothing

                mov     ah, (ADP_DATA PTR [BX])[SI].bInstState ; Get old state
                mov     (ADP_DATA PTR [BX])[SI].bInstState, al ; Save new state

                xor     ah, al              ; what's different between
                                            ; instantaneous and saved state?

                or      (ADP_DATA PTR [BX])[SI].bSktChanges, ah
                                            ; Collect changes into bSktChanges
                mov     ah, (ADP_DATA PTR [BX])[SI].bSktChanges
                                            ; ah - bSktChanges, al - State
                and     al, ah              ; ah = bSktChanges & State
                or      al, ah              ; ah = (bSktChanges & State) | bSktChanges

                ret
GetSktChanges   ENDP

;*****************************************************************************
;*                          --- GetAdapterCnt ---
;*
;*     Purpose: Return number of adapters supported
;*       Input: [BP] = Pointer to entry args on stack
;*      Output: Args.ALReg - bTotAdapters
;*              Args.CXReg - Socket Services signature ('SS')
;* Scratch reg: all
;*     Written: by Alexis A.Piatetsky 28.07.94
;*****************************************************************************
GetAdapterCnt   PROC    NEAR
                assume  ds:@data, es:Nothing

                mov     al, bTotAdapters
                mov     (ARGS PTR [BP]).ALReg, al
                mov     (ARGS PTR [BP]).CXReg, SS_SIGNATURE
                mov     ah, SUCCESS
                ret

GetAdapterCnt   ENDP

COMMENT ~*********************************************************************
        Procedure:      GetSSInfo
        Revision:       1
        Date:           05/25/1993
        Purpose:        Returns PCMCIA compliance level and supported adapters
        Entry:          [BP] = Pointer to entry args on stack
        Exit:           Args.ALReg = 0 (Backward compatible with Socket Services 1.01)
                        Args.BXReg = PCMCIA compliance level
                        Args.CLReg = First adapter serviced by this handler
                        Args.CHReg = Number of adapters serviced by this handler
*****************************************************************************~
GetSSInfo       PROC    NEAR
                assume  ds:@data, es:Nothing

                mov     (ARGS PTR [BP]).ALReg, 0
                mov     (ARGS PTR [BP]).BXReg, PCMCIA_LEVEL
                mov     al, bFirstAdapter
                mov     (ARGS PTR [BP]).CLReg, al
                mov     al, bNumAdapters
                mov     (ARGS PTR [BP]).CHReg, al
                mov     ah, SUCCESS
                ret
GetSSInfo       ENDP

COMMENT ~*********************************************************************
        Procedure:      GetVendorInfo
        Revision:       1
        Date:           05/25/1993
        Purpose:        Return vendor information
        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        Args.BLReg = Subfunction (Only zero supported)
                        [ES]:[DI] = Client-supplied buffer for Vendor string
        Exit:           Args.AHReg = Return Code
                        If (Args.BLReg NE 0)
                          Args.AHReg = BAD_FUNCTION
                        Else
                          Args.DXReg = Vendor's release number
                          Client-supplied buffer filled with Vendor ASCIIZ string
*****************************************************************************~
GetVendorInfo   PROC    NEAR
                assume  ds:@data, es:Nothing

                mov     AH, BAD_FUNCTION    ; Default to bad function
                cmp     (ARGS PTR [BP]).BLReg, 0        ; Recognized function ?
                jne     @f                  ; No, we're done

                mov     si, OFFSET VendorInfo           ; Point to source of
                                                        ; information

;-------------------- Get Length of the Vendor Info string --------------------

                push    es
                push    di

                push    ds
                pop     es
        assume  es:@data

                mov     di, si
                xor     al, al
                cld
                mov     cx, -1
        repne   scasb

                mov     cx, di
                sub     cx, si

                pop     di
                pop     es

;--------------------- Move the info to the client buffer ---------------------

                call    couCopyInfo

                add     di, es:[di]             ; Add length of buffer
                add     di, 4 - 1               ; Point past length bytes (less one)
                mov     byte ptr es:[di], 0     ; Make NULL terminate string

                mov     (ARGS PTR [BP]).DXReg, RELEASE_NUM
                mov     ah, SUCCESS
@@:             ret

GetVendorInfo   ENDP

COMMENT ~*********************************************************************

        Procedure:      AckInterrupt

        Purpose:        Acknowledge change and identify interupting socket(s)

        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array

        Exit:           Args.CXReg = Bit-map of sockets reporting status change

        Note:           This function is typically called within an interrupt
                        handler and must not enable interrupts.  It is also
                        responsible for resetting the adapter hardware so that
                        it can generate future status change interrupts

*****************************************************************************~

AckInterrupt    PROC    NEAR
                assume  ds:@data, es:Nothing

                xor     ch, ch                  ; Prepare loop counter
                mov     cl, (ADP_DATA PTR [BX]).bNumSockets

                mov     dh, 1                   ; SKTBITS Start with Socket 0
                xor     dl, dl                  ; SKTBITS Holder

                xor     si, si                  ; Start from Socket 0

CheckNextSkt:   mov     ax, si
                mov     (ARGS PTR [BP]).bSocketNum, al
                push    cx
                mov     cl, PCIC_SKTINC
                mul     cl
                mov     (ARGS PTR [BP]).bSocketIdx, al
                pop     cx

                mov     al, PCIC_STATE
                call    GetReg                  ; Reading will clear all bits
                                                ; (for acknowledge purposes only
                                                ; We will get the real status)
                                                ; change later.

                call    GetInstSktState         ; AL - New Instantineous state
                xor     al, (ADP_DATA PTR [BX])[SI].bInstState
                                                ; Compare with saved value
                and     al, (ADP_DATA PTR [BX])[SI].bSCIRQMask
                                                ; Report only what user asked
                                                ; for
                or      al, al                  ; Any Change Bits Active?
                je      short @f                ; No Change, Continue.


; ----- Yes. Rewrite Status to Local Variable

                or      dl, dh                  ; Mark Socket as changed

@@:
                shl     dh, 1                   ; Advance Socket Mask
                inc     si                      ; Advance Socket Number
                loop    CheckNextSkt

                xor     dh, dh
                mov     (ARGS PTR [BP]).CXReg, dx
                mov     ah, SUCCESS
                ret

AckInterrupt    ENDP

COMMENT ~*********************************************************************
        Procedure:      InquireAdapter
        Revision:       1
        Date:           05/25/1993
        Purpose:        Return adapter capabilities and power management tables
        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        [ES]:[DI] = Client-supplied buffer for characteristics
        Exit:           Args.BHReg = Number of windows supported by adapter
                        Args.BLReg = Number of sockets supported by adapter
                        Args.CXReg = Number of EDCs supported by adapter
                        Client-supplied buffer filled with adapter characteristics
*****************************************************************************~
InquireAdapter  PROC    NEAR
                assume  ds:@data, es:Nothing

                mov     cx, AdapterInfoLen      ; Get length of adapter information
                mov     si, OFFSET AdapterInfo  ; Point to source of information
                call    couCopyInfo             ; Copy information that fits into buffer

;------------------------ Return adapter specific data  -----------------------

                mov     al, (ADP_DATA PTR [BX]).bNumWindows
                mov     (ARGS PTR [BP]).BHReg, al
                mov     al, (ADP_DATA PTR [BX]).bNumSockets
                mov     (ARGS PTR [BP]).BLReg, al
                mov     ax, (ADP_DATA PTR [BX]).wNumEDCs
                mov     (ARGS PTR [BP]).CXReg, ax
                mov     ah, SUCCESS
                ret

InquireAdapter  ENDP

COMMENT ~*********************************************************************
        Procedure:      InquireSocket
        Revision:       1
        Date:           05/25/1993
        Purpose:        Return socket capabilities
        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        [ES]:[DI] = Client-supplied buffer for characteristics
        Exit:           Args.BHReg = Status change interrupt capabilities (set = true)
                        Args.DHReg = Status change reporting capabilities (set = true)
                        Args.DLReg = Control and indicator capabilities (set = true)
                        Client-supplied buffer filled with socket characteristics
*****************************************************************************~
InquireSocket   PROC    NEAR
                assume  ds:@data, es:Nothing

                mov     cx, SocketInfoLen       ; Get length of socket information
                mov     si, OFFSET SocketInfo   ; Point to source of information
                call    couCopyInfo
                mov     al, SocketCaps.SCIntCaps
                mov     (ARGS PTR [BP]).BHReg, al
                mov     al, SocketCaps.SCRptCaps
                mov     (ARGS PTR [BP]).DHReg, al
                mov     al, SocketCaps.SCIndCaps
                mov     (ARGS PTR [BP]).DLReg, al
                mov     ah, SUCCESS
                ret
InquireSocket   ENDP



;*****************************************************************************
;*                           --- SetSktPower ---
;*
;*     Purpose: Set Power levels
;*       Input: AH   = Lower nibble - Vcc Level
;*              AL   = Upper nibble - Vpp1 Level, Lower nibble - Vpp2 Level
;*              [BP] = Pointer to entry args on stack
;*              [BX] = Pointer to adapter entry in Adapters array
;*      Output: none
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 12.06.94
;*****************************************************************************
SetSktPower     PROC    NEAR
                assume  ds:@data, es:Nothing

                pushx   <cx, dx>
                mov     cx, ax

                mov     dl, 0               ; Index of 0.0V

                call    GetPower            ; Get current power levels
                                            ; Get required power level
                cmp     ah, ch              ; Any change to Vcc?
                je      ss_set_vpp          ; No changes required

                cmp     ah, dl              ; Power go from on to off?
                jne     @f                  ; Yes, skip next

                ; Power is off and being switched on - requires 5V to Vcc,
                ; Vpp1 and Vpp2

                ; Deassert output to PC Card

                mov     al, PCIC_POWER
                call    GetReg

                and     al, NOT PCIC_POWER_ENOUTPUT
                mov     ah, al

                mov     al, PCIC_POWER
                call    SetReg

                mov     al, PCIC_INTER
                call    GetReg

                ; No reset at initial Output Enable after power on

                or      al, PCIC_INTER_RESET
                mov     ah, al              ; Disable RESET condition

                mov     al, PCIC_INTER
                call    SetReg

                mov     ax, 0222h           ; Set all to 5 volts

                push    ax                  ; Save Power levels

; On IBM Thinkpad 750Cs machine setting of PCIC_POWER to default values causes
; cross-talk to PIC (programmable Interrupt Controller), that result in issue
; of random hardware IRQ. We try to prevent this by disabling of INT's during
; the switch
                pushf                       ; Save state of Interrupt flag
                cli                         ; Disable interrupts
                call    SetVcc
                call    SetVpp

                mov     ax, POWER_DEAD_TIME
                call    couDelay

                popf                        ; Restore interrupt state

                mov     ax, POWERON_WAIT
                call    couDelay

;-------------------------------- Enable Output -------------------------------

                mov     al, PCIC_POWER
                call    GetReg

                or      al, PCIC_POWER_ENOUTPUT
                mov     ah, al

                mov     al, PCIC_POWER
                call    SetReg

;----------------------- Generate soft reset to PC Card -----------------------

                call    SoftReset

                pop     ax                  ; Restore power levels

;------------------------------- Set Correct Vcc ------------------------------

@@:             cmp     ah, ch              ; Change to Vcc?
                je      ss_set_vpp          ; No, skip next

                push    ax
                mov     ah, ch              ; Take new level
                pushf                       ; Save state of Interrupt flag
                cli                         ; Disable interrupts
                call    SetVcc

                mov     ax, POWER_DEAD_TIME
                call    couDelay

                popf                        ; Restore interrupt state
                pop     ax

;------------------------------- Set correct Vpp ------------------------------

ss_set_vpp:     cmp     al, cl              ; Any change to Vpp?
                je      @f                  ; No, skip next

                mov     al, cl              ; Take new level
                pushf                       ; Save state of Interrupt flag
                cli                         ; Disable interrupts
                call    SetVpp

                mov     ax, POWER_DEAD_TIME
                call    couDelay

                popf                        ; Restore interrupt state

                mov     ax, PROG_POWER_WAIT ; Wait 100 ms
                call    couDelay

;------------------------ Assert correct initialisation -----------------------

@@:             cmp     ch, dl              ; Vcc enabled on card?
                jne     @f                  ; Yes, skip next

                mov     al, PCIC_POWER      ; Deassert output
                call    GetReg

                and     al, NOT PCIC_POWER_ENOUTPUT
                mov     ah, al

                mov     al, PCIC_POWER
                call    SetReg

                mov     al, PCIC_INTER
                call    GetReg

                or      al, PCIC_INTER_RESET
                mov     ah, al              ; Disable RESET condition

                mov     al, PCIC_INTER
                call    SetReg

@@:             mov     ax, cx              ; Restore AX value
                popx    <dx, cx>            ; Restore CX, DX values
                ret
SetSktPower     ENDP

COMMENT ~*********************************************************************
        Procedure:      GetSocket
        Revision:       7
        Date:           09/30/1993
        Purpose:        Return current socket configuration
        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        Args.BLReg = Socket Number
        Exit:           Args.BHReg = Status change interrupt mask (set = enabled)
                        Args.CHReg = Lower nibble - Vcc Level
                        Args.CLReg = Upper nibble - Vpp1 Level, Lower nibble - Vpp2 Level
                        Args.DHReg = Socket state (set = true)
                        Args.DLReg = Control and indicator state (set = true)
                          Bit 0..4 = IRQ Level and Interface Type
                          Bit 5    = Level (reset = active low, set = active high)
                          Bit 7    = State (reset = disabled, set = enabled)
                          Bit 8    = Memory-only interface
                          Bit 9    = I/O and memory interface
                          All other bits reserved and are reset to zero (0)
*****************************************************************************~
GetSocket       PROC    NEAR
                assume  ds:@data, es:Nothing

;---------------------- Get Status Change Interrupt mask ----------------------

                xor     ah, ah
                mov     al, (ARGS PTR [BP]).bSocketNum
                mov     si, ax              ; Setup pointer to socket status

                mov     al, (ADP_DATA PTR [BX])[SI].bSCIRQMask
                mov     (ARGS PTR [BP]).BHReg, al   ; Return SCIRQ Mask

;------------------------------ Get Power levels ------------------------------

                call    GetPower
                mov     (ARGS PTR [BP]).CXReg, ax

;------------------ Get Socket State and socket changed state -----------------

                call    GetInstSktState         ; al - Inst. socket state
                call    GetSktChanges           ; al - Socket changes

                mov     (ARGS PTR [BP]).DHReg, al

;----------------------- Get control and indicator state ----------------------

                mov     al, (ADP_DATA PTR [BX]).bCntrlInd
                mov     (ARGS PTR [BP]).DLReg, al

;----------------- Get current IRQ routing and interface type -----------------

                mov     ah, (ADP_DATA PTR [BX])[SI].bSktIFType
                mov     al, (ADP_DATA PTR [BX])[SI].bSktIRQLevel
                mov     (ARGS PTR [BP]).DIReg, ax

                mov     ah, SUCCESS
                ret

GetSocket       ENDP

COMMENT ~*********************************************************************

        Procedure:      GetStatus

        Purpose:        Return current PC Card and socket status

        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        Args.ALReg = Adapter Number
                        Args.BLReg = Socket Number

        Exit:           Args.BHReg = Current card state (set = true)
                        Args.DHReg = Socket state (set = true)
                        Args.DLReg = Control and indicator state (set = true)
                        Args.DIReg = IFType (hi byte) IREQRoute (lo byte)
*****************************************************************************~

GetStatus       PROC    NEAR
                assume  ds:@data, es:Nothing

                xor     ah, ah
                mov     al, (ARGS PTR [BP]).bSocketNum
                mov     si, ax                  ; si to contain socket number

;-------------------------- Get current PC Card state -------------------------

                call    GetInstSktState         ; al - Inst. state
                mov     (ARGS PTR [BP]).BHReg, al

;-------------------------- Get latched socket state --------------------------

                call    GetSktChanges           ; al - Socket changes
                mov     (ARGS PTR [BP]).DHReg, al

;----------------------- Get control and indicator state ----------------------

                mov     al, (ADP_DATA PTR [bx]).bCntrlInd
                mov     (ARGS PTR [BP]).DLReg, al

;------------------------- Get IREQRouting and IFType -------------------------

                mov     ah, (ADP_DATA PTR [BX])[SI].bSktIFType
                mov     al, (ADP_DATA PTR [BX])[SI].bSktIRQLevel
                mov     (ARGS PTR [BP]).DIReg, ax

                mov     ah, SUCCESS
                ret
GetStatus       ENDP

COMMENT ~*********************************************************************
        Procedure:      SetSocket
        Revision:       16
        Date:           09/30/1993
        Purpose:        Configure socket
        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        Args.BLReg = Socket Number
                        Args.BHReg = Status change interrupt mask (set = enabled)
                        Args.CHReg = Lower nibble - Vcc Level
                        Args.CLReg = Upper nibble - Vpp1 Level, Lower nibble - Vpp2 Level
                        Args.DHReg = Socket state (set = true)
                        Args.DLReg = Control and indicator state (set = true)
                        Args.DIReg = I/O IREQ Routing and IFType
                          Bit 0..4 = IRQ Level
                          Bit 6    = Level (reset = active low, set = active high)
                          Bit 7    = State (reset = disabled, set = enabled)
                          Bit 8    = Memory-only interface
                          Bit 9    = I/O and memory interface
                          All other bits reserved and are reset to zero (0)
        Exit:           Args.AHReg = Return Code
*****************************************************************************~

SetSocket       PROC    NEAR
                assume  ds:@data, es:Nothing

;---------------------------- Validate power levels ---------------------------

                mov     ax, (ARGS PTR [BP]).CXReg
                call    covValidatePw
                jc      ss_exit

;------------------------ Validate IFType and IRQ Level -----------------------

                mov     si, offset SocketInfo
                mov     ax, (ARGS PTR [BP]).DIReg
                call    covValidateIFt
                jc      ss_exit

;------- If set default IRQ, do it, even if IRQ isn't in capability mask ------

                mov     cl, PCIC_DEF_IRQ
                push    ax
                and     al, (P_IRQ15 OR IRQ_HIGH)
                and     cl, (P_IRQ15 OR IRQ_HIGH)
                cmp     al, cl
                pop     ax
                je      @f

                call    covValidateIRQ
                jc      ss_exit

;----------------------------- Prepare Set Socket -----------------------------

@@:             push    ax                  ; Save IFType & IRQ
                xor     ah, ah
                mov     al, (ARGS PTR [BP]).bSocketNum
                mov     si, ax              ; si to contain socket number
                pop     ax                  ; Restore IFType & IRQ

;---------------------------- Set Socket Interface ----------------------------

                mov     (ADP_DATA PTR [BX])[SI].bSktIFType, ah
                call    asSetSktInterface

;------------------------------- Set Socket IRQ -------------------------------

                test    ah, IF_MEMORY       ; Memory Only Interface?
                jz      @f                  ; No, I/O

                ; Disable set IREQ routing with appropriate interface type
                and     al, NOT IRQ_ENABLED

@@:             cmp     al, (ADP_DATA PTR [BX])[SI].bSktIRQLevel ; New IRQ?
                je      short @f                ; No, continue

                ; New IRQ level requested, change in local variable.

                mov     (ADP_DATA PTR [BX])[SI].bSktIRQLevel, al
                call    asSetSktIRQ

;------------------------------ Set the SCIRQMask -----------------------------

@@:             mov     ah, (ARGS PTR [BP]).BHReg
                mov     (ADP_DATA PTR [BX])[SI].bSCIRQMask, ah
                call    asSetSktMask

;------------------------- Set Control and Indicators -------------------------

                mov     ah, (ARGS PTR [BP]).DLReg
                mov     (ADP_DATA PTR [BX]).bCntrlInd, ah

;---------------------------- Reset specified bits ----------------------------

                mov     al, (ARGS PTR [BP]).DHReg

                not     al                  ; Update socket changes mask
                and     (ADP_DATA PTR [BX])[SI].bSktChanges, al

;------------------------------ Set Socket Power ------------------------------

                mov     ax, (ARGS PTR [BP]).CXReg
                call    SetSktPower

                mov     ah, SUCCESS
ss_exit:        ret

SetSocket       ENDP

COMMENT ~*********************************************************************

        Procedure:      ResetSocket

        Purpose:        Reset PC Card Scoket

        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        Args.ALReg = Adapter Number
                        Args.BLReg = Socket Number
        Exit:           Args.AHReg = Return Code

*****************************************************************************~

ResetSocket     PROC    NEAR
                assume  ds:@data, es:Nothing


;----------------------- Disable status change interrupt ----------------------

                xor     ah, ah              ; Set empty mask
                call    asSetSktMask

;---------------- Disable windows currently assigned to socket ----------------

                mov     cl, (ADP_DATA PTR [BX]).bNumWindows
                xor     ch, ch
                mov     dl, (ARGS PTR [BP]).bSocketNum ; Protect important
                mov     dh, (ARGS PTR [BP]).bSocketIdx ; values

                xor     al, al              ; Start from window 0

es_diswin:      call    CalcWndIndex        ; Calculate Window Index

                cmp     dl, (ARGS PTR [BP]).bSocketNum  ; Our Socket?
                jne     es_diswin_next

                pushx   <ax, cx>
                mov     al, (ARGS PTR [BP]).bSocketNum
                mov     cl, PCIC_SKTINC
                mul     cl
                mov     (ARGS PTR [BP]).bSocketIdx, al
                popx    <cx, ax>

                call    cowIsWinEnabled     ; Window enabled?
                jz      es_diswin_next      ; No, continue

                call    cowDisableWindow    ; Disable Window

es_diswin_next: inc     al
                loop    es_diswin

                mov     (ARGS PTR [BP]).bSocketNum, dl  ; Restore important
                mov     (ARGS PTR [BP]).bSocketIdx, dh  ; values

;----------------------- Put default power to the socket ----------------------

                push    (ARGS PTR [BP]).AXReg   ; Save Stack frame
                push    (ARGS PTR [BP]).BXReg
                push    (ARGS PTR [BP]).CXReg
                push    (ARGS PTR [BP]).DXReg
                push    (ARGS PTR [BP]).DIReg

                call    GetSocket

                mov     ax, 0222h           ; Initialize socket power up
                MOV     (ARGS PTR [BP]).CXReg, ax               ; to 5V
                AND     (ARGS PTR [BP]).DIReg, NOT IRQ_ENABLED  ; Disable IRQ
                MOV     (ARGS PTR [BP]).DHReg, 0 ; Keep Socket changes mask in
                                                 ; case SC Interrupt occured
                                                 ; but not treated yet
                call    SetSocket

                pop     (ARGS PTR [BP]).DIReg   ; Restore stack frame
                pop     (ARGS PTR [BP]).DXReg
                pop     (ARGS PTR [BP]).CXReg
                pop     (ARGS PTR [BP]).BXReg
                pop     (ARGS PTR [BP]).AXReg

;-------------------------------- Perform reset -------------------------------

                call    SoftReset

;--------------------- Set Socket Interface to Memory Only --------------------

                xor     ah, ah
                mov     al, (ARGS PTR [BP]).bSocketNum
                mov     si, ax              ; Setup pointer to socket status
                mov     ah, IF_MEMORY
                mov     (ADP_DATA PTR [BX])[SI].bSktIFType, ah
                call    asSetSktInterface

;------------------ Restore Status Change Interrupt IRQ value -----------------

                mov     ah, (ADP_DATA PTR [bx]).bSCIRQMask
                call    asSetSktMask

                mov     ah, SUCCESS         ; Report success
                ret

ResetSocket     ENDP

;*****************************************************************************
;*                        --- GetInstSktState   ---
;*
;*     Purpose: Return Instantaneous socket state
;*       Input: [BX] - Pointer to the adapter structure
;*              [BP] - Pointer to the user args
;*      Output: AL   - Instantaneous socket state
;* Scratch reg: none
;*     Written: by Alexis A.Piatetsky 21.01.94
;*****************************************************************************
GetInstSktState PROC NEAR
                assume  ds:@data, es:Nothing

                pushx   <cx, dx>

;----------------------------- Get Current Status -----------------------------

                mov     al, PCIC_IFSTAT
                call    GetReg              ; Read Interface Status Register

;------------------------------- Battery detect -------------------------------

                push    ax                  ; Mask battery bits out
                not     al
                and     al, PCIC_IFSTAT_BVDMASK

                mov     cl, 4               ; Move battery bits to the right
                shl     al, cl              ; position

                mov     dl, al              ; Store to accumulator. Clear
                pop     ax                  ; all other bits

;-------------------- Card detect and write protect detect --------------------

                push    ax                  ; Mask card detect bits
                and     al, PCIC_IFSTAT_CDMASK
                cmp     al, PCIC_IFSTAT_CDMASK
                jne     @f                  ; No card inserted

                or      dl, SBM_CD          ; Card Inserted

@@:             pop     ax

;-------------------------------- Write protect -------------------------------

                test    al, PCIC_IFSTAT_WP  ; Write protected?
                jz      @f                  ; No, continue

                or      dl, SBM_WP          ; Yes, report it

;--------------------------------- Ready/Busy ---------------------------------

@@:             test    al, PCIC_IFSTAT_RDYBSY  ; Card is ready?
                jz      @f                  ; No, continue

                or      dl, SBM_RDYBSY      ; Yes, indicate ready

@@:             mov     al, dl              ; Return result in al
                popx    <dx, cx>
                ret
GetInstSktState ENDP

COMMENT ~*********************************************************************
        Procedure:      GetAdapter
        Revision:       2
        Date:           05/25/1993
        Purpose:        Return current adapter configuration
        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
        Exit:           Args.AHReg = Return Code
                        Args.DHReg = Adapter state
                          Bit 0    = Reduced Power Consumption (Sleep Mode)
                          Bit 1    = State Information Preserved
                          All other bits reserved and are reset to zero (0)
                        Args.DIReg = Status Change Interrupt (SCI) State
                          Bit 0..4 = SCI IRQ Level
                          Bit 5    = SCI Level (reset = active low, set = active high)
                          Bit 7    = SCI State (reset = disabled, set = enabled)
                          All other bits reserved and are reset to zero (0)
*****************************************************************************~
GetAdapter      PROC    NEAR


;-------------------------------- Report status -------------------------------

                mov     (ARGS PTR [BP]).DHReg,0 ; Initialise variable

                xor     ah, ah          ; Returned saved IRQ state
                mov     al, (ADP_DATA PTR [BX]).bSCIRQLevel

                mov     (ARGS PTR [BP]).DIReg, AX
                ret

GetAdapter      endp


COMMENT ~*********************************************************************
        Procedure:      SetAdapter
        Revision:       7
        Date:           09/15/1993
        Purpose:        Configure adapter
        Entry:          [BP] = Pointer to entry args on stack
                        [BX] = Pointer to adapter entry in Adapters array
                        Args.ALReg = Adapter Number
                        Args.DHReg = Adapter Control
                          Bit 0    = Reduce Power Consumption (set = true)
                          Bit 1    = Preserve state information when power reduced
                          All other bits are reserved
                        Args.DIReg = Status Change Interrupt Control
                          Bit 0..4 = SCI IRQ Level
                          Bit 5    = SCI Active Level (reset = low, set = high)
                          Bit 7    = SCI State (reset = disabled, set = enabled)
                          All other bits reserved and are reset to zero (0)
        Exit:           Args.AHReg = Return Code
                        If SCI IRQ Level and Active Level are valid
                          Args.AHReg = SUCCESS
                          SCI set as requested for all sockets on adapter
                        Else
                          Args.AHReg = BAD_IRQ
        Notes:          SCI IRQ Level and SCI Active Level fields are validated
                        whether SCI state is enabled or disabled
                        If SCI request matches current setting, hardware is
                        not rewritten
                        SCI setting is shadowed in RAM.  PCIC requires routing
                        hardware be set to zero (0) to disable interrupt, losing
                        IRQ level.
                        PCIC does not support power management.
*****************************************************************************~
SetAdapter      PROC    NEAR

;---------------------------- Check SC IRQ request ----------------------------

                mov     ax, (ARGS PTR [bp]).DIReg   ; Get IRQ requested

                mov     si, offset AdapterInfo

;------- If set default IRQ, do it, even if IRQ isn't in capability mask ------

                mov     di, PCIC_DEF_SCIRQ
                mov     cx, di
                push    ax
                and     al, (P_IRQ15 OR IRQ_HIGH)
                and     cl, (P_IRQ15 OR IRQ_HIGH)
                cmp     al, cl
                pop     ax
                je      @f

                call    covValidateIRQ      ; Is IRQ valid?
                jc      saExit              ; No, exit now

;---------- Request is valid, save it locally and initialize hardware ----------

@@:             mov     ah, al
                mov     (ADP_DATA PTR [BX]).bSCIRQLevel, ah ; Save new setting

; Do for all sockets

                mov     cl, (ADP_DATA PTR [BX]).bNumSockets

saLoop:         dec     cl

                mov     (ARGS PTR [bp]).bSocketNum, cl
                pushx   <ax, cx>
                mov     al, cl
                mov     cl, PCIC_SKTINC
                mul     cl
                mov     (ARGS PTR [BP]).bSocketIdx, al
                popx    <cx, ax>

                push    ax                  ; Save IRQ settings
                and     al, P_IRQ15         ; Mask IRQ level
                push    cx                  ; Save socket number counter
                mov     cl, 4               ; Shift to the right position
                shl     al, cl
                mov     ah, al
                pop     cx                  ; Restore socket number counter

                mov     al, PCIC_SCINT      ; Set a new value of IRQ
                call    SetReg              ; (Clear Socket Status Change
                                            ;  interrupt mask)

                pop     ax                  ; Restore IRQ settings

                test    al, IRQ_ENABLED
                jz      @f

                push    ax
                mov     ah, (ADP_DATA PTR [bx]).bSCIRQMask
                call    asSetSktMask
                pop     ax

@@:             inc     cl                  ; Restore Socket counter
                loop    saLoop


                mov     ah, SUCCESS         ; Indicate success

saExit:         ret

SetAdapter      ENDP

sEnd            ResCode

                END
