📄 emu8000.c
字号:
/* write out a magic number */ snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE); snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_READ); EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET); EMU8000_SMLD_WRITE(emu, UNIQUE_ID1); snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */ while (size < EMU8000_MAX_DRAM) { size += 512 * 1024; /* increment 512kbytes */ /* Write a unique data on the test address. * if the address is out of range, the data is written on * 0x200000(=EMU8000_DRAM_OFFSET). Then the id word is * changed by this data. */ /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/ EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1)); EMU8000_SMLD_WRITE(emu, UNIQUE_ID2); snd_emu8000_write_wait(emu); /* * read the data on the just written DRAM address * if not the same then we have reached the end of ram. */ /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/ EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1)); /*snd_emu8000_read_wait(emu);*/ EMU8000_SMLD_READ(emu); /* discard stale data */ if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2) break; /* we must have wrapped around */ snd_emu8000_read_wait(emu); /* * If it is the same it could be that the address just * wraps back to the beginning; so check to see if the * initial value has been overwritten. */ EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET); EMU8000_SMLD_READ(emu); /* discard stale data */ if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1) break; /* we must have wrapped around */ snd_emu8000_read_wait(emu); } /* wait until FULL bit in SMAxW register is false */ for (i = 0; i < 10000; i++) { if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0) break; schedule_timeout_interruptible(1); if (signal_pending(current)) break; } snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE); snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE); snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n", emu->port1, size/1024); emu->mem_size = size; emu->dram_checked = 1;}/* * Initiailise the FM section. You have to do this to use sample RAM * and therefore lose 2 voices. *//*exported*/ voidsnd_emu8000_init_fm(emu8000_t *emu){ unsigned long flags; /* Initialize the last two channels for DRAM refresh and producing the reverb and chorus effects for Yamaha OPL-3 synthesizer */ /* 31: FM left channel, 0xffffe0-0xffffe8 */ EMU8000_DCYSUSV_WRITE(emu, 30, 0x80); EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */ EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24)); EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8)); EMU8000_CPF_WRITE(emu, 30, 0); EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3); /* 32: FM right channel, 0xfffff0-0xfffff8 */ EMU8000_DCYSUSV_WRITE(emu, 31, 0x80); EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */ EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24)); EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8)); EMU8000_CPF_WRITE(emu, 31, 0x8000); EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3); snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0); spin_lock_irqsave(&emu->reg_lock, flags); while (!(inw(EMU8000_PTR(emu)) & 0x1000)) ; while ((inw(EMU8000_PTR(emu)) & 0x1000)) ; spin_unlock_irqrestore(&emu->reg_lock, flags); snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828); /* this is really odd part.. */ outb(0x3C, EMU8000_PTR(emu)); outb(0, EMU8000_DATA1(emu)); /* skew volume & cutoff */ EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF); EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);}/* * The main initialization routine. */static void __initsnd_emu8000_init_hw(emu8000_t *emu){ int i; emu->last_reg = 0xffff; /* reset the last register index */ /* initialize hardware configuration */ EMU8000_HWCF1_WRITE(emu, 0x0059); EMU8000_HWCF2_WRITE(emu, 0x0020); /* disable audio; this seems to reduce a clicking noise a bit.. */ EMU8000_HWCF3_WRITE(emu, 0); /* initialize audio channels */ init_audio(emu); /* initialize DMA */ init_dma(emu); /* initialize init arrays */ init_arrays(emu); /* * Initialize the FM section of the AWE32, this is needed * for DRAM refresh as well */ snd_emu8000_init_fm(emu); /* terminate all voices */ for (i = 0; i < EMU8000_DRAM_VOICES; i++) EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F); /* check DRAM memory size */ size_dram(emu); /* enable audio */ EMU8000_HWCF3_WRITE(emu, 0x4); /* set equzlier, chorus and reverb modes */ snd_emu8000_update_equalizer(emu); snd_emu8000_update_chorus_mode(emu); snd_emu8000_update_reverb_mode(emu);}/*---------------------------------------------------------------- * Bass/Treble Equalizer *----------------------------------------------------------------*/static unsigned short bass_parm[12][3] = { {0xD26A, 0xD36A, 0x0000}, /* -12 dB */ {0xD25B, 0xD35B, 0x0000}, /* -8 */ {0xD24C, 0xD34C, 0x0000}, /* -6 */ {0xD23D, 0xD33D, 0x0000}, /* -4 */ {0xD21F, 0xD31F, 0x0000}, /* -2 */ {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */ {0xC219, 0xC319, 0x0001}, /* +2 */ {0xC22A, 0xC32A, 0x0001}, /* +4 */ {0xC24C, 0xC34C, 0x0001}, /* +6 */ {0xC26E, 0xC36E, 0x0001}, /* +8 */ {0xC248, 0xC384, 0x0002}, /* +10 */ {0xC26A, 0xC36A, 0x0002}, /* +12 dB */};static unsigned short treble_parm[12][9] = { {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */ {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002}, {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002}, {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002}, {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002}, {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */ {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002} /* +12 dB */};/* * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB] *//*exported*/ voidsnd_emu8000_update_equalizer(emu8000_t *emu){ unsigned short w; int bass = emu->bass_level; int treble = emu->treble_level; if (bass < 0 || bass > 11 || treble < 0 || treble > 11) return; EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]); EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]); EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]); EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]); EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]); EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]); EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]); EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]); EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]); EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]); w = bass_parm[bass][2] + treble_parm[treble][8]; EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262)); EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));}/*---------------------------------------------------------------- * Chorus mode control *----------------------------------------------------------------*//* * chorus mode parameters */#define SNDRV_EMU8000_CHORUS_1 0#define SNDRV_EMU8000_CHORUS_2 1#define SNDRV_EMU8000_CHORUS_3 2#define SNDRV_EMU8000_CHORUS_4 3#define SNDRV_EMU8000_CHORUS_FEEDBACK 4#define SNDRV_EMU8000_CHORUS_FLANGER 5#define SNDRV_EMU8000_CHORUS_SHORTDELAY 6#define SNDRV_EMU8000_CHORUS_SHORTDELAY2 7#define SNDRV_EMU8000_CHORUS_PREDEFINED 8/* user can define chorus modes up to 32 */#define SNDRV_EMU8000_CHORUS_NUMBERS 32typedef struct soundfont_chorus_fx_t { unsigned short feedback; /* feedback level (0xE600-0xE6FF) */ unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */ unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */ unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */ unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */} soundfont_chorus_fx_t;/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];static soundfont_chorus_fx_t chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = { {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */ {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */ {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */ {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */ {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */ {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */ {0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */ {0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */};/*exported*/ intsnd_emu8000_load_chorus_fx(emu8000_t *emu, int mode, const void __user *buf, long len){ soundfont_chorus_fx_t rec; if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) { snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode); return -EINVAL; } if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec))) return -EFAULT; chorus_parm[mode] = rec; chorus_defined[mode] = 1; return 0;}/*exported*/ voidsnd_emu8000_update_chorus_mode(emu8000_t *emu){ int effect = emu->chorus_mode; if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS || (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect])) return; EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback); EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset); EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth); EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay); EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq); EMU8000_HWCF6_WRITE(emu, 0x8000); EMU8000_HWCF7_WRITE(emu, 0x0000);}/*---------------------------------------------------------------- * Reverb mode control *----------------------------------------------------------------*//* * reverb mode parameters */#define SNDRV_EMU8000_REVERB_ROOM1 0#define SNDRV_EMU8000_REVERB_ROOM2 1#define SNDRV_EMU8000_REVERB_ROOM3 2#define SNDRV_EMU8000_REVERB_HALL1 3#define SNDRV_EMU8000_REVERB_HALL2 4#define SNDRV_EMU8000_REVERB_PLATE 5#define SNDRV_EMU8000_REVERB_DELAY 6#define SNDRV_EMU8000_REVERB_PANNINGDELAY 7#define SNDRV_EMU8000_REVERB_PREDEFINED 8/* user can define reverb modes up to 32 */#define SNDRV_EMU8000_REVERB_NUMBERS 32typedef struct soundfont_reverb_fx_t { unsigned short parms[28];} soundfont_reverb_fx_t;/* reverb mode settings; write the following 28 data of 16 bit length * on the corresponding ports in the reverb_cmds array */static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];static soundfont_reverb_fx_t reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {{{ /* room 1 */ 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4, 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516, 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,}},{{ /* room 2 */ 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284, 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,}},{{ /* room 3 */ 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284, 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516, 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,}},{{ /* hall 1 */ 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284, 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548, 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,}},{{ /* hall 2 */ 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254, 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3, 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,}},{{ /* plate */ 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548, 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,}},{{ /* delay */ 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204, 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,}},{{ /* panning delay */ 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204, 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500, 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,}},};enum { DATA1, DATA2 };#define AWE_INIT1(c) EMU8000_CMD(2,c), DATA1#define AWE_INIT2(c) EMU8000_CMD(2,c), DATA2#define AWE_INIT3(c) EMU8000_CMD(3,c), DATA1#define AWE_INIT4(c) EMU8000_CMD(3,c), DATA2static struct reverb_cmd_pair { unsigned short cmd, port;} reverb_cmds[28] = { {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)}, {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)}, {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)}, {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)}, {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -