Commit 80e38dd5 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] emu10k further updates/bug fixes

parent ebf09724
This diff is collapsed.
......@@ -158,8 +158,8 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t
spin_unlock_irqrestore(&woinst->lock, flags);
return -ENXIO;
}
if (woinst->format.passthrough) {
// This is for emu10k1 revs less than 7, we need to go through tram
if (woinst->format.passthrough == 1) {
int r;
woinst->buffer.ossfragshift = PT_BLOCKSIZE_LOG2;
......@@ -350,8 +350,9 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
case SNDCTL_DSP_GETCAPS:
DPF(2, "SNDCTL_DSP_GETCAPS:\n");
return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg);
return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
DSP_CAP_TRIGGER | DSP_CAP_MMAP |
DSP_CAP_COPROC| DSP_CAP_MULTI, (int *) arg);
case SNDCTL_DSP_SPEED:
DPF(2, "SNDCTL_DSP_SPEED:\n");
......@@ -789,7 +790,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
cinfo.blocks = 0;
}
if(wiinst->mmapped)
if (wiinst->mmapped)
wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size;
spin_unlock_irqrestore(&wiinst->lock, flags);
......@@ -811,15 +812,17 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
spin_lock_irqsave(&woinst->lock, flags);
if (woinst->state & WAVE_STATE_OPEN ||
(woinst->format.passthrough && wave_dev->card->pt.state)) {
((woinst->format.passthrough == 1) && wave_dev->card->pt.state)) {
int num_fragments;
if (woinst->format.passthrough) {
if (woinst->format.passthrough == 1) {
emu10k1_pt_waveout_update(wave_dev);
cinfo.bytes = woinst->total_played;
} else {
emu10k1_waveout_update(woinst);
cinfo.bytes = woinst->total_played;
}
cinfo.ptr = woinst->buffer.hw_pos;
num_fragments = cinfo.bytes / woinst->buffer.fragment_size;
cinfo.blocks = num_fragments - woinst->blocks;
......@@ -899,7 +902,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
if (file->f_mode & FMODE_WRITE) {
/* digital pass-through fragment count and size are fixed values */
if (woinst->state & WAVE_STATE_OPEN || woinst->format.passthrough)
if (woinst->state & WAVE_STATE_OPEN || (woinst->format.passthrough == 1))
return -EINVAL; /* too late to change */
woinst->buffer.ossfragshift = val & 0xffff;
......@@ -936,19 +939,35 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
kfree (buf);
return -EINVAL;
}
if (buf->command == CMD_WRITE) {
#ifdef DBGEMU
if ( (buf->offs < 0) || (buf->offs + buf->len > 0x800) || (buf->len > 1000)) {
if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) {
#else
if ( ((buf->offs < 0x100 ) || (buf->offs + buf->len > 0x800) || (buf->len > 1000))
&& !( ( buf->offs == DBG) && (buf->len ==1) )){
if (((buf->offs < 0x100) || (buf->offs + buf->len > (wave_dev->card->is_audigy ? 0xe00 : 0x800)) || (buf->len > 1000)
) && !(
//any register allowed raw access to users goes here:
(buf->offs == DBG ||
buf->offs == A_DBG)
&& (buf->len == 1))) {
#endif
kfree(buf);
return -EINVAL;
}
} else {
if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) {
kfree(buf);
return -EINVAL;
}
}
if (((unsigned)buf->flags) > 0x3f)
buf->flags = 0;
if (buf->command == CMD_READ) {
for (i = 0; i < buf->len; i++)
((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, 0);
((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, buf->flags);
if (copy_to_user((copr_buffer *) arg, buf, sizeof(copr_buffer))) {
kfree(buf);
......@@ -956,7 +975,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
}
} else {
for (i = 0; i < buf->len; i++)
sblive_writeptr(wave_dev->card, buf->offs + i, 0, ((u32 *) buf->data)[i]);
sblive_writeptr(wave_dev->card, buf->offs + i, buf->flags, ((u32 *) buf->data)[i]);
}
kfree (buf);
......@@ -1244,8 +1263,9 @@ static int emu10k1_audio_release(struct inode *inode, struct file *file)
struct woinst *woinst = wave_dev->woinst;
spin_lock_irqsave(&woinst->lock, flags);
if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE) {
if(woinst->format.passthrough==2)
card->pt.state=PT_STATE_PLAYING;
if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE){
spin_lock(&card->pt.lock);
emu10k1_pt_stop(card);
spin_unlock(&card->pt.lock);
......
......@@ -113,7 +113,7 @@ int emu10k1_mpuin_close(struct emu10k1_card *card)
}
/* Disable RX interrupt */
emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
emu10k1_mpu_release(card);
......@@ -189,7 +189,7 @@ int emu10k1_mpuin_start(struct emu10k1_card *card)
card_mpuin->qhead = 0;
card_mpuin->qtail = 0;
emu10k1_irq_enable(card, INTE_MIDIRXENABLE);
emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
}
return 0;
......@@ -207,7 +207,7 @@ int emu10k1_mpuin_stop(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuin_stop()\n");
emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
......@@ -246,7 +246,7 @@ int emu10k1_mpuin_reset(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuin_reset()\n");
emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
while (card_mpuin->firstmidiq) {
midiq = card_mpuin->firstmidiq;
......
......@@ -72,7 +72,7 @@ int emu10k1_mpuout_close(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuout_close()\n");
emu10k1_irq_disable(card, INTE_MIDITXENABLE);
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
spin_lock_irqsave(&card_mpuout->lock, flags);
......@@ -142,7 +142,7 @@ int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihd
card_mpuout->intr = 0;
emu10k1_irq_enable(card, INTE_MIDITXENABLE);
emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
spin_unlock_irqrestore(&card_mpuout->lock, flags);
......@@ -206,7 +206,7 @@ void emu10k1_mpuout_bh(unsigned long refdata)
if ((card_mpuout->firstmidiq != NULL) || cByteSent) {
card_mpuout->intr = 0;
emu10k1_irq_enable(card, INTE_MIDITXENABLE);
emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
}
spin_unlock_irqrestore(&card_mpuout->lock, flags);
......@@ -221,7 +221,7 @@ int emu10k1_mpuout_irqhandler(struct emu10k1_card *card)
DPF(4, "emu10k1_mpuout_irqhandler\n");
card_mpuout->intr = 1;
emu10k1_irq_disable(card, INTE_MIDITXENABLE);
emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
tasklet_hi_schedule(&card_mpuout->tasklet);
......
......@@ -85,26 +85,37 @@ static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format
break;
}
if (do_passthrough) {
i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name);
j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name);
/* currently only one waveout instance may use pass-through */
if (i < 0 || j < 0 || woinst->state != WAVE_STATE_CLOSED ||
if (woinst->state != WAVE_STATE_CLOSED ||
card->pt.state != PT_STATE_INACTIVE ||
(wave_fmt->samplingrate != 48000 && !is_ac3) ||
(wave_fmt->samplingrate != 48000 && !is_ac3)) {
DPF(2, "unable to set pass-through mode\n");
} else {
} else if (USE_PT_METHOD1) {
i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name);
j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name);
if (i < 0 || j < 0)
DPF(2, "unable to set pass-through mode\n");
else {
wave_fmt->samplingrate = 48000;
wave_fmt->channels = 2;
card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
card->pt.pos_gpr_name);
wave_fmt->passthrough = 1;
card->pt.intr_gpr = i;
card->pt.enable_gpr = j;
card->pt.state = PT_STATE_INACTIVE;
card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.pos_gpr_name);
DPD(2, "is_ac3 is %d\n", is_ac3);
card->pt.ac3data = is_ac3;
wave_fmt->bitsperchannel = 16;
}
}else{
DPF(2, "Using Passthrough Method 2\n");
card->pt.enable_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
card->pt.enable_gpr_name);
wave_fmt->passthrough = 2;
wave_fmt->bitsperchannel = 16;
}
}
wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
......@@ -149,16 +160,6 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample;
voice->start = voice->startloop;
if (voice->flags & VOICE_FLAGS_STEREO) {
voice->params[0].send_a = card->waveout.send_a[1];
voice->params[0].send_b = card->waveout.send_b[1];
voice->params[0].send_c = card->waveout.send_c[1];
voice->params[0].send_d = card->waveout.send_d[1];
if (woinst->device)
voice->params[0].send_routing = 0x7654;
else
voice->params[0].send_routing = card->waveout.send_routing[1];
voice->params[0].volume_target = 0xffff;
voice->params[0].initial_fc = 0xff;
......@@ -166,15 +167,29 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
voice->params[0].byampl_env_sustain = 0x7f;
voice->params[0].byampl_env_decay = 0x7f;
voice->params[1].send_a = card->waveout.send_a[2];
voice->params[1].send_b = card->waveout.send_b[2];
voice->params[1].send_c = card->waveout.send_c[2];
voice->params[1].send_d = card->waveout.send_d[2];
if (woinst->device)
voice->params[1].send_routing = 0x7654;
else
voice->params[1].send_routing = card->waveout.send_routing[2];
if (voice->flags & VOICE_FLAGS_STEREO) {
if (woinst->format.passthrough == 2) {
voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PT];
voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PT];
voice->params[0].send_dcba = 0xff;
voice->params[1].send_dcba = 0xff00;
voice->params[0].send_hgfe = voice->params[1].send_hgfe=0;
} else {
voice->params[0].send_dcba = card->waveout.send_dcba[SEND_LEFT];
voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_LEFT];
voice->params[1].send_dcba = card->waveout.send_dcba[SEND_RIGHT];
voice->params[1].send_hgfe = card->waveout.send_hgfe[SEND_RIGHT];
if (woinst->device) {
// /dev/dps1
voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM1];
voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
} else {
voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM];
voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
}
}
voice->params[1].volume_target = 0xffff;
voice->params[1].initial_fc = 0xff;
......@@ -183,30 +198,28 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
voice->params[1].byampl_env_decay = 0x7f;
} else {
if (woinst->num_voices > 1) {
voice->params[0].send_a = 0xff;
voice->params[0].send_b = 0;
voice->params[0].send_c = 0;
voice->params[0].send_d = 0;
// Multichannel pcm
voice->params[0].send_dcba=0xff;
voice->params[0].send_hgfe=0;
if (card->is_audigy) {
voice->params[0].send_routing = 0x3f3f3f00 + card->mchannel_fx + voicenum;
voice->params[0].send_routing2 = 0x3f3f3f3f;
} else {
voice->params[0].send_routing = 0xfff0 + card->mchannel_fx + voicenum;
}
voice->params[0].send_routing =
0xfff0 + card->mchannel_fx + voicenum;
} else {
voice->params[0].send_a = card->waveout.send_a[0];
voice->params[0].send_b = card->waveout.send_b[0];
voice->params[0].send_c = card->waveout.send_c[0];
voice->params[0].send_d = card->waveout.send_d[0];
voice->params[0].send_dcba = card->waveout.send_dcba[SEND_MONO];
voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_MONO];
if (woinst->device)
voice->params[0].send_routing = 0x7654;
else
voice->params[0].send_routing = card->waveout.send_routing[0];
if (woinst->device) {
voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM1];
voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
} else {
voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM];
voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
}
}
voice->params[0].volume_target = 0xffff;
voice->params[0].initial_fc = 0xff;
voice->params[0].initial_attn = 0x00;
voice->params[0].byampl_env_sustain = 0x7f;
voice->params[0].byampl_env_decay = 0x7f;
}
DPD(2, "voice: startloop=%#x, endloop=%#x\n", voice->startloop, voice->endloop);
......@@ -280,9 +293,16 @@ void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
struct pt_data *pt = &card->pt;
DPF(2, "emu10k1_waveout_start()\n");
if (woinst->format.passthrough == 2) {
emu10k1_pt_setup(wave_dev);
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 1);
pt->state = PT_STATE_PLAYING;
}
/* Actual start */
emu10k1_voices_start(woinst->voice, woinst->num_voices, woinst->total_played);
......
......@@ -80,15 +80,20 @@ void emu10k1_set_control_gpr(struct emu10k1_card *card, int addr, s32 val, int f
if (addr < 0 || addr >= NUM_GPRS)
return;
//fixme: once patch manager is up, remember to fix this for the audigy
if (card->is_audigy) {
sblive_writeptr(card, A_GPR_BASE + addr, 0, val);
} else {
if (flag)
val += sblive_readptr(card, GPR_BASE + addr, 0);
if (val > mgr->gpr[addr].max)
val = mgr->gpr[addr].max;
else if (val < mgr->gpr[addr].min)
val = mgr->gpr[addr].min;
sblive_writeptr(card, GPR_BASE + addr, 0, val);
}
}
//TODO: make this configurable:
......
......@@ -32,16 +32,30 @@
#ifndef _EFXMGR_H
#define _EFXMGR_H
#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
struct emu_efx_info_t{
int opcode_shift;
int high_operand_shift;
int instruction_start;
int gpr_base;
int output_base;
};
#define WRITE_EFX(a, b, c) sblive_writeptr((a), emu_efx_info[card->is_audigy].instruction_start + (b), 0, (c))
#define OP(op, z, w, x, y) \
do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \
WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \
do { WRITE_EFX(card, (pc) * 2, ((x) << emu_efx_info[card->is_audigy].high_operand_shift) | (y)); \
WRITE_EFX(card, (pc) * 2 + 1, ((op) << emu_efx_info[card->is_audigy].opcode_shift ) | ((z) << emu_efx_info[card->is_audigy].high_operand_shift) | (w)); \
++pc; } while (0)
#define NUM_INPUTS 0x20
#define NUM_OUTPUTS 0x20
#define NUM_GPRS 0x100
#define A_NUM_INPUTS 0x60
#define A_NUM_OUTPUTS 0x60 //fixme: this may or may not be true
#define A_NUM_GPRS 0x200
#define GPR_NAME_SIZE 32
#define PATCH_NAME_SIZE 32
......@@ -98,6 +112,9 @@ enum {
#define GPR_BASE 0x100
#define OUTPUT_BASE 0x20
#define A_GPR_BASE 0x400
#define A_OUTPUT_BASE 0x60
#define MAX_PATCHES_PAGES 32
struct patch_manager {
......
......@@ -160,6 +160,24 @@ void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data)
return;
}
void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size)
{
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
if (size == 32)
outl(data, card->iobase + (reg & 0x1F));
else if (size == 16)
outw(data, card->iobase + (reg & 0x1F));
else
outb(data, card->iobase + (reg & 0x1F));
spin_unlock_irqrestore(&card->lock, flags);
return;
}
u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
{
u32 val;
......@@ -200,12 +218,13 @@ void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
* write/read Emu10k1 pointer-offset register set, accessed through *
* the PTR and DATA registers *
*************************************************************************/
#define A_PTR_ADDRESS_MASK 0x0fff0000
void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
{
u32 regptr;
unsigned long flags;
regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
if (reg & 0xff000000) {
u32 mask;
......@@ -242,7 +261,7 @@ void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
spin_lock_irqsave(&card->lock, flags);
while ((reg = va_arg(args, u32)) != TAGLIST_END) {
u32 data = va_arg(args, u32);
u32 regptr = (((reg << 16) & PTR_ADDRESS_MASK)
u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK)
| (channel & PTR_CHANNELNUM_MASK));
outl(regptr, card->iobase + PTR);
if (reg & 0xff000000) {
......@@ -267,7 +286,7 @@ u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
u32 regptr, val;
unsigned long flags;
regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
if (reg & 0xff000000) {
u32 mask;
......@@ -389,7 +408,7 @@ void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value)
outb(reg, card->iobase + AC97ADDRESS);
outw(value, card->iobase + AC97DATA);
outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS);
spin_unlock_irqrestore(&card->lock, flags);
}
......@@ -402,6 +421,13 @@ int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
unsigned long flags;
int ret;
if (card->is_audigy) {
if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) {
sblive_writeptr(card, A_MUDATA, 0, data);
ret = 0;
} else
ret = -1;
} else {
spin_lock_irqsave(&card->lock, flags);
if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
......@@ -411,6 +437,7 @@ int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
ret = -1;
spin_unlock_irqrestore(&card->lock, flags);
}
return ret;
}
......@@ -420,6 +447,13 @@ int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
unsigned long flags;
int ret;
if (card->is_audigy) {
if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) {
*data = sblive_readptr(card, A_MUDATA,0);
ret = 0;
} else
ret = -1;
} else {
spin_lock_irqsave(&card->lock, flags);
if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
......@@ -429,6 +463,7 @@ int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
ret = -1;
spin_unlock_irqrestore(&card->lock, flags);
}
return ret;
}
......@@ -439,7 +474,23 @@ int emu10k1_mpu_reset(struct emu10k1_card *card)
unsigned long flags;
DPF(2, "emu10k1_mpu_reset()\n");
if (card->is_audigy) {
if (card->mpuacqcount == 0) {
sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
sblive_wcwait(card, 8);
sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
sblive_wcwait(card, 8);
sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE);
sblive_wcwait(card, 8);
status = sblive_readptr(card, A_MUDATA, 0);
if (status == 0xfe)
return 0;
else
return -1;
}
return 0;
} else {
if (card->mpuacqcount == 0) {
spin_lock_irqsave(&card->lock, flags);
outb(MUCMD_RESET, card->iobase + MUCMD);
......@@ -470,6 +521,7 @@ int emu10k1_mpu_reset(struct emu10k1_card *card)
}
return 0;
}
}
int emu10k1_mpu_acquire(struct emu10k1_card *card)
......
......@@ -79,13 +79,21 @@ struct memhandle
struct emu10k1_waveout
{
u16 send_routing[3];
u32 send_routing[3];
// audigy only:
u32 send_routing2[3];
u8 send_a[3];
u8 send_b[3];
u8 send_c[3];
u8 send_d[3];
u32 send_dcba[3];
// audigy only:
u32 send_hgfe[3];
};
#define ROUTE_PCM 0
#define ROUTE_PT 1
#define ROUTE_PCM1 2
#define SEND_MONO 0
#define SEND_LEFT 1
#define SEND_RIGHT 2
struct emu10k1_wavein
{
......@@ -129,7 +137,7 @@ struct mixer_private_ioctl {
#define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl)
//up this number when breaking compatibility
#define PRIVATE3_VERSION 1
#define PRIVATE3_VERSION 2
struct emu10k1_card
{
......@@ -181,7 +189,7 @@ struct emu10k1_card
u32 has_toslink; // TOSLink detection
u8 chiprev; /* Chip revision */
u8 is_audigy;
u8 is_aps;
struct patch_manager mgr;
......@@ -211,6 +219,7 @@ extern struct list_head emu10k1_devs;
/* Hardware Abstraction Layer access functions */
void emu10k1_writefn0(struct emu10k1_card *, u32, u32);
void emu10k1_writefn0_2(struct emu10k1_card *, u32, u32, int);
u32 emu10k1_readfn0(struct emu10k1_card *, u32);
void emu10k1_timer_set(struct emu10k1_card *, u16);
......
......@@ -37,8 +37,8 @@
#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
#define IRQTYPE_MPUOUT IPR_MIDITRANSBUFEMPTY
#define IRQTYPE_MPUIN IPR_MIDIRECVBUFEMPTY
#define IRQTYPE_MPUOUT (IPR_MIDITRANSBUFEMPTY | A_IPR_MIDITRANSBUFEMPTY2)
#define IRQTYPE_MPUIN (IPR_MIDIRECVBUFEMPTY | A_IPR_MIDIRECVBUFEMPTY2)
#define IRQTYPE_TIMER IPR_INTERVALTIMER
#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
#define IRQTYPE_DSP IPR_FXDSP
......
This diff is collapsed.
......@@ -52,4 +52,27 @@ struct emu10k1_mididevice
struct list_head mid_hdrs;
};
/* uncomment next line to use midi port on Audigy drive */
//#define USE_AUDIGY_DRIVE_MIDI
#ifdef USE_AUDIGY_DRIVE_MIDI
#define A_MUDATA A_MUDATA2
#define A_MUCMD A_MUCMD2
#define A_MUSTAT A_MUCMD2
#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY2
#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY2
#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE2
#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE2
#else
#define A_MUDATA A_MUDATA1
#define A_MUCMD A_MUCMD1
#define A_MUSTAT A_MUCMD1
#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY1
#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY1
#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE1
#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE1
#endif
#endif /* _MIDI_H */
......@@ -136,7 +136,7 @@ static void set_bass(struct emu10k1_card *card, int l, int r)
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++)
sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]);
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]);
}
static void set_treble(struct emu10k1_card *card, int l, int r)
......@@ -147,7 +147,7 @@ static void set_treble(struct emu10k1_card *card, int l, int r)
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++)
sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]);
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]);
}
const char volume_params[SOUND_MIXER_NRDEVICES]= {
......@@ -206,22 +206,25 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
switch (ctl->cmd) {
#ifdef DBGEMU
case CMD_WRITEFN0:
emu10k1_writefn0(card, ctl->val[0], ctl->val[1]);
emu10k1_writefn0_2(card, ctl->val[0], ctl->val[1], ctl->val[2]);
break;
#endif
case CMD_WRITEPTR:
if (ctl->val[1] >= 0x40 || ctl->val[0] > 0xff) {
#ifdef DBGEMU
if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000) {
#else
if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000 || ((ctl->val[0] < 0x100 ) &&
//Any register allowed raw access goes here:
(ctl->val[0] != A_SPDIF_SAMPLERATE) && (ctl->val[0] != A_DBG)
)
) {
#endif
ret = -EINVAL;
break;
}
if ((ctl->val[0] & 0x7ff) > 0x3f)
ctl->val[1] = 0x00;
sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]);
break;
#endif
case CMD_READFN0:
ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]);
......@@ -286,16 +289,13 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
case CMD_GETVOICEPARAM:
ctl->val[0] = card->waveout.send_routing[0];
ctl->val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 |
card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24;
ctl->val[1] = card->waveout.send_dcba[0];
ctl->val[2] = card->waveout.send_routing[1];
ctl->val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 |
card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24;
ctl->val[3] = card->waveout.send_dcba[1];
ctl->val[4] = card->waveout.send_routing[2];
ctl->val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 |
card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24;
ctl->val[5] = card->waveout.send_dcba[2];
if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
......@@ -303,23 +303,14 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break;
case CMD_SETVOICEPARAM:
card->waveout.send_routing[0] = ctl->val[0] & 0xffff;
card->waveout.send_a[0] = ctl->val[1] & 0xff;
card->waveout.send_b[0] = (ctl->val[1] >> 8) & 0xff;
card->waveout.send_c[0] = (ctl->val[1] >> 16) & 0xff;
card->waveout.send_d[0] = (ctl->val[1] >> 24) & 0xff;
card->waveout.send_routing[0] = ctl->val[0];
card->waveout.send_dcba[0] = ctl->val[1];
card->waveout.send_routing[1] = ctl->val[2] & 0xffff;
card->waveout.send_a[1] = ctl->val[3] & 0xff;
card->waveout.send_b[1] = (ctl->val[3] >> 8) & 0xff;
card->waveout.send_c[1] = (ctl->val[3] >> 16) & 0xff;
card->waveout.send_d[1] = (ctl->val[3] >> 24) & 0xff;
card->waveout.send_routing[1] = ctl->val[2];
card->waveout.send_dcba[1] = ctl->val[3];
card->waveout.send_routing[2] = ctl->val[4] & 0xffff;
card->waveout.send_a[2] = ctl->val[5] & 0xff;
card->waveout.send_b[2] = (ctl->val[5] >> 8) & 0xff;
card->waveout.send_c[2] = (ctl->val[5] >> 16) & 0xff;
card->waveout.send_d[2] = (ctl->val[5] >> 24) & 0xff;
card->waveout.send_routing[2] = ctl->val[4];
card->waveout.send_dcba[2] = ctl->val[5];
break;
......@@ -416,11 +407,15 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break;
case CMD_SETGPOUT:
if (ctl->val[0] > 2 || ctl->val[1] > 1) {
if ( ((ctl->val[0] > 2) && (!card->is_audigy))
|| (ctl->val[0] > 15) || ctl->val[1] > 1) {
ret= -EINVAL;
break;
}
if (card->is_audigy)
emu10k1_writefn0(card, (1 << 24) | ((ctl->val[0]) << 16) | A_IOCFG, ctl->val[1]);
else
emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]);
break;
......@@ -493,13 +488,20 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break;
case CMD_PRIVATE3_VERSION:
ctl->val[0]=PRIVATE3_VERSION;
ctl->val[0] = PRIVATE3_VERSION; //private3 version
ctl->val[1] = MAJOR_VER; //major driver version
ctl->val[2] = MINOR_VER; //minor driver version
ctl->val[3] = card->is_audigy; //1=card is audigy
if (card->is_audigy)
ctl->val[4]=emu10k1_readfn0(card, 0x18);
if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_AC97_BOOST:
if(ctl->val[0])
if (ctl->val[0])
emu10k1_ac97_write(card->ac97, 0x18, 0x0);
else
emu10k1_ac97_write(card->ac97, 0x18, 0x0808);
......@@ -556,7 +558,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
card->tankmem.size = size;
sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END);
sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS,(u32) size_reg, TAGLIST_END);
emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
}
......@@ -623,8 +625,13 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
strncpy(info.id, card->ac97->name, sizeof(info.id));
strncpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
strlcpy(info.id, card->ac97->name, sizeof(info.id));
if (card->is_audigy)
strlcpy(info.name, "Audigy - Emu10k1", sizeof(info.name));
else
strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
info.modify_counter = card->ac97->modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
......
......@@ -109,7 +109,7 @@ static int pt_putblock(struct emu10k1_wavedevice *wave_dev, u16 *block, int nonb
return 0;
}
static int pt_setup(struct emu10k1_wavedevice *wave_dev)
int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev)
{
u32 bits;
struct emu10k1_card *card = wave_dev->card;
......@@ -155,7 +155,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count)
pt->prepend_size = 0;
if (pt->buf == NULL)
return -ENOMEM;
pt_setup(wave_dev);
emu10k1_pt_setup(wave_dev);
}
if (pt->prepend_size) {
int needed = PT_BLOCKSIZE - pt->prepend_size;
......@@ -208,12 +208,13 @@ void emu10k1_pt_stop(struct emu10k1_card *card)
if (pt->state != PT_STATE_INACTIVE) {
DPF(2, "digital pass-through stopped\n");
sblive_writeptr(card, GPR_BASE + pt->enable_gpr, 0, 0);
sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 0);
for (i = 0; i < 3; i++) {
if (pt->spcs_to_use & (1 << i))
sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
}
pt->state = PT_STATE_INACTIVE;
if(pt->buf)
kfree(pt->buf);
}
}
......
......@@ -63,7 +63,36 @@ struct pt_data
spinlock_t lock;
};
/*
Passthrough can be done in two methods:
Method 1 : tram
In original emu10k1, we couldn't bypass the sample rate converters. Even at 48kHz
(the internal sample rate of the emu10k1) the samples would get messed up.
To over come this, samples are copied into the tram and a special dsp patch copies
the samples out and generates interrupts when a block has finnished playing.
Method 2 : Interpolator bypass
Creative fixed the sample rate convert problem in emu10k1 rev 7 and higher
(including the emu10k2 (audigy)). This allows us to use the regular, and much simpler
playback method.
In both methods, dsp code is used to mux audio and passthrough. This ensures that the spdif
doesn't receive audio and pasthrough data at the same time. The spdif flag SPCS_NOTAUDIODATA
is set to tell
*/
// emu10k1 revs greater than or equal to 7 can use method2
#define USE_PT_METHOD2 (card->is_audigy)
#define USE_PT_METHOD1 !USE_PT_METHOD2
ssize_t emu10k1_pt_write(struct file *file, const char *buf, size_t count);
int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev);
void emu10k1_pt_stop(struct emu10k1_card *card);
void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev);
......
......@@ -74,7 +74,7 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
DPF(2, "recording source: AC97\n");
buffer->sizereg = ADCBS;
buffer->addrreg = ADCBA;
buffer->idxreg = ADCIDX_IDX;
buffer->idxreg = card->is_audigy ? A_ADCIDX_IDX : ADCIDX_IDX;
switch (wiinst->format.samplingrate) {
case 0xBB80:
......@@ -95,21 +95,27 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
case 0x3E80:
buffer->adcctl = ADCCR_SAMPLERATE_16;
break;
// FIXME: audigy supports 12kHz recording
/*
case ????:
buffer->adcctl = A_ADCCR_SAMPLERATE_12;
break;
*/
case 0x2B11:
buffer->adcctl = ADCCR_SAMPLERATE_11;
buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_11 : ADCCR_SAMPLERATE_11;
break;
case 0x1F40:
buffer->adcctl = ADCCR_SAMPLERATE_8;
buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_8 : ADCCR_SAMPLERATE_8;
break;
default:
BUG();
break;
}
buffer->adcctl |= ADCCR_LCHANENABLE;
buffer->adcctl |= card->is_audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
if (wiinst->format.channels == 2)
buffer->adcctl |= ADCCR_RCHANENABLE;
buffer->adcctl |= card->is_audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
break;
......
......@@ -32,6 +32,34 @@
#include "voicemgr.h"
#include "8010.h"
#define PITCH_48000 0x00004000
#define PITCH_96000 0x00008000
#define PITCH_85000 0x00007155
#define PITCH_80726 0x00006ba2
#define PITCH_67882 0x00005a82
#define PITCH_57081 0x00004c1c
u32 emu10k1_select_interprom(struct emu10k1_card *card, struct emu_voice *voice)
{
if(voice->pitch_target==PITCH_48000)
return CCCA_INTERPROM_0;
else if(voice->pitch_target<PITCH_48000)
return CCCA_INTERPROM_1;
else if(voice->pitch_target>=PITCH_96000)
return CCCA_INTERPROM_0;
else if(voice->pitch_target>=PITCH_85000)
return CCCA_INTERPROM_6;
else if(voice->pitch_target>=PITCH_80726)
return CCCA_INTERPROM_5;
else if(voice->pitch_target>=PITCH_67882)
return CCCA_INTERPROM_4;
else if(voice->pitch_target>=PITCH_57081)
return CCCA_INTERPROM_3;
else
return CCCA_INTERPROM_2;
}
/**
* emu10k1_voice_alloc_buffer -
*
......@@ -216,17 +244,25 @@ void emu10k1_voice_playback_setup(struct emu_voice *voice)
voice->start += start;
for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
if (card->is_audigy) {
sblive_writeptr(card, A_FXRT1, voice->num + i, voice->params[i].send_routing);
sblive_writeptr(card, A_FXRT2, voice->num + i, voice->params[i].send_routing2);
sblive_writeptr(card, A_SENDAMOUNTS, voice->num + i, voice->params[i].send_hgfe);
} else {
sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
}
/* Stop CA */
/* Assumption that PT is already 0 so no harm overwriting */
sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b);
sblive_writeptr(card, PTRX, voice->num + i, ((voice->params[i].send_dcba & 0xff) << 8)
| ((voice->params[i].send_dcba & 0xff00) >> 8));
sblive_writeptr_tag(card, voice->num + i,
/* CSL, ST, CA */
DSL, voice->endloop | (voice->params[i].send_d << 24),
PSST, voice->startloop | (voice->params[i].send_c << 24),
CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
DSL, voice->endloop | (voice->params[i].send_dcba & 0xff000000),
PSST, voice->startloop | ((voice->params[i].send_dcba & 0x00ff0000) << 8),
CCCA, (voice->start) | emu10k1_select_interprom(card,voice) |
((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
/* Clear filter delay memory */
Z1, 0,
Z2, 0,
......
......@@ -48,11 +48,13 @@ struct voice_param
/* FX bus amount send */
u32 send_routing;
// audigy only:
u32 send_routing2;
u32 send_dcba;
// audigy only:
u32 send_hgfe;
u32 send_a;
u32 send_b;
u32 send_c;
u32 send_d;
u32 initial_fc;
u32 fc_target;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment