Metropoli BBS
VIEWER: gus.asm MODE: TEXT (CP437)
;--------------------------------------------------------------------------;
;    DOS32    32BIT  DOS  EXTENDER  LIBRARY  Gravis Ultrasound Routines    ;
;                                                                          ;
; Written by Adam Seychell                                                 ;
;                                                                          ;
;                                                                          ;
;  Last modified    1st September 1995                                         ;
;                                                                          ;
;--------------------------------------------------------------------------;
; Note  The "GF1" is the Ultrasounds programable Synthesizer chip for the
;  32 multi-timbral digital 16bit CD quality voices with independed volume
;  ramping, panning and smapling rate.
;
.386
.Model flat , C
.Code


Include GUS.INC                       ; Define all the publics symbols


outp    MACRO port,value
        mov     al,value
        mov     edx,dword ptr port
        out     dx,al
ENDM

FALSE    equ    0
TRUE     equ     1


;╒═════════════════════════════════════════════════════════════════════════╕
;│           THE GRAVIS UILTRASOUND PORT ADDRESS VARIBLES                  │
;│                                                                         │
;│  These 12 data vaibles below contian the ultrasounds port addresses.    │
;│  See the SDK for what each port does. These varibles will be initalized │
;│  on the first successful call to the Ultrasound_Reset routine in this   │
;│  library.                                                               │
;│  * Do not use these port address varibles until they are initalized as  │
;│  otherwise they will contian wrong values.                              │
;└─────────────────────────────────────────────────────────────────────────┘
align 4
    The_Ultrasound_port_Addresses                               LABEL dword
gf1_voice_select        dw  102h        ; GF1 Synthesizer
gf1_reg_select          dw  103h
gf1_data_low            dw  104h
gf1_data_high           dw  105h
gf1_irq_status          dw  006h
gf1_dram                dw  107h
gf1_timer_ctrl          dw  008h
gf1_timer_data          dw  009h
midi_control            dw  100h        ; MIDI Interface
midi_data               dw  101h
mix_control             dw  000h        ; BOARD CONTROL ONLY
irqdma_ctrl             dw  00Bh
Ultrasound_ports_ends                                          LABEL dword







dma_reg_list            db  0,1,0,2,0,3,4,5
irq_reg_list            db  0,0,1,3,0,2,0,4,0,0,0,5,6,0,0,7
GUS_base_port           dw  0h
ULTRASND_string         db 'ULTRASND='
GUSdetected_flag        db  0


;╒═════════════════════════════════════════════════════════════════════════╕
;│           GET THE DEFAULT SETTING OF THE GRAVIS UILTRASOUND             │
;│                                                                         │
;│                                                                         │
;│  Looks for the environment varible "ULTRASND" for the default settings  │
;│  of the Ultrasound.                                                     │
;│                                                                         │
;│   IN:  nothing                                                          │
;│                                                                         │
;│  OUT:   Carry is set if couldn't find environment or it has invalid     │
;│         settings.                                                       │
;│                                                                         │
;│         Otherwise the carry flag is cleared and;                        │
;│      BL = GF1  IRQ number  ( IRQ is either 0,2,3,5,7,11,12 or 15 )      │
;│      BH = MIDI IRQ number                                               │
;│      CL = DMA Playback channel  ( DMA is either 0,1,3,5,6 or 7 )        │
;│      CH = DMA Record channel                                            │
;│      DX = Port Address ( 210h,220h,230h,240h,250h or 260h )             │
;│                                                                         │
;└─────────────────────────────────────────────────────────────────────────┘
GetUltraConfig PROC

local   Base_port       :WORD
local   dma_control     :BYTE
local   irq_control     :BYTE

        push     Eax
        push     Edi
    ;
    ; Search for the string "ULTRASND="  in the environment area
    ;
        Mov     Ax,0EE02h
        Int     31h                             ; Returns EDI -> environment
        cld
Loop_Envir:
        Cmp     Dword Ptr [edi],'RTLU'
        jne  @Jn90
        Cmp     Dword Ptr [edi+4],'DNSA'
        je   Found_string
