From 1e2ddab65ead32350d8ff87a6de74168e429666b Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Thu, 24 May 2018 22:15:14 +0300 Subject: [PATCH] sound blaster code doesn't work yet --- .gitattributes | 1 + Makefile | 2 +- click-s8_mono.pcm | Bin 0 -> 22310 bytes src/au_sb.c | 139 ++++++++++++++++++++++++++++++++++++++++++++-- src/au_sb.h | 11 ++++ src/audio.c | 62 ++++++++++++++++++++- src/audio.h | 14 ++++- src/dma.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/dma.h | 34 ++++++++++++ src/kmain.c | 2 +- src/test/ausamples.s | 6 ++ src/test/vbetest.c | 37 ++++++++++++- 12 files changed, 448 insertions(+), 10 deletions(-) create mode 100644 click-s8_mono.pcm create mode 100644 src/dma.c create mode 100644 src/dma.h create mode 100644 src/test/ausamples.s diff --git a/.gitattributes b/.gitattributes index 74778d1..de879ae 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ *.raw filter=lfs diff=lfs merge=lfs -text *.pal filter=lfs diff=lfs merge=lfs -text +*.pcm filter=lfs diff=lfs merge=lfs -text diff --git a/Makefile b/Makefile index 07e856f..9622719 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c) $(wildcard src/test/*.c) -ssrc = $(wildcard src/*.s) $(wildcard src/libc/*.s) $(wildcard src/boot/*.s) +ssrc = $(wildcard src/*.s) $(wildcard src/libc/*.s) $(wildcard src/boot/*.s) $(wildcard src/test/*.s) Ssrc = $(wildcard src/*.S) obj = $(csrc:.c=.o) $(ssrc:.s=.o) $(Ssrc:.S=.o) dep = $(obj:.o=.d) diff --git a/click-s8_mono.pcm b/click-s8_mono.pcm new file mode 100644 index 0000000000000000000000000000000000000000..184f5dce830e3316219e7ebdd7d3279eded23207 GIT binary patch literal 22310 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 VS5;#Ju(eh8e6#yiRDXWqzX03>*jWGo literal 0 HcmV?d00001 diff --git a/src/au_sb.c b/src/au_sb.c index f3184ae..b42a603 100644 --- a/src/au_sb.c +++ b/src/au_sb.c @@ -19,6 +19,8 @@ along with this program. If not, see . #include "audio.h" #include "au_sb.h" #include "asmops.h" +#include "intr.h" +#include "dma.h" #define REG_MIXPORT (base_port + 0x4) #define REG_MIXDATA (base_port + 0x5) @@ -33,20 +35,49 @@ along with this program. If not, see . #define WSTAT_BUSY 0x80 #define RSTAT_RDY 0x80 -#define CMD_SET_RATE 0x41 -#define CMD_PLAY_PCM 0xa6 -#define CMD_STOP_PCM 0xd9 -#define CMD_GET_VER 0xe1 +#define CMD_RATE 0x40 +#define CMD_SB16_OUT_RATE 0x41 +#define CMD_SB16_IN_RATE 0x42 +#define CMD_GET_VER 0xe1 + +/* start DMA playback/recording. combine with fifo/auto/input flags */ +#define CMD_START_DMA8 0xc0 +#define CMD_START_DMA16 0xb0 +#define CMD_FIFO 0x02 +#define CMD_AUTO 0x04 +#define CMD_INPUT 0x08 + +/* immediately pause/continue */ +#define CMD_PAUSE_DMA8 0xd0 +#define CMD_CONT_DMA8 0xd4 +#define CMD_PAUSE_DMA16 0xd5 +#define CMD_CONT_DMA16 0xd6 + +/* end the playback at the end of the current buffer */ +#define CMD_END_DMA16 0xd9 +#define CMD_END_DMA8 0xda + +/* transfer mode commands */ +#define CMD_MODE_SIGNED 0x10 +#define CMD_MODE_STEREO 0x20 #define VER_MAJOR(x) ((x) >> 8) #define VER_MINOR(x) ((x) & 0xff) +static void intr_handler(); +static void start_dma_transfer(uint32_t addr, int size); static void write_dsp(unsigned char val); static unsigned char read_dsp(void); static int get_dsp_version(void); static const char *sbname(int ver); +extern unsigned char low_mem_buffer[]; + static int base_port; +static int irq, dma_chan; +static int sb16; +static void *buffer; +static int xfer_mode; int sb_detect(void) { @@ -56,12 +87,17 @@ int sb_detect(void) base_port = 0x200 + ((i + 1) << 4); if(sb_reset_dsp() == 0) { ver = get_dsp_version(); + sb16 = VER_MAJOR(ver) >= 4; printf("sb_detect: found %s (DSP v%d.%02d) at port %xh\n", sbname(ver), VER_MAJOR(ver), VER_MINOR(ver), base_port); return 1; } } + /* TODO: detect these somehow? */ + irq = 5; + dma_chan = 1; + return 0; } @@ -84,6 +120,101 @@ int sb_reset_dsp(void) return -1; } +void sb_set_output_rate(int rate) +{ + if(sb16) { + write_dsp(CMD_SB16_OUT_RATE); + write_dsp(rate >> 8); + write_dsp(rate & 0xff); + } else { + int tcon = 256 - 1000000 / rate; + write_dsp(CMD_RATE); + write_dsp(tcon); + } +} + +void *sb_buffer(int *size) +{ + *size = 65536; + return buffer; +} + +void sb_start(int rate, int nchan) +{ + uint32_t addr; + int size; + + /* for now just use the are after boot2. it's only used by the second stage + * loader and the VBE init code, none of which should overlap with audio playback. + * It's not necessary to use low memory. We can use up to the first 16mb for this, + * so if this becomes an issue, I'll make a DMA buffer allocator over 1mb. + * start the buffer from the next 64k boundary. + */ + addr = ((uint32_t)low_mem_buffer + 0xffff) & 0xffff0000; + buffer = (void*)addr; + + xfer_mode = CMD_MODE_SIGNED; + if(nchan > 1) { + xfer_mode |= CMD_MODE_STEREO; + } + + if(!(size = audio_callback(buffer, 65536))) { + return; + } + + interrupt(IRQ_TO_INTR(irq), intr_handler); + + start_dma_transfer(addr, size); +} + +void sb_pause(void) +{ + write_dsp(CMD_PAUSE_DMA8); +} + +void sb_continue(void) +{ + write_dsp(CMD_CONT_DMA8); +} + +void sb_stop(void) +{ + write_dsp(CMD_END_DMA8); +} + +void sb_volume(int vol) +{ + /* TODO */ +} + +static void intr_handler() +{ + int size; + + /* ask for more data */ + if(!(size = audio_callback(buffer, 65536))) { + sb_stop(); + return; + } + start_dma_transfer((uint32_t)buffer, size); + + /* acknowledge the interrupt */ + inb(REG_INTACK); +} + +static void start_dma_transfer(uint32_t addr, int size) +{ + /* set up the next DMA transfer */ + dma_out(dma_chan, addr, size, DMA_SINGLE); + + /* program the DSP to accept the DMA transfer */ + write_dsp(CMD_START_DMA8 | CMD_FIFO); + write_dsp(xfer_mode); + size--; + write_dsp(size & 0xff); + write_dsp((size >> 8) & 0xff); +} + static void write_dsp(unsigned char val) { while(inb(REG_WSTAT) & WSTAT_BUSY); diff --git a/src/au_sb.h b/src/au_sb.h index 9552bcd..d437ff7 100644 --- a/src/au_sb.h +++ b/src/au_sb.h @@ -28,4 +28,15 @@ int sb_detect(void); */ int sb_reset_dsp(void); +void *sb_buffer(int *size); + +void sb_set_output_rate(int rate); + +void sb_start(int rate, int nchan); +void sb_pause(void); +void sb_continue(void); +void sb_stop(void); + +void sb_volume(int vol); + #endif /* AU_SB_H_ */ diff --git a/src/audio.c b/src/audio.c index c7142f1..49b8a8d 100644 --- a/src/audio.c +++ b/src/audio.c @@ -19,12 +19,70 @@ along with this program. If not, see . #include "audio.h" #include "au_sb.h" -void init_audio(void) +struct audrv { + void *(*get_buffer)(int *size); + void (*start)(int rate, int nchan); + void (*pause)(void); + void (*cont)(void); + void (*stop)(void); + void (*volume)(int vol); +}; + +static struct audrv drv; + +static audio_callback_func cbfunc; +static void *cbcls; + +void audio_init(void) { if(sb_detect()) { - /* TODO use the sound blaster */ + drv.get_buffer = sb_buffer; + drv.start = sb_start; + drv.pause = sb_pause; + drv.cont = sb_continue; + drv.stop = sb_stop; + drv.volume = sb_volume; return; } printf("No supported audio device detected\n"); } + +void audio_set_callback(audio_callback_func func, void *cls) +{ + cbfunc = func; + cbcls = cls; +} + +int audio_callback(void *buf, int sz) +{ + if(!cbfunc) { + return 0; + } + return cbfunc(buf, sz, cbcls); +} + +void audio_play(int rate, int nchan) +{ + drv.start(rate, nchan); +} + +void audio_pause(void) +{ + drv.pause(); +} + +void audio_resume(void) +{ + drv.cont(); +} + +void audio_stop(void) +{ + drv.stop(); +} + +void audio_volume(int vol) +{ + drv.volume(vol); +} diff --git a/src/audio.h b/src/audio.h index 60b6bd5..9b528c2 100644 --- a/src/audio.h +++ b/src/audio.h @@ -18,6 +18,18 @@ along with this program. If not, see . #ifndef AUDIO_H_ #define AUDIO_H_ -void init_audio(void); +typedef int (*audio_callback_func)(void *buffer, int size, void *cls); + +void audio_init(void); + +void audio_set_callback(audio_callback_func func, void *cls); +int audio_callback(void *buf, int sz); + +void audio_play(int rate, int nchan); +void audio_pause(void); +void audio_resume(void); +void audio_stop(void); + +void audio_volume(int vol); #endif /* AUDIO_H_ */ diff --git a/src/dma.c b/src/dma.c new file mode 100644 index 0000000..b6c4605 --- /dev/null +++ b/src/dma.c @@ -0,0 +1,150 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include "dma.h" +#include "asmops.h" + +/* 8bit DMA ports */ +#define DMA_0_ADDR 0x00 +#define DMA_0_COUNT 0x01 +#define DMA_1_ADDR 0x02 +#define DMA_1_COUNT 0x03 +#define DMA_2_ADDR 0x04 +#define DMA_2_COUNT 0x05 +#define DMA_3_ADDR 0x06 +#define DMA_3_COUNT 0x07 +/* 16bit DMA ports */ +#define DMA_4_ADDR 0xc0 +#define DMA_4_COUNT 0xc2 +#define DMA_5_ADDR 0xc4 +#define DMA_5_COUNT 0xc6 +#define DMA_6_ADDR 0xc8 +#define DMA_6_COUNT 0xca +#define DMA_7_ADDR 0xcc +#define DMA_7_COUNT 0xce + +#define DMA_ADDR(c) \ + ((c < 4) ? DMA_0_ADDR + ((c) << 1) : (DMA_4_ADDR + ((c) << 2))) +#define DMA_COUNT(c) \ + ((c < 4) ? DMA_0_COUNT + ((c) << 1) : (DMA_4_COUNT + ((c) << 2))) + +#define DMA8_MASK 0x0a +#define DMA8_MODE 0x0b +#define DMA8_CLR_FLIPFLOP 0x0c +#define DMA8_RESET 0x0d +#define DMA8_MASK_RST 0x0e +#define DMA8_RMASK 0x0f +#define DMA16_MASK 0xd4 +#define DMA16_MODE 0xd6 +#define DMA16_CLR_FLIPFLOP 0xd8 +#define DMA16_RESET 0xda +#define DMA16_MASK_RST 0xdc +#define DMA16_RMASK 0xde + +#define DMA_MASK(c) ((c) < 4 ? DMA8_MASK : DMA16_MASK) +#define DMA_MODE(c) ((c) < 4 ? DMA8_MODE : DMA16_MODE) +#define DMA_CLR_FLIPFLOP(c) ((c) < 4 ? DMA8_CLR_FLIPFLOP : DMA16_CLR_FLIPFLOP) +#define DMA_RESET(c) ((c) < 4 ? DMA8_RESET : DMA16_RESET) +#define DMA_MASK_RST(c) ((c) < 4 ? DMA8_MASK_RST : DMA16_MASK_RST) +#define DMA_RMASK(c) ((c) < 4 ? DMA8_RMASK : DMA16_RMASK) + +#define DMA_0_PAGE 0x87 +#define DMA_1_PAGE 0x83 +#define DMA_2_PAGE 0x81 +#define DMA_3_PAGE 0x82 +#define DMA_4_PAGE 0x8f +#define DMA_5_PAGE 0x8b +#define DMA_6_PAGE 0x89 +#define DMA_7_PAGE 0x8a + +#define MODE_CHAN(x) ((x) & 3) +#define MODE_WRITE 0x04 +#define MODE_READ 0x08 +#define MODE_AUTO 0x10 +#define MODE_DECR 0x20 +#define MODE_SINGLE 0x40 +#define MODE_BLOCK 0x80 +#define MODE_CASCADE 0xc0 + +#define MASK_CHAN(x) ((x) & 3) +#define MASK_DISABLE 0x04 + +#define RMASK_CHAN(x) (1 << ((x) & 3)) + +#define IS_16BIT(c) ((c) >= 4) + +static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir); +static inline void mask(int chan); +static inline void unmask(int chan); + +static int page_port[] = { + DMA_0_PAGE, DMA_1_PAGE, DMA_2_PAGE, DMA_3_PAGE, + DMA_4_PAGE, DMA_5_PAGE, DMA_6_PAGE, DMA_7_PAGE +}; + +void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags) +{ + dma_io(chan, phyaddr, size, flags, MODE_READ); +} + +void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags) +{ + dma_io(chan, phyaddr, size, flags, MODE_WRITE); +} + +static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir) +{ + unsigned int mode; + int addr_port, count_port; + + addr_port = DMA_ADDR(chan); + count_port = DMA_COUNT(chan); + + mask(chan); + outb(0, DMA_CLR_FLIPFLOP(chan)); + + /* single / block / cascade */ + mode = ((flags & 3) << 6) | MODE_CHAN(chan); + if(flags & DMA_DECR) mode |= MODE_DECR; + if(flags & DMA_AUTO) mode |= MODE_AUTO; + outb(mode, DMA_MODE(chan)); + + if(IS_16BIT(chan)) { + phyaddr >>= 1; + size >>= 1; + } + + outb(phyaddr & 0xff, addr_port); + outb((phyaddr >> 8) & 0xff, addr_port); + outb((phyaddr >> 16) & 0xff, page_port[chan]); + + size--; + outb(size & 0xff, count_port); + outb((size >> 8) & 0xff, count_port); + + unmask(chan); +} + +static inline void mask(int chan) +{ + outb(MASK_CHAN(chan) | MASK_DISABLE, DMA_MASK(chan)); +} + +static inline void unmask(int chan) +{ + outb(MASK_CHAN(chan), DMA_MASK(chan)); +} diff --git a/src/dma.h b/src/dma.h new file mode 100644 index 0000000..8f469c0 --- /dev/null +++ b/src/dma.h @@ -0,0 +1,34 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef DMA_H_ +#define DMA_H_ + +#include + +enum { + DMA_SINGLE = 0x01, + DMA_BLOCK = 0x02, + DMA_CASCADE = DMA_SINGLE | DMA_BLOCK, + DMA_DECR = 0x08, + DMA_AUTO = 0x10 +}; + +void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags); +void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags); + +#endif /* DMA_H_ */ diff --git a/src/kmain.c b/src/kmain.c index 8e4eba4..8af7cc3 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -49,7 +49,7 @@ void pcboot_main(void) /* initialize the timer */ init_timer(); - init_audio(); + audio_init(); enable_intr(); diff --git a/src/test/ausamples.s b/src/test/ausamples.s new file mode 100644 index 0000000..f20b5a9 --- /dev/null +++ b/src/test/ausamples.s @@ -0,0 +1,6 @@ + .data + .global snd_click + .global snd_click_size +snd_click: + .incbin "click-s8_mono.pcm" +snd_click_size: .long . - snd_click diff --git a/src/test/vbetest.c b/src/test/vbetest.c index 1133dec..186d7a9 100644 --- a/src/test/vbetest.c +++ b/src/test/vbetest.c @@ -5,8 +5,10 @@ #include "keyb.h" #include "psaux.h" #include "contty.h" +#include "audio.h" static void draw_cursor(int x, int y, uint16_t col); +static int click_sound_callback(void *buffer, int size, void *cls); static uint16_t *framebuf; @@ -31,10 +33,16 @@ static uint16_t cursor[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; +static int click; + +/* defined in sndsamples.s */ +extern void *snd_click; +extern int snd_click_size; + int vbetest(void) { int i, j, nmodes, mx, my; - unsigned int st; + unsigned int st, prev_st = 0; struct video_mode vi; uint16_t *fbptr; @@ -78,6 +86,8 @@ int vbetest(void) set_mouse_bounds(0, 0, 639, 479); + audio_set_callback(click_sound_callback, 0); + /* empty the kb queue */ while(kb_getkey() != -1); @@ -87,6 +97,20 @@ int vbetest(void) } st = mouse_state(&mx, &my); + + for(i=0; i<3; i++) { + unsigned int bit = 1 << i; + if(((st & bit) ^ (prev_st & bit)) & (st & bit)) { + click = 1; + } + } + if(click) { + printf("click!\n"); + audio_play(22050, 1); + } + + prev_st = st; + draw_cursor(mx, my, st & 1 ? 0xf800 : (st & 2 ? 0x7e0 : (st & 4 ? 0x00ff : 0))); halt_cpu(); @@ -147,3 +171,14 @@ static void draw_cursor(int x, int y, uint16_t col) savp += CURSOR_XSZ - w; } } + +/* snd_click_size is < 65536 so we can just throw it all at once in there */ +static int click_sound_callback(void *buffer, int size, void *cls) +{ + if(click) { + memcpy(buffer, snd_click, snd_click_size); + click = 0; + return snd_click_size; + } + return 0; +} -- 1.7.10.4