Skip to content

Commit

Permalink
WIP: basic DMA functionality for screamer
Browse files Browse the repository at this point in the history
  • Loading branch information
mcayland committed Sep 23, 2024
1 parent 4431f3f commit 36d2758
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 11 deletions.
96 changes: 85 additions & 11 deletions hw/audio/screamer.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
#define CODEC_STAT_MASK_VALID (0x1 << 22)

/* Audio */
#define SCREAMER_SAMPLE_RATE 44100
static const char *s_spk = "screamer";

static void pmac_transfer(DBDMA_io *io)
Expand All @@ -74,15 +73,14 @@ static void pmac_transfer(DBDMA_io *io)
io->len = 0;

/* Finish */
qemu_irq_raise(s->irq);
io->dma_end(io);
}

static void pmac_screamer_tx(DBDMA_io *io)
{
ScreamerState *s = io->opaque;

printf("TX yeah!\n");
printf("DMA TX!\n");

if (s->bpos + io->len > SCREAMER_BUFFER_SIZE) {
/* Not enough space in the buffer, so defer IRQ */
Expand Down Expand Up @@ -121,7 +119,7 @@ static void screamerspk_callback(void *opaque, int avail)
if (s->bpos) {
if (s->ppos < s->bpos) {
n = MIN(s->bpos - s->ppos, (unsigned int)avail);
printf("########### SPEAKER WRITE! %d / %d - %d\n", s->ppos, s->bpos, n);
printf("########### AUDIO WRITE! %d / %d - %d\n", s->ppos, s->bpos, n);
len = AUD_write(s->voice, &s->buf[s->ppos], n);
s->ppos += len;
return;
Expand All @@ -136,35 +134,80 @@ static void screamerspk_callback(void *opaque, int avail)
}
}

static void screamer_update_rate(ScreamerState *s)
{
struct audsettings as = { s->rate, 2, AUDIO_FORMAT_U16, 0 };

s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, screamerspk_callback, &as);
if (!s->voice) {
AUD_log(s_spk, "Could not open voice\n");
return;
}

AUD_set_active_out(s->voice, true);
}

static void screamer_reset(DeviceState *dev)
{
ScreamerState *s = SCREAMER(dev);

memset(s->regs, 0, sizeof(s->regs));
memset(s->codec_ctrl_regs, 0, sizeof(s->codec_ctrl_regs));

s->rate = 44100;
s->bpos = 0;
s->ppos = 0;

screamer_update_rate(s);

return;
}

static void screamer_realizefn(DeviceState *dev, Error **errp)
{
struct audsettings as = {SCREAMER_SAMPLE_RATE, 2, AUDIO_FORMAT_S16, 0};
ScreamerState *s = SCREAMER(dev);

if (!AUD_register_card(s_spk, &s->card, errp)) {
return;
}
}

s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, screamerspk_callback, &as);
if (!s->voice) {
AUD_log(s_spk, "Could not open voice\n");
return;
static void screamer_control_write(ScreamerState *s, uint32_t val)
{
printf("%s: val %" PRId32 "\n", __func__, val);

s->regs[0] = val;

/* Basic rate selection */
switch ((val & 0x700) >> 8) {
case 0x00:
s->rate = 44100;
break;
case 0x1:
s->rate = 29400;
break;
case 0x2:
s->rate = 22050;
break;
case 0x3:
s->rate = 17640;
break;
case 0x4:
s->rate = 14700;
break;
case 0x5:
s->rate = 11025;
break;
case 0x6:
s->rate = 8820;
break;
case 0x7:
s->rate = 7350;
break;
}

AUD_set_active_out(s->voice, true);
printf("basic rate: %d\n", s->rate);
screamer_update_rate(s);
}

static void screamer_codec_write(ScreamerState *s, hwaddr addr,
Expand All @@ -173,6 +216,37 @@ static void screamer_codec_write(ScreamerState *s, hwaddr addr,
SCREAMER_DPRINTF("%s: addr " HWADDR_PRIx " val %" PRIx64 "\n", __func__, addr, val);

s->codec_ctrl_regs[addr] = val;

/* Extra rate selection */
switch ((val & 0x38) >> 3) {
case 0x0:
s->rate = 48000;
break;
case 0x1:
s->rate = 32000;
break;
case 0x2:
s->rate = 24000;
break;
case 0x3:
s->rate = 19200;
break;
case 0x4:
s->rate = 16000;
break;
case 0x5:
s->rate = 12000;
break;
case 0x6:
s->rate = 9600;
break;
case 0x7:
s->rate = 8000;
break;
}

printf("extra rate: %d\n", s->rate);
screamer_update_rate(s);
}

static uint64_t screamer_read(void *opaque, hwaddr addr, unsigned size)
Expand Down Expand Up @@ -221,7 +295,7 @@ static void screamer_write(void *opaque, hwaddr addr,

switch (addr) {
case SND_CTRL_REG:
s->regs[addr] = val & 0xffffffff;
screamer_control_write(s, val & 0xffffffff);
break;
case CODEC_CTRL_REG:
s->regs[addr] = val & 0xffffffff;
Expand Down
1 change: 1 addition & 0 deletions include/hw/audio/screamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct ScreamerState {
uint8_t buf[SCREAMER_BUFFER_SIZE];
uint32_t bpos;
uint32_t ppos;
uint32_t rate;
DBDMA_io io;

uint32_t regs[6];
Expand Down

0 comments on commit 36d2758

Please sign in to comment.