Skip to content

Commit 1e2ddab

Browse files
committed
sound blaster code doesn't work yet
1 parent bd35c98 commit 1e2ddab

File tree

12 files changed

+448
-10
lines changed

12 files changed

+448
-10
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
*.raw filter=lfs diff=lfs merge=lfs -text
22
*.pal filter=lfs diff=lfs merge=lfs -text
3+
*.pcm filter=lfs diff=lfs merge=lfs -text

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c) $(wildcard src/test/*.c)
2-
ssrc = $(wildcard src/*.s) $(wildcard src/libc/*.s) $(wildcard src/boot/*.s)
2+
ssrc = $(wildcard src/*.s) $(wildcard src/libc/*.s) $(wildcard src/boot/*.s) $(wildcard src/test/*.s)
33
Ssrc = $(wildcard src/*.S)
44
obj = $(csrc:.c=.o) $(ssrc:.s=.o) $(Ssrc:.S=.o)
55
dep = $(obj:.o=.d)

click-s8_mono.pcm

21.8 KB
Binary file not shown.

src/au_sb.c

Lines changed: 135 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
1919
#include "audio.h"
2020
#include "au_sb.h"
2121
#include "asmops.h"
22+
#include "intr.h"
23+
#include "dma.h"
2224

2325
#define REG_MIXPORT (base_port + 0x4)
2426
#define REG_MIXDATA (base_port + 0x5)
@@ -33,20 +35,49 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
3335
#define WSTAT_BUSY 0x80
3436
#define RSTAT_RDY 0x80
3537

36-
#define CMD_SET_RATE 0x41
37-
#define CMD_PLAY_PCM 0xa6
38-
#define CMD_STOP_PCM 0xd9
39-
#define CMD_GET_VER 0xe1
38+
#define CMD_RATE 0x40
39+
#define CMD_SB16_OUT_RATE 0x41
40+
#define CMD_SB16_IN_RATE 0x42
41+
#define CMD_GET_VER 0xe1
42+
43+
/* start DMA playback/recording. combine with fifo/auto/input flags */
44+
#define CMD_START_DMA8 0xc0
45+
#define CMD_START_DMA16 0xb0
46+
#define CMD_FIFO 0x02
47+
#define CMD_AUTO 0x04
48+
#define CMD_INPUT 0x08
49+
50+
/* immediately pause/continue */
51+
#define CMD_PAUSE_DMA8 0xd0
52+
#define CMD_CONT_DMA8 0xd4
53+
#define CMD_PAUSE_DMA16 0xd5
54+
#define CMD_CONT_DMA16 0xd6
55+
56+
/* end the playback at the end of the current buffer */
57+
#define CMD_END_DMA16 0xd9
58+
#define CMD_END_DMA8 0xda
59+
60+
/* transfer mode commands */
61+
#define CMD_MODE_SIGNED 0x10
62+
#define CMD_MODE_STEREO 0x20
4063

4164
#define VER_MAJOR(x) ((x) >> 8)
4265
#define VER_MINOR(x) ((x) & 0xff)
4366

67+
static void intr_handler();
68+
static void start_dma_transfer(uint32_t addr, int size);
4469
static void write_dsp(unsigned char val);
4570
static unsigned char read_dsp(void);
4671
static int get_dsp_version(void);
4772
static const char *sbname(int ver);
4873

74+
extern unsigned char low_mem_buffer[];
75+
4976
static int base_port;
77+
static int irq, dma_chan;
78+
static int sb16;
79+
static void *buffer;
80+
static int xfer_mode;
5081

5182
int sb_detect(void)
5283
{
@@ -56,12 +87,17 @@ int sb_detect(void)
5687
base_port = 0x200 + ((i + 1) << 4);
5788
if(sb_reset_dsp() == 0) {
5889
ver = get_dsp_version();
90+
sb16 = VER_MAJOR(ver) >= 4;
5991
printf("sb_detect: found %s (DSP v%d.%02d) at port %xh\n", sbname(ver),
6092
VER_MAJOR(ver), VER_MINOR(ver), base_port);
6193
return 1;
6294
}
6395
}
6496

97+
/* TODO: detect these somehow? */
98+
irq = 5;
99+
dma_chan = 1;
100+
65101
return 0;
66102
}
67103

@@ -84,6 +120,101 @@ int sb_reset_dsp(void)
84120
return -1;
85121
}
86122

