;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

format MS COFF

DEBUG		equ 1
DEBUG_IRQ	equ 0

include 'proc32.inc'
include 'imports.inc'

API_VERSION	equ 0x01000100

USE_COM_IRQ	equ 0	 ;make irq 3 and irq 4 available for PCI devices

;irq 0,1,2,8,12,13 íåäîñòóïíû
;                   FEDCBA9876543210
VALID_IRQ	equ 1100111011111000b
ATTCH_IRQ	equ 0000111010100000b

if USE_COM_IRQ
ATTCH_IRQ	equ 0000111010111000b
end if

CPU_FREQ	equ  2000d

BIT0  EQU 0x00000001
BIT1  EQU 0x00000002
BIT2  EQU 0x00000004
BIT3  EQU 0x00000008
BIT4  EQU 0x00000010
BIT5  EQU 0x00000020
BIT6  EQU 0x00000040
BIT7  EQU 0x00000080
BIT8  EQU 0x00000100
BIT9  EQU 0x00000200
BIT10 EQU 0x00000400
BIT11 EQU 0x00000800
BIT12 EQU 0x00001000
BIT13 EQU 0x00002000
BIT14 EQU 0x00004000
BIT15 EQU 0x00008000
BIT16 EQU 0x00010000
BIT17 EQU 0x00020000
BIT18 EQU 0x00040000
BIT19 EQU 0x00080000
BIT20 EQU 0x00100000
BIT21 EQU 0x00200000
BIT22 EQU 0x00400000
BIT23 EQU 0x00800000
BIT24 EQU 0x00100000
BIT25 EQU 0x02000000
BIT26 EQU 0x04000000
BIT27 EQU 0x08000000
BIT28 EQU 0x10000000
BIT29 EQU 0x20000000
BIT30 EQU 0x40000000
BIT31 EQU 0x80000000

VID_FM801 	  equ 0x1319
CTRL_FM801	  equ 0x0801

FM_PCM_VOLUME         equ 0x00
FM_FM_VOLUME          equ 0x02
FM_I2S_VOLUME         equ 0x04
FM_RECORD_SOURCE      equ 0x06

FM_PLAY_CTL           equ 0x08
FM_PLAY_RATE_MASK     equ 0x0f00
FM_PLAY_BUF1_LAST     equ 0x0001
FM_PLAY_BUF2_LAST     equ 0x0002
FM_PLAY_START         equ 0x0020
FM_PLAY_PAUSE         equ 0x0040
FM_PLAY_STOPNOW       equ 0x0080
FM_PLAY_16BIT         equ 0x4000
FM_PLAY_STEREO        equ 0x8000

FM_PLAY_DMALEN        equ 0x0a
FM_PLAY_DMABUF1       equ 0x0c
FM_PLAY_DMABUF2       equ 0x10

FM_REC_CTL            equ 0x14
FM_REC_RATE_MASK      equ 0x0f00
FM_REC_BUF1_LAST      equ 0x0001
FM_REC_BUF2_LAST      equ 0x0002
FM_REC_START          equ 0x0020
FM_REC_PAUSE          equ 0x0040
FM_REC_STOPNOW        equ 0x0080
FM_REC_16BIT          equ 0x4000
FM_REC_STEREO         equ 0x8000

FM_REC_DMALEN         equ 0x16
FM_REC_DMABUF1        equ 0x18
FM_REC_DMABUF2        equ 0x1c

FM_CODEC_CTL          equ 0x22
FM_VOLUME             equ 0x26
FM_VOLUME_MUTE        equ 0x8000

FM_CODEC_CMD          equ 0x2a
FM_CODEC_CMD_READ     equ 0x0080
FM_CODEC_CMD_VALID    equ 0x0100
FM_CODEC_CMD_BUSY     equ 0x0200

FM_CODEC_DATA         equ 0x2c

FM_IO_CTL             equ 0x52
FM_CARD_CTL           equ 0x54

FM_INTMASK            equ 0x56
FM_INTMASK_PLAY       equ 0x0001
FM_INTMASK_REC        equ 0x0002
FM_INTMASK_VOL        equ 0x0040
FM_INTMASK_MPU        equ 0x0080

FM_INTSTATUS          equ 0x5a
FM_INTSTATUS_PLAY     equ 0x0100
FM_INTSTATUS_REC      equ 0x0200
FM_INTSTATUS_VOL      equ 0x4000
FM_INTSTATUS_MPU      equ 0x8000

CODEC_MASTER_VOL_REG	     equ 0x02 ;
CODEC_AUX_VOL		     equ 0x04 ;
CODEC_PCM_OUT_REG	     equ 0x18 ; PCM output volume
CODEC_EXT_AUDIO_REG	     equ 0x28 ; extended audio
CODEC_EXT_AUDIO_CTRL_REG     equ 0x2a ; extended audio control
CODEC_PCM_FRONT_DACRATE_REG  equ 0x2c ; PCM out sample rate
CODEC_PCM_SURND_DACRATE_REG  equ 0x2e ; surround sound sample rate
CODEC_PCM_LFE_DACRATE_REG    equ 0x30 ; LFE sample rate

SRV_GETVERSION	      equ  0
DEV_PLAY	      equ  1
DEV_STOP	      equ  2
DEV_CALLBACK	      equ  3
DEV_SET_BUFF	      equ  4
DEV_NOTIFY	      equ  5
DEV_SET_MASTERVOL     equ  6
DEV_GET_MASTERVOL     equ  7
DEV_GET_INFO	      equ  8

struc AC_CNTRL	  ;AC controller base class
{ .bus		      dd ?
  .devfn	      dd ?

  .vendor	      dd ?
  .dev_id	      dd ?
  .pci_cmd	      dd ?
  .pci_stat	      dd ?

  .codec_io_base      dd ?
  .codec_mem_base     dd ?

  .ctrl_io_base       dd ?
  .ctrl_mem_base      dd ?
  .cfg_reg	      dd ?
  .int_line	      dd ?

  .vendor_ids	      dd ?    ;vendor id string
  .ctrl_ids	      dd ?    ;hub id string

  .buffer	      dd ?

  .notify_pos	      dd ?
  .notify_task	      dd ?

  .lvi_reg	      dd ?
  .ctrl_setup	      dd ?
  .user_callback      dd ?
  .codec_read16       dd ?
  .codec_write16      dd ?

  .ctrl_read8	      dd ?
  .ctrl_read16	      dd ?
  .ctrl_read32	      dd ?

  .ctrl_write8	      dd ?
  .ctrl_write16       dd ?
  .ctrl_write32       dd ?
}

struc CODEC   ;Audio Chip base class
{
  .chip_id	      dd ?
  .flags	      dd ?
  .status	      dd ?

  .ac_vendor_ids      dd ?    ;ac vendor id string
  .chip_ids	      dd ?    ;chip model string

  .shadow_flag	      dd ?
		      dd ?

  .regs 	      dw ?     ; codec registers
  .reg_master_vol     dw ?     ;0x02
  .reg_aux_out_vol    dw ?     ;0x04
  .reg_mone_vol       dw ?     ;0x06
  .reg_master_tone    dw ?     ;0x08
  .reg_beep_vol       dw ?     ;0x0A
  .reg_phone_vol      dw ?     ;0x0C
  .reg_mic_vol	      dw ?     ;0x0E
  .reg_line_in_vol    dw ?     ;0x10
  .reg_cd_vol	      dw ?     ;0x12
  .reg_video_vol      dw ?     ;0x14
  .reg_aux_in_vol     dw ?     ;0x16
  .reg_pcm_out_vol    dw ?     ;0x18
  .reg_rec_select     dw ?     ;0x1A
  .reg_rec_gain       dw ?     ;0x1C
  .reg_rec_gain_mic   dw ?     ;0x1E
  .reg_gen	      dw ?     ;0x20
  .reg_3d_ctrl	      dw ?     ;0X22
  .reg_page	      dw ?     ;0X24
  .reg_powerdown      dw ?     ;0x26
  .reg_ext_audio      dw ?     ;0x28
  .reg_ext_st	      dw ?     ;0x2a
  .reg_pcm_front_rate dw ?     ;0x2c
  .reg_pcm_surr_rate  dw ?     ;0x2e
  .reg_lfe_rate       dw ?     ;0x30
  .reg_pcm_in_rate    dw ?     ;0x32
		      dw ?     ;0x34
  .reg_cent_lfe_vol   dw ?     ;0x36
  .reg_surr_vol       dw ?     ;0x38
  .reg_spdif_ctrl     dw ?     ;0x3A
		      dw ?     ;0x3C
		      dw ?     ;0x3E
		      dw ?     ;0x40
		      dw ?     ;0x42
		      dw ?     ;0x44
		      dw ?     ;0x46
		      dw ?     ;0x48
		      dw ?     ;0x4A
		      dw ?     ;0x4C
		      dw ?     ;0x4E
		      dw ?     ;0x50
		      dw ?     ;0x52
		      dw ?     ;0x54
		      dw ?     ;0x56
		      dw ?     ;0x58
		      dw ?     ;0x5A
		      dw ?     ;0x5C
		      dw ?     ;0x5E
  .reg_page_0	      dw ?     ;0x60
  .reg_page_1	      dw ?     ;0x62
  .reg_page_2	      dw ?     ;0x64
  .reg_page_3	      dw ?     ;0x66
  .reg_page_4	      dw ?     ;0x68
  .reg_page_5	      dw ?     ;0x6A
  .reg_page_6	      dw ?     ;0x6C
  .reg_page_7	      dw ?     ;0x6E
		      dw ?     ;0x70
		      dw ?     ;0x72
		      dw ?     ;0x74
		      dw ?     ;0x76
		      dw ?     ;0x78
		      dw ?     ;0x7A
  .reg_vendor_id_1    dw ?     ;0x7C
  .reg_vendor_id_2    dw ?     ;0x7E


  .reset	      dd ?    ;virual
  .set_master_vol     dd ?
}

