From 21ee3e96a81b98d309be1b83f383e44b554ae173 Mon Sep 17 00:00:00 2001 From: tsdima Date: Tue, 29 Dec 2009 20:09:28 +0000 Subject: [PATCH] new sound driver added git-svn-id: svn://kolibrios.org@1340 a494cfbc-eb01-0410-851d-a64ba20cac60 --- kernel/trunk/drivers/codec.inc | 362 +++++------ kernel/trunk/drivers/fm801.asm | 1061 ++++++++++++++++++++++++++++++++ 2 files changed, 1248 insertions(+), 175 deletions(-) create mode 100644 kernel/trunk/drivers/fm801.asm diff --git a/kernel/trunk/drivers/codec.inc b/kernel/trunk/drivers/codec.inc index f79102f69f..0c2569fd11 100644 --- a/kernel/trunk/drivers/codec.inc +++ b/kernel/trunk/drivers/codec.inc @@ -11,117 +11,117 @@ AD_HPSEL equ BIT10 align 4 proc detect_codec - locals - codec_id dd ? - endl + locals + codec_id dd ? + endl - stdcall codec_read, dword 0x7C - shl eax, 16 - mov [codec_id], eax + stdcall codec_read, dword 0x7C + shl eax, 16 + mov [codec_id], eax - stdcall codec_read, dword 0x7E - or eax, [codec_id] + stdcall codec_read, dword 0x7E + or eax, [codec_id] - mov [codec.chip_id], eax - and eax, 0xFFFFFF00 + mov [codec.chip_id], eax + and eax, 0xFFFFFF00 - mov edi, codecs + mov edi, codecs @@: - mov ebx, [edi] - test ebx, ebx - jz .unknown + mov ebx, [edi] + test ebx, ebx + jz .unknown - cmp eax, ebx - jne .next - mov eax, [edi+4] - mov [codec.ac_vendor_ids], eax - mov esi, eax - call SysMsgBoardStr - stdcall detect_chip, [edi+8] + cmp eax, ebx + jne .next + mov eax, [edi+4] + mov [codec.ac_vendor_ids], eax + mov esi, eax + call SysMsgBoardStr + stdcall detect_chip, [edi+8] - ret + ret .next: - add edi, 12 - jmp @B + add edi, 12 + jmp @B .unknown: - mov [codec.ac_vendor_ids], ac_unknown - mov [codec.chip_ids], chip_unknown + mov [codec.ac_vendor_ids], ac_unknown + mov [codec.chip_ids], chip_unknown - mov esi, chip_unknown - call SysMsgBoardStr - mov eax, [codec.chip_id] - call dword2str - call SysMsgBoardStr - ret + mov esi, chip_unknown + call SysMsgBoardStr + mov eax, [codec.chip_id] + call dword2str + call SysMsgBoardStr + ret endp align 4 proc detect_chip stdcall, chip_tab:dword - mov eax, [codec.chip_id] - and eax, 0xFF + mov eax, [codec.chip_id] + and eax, 0xFF - mov edi, [chip_tab] + mov edi, [chip_tab] @@: - mov ebx, [edi] - cmp ebx, 0xFF - je .unknown + mov ebx, [edi] + cmp ebx, 0xFF + je .unknown - cmp eax,ebx - jne .next - mov eax, [edi+4] - mov [codec.chip_ids], eax - mov esi, eax - call SysMsgBoardStr - ret + cmp eax,ebx + jne .next + mov eax, [edi+4] + mov [codec.chip_ids], eax + mov esi, eax + call SysMsgBoardStr + ret .next: - add edi, 8 - jmp @b + add edi, 8 + jmp @b .unknown: - mov [codec.chip_ids], chip_unknown - mov esi, chip_unknown - call SysMsgBoardStr - mov eax, [codec.chip_id] - call dword2str - call SysMsgBoardStr - ret + mov [codec.chip_ids], chip_unknown + mov esi, chip_unknown + call SysMsgBoardStr + mov eax, [codec.chip_id] + call dword2str + call SysMsgBoardStr + ret endp align 4 proc setup_codec - xor eax, eax - stdcall codec_write, dword CODEC_AUX_VOL + xor eax, eax + stdcall codec_write, dword CODEC_AUX_VOL - mov eax, 0x0B0B - stdcall codec_write, dword CODEC_MASTER_VOL_REG + mov eax, 0x0B0B + stdcall codec_write, dword CODEC_MASTER_VOL_REG - mov ax, 0x08 - stdcall codec_write, dword 0x0C + mov ax, 0x08 + stdcall codec_write, dword 0x0C - mov ax, 0x0808 - stdcall codec_write, dword CODEC_PCM_OUT_REG + mov ax, 0x0808 + stdcall codec_write, dword CODEC_PCM_OUT_REG - mov ax, 0x0808 - stdcall codec_write, dword 0x10 + mov ax, 0x0808 + stdcall codec_write, dword 0x10 - mov ax, 0x0808 - stdcall codec_write, dword 0x12 + mov ax, 0x0808 + stdcall codec_write, dword 0x12 - mov ax, 0x0808 - stdcall codec_write, dword 0x16 + mov ax, 0x0808 + stdcall codec_write, dword 0x16 - stdcall codec_read, dword CODEC_EXT_AUDIO_CTRL_REG - and eax, 0FFFFh - BIT1 ; clear DRA (BIT1) - or eax, BIT0 ; set VRA (BIT0) - stdcall codec_write, dword CODEC_EXT_AUDIO_CTRL_REG + stdcall codec_read, dword CODEC_EXT_AUDIO_CTRL_REG + and eax, 0FFFFh - BIT1 ; clear DRA (BIT1) + or eax, BIT0 ; set VRA (BIT0) + stdcall codec_write, dword CODEC_EXT_AUDIO_CTRL_REG - stdcall set_sample_rate, dword 48000 + stdcall set_sample_rate, dword 48000 .init_error: - xor eax, eax ; exit with error - ret + xor eax, eax ; exit with error + ret endp @@ -130,47 +130,47 @@ endp align 4 set_master_vol: - cmp eax, 0 - jl @F - xor eax, eax - jmp .set + cmp eax, 0 + jl @F + xor eax, eax + jmp .set @@: - cmp eax, -9450 - jg .set - mov eax, -9450 ;clamp into 6 bits + cmp eax, -9450 + jg .set + mov eax, -9450 ;clamp into 6 bits .set: - cdq - mov ebx, -150 - idiv ebx - mov ah, al - stdcall codec_write, dword CODEC_MASTER_VOL_REG - xor eax, eax - ret + cdq + mov ebx, -150 + idiv ebx + mov ah, al + stdcall codec_write, dword CODEC_MASTER_VOL_REG + xor eax, eax + ret align 4 proc get_master_vol stdcall, pvol:dword - stdcall codec_read, dword CODEC_MASTER_VOL_REG - and eax, 0x3F - imul eax, -150 - mov ebx, [pvol] - mov [ebx], eax - xor eax, eax - ret + stdcall codec_read, dword CODEC_MASTER_VOL_REG + and eax, 0x3F + imul eax, -150 + mov ebx, [pvol] + mov [ebx], eax + xor eax, eax + ret endp align 4 proc set_sample_rate stdcall, rate:dword - mov eax, [rate] - stdcall codec_write, dword CODEC_PCM_FRONT_DACRATE_REG - ret + mov eax, [rate] + stdcall codec_write, dword CODEC_PCM_FRONT_DACRATE_REG + ret endp patch_AD: - stdcall codec_read, 0x76 - or ax, BIT5+BIT10 - stdcall codec_write, 0x76 - ret + stdcall codec_read, 0x76 + or ax, BIT5+BIT10 + stdcall codec_write, 0x76 + ret @@ -180,6 +180,7 @@ ac_Realtek db 'Realtek Semiconductor',13,10,0 ac_Analog db 'Analog Devices',13,10,0 ac_CMedia db 'C-Media Electronics',13,10,0 ac_Cirrus db 'Cirrus Logic',13,10,0 +ac_Wolfson db 'Wolfson Microelectronics',13,10,0 chip_unknown db 'unknown codec id ', 0 @@ -187,97 +188,108 @@ CHIP_ANALOG equ 0x41445300 CHIP_REALTEK equ 0x414C4700 CHIP_CMEDIA equ 0x434D4900 CHIP_CIRRUS equ 0x43525900 +CHIP_WOLFSON equ 0x574D4C00 align 16 -codecs dd CHIP_ANALOG, ac_Analog, chips_Analog - dd CHIP_CMEDIA, ac_CMedia, chips_CMedia - dd CHIP_REALTEK,ac_Realtek, chips_Realtek - dd CHIP_CIRRUS, ac_Cirrus, chips_Cirrus - dd 0 +codecs dd CHIP_ANALOG, ac_Analog, chips_Analog + dd CHIP_CMEDIA, ac_CMedia, chips_CMedia + dd CHIP_REALTEK,ac_Realtek, chips_Realtek + dd CHIP_CIRRUS, ac_Cirrus, chips_Cirrus + dd CHIP_WOLFSON,ac_Wolfson, chips_Wolfson + dd 0 align 16 chips_Analog dd 0x03, chip_AD1819 - dd 0x40, chip_AD1881 - dd 0x48, chip_AD1881A - dd 0x60, chip_AD1884 - dd 0x61, chip_AD1886 - dd 0x62, chip_AD1887 - dd 0x63, chip_AD1886A - dd 0x70, chip_AD1980 - dd 0x75, chip_AD1985 - dd 0xFF + dd 0x40, chip_AD1881 + dd 0x48, chip_AD1881A + dd 0x60, chip_AD1884 + dd 0x61, chip_AD1886 + dd 0x62, chip_AD1887 + dd 0x63, chip_AD1886A + dd 0x70, chip_AD1980 + dd 0x75, chip_AD1985 + dd 0xFF chips_Realtek: - dd 0x20, chip_ALC650 - dd 0x21, chip_ALC650D - dd 0x22, chip_ALC650E - dd 0x23, chip_ALC650F - dd 0x60, chip_ALC655 - dd 0x80, chip_ALC658 - dd 0x81, chip_ALC658D - dd 0x90, chip_ALC850 - dd 0xFF + dd 0x10, chip_ALC201a + dd 0x20, chip_ALC650 + dd 0x21, chip_ALC650D + dd 0x22, chip_ALC650E + dd 0x23, chip_ALC650F + dd 0x60, chip_ALC655 + dd 0x80, chip_ALC658 + dd 0x81, chip_ALC658D + dd 0x90, chip_ALC850 + dd 0xFF chips_CMedia dd 0x41, chip_CM9738 - dd 0x61, chip_CM9739 - dd 0x69, chip_CM9780 - dd 0x78, chip_CM9761 - dd 0x82, chip_CM9761 - dd 0x83, chip_CM9761 - dd 0xFF + dd 0x61, chip_CM9739 + dd 0x69, chip_CM9780 + dd 0x78, chip_CM9761 + dd 0x82, chip_CM9761 + dd 0x83, chip_CM9761 + dd 0xFF chips_Cirrus dd 0x00, chip_CS4297 - dd 0x10, chip_CS4297A - dd 0x20, chip_CS4298 - dd 0x28, chip_CS4294 - dd 0x30, chip_CS4299 - dd 0x34, chip_CS4299D - dd 0x48, chip_CS4201 - dd 0x58, chip_CS4205 - dd 0x60, chip_CS4291 - dd 0x70, chip_CS4202 - dd 0xFF + dd 0x10, chip_CS4297A + dd 0x20, chip_CS4298 + dd 0x28, chip_CS4294 + dd 0x30, chip_CS4299 + dd 0x34, chip_CS4299D + dd 0x48, chip_CS4201 + dd 0x58, chip_CS4205 + dd 0x60, chip_CS4291 + dd 0x70, chip_CS4202 + dd 0xFF +chips_Wolfson dd 0x00, chip_WM9700 + dd 0x03, chip_WM9703 + dd 0x04, chip_WM9704 + dd 0xFF align 16 ;Analog Devices -chip_AD1819 db 'AD1819 ',0dh,0ah,00h -chip_AD1881 db 'AD1881 ',0dh,0ah,00h -chip_AD1881A db 'AD1881A',0dh,0ah,00h -chip_AD1884 db 'AD1885 ',0dh,0ah,00h -chip_AD1885 db 'AD1885 ',0dh,0ah,00h -chip_AD1886 db 'AD1886 ',0dh,0ah,00h -chip_AD1886A db 'AD1886A',0dh,0ah,00h -chip_AD1887 db 'AD1887 ',0dh,0ah,00h -chip_AD1980 db 'AD1980 ',0dh,0ah,00h -chip_AD1985 db 'AD1985 ',0dh,0ah,00h +chip_AD1819 db 'AD1819 ',0dh,0ah,00h +chip_AD1881 db 'AD1881 ',0dh,0ah,00h +chip_AD1881A db 'AD1881A',0dh,0ah,00h +chip_AD1884 db 'AD1885 ',0dh,0ah,00h +chip_AD1885 db 'AD1885 ',0dh,0ah,00h +chip_AD1886 db 'AD1886 ',0dh,0ah,00h +chip_AD1886A db 'AD1886A',0dh,0ah,00h +chip_AD1887 db 'AD1887 ',0dh,0ah,00h +chip_AD1980 db 'AD1980 ',0dh,0ah,00h +chip_AD1985 db 'AD1985 ',0dh,0ah,00h ;Realtek -chip_ALC650 db 'ALC650 ',0dh,0ah,00h -chip_ALC650D db 'ALC650D',0dh,0ah,00h -chip_ALC650E db 'ALC650E',0dh,0ah,00h -chip_ALC650F db 'ALC650F',0dh,0ah,00h -chip_ALC655 db 'ALC655 ',0dh,0ah,00h -chip_ALC658 db 'ALC658 ',0dh,0ah,00h -chip_ALC658D db 'ALC658D',0dh,0ah,00h -chip_ALC850 db 'ALC850 ',0dh,0ah,00h +chip_ALC201a db 'ALC201a',0dh,0ah,00h +chip_ALC650 db 'ALC650 ',0dh,0ah,00h +chip_ALC650D db 'ALC650D',0dh,0ah,00h +chip_ALC650E db 'ALC650E',0dh,0ah,00h +chip_ALC650F db 'ALC650F',0dh,0ah,00h +chip_ALC655 db 'ALC655 ',0dh,0ah,00h +chip_ALC658 db 'ALC658 ',0dh,0ah,00h +chip_ALC658D db 'ALC658D',0dh,0ah,00h +chip_ALC850 db 'ALC850 ',0dh,0ah,00h ;CMedia -chip_CM9738 db 'CMI9738', 0dh,0ah,0 -chip_CM9739 db 'CMI9739', 0dh,0ah,0 -chip_CM9780 db 'CMI9780', 0dh,0ah,0 -chip_CM9761 db 'CMI9761', 0dh,0ah,0 +chip_CM9738 db 'CMI9738', 0dh,0ah,0 +chip_CM9739 db 'CMI9739', 0dh,0ah,0 +chip_CM9780 db 'CMI9780', 0dh,0ah,0 +chip_CM9761 db 'CMI9761', 0dh,0ah,0 ;Cirrus -chip_CS4297 db 'CS4297',13,10,0 -chip_CS4297A db 'CS4297A',13,10,0 -chip_CS4298 db 'CS4298',13,10,0 -chip_CS4294 db 'CS4294',13,10,0 -chip_CS4299 db 'CS4299',13,10,0 -chip_CS4299D db 'CS4299D',13,10,0 -chip_CS4201 db 'CS4201',13,10,0 -chip_CS4205 db 'CS4205',13,10,0 -chip_CS4291 db 'CS4291',13,10,0 -chip_CS4202 db 'CS4202',13,10,0 - +chip_CS4297 db 'CS4297',13,10,0 +chip_CS4297A db 'CS4297A',13,10,0 +chip_CS4298 db 'CS4298',13,10,0 +chip_CS4294 db 'CS4294',13,10,0 +chip_CS4299 db 'CS4299',13,10,0 +chip_CS4299D db 'CS4299D',13,10,0 +chip_CS4201 db 'CS4201',13,10,0 +chip_CS4205 db 'CS4205',13,10,0 +chip_CS4291 db 'CS4291',13,10,0 +chip_CS4202 db 'CS4202',13,10,0 +;Wolfson +chip_WM9700 db 'WM9704',13,10,0 +chip_WM9703 db 'WM9703/9704',13,10,0 +chip_WM9704 db 'WM9704 (quad)',13,10,0 diff --git a/kernel/trunk/drivers/fm801.asm b/kernel/trunk/drivers/fm801.asm new file mode 100644 index 0000000000..95f283ab9f --- /dev/null +++ b/kernel/trunk/drivers/fm801.asm @@ -0,0 +1,1061 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; 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