123+
void sb_set_output_rate(int rate)
124+
{
125+
if(sb16) {
126+
write_dsp(CMD_SB16_OUT_RATE);
127+
write_dsp(rate >> 8);
128+
write_dsp(rate & 0xff);
129+
} else {
130+
int tcon = 256 - 1000000 / rate;
131+
write_dsp(CMD_RATE);
132+
write_dsp(tcon);
133+
}
134+
}
135+
136+
void *sb_buffer(int *size)
137+
{
138+
*size = 65536;
139+
return buffer;
140+
}
141+
142+
void sb_start(int rate, int nchan)
143+
{
144+
uint32_t addr;
145+
int size;
146+
147+
/* for now just use the are after boot2. it's only used by the second stage
148+
* loader and the VBE init code, none of which should overlap with audio playback.
149+
* It's not necessary to use low memory. We can use up to the first 16mb for this,
150+
* so if this becomes an issue, I'll make a DMA buffer allocator over 1mb.
151+
* start the buffer from the next 64k boundary.
152+
*/
153+
addr = ((uint32_t)low_mem_buffer + 0xffff) & 0xffff0000;
154+
buffer = (void*)addr;
155+
156+
xfer_mode = CMD_MODE_SIGNED;
157+
if(nchan > 1) {
158+
xfer_mode |= CMD_MODE_STEREO;
159+
}
160+
161+
if(!(size = audio_callback(buffer, 65536))) {
162+
return;
163+
}
164+
165+
interrupt(IRQ_TO_INTR(irq), intr_handler);
166+
167+
start_dma_transfer(addr, size);
168+
}
169+
170+
void sb_pause(void)
171+
{
172+
write_dsp(CMD_PAUSE_DMA8);
173+
}
174+
175+
void sb_continue(void)
176+
{
177+
write_dsp(CMD_CONT_DMA8);
178+
}
179+
180+
void sb_stop(void)
181+
{
182+
write_dsp(CMD_END_DMA8);
183+
}
184+
185+
void sb_volume(int vol)
186+
{
187+
/* TODO */
188+
}
189+
190+
static void intr_handler()
191+
{
192+
int size;
193+
194+
/* ask for more data */
195+
if(!(size = audio_callback(buffer, 65536))) {
196+
sb_stop();
197+
return;
198+
}
199+
start_dma_transfer((uint32_t)buffer, size);
200+
201+
/* acknowledge the interrupt */
202+
inb(REG_INTACK);
203+
}
204+
205+
static void start_dma_transfer(uint32_t addr, int size)
206+
{
207+
/* set up the next DMA transfer */
208+
dma_out(dma_chan, addr, size, DMA_SINGLE);
209+
210+
/* program the DSP to accept the DMA transfer */
211+
write_dsp(CMD_START_DMA8 | CMD_FIFO);
212+
write_dsp(xfer_mode);
213+
size--;
214+
write_dsp(size & 0xff);
215+
write_dsp((size >> 8) & 0xff);
216+
}
217+
87218
static void write_dsp(unsigned char val)
88219
{
89220
while(inb(REG_WSTAT) & WSTAT_BUSY);

src/au_sb.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,15 @@ int sb_detect(void);
2828
*/
2929
int sb_reset_dsp(void);
3030

31+
void *sb_buffer(int *size);
32+
33+
void sb_set_output_rate(int rate);
34+
35+
void sb_start(int rate, int nchan);
36+
void sb_pause(void);
37+
void sb_continue(void);
38+
void sb_stop(void);
39+
40+
void sb_volume(int vol);
41+
3142
#endif /* AU_SB_H_ */

src/audio.c

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,70 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
1919
#include "audio.h"
2020
#include "au_sb.h"
2121

22-
void init_audio(void)
22+
struct audrv {
23+
void *(*get_buffer)(int *size);
24+
void (*start)(int rate, int nchan);
25+
void (*pause)(void);
26+
void (*cont)(void);
27+
void (*stop)(void);
28+
void (*volume)(int vol);
29+
};
30+
31+
static struct audrv drv;
32+
33+
static audio_callback_func cbfunc;
34+
static void *cbcls;
35+
36+
void audio_init(void)
2337
{
2438
if(sb_detect()) {
25-
/* TODO use the sound blaster */
39+
drv.get_buffer = sb_buffer;
40+
drv.start = sb_start;
41+
drv.pause = sb_pause;
42+
drv.cont = sb_continue;
43+
drv.stop = sb_stop;
44+
drv.volume = sb_volume;
2645
return;
2746
}
2847

2948
printf("No supported audio device detected\n");
3049
}
50+
51+
void audio_set_callback(audio_callback_func func, void *cls)
52+
{
53+
cbfunc = func;
54+
cbcls = cls;
55+
}
56+
57+
int audio_callback(void *buf, int sz)
58+
{
59+
if(!cbfunc) {
60+
return 0;
61+
}
62+
return cbfunc(buf, sz, cbcls);
63+
}
64+
65+
void audio_play(int rate, int nchan)
66+
{
67+
drv.start(rate, nchan);
68+
}
69+
70+
void audio_pause(void)
71+
{
72+
drv.pause();
73+
}
74+
75+
void audio_resume(void)
76+
{
77+
drv.cont();
78+
}
79+
80+
void audio_stop(void)
81+
{
82+
drv.stop();
83+
}
84+
85+
void audio_volume(int vol)
86+
{
87+
drv.volume(vol);
88+
}

src/audio.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
#ifndef AUDIO_H_
1919
#define AUDIO_H_
2020

21-
void init_audio(void);
21+
typedef int (*audio_callback_func)(void *buffer, int size, void *cls);
22+
23+
void audio_init(void);
24+
25+
void audio_set_callback(audio_callback_func func, void *cls);
26+
int audio_callback(void *buf, int sz);
27+
28+
void audio_play(int rate, int nchan);
29+
void audio_pause(void);
30+
void audio_resume(void);
31+
void audio_stop(void);
32+
33+
void audio_volume(int vol);
2234

2335
#endif /* AUDIO_H_ */

0 commit comments

Comments
 (0)