该文件用于播放一段wav文件。
file_copy:将音乐文件拷贝到内存中。音乐文件被保存在硬盘逻辑扇区300的地方,长度为64K;
play_sound:播放该音乐文件;
install_0x25_interrupt:安装0x25号中断(DMA);
rtm_0x25_interrupt_handle:DMA中断处理过程;
write_dsp:向DSP写入命令;
read_dsp:从DSP读取状态 ;
;-------------------------------------------------------------------------------
file_copy:
mov eax, 300
mov ebx, sound_file_address-44
mov ecx, 128
_file_cpy_loop:
call read_hard_disk_0
inc eax
loop _file_cpy_loop
ret
;-------------------------------------------------------------------------------
play_sound:
pushad
call file_copy
;以下复位DSP芯片
mov dx,0x226
mov al,1 ;第一步,先写“1”到复位端口
out dx,al
xor ax,ax
_@1:
dec ax
jnz _@1 ;一个硬件要求的延时(至少3ms)
out dx,al ;第二步,写“0”到复位端口
call read_dsp
cmp al,0xaa ;状态值0xaa表示初始化完成
jz _@4
ret ;直接停机
_@4:
;对DMA控制器编程,设置其工作模式、缓冲区地址和传输长度
mov dx,0x0a ;DMAC1的屏蔽寄存器
mov al,00000_1_01B ;关闭主DMAC的1号通道
out dx,al
;计算缓冲区物理地址
xor ax, ax ;bx:ax=缓冲区20位地址
mov bx, 0x03
xor al,al
out 0x0c,al ;DMAC1高低触发器清零
mov dx,0x02 ;写通道1基址与当前地址寄存器
out dx,al ;低8位DMA地址
mov al,ah
out dx,al ;高8位DMA地址
mov dx,0x83 ;写DMA通道 1 的页面寄存器
mov al,bl
out dx,al
mov dx,0x03 ;写通道1的基字计数与当前字计数器
mov ax,65132 ;数据块(当缓冲区用)的大小
dec ax ;DMA要求实际大小减一
out dx,al ;缓冲区长度低8位
mov al,ah
out dx,al ;缓冲区长度高8位
mov al,0101_1001b ;设置DMAC1通道1工作方式:单字节传送/
out 0x0b,al ;地址递增/自动预置/读传送/通道1
mov dx,0x0a ;DMAC1屏蔽寄存器
mov al,1 ;允许通道1接受请求
out dx,al
mov al,0x40 ;设置DSP采样率(播放)
call write_dsp
mov ax,65536-(256000000/(1*8000))
xchg ah,al ;只使用结果的高8位
call write_dsp
;编程设置DSP的DMA传输模式和数据长度,以启动音频播放
mov al,0x48
call write_dsp
mov ax,65132 ;数据块(当缓冲区用)的大小
shr ax,1 ;长度设为DMA的一半
dec ax
call write_dsp ;写低字节
xchg ah,al
call write_dsp ;写高字节
;打开喇叭输出
mov al,0xd1
call write_dsp
;启动DSP的传输的播放
mov al,0x1c
call write_dsp
popad
ret
;-------------------------------------------------------------------------------
install_0x25_interrupt: ;安装0x25号中断(DMA)
cli ;关中断
sidt [pidt] ;取idt段地址
;设置实时时钟中断处理过程
mov eax, rtm_0x25_interrupt_handle ;门代码在段内偏移地址
mov bx, flat_4gb_code_seg_sel ;门代码所在段的选择子
mov cx, 0x8e00 ;32位中断门,0特权级
call make_gate_descriptor
mov ebx, [pidt + 2] ;中断描述符表的线性地址
mov [ebx + 0x25*8], eax ;中断描述符低32位
mov [ebx + 0x25*8 + 4], edx ;中断描述符高32位
lidt [pidt] ;重新加载中断描述符表寄存器IDTR
in al,0x21 ;读8259主片的IMR寄存器
and al,0xdf ;清除bit 5(DMA)
out 0x21,al ;写回此寄存器
sti ;开中断
ret
;-------------------------------------------------------------------------------
rtm_0x25_interrupt_handle: ;DMA中断处理过程
pushad
;退出自动初始化模式
;mov al,0xda
;call write_dsp
;关闭扬声器
;mov al,0xd3
;call write_dsp
mov dx,0x22f ;DSP中断应答
in al,dx
;发送EOI命令到中断控制器(主片)
mov al,0x20 ;中断结束命令EOI
out 0x20,al ;发给主片
popad
iret
;-------------------------------------------------------------------------------
write_dsp:
push edx
push eax
mov dx,022ch
_@22c:
in al,dx
and al,1000_0000b ;监视22c端口的第7位,直到它变为0
jnz _@22c
pop eax
out dx,al
pop edx
ret
;-------------------------------------------------------------------------------
read_dsp:
push edx
mov dx,22eh
_@22e:
in al,dx
and al,1000_0000b ;监视22e端口的位7,直到它变成1
jz _@22e
mov dx,22ah
in al,dx ;此时可以从22a端口读取数据
pop edx
ret