struc CTRL_INFO
{   .pci_cmd	      dd ?
    .irq	      dd ?
    .glob_cntrl       dd ?
    .glob_sta	      dd ?
    .codec_io_base    dd ?
    .ctrl_io_base     dd ?
    .codec_mem_base   dd ?
    .ctrl_mem_base    dd ?
    .codec_id	      dd ?
}

struc IOCTL
{  .handle	      dd ?
   .io_code	      dd ?
   .input	      dd ?
   .inp_size	      dd ?
   .output	      dd ?
   .out_size	      dd ?
}

virtual at 0
  IOCTL IOCTL
end virtual

EVENT_NOTIFY	  equ 0x00000200

public START
public service_proc
public version

section '.flat' code readable align 16

proc START stdcall, state:dword

	   cmp [state], 1
	   jne .stop

     if DEBUG
           mov eax, START
	   call dword2str
	   call SysMsgBoardStr
	   mov esi, msgInit
	   call SysMsgBoardStr
     end if

	   call detect_controller
	   test eax, eax
	   jz .fail

     if DEBUG
	   mov  esi, [ctrl.vendor_ids]
	   call SysMsgBoardStr
	   mov	esi, [ctrl.ctrl_ids]
	   call SysMsgBoardStr

     end if

	   call init_controller
	   test eax, eax
	   jz .fail

	   call init_codec
	   test eax, eax
	   jz .fail

	   call reset_controller
	   call setup_codec

	   mov esi, msgPrimBuff
	   call SysMsgBoardStr
	   call create_primary_buff

	   mov esi, msgDone
	   call SysMsgBoardStr

	   mov eax, VALID_IRQ
	   mov ebx, [ctrl.int_line]
	   mov esi, msgInvIRQ
	   bt eax, ebx
	   jnc .fail_msg
	   mov eax, ATTCH_IRQ
	   mov esi, msgAttchIRQ
	   bt eax, ebx
	   jnc .fail_msg

	   stdcall AttachIntHandler, ebx, ac97_irq, dword 0
.reg:

	   stdcall RegService, sz_sound_srv, service_proc
	   ret
.fail:
   if DEBUG
	   mov esi, msgFail
	   call SysMsgBoardStr
   end if
	   xor eax, eax
	   ret
.fail_msg:
	   call SysMsgBoardStr
	   xor eax, eax
	   ret
.stop:
	   call stop
	   xor eax, eax
	   ret
endp

handle	   equ	IOCTL.handle
io_code    equ	IOCTL.io_code
input	   equ	IOCTL.input
inp_size   equ	IOCTL.inp_size
output	   equ	IOCTL.output
out_size   equ	IOCTL.out_size

align 4
proc service_proc stdcall, ioctl:dword

	   mov edi, [ioctl]
	   mov eax, [edi+io_code]

	   cmp eax, SRV_GETVERSION
	   jne @F

	   mov eax, [edi+output]
	   cmp [edi+out_size], 4
	   jne .fail

	   mov [eax], dword API_VERSION
	   xor eax, eax
	   ret