@Jn90:  xor     al,al
        repne   scasb
        cmp     byte ptr [edi],0
        jne  Loop_Envir
        jmp  No_ULTRASND


Found_string:

        add     edi,9                  ; EDI -> first char of string
        mov     ebx,[edi]              ; OK, Found the string 'ULTRASND'
        mov     eax,ebx                ; check for the valid paramters
        and     ebx,0ffff00ffh
        cmp     ebx,02C300032h         ; '2x0,'
        jne  No_ULTRASND
        shr     eax,8
        call    get_digit               ; eax = char digit in al
        mov     DX,ax                   ; load port address
        shl     edx,4
        add     dx,200h
        sub     al,1h          ; port must be between  210h .. 260h
        cmp     al,5h
        ja  No_ULTRASND
        add     edi,4

                        ;*****  Get playback DMA channel ****
        xor     ecx,ecx
        mov     al,[edi]
        call    get_digit
        cmp     dma_reg_list[eax],0
        je  No_ULTRASND
        mov     CL,AL
        inc     edi
        cmp     byte ptr [edi],','
        jne  No_ULTRASND

                        ;*****  Get record DMA channel  ****
        inc     edi
        mov     al,[edi]
        call    get_digit
        cmp     dma_reg_list[eax],0
        je  No_ULTRASND
        mov     CH,AL
        inc     edi
        cmp     byte ptr [edi],','
        jne  No_ULTRASND

                    ; **** Get IRQ numnber GF1 ****
        xor     ebx,ebx
        inc     edi
        cmp     byte ptr [edi],'1'
        jne J61
          mov    BL,10
          inc    edi
J61:    mov     al,[edi]
        call    get_digit
        add     al,bl
        cmp     al,15
        ja  No_ULTRASND
        cmp     irq_reg_list[eax],0     	; check for valid IRQ number
        je  No_ULTRASND
        mov     BL,AL
        inc     edi
        cmp     byte ptr [edi],','
        jne  No_ULTRASND

                     ;  **** Get MIDI IRQ numnber *****

        inc     edi
        cmp     byte ptr [edi],'1'
        jne J62
         mov    BH,10
         inc    edi
J62:     mov     al,[edi]
        call    get_digit
        add     al,bh
        cmp     al,15
        ja  No_ULTRASND
        cmp     irq_reg_list[eax],0     	; check for valid IRQ number
        je  No_ULTRASND
        mov     BH,AL
                                                ;CHECK FOR STRING ENDING
        inc     edi
        cmp     byte ptr [edi],','
        je got_it
        cmp     byte ptr [edi],' '
        je got_it
        cmp     byte ptr [edi],0
        jne  No_ULTRASND

got_it:
        clc
        Pop    Edi
        Pop    Eax
        ret


No_ULTRASND:
        stc
        Pop    Edi
        Pop    Eax
        ret


get_digit:
        sub     al,'0'
        jc No_digi
        cmp     al,9
        ja No_digi
        movzx   eax,al
        ret 0
No_digi:
        add     esp,4   ; ignore pushed EIP
        stc
        Pop    Edi
        Pop    Eax
        ret

GetUltraConfig ENDP





