/* * Emuxki BeOS Driver for Creative Labs SBLive!/Audigy series * * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) * * Authors: * Alexander Coers Alexander.Coers@gmx.de * Fredrik Modéen fredrik@modeen.se * */ /* This code is derived from the NetBSD driver for Creative Labs SBLive! series * * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Yannick Montulet. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include "emuxki.h" #include "debug.h" #include "config.h" #include "util.h" #include "io.h" #include "multi.h" #include "ac97.h" status_t init_hardware(void); status_t init_driver(void); void uninit_driver(void); const char ** publish_devices(void); device_hooks * find_device(const char *); pci_module_info *pci; generic_mpu401_module * mpu401; //static char gameport_name[] = "generic/gameport/v2"; //generic_gameport_module * gameport; int32 num_cards; emuxki_dev cards[NUM_CARDS]; int32 num_names; char * names[NUM_CARDS*20+1]; emuxki_settings current_settings = { 2, // channels 16, // bits per sample 48000, // sample rate 512, // buffer frames 2 // buffer count }; status_t emuxki_init(emuxki_dev *card); void emuxki_shutdown(emuxki_dev *card); extern device_hooks multi_hooks; extern device_hooks midi_hooks; //extern device_hooks joy_hooks; /* Hardware Dump */ static void dump_hardware_regs(device_config *config) { LOG(("EMU_IPR = %#08x\n",emuxki_reg_read_32(config, EMU_IPR))); LOG(("EMU_INTE = %#08x\n",emuxki_reg_read_32(config, EMU_INTE))); LOG(("EMU_HCFG = %#08x\n",emuxki_reg_read_32(config, EMU_HCFG))); snooze(1000); /*emuxki_reg_write_8(config, EMU_AC97ADDRESS, EMU_AC97ADDRESS_READY); LOG(("EMU_AC97ADDRESS_READY = %#08x\n", emuxki_reg_read_16(config, EMU_AC97DATA)));*/ /*emuxki_reg_write_8(config, EMU_AC97ADDRESS, EMU_AC97ADDRESS_ADDRESS); LOG(("EMU_AC97ADDRESS_ADDRESS = %#08x\n", emuxki_reg_read_16(config, EMU_AC97DATA)));*/ /*LOG(("EMU_CHAN_CPF_STEREO = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_CPF_STEREO))); LOG(("EMU_CHAN_FXRT = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_FXRT))); LOG(("EMU_CHAN_PTRX = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_PTRX))); LOG(("EMU_CHAN_DSL = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_DSL))); LOG(("EMU_CHAN_PSST = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_PSST))); LOG(("EMU_CHAN_CCCA = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_CCCA))); LOG(("EMU_CHAN_Z1 = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_Z1))); LOG(("EMU_CHAN_Z2 = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_Z2))); LOG(("EMU_CHAN_MAPA = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_MAPA))); LOG(("EMU_CHAN_MAPB = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_MAPB))); LOG(("EMU_CHAN_CVCF_CURRENTFILTER = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_CVCF_CURRENTFILTER))); LOG(("EMU_CHAN_VTFT_FILTERTARGET = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_VTFT_FILTERTARGET))); LOG(("EMU_CHAN_ATKHLDM = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_ATKHLDM))); LOG(("EMU_CHAN_DCYSUSM = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_DCYSUSM))); LOG(("EMU_CHAN_LFOVAL1 = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_LFOVAL1))); LOG(("EMU_CHAN_LFOVAL2 = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_LFOVAL2))); LOG(("EMU_CHAN_FMMOD = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_FMMOD))); LOG(("EMU_CHAN_TREMFRQ = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_TREMFRQ))); LOG(("EMU_CHAN_FM2FRQ2 = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_FM2FRQ2))); LOG(("EMU_CHAN_ENVVAL = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_ENVVAL))); LOG(("EMU_CHAN_ATKHLDV = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_ATKHLDV))); LOG(("EMU_CHAN_ENVVOL = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_ENVVOL))); LOG(("EMU_CHAN_PEFE = %#08x\n",emuxki_chan_read(config, 0, EMU_CHAN_PEFE)));*/ } /*static void trace_hardware_regs(device_config *config) { TRACE(("EMU_IPR = %#08x\n",emuxki_reg_read_32(config, EMU_IPR))); TRACE(("EMU_INTE = %#08x\n",emuxki_reg_read_32(config, EMU_INTE))); TRACE(("EMU_HCFG = %#08x\n",emuxki_reg_read_32(config, EMU_HCFG))); }*/ /* Misc stuff relative to Emuxki */ int emu10k1_recbuf_sizes[] = { 0, 384, 448, 512, 640, 768, 896, 1024, 1280, 1536, 1792, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 10240, 12288, 14366, 16384, 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536 }; static uint32 emuxki_rate_to_pitch(uint32 rate) { static uint32 logMagTable[128] = { 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df }; static uint8 logSlopeTable[128] = { 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f }; int8 i; if (rate == 0) return 0; /* Bail out if no leading "1" */ rate *= 11185; /* Scale 48000 to 0x20002380 */ for (i = 31; i > 0; i--) { if (rate & 0x80000000) { /* Detect leading "1" */ return (((uint32) (i - 15) << 20) + logMagTable[0x7f & (rate >> 24)] + (0x7f & (rate >> 17)) * logSlopeTable[0x7f & (rate >> 24)]); } rate <<= 1; } return 0; /* Should never reach this point */ } /* Emuxki Memory management */ static emuxki_mem * emuxki_mem_new(emuxki_dev *card, int ptbidx, size_t size) { emuxki_mem *mem; if ((mem = malloc(sizeof(*mem))) == NULL) return (NULL); mem->ptbidx = ptbidx; mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "emuxki buffer", true); mem->size = size; if (mem->area < B_OK) { free(mem); return NULL; } return mem; } static void emuxki_mem_delete(emuxki_mem *mem) { if (mem->area > B_OK) delete_area(mem->area); free(mem); } void * emuxki_pmem_alloc(emuxki_dev *card, size_t size) { int i;//, s; size_t numblocks; emuxki_mem *mem; uint32 j, *ptb, silentpage; ptb = card->ptb_log_base; silentpage = ((uint32)card->silentpage_phy_base) << 1; numblocks = size / EMU_PTESIZE; if (size % EMU_PTESIZE) numblocks++; PRINT(("emuxki_pmem_alloc : numblocks : %ld\n", numblocks)); for (i = 0; i < EMU_MAXPTE; i++) { PRINT(("emuxki_pmem_alloc : %d\n", i)); if ((B_LENDIAN_TO_HOST_INT32(ptb[i]) & EMU_CHAN_MAP_PTE_MASK) == silentpage) { /* We look for a free PTE */ //s = splaudio(); for (j = 0; j < numblocks; j++) if ((B_LENDIAN_TO_HOST_INT32(ptb[i + j]) & EMU_CHAN_MAP_PTE_MASK) != silentpage) break; if (j == numblocks) { PRINT(("emuxki_pmem_alloc : j == numblocks %" B_PRIu32 "\n", j)); if ((mem = emuxki_mem_new(card, i, size)) == NULL) { //splx(s); return (NULL); } PRINT(("emuxki_pmem_alloc : j == numblocks emuxki_mem_new ok\n")); for (j = 0; j < numblocks; j++) ptb[i + j] = B_HOST_TO_LENDIAN_INT32((uint32) ( (( ((uint32)mem->phy_base) + j * EMU_PTESIZE) << 1) | (i + j))); LIST_INSERT_HEAD(&(card->mem), mem, next); PRINT(("emuxki_pmem_alloc : j == numblocks returning\n")); //splx(s); return mem->log_base; } else { PRINT(("emuxki_pmem_alloc : j != numblocks %" B_PRIu32 "\n", j)); i += j; } //splx(s); } } return NULL; } void * emuxki_rmem_alloc(emuxki_dev *card, size_t size) { emuxki_mem *mem; //int s; mem = emuxki_mem_new(card, EMU_RMEM, size); if (mem == NULL) return (NULL); //s = splaudio(); LIST_INSERT_HEAD(&(card->mem), mem, next); //splx(s); return mem->log_base; } void emuxki_mem_free(emuxki_dev *card, void *ptr) { emuxki_mem *mem; size_t numblocks; uint32 i, *ptb, silentpage; ptb = card->ptb_log_base; silentpage = ((uint32)card->silentpage_phy_base) << 1; LOG(("emuxki_mem_free 1\n")); LIST_FOREACH(mem, &card->mem, next) { LOG(("emuxki_mem_free 2\n")); if (mem->log_base != ptr) continue; LOG(("emuxki_mem_free 3\n")); //s = splaudio(); if (mem->ptbidx != EMU_RMEM) { LOG(("mem_size : %i\n", mem->size)); numblocks = mem->size / EMU_PTESIZE; if (mem->size % EMU_PTESIZE) numblocks++; for (i = 0; i < numblocks; i++) ptb[mem->ptbidx + i] = B_HOST_TO_LENDIAN_INT32(silentpage | (mem->ptbidx + i)); } LIST_REMOVE(mem, next); //splx(s); LOG(("freeing mem\n")); emuxki_mem_delete(mem); break; } } /* Emuxki channel functions */ static void emuxki_chanparms_set_defaults(emuxki_channel *chan) { chan->fxsend.a.level = chan->fxsend.b.level = chan->fxsend.c.level = chan->fxsend.d.level /* for audigy */ = chan->fxsend.e.level = chan->fxsend.f.level = chan->fxsend.g.level = chan->fxsend.h.level = IS_AUDIGY(&chan->voice->stream->card->config) ? 0xc0 : 0xff; /* not max */ chan->fxsend.a.dest = 0x0; chan->fxsend.b.dest = 0x1; chan->fxsend.c.dest = 0x2; chan->fxsend.d.dest = 0x3; /* for audigy */ chan->fxsend.e.dest = 0x4; chan->fxsend.f.dest = 0x5; chan->fxsend.g.dest = 0x6; chan->fxsend.h.dest = 0x7; chan->pitch.intial = 0x0000; /* shouldn't it be 0xE000 ? */ chan->pitch.current = 0x0000; /* should it be 0x0400 */ chan->pitch.target = 0x0000; /* the unity pitch shift ? */ chan->pitch.envelope_amount = 0x00; /* none */ chan->initial_attenuation = 0x00; /* no attenuation */ chan->volume.current = 0x0000; /* no volume */ chan->volume.target = 0xffff; chan->volume.envelope.current_state = 0x8000; /* 0 msec delay */ chan->volume.envelope.hold_time = 0x7f; /* 0 msec */ chan->volume.envelope.attack_time = 0x7f; /* 5.5msec */ chan->volume.envelope.sustain_level = 0x7f; /* full */ chan->volume.envelope.decay_time = 0x7f; /* 22msec */ chan->filter.initial_cutoff_frequency = 0xff; /* no filter */ chan->filter.current_cutoff_frequency = 0xffff; /* no filtering */ chan->filter.target_cutoff_frequency = 0xffff; /* no filtering */ chan->filter.lowpass_resonance_height = 0x0; chan->filter.interpolation_ROM = 0x1; /* full band */ chan->filter.envelope_amount = 0x7f; /* none */ chan->filter.LFO_modulation_depth = 0x00; /* none */ chan->loop.start = 0x000000; chan->loop.end = 0x000010; /* Why ? */ chan->modulation.envelope.current_state = 0x8000; chan->modulation.envelope.hold_time = 0x00; /* 127 better ? */ chan->modulation.envelope.attack_time = 0x00; /* infinite */ chan->modulation.envelope.sustain_level = 0x00; /* off */ chan->modulation.envelope.decay_time = 0x7f; /* 22 msec */ chan->modulation.LFO_state = 0x8000; chan->vibrato_LFO.state = 0x8000; chan->vibrato_LFO.modulation_depth = 0x00; /* none */ chan->vibrato_LFO.vibrato_depth = 0x00; chan->vibrato_LFO.frequency = 0x00; /* Why set to 24 when * initialized ? */ chan->tremolo_depth = 0x00; } static emuxki_channel * emuxki_channel_new(emuxki_voice *voice, uint8 num) { emuxki_channel *chan; chan = (emuxki_channel *) malloc(sizeof(emuxki_channel)); if (chan == NULL) return NULL; chan->voice = voice; chan->num = num; emuxki_chanparms_set_defaults(chan); chan->voice->stream->card->channel[num] = chan; return chan; } static void emuxki_channel_delete(emuxki_channel *chan) { chan->voice->stream->card->channel[chan->num] = NULL; free(chan); } static void emuxki_channel_set_fxsend(emuxki_channel *chan, emuxki_chanparms_fxsend *fxsend) { /* Could do a memcpy ...*/ chan->fxsend.a.level = fxsend->a.level; chan->fxsend.b.level = fxsend->b.level; chan->fxsend.c.level = fxsend->c.level; chan->fxsend.d.level = fxsend->d.level; chan->fxsend.a.dest = fxsend->a.dest; chan->fxsend.b.dest = fxsend->b.dest; chan->fxsend.c.dest = fxsend->c.dest; chan->fxsend.d.dest = fxsend->d.dest; /* for audigy */ chan->fxsend.e.level = fxsend->e.level; chan->fxsend.f.level = fxsend->f.level; chan->fxsend.g.level = fxsend->g.level; chan->fxsend.h.level = fxsend->h.level; chan->fxsend.e.dest = fxsend->e.dest; chan->fxsend.f.dest = fxsend->f.dest; chan->fxsend.g.dest = fxsend->g.dest; chan->fxsend.h.dest = fxsend->h.dest; } static void emuxki_channel_set_srate(emuxki_channel *chan, uint32 srate) { chan->pitch.target = (srate << 8) / 375; chan->pitch.target = (chan->pitch.target >> 1) + (chan->pitch.target & 1); chan->pitch.target &= 0xffff; chan->pitch.current = chan->pitch.target; chan->pitch.intial = (emuxki_rate_to_pitch(srate) >> 8) & EMU_CHAN_IP_MASK; } /* voice params must be set before calling this */ static void emuxki_channel_set_bufparms(emuxki_channel *chan, uint32 start, uint32 end) { chan->loop.start = start & EMU_CHAN_PSST_LOOPSTARTADDR_MASK; chan->loop.end = end & EMU_CHAN_DSL_LOOPENDADDR_MASK; } static void emuxki_channel_commit_fx(emuxki_channel *chan) { emuxki_dev *card = chan->voice->stream->card; uint8 chano = chan->num; if (IS_AUDIGY(&card->config)) { emuxki_chan_write(&card->config, chano, 0x4c, 0); emuxki_chan_write(&card->config, chano, 0x4d, 0); emuxki_chan_write(&card->config, chano, 0x4e, 0); emuxki_chan_write(&card->config, chano, 0x4f, 0); emuxki_chan_write(&card->config, chano, EMU_A_CHAN_FXRT1, (chan->fxsend.d.dest << 24) | (chan->fxsend.c.dest << 16) | (chan->fxsend.b.dest << 8) | (chan->fxsend.a.dest)); emuxki_chan_write(&card->config, chano, EMU_A_CHAN_FXRT2, (chan->fxsend.h.dest << 24) | (chan->fxsend.g.dest << 16) | (chan->fxsend.f.dest << 8) | (chan->fxsend.e.dest)); emuxki_chan_write(&card->config, chano, EMU_A_CHAN_SENDAMOUNTS, (chan->fxsend.e.level << 24) | (chan->fxsend.f.level << 16) | (chan->fxsend.g.level << 8) | (chan->fxsend.h.level)); } else { emuxki_chan_write(&card->config, chano, EMU_CHAN_FXRT, (chan->fxsend.d.dest << 28) | (chan->fxsend.c.dest << 24) | (chan->fxsend.b.dest << 20) | (chan->fxsend.a.dest << 16)); } emuxki_chan_write(&card->config, chano, 0x10000000 | EMU_CHAN_PTRX, (chan->fxsend.a.level << 8) | chan->fxsend.b.level); emuxki_chan_write(&card->config, chano, EMU_CHAN_DSL, (chan->fxsend.d.level << 24) | chan->loop.end); emuxki_chan_write(&card->config, chano, EMU_CHAN_PSST, (chan->fxsend.c.level << 24) | chan->loop.start); } static void emuxki_channel_commit_parms(emuxki_channel *chan) { emuxki_voice *voice = chan->voice; emuxki_dev *card = chan->voice->stream->card; uint32 start, mapval; uint8 chano = chan->num; //int s; start = chan->loop.start + (voice->stereo ? 28 : 30) * (voice->b16 + 1); mapval = ((uint32)card->silentpage_phy_base) << 1 | EMU_CHAN_MAP_PTI_MASK; //s = splaudio(); emuxki_chan_write(&card->config, chano, EMU_CHAN_CPF_STEREO, voice->stereo); emuxki_channel_commit_fx(chan); emuxki_chan_write(&card->config, chano, EMU_CHAN_CCCA, (chan->filter.lowpass_resonance_height << 28) | (chan->filter.interpolation_ROM << 25) | (voice->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT) | start); emuxki_chan_write(&card->config, chano, EMU_CHAN_Z1, 0); emuxki_chan_write(&card->config, chano, EMU_CHAN_Z2, 0); emuxki_chan_write(&card->config, chano, EMU_CHAN_MAPA, mapval); emuxki_chan_write(&card->config, chano, EMU_CHAN_MAPB, mapval); emuxki_chan_write(&card->config, chano, EMU_CHAN_CVCF_CURRFILTER, chan->filter.current_cutoff_frequency); emuxki_chan_write(&card->config, chano, EMU_CHAN_VTFT_FILTERTARGET, chan->filter.target_cutoff_frequency); emuxki_chan_write(&card->config, chano, EMU_CHAN_ATKHLDM, (chan->modulation.envelope.hold_time << 8) | chan->modulation.envelope.attack_time); emuxki_chan_write(&card->config, chano, EMU_CHAN_DCYSUSM, (chan->modulation.envelope.sustain_level << 8) | chan->modulation.envelope.decay_time); emuxki_chan_write(&card->config, chano, EMU_CHAN_LFOVAL1, chan->modulation.LFO_state); emuxki_chan_write(&card->config, chano, EMU_CHAN_LFOVAL2, chan->vibrato_LFO.state); emuxki_chan_write(&card->config, chano, EMU_CHAN_FMMOD, (chan->vibrato_LFO.modulation_depth << 8) | chan->filter.LFO_modulation_depth); emuxki_chan_write(&card->config, chano, EMU_CHAN_TREMFRQ, (chan->tremolo_depth << 8)); emuxki_chan_write(&card->config, chano, EMU_CHAN_FM2FRQ2, (chan->vibrato_LFO.vibrato_depth << 8) | chan->vibrato_LFO.frequency); emuxki_chan_write(&card->config, chano, EMU_CHAN_ENVVAL, chan->modulation.envelope.current_state); emuxki_chan_write(&card->config, chano, EMU_CHAN_ATKHLDV, (chan->volume.envelope.hold_time << 8) | chan->volume.envelope.attack_time); emuxki_chan_write(&card->config, chano, EMU_CHAN_ENVVOL, chan->volume.envelope.current_state); emuxki_chan_write(&card->config, chano, EMU_CHAN_PEFE, (chan->pitch.envelope_amount << 8) | chan->filter.envelope_amount); //splx(s); } static void emuxki_channel_start(emuxki_channel *chan) { emuxki_voice *voice = chan->voice; emuxki_dev *card = chan->voice->stream->card; uint8 cache_sample, cache_invalid_size, chano = chan->num; uint32 sample; //int s; cache_sample = voice->stereo ? 4 : 2; sample = voice->b16 ? 0x00000000 : 0x80808080; cache_invalid_size = (voice->stereo ? 28 : 30) * (voice->b16 + 1); //s = splaudio(); while (cache_sample--) emuxki_chan_write(&card->config, chano, EMU_CHAN_CD0 + cache_sample, sample); emuxki_chan_write(&card->config, chano, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0); emuxki_chan_write(&card->config, chano, EMU_CHAN_CCR_READADDRESS, 64); emuxki_chan_write(&card->config, chano, EMU_CHAN_CCR_CACHEINVALIDSIZE, cache_invalid_size); emuxki_chan_write(&card->config, chano, EMU_CHAN_IFATN, (chan->filter.target_cutoff_frequency << 8) | chan->initial_attenuation); emuxki_chan_write(&card->config, chano, EMU_CHAN_VTFT_VOLUMETARGET, chan->volume.target); emuxki_chan_write(&card->config, chano, EMU_CHAN_CVCF_CURRVOL, chan->volume.current); emuxki_chan_write(&card->config, 0, EMU_MKSUBREG(1, chano, EMU_SOLEL + (chano >> 5)), 0); /* Clear stop on loop */ emuxki_chan_write(&card->config, 0, EMU_MKSUBREG(1, chano, EMU_CLIEL + (chano >> 5)), 0); /* Clear loop interrupt */ emuxki_chan_write(&card->config, chano, EMU_CHAN_DCYSUSV, (chan->volume.envelope.sustain_level << 8) | chan->volume.envelope.decay_time); emuxki_chan_write(&card->config, chano, EMU_CHAN_PTRX_PITCHTARGET, chan->pitch.target); emuxki_chan_write(&card->config, chano, EMU_CHAN_CPF_PITCH, chan->pitch.current); emuxki_chan_write(&card->config, chano, EMU_CHAN_IP, chan->pitch.intial); //splx(s); } static void emuxki_channel_stop(emuxki_channel *chan) { emuxki_dev *card = chan->voice->stream->card; //int s; uint8 chano = chan->num; //s = splaudio(); emuxki_chan_write(&card->config, chano, EMU_CHAN_PTRX_PITCHTARGET, 0); emuxki_chan_write(&card->config, chano, EMU_CHAN_CPF_PITCH, 0); emuxki_chan_write(&card->config, chano, EMU_CHAN_IFATN_ATTENUATION, 0xff); emuxki_chan_write(&card->config, chano, EMU_CHAN_VTFT_VOLUMETARGET, 0); emuxki_chan_write(&card->config, chano, EMU_CHAN_CVCF_CURRVOL, 0); emuxki_chan_write(&card->config, chano, EMU_CHAN_IP, 0); //splx(s); } /* Emuxki voice functions */ /*static void emuxki_dump_voice(emuxki_voice *voice) { LOG(("voice->use = %#u\n", voice->use)); LOG(("voice->state = %#u\n", voice->state)); LOG(("voice->stereo = %#u\n", voice->stereo)); LOG(("voice->b16 = %#u\n", voice->b16)); LOG(("voice->sample_rate = %#lu\n", voice->sample_rate)); LOG(("voice->buffer = %#08x\n", voice->buffer)); if (voice->buffer) { LOG(("voice->buffer->ptbidx = %#u\n", voice->buffer->ptbidx)); LOG(("voice->buffer->log_base = %#08x\n", voice->buffer->log_base)); LOG(("voice->buffer->phy_base = %#08x\n", voice->buffer->phy_base)); LOG(("voice->buffer->size = %#08x\n", voice->buffer->size)); LOG(("voice->buffer->area = %#08x\n", voice->buffer->area)); } LOG(("voice->blksize = %#u\n", voice->blksize)); LOG(("voice->trigblk = %#u\n", voice->trigblk)); LOG(("voice->blkmod = %#u\n", voice->blkmod)); LOG(("voice->timerate = %#u\n", voice->timerate)); }*/ /* Allocate channels for voice in case of play voice */ static status_t emuxki_voice_channel_create(emuxki_voice *voice) { emuxki_channel **channel = voice->stream->card->channel; uint8 i, stereo = voice->stereo; //int s; for (i = 0; i < EMU_NUMCHAN - stereo; i += stereo + 1) { if ((stereo && (channel[i + 1] != NULL)) || (channel[i] != NULL)) /* Looking for free channels */ continue; //s = splaudio(); if (stereo) { voice->dataloc.chan[1] = emuxki_channel_new(voice, i + 1); if (voice->dataloc.chan[1] == NULL) { //splx(s); return ENOMEM; } } voice->dataloc.chan[0] = emuxki_channel_new(voice, i); if (voice->dataloc.chan[0] == NULL) { if (stereo) { emuxki_channel_delete(voice->dataloc.chan[1]); voice->dataloc.chan[1] = NULL; } //splx(s); return ENOMEM; } //splx(s); return B_OK; } return EAGAIN; } /* When calling this function we assume no one can access the voice */ static void emuxki_voice_channel_destroy(emuxki_voice *voice) { emuxki_channel_delete(voice->dataloc.chan[0]); voice->dataloc.chan[0] = NULL; if (voice->stereo) emuxki_channel_delete(voice->dataloc.chan[1]); voice->dataloc.chan[1] = NULL; } static status_t emuxki_voice_dataloc_create(emuxki_voice *voice) { status_t error; if (voice->use & EMU_USE_PLAY) { if ((error = emuxki_voice_channel_create(voice))) return (error); } else { } return B_OK; } static void emuxki_voice_dataloc_destroy(emuxki_voice *voice) { if (voice->use & EMU_USE_PLAY) { if (voice->dataloc.chan[0] != NULL) emuxki_voice_channel_destroy(voice); } else { uint32 buffaddr_reg, buffsize_reg; switch (voice->dataloc.source) { case EMU_RECSRC_MIC: buffaddr_reg = EMU_MICBA; buffsize_reg = EMU_MICBS; break; case EMU_RECSRC_ADC: buffaddr_reg = EMU_ADCBA; buffsize_reg = EMU_ADCBS; break; case EMU_RECSRC_FX: buffaddr_reg = EMU_FXBA; buffsize_reg = EMU_FXBS; break; default: return; } emuxki_chan_write(&voice->stream->card->config, 0, buffaddr_reg, 0); emuxki_chan_write(&voice->stream->card->config, 0, buffsize_reg, EMU_RECBS_BUFSIZE_NONE); } } static void emuxki_voice_fxupdate(emuxki_voice *voice) { emuxki_chanparms_fxsend fxsend; uint8 maxlevel = IS_AUDIGY(&voice->stream->card->config) ? 0xc0 : 0xff; /* not max */ if (voice->use & EMU_USE_PLAY) { fxsend.a.dest = 0x3f; fxsend.b.dest = 0x3f; fxsend.c.dest = 0x3f; fxsend.d.dest = 0x3f; /* for audigy */ fxsend.e.dest = 0x3f; fxsend.f.dest = 0x3f; fxsend.g.dest = 0x3f; fxsend.h.dest = 0x3f; fxsend.a.level = fxsend.b.level = fxsend.c.level = fxsend.d.level = fxsend.e.level = fxsend.g.level = fxsend.f.level = fxsend.h.level = 0x00; if (voice->stereo) { switch(voice->stream->card->play_mode) { case 2: if (voice->stream->nstereo == 1) { fxsend.a.dest = voice->voicenum * 2; fxsend.a.level = maxlevel; } else if ((voice->stream->nstereo == 2) || ((voice->stream->nstereo == 3)&&(voice->voicenum < 2))) { fxsend.a.dest = voice->voicenum * 2; fxsend.a.level = maxlevel; if (voice->voicenum > 1 - 1) fxsend.a.dest-=2; } else if (voice->stream->nstereo == 3 && voice->voicenum > 1) { fxsend.a.dest = 0x0; fxsend.a.level = maxlevel / 2; fxsend.b.dest = 0x1; fxsend.b.level = maxlevel / 2; } else { LOG(("emuxki_voice_set_stereo case 2 badly managed\n")); } break; case 4: if (voice->stream->nstereo == 1) { fxsend.a.dest = voice->voicenum * 2; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum * 2 + 2; fxsend.b.level = maxlevel; } else if ((voice->stream->nstereo == 2) || ((voice->stream->nstereo == 3)&&(voice->voicenum < 2))) { fxsend.a.dest = voice->voicenum * 2; fxsend.a.level = maxlevel; } else if (voice->stream->nstereo == 3 && voice->voicenum > 1) { fxsend.a.dest = 0x0; fxsend.a.level = maxlevel / 2; fxsend.b.dest = 0x1; fxsend.b.level = maxlevel / 2; } else { LOG(("emuxki_voice_set_stereo case 4 badly managed\n")); } break; case 6: // only on audigy if (voice->stream->nstereo == 1) { fxsend.a.dest = voice->voicenum * 2; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum * 2 + 2; fxsend.b.level = maxlevel; fxsend.c.dest = 0x4; fxsend.c.level = maxlevel / 2; fxsend.d.dest = 0x5; fxsend.d.level = maxlevel / 2; } else if (voice->stream->nstereo == 2) { fxsend.a.dest = voice->voicenum * 2; fxsend.a.level = maxlevel; if (voice->voicenum < 1) { fxsend.b.dest = 0x4; fxsend.b.level = maxlevel / 2; fxsend.c.dest = 0x5; fxsend.c.level = maxlevel / 2; } } else if (voice->stream->nstereo == 3) { fxsend.a.dest = voice->voicenum * 2; fxsend.a.level = maxlevel; } else { LOG(("emuxki_voice_set_stereo case 6 badly managed\n")); } break; } emuxki_channel_set_fxsend(voice->dataloc.chan[0], &fxsend); switch(voice->stream->card->play_mode) { case 2: if (voice->stream->nstereo == 1) { fxsend.a.dest = voice->voicenum * 2 + 1; fxsend.a.level = maxlevel; } else if ((voice->stream->nstereo == 2) || ((voice->stream->nstereo == 3)&&(voice->voicenum < 2))) { fxsend.a.dest = voice->voicenum * 2 + 1; fxsend.a.level = maxlevel; if (voice->voicenum > 1 - 1) fxsend.a.dest-=2; } else if (voice->stream->nstereo == 3 && voice->voicenum > 1) { fxsend.a.dest = 0x0; fxsend.a.level = maxlevel / 2; fxsend.b.dest = 0x1; fxsend.b.level = maxlevel / 2; } else { LOG(("emuxki_voice_set_stereo case 2 badly managed\n")); } break; case 4: if (voice->stream->nstereo == 1) { fxsend.a.dest = voice->voicenum * 2 + 1; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum * 2 + 3; fxsend.b.level = maxlevel; } else if ((voice->stream->nstereo == 2) || ((voice->stream->nstereo == 3)&&(voice->voicenum < 2))) { fxsend.a.dest = voice->voicenum * 2 + 1; fxsend.a.level = maxlevel; } else if (voice->stream->nstereo == 3 && voice->voicenum > 1) { fxsend.a.dest = 0x0; fxsend.a.level = maxlevel / 2; fxsend.b.dest = 0x1; fxsend.b.level = maxlevel / 2; } else { LOG(("emuxki_voice_set_stereo case 4 badly managed\n")); } break; case 6: // only on audigy if (voice->stream->nstereo == 1) { fxsend.a.dest = voice->voicenum * 2 + 1; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum * 2 + 3; fxsend.b.level = maxlevel; fxsend.c.dest = 0x4; fxsend.c.level = maxlevel / 2; fxsend.d.dest = 0x5; fxsend.d.level = maxlevel / 2; } else if (voice->stream->nstereo == 2) { fxsend.a.dest = voice->voicenum * 2 + 1; fxsend.a.level = maxlevel; if (voice->voicenum < 1) { fxsend.b.dest = 0x4; fxsend.b.level = maxlevel / 2; fxsend.c.dest = 0x5; fxsend.c.level = maxlevel / 2; } } else if (voice->stream->nstereo == 3) { fxsend.a.dest = voice->voicenum * 2 + 1; fxsend.a.level = maxlevel; } else { LOG(("emuxki_voice_set_stereo case 6 badly managed\n")); } break; } emuxki_channel_set_fxsend(voice->dataloc.chan[1], &fxsend); } else { switch(voice->stream->card->play_mode) { case 2: if (voice->stream->nmono == 1) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum + 1; fxsend.b.level = maxlevel; } else if (voice->stream->nmono == 2) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; } else if ((voice->stream->nmono == 4) || ((voice->stream->nmono == 6)&&(voice->voicenum < 4))) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; if (voice->voicenum > 2 - 1) fxsend.a.dest-=2; } else if (voice->stream->nmono == 6 && voice->voicenum > 3) { fxsend.a.dest = 0x0; fxsend.a.level = maxlevel / 2; fxsend.b.dest = 0x1; fxsend.b.level = maxlevel / 2; } else { LOG(("emuxki_voice_set_stereo case 2 badly managed\n")); } break; case 4: if (voice->stream->nmono == 1) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum + 1; fxsend.b.level = maxlevel; fxsend.c.dest = voice->voicenum + 2; fxsend.c.level = maxlevel; fxsend.d.dest = voice->voicenum + 3; fxsend.d.level = maxlevel; } else if (voice->stream->nmono == 2) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum + 2; fxsend.b.level = maxlevel; } else if ((voice->stream->nmono == 4) || ((voice->stream->nmono == 6)&&(voice->voicenum < 4))) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; } else if (voice->stream->nmono == 6 && voice->voicenum > 3) { fxsend.a.dest = 0x0; fxsend.a.level = maxlevel / 2; fxsend.b.dest = 0x1; fxsend.b.level = maxlevel / 2; } else { LOG(("emuxki_voice_set_stereo case 4 badly managed\n")); } break; case 6: // only on audigy if (voice->stream->nmono == 1) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum + 1; fxsend.b.level = maxlevel; fxsend.c.dest = voice->voicenum + 2; fxsend.c.level = maxlevel; fxsend.d.dest = voice->voicenum + 3; fxsend.d.level = maxlevel; fxsend.e.dest = voice->voicenum + 4; fxsend.e.level = maxlevel; fxsend.f.dest = voice->voicenum + 5; fxsend.f.level = maxlevel; } else if (voice->stream->nmono == 2) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; fxsend.b.dest = voice->voicenum + 2; fxsend.b.level = maxlevel; fxsend.c.dest = 0x4; fxsend.c.level = maxlevel / 2; fxsend.d.dest = 0x5; fxsend.d.level = maxlevel / 2; } else if (voice->stream->nmono == 4) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; if (voice->voicenum < 2) { fxsend.b.dest = 0x4; fxsend.b.level = maxlevel / 2; fxsend.c.dest = 0x5; fxsend.c.level = maxlevel / 2; } } else if (voice->stream->nmono == 6) { fxsend.a.dest = voice->voicenum; fxsend.a.level = maxlevel; } else { LOG(("emuxki_voice_set_stereo case 6 badly managed\n")); } break; } emuxki_channel_set_fxsend(voice->dataloc.chan[0], &fxsend); } } } static status_t emuxki_voice_set_stereo(emuxki_voice *voice, uint8 stereo) { status_t error; emuxki_voice_dataloc_destroy(voice); voice->stereo = stereo; if ((error = emuxki_voice_dataloc_create(voice))) return error; emuxki_voice_fxupdate(voice); return B_OK; } static status_t emuxki_voice_set_srate(emuxki_voice *voice, uint32 srate) { voice->sample_rate = srate; if (voice->use & EMU_USE_PLAY) { if ((srate < 4000) || (srate > 48000)) return (EINVAL); emuxki_channel_set_srate(voice->dataloc.chan[0], srate); if (voice->stereo) emuxki_channel_set_srate(voice->dataloc.chan[1], srate); } return B_OK; } status_t emuxki_voice_set_audioparms(emuxki_voice *voice, uint8 stereo, uint8 b16, uint32 srate) { status_t error; if (voice->stereo == stereo && voice->b16 == b16 && voice->sample_rate == srate) return B_OK; if (voice->stereo != stereo) { if ((error = emuxki_voice_set_stereo(voice, stereo))) return error; } voice->b16 = b16; if (voice->sample_rate != srate) emuxki_voice_set_srate(voice, srate); return B_OK; } status_t emuxki_voice_set_recparms(emuxki_voice *voice, emuxki_recsrc_t recsrc, emuxki_recparams *recparams) { if (voice->use & EMU_USE_RECORD) { switch(recsrc) { case EMU_RECSRC_MIC: break; case EMU_RECSRC_ADC: break; case EMU_RECSRC_FX: if (!recparams) return B_ERROR; voice->recparams.efx_voices[0] = recparams->efx_voices[0]; voice->recparams.efx_voices[1] = recparams->efx_voices[1]; break; default: return B_ERROR; break; } voice->dataloc.source = recsrc; } return B_OK; } /* voice audio parms (see just before) must be set prior to this */ status_t emuxki_voice_set_bufparms(emuxki_voice *voice, void *ptr, uint32 bufsize, uint16 blksize) { emuxki_mem *mem; emuxki_channel **chan; uint32 start, end; uint8 sample_size; status_t error = EFAULT; LIST_FOREACH(mem, &voice->stream->card->mem, next) { if (mem->log_base != ptr) continue; voice->buffer = mem; sample_size = (voice->b16 + 1) * (voice->stereo + 1); voice->trigblk = 0; /* This shouldn't be needed */ voice->blkmod = bufsize / blksize; if (bufsize % blksize) /* This should not happen */ voice->blkmod++; error = 0; if (voice->use & EMU_USE_PLAY) { voice->blksize = blksize / sample_size; chan = voice->dataloc.chan; start = (mem->ptbidx << 12) / sample_size; end = start + bufsize / sample_size; emuxki_channel_set_bufparms(chan[0], start, end); if (voice->stereo) emuxki_channel_set_bufparms(chan[1], start, end); voice->timerate = (uint32) 48000 * voice->blksize / voice->sample_rate / 2; if (voice->timerate < 5) error = EINVAL; } else { voice->blksize = blksize; } break; } return error; } status_t emuxki_voice_commit_parms(emuxki_voice *voice) { if (voice->use & EMU_USE_PLAY) { emuxki_channel_commit_parms(voice->dataloc.chan[0]); if (voice->stereo) emuxki_channel_commit_parms(voice->dataloc.chan[1]); } else { uint32 buffaddr_reg, buffsize_reg, idx_reg; switch (voice->dataloc.source) { case EMU_RECSRC_MIC: buffaddr_reg = EMU_MICBA; buffsize_reg = EMU_MICBS; idx_reg = EMU_MICIDX; break; case EMU_RECSRC_ADC: buffaddr_reg = EMU_ADCBA; buffsize_reg = EMU_ADCBS; idx_reg = EMU_ADCIDX; break; case EMU_RECSRC_FX: buffaddr_reg = EMU_FXBA; buffsize_reg = EMU_FXBS; idx_reg = EMU_FXIDX; break; default: return B_ERROR; } emuxki_chan_write(&voice->stream->card->config, 0, buffaddr_reg, (uint32)voice->buffer->phy_base); emuxki_chan_write(&voice->stream->card->config, 0, buffsize_reg, EMU_RECBS_BUFSIZE_NONE); emuxki_chan_write(&voice->stream->card->config, 0, buffsize_reg, EMU_RECBS_BUFSIZE_4096); LOG(("emuxki_voice_commit_parms idx_reg : %u\n", idx_reg)); idx_reg = EMU_RECIDX(idx_reg); while (emuxki_chan_read(&voice->stream->card->config, 0, idx_reg)) snooze(5); } return B_OK; } static uint32 emuxki_voice_curaddr(emuxki_voice *voice) { if (voice->use & EMU_USE_PLAY) return (emuxki_chan_read(&voice->stream->card->config, voice->dataloc.chan[0]->num, EMU_CHAN_CCCA_CURRADDR) - voice->dataloc.chan[0]->loop.start); else { uint32 idx_reg = 0; switch (voice->dataloc.source) { case EMU_RECSRC_MIC: idx_reg = IS_AUDIGY(&voice->stream->card->config) ? EMU_A_MICIDX : EMU_MICIDX; break; case EMU_RECSRC_ADC: idx_reg = IS_AUDIGY(&voice->stream->card->config) ? EMU_A_ADCIDX : EMU_ADCIDX; break; case EMU_RECSRC_FX: idx_reg = EMU_FXIDX; break; default: TRACE(("emuxki_voice_curaddr : BUG!!\n")); } //TRACE(("emuxki_voice_curaddr idx_reg : %u\n", idx_reg)); //TRACE(("emuxki_voice_curaddr : %lu\n", emuxki_chan_read(&voice->stream->card->config, 0, idx_reg))); return emuxki_chan_read(&voice->stream->card->config, 0, idx_reg); } } static void emuxki_resched_timer(emuxki_dev *card) { emuxki_voice *voice; emuxki_stream *stream; uint16 timerate = 1024; uint8 active = 0; //int s = splaudio(); LOG(("emuxki_resched_timer begin\n")); LIST_FOREACH(stream, &card->streams, next) { LIST_FOREACH(voice, &stream->voices, next) { if ((voice->use & EMU_USE_PLAY) == 0 || (voice->state & EMU_STATE_STARTED) == 0) continue; active = 1; if (voice->timerate < timerate) timerate = voice->timerate; } } if (timerate & ~EMU_TIMER_RATE_MASK) timerate = 0; if (card->timerate > timerate) { LOG(("emuxki_resched_timer written (old %u, new %u)\n", card->timerate, timerate)); card->timerate = timerate; emuxki_reg_write_16(&card->config, EMU_TIMER, timerate); } if (!active && (card->timerstate & EMU_TIMER_STATE_ENABLED)) { emuxki_inte_disable(&card->config, EMU_INTE_INTERTIMERENB); card->timerstate &= ~EMU_TIMER_STATE_ENABLED; LOG(("emuxki_resched_timer : timer disabled\n")); } else if (active && !(card->timerstate & EMU_TIMER_STATE_ENABLED)) { emuxki_inte_enable(&card->config, EMU_INTE_INTERTIMERENB); card->timerstate |= EMU_TIMER_STATE_ENABLED; LOG(("emuxki_resched_timer : timer enabled\n")); } LOG(("emuxki_resched_timer state : %x\n", card->timerstate)); //splx(s); } static uint32 emuxki_voice_adc_rate(emuxki_voice *voice) { switch(voice->sample_rate) { case 48000: return EMU_ADCCR_SAMPLERATE_48; break; case 44100: return EMU_ADCCR_SAMPLERATE_44; break; case 32000: return EMU_ADCCR_SAMPLERATE_32; break; case 24000: return EMU_ADCCR_SAMPLERATE_24; break; case 22050: return EMU_ADCCR_SAMPLERATE_22; break; case 16000: return EMU_ADCCR_SAMPLERATE_16; break; case 12000: if (IS_AUDIGY(&voice->stream->card->config)) return EMU_A_ADCCR_SAMPLERATE_12; else PRINT(("recording sample_rate not supported : %" B_PRIu32 "\n", voice->sample_rate)); break; case 11000: if (IS_AUDIGY(&voice->stream->card->config)) return EMU_A_ADCCR_SAMPLERATE_11; else return EMU_ADCCR_SAMPLERATE_11; break; case 8000: if (IS_AUDIGY(&voice->stream->card->config)) return EMU_A_ADCCR_SAMPLERATE_8; else return EMU_ADCCR_SAMPLERATE_8; break; default: PRINT(("recording sample_rate not supported : %" B_PRIu32 "\n", voice->sample_rate)); } return 0; } void emuxki_voice_start(emuxki_voice *voice) { LOG(("emuxki_voice_start\n")); if (voice->use & EMU_USE_PLAY) { voice->trigblk = 1; emuxki_channel_start(voice->dataloc.chan[0]); if (voice->stereo) emuxki_channel_start(voice->dataloc.chan[1]); } else { switch (voice->dataloc.source) { case EMU_RECSRC_MIC: emuxki_inte_enable(&voice->stream->card->config, EMU_INTE_MICBUFENABLE); break; case EMU_RECSRC_ADC: { uint32 adccr_value = 0; adccr_value = emuxki_voice_adc_rate(voice); LOG(("emuxki_voice_start adccr_value : %u\n", adccr_value)); if (voice->stereo) adccr_value |= ( (IS_AUDIGY(&voice->stream->card->config) ? EMU_A_ADCCR_LCHANENABLE : EMU_ADCCR_LCHANENABLE ) | ( IS_AUDIGY(&voice->stream->card->config) ? EMU_A_ADCCR_RCHANENABLE : EMU_ADCCR_RCHANENABLE )); else adccr_value |= IS_AUDIGY(&voice->stream->card->config) ? EMU_A_ADCCR_LCHANENABLE : EMU_ADCCR_LCHANENABLE; LOG(("emuxki_voice_start adccr_value : %u, %u\n", adccr_value, EMU_ADCCR_LCHANENABLE | EMU_ADCCR_RCHANENABLE)); emuxki_chan_write(&voice->stream->card->config, 0, EMU_ADCCR, adccr_value); emuxki_inte_enable(&voice->stream->card->config, EMU_INTE_ADCBUFENABLE); } break; case EMU_RECSRC_FX: if (IS_AUDIGY(&voice->stream->card->config)) { emuxki_chan_write(&voice->stream->card->config, 0, EMU_A_FXWC1, voice->recparams.efx_voices[0]); emuxki_chan_write(&voice->stream->card->config, 0, EMU_A_FXWC2, voice->recparams.efx_voices[1]); } else { emuxki_chan_write(&voice->stream->card->config, 0, EMU_FXWC, voice->recparams.efx_voices[0]); } emuxki_inte_enable(&voice->stream->card->config, EMU_INTE_EFXBUFENABLE); break; default: PRINT(("emuxki_voice_start BUG\n")); } } voice->state |= EMU_STATE_STARTED; if (voice->use & EMU_USE_PLAY) { emuxki_resched_timer(voice->stream->card); } } void emuxki_voice_halt(emuxki_voice *voice) { LOG(("emuxki_voice_halt\n")); if (voice->use & EMU_USE_PLAY) { emuxki_channel_stop(voice->dataloc.chan[0]); if (voice->stereo) emuxki_channel_stop(voice->dataloc.chan[1]); } else { switch (voice->dataloc.source) { case EMU_RECSRC_MIC: emuxki_inte_disable(&voice->stream->card->config, EMU_INTE_MICBUFENABLE); break; case EMU_RECSRC_ADC: emuxki_chan_write(&voice->stream->card->config, 0, EMU_ADCCR, 0); emuxki_inte_disable(&voice->stream->card->config, EMU_INTE_ADCBUFENABLE); break; case EMU_RECSRC_FX: if (IS_AUDIGY(&voice->stream->card->config)) { emuxki_chan_write(&voice->stream->card->config, 0, EMU_A_FXWC1, 0); emuxki_chan_write(&voice->stream->card->config, 0, EMU_A_FXWC2, 0); } else emuxki_chan_write(&voice->stream->card->config, 0, EMU_FXWC, 0); emuxki_inte_disable(&voice->stream->card->config, EMU_INTE_EFXBUFENABLE); break; default: PRINT(("emuxki_voice_halt BUG\n")); } } voice->state &= ~EMU_STATE_STARTED; if (voice->use & EMU_USE_PLAY) { emuxki_resched_timer(voice->stream->card); } } emuxki_voice * emuxki_voice_new(emuxki_stream *stream, uint8 use, uint8 voicenum) { emuxki_voice *voice; //int s; LOG(("emuxki_voice_new\n")); voice = malloc(sizeof(emuxki_voice)); if (voice == NULL) return (NULL); voice->stream = stream; voice->use = use; voice->state = !EMU_STATE_STARTED; voice->stereo = EMU_STEREO_NOTSET; voice->b16 = 0; voice->sample_rate = 0; if (use & EMU_USE_PLAY) voice->dataloc.chan[0] = voice->dataloc.chan[1] = NULL; else voice->dataloc.source = EMU_RECSRC_NOTSET; voice->buffer = NULL; voice->blksize = 0; voice->trigblk = 0; voice->blkmod = 0; voice->timerate = 0; voice->voicenum = voicenum; return voice; } void emuxki_voice_delete(emuxki_voice *voice) { if (voice->state & EMU_STATE_STARTED) emuxki_voice_halt(voice); emuxki_voice_dataloc_destroy(voice); free(voice); } /* Emuxki stream functions */ status_t emuxki_stream_set_audioparms(emuxki_stream *stream, bool stereo, uint8 channels, uint8 b16, uint32 sample_rate) { status_t error; emuxki_voice *voice; uint8 i, nvoices; char *buffer; uint8 sample_size, frame_size; LOG(("emuxki_stream_set_audioparms\n")); if (stream->stereo == stereo && ((stream->nmono + 2*stream->nstereo) == channels) && (stream->b16 == b16) && (stream->sample_rate == sample_rate)) return B_OK; LIST_FOREACH(voice, &stream->voices, next) { if (voice->buffer) emuxki_mem_free(stream->card, voice->buffer->log_base); emuxki_voice_delete(voice); } stream->first_voice = NULL; LIST_INIT(&(stream->voices)); stream->b16 = b16; stream->sample_rate = sample_rate; if (stereo && (channels % 2 == 0)) { stream->stereo = true; stream->nstereo = channels / 2; stream->nmono = 0; nvoices = stream->nstereo; } else { stream->stereo = false; stream->nstereo = 0; stream->nmono = channels; nvoices = stream->nmono; } sample_size = stream->b16 + 1; frame_size = sample_size * (stream->stereo ? 2 : 1); for (i = 0; i < nvoices; i++) { voice = emuxki_voice_new(stream, stream->use, i); if (voice) { if (!stream->first_voice) stream->first_voice = voice; LIST_INSERT_HEAD((&stream->voices), voice, next); if ((error = emuxki_voice_set_audioparms(voice, stream->stereo, stream->b16, stream->sample_rate))) return error; if (stream->use & EMU_USE_PLAY) buffer = emuxki_pmem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount); else buffer = emuxki_rmem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount); emuxki_voice_set_bufparms(voice, buffer, stream->bufframes * frame_size * stream->bufcount, stream->bufframes * frame_size); } } return B_OK; } status_t emuxki_stream_set_recparms(emuxki_stream *stream, emuxki_recsrc_t recsrc, emuxki_recparams *recparams) { emuxki_voice *voice; LOG(("emuxki_stream_set_recparms\n")); if (stream->use & EMU_USE_RECORD) { switch(recsrc) { case EMU_RECSRC_MIC: break; case EMU_RECSRC_ADC: break; case EMU_RECSRC_FX: if (!recparams) return B_ERROR; LIST_FOREACH(voice, &stream->voices, next) { voice->recparams.efx_voices[0] = recparams->efx_voices[0]; voice->recparams.efx_voices[1] = recparams->efx_voices[1]; } break; default: return B_ERROR; break; } LIST_FOREACH(voice, &stream->voices, next) voice->dataloc.source = recsrc; } return B_OK; } status_t emuxki_stream_commit_parms(emuxki_stream *stream) { emuxki_voice *voice; status_t error; LOG(("emuxki_stream_commit_parms\n")); LIST_FOREACH(voice, &stream->voices, next) if ((error = emuxki_voice_commit_parms(voice))) return error; return B_OK; } status_t emuxki_stream_get_nth_buffer(emuxki_stream *stream, uint8 chan, uint8 buf, char** buffer, size_t *stride) { emuxki_voice *voice = NULL; uint8 i, sample_size; LOG(("emuxki_stream_get_nth_buffer\n")); sample_size = stream->b16 + 1; if (buf >= stream->bufcount) return B_BAD_INDEX; if (stream->stereo) { i = stream->nstereo - 1; if (chan/2 > i) return B_BAD_INDEX; LIST_FOREACH(voice, &stream->voices, next) if (i != chan/2) i--; else break; if (voice) { *buffer = (char*)voice->buffer->log_base + (buf * stream->bufframes * sample_size * 2); if (chan % 2 == 1) *buffer += sample_size; *stride = sample_size * 2; } else return B_ERROR; } else { i = stream->nmono - 1; if (chan > i) return B_BAD_INDEX; LIST_FOREACH(voice, &stream->voices, next) if (i != chan) i--; else break; if (voice) { *buffer = (char*)voice->buffer->log_base + (buf * stream->bufframes * sample_size); *stride = sample_size; } else return B_ERROR; } return B_OK; } void emuxki_stream_start(emuxki_stream *stream, void (*inth) (void *), void *inthparam) { emuxki_voice *voice; LOG(("emuxki_stream_start\n")); stream->inth = inth; stream->inthparam = inthparam; LIST_FOREACH(voice, &stream->voices, next) { emuxki_voice_start(voice); } stream->state |= EMU_STATE_STARTED; } void emuxki_stream_halt(emuxki_stream *stream) { emuxki_voice *voice; LOG(("emuxki_stream_halt\n")); LIST_FOREACH(voice, &stream->voices, next) { emuxki_voice_halt(voice); } stream->state &= ~EMU_STATE_STARTED; } emuxki_stream * emuxki_stream_new(emuxki_dev *card, uint8 use, uint32 bufframes, uint8 bufcount) { emuxki_stream *stream; cpu_status status; LOG(("emuxki_stream_new\n")); stream = malloc(sizeof(emuxki_stream)); if (stream == NULL) return (NULL); stream->card = card; stream->use = use; stream->state = !EMU_STATE_STARTED; stream->stereo = EMU_STEREO_NOTSET; stream->b16 = 0; stream->sample_rate = 0; stream->nmono = 0; stream->nstereo = 0; stream->bufframes = bufframes; stream->bufcount = bufcount; stream->first_voice = NULL; stream->inth = NULL; stream->inthparam = NULL; stream->frames_count = 0; stream->real_time = 0; stream->buffer_cycle = 0; stream->update_needed = false; /* Init voices list */ LIST_INIT(&(stream->voices)); status = lock(); LIST_INSERT_HEAD((&card->streams), stream, next); unlock(status); return stream; } void emuxki_stream_delete(emuxki_stream *stream) { emuxki_voice *voice; cpu_status status; LOG(("emuxki_stream_delete\n")); emuxki_stream_halt(stream); status = lock(); LIST_REMOVE(stream, next); unlock(status); while (!LIST_EMPTY(&stream->voices)) { voice = LIST_FIRST(&stream->voices); LIST_REMOVE(voice, next); if (voice->buffer) emuxki_mem_free(stream->card, voice->buffer->log_base); emuxki_voice_delete(voice); } free(stream); } /* Emuxki gprs */ // 87 values from 0.0dB to -xdB (-0.75dB each) static uint32 db_table[] = { 2147483647, 1969835071, 1806882308, 1657409659, 1520301995, 1394536435, 1279174712, 1173356181, 1076291388, 987256190, 905586345, 830672562, 761955951, 698923858, 641106035, 588071138, 539423503, 494800198, 453868315, 416322483, 381882595, 350291714, 321314160, 294733747, 270352173, 247987542, 227473005, 208655513, 191394681, 175561735, 161038555, 147716791, 135497057, 124288190, 114006566, 104575479, 95924570, 87989300, 80710468, 74033770, 67909395, 62291654, 57138635, 52411895, 48076170, 44099114, 40451056, 37104780, 34035322, 31219781, 28637154, 26268172, 24095162, 22101913, 20273552, 18596442, 17058068, 15646956, 14352576, 13165272, 12076188, 11077196, 10160845, 9320299, 8549286, 7842054, 7193328, 6598266, 6052431, 5551749, 5092486, 4671215, 4284793, 3930337, 3605204, 3306967, 3033401, 2782465, 2552289, 2341153, 2147483, 1969835, 1806882, 1657409, 1520301, 1394536, 1279174 }; void emuxki_gpr_set(emuxki_dev *card, emuxki_gpr *gpr, int32 type, float *values) { uint8 count = gpr->type & EMU_MIX_STEREO ? 2 : 1; uint8 i; uint32 index; LOG(("emuxki_set_gpr\n")); switch(type) { case EMU_MIX_MUTE: gpr->mute = (values[0] == 1.0); if (gpr->mute) { for (i = 0; i < count; i++) emuxki_write_gpr(&card->config, gpr->gpr + i, 0); break; } for (i = 0; i < count; i++) { values[i] = gpr->current[i]; } case EMU_MIX_GAIN: for (i = 0; i < count; i++) { if (values[i]>gpr->max_gain || values[i]min_gain) return; index = values[i] / gpr->granularity; if (index > sizeof(db_table)/sizeof(db_table[0])) index = sizeof(db_table)/sizeof(db_table[0]); LOG(("emuxki_set_gpr gpr: %d \n", gpr->gpr + i)); LOG(("emuxki_set_gpr values[i]: %g \n", values[i])); LOG(("emuxki_set_gpr index: %u \n", index)); if (!gpr->mute) emuxki_write_gpr(&card->config, gpr->gpr + i, db_table[index]); gpr->current[i] = index * gpr->granularity; } break; } } void emuxki_gpr_get(emuxki_dev *card, emuxki_gpr *gpr, int32 type, float *values) { uint8 count = gpr->type & EMU_MIX_STEREO ? 2 : 1; uint16 i; LOG(("emuxki_get_gpr\n")); switch(type) { case EMU_MIX_GAIN: for (i = 0; i < count; i++) { values[i] = gpr->current[i]; } break; case EMU_MIX_MUTE: values[0] = (gpr->mute ? 1.0 : 0.0); break; } } void emuxki_gpr_dump(emuxki_dev * card, uint16 count) { uint16 pc; uint32 value; LOG(("emuxki_dump_gprs\n")); for (pc = 0; pc < count; pc++) { value = emuxki_read_gpr(&card->config, pc); LOG(("dsp_gpr pc=%x, value=%x\n", pc, value)); } } static emuxki_gpr * emuxki_gpr_new(emuxki_dev *card, const char *name, emuxki_gpr_type type, uint16 *gpr_num, float default_value, float default_mute, float min_gain, float max_gain, float granularity) { emuxki_gpr *gpr; float values[2]; LOG(("emuxki_gpr_new\n")); gpr = &card->gpr[*gpr_num]; strncpy(gpr->name, name, 32); gpr->type = type; gpr->gpr = *gpr_num; gpr->default_value = default_value; gpr->min_gain = min_gain; gpr->max_gain = max_gain; gpr->granularity = granularity; gpr->mute = false; (*gpr_num)++; if (gpr->type & EMU_MIX_STEREO) (*gpr_num)++; if (default_mute == 1.0) { values[0] = default_mute; emuxki_gpr_set(card, gpr, EMU_MIX_MUTE, values); } values[0] = gpr->default_value; if (gpr->type & EMU_MIX_STEREO) values[1] = gpr->default_value; emuxki_gpr_set(card, gpr, EMU_MIX_GAIN, values); return gpr; } /* Emuxki parameter */ void emuxki_parameter_set(emuxki_dev *card, const void* cookie, int32 type, int32 *value) { emuxki_stream *stream; emuxki_voice *voice; LOG(("emuxki_parameter_set\n")); switch(type) { case EMU_DIGITAL_MODE: card->digital_enabled = *value == 1; if (IS_AUDIGY(&card->config)) if (IS_AUDIGY2(&card->config)) { // this disables analog, not enough emuxki_reg_write_32(&card->config, EMU_A_IOCFG, (card->digital_enabled ? 0 : EMU_A_IOCFG_GPOUT0) | (emuxki_reg_read_32(&card->config, EMU_A_IOCFG) & ~(EMU_A_IOCFG_GPOUT0 | EMU_A_IOCFG_GPOUT1) ) ); } else { // this disables analog, and enables digital emuxki_reg_write_32(&card->config, EMU_A_IOCFG, (card->digital_enabled ? EMU_A_IOCFG_GPOUT0 | EMU_A_IOCFG_GPOUT1 : 0) | (emuxki_reg_read_32(&card->config, EMU_A_IOCFG) & ~(EMU_A_IOCFG_GPOUT0 | EMU_A_IOCFG_GPOUT1) ) ); } else { // this enables digital, not enough emuxki_reg_write_32(&card->config, EMU_HCFG, (card->digital_enabled ? EMU_HCFG_GPOUTPUT0 : 0) | (emuxki_reg_read_32(&card->config, EMU_HCFG) & ~EMU_HCFG_GPOUTPUT0)); } break; case EMU_AUDIO_MODE: if (*value!=0 && *value!=1 && *value!=2) { PRINT(("emuxki_parameter_set error value unexpected\n")); return; } card->play_mode = (*value + 1) * 2; LIST_FOREACH(stream, &card->streams, next) { if ((stream->use & EMU_USE_PLAY) == 0 || (stream->state & EMU_STATE_STARTED) == 0) continue; LIST_FOREACH(voice, &stream->voices, next) { emuxki_voice_fxupdate(voice); emuxki_channel_commit_fx(voice->dataloc.chan[0]); if (voice->stereo) emuxki_channel_commit_fx(voice->dataloc.chan[1]); } } break; } } void emuxki_parameter_get(emuxki_dev *card, const void* cookie, int32 type, int32 *value) { LOG(("emuxki_parameter_get\n")); switch(type) { case EMU_DIGITAL_MODE: *value = card->digital_enabled ? 1 : 0; break; case EMU_AUDIO_MODE: *value = card->play_mode / 2 - 1; break; } } /* Emuxki interrupt */ static int32 emuxki_int(void *arg) { emuxki_dev *card = arg; uint32 ipr, curblk; bool gotone = false; emuxki_voice *voice; emuxki_stream *stream; while ((ipr = emuxki_reg_read_32(&card->config, EMU_IPR))) { gotone = true; if (ipr & EMU_IPR_INTERVALTIMER) { //TRACE(("EMU_IPR_INTERVALTIMER\n")); LIST_FOREACH(stream, &card->streams, next) { if ((stream->use & EMU_USE_PLAY) == 0 || (stream->state & EMU_STATE_STARTED) == 0 || (stream->inth == NULL)) continue; voice = stream->first_voice; //TRACE(("voice %p\n", voice)); curblk = emuxki_voice_curaddr(voice) / voice->blksize; //TRACE(("EMU_IPR_INTERVALTIMER at trigblk %lu\n", curblk)); //TRACE(("EMU_IPR_INTERVALTIMER at voice->trigblk %lu\n", voice->trigblk)); if (curblk == voice->trigblk) { //TRACE(("EMU_IPR_INTERVALTIMER at trigblk %lu\n", curblk)); //dump_voice(voice); //trace_hardware_regs(&card->config); //TRACE(("voice pointer %p\n", voice)); if (stream->inth) stream->inth(stream->inthparam); voice->trigblk++; voice->trigblk %= voice->blkmod; } } } #if MIDI if (ipr & (EMU_IPR_MIDIRECVBUFE)) { midi_interrupt(card); /* Gameport */ } if (ipr & (EMU_IPR_MIDITRANSBUFE)) { if (!midi_interrupt(card)) { emuxki_inte_disable(&card->config, EMU_INTE_MIDITXENABLE); TRACE(("EMU_INTE_MIDITXENABLE disabled\n")); } } #endif if (ipr & (EMU_IPR_ADCBUFHALFFULL | EMU_IPR_ADCBUFFULL | EMU_IPR_MICBUFHALFFULL | EMU_IPR_MICBUFFULL | EMU_IPR_EFXBUFHALFFULL | EMU_IPR_EFXBUFFULL)) { //TRACE(("EMU_IPR_ADCBUF\n")); LIST_FOREACH(stream, &card->streams, next) { if ((stream->use & EMU_USE_RECORD) == 0 || (stream->state & EMU_STATE_STARTED) == 0 || (stream->inth == NULL) || (stream->first_voice == NULL)) continue; voice = stream->first_voice; curblk = emuxki_voice_curaddr(voice) / voice->blksize; //TRACE(("EMU_IPR_ADCBUF at trigblk %lu\n", curblk)); //TRACE(("EMU_IPR_ADCBUF at voice->trigblk %lu\n", voice->trigblk)); if (curblk == voice->trigblk) { //TRACE(("EMU_IPR_ADCBUF at trigblk %lu\n", curblk)); //dump_voice(voice); //trace_hardware_regs(&card->config); if (stream->inth) stream->inth(stream->inthparam); voice->trigblk++; voice->trigblk %= voice->blkmod; } } } /*if (ipr & (EMU_IPR_CHANNELLOOP)) { TRACE(("EMU_IPR_CHANNELLOOP pending channel : %u\n", ipr & EMU_IPR_CHNOMASK)); LIST_FOREACH(stream, &card->streams, next) LIST_FOREACH(voice, &stream->voices, next) { if ((voice->use & EMU_USE_PLAY) == 0 || (voice->state & EMU_STATE_STARTED) == 0) continue; TRACE(("EMU_IPR_CHANNELLOOP at trigblk %lu\n", emuxki_voice_curaddr(voice))); TRACE(("EMU_IPR_CHANNELLOOP read %x\n", emuxki_chan_read(&voice->card->config, 0, EMU_CLIPL))); emuxki_chan_write(&voice->card->config, 0, EMU_CLIPL, emuxki_chan_read(&voice->card->config, 0, EMU_CLIPL)); } }*/ if (ipr & ~(EMU_IPR_RATETRCHANGE | EMU_IPR_INTERVALTIMER | EMU_IPR_MIDITRANSBUFE | EMU_IPR_MIDIRECVBUFE | EMU_IPR_ADCBUFHALFFULL | EMU_IPR_ADCBUFFULL | EMU_IPR_MICBUFHALFFULL | EMU_IPR_MICBUFFULL | EMU_IPR_EFXBUFHALFFULL | EMU_IPR_EFXBUFFULL)) TRACE(("Got interrupt 0x%08x !!!\n", ipr & ~(EMU_IPR_RATETRCHANGE | EMU_IPR_INTERVALTIMER))); emuxki_reg_write_32(&card->config, EMU_IPR, ipr); } if (IS_AUDIGY2(&card->config)) { while ((ipr = emuxki_reg_read_32(&card->config, EMU_A2_IPR2))) { emuxki_reg_write_32(&card->config, EMU_A2_IPR2, ipr); break; // avoid loop } if (!IS_AUDIGY2_VALUE(&card->config)) { while ((ipr = emuxki_reg_read_32(&card->config, EMU_A2_IPR3))) { emuxki_reg_write_32(&card->config, EMU_A2_IPR3, ipr); break; // avoid loop } } } if (gotone) return B_INVOKE_SCHEDULER; TRACE(("Got unhandled interrupt\n")); return B_UNHANDLED_INTERRUPT; } /* Emu10k1 driver functions */ /* detect presence of our hardware */ status_t init_hardware(void) { int ix = 0; pci_info info; // uint32 buffer; status_t err = ENODEV; LOG_CREATE(); PRINT(("init_hardware()\n")); if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci)) return ENOSYS; while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { if (info.vendor_id == CREATIVELABS_VENDOR_ID && (info.device_id == CREATIVELABS_SBLIVE_DEVICE_ID #if AUDIGY || info.device_id == CREATIVELABS_AUDIGY_DEVICE_ID || info.device_id == CREATIVELABS_AUDIGY2_VALUE_DEVICE_ID #endif )) { err = B_OK; /* Joystick suport if (!(info.u.h0.subsystem_id == 0x20 || info.u.h0.subsystem_id == 0xc400 || (info.u.h0.subsystem_id == 0x21 && info.revision < 6))) { buffer = (*pci->read_io_32)(info.u.h0.base_registers[0] + HCFG); buffer |= HCFG_JOYENABLE; (*pci->write_io_32)(info.u.h0.base_registers[0] + HCFG, buffer); }*/ } ix++; } put_module(B_PCI_MODULE_NAME); return err; } static void make_device_names( emuxki_dev * card) { #if MIDI sprintf(card->midi.name, "midi/emuxki/%ld", card-cards+1); names[num_names++] = card->midi.name; #endif // sprintf(card->joy.name1, "joystick/"DRIVER_NAME "/%x", card-cards+1); // names[num_names++] = card->joy.name1; sprintf(card->name, "audio/hmulti/emuxki/%ld", card-cards+1); names[num_names++] = card->name; names[num_names] = NULL; } static status_t emuxki_setup(emuxki_dev * card) { status_t err = B_OK; unsigned char cmd; //int32 base; PRINT(("setup_emuxki(%p)\n", card)); make_device_names(card); card->config.nabmbar = card->info.u.h0.base_registers[0]; card->config.irq = card->info.u.h0.interrupt_line; card->config.type = 0; if (card->info.device_id == CREATIVELABS_AUDIGY_DEVICE_ID) { card->config.type |= TYPE_AUDIGY; if (card->info.revision == 4) card->config.type |= TYPE_AUDIGY2; } else if (card->info.device_id == CREATIVELABS_AUDIGY2_VALUE_DEVICE_ID) card->config.type |= TYPE_AUDIGY | TYPE_AUDIGY2 | TYPE_AUDIGY2_VALUE; PRINT(("%s deviceid = %#04x chiprev = %x model = %x " "enhanced at %" B_PRIx32 "\n", card->name, card->info.device_id, card->info.revision, card->info.u.h0.subsystem_id, card->config.nabmbar)); cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); PRINT(("PCI command before: %x\n", cmd)); (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2, cmd | PCI_command_io); cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); PRINT(("PCI command after: %x\n", cmd)); dump_hardware_regs(&card->config); emuxki_reg_write_32(&card->config, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK| EMU_HCFG_MUTEBUTTONENABLE); dump_hardware_regs(&card->config); #if MIDI //SBLIVE : EMU_MUDATA, workaround 0, AUDIGY, AUDIGY2: 0, workaround 0x11020004 if ((err = (*mpu401->create_device)((card->config.nabmbar + (!IS_AUDIGY(&card->config) ? EMU_MUDATA : 0)), &card->midi.driver, !IS_AUDIGY(&card->config) ? 0 : 0x11020004, midi_interrupt_op, &card->midi)) < B_OK) return (err); card->midi.card = card; #endif // begin Joystick part /* base = card->info.u.h0.base_registers[0]; (*pci->write_pci_config) (card->info.bus,card->info.device, card->info.function, 0x10, 2, base); if ((*gameport->create_device)(base, &card->joy.driver) < B_OK) { dprintf("Audigy joystick - Error creating device\n"); (*gameport->delete_device)(card->joy.driver); }*/ // end Joystick part /* reset the codec */ PRINT(("codec reset\n")); emuxki_codec_write(&card->config, 0x00, 0x0000); snooze(50000); // 50 ms ac97_init(&card->config); ac97_amp_enable(&card->config, true); PRINT(("codec vendor id = %#08" B_PRIx32 "\n", ac97_get_vendor_id(&card->config))); PRINT(("codec description = %s\n", ac97_get_vendor_id_description(&card->config))); PRINT(("codec 3d enhancement = %s\n", ac97_get_3d_stereo_enhancement(&card->config))); if (IS_AUDIGY2(&card->config)) { emuxki_reg_write_32(&card->config, EMU_A_IOCFG, EMU_A_IOCFG_GPOUT0 | emuxki_reg_read_32(&card->config, EMU_A_IOCFG)); } dump_hardware_regs(&card->config); /*PRINT(("codec master output = %#04x\n",emuxki_codec_read(&card->config, 0x02))); PRINT(("codec aux output = %#04x\n",emuxki_codec_read(&card->config, 0x04))); PRINT(("codec mono output = %#04x\n",emuxki_codec_read(&card->config, 0x06))); PRINT(("codec pcm output = %#04x\n",emuxki_codec_read(&card->config, 0x18))); PRINT(("codec line in = %#04x\n",emuxki_codec_read(&card->config, 0x10))); PRINT(("codec record line in= %#04x\n",emuxki_codec_read(&card->config, 0x1a))); PRINT(("codec record gain = %#04x\n",emuxki_codec_read(&card->config, 0x1c)));*/ /*PRINT(("adc index = %#08x\n",emuxki_chan_read(&card->config, EMU_ADCIDX, 0))); PRINT(("micro index = %#08x\n",emuxki_chan_read(&card->config, EMU_MICIDX, 0))); PRINT(("fx index = %#08x\n",emuxki_chan_read(&card->config, EMU_FXIDX, 0))); PRINT(("adc addr = %#08x\n",emuxki_chan_read(&card->config, EMU_ADCBA, 0))); PRINT(("micro addr = %#08x\n",emuxki_chan_read(&card->config, EMU_MICBA, 0))); PRINT(("fx addr = %#08x\n",emuxki_chan_read(&card->config, EMU_FXBA, 0))); PRINT(("adc size = %#08x\n",emuxki_chan_read(&card->config, EMU_ADCBS, 0))); PRINT(("micro size = %#08x\n",emuxki_chan_read(&card->config, EMU_MICBS, 0))); PRINT(("fx size = %#08x\n",emuxki_chan_read(&card->config, EMU_FXBS, 0))); PRINT(("EMU_ADCCR = %#08x\n",emuxki_chan_read(&card->config, EMU_ADCCR, 0))); PRINT(("EMU_FXWC = %#08x\n",emuxki_chan_read(&card->config, EMU_FXWC, 0))); PRINT(("EMU_FXWC = %#08x\n",emuxki_reg_read_32(&card->config, EMU_FXWC)));*/ PRINT(("writing codec registers\n")); // TODO : to move with AC97 /* enable master output */ emuxki_codec_write(&card->config, AC97_MASTER_VOLUME, 0x0000); /* enable aux output */ emuxki_codec_write(&card->config, AC97_AUX_OUT_VOLUME, 0x0000); /* enable mono output */ //emuxki_codec_write(&card->config, AC97_MONO_VOLUME, 0x0004); /* enable pcm output */ emuxki_codec_write(&card->config, AC97_PCM_OUT_VOLUME, 0x0808); /* enable line in */ //emuxki_codec_write(&card->config, AC97_LINE_IN_VOLUME, 0x8808); /* set record line in */ emuxki_codec_write(&card->config, AC97_RECORD_SELECT, 0x0404); /* set record gain */ //emuxki_codec_write(&card->config, AC97_RECORD_GAIN, 0x0000); PRINT(("codec master output = %#04x\n",emuxki_codec_read(&card->config, AC97_MASTER_VOLUME))); PRINT(("codec aux output = %#04x\n",emuxki_codec_read(&card->config, AC97_AUX_OUT_VOLUME))); PRINT(("codec mono output = %#04x\n",emuxki_codec_read(&card->config, AC97_MONO_VOLUME))); PRINT(("codec pcm output = %#04x\n",emuxki_codec_read(&card->config, AC97_PCM_OUT_VOLUME))); PRINT(("codec line in = %#04x\n",emuxki_codec_read(&card->config, AC97_LINE_IN_VOLUME))); PRINT(("codec record line in= %#04x\n",emuxki_codec_read(&card->config, AC97_RECORD_SELECT))); PRINT(("codec record gain = %#04x\n",emuxki_codec_read(&card->config, AC97_RECORD_GAIN))); if (emuxki_codec_read(&card->config, AC97_EXTENDED_AUDIO_ID) & 0x0080) { card->config.type |= TYPE_LIVE_5_1; emuxki_chan_write(&card->config, 0, EMU_AC97SLOT, EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE); emuxki_codec_write(&card->config, AC97_SURROUND_VOLUME, 0x0000); } if ((err = emuxki_init(card))) return (err); if (IS_AUDIGY(&card->config) || IS_LIVE_5_1(&card->config)) { card->play_mode = 6; // mode 5.1 } else { card->play_mode = 4; // mode 4.0 } emuxki_reg_write_32(&card->config, EMU_INTE, EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE); if (IS_AUDIGY2(&card->config)) { emuxki_reg_write_32(&card->config, EMU_A2_INTE2, 0); if (!IS_AUDIGY2_VALUE(&card->config)) { emuxki_reg_write_32(&card->config, EMU_A2_INTE3, 0); } } PRINT(("installing interrupt : %" B_PRIx32 "\n", card->config.irq)); err = install_io_interrupt_handler(card->config.irq, emuxki_int, card, 0); if (err != B_OK) { PRINT(("failed to install interrupt\n")); emuxki_shutdown(card); return err; } emuxki_inte_enable(&card->config, EMU_INTE_VOLINCRENABLE | EMU_INTE_VOLDECRENABLE | EMU_INTE_MUTEENABLE | EMU_INTE_FXDSPENABLE); if (IS_AUDIGY2(&card->config)) { emuxki_reg_write_32(&card->config, EMU_HCFG, EMU_HCFG_AUDIOENABLE | EMU_HCFG_AC3ENABLE_CDSPDIF | EMU_HCFG_AC3ENABLE_GPSPDIF| EMU_HCFG_JOYENABLE | EMU_HCFG_AUTOMUTE); } else if (IS_AUDIGY(&card->config)) { emuxki_reg_write_32(&card->config, EMU_HCFG, EMU_HCFG_AUDIOENABLE | EMU_HCFG_JOYENABLE | EMU_HCFG_AUTOMUTE); } else { emuxki_reg_write_32(&card->config, EMU_HCFG, EMU_HCFG_AUDIOENABLE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_JOYENABLE | EMU_HCFG_AUTOMUTE); } PRINT(("setup_emuxki done\n")); return err; } void emuxki_dump_fx(emuxki_dev * card) { uint16 pc = 0; uint8 op; uint16 r,a,x,y,zero; LOG(("emuxki_dump_fx\n")); zero = IS_AUDIGY(&card->config) ? EMU_A_DSP_CST(0) : EMU_DSP_CST(0); while (pc < 512) { emuxki_dsp_getop(&card->config, &pc, &op, &r, &a, &x, &y); if (op!=EMU_DSP_OP_ACC3 || r!=zero || a!=zero || x!=zero || y!=zero) { LOG(("dsp_op pc=%u, op=%x, r=%x, a=%x, x=%x, y=%x\n", pc, op, r, a, x, y)); } } } static void emuxki_initfx(emuxki_dev * card) { uint16 pc, gpr; emuxki_gpr *a_front_gpr, *a_rear_gpr, *a_center_sub_gpr = NULL; emuxki_gpr *p_ac97_in_gpr, *p_cd_in_gpr, *r_ac97_in_gpr, *r_cd_in_gpr, *r_fx_out_gpr; emuxki_gpr *d_front_gpr, *d_rear_gpr, *d_center_sub_gpr; /* Set all GPRs to 0 */ for (pc = 0; pc < 256; pc++) { emuxki_write_gpr(&card->config, pc, 0); card->gpr[pc].gpr = -1; } for (pc = 0; pc < 160; pc++) { emuxki_chan_write(&card->config, 0, EMU_TANKMEMDATAREGBASE + pc, 0); emuxki_chan_write(&card->config, 0, EMU_TANKMEMADDRREGBASE + pc, 0); } pc = 0; gpr = EMU_GPR_FIRST_MIX; // we reserve 16 gprs for processing #define EMU_DSP_TMPGPR_FRONT_LEFT 0 #define EMU_DSP_TMPGPR_FRONT_RIGHT 1 #define EMU_DSP_TMPGPR_REAR_LEFT 2 #define EMU_DSP_TMPGPR_REAR_RIGHT 3 #define EMU_DSP_TMPGPR_CENTER 4 #define EMU_DSP_TMPGPR_SUB 5 #define EMU_DSP_TMPGPR_DSP_IN_L 6 #define EMU_DSP_TMPGPR_DSP_IN_R 7 a_front_gpr = emuxki_gpr_new(card, "Analog Front", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); a_rear_gpr = emuxki_gpr_new(card, "Analog Rear", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); if (IS_AUDIGY(&card->config) || IS_LIVE_5_1(&card->config)) a_center_sub_gpr = emuxki_gpr_new(card, "Analog Center/Sub", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); d_front_gpr = emuxki_gpr_new(card, "Digital Front", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); d_rear_gpr = emuxki_gpr_new(card, "Digital Rear", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); d_center_sub_gpr = emuxki_gpr_new(card, "Digital Center/Sub", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); /* playback in gprs */ p_ac97_in_gpr = emuxki_gpr_new(card, "AC97 Record In", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 1.0, -46.5, 0.0, -0.75); p_cd_in_gpr = emuxki_gpr_new(card, "CD Spdif In", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_PLAYBACK, &gpr, 0.0, 1.0, -46.5, 0.0, -0.75); /* record in gprs */ r_ac97_in_gpr = emuxki_gpr_new(card, "AC97 Record In", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_RECORD, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); r_cd_in_gpr = emuxki_gpr_new(card, "CD Spdif In", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_RECORD, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); r_fx_out_gpr = emuxki_gpr_new(card, "FX 0/1", EMU_MIX_GAIN|EMU_MIX_STEREO|EMU_MIX_MUTE|EMU_MIX_RECORD, &gpr, 0.0, 0.0, -46.5, 0.0, -0.75); card->gpr_count = gpr; if (IS_AUDIGY(&card->config)) { /* DSP_IN_GPR(l/r) = 0 + AC97In(l/r) * P_AC97_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_CST(0), EMU_A_DSP_INL(EMU_DSP_IN_AC97), EMU_A_DSP_GPR(p_ac97_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_CST(0), EMU_A_DSP_INR(EMU_DSP_IN_AC97), EMU_A_DSP_GPR(p_ac97_in_gpr->gpr + 1)); /* DSP_IN_GPR(l/r) = DSP_IN_GPR(l/r) + CDIn(l/r) * P_CD_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_INL(EMU_DSP_IN_CDSPDIF), EMU_A_DSP_GPR(p_cd_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_INR(EMU_DSP_IN_CDSPDIF), EMU_A_DSP_GPR(p_cd_in_gpr->gpr + 1)); /* Front GPR(l/r) = DSP_IN_GPR(l/r) + FX(0/1) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_FRONT_LEFT), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_FX(0), EMU_A_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_FRONT_RIGHT), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_FX(1), EMU_A_DSP_CST(4)); /* Rear GPR(l/r) = DSP_IN_GPR(l/r) + FX(2/3) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_REAR_LEFT), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_FX(2), EMU_A_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_REAR_RIGHT), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_FX(3), EMU_A_DSP_CST(4)); /* Center/Sub GPR = 0 + FX(4/5) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_CENTER), EMU_A_DSP_CST(0), EMU_DSP_FX(4), EMU_A_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_SUB), EMU_A_DSP_CST(0), EMU_DSP_FX(5), EMU_A_DSP_CST(4)); /* Analog Front Output l/r = 0 + Front GPR(l/r) * A_FRONT_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_FRONT), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_FRONT_LEFT), EMU_A_DSP_GPR(a_front_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_FRONT), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_FRONT_RIGHT), EMU_A_DSP_GPR(a_front_gpr->gpr+1)); /* Analog Rear Output l/r = 0 + Rear GPR(l/r) * A_REAR_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_REAR), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_REAR_LEFT), EMU_A_DSP_GPR(a_rear_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_REAR), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_REAR_RIGHT), EMU_A_DSP_GPR(a_rear_gpr->gpr+1)); /* Analog Center/Sub = 0 + Center/Sub GPR(l/r) * A_CENTER_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_CENTER), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_CENTER), EMU_A_DSP_GPR(a_center_sub_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_CENTER), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_SUB), EMU_A_DSP_GPR(a_center_sub_gpr->gpr+1)); /* Digital Front Output l/r = 0 + Front GPR(l/r) * D_FRONT_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTL(EMU_A_DSP_OUT_D_FRONT), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_FRONT_LEFT), EMU_A_DSP_GPR(d_front_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTR(EMU_A_DSP_OUT_D_FRONT), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_FRONT_RIGHT), EMU_A_DSP_GPR(d_front_gpr->gpr+1)); /* Digital Rear Output l/r = 0 + Rear GPR(l/r) * D_REAR_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTL(EMU_A_DSP_OUT_D_REAR), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_REAR_LEFT), EMU_A_DSP_GPR(d_rear_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTR(EMU_A_DSP_OUT_D_REAR), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_REAR_RIGHT), EMU_A_DSP_GPR(d_rear_gpr->gpr+1)); /* Digital Center/Sub = 0 + Center/Sub GPR(l/r) * D_CENTER_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTL(EMU_A_DSP_OUT_D_CENTER), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_CENTER), EMU_A_DSP_GPR(d_center_sub_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTR(EMU_A_DSP_OUT_D_CENTER), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_SUB), EMU_A_DSP_GPR(d_center_sub_gpr->gpr+1)); /* DSP_IN_GPR(l/r) = 0 + AC97In(l/r) * R_AC97_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_CST(0), EMU_A_DSP_INL(EMU_DSP_IN_AC97), EMU_A_DSP_GPR(r_ac97_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_CST(0), EMU_A_DSP_INR(EMU_DSP_IN_AC97), EMU_A_DSP_GPR(r_ac97_in_gpr->gpr + 1)); /* DSP_IN_GPR (l/r) = DSP_IN_GPR(l/r) + FX(0/1) * R_FX_OUT_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_FX(0), EMU_A_DSP_GPR(r_fx_out_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_FX(1), EMU_A_DSP_GPR(r_fx_out_gpr->gpr + 1)); /* DSP_IN_GPR(l/r) = 0 + DSP_IN_GPR(l/r) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_CST(0), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_CST(4)); /* ADC recording buffer (l/r) = DSP_IN_GPR(l/r) + CDIn(l/r) * R_CD_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTL(EMU_A_DSP_OUT_ADC), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_A_DSP_INL(EMU_DSP_IN_CDSPDIF), EMU_A_DSP_GPR(r_cd_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_A_DSP_OUTR(EMU_A_DSP_OUT_ADC), EMU_A_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_A_DSP_INR(EMU_DSP_IN_CDSPDIF), EMU_A_DSP_GPR(r_cd_in_gpr->gpr + 1)); /* zero out the rest of the microcode */ while (pc < 512) emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_ACC3, EMU_A_DSP_CST(0), EMU_A_DSP_CST(0), EMU_A_DSP_CST(0), EMU_A_DSP_CST(0)); emuxki_chan_write(&card->config, 0, EMU_A_DBG, 0); /* Is it really necessary ? */ } else { /* DSP_IN_GPR(l/r) = 0 + AC97In(l/r) * P_AC97_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_CST(0), EMU_DSP_INL(EMU_DSP_IN_AC97), EMU_DSP_GPR(p_ac97_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_CST(0), EMU_DSP_INR(EMU_DSP_IN_AC97), EMU_DSP_GPR(p_ac97_in_gpr->gpr + 1)); /* DSP_IN_GPR(l/r) = DSP_IN_GPR(l/r) + CDIn(l/r) * P_CD_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_INL(EMU_DSP_IN_CDSPDIF), EMU_DSP_GPR(p_cd_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_INR(EMU_DSP_IN_CDSPDIF), EMU_DSP_GPR(p_cd_in_gpr->gpr + 1)); /* Front GPR(l/r) = DSP_IN_GPR(l/r) + FX(0/1) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_FRONT_LEFT), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_FX(0), EMU_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_FRONT_RIGHT), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_FX(1), EMU_DSP_CST(4)); /* Rear GPR(l/r) = DSP_IN_GPR(l/r) + FX(2/3) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_REAR_LEFT), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_FX(2), EMU_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_REAR_RIGHT), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_FX(3), EMU_DSP_CST(4)); /* Center/Sub GPR = 0 + FX(4/5) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_CENTER), EMU_DSP_CST(0), EMU_DSP_FX(4), EMU_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_SUB), EMU_DSP_CST(0), EMU_DSP_FX(5), EMU_DSP_CST(4)); /* Analog Front Output l/r = 0 + Front GPR(l/r) * A_FRONT_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTL(EMU_DSP_OUT_A_FRONT), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_FRONT_LEFT), EMU_DSP_GPR(a_front_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTR(EMU_DSP_OUT_A_FRONT), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_FRONT_RIGHT), EMU_DSP_GPR(a_front_gpr->gpr+1)); /* Analog Rear Output l/r = 0 + Rear GPR(l/r) * A_REAR_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTL(EMU_DSP_OUT_AD_REAR), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_REAR_LEFT), EMU_DSP_GPR(a_rear_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTR(EMU_DSP_OUT_AD_REAR), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_REAR_RIGHT), EMU_DSP_GPR(a_rear_gpr->gpr+1)); /* Analog Center/Sub = 0 + Center/Sub GPR(l/r) * A_CENTER_GPR(l/r) */ if (IS_LIVE_5_1(&card->config)) { emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUT_A_CENTER, EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_CENTER), EMU_DSP_GPR(a_center_sub_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUT_A_SUB, EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_SUB), EMU_DSP_GPR(a_center_sub_gpr->gpr+1)); } /* Digital Front Output l/r = 0 + Front GPR(l/r) * D_FRONT_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTL(EMU_DSP_OUT_D_FRONT), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_FRONT_LEFT), EMU_DSP_GPR(d_front_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTR(EMU_DSP_OUT_D_FRONT), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_FRONT_RIGHT), EMU_DSP_GPR(d_front_gpr->gpr+1)); /* Digital Rear Output l/r = 0 + Rear GPR(l/r) * D_REAR_GPR(l/r) */ /*emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTL(EMU_DSP_OUT_D_REAR), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_REAR_LEFT), EMU_DSP_GPR(d_rear_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTR(EMU_DSP_OUT_D_REAR), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_REAR_RIGHT), EMU_DSP_GPR(d_rear_gpr->gpr+1));*/ /* Digital Center/Sub = 0 + Center/Sub GPR(l/r) * D_CENTER_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTL(EMU_DSP_OUT_D_CENTER), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_CENTER), EMU_DSP_GPR(d_center_sub_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTR(EMU_DSP_OUT_D_CENTER), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_SUB), EMU_DSP_GPR(d_center_sub_gpr->gpr+1)); /* DSP_IN_GPR(l/r) = 0 + AC97In(l/r) * R_AC97_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_CST(0), EMU_DSP_INL(EMU_DSP_IN_AC97), EMU_DSP_GPR(r_ac97_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_CST(0), EMU_DSP_INR(EMU_DSP_IN_AC97), EMU_DSP_GPR(r_ac97_in_gpr->gpr + 1)); /* DSP_IN_GPR (l/r) = DSP_IN_GPR(l/r) + FX(0/1) * R_FX_OUT_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_FX(0), EMU_DSP_GPR(r_fx_out_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_FX(1), EMU_DSP_GPR(r_fx_out_gpr->gpr + 1)); /* DSP_IN_GPR(l/r) = 0 + DSP_IN_GPR(l/r) * 4 */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_CST(4)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACINTS, EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_CST(0), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_CST(4)); /* ADC recording buffer (l/r) = DSP_IN_GPR(l/r) + CDIn(l/r) * R_CD_IN_GPR(l/r) */ emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTL(EMU_DSP_OUT_ADC), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_L), EMU_DSP_INL(EMU_DSP_IN_CDSPDIF), EMU_DSP_GPR(r_cd_in_gpr->gpr)); emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_MACS, EMU_DSP_OUTR(EMU_DSP_OUT_ADC), EMU_DSP_GPR(EMU_DSP_TMPGPR_DSP_IN_R), EMU_DSP_INR(EMU_DSP_IN_CDSPDIF), EMU_DSP_GPR(r_cd_in_gpr->gpr + 1)); /* zero out the rest of the microcode */ while (pc < 512) emuxki_dsp_addop(&card->config, &pc, EMU_DSP_OP_ACC3, EMU_DSP_CST(0), EMU_DSP_CST(0), EMU_DSP_CST(0), EMU_DSP_CST(0)); emuxki_chan_write(&card->config, 0, EMU_DBG, 0); /* Is it really necessary ? */ } emuxki_dump_fx(card); } status_t emuxki_init(emuxki_dev * card) { uint16 i; uint32 spcs, *ptb; uint32 silentpage; /* disable any channel interrupt */ emuxki_chan_write(&card->config, 0, EMU_CLIEL, 0); emuxki_chan_write(&card->config, 0, EMU_CLIEH, 0); emuxki_chan_write(&card->config, 0, EMU_SOLEL, 0); emuxki_chan_write(&card->config, 0, EMU_SOLEH, 0); /* Set recording buffers sizes to zero */ emuxki_chan_write(&card->config, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE); emuxki_chan_write(&card->config, 0, EMU_MICBA, 0); emuxki_chan_write(&card->config, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE); emuxki_chan_write(&card->config, 0, EMU_FXBA, 0); emuxki_chan_write(&card->config, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE); emuxki_chan_write(&card->config, 0, EMU_ADCBA, 0); if (IS_AUDIGY(&card->config)) { emuxki_chan_write(&card->config, 0, EMU_SPBYPASS, EMU_SPBYPASS_24_BITS); emuxki_chan_write(&card->config, 0, EMU_AC97SLOT, EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE); } /* Initialize all channels to stopped and no effects */ for (i = 0; i < EMU_NUMCHAN; i++) { emuxki_chan_write(&card->config, i, EMU_CHAN_DCYSUSV, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_IP, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_VTFT, 0xffff); emuxki_chan_write(&card->config, i, EMU_CHAN_CVCF, 0xffff); emuxki_chan_write(&card->config, i, EMU_CHAN_PTRX, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_CPF, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_CCR, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_PSST, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_DSL, 0x10); /* Why 16 ? */ emuxki_chan_write(&card->config, i, EMU_CHAN_CCCA, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_Z1, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_Z2, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_FXRT, 0x32100000); emuxki_chan_write(&card->config, i, EMU_CHAN_ATKHLDM, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_DCYSUSM, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_IFATN, 0xffff); emuxki_chan_write(&card->config, i, EMU_CHAN_PEFE, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_FMMOD, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_TREMFRQ, 24); emuxki_chan_write(&card->config, i, EMU_CHAN_FM2FRQ2, 24); emuxki_chan_write(&card->config, i, EMU_CHAN_TEMPENV, 0); /*** these are last so OFF prevents writing ***/ emuxki_chan_write(&card->config, i, EMU_CHAN_LFOVAL2, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_LFOVAL1, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_ATKHLDV, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_ENVVOL, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_ENVVAL, 0); } /* set digital outputs format */ spcs = (EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 | EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC | EMU_SPCS_GENERATIONSTATUS | 0x00001200 /* Cat code. */ | 0x00000000 /* IEC-958 Mode */ | EMU_SPCS_EMPHASIS_NONE | EMU_SPCS_COPYRIGHT); emuxki_chan_write(&card->config, 0, EMU_SPCS0, spcs); emuxki_chan_write(&card->config, 0, EMU_SPCS1, spcs); emuxki_chan_write(&card->config, 0, EMU_SPCS2, spcs); if (IS_AUDIGY2(&card->config)) { emuxki_chan_write(&card->config, 0, EMU_A2_SPDIF_SAMPLERATE, EMU_A2_SPDIF_UNKNOWN); emuxki_p16v_write(&card->config, 0, EMU_A2_SRCSEL, EMU_A2_SRCSEL_ENABLE_SPDIF | EMU_A2_SRCSEL_ENABLE_SRCMULTI); if (IS_AUDIGY2_VALUE(&card->config)) { emuxki_p16v_write(&card->config, 0, EMU_A2_P17V_I2S, EMU_A2_P17V_I2S_ENABLE); emuxki_p16v_write(&card->config, 0, EMU_A2_P17V_SPDIF, EMU_A2_P17V_SPDIF_ENABLE); emuxki_reg_write_32(&card->config, EMU_A_IOCFG, emuxki_reg_read_32(&card->config, EMU_A_IOCFG) & ~0x8); } else { emuxki_p16v_write(&card->config, 0, EMU_A2_SRCMULTI, EMU_A2_SRCMULTI_ENABLE_INPUT); } } /* Let's play with sound processor */ emuxki_initfx(card); /* allocate memory for our Page Table */ card->ptb_area = alloc_mem(&card->ptb_phy_base, &card->ptb_log_base, EMU_MAXPTE * sizeof(uint32), "emuxki ptb", false); /* This is necessary unless you like Metallic noise... */ card->silentpage_area = alloc_mem(&card->silentpage_phy_base, &card->silentpage_log_base, EMU_PTESIZE, "emuxki sp", false); if (card->ptb_area < B_OK || card->silentpage_area < B_OK) { PRINT(("couldn't allocate memory\n")); if (card->ptb_area > B_OK) delete_area(card->ptb_area); if (card->silentpage_area > B_OK) delete_area(card->silentpage_area); return B_ERROR; } /* Zero out the silent page */ /* This might not be always true, it might be 128 for 8bit channels */ memset(card->ptb_log_base, 0, EMU_PTESIZE); /* * Set all the PTB Entries to the silent page We shift the physical * address by one and OR it with the page number. I don't know what * the ORed index is for, might be a very useful unused feature... */ silentpage = ((uint32)card->silentpage_phy_base) << 1; ptb = card->ptb_log_base; for (i = 0; i < EMU_MAXPTE; i++) ptb[i] = B_HOST_TO_LENDIAN_INT32(silentpage | i); /* Write PTB address and set TCB to none */ emuxki_chan_write(&card->config, 0, EMU_PTB, (uint32)card->ptb_phy_base); emuxki_chan_write(&card->config, 0, EMU_TCBS, 0); /* This means 16K TCB */ emuxki_chan_write(&card->config, 0, EMU_TCB, 0); /* No TCB use for now */ /* * Set channels MAPs to the silent page. * I don't know what MAPs are for. */ silentpage |= EMU_CHAN_MAP_PTI_MASK; for (i = 0; i < EMU_NUMCHAN; i++) { emuxki_chan_write(&card->config, i, EMU_CHAN_MAPA, silentpage); emuxki_chan_write(&card->config, i, EMU_CHAN_MAPB, silentpage); card->channel[i] = NULL; } /* Init streams list */ LIST_INIT(&(card->streams)); /* Init mems list */ LIST_INIT(&(card->mem)); /* Timer is stopped */ card->timerstate &= ~EMU_TIMER_STATE_ENABLED; card->timerate = 0xffff; return B_OK; } status_t init_driver(void) { void *settings_handle; pci_info info; status_t err; int ix = 0; num_cards = 0; PRINT(("init_driver()\n")); // get driver settings settings_handle = load_driver_settings("emuxki.settings"); if (settings_handle != NULL) { const char *item; char *end; uint32 value; item = get_driver_parameter (settings_handle, "channels", NULL, NULL); if (item) { value = strtoul (item, &end, 0); if (*end == '\0') current_settings.channels = value; } item = get_driver_parameter (settings_handle, "bitsPerSample", NULL, NULL); if (item) { value = strtoul (item, &end, 0); if (*end == '\0') current_settings.bitsPerSample = value; } item = get_driver_parameter (settings_handle, "sample_rate", NULL, NULL); if (item) { value = strtoul (item, &end, 0); if (*end == '\0') current_settings.sample_rate = value; } item = get_driver_parameter (settings_handle, "buffer_frames", NULL, NULL); if (item) { value = strtoul (item, &end, 0); if (*end == '\0') current_settings.buffer_frames = value; } item = get_driver_parameter (settings_handle, "buffer_count", NULL, NULL); if (item) { value = strtoul (item, &end, 0); if (*end == '\0') current_settings.buffer_count = value; } unload_driver_settings (settings_handle); } if (get_module(B_PCI_MODULE_NAME, (module_info **) &pci)) return ENOSYS; // if (get_module (gameport_name, (module_info **)&gameport)) { // put_module (B_PCI_MODULE_NAME); // return ENOSYS; // } if (get_module(B_MPU_401_MODULE_NAME, (module_info **) &mpu401)) { //put_module(gameport_name); put_module(B_PCI_MODULE_NAME); return ENOSYS; } while ((*pci->get_nth_pci_info)(ix++, &info) == B_OK) { if (info.vendor_id == CREATIVELABS_VENDOR_ID && (info.device_id == CREATIVELABS_SBLIVE_DEVICE_ID #if AUDIGY || info.device_id == CREATIVELABS_AUDIGY_DEVICE_ID || info.device_id == CREATIVELABS_AUDIGY2_VALUE_DEVICE_ID #endif )) { if (num_cards == NUM_CARDS) { PRINT(("Too many emuxki cards installed!\n")); break; } memset(&cards[num_cards], 0, sizeof(emuxki_dev)); cards[num_cards].info = info; #ifdef __HAIKU__ if ((err = (*pci->reserve_device)(info.bus, info.device, info.function, DRIVER_NAME, &cards[num_cards])) < B_OK) { dprintf("%s: failed to reserve_device(%d, %d, %d,): %s\n", DRIVER_NAME, info.bus, info.device, info.function, strerror(err)); continue; } #endif if (emuxki_setup(&cards[num_cards])) { PRINT(("Setup of emuxki %" B_PRId32 " failed\n", num_cards + 1)); #ifdef __HAIKU__ (*pci->unreserve_device)(info.bus, info.device, info.function, DRIVER_NAME, &cards[num_cards]); #endif } else { num_cards++; } } } if (!num_cards) { put_module(B_MPU_401_MODULE_NAME); // put_module(gameport_name); put_module(B_PCI_MODULE_NAME); PRINT(("emuxki: no suitable cards found\n")); return ENODEV; } return B_OK; } void emuxki_shutdown(emuxki_dev *card) { uint32 i; PRINT(("shutdown(%p)\n", card)); emuxki_reg_write_32(&card->config, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE); emuxki_reg_write_32(&card->config, EMU_INTE, 0); dump_hardware_regs(&card->config); /* Disable any Channels interrupts */ emuxki_chan_write(&card->config, 0, EMU_CLIEL, 0); emuxki_chan_write(&card->config, 0, EMU_CLIEH, 0); emuxki_chan_write(&card->config, 0, EMU_SOLEL, 0); emuxki_chan_write(&card->config, 0, EMU_SOLEH, 0); /* Stop all channels */ /* This shouldn't be necessary, i'll remove once everything works */ for (i = 0; i < EMU_NUMCHAN; i++) emuxki_chan_write(&card->config, i, EMU_CHAN_DCYSUSV, 0); for (i = 0; i < EMU_NUMCHAN; i++) { emuxki_chan_write(&card->config, i, EMU_CHAN_VTFT, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_CVCF, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_PTRX, 0); emuxki_chan_write(&card->config, i, EMU_CHAN_CPF, 0); } remove_io_interrupt_handler(card->config.irq, emuxki_int, card); /* * deallocate Emu10k1 caches and recording buffers Again it will be * removed because it will be done in voice shutdown. */ emuxki_chan_write(&card->config, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE); emuxki_chan_write(&card->config, 0, EMU_MICBA, 0); emuxki_chan_write(&card->config, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE); emuxki_chan_write(&card->config, 0, EMU_FXBA, 0); if (IS_AUDIGY(&card->config)) { emuxki_chan_write(&card->config, 0, EMU_A_FXWC1, 0); emuxki_chan_write(&card->config, 0, EMU_A_FXWC2, 0); } else { emuxki_chan_write(&card->config, 0, EMU_FXWC, 0); } emuxki_chan_write(&card->config, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE); emuxki_chan_write(&card->config, 0, EMU_ADCBA, 0); /* * I don't know yet how i will handle tank cache buffer, * I don't even clearly know what it is for */ emuxki_chan_write(&card->config, 0, EMU_TCB, 0); /* 16K again */ emuxki_chan_write(&card->config, 0, EMU_TCBS, 0); emuxki_chan_write(&card->config, 0, EMU_DBG, 0x8000); /* necessary ? */ PRINT(("freeing ptb_area\n")); if (card->ptb_area > B_OK) delete_area(card->ptb_area); PRINT(("freeing silentpage_area\n")); if (card->silentpage_area > B_OK) delete_area(card->silentpage_area); // (*gameport->delete_device)(card->joy.driver); } void uninit_driver(void) { int ix, cnt = num_cards; PRINT(("uninit_driver()\n")); for (ix=0; ixunreserve_device)(cards[ix].info.bus, cards[ix].info.device, cards[ix].info.function, DRIVER_NAME, &cards[ix]); #endif } memset(&cards, 0, sizeof(cards)); put_module(B_MPU_401_MODULE_NAME); // put_module(gameport_name); put_module(B_PCI_MODULE_NAME); num_cards = 0; } const char ** publish_devices(void) { int ix = 0; PRINT(("publish_devices()\n")); for (ix=0; names[ix]; ix++) { PRINT(("publish %s\n", names[ix])); } return (const char **)names; } device_hooks * find_device(const char * name) { int ix; PRINT(("emuxki: find_device(%s)\n", name)); for (ix=0; ix