如何使用直写模式编写一个简单的 soundblaster 16 驱动程序作为一个爱好 OS?

How to write a simple soundblaster 16 driver using direct write mode for a hobby OS?

我正在开发一个 32 位、保护模式的业余操作系统。目前,我希望添加简单的声音支持。为此,我希望使用 sound blaster 16 并使用直接模式写入 DAC(我想不惜一切代价避免使用 DMA)。然而,当我向 DAC 输出一个简单的方波时(使用命令 0x10),我的计算机扬声器没有声音输出。我正在寻找这个问题的解决方案。

我正在尝试使用以下算法来产生声音:

1. Reset DSP
2. Enable the speakers
3. Write 0x10 to 0x22C (direct mode DAC write command)
4. Write 0x00 to 0x22C (To set the speaker to low)
5. Write 0x10 to 0x22C
6. Write 0xFF to 0x22C (To set the speaker to high)
7. Jump back to step 4 and repeat.

这是我的代码:

#define DSP_RESET 0x226
#define DSP_READ 0x22A
#define DSP_WRITE 0x22C
#define DSP_READ_STATUS 0x22E
#define DSP_INT_ACK 0x22F

#define REG_ADDR 0x224
#define REG_DATA 0x225

#define DIRECT_DAC 0x10
#define ENABLE_SPEAKER 0xD1

void dsp_reset(){
      uint32_t buf[4];
      *buf = 128;
      rtc_write(0, buf, 4);

      outb(1, DSP_RESET);
      rtc_read(0, 0, NULL, 0);
      outb(0, DSP_RESET);

      if(inb(DSP_READ) != 0xAA){
            print_term((uint8_t *)"Could not init sb16\n", 20);
      }

      return;
}

void play_simple_sound(){

      dsp_reset();

      while(inb(DSP_WRITE));
      print_term((uint8_t *)"Enabling speaker\n", 18);
      outb(0xD1, DSP_WRITE);

      while(inb(DSP_WRITE));
      print_term((uint8_t *)"Playing sound\n", 14);
      outb(0xF0, DSP_WRITE);

      while(1){
            while(inb(DSP_WRITE));
            outb(0x10, DSP_WRITE);
            outb(0x00, DSP_WRITE);
            rtc_read(0, 0, NULL, 0);
            while(inb(DSP_WRITE));
            outb(0x10, DSP_WRITE);
            outb(0xFF, DSP_WRITE);
            rtc_read(0, 0, NULL, 0);
      }

      return;
}

rtc_write 将 rtc 频率设置为几百赫兹,rct_read 使程序在 rtc 上等待(这两个程序都可以正常工作)。 dsp_reset 也能正常工作,因为从 DSP 读取输出时,返回 0xAA(这表明存在 soundblaster 16)。

目前我正在使用 windows 10 64 位到 运行 模拟操作系统的 Qemu。我 运行ning qemu 设置了“-soundhw all”选项。我不确定是否因为我编写的代码而无法听到声音,或者 Qemu 是否有问题。我的问题是,问题可能是什么,我可以采取哪些步骤来解决这个问题?此外,与 sb 16 相关的文档和教程将不胜感激。

在 Qemu 仿真下,无法使用 soundblaster 16 直接进行 DAC。也不允许使用直接 ADC。查看这里找到的源代码,查看从第390行开始支持的命令:

https://github.com/qemu/qemu/blob/master/hw/audio/sb16.c

看来要使用声霸卡输出声音,必须使用DMA。更进一步,看起来 Qemu 上的 SB16 仿真非常缺乏。真正的 SB16 支持的命令列表可以在这里找到:http://the.earth.li/~tfm/oldpage/sb_dsp.html。将这些命令与 Qemu 支持的命令进行比较,只模拟了一小部分。

编辑 2:查看其他仿真器,Bochs 不支持 sb16(参见第 858 行:http://bochs.sourceforge.net/cgi-bin/lxr/source/iodev/sound/sb16.cc), but DOSBox has very impressive SB16 support, and does support direct DAC, but still doesn't support microphone direct ADC (see line 1611: http://dosbox-x.com/doxygen/html/sblaster_8cpp_source.html