comment %
╒══════════════════════════════════════════════════════════════════════════╕
│    COMPLETELY RESET THE GRAVIS ULTRASOUND                                │
│                                                                          │
│                                                                          │
│ INPUT:                                                                   │
│       BL = GF1  IRQ number  ( IRQ must be 0,2,3,5,7,11,12 or 15 )        │
│       BH = MIDI IRQ number                                               │
│       CL = DMA Playback channel  ( DMA must be 0,1,3,5,6 or 7 )          │
│       CH = DMA Record channel                                            │
│       DX = Base port address of the Ultrasound ( must be 2x0h )          │
│                                                                          │
│                                                                          │
│ OUTPUT:                                                                  │
│    The function will fail if an illeagal DMA or IRQ number is selected   │
│    and/or if the card has was not detected at the specified bass address │
│                                                                          │
│      If function successful the carry is cleared and                     │
│       the card is fully reset and all 32 voices are initalised           │
│       EDI = DRAM installed on the ultrasound                             │
│                                                                          │
│ Other registers of the GF1 are set as follows                            │
│        LINE OUT enabled                                                  │
│        MIC  IN  disabled                                                 │
│        LINE IN  disabled                                                 │
│                                                                          │
│NOTES:                                                                    │
│     o    This routine will probe the ultrasound on port address DX       │
│     o    This function should only need to be used once by your program. │
│     o    Both PICs ( 8259's ) mask registers might be modified.          │
│     o    If the IRQ number is ZERO then the Ultrasound is programmed     │
│          with that IRQ disabled.                                         │
│     o    If the DMA channel is ZERO then the Ultrasound is programmed    │
│          with that DMA disabled.                                         │
│     o    EDI will contain the amount of RAM ( in bytes ) installed on the│
│           Ultrasound however it dos not do a complete RAM test. It will  │
│           always return 0KB, 256KB ,512KB, 768KB or 1024KB.              │
│                                                                          │
└───────────────────────────────────────────────────────────────────────── %
Ultrasound_Reset PROC

local   dma_control     :BYTE
local   irq_control     :BYTE
local   gf1             :Byte
local   midi            :Byte
local   dram            :Byte
local   adci            :Byte
local   gus_dram_size   :Dword


        pushad

        cmp     GUSdetected_flag, 0            ; Don't detect if a GUS has
        jne @@skip_detection                   ; already been detected.


     ;
     ; check if DX = 2x0h.  where x = 1,2,3,4,5,,,F
     ;
        mov     eax,edx
        and     ax,0F0Fh
        cmp     ax,0200h
        jne  invalid_setting
        mov     al,dl
        and     al,0F0h
        jz  invalid_setting

        call    Ultrasound_Probe          ; See if there's an ultrasound
        jc  invalid_setting


@@skip_detection:

        and     bx,0f0fh
        and     cx,0707h
        mov     gf1,bl              ; Save IRQ's
        mov     midi,bh

     ;****   convert IRQ numbers into register value   *****
                movzx   edx,bl
                and     dl,dl
                jz  Zero_irq1
                mov     dl,irq_reg_list[edx]
                and     dl,dl
                jz  invalid_setting
Zero_irq1:      mov     irq_control,dl

                movzx   edx,bh
                and     dl,dl
                jz  Zero_irq2
                mov     dl,irq_reg_list[edx]
                and     dl,dl
                jz  invalid_setting
                shl     dl,3
Zero_irq2:      or      irq_control,dl

                cmp     bh,bl                        ; Chech if both IRQ
                jne diff_irqs                        ;   are equal then
                and     bl,bl                       ;( Except when zero)
                jz  diff_irqs
                and     irq_control,0111b            ; Clear Channel 2 IRQ
                or      irq_control,40h              ; and turn on bit 6
diff_irqs:

     ;****   convert DMA number into register value   *****
                movzx   edx,cl
                and     dl,dl
                jz  Zero_dma2
                mov     dl,dma_reg_list[edx]
                and     dl,dl
                jz  invalid_setting
Zero_dma1:      mov     dma_control,dl

                movzx   edx,ch
                and     dl,dl
                jz  Zero_dma2
                mov     dl,dma_reg_list[edx]
                and     dl,dl
                jz  invalid_setting
                shl     dl,3
Zero_dma2:      or      dma_control,dl

                cmp     ch,cl                        ; Chech if both DMAs
                jne diff_dmas                        ;   are equal then
                and     cl,cl                       ;( Except when zero)
                jz  diff_irqs
                and     dma_control,0111b            ; Clear Channel 2 DMA
                or      dma_control,40h              ; and turn on bit 6.
diff_dmas:



        cli                         ; must not be disterbed

; The code below sets the DMA and IRQ  settings of the Ultrasound
;  It was sort of taken from the file RESET.C  of GUS SDK  V2.10

        mov     ecx,200h            ; delay a bit
        loop $


;/* Set up for Digital ASIC */
        mov    dx,GUS_base_port
        add     dx,0fh
        mov     al,5
        out     dx,al           ; Seems to be a undocumented register

        outp    mix_control,00001011b
        outp    irqdma_ctrl,0

        mov     dx,GUS_base_port
        add     dx,0fh
        mov     al,0
        out     dx,al

;/* First do DMA control register */
    outp        mix_control,00001011b
    mov         dx,irqdma_ctrl
    mov         al,dma_control
    or          al,80h
    out         dx,al

;/* IRQ CONTROL REG */
    outp        mix_control,01001011b
    outp        irqdma_ctrl,irq_control

;/* First do DMA control register */
    outp        mix_control,00001011b
    outp        irqdma_ctrl,dma_control

;/* IRQ CONTROL REG */
    outp        mix_control,01001011b
    outp        irqdma_ctrl,irq_control

;/* IRQ CONTROL, ENABLE IRQ */
;/* just to Lock out writes to irq\dma register ... */
        outp    gf1_voice_select,0

;/* enable output & irq, disable line & mic input */
    outp        mix_control,0001001b

;/* outp just to Lock out writes to irq\dma register ... */
        outp    gf1_voice_select,0



;
; Unmask the IRQ lines  for the GF1 and MIDI IRQ settings
;
 ; NOTE: the pin labled IRQ 2 on the BUS connects to IRQ 9 of the PIC
 ; controllers. The IRQ 2 on the PIC is used for slave.
 ; The ultrasound SDK ( Software Development Kit ) says that the GUS can use
 ; IRQ 2 this means you must actualy hook IRQ 9.

        in      al,0A1h
        mov     ah,al
        in      al,21h
        mov     cl,gf1                 ; Get GF1 IRQ
        cmp cl , 2                     ; gota put right IRQ 2
        jne j3
           mov cl,9
    j3:
        mov     ebx,1
        shl     ebx,cl
        not     ebx
        and     eax,ebx
        mov     cl,midi                ; Get MIDI IRQ
        cmp cl , 2                     ; gota put right IRQ 2
        jne j4
           mov cl,9
    j4:
        mov     ebx,1
        shl     ebx,cl
        not     ebx
        and     eax,ebx
        out     021h,al
        mov     al,ah
        out     0A1h,al
        sti


   ;
   ;   Get amount of RAM installed on the sound card (return into EDI)
   ;
        xor     edi,edi
GetSizeloop:
        mov     ecx,edi                       	; Set DRAM  I/O address
        call    UltraSetDRAM_address
        in      al,dx                           ; see if the DRAM locaion
        mov     cl,al                           ; can store some data
        not     al
        out     dx,al
        in      al,dx
        cmp     al,cl
        jz   NoDRAM
        add     edi,40000h
        cmp     edi,100000h                     ; the GF1 can only hold 1MB
        jb  GetSizeloop

NoDRAM: add     edi,3ffffh                      ; align EDI on 256KB
        and     edi,NOT 3ffffh
        mov     gus_dram_size,edi


;*** Initalise the UltraSound  ****
        call Ultrasound_Init

        clc
        popad
        mov     edi,gus_dram_size
        ret


invalid_setting:                        	; jump here on error
         stc
         popad
         ret

;=================== Ultrasound reseted ============================
Ultrasound_Reset ENDP


comment %
╒══════════════════════════════════════════════════════════════════════════╕
│           INITALIZE  THE  ULTRASOUND'S  VOICES                           │
│                                                                          │
│                                                                          │
│                                                                          │
│   IN:  nothing                                                           │
│                                                                          │
│  OUT:   All 32 voices have initalized , cleared buffered IRQ's           │
│        enables line out                                                  │
│  Each of the 32 voices are set as follows                                │
│                                                                          │
│Frequency     = 0                                                         │
│Voice stoped                                                              │
│Bi-directional looping off                                                │
│IRQs disabled                                                             │
│Current Volume = 0                                                        │
│Active Number of Voices = 14                                              │
│                                                                          │
│NOTE:                                                                     │
│     o    This function will only be successful on a successful call      │
│          to the "Ultrasound_Reset" routine                               │
└──────────────────────────────────────────────────────────────────────────┘%
Ultrasound_Init PROC

         cmp     GUSdetected_flag, 0            ; do only if gus has
         jne GUSok                              ; been previously detected
         stc
         ret

GUSok:
        pushad

;/* Pull a reset on the GF1 */
        mov     al,04Ch
        mov     cl,00000000b
        call    Set_GF1_ByteRegister

;/* Wait a little while ... */
        mov     ecx,10
J56:     call   GF1_delay
        loop J56

;/* Release Reset */
       mov     al,04Ch
        mov     cl,00000001b
        call    Set_GF1_ByteRegister

;/* Wait a little while ... */
        mov     ecx,10
J57:    call   GF1_delay
       loop J57

;/* Reset the MIDI port also */
        mov     edx,dword ptr midi_control
        mov     al,00000011b
        out     dx,al

        mov     ecx,10
J58:    call   GF1_delay
        loop J58

        xor     al,al
        out     dx,al

;/* Clear all interrupts. */
        mov     al,41h                  ;DRAM  DMA Control Register
        mov     cl,0
        call    Set_GF1_ByteRegister
        mov     al,045h               	;Timer  Control Register
        mov     cl,00h
        call    Set_GF1_ByteRegister
        mov     al,049h               	;Sampling  Control Register
        mov     cl,00h
        call    Set_GF1_ByteRegister

        mov     al,0Eh              ; set active voices to 32
        mov     cl, 31 or 0C0h
        call    Set_GF1_ByteRegister


;/* Clear interrupts on voices. */
;/* Reading the status ports will clear the irqs. */
        mov     edx,dword ptr gf1_irq_status      ; Read
        in      al,dx
        mov     al,041h                       ;DRAM  DMA Control Register
        call    read_GF1_ByteRegister
        mov    al,049h                 ; Sampling  Control Register
        call    read_GF1_ByteRegister
ClrFIFO:mov     al,08Fh                 ;IRQ source Register
        call    read_GF1_ByteRegister
        and     al,11000000b
        cmp     al,11000000b            ; keep on reading to clear IRQ's
        jne ClrFIFO


         mov    BL,0
    stop_loop:
                outp    gf1_voice_select,BL  ; select voice to operate with
                mov     al,00h                   ; set Voice control
                mov     cl,00000010b               ; (Stoped voice )
                call    Set_GF1_ByteRegister
                mov     al,0Dh                 ; set Volume Ramp control
                mov     cl,00000010b                ; ( stoped ramping)
	        call    Set_GF1_ByteRegister
                mov     al,09h                   ; Current Volume fully off
	        xor     ecx,ecx
	        call    Set_GF1_WordRegister
                call   GF1_delay        ; /* Wait 4.8 micos. or more. */

        inc    bl
        cmp    bl,32
        jb stop_loop


        mov     edx,dword ptr gf1_irq_status      ; Read
        in      al,dx
        mov     al,041h                  ;DRAM  DMA Control Register
        call    read_GF1_ByteRegister
        mov    al,049h                 ; Sampling  Control Register
        call    read_GF1_ByteRegister
Cl2FIFO:mov     al,08Fh                 ;IRQ source Register
        call    read_GF1_ByteRegister
        and     al,11000000b
        cmp     al,11000000b            ; keep on reading to clear IRQ's
        jne Cl2FIFO

        mov     al,0Eh              ; set active voices to 14 again
        mov     cl, 13 or 0C0h
        call    Set_GF1_ByteRegister


        ;/* Set up GF1 Chip for interrupts & enable DACs. */
        mov     al,04Ch
        mov     cl,00000111b
        call    Set_GF1_ByteRegister

        clc
        popad
        ret
Ultrasound_Init ENDP




;--------------------- end of ultrasound services ----------------------



; Some little procedures that are used by the Ultrasound services
read_GF1_ByteRegister proc
        mov     edx,dword ptr gf1_reg_select
        out     dx,al
        add     dl,2
        in      al,dx
        ret
read_GF1_ByteRegister endp

Set_GF1_ByteRegister proc
        mov     edx,dword ptr gf1_reg_select
        out     dx,al
        add     dl,2
        mov     al,cl
        out     dx,al
        ret
Set_GF1_ByteRegister endp

Set_GF1_WordRegister proc
        mov     edx,dword ptr gf1_reg_select
        out     dx,al
        inc     dl
        mov     eax,ecx
        out     dx,ax
        ret
Set_GF1_WordRegister endp



;/***************************************************************
; * This function is used as a 1.6*3 microsecond (or longer) delay.
; * This is needed when trying to change any of the 'self-modifying
; * bits in the voice registers.
; ***************************************************************/
GF1_delay        PROC 
        push    edx
        mov     ah,7h
J55:     mov     dx,gf1_dram        ; dummy port Read
        in      al,dx
        dec     ah
        jnz  J55
        pop     edx
        ret
GF1_delay ENDP

;============================================================================
;
; Probe for an Ultrasound
;
; Expects      DX  = Ultrasound base port address
;
; Returns      Carry clear if detected a GUS at this port address
;               otherwise carry is set.
;
;============================================================================
Ultrasound_Probe PROC
  push    Eax
  push    Edx
  push    Ecx

  cmp     GUSdetected_flag, 0            ; Don't detect if a GUS has aleady
  jne skip_detection                     ; been detected because some how
                                         ; I don't think too many pople are
                                         ; going to be unpluging thier GUS
                                         ; half way through a game.

        mov     GUS_base_port,DX
                                 ; Take the Ultrasound out of a reset state
        add     dx,103h          ; because it's in a reset state at power up.
        mov     al,04Ch
        out     dx,al
        add     dl,2
        mov     al,00000111b
        out     dx,al
        mov     ecx,100h              ; delay a bit ????
        loop $


        xor      ecx,ecx                        ; Set location 0 to 055h
        call    UltraSetDRAM_address
        mov     al,055h
        out     dx,al

        inc     ecx                             ; Set location 1 to 0AAh
        call    UltraSetDRAM_address
        mov     al,0AAh
        out     dx,al

        xor      ecx,ecx                        ; Read  location 0 and
        call     UltraSetDRAM_address           ; compare it to 055h.
        in       al,dx
        cmp      al,055h
        jne No_GUS_Found_here
        mov     GUSdetected_flag,1              ; Set the GUS detected flag
   ;
   ; OK, there is a GUS. Time to initalize the port address varibles.
   ;
              mov     ax,GUS_base_port
  	      mov     ecx,offset The_Ultrasound_port_Addresses
PAdrLoop:     add     [ecx],ax
              add     ecx,2
              cmp     ecx,offset Ultrasound_ports_ends
              jb PAdrLoop

skip_detection:
        clc
        pop     ecx
        pop     edx
        pop     eax
        ret

No_GUS_Found_here:
        stc
        pop     ecx
        pop     edx
        pop     eax
        ret

Ultrasound_Probe ENDP

;----------------------------------------------------------
; Procedure to set the DRAM I/O address of the Ultrasound
;
; Expects       ECX with address
;
UltraSetDRAM_address PROC
        mov     DX,GUS_base_port
        add     dx,103h
        mov     al,043h                 ; DRAM I/O reg  bits 0..15
        out     dx,al
        inc     dl
        mov     eax,ecx
        out     dx,ax
        dec     dl
        mov     al,044h                 ; DRAM I/O reg bits 16..19
        out     dx,al
        add     dl,2
        shr     eax,16
        out     dx,al
        add     dl,2                    ; set DX to  DRAM port
        ret
UltraSetDRAM_address ENDP



;********************* END OF THE ULTRASOUND ROUTINES *********************
END
[ RETURN TO DIRECTORY ]