@@:
	   cmp eax, DEV_PLAY
	   jne @F
     if DEBUG
	   mov esi, msgPlay
	   call SysMsgBoardStr
     end if
	   call play
	   ret
@@:
	   cmp eax, DEV_STOP
	   jne @F
     if DEBUG
	   mov esi, msgStop
	   call SysMsgBoardStr
     end if
	   call stop
	   ret
@@:
	   cmp eax, DEV_CALLBACK
	   jne @F
	   mov ebx, [edi+input]
	   stdcall set_callback, [ebx]
	   ret
@@:
	   cmp eax, DEV_SET_MASTERVOL
	   jne @F
	   mov eax, [edi+input]
	   mov eax, [eax]
	   call set_master_vol	    ;eax= vol
	   ret
@@:
	   cmp eax, DEV_GET_MASTERVOL
	   jne @F
	   mov ebx, [edi+output]
	   stdcall get_master_vol, ebx
	   ret
;@@:
;           cmp eax, DEV_GET_INFO
;           jne @F
;           mov ebx, [edi+output]
;           stdcall get_dev_info, ebx
;           ret
@@:
.fail:
	   or eax, -1
	   ret
endp

restore   handle
restore   io_code
restore   input
restore   inp_size
restore   output
restore   out_size

align 4
proc fill_buffer

	   cmp [ctrl.user_callback], 0
	   je .exit

	   mov esi, [ctrl.buffer]
	   mov eax, int_flip_flop
	   inc dword [eax]
	   test dword [eax],1
	   je @f
	   add esi, 0x4000
@@:
	   stdcall [ctrl.user_callback], esi

	   mov edx, FM_PLAY_DMABUF1
	   mov eax, [buffer_pgaddr]
	   mov esi, int_flip_flop
	   test dword [esi],1
	   je @f
	   mov edx, FM_PLAY_DMABUF2
	   add eax, 0x4000
@@:
	   call [ctrl.ctrl_write32]

.exit:
	   ret
endp

align 4
proc ac97_irq

     if DEBUG_IRQ
	   mov esi, msgIRQ
	   call SysMsgBoardStr
     end if

	   mov edx, FM_INTSTATUS
	   call [ctrl.ctrl_read16]

	   test eax, FM_INTSTATUS_PLAY
	   je .exit

	   push eax
	   call fill_buffer
           pop eax

.exit:
	   mov edx, FM_INTSTATUS
	   call [ctrl.ctrl_write16]

	   ret
endp

align 4
proc create_primary_buff

	   stdcall KernelAlloc, 0x10000
	   mov [ctrl.buffer], eax

	   mov edi, eax
	   mov ecx, 0x10000/4
	   xor eax, eax
	   cld
	   rep stosd

	   mov eax, [ctrl.buffer]
	   call GetPgAddr
	   mov [buffer_pgaddr], eax

	   ret
endp

align 4
proc detect_controller
	   locals
	     last_bus dd ?
	     bus      dd ?
	     devfn    dd ?
	   endl

	   xor eax, eax
	   mov [bus], eax
	   inc eax
	   call PciApi
	   cmp eax, -1
	   je .err

	   mov [last_bus], eax

.next_bus:
	   and [devfn], 0
.next_dev:
	   stdcall PciRead32, [bus], [devfn], dword 0
	   test eax, eax
	   jz .next
	   cmp eax, -1
	   je .next

	   push eax
	   stdcall PciRead32, [bus], [devfn], dword 0x09
	   and eax,0xffffff
	   cmp eax, 0x060100  ;pci-isa
	   jne .no_bridge

	   mov eax, [bus]
	   mov [brg_bus], eax
	   mov eax, [devfn]
	   mov [brg_devfn],eax
.no_bridge:pop eax

	   mov edi, devices
@@:
	   mov ebx, [edi]
	   test ebx, ebx
	   jz .next

	   cmp eax, ebx
	   je .found
	   add edi, 12
	   jmp @B
.next:
	   inc [devfn]
	   cmp [devfn], 256
	   jb  .next_dev
	   mov eax, [bus]
	   inc eax
	   mov [bus], eax
	   cmp eax, [last_bus]
	   jna .next_bus
	   xor eax, eax
	   ret
.found:
	   mov ebx, [bus]
	   mov [ctrl.bus], ebx

	   mov ecx, [devfn]
	   mov [ctrl.devfn], ecx

	   mov edx, eax
	   and edx, 0xFFFF
	   mov [ctrl.vendor], edx
	   shr eax, 16
	   mov [ctrl.dev_id], eax

	   mov ebx, [edi+4]
	   mov [ctrl.ctrl_ids], ebx
	   mov [ctrl.vendor_ids], msg_FM

	   mov esi, [edi+8]
	   mov [ctrl.ctrl_setup], esi
	   ret
.err:
	   xor eax, eax
	   ret
endp

align 4
proc init_controller

	   stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4
	   mov ebx, eax
	   and eax, 0xFFFF
	   mov [ctrl.pci_cmd], eax
	   shr ebx, 16
	   mov [ctrl.pci_stat], ebx

	   mov esi, msgPciCmd
	   call SysMsgBoardStr
	   call dword2str
	   call SysMsgBoardStr

	   mov esi, msgPciStat
	   call SysMsgBoardStr
	   mov eax, [ctrl.pci_stat]
	   call dword2str
	   call SysMsgBoardStr

	   mov esi, msgCtrlIsaIo
	   call SysMsgBoardStr

	   stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10

	   call dword2str
	   call SysMsgBoardStr

	   and eax,0xFFFE
	   mov [ctrl.ctrl_io_base], eax

	   mov esi, msgIrqNum
	   call SysMsgBoardStr

	   stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C
	   and eax, 0xFF
	   mov [ctrl.int_line], eax

	   call dword2str
	   call SysMsgBoardStr

	   call [ctrl.ctrl_setup]
	   xor eax, eax
	   inc eax
	   ret
endp

align 4
proc set_FM
	   mov [ctrl.codec_read16],  codec_io_r16    ;virtual
	   mov [ctrl.codec_write16], codec_io_w16    ;virtual

	   mov [ctrl.ctrl_read8 ],  ctrl_io_r8	    ;virtual
	   mov [ctrl.ctrl_read16],  ctrl_io_r16      ;virtual
	   mov [ctrl.ctrl_read32],  ctrl_io_r32      ;virtual

	   mov [ctrl.ctrl_write8 ], ctrl_io_w8	    ;virtual
	   mov [ctrl.ctrl_write16], ctrl_io_w16      ;virtual
	   mov [ctrl.ctrl_write32], ctrl_io_w32      ;virtual
	   ret
endp

align 4
proc reset_controller

	   mov esi, msgInitCtrl
	   call SysMsgBoardStr

	   mov edx, FM_CARD_CTL
	   call [ctrl.ctrl_read8]
	   push eax
	   or al,1
	   mov edx, FM_CARD_CTL
	   call [ctrl.ctrl_write8]
	   mov eax, 10
	   call StallExec
	   pop eax
	   and al,0xFE
	   mov edx, FM_CARD_CTL
	   call [ctrl.ctrl_write8]
	   mov eax, 10
	   call StallExec

	   mov eax, 0x0404
	   mov edx, FM_PCM_VOLUME
	   call [ctrl.ctrl_write16]
	   mov edx, FM_FM_VOLUME
	   call [ctrl.ctrl_write16]
	   mov edx, FM_I2S_VOLUME
	   call [ctrl.ctrl_write16]

	   mov edx, FM_INTMASK
	   call [ctrl.ctrl_read16]
	   and eax, not FM_INTMASK_PLAY
	   or eax, FM_INTMASK_REC or FM_INTMASK_MPU or FM_INTMASK_VOL
	   mov edx, FM_INTMASK
	   call [ctrl.ctrl_write16]

	   mov eax, FM_INTMASK_PLAY or FM_INTMASK_REC or FM_INTMASK_MPU or FM_INTMASK_VOL
	   mov edx, FM_INTSTATUS
	   call [ctrl.ctrl_write16]

	   ret
endp

align 4
proc init_codec

	   mov esi, msgInitCodec
	   call SysMsgBoardStr

	   mov al, FM_CODEC_CMD_READ
	   mov edx, FM_CODEC_CMD
	   call [ctrl.ctrl_write8]

           call reset_codec

	   call detect_codec

	   xor eax, eax
	   inc eax
	   ret
endp

align 4
proc reset_codec

	   mov ecx, 255
.L1:
	   mov edx, FM_CODEC_CMD
	   call [ctrl.ctrl_read16]
	   test ah, FM_CODEC_CMD_VALID shr 8
	   jne .L2
	   loop .L1
.L2:
	   mov edx, FM_CODEC_CTL
	   call [ctrl.ctrl_read8]
	   push eax
	   or al, 0x20
	   mov edx, FM_CODEC_CTL
	   call [ctrl.ctrl_write8]
	   pop eax
	   and al,0xDF
	   mov edx, FM_CODEC_CTL
	   call [ctrl.ctrl_write8]

	   xor eax, eax
	   inc eax
	   ret
endp

align 4
play:
           mov eax, 0x4000-1
	   mov edx, FM_PLAY_DMALEN
	   call [ctrl.ctrl_write16]

	   call fill_buffer

	   mov eax, FM_PLAY_START or FM_PLAY_STOPNOW or FM_PLAY_STEREO or FM_PLAY_16BIT or 0xA00
	   mov edx, FM_PLAY_CTL
	   call [ctrl.ctrl_write16]

	   xor eax, eax
	   ret

align 4
stop:
	   mov edx, FM_PLAY_CTL
	   call [ctrl.ctrl_read16]
	   and eax, not (FM_PLAY_START or FM_PLAY_STOPNOW)
	   or eax, FM_PLAY_BUF1_LAST or FM_PLAY_BUF2_LAST
	   mov edx, FM_PLAY_CTL
	   call [ctrl.ctrl_write16]

	   xor eax, eax
	   ret

align 4
proc get_dev_info stdcall, p_info:dword
	   virtual at esi
	     CTRL_INFO CTRL_INFO
	   end virtual

	   mov esi, [p_info]
	   mov eax, [ctrl.int_line]
	   mov ebx, [ctrl.codec_io_base]
	   mov ecx, [ctrl.ctrl_io_base]
	   mov edx, [ctrl.codec_mem_base]
	   mov edi, [ctrl.ctrl_mem_base]

	   mov [CTRL_INFO.irq], eax
	   mov [CTRL_INFO.codec_io_base], ebx
	   mov [CTRL_INFO.ctrl_io_base], ecx
	   mov [CTRL_INFO.codec_mem_base], edx
	   mov [CTRL_INFO.ctrl_mem_base], edi

	   mov eax, [codec.chip_id]
	   mov [CTRL_INFO.codec_id], eax

	   mov ebx, [ctrl.pci_cmd]
	   mov [CTRL_INFO.pci_cmd], ebx
	   ret
endp

align 4
proc set_callback stdcall, handler:dword
	   mov eax, [handler]
	   mov [ctrl.user_callback], eax
	   ret
endp

align 4
proc codec_read stdcall, ac_reg:dword	; reg = edx, reval = eax

	   mov edx, [ac_reg]

	   mov ebx, edx
	   shr ebx, 1
	   bt [codec.shadow_flag], ebx
	   jc .use_shadow

	   call [ctrl.codec_read16]  ;change edx !!!
	   mov ecx, eax

.read_ok:
	   mov edx, [ac_reg]
	   mov [codec.regs+edx], cx
	   bts [codec.shadow_flag], ebx
	   mov eax, ecx
	   ret
.use_shadow:
	   movzx eax, word [codec.regs+edx]
	   ret

endp

align 4
proc codec_write stdcall, ac_reg:dword

	   mov esi, [ac_reg]

	   mov edx, esi

	   call [ctrl.codec_write16]

	   mov [codec.regs+esi], ax
	   shr esi, 1
	   bts [codec.shadow_flag], esi

	   ret
endp

align 4
proc check_semafore
align 4
.ok:
	   xor eax,eax
	   inc eax
	   ret
endp

align 4
proc StallExec
	   push ecx
	   push edx
	   push ebx
	   push eax

	   mov ecx, CPU_FREQ
	   mul ecx
	   mov ebx, eax       ;low
	   mov ecx, edx       ;high
	   rdtsc
	   add ebx, eax
	   adc ecx, edx
@@:
	   rdtsc
	   sub eax, ebx
	   sbb edx, ecx
	   js @B

	   pop eax
	   pop ebx
	   pop edx
	   pop ecx
	   ret
endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;          CONTROLLER IO functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

align 4
proc codec_io_r16

           push edx
	   mov ecx, 255
.L1:
	   mov edx, FM_CODEC_CMD
	   call [ctrl.ctrl_read16]
	   test ah, FM_CODEC_CMD_BUSY shr 8
	   je .L2
	   loop .L1
.L2:
           pop eax
           or al, FM_CODEC_CMD_READ
	   mov edx, FM_CODEC_CMD
	   call [ctrl.ctrl_write8]

	   mov ecx, 255
.L3:
	   mov edx, FM_CODEC_CMD
	   call [ctrl.ctrl_read16]
	   test ah, FM_CODEC_CMD_VALID shr 8
	   jne .L4
	   loop .L3
.L4:
	   mov edx, FM_CODEC_DATA
	   call [ctrl.ctrl_read16]

	   ret
endp

align 4
proc codec_io_w16

           push edx
	   push eax
	   mov ecx, 255
.L1:
	   mov edx, FM_CODEC_CMD
	   call [ctrl.ctrl_read16]
	   test ah, FM_CODEC_CMD_BUSY shr 8
	   je .L2
	   loop .L1
.L2:
           pop eax
	   mov edx, FM_CODEC_DATA
	   call [ctrl.ctrl_write16]

	   pop eax
	   mov edx, FM_CODEC_CMD
	   call [ctrl.ctrl_write16]

	   ret
endp

align 4
proc ctrl_io_r8
	   add edx, [ctrl.ctrl_io_base]
	   in  al, dx
	   ret
endp

align 4
proc ctrl_io_r16
	   add edx, [ctrl.ctrl_io_base]
	   in  ax, dx
	   ret
endp

align 4
proc ctrl_io_r32
	   add edx, [ctrl.ctrl_io_base]
	   in  eax, dx
	   ret
endp

align 4
proc ctrl_io_w8
	   add edx, [ctrl.ctrl_io_base]
	   out dx, al
	   ret
endp

align 4
proc ctrl_io_w16
	   add edx, [ctrl.ctrl_io_base]
	   out dx, ax
	   ret
endp

align 4
proc ctrl_io_w32
	   add edx, [ctrl.ctrl_io_base]
	   out dx, eax
	   ret
endp

align 4
dword2str:
      mov  esi, hex_buff
      mov ecx, -8
@@:
      rol eax, 4
      mov ebx, eax
      and ebx, 0x0F
      mov bl, [ebx+hexletters]
      mov [8+esi+ecx], bl
      inc ecx
      jnz @B
      ret

hexletters   db '0123456789ABCDEF'
hex_buff     db 8 dup(0),13,10,0
brg_bus      dd ?
brg_devfn    dd ?
include "codec.inc"

align 4
devices dd (CTRL_FM801 shl 16)+VID_FM801, msg_FM801, set_FM
	dd 0

version      dd (5 shl 16) or (API_VERSION and 0xFFFF)

msg_FM801    db 'FM801 AC97 controller',13,10, 0
msg_FM       db 'Forte Media',13,10, 0

sz_sound_srv db 'SOUND',0

msgInit       db 'detect hardware...',13,10,0
msgFail       db 'device not found',13,10,0
msgAttchIRQ   db 'IRQ line not supported', 13,10, 0
msgInvIRQ     db 'IRQ line not assigned or invalid', 13,10, 0
msgPlay       db 'start play', 13,10,0
msgStop       db 'stop play',  13,10,0
;msgNotify    db 'call notify',13,10,0
msgIRQ	      db 'AC97 IRQ', 13,10,0
msgInitCtrl  db 'init controller',13,10,0
msgInitCodec db 'init codec',13,10,0
msgPrimBuff   db 'create primary buffer ...',0
msgDone       db 'done',13,10,0
;msgReg       db 'set service handler',13,10,0
;msgOk	      db 'service installed',13,10,0
;msgStatus    db 'global status   ',0
;msgControl   db 'global control  ',0
msgPciCmd     db 'PCI command     ',0
msgPciStat    db 'PCI status      ',0
msgCtrlIsaIo  db 'controller io base   ',0
msgIrqNum     db 'IRQ default          ',0
;msgIrqMap    db 'AC97 irq map as      ',0

section '.data' data readable writable align 16

codec CODEC
ctrl AC_CNTRL

int_flip_flop	   rd 1
buffer_pgaddr      rd 1