freebsd-skq/sys/dev/sound/pci/emu10kx.c

3570 lines
99 KiB
C
Raw Normal View History

/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
* Copyright (c) 2003-2007 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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, WHETHERIN 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.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <sys/sbuf.h>
#include <sys/queue.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/kdb.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <machine/clock.h> /* for DELAY */
Sound Mega-commit. Expect further cleanup until code freeze. For a slightly thorough explaination, please refer to [1] http://people.freebsd.org/~ariff/SOUND_4.TXT.html . Summary of changes includes: 1 Volume Per-Channel (vpc). Provides private / standalone volume control unique per-stream pcm channel without touching master volume / pcm. Applications can directly use SNDCTL_DSP_[GET|SET][PLAY|REC]VOL, or for backwards compatibility, SOUND_MIXER_PCM through the opened dsp device instead of /dev/mixer. Special "bypass" mode is enabled through /dev/mixer which will automatically detect if the adjustment is made through /dev/mixer and forward its request to this private volume controller. Changes to this volume object will not interfere with other channels. Requirements: - SNDCTL_DSP_[GET|SET][PLAY|REC]_VOL are newer ioctls (OSSv4) which require specific application modifications (preferred). - No modifications required for using bypass mode, so applications like mplayer or xmms should work out of the box. Kernel hints: - hint.pcm.%d.vpc (0 = disable vpc). Kernel sysctls: - hw.snd.vpc_mixer_bypass (default: 1). Enable or disable /dev/mixer bypass mode. - hw.snd.vpc_autoreset (default: 1). By default, closing/opening /dev/dsp will reset the volume back to 0 db gain/attenuation. Setting this to 0 will preserve its settings across device closing/opening. - hw.snd.vpc_reset (default: 0). Panic/reset button to reset all volume settings back to 0 db. - hw.snd.vpc_0db (default: 45). 0 db relative to linear mixer value. 2 High quality fixed-point Bandlimited SINC sampling rate converter, based on Julius O'Smith's Digital Audio Resampling - http://ccrma.stanford.edu/~jos/resample/. It includes a filter design script written in awk (the clumsiest joke I've ever written) - 100% 32bit fixed-point, 64bit accumulator. - Possibly among the fastest (if not fastest) of its kind. - Resampling quality is tunable, either runtime or during kernel compilation (FEEDER_RATE_PRESETS). - Quality can be further customized during kernel compilation by defining FEEDER_RATE_PRESETS in /etc/make.conf. Kernel sysctls: - hw.snd.feeder_rate_quality. 0 - Zero-order Hold (ZOH). Fastest, bad quality. 1 - Linear Interpolation (LINEAR). Slightly slower than ZOH, better quality but still does not eliminate aliasing. 2 - (and above) - Sinc Interpolation(SINC). Best quality. SINC quality always start from 2 and above. Rough quality comparisons: - http://people.freebsd.org/~ariff/z_comparison/ 3 Bit-perfect mode. Bypasses all feeder/dsp effects. Pure sound will be directly fed into the hardware. 4 Parametric (compile time) Software Equalizer (Bass/Treble mixer). Can be customized by defining FEEDER_EQ_PRESETS in /etc/make.conf. 5 Transparent/Adaptive Virtual Channel. Now you don't have to disable vchans in order to make digital format pass through. It also makes vchans more dynamic by choosing a better format/rate among all the concurrent streams, which means that dev.pcm.X.play.vchanformat/rate becomes sort of optional. 6 Exclusive Stream, with special open() mode O_EXCL. This will "mute" other concurrent vchan streams and only allow a single channel with O_EXCL set to keep producing sound. Other Changes: * most feeder_* stuffs are compilable in userland. Let's not speculate whether we should go all out for it (save that for FreeBSD 16.0-RELEASE). * kobj signature fixups, thanks to Andriy Gapon <avg@freebsd.org> * pull out channel mixing logic out of vchan.c and create its own feeder_mixer for world justice. * various refactoring here and there, for good or bad. * activation of few more OSSv4 ioctls() (see [1] above). * opt_snd.h for possible compile time configuration: (mostly for debugging purposes, don't try these at home) SND_DEBUG SND_DIAGNOSTIC SND_FEEDER_MULTIFORMAT SND_FEEDER_FULL_MULTIFORMAT SND_FEEDER_RATE_HP SND_PCM_64 SND_OLDSTEREO Manual page updates are on the way. Tested by: joel, Olivier SMEDTS <olivier at gid0 d org>, too many unsung / unnamed heroes.
2009-06-07 19:12:08 +00:00
#ifdef HAVE_KERNEL_OPTION_HEADERS
#include "opt_snd.h"
#endif
#include <dev/sound/chip.h>
#include <dev/sound/pcm/sound.h>
#include <dev/sound/pcm/ac97.h>
#include <dev/sound/pci/emuxkireg.h>
#include <dev/sound/pci/emu10kx.h>
/* hw flags */
#define HAS_51 0x0001
#define HAS_71 0x0002
#define HAS_AC97 0x0004
#define IS_EMU10K1 0x0008
#define IS_EMU10K2 0x0010
#define IS_CA0102 0x0020
#define IS_CA0108 0x0040
#define IS_UNKNOWN 0x0080
#define BROKEN_DIGITAL 0x0100
#define DIGITAL_ONLY 0x0200
#define IS_CARDBUS 0x0400
#define MODE_ANALOG 1
#define MODE_DIGITAL 2
#define SPDIF_MODE_PCM 1
#define SPDIF_MODE_AC3 2
#define MACS 0x0
#define MACS1 0x1
#define MACW 0x2
#define MACW1 0x3
#define MACINTS 0x4
#define MACINTW 0x5
#define ACC3 0x6
#define MACMV 0x7
#define ANDXOR 0x8
#define TSTNEG 0x9
#define LIMIT 0xA
#define LIMIT1 0xB
#define LOG 0xC
#define EXP 0xD
#define INTERP 0xE
#define SKIP 0xF
#define GPR(i) (sc->gpr_base+(i))
#define INP(i) (sc->input_base+(i))
#define OUTP(i) (sc->output_base+(i))
#define FX(i) (i)
#define FX2(i) (sc->efxc_base+(i))
#define DSP_CONST(i) (sc->dsp_zero+(i))
#define COND_NORMALIZED DSP_CONST(0x1)
#define COND_BORROW DSP_CONST(0x2)
#define COND_MINUS DSP_CONST(0x3)
#define COND_LESS_ZERO DSP_CONST(0x4)
#define COND_EQ_ZERO DSP_CONST(0x5)
#define COND_SATURATION DSP_CONST(0x6)
#define COND_NEQ_ZERO DSP_CONST(0x8)
#define DSP_ACCUM DSP_CONST(0x16)
#define DSP_CCR DSP_CONST(0x17)
/* Live! Inputs */
#define IN_AC97_L 0x00
#define IN_AC97_R 0x01
#define IN_AC97 IN_AC97_L
#define IN_SPDIF_CD_L 0x02
#define IN_SPDIF_CD_R 0x03
#define IN_SPDIF_CD IN_SPDIF_CD_L
#define IN_ZOOM_L 0x04
#define IN_ZOOM_R 0x05
#define IN_ZOOM IN_ZOOM_L
#define IN_TOSLINK_L 0x06
#define IN_TOSLINK_R 0x07
#define IN_TOSLINK IN_TOSLINK_L
#define IN_LINE1_L 0x08
#define IN_LINE1_R 0x09
#define IN_LINE1 IN_LINE1_L
#define IN_COAX_SPDIF_L 0x0a
#define IN_COAX_SPDIF_R 0x0b
#define IN_COAX_SPDIF IN_COAX_SPDIF_L
#define IN_LINE2_L 0x0c
#define IN_LINE2_R 0x0d
#define IN_LINE2 IN_LINE2_L
#define IN_0E 0x0e
#define IN_0F 0x0f
/* Outputs */
#define OUT_AC97_L 0x00
#define OUT_AC97_R 0x01
#define OUT_AC97 OUT_AC97_L
#define OUT_A_FRONT OUT_AC97
#define OUT_TOSLINK_L 0x02
#define OUT_TOSLINK_R 0x03
#define OUT_TOSLINK OUT_TOSLINK_L
#define OUT_D_CENTER 0x04
#define OUT_D_SUB 0x05
#define OUT_HEADPHONE_L 0x06
#define OUT_HEADPHONE_R 0x07
#define OUT_HEADPHONE OUT_HEADPHONE_L
#define OUT_REAR_L 0x08
#define OUT_REAR_R 0x09
#define OUT_REAR OUT_REAR_L
#define OUT_ADC_REC_L 0x0a
#define OUT_ADC_REC_R 0x0b
#define OUT_ADC_REC OUT_ADC_REC_L
#define OUT_MIC_CAP 0x0c
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
2012-01-15 13:36:47 +00:00
/* Live! 5.1 Digital, non-standard 5.1 (center & sub) outputs */
#define OUT_A_CENTER 0x11
#define OUT_A_SUB 0x12
/* Audigy Inputs */
#define A_IN_AC97_L 0x00
#define A_IN_AC97_R 0x01
#define A_IN_AC97 A_IN_AC97_L
#define A_IN_SPDIF_CD_L 0x02
#define A_IN_SPDIF_CD_R 0x03
#define A_IN_SPDIF_CD A_IN_SPDIF_CD_L
#define A_IN_O_SPDIF_L 0x04
#define A_IN_O_SPDIF_R 0x05
#define A_IN_O_SPDIF A_IN_O_SPDIF_L
#define A_IN_LINE2_L 0x08
#define A_IN_LINE2_R 0x09
#define A_IN_LINE2 A_IN_LINE2_L
#define A_IN_R_SPDIF_L 0x0a
#define A_IN_R_SPDIF_R 0x0b
#define A_IN_R_SPDIF A_IN_R_SPDIF_L
#define A_IN_AUX2_L 0x0c
#define A_IN_AUX2_R 0x0d
#define A_IN_AUX2 A_IN_AUX2_L
/* Audigy Outputs */
#define A_OUT_D_FRONT_L 0x00
#define A_OUT_D_FRONT_R 0x01
#define A_OUT_D_FRONT A_OUT_D_FRONT_L
#define A_OUT_D_CENTER 0x02
#define A_OUT_D_SUB 0x03
#define A_OUT_D_SIDE_L 0x04
#define A_OUT_D_SIDE_R 0x05
#define A_OUT_D_SIDE A_OUT_D_SIDE_L
#define A_OUT_D_REAR_L 0x06
#define A_OUT_D_REAR_R 0x07
#define A_OUT_D_REAR A_OUT_D_REAR_L
/* on Audigy Platinum only */
#define A_OUT_HPHONE_L 0x04
#define A_OUT_HPHONE_R 0x05
#define A_OUT_HPHONE A_OUT_HPHONE_L
#define A_OUT_A_FRONT_L 0x08
#define A_OUT_A_FRONT_R 0x09
#define A_OUT_A_FRONT A_OUT_A_FRONT_L
#define A_OUT_A_CENTER 0x0a
#define A_OUT_A_SUB 0x0b
#define A_OUT_A_SIDE_L 0x0c
#define A_OUT_A_SIDE_R 0x0d
#define A_OUT_A_SIDE A_OUT_A_SIDE_L
#define A_OUT_A_REAR_L 0x0e
#define A_OUT_A_REAR_R 0x0f
#define A_OUT_A_REAR A_OUT_A_REAR_L
#define A_OUT_AC97_L 0x10
#define A_OUT_AC97_R 0x11
#define A_OUT_AC97 A_OUT_AC97_L
#define A_OUT_ADC_REC_L 0x16
#define A_OUT_ADC_REC_R 0x17
#define A_OUT_ADC_REC A_OUT_ADC_REC_L
#define EMU_DATA2 0x24
#define EMU_IPR2 0x28
#define EMU_INTE2 0x2c
#define EMU_IPR3 0x38
#define EMU_INTE3 0x3c
#define EMU_A2_SRCSel 0x60
#define EMU_A2_SRCMULTI_ENABLE 0x6e
#define EMU_A_I2S_CAPTURE_96000 0x00000400
#define EMU_A2_MIXER_I2S_ENABLE 0x7B
#define EMU_A2_MIXER_SPDIF_ENABLE 0x7A
#define C_FRONT_L 0
#define C_FRONT_R 1
#define C_REC_L 2
#define C_REC_R 3
#define C_REAR_L 4
#define C_REAR_R 5
#define C_CENTER 6
#define C_SUB 7
#define C_SIDE_L 8
#define C_SIDE_R 9
#define NUM_CACHES 10
#define CDSPDIFMUTE 0
#define ANALOGMUTE 1
#define NUM_MUTE 2
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
#define EMU_MAX_GPR 512
#define EMU_MAX_IRQ_CONSUMERS 32
struct emu_voice {
int vnum;
unsigned int b16:1, stereo:1, busy:1, running:1, ismaster:1;
int speed;
int start;
int end;
int vol;
uint32_t buf;
void *vbuf;
struct emu_voice *slave;
uint32_t sa;
uint32_t ea;
uint32_t routing[8];
uint32_t amounts[8];
};
struct emu_memblk {
SLIST_ENTRY(emu_memblk) link;
void *buf;
char owner[16];
bus_addr_t buf_addr;
uint32_t pte_start, pte_size;
bus_dmamap_t buf_map;
};
struct emu_mem {
uint8_t bmap[EMU_MAXPAGES / 8];
uint32_t *ptb_pages;
void *silent_page;
bus_addr_t ptb_pages_addr;
bus_addr_t silent_page_addr;
bus_dmamap_t ptb_map;
bus_dmamap_t silent_map;
bus_dma_tag_t dmat;
struct emu_sc_info *card;
SLIST_HEAD(, emu_memblk) blocks;
};
/* rm */
struct emu_rm {
struct emu_sc_info *card;
struct mtx gpr_lock;
signed int allocmap[EMU_MAX_GPR];
int num_gprs;
int last_free_gpr;
int num_used;
};
struct emu_intr_handler {
void* softc;
uint32_t intr_mask;
uint32_t inte_mask;
uint32_t(*irq_func) (void *softc, uint32_t irq);
};
struct emu_sc_info {
struct mtx lock;
struct mtx rw; /* Hardware exclusive access lock */
/* Hardware and subdevices */
device_t dev;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
device_t pcm[RT_COUNT];
device_t midi[2];
uint32_t type;
uint32_t rev;
bus_space_tag_t st;
bus_space_handle_t sh;
struct cdev *cdev; /* /dev/emu10k character device */
struct mtx emu10kx_lock;
int emu10kx_isopen;
struct sbuf emu10kx_sbuf;
int emu10kx_bufptr;
/* Resources */
struct resource *reg;
struct resource *irq;
void *ih;
/* IRQ handlers */
struct emu_intr_handler ihandler[EMU_MAX_IRQ_CONSUMERS];
/* Card HW configuration */
unsigned int mode; /* analog / digital */
unsigned int mchannel_fx;
unsigned int dsp_zero;
unsigned int code_base;
unsigned int code_size;
unsigned int gpr_base;
unsigned int num_gprs;
unsigned int input_base;
unsigned int output_base;
unsigned int efxc_base;
unsigned int opcode_shift;
unsigned int high_operand_shift;
unsigned int address_mask;
uint32_t is_emu10k1:1, is_emu10k2, is_ca0102, is_ca0108:1,
has_ac97:1, has_51:1, has_71:1,
enable_ir:1,
broken_digital:1, is_cardbus:1;
signed int mch_disabled, mch_rec, dbg_level;
signed int num_inputs;
unsigned int num_outputs;
unsigned int num_fxbuses;
unsigned int routing_code_start;
unsigned int routing_code_end;
/* HW resources */
struct emu_voice voice[NUM_G]; /* Hardware voices */
uint32_t irq_mask[EMU_MAX_IRQ_CONSUMERS]; /* IRQ manager data */
int timer[EMU_MAX_IRQ_CONSUMERS]; /* timer */
int timerinterval;
struct emu_rm *rm;
struct emu_mem mem; /* memory */
/* Mixer */
int mixer_gpr[NUM_MIXERS];
int mixer_volcache[NUM_MIXERS];
int cache_gpr[NUM_CACHES];
int dummy_gpr;
int mute_gpr[NUM_MUTE];
struct sysctl_ctx_list *ctx;
struct sysctl_oid *root;
};
static void emu_setmap(void *arg, bus_dma_segment_t * segs, int nseg, int error);
static void* emu_malloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, bus_dmamap_t *map);
static void emu_free(struct emu_mem *mem, void *dmabuf, bus_dmamap_t map);
static void* emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char * owner);
static int emu_memfree(struct emu_mem *mem, void *membuf);
static int emu_memstart(struct emu_mem *mem, void *membuf);
/* /dev */
static int emu10kx_dev_init(struct emu_sc_info *sc);
static int emu10kx_dev_uninit(struct emu_sc_info *sc);
static int emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s);
static void emumix_set_mode(struct emu_sc_info *sc, int mode);
static void emumix_set_spdif_mode(struct emu_sc_info *sc, int mode);
static void emumix_set_fxvol(struct emu_sc_info *sc, unsigned gpr, int32_t vol);
static void emumix_set_gpr(struct emu_sc_info *sc, unsigned gpr, int32_t val);
static int sysctl_emu_mixer_control(SYSCTL_HANDLER_ARGS);
static int emu_rm_init(struct emu_sc_info *sc);
static int emu_rm_uninit(struct emu_sc_info *sc);
static int emu_rm_gpr_alloc(struct emu_rm *rm, int count);
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
static unsigned int emu_getcard(device_t dev);
static uint32_t emu_rd_nolock(struct emu_sc_info *sc, unsigned int regno, unsigned int size);
static void emu_wr_nolock(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size);
static void emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data);
static void emu_vstop(struct emu_sc_info *sc, char channel, int enable);
static void emu_intr(void *p);
static void emu_wrefx(struct emu_sc_info *sc, unsigned int pc, unsigned int data);
static void emu_addefxop(struct emu_sc_info *sc, unsigned int op, unsigned int z, unsigned int w, unsigned int x, unsigned int y, uint32_t * pc);
static void emu_initefx(struct emu_sc_info *sc);
static int emu_cardbus_init(struct emu_sc_info *sc);
static int emu_init(struct emu_sc_info *sc);
static int emu_uninit(struct emu_sc_info *sc);
static int emu_read_ivar(device_t bus __unused, device_t dev, int ivar_index, uintptr_t * result);
static int emu_write_ivar(device_t bus __unused, device_t dev __unused,
int ivar_index, uintptr_t value __unused);
static int emu_pci_probe(device_t dev);
static int emu_pci_attach(device_t dev);
static int emu_pci_detach(device_t dev);
static int emu_modevent(module_t mod __unused, int cmd, void *data __unused);
#ifdef SND_EMU10KX_DEBUG
#define EMU_MTX_DEBUG() do { \
if (mtx_owned(&sc->rw)) { \
printf("RW owned in %s line %d for %s\n", __func__, \
__LINE__ , device_get_nameunit(sc->dev)); \
printf("rw lock owned: %d\n", mtx_owned(&sc->rw)); \
printf("rw lock: value %x thread %x\n", \
((&sc->rw)->mtx_lock & ~MTX_FLAGMASK), \
(uintptr_t)curthread); \
printf("rw lock: recursed %d\n", mtx_recursed(&sc->rw));\
db_show_mtx(&sc->rw); \
} \
} while (0)
#else
#define EMU_MTX_DEBUG() do { \
} while (0)
#endif
#define EMU_RWLOCK() do { \
EMU_MTX_DEBUG(); \
mtx_lock(&(sc->rw)); \
} while (0)
#define EMU_RWUNLOCK() do { \
mtx_unlock(&(sc->rw)); \
EMU_MTX_DEBUG(); \
} while (0)
/* Supported cards */
struct emu_hwinfo {
uint16_t vendor;
uint16_t device;
uint16_t subvendor;
uint16_t subdevice;
char SBcode[8];
char desc[32];
int flags;
};
static struct emu_hwinfo emu_cards[] = {
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
{0xffff, 0xffff, 0xffff, 0xffff, "BADCRD", "Not a compatible card", 0},
/* 0x0020..0x002f 4.0 EMU10K1 cards */
{0x1102, 0x0002, 0x1102, 0x0020, "CT4850", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x0021, "CT4620", "SBLive!", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x002f, "CT????", "SBLive! mainboard implementation", HAS_AC97 | IS_EMU10K1},
/* (range unknown) 5.1 EMU10K1 cards */
{0x1102, 0x0002, 0x1102, 0x100a, "CT????", "SBLive! 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1},
/* 0x80??..0x805? 4.0 EMU10K1 cards */
{0x1102, 0x0002, 0x1102, 0x8022, "CT4780", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8023, "CT4790", "SB PCI512", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8024, "CT4760", "SBLive!", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8025, "CT????", "SBLive! Mainboard Implementation", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8026, "CT4830", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8027, "CT4832", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8028, "CT4760", "SBLive! OEM version", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8031, "CT4831", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8040, "CT4760", "SBLive!", HAS_AC97 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8051, "CT4850", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
/* 0x8061..0x???? 5.1 EMU10K1 cards */
{0x1102, 0x0002, 0x1102, 0x8061, "SB????", "SBLive! Player 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8062, "CT4830", "SBLive! 1024", HAS_AC97 | HAS_51 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8064, "SB????", "SBLive! 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8065, "SB0220", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8066, "CT4780", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1},
{0x1102, 0x0002, 0x1102, 0x8067, "SB????", "SBLive!", HAS_AC97 | HAS_51 | IS_EMU10K1},
/* Generic SB Live! */
{0x1102, 0x0002, 0x1102, 0x0000, "SB????", "SBLive! (Unknown model)", HAS_AC97 | IS_EMU10K1},
/* 0x0041..0x0043 EMU10K2 (some kind of Audigy) cards */
/* 0x0051..0x0051 5.1 CA0100-IAF cards */
{0x1102, 0x0004, 0x1102, 0x0051, "SB0090", "Audigy", HAS_AC97 | HAS_51 | IS_EMU10K2},
/* ES is CA0100-IDF chip that don't work in digital mode */
{0x1102, 0x0004, 0x1102, 0x0052, "SB0160", "Audigy ES", HAS_AC97 | HAS_71 | IS_EMU10K2 | BROKEN_DIGITAL},
/* 0x0053..0x005C 5.1 CA0101-NAF cards */
{0x1102, 0x0004, 0x1102, 0x0053, "SB0090", "Audigy Player/OEM", HAS_AC97 | HAS_51 | IS_EMU10K2},
{0x1102, 0x0004, 0x1102, 0x0058, "SB0090", "Audigy Player/OEM", HAS_AC97 | HAS_51 | IS_EMU10K2},
/* 0x1002..0x1009 5.1 CA0102-IAT cards */
{0x1102, 0x0004, 0x1102, 0x1002, "SB????", "Audigy 2 Platinum", HAS_51 | IS_CA0102},
{0x1102, 0x0004, 0x1102, 0x1005, "SB????", "Audigy 2 Platinum EX", HAS_51 | IS_CA0102},
{0x1102, 0x0004, 0x1102, 0x1007, "SB0240", "Audigy 2", HAS_AC97 | HAS_51 | IS_CA0102},
/* 0x2001..0x2003 7.1 CA0102-ICT cards */
{0x1102, 0x0004, 0x1102, 0x2001, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
{0x1102, 0x0004, 0x1102, 0x2002, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
/* XXX No reports about 0x2003 & 0x2004 cards */
{0x1102, 0x0004, 0x1102, 0x2003, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
{0x1102, 0x0004, 0x1102, 0x2004, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
{0x1102, 0x0004, 0x1102, 0x2005, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
/* (range unknown) 7.1 CA0102-xxx Audigy 4 cards */
{0x1102, 0x0004, 0x1102, 0x2007, "SB0380", "Audigy 4 Pro", HAS_AC97 | HAS_71 | IS_CA0102},
/* Generic Audigy or Audigy 2 */
{0x1102, 0x0004, 0x1102, 0x0000, "SB????", "Audigy (Unknown model)", HAS_AC97 | HAS_51 | IS_EMU10K2},
/* We don't support CA0103-DAT (Audigy LS) cards */
/* There is NO CA0104-xxx cards */
/* There is NO CA0105-xxx cards */
/* We don't support CA0106-DAT (SB Live! 24 bit) cards */
/* There is NO CA0107-xxx cards */
/* 0x1000..0x1001 7.1 CA0108-IAT cards */
{0x1102, 0x0008, 0x1102, 0x1000, "SB????", "Audigy 2 LS", HAS_AC97 | HAS_51 | IS_CA0108 | DIGITAL_ONLY},
{0x1102, 0x0008, 0x1102, 0x1001, "SB0400", "Audigy 2 Value", HAS_AC97 | HAS_71 | IS_CA0108 | DIGITAL_ONLY},
{0x1102, 0x0008, 0x1102, 0x1021, "SB0610", "Audigy 4", HAS_AC97 | HAS_71 | IS_CA0108 | DIGITAL_ONLY},
{0x1102, 0x0008, 0x1102, 0x2001, "SB0530", "Audigy 2 ZS CardBus", HAS_AC97 | HAS_71 | IS_CA0108 | IS_CARDBUS},
{0x1102, 0x0008, 0x0000, 0x0000, "SB????", "Audigy 2 Value (Unknown model)", HAS_AC97 | HAS_51 | IS_CA0108},
};
/* Unsupported cards */
static struct emu_hwinfo emu_bad_cards[] = {
/* APS cards should be possible to support */
{0x1102, 0x0002, 0x1102, 0x4001, "EMUAPS", "E-mu APS", 0},
{0x1102, 0x0002, 0x1102, 0x4002, "EMUAPS", "E-mu APS", 0},
{0x1102, 0x0004, 0x1102, 0x4001, "EMU???", "E-mu 1212m [4001]", 0},
/* Similar-named ("Live!" or "Audigy") cards on different chipsets */
{0x1102, 0x8064, 0x0000, 0x0000, "SB0100", "SBLive! 5.1 OEM", 0},
{0x1102, 0x0006, 0x0000, 0x0000, "SB0200", "DELL OEM SBLive! Value", 0},
{0x1102, 0x0007, 0x0000, 0x0000, "SB0310", "Audigy LS", 0},
};
/*
* Get best known information about device.
*/
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
static unsigned int
emu_getcard(device_t dev)
{
uint16_t device;
uint16_t subdevice;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
unsigned int thiscard;
int i;
device = pci_read_config(dev, PCIR_DEVICE, /* bytes */ 2);
subdevice = pci_read_config(dev, PCIR_SUBDEV_0, /* bytes */ 2);
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
thiscard = 0;
for (i = 1; i < nitems(emu_cards); i++) {
if (device == emu_cards[i].device) {
if (subdevice == emu_cards[i].subdevice) {
thiscard = i;
break;
}
if (0x0000 == emu_cards[i].subdevice) {
thiscard = i;
/*
* don't break, we can get more specific card
* later in the list.
*/
}
}
}
for (i = 0; i < nitems(emu_bad_cards); i++) {
if (device == emu_bad_cards[i].device) {
if (subdevice == emu_bad_cards[i].subdevice) {
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
thiscard = 0;
break;
}
if (0x0000 == emu_bad_cards[i].subdevice) {
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
thiscard = 0;
break; /* we avoid all this cards */
}
}
}
return (thiscard);
}
/*
* Base hardware interface are 32 (Audigy) or 64 (Audigy2) registers.
* Some of them are used directly, some of them provide pointer / data pairs.
*/
static uint32_t
emu_rd_nolock(struct emu_sc_info *sc, unsigned int regno, unsigned int size)
{
KASSERT(sc != NULL, ("emu_rd: NULL sc"));
switch (size) {
case 1:
return (bus_space_read_1(sc->st, sc->sh, regno));
case 2:
return (bus_space_read_2(sc->st, sc->sh, regno));
case 4:
return (bus_space_read_4(sc->st, sc->sh, regno));
}
return (0xffffffff);
}
static void
emu_wr_nolock(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size)
{
KASSERT(sc != NULL, ("emu_rd: NULL sc"));
switch (size) {
case 1:
bus_space_write_1(sc->st, sc->sh, regno, data);
break;
case 2:
bus_space_write_2(sc->st, sc->sh, regno, data);
break;
case 4:
bus_space_write_4(sc->st, sc->sh, regno, data);
break;
}
}
/*
* EMU_PTR / EMU_DATA interface. Access to EMU10Kx is made
* via (channel, register) pair. Some registers are channel-specific,
* some not.
*/
uint32_t
emu_rdptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg)
{
uint32_t ptr, val, mask, size, offset;
ptr = ((reg << 16) & sc->address_mask) | (chn & EMU_PTR_CHNO_MASK);
EMU_RWLOCK();
emu_wr_nolock(sc, EMU_PTR, ptr, 4);
val = emu_rd_nolock(sc, EMU_DATA, 4);
EMU_RWUNLOCK();
/*
* XXX Some register numbers has data size and offset encoded in
* it to get only part of 32bit register. This use is not described
* in register name, be careful!
*/
if (reg & 0xff000000) {
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
val &= mask;
val >>= offset;
}
return (val);
}
void
emu_wrptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg, uint32_t data)
{
uint32_t ptr, mask, size, offset;
ptr = ((reg << 16) & sc->address_mask) | (chn & EMU_PTR_CHNO_MASK);
EMU_RWLOCK();
emu_wr_nolock(sc, EMU_PTR, ptr, 4);
/*
* XXX Another kind of magic encoding in register number. This can
* give you side effect - it will read previous data from register
* and change only required bits.
*/
if (reg & 0xff000000) {
size = (reg >> 24) & 0x3f;
offset = (reg >> 16) & 0x1f;
mask = ((1 << size) - 1) << offset;
data <<= offset;
data &= mask;
data |= emu_rd_nolock(sc, EMU_DATA, 4) & ~mask;
}
emu_wr_nolock(sc, EMU_DATA, data, 4);
EMU_RWUNLOCK();
}
/*
* EMU_A2_PTR / EMU_DATA2 interface. Access to P16v is made
* via (channel, register) pair. Some registers are channel-specific,
* some not. This interface is supported by CA0102 and CA0108 chips only.
*/
uint32_t
emu_rd_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg)
{
uint32_t val;
/* XXX separate lock? */
EMU_RWLOCK();
emu_wr_nolock(sc, EMU_A2_PTR, (reg << 16) | chn, 4);
val = emu_rd_nolock(sc, EMU_DATA2, 4);
EMU_RWUNLOCK();
return (val);
}
void
emu_wr_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg, uint32_t data)
{
EMU_RWLOCK();
emu_wr_nolock(sc, EMU_A2_PTR, (reg << 16) | chn, 4);
emu_wr_nolock(sc, EMU_DATA2, data, 4);
EMU_RWUNLOCK();
}
/*
* XXX CardBus interface. Not tested on any real hardware.
*/
static void
emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data)
{
uint32_t val;
/*
* 0x38 is IPE3 (CD S/PDIF interrupt pending register) on CA0102. Seems
* to be some reg/value accessible kind of config register on CardBus
* CA0108, with value(?) in top 16 bit, address(?) in low 16
*/
val = emu_rd_nolock(sc, 0x38, 4);
emu_wr_nolock(sc, 0x38, data, 4);
val = emu_rd_nolock(sc, 0x38, 4);
}
/*
* Direct hardware register access
* Assume that it is never used to access EMU_PTR-based registers and can run unlocked.
*/
void
emu_wr(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size)
{
KASSERT(regno != EMU_PTR, ("emu_wr: attempt to write to EMU_PTR"));
KASSERT(regno != EMU_A2_PTR, ("emu_wr: attempt to write to EMU_A2_PTR"));
emu_wr_nolock(sc, regno, data, size);
}
uint32_t
emu_rd(struct emu_sc_info *sc, unsigned int regno, unsigned int size)
{
uint32_t rd;
KASSERT(regno != EMU_DATA, ("emu_rd: attempt to read DATA"));
KASSERT(regno != EMU_DATA2, ("emu_rd: attempt to read DATA2"));
rd = emu_rd_nolock(sc, regno, size);
return (rd);
}
/*
* Enabling IR MIDI messages is another kind of black magic. It just
* has to be made this way. It really do it.
*/
void
emu_enable_ir(struct emu_sc_info *sc)
{
uint32_t iocfg;
if (sc->is_emu10k2 || sc->is_ca0102) {
iocfg = emu_rd_nolock(sc, EMU_A_IOCFG, 2);
emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT2, 2);
DELAY(500);
emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT1 | EMU_A_IOCFG_GPOUT2, 2);
DELAY(500);
emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT1, 2);
DELAY(100);
emu_wr_nolock(sc, EMU_A_IOCFG, iocfg, 2);
device_printf(sc->dev, "Audigy IR MIDI events enabled.\n");
sc->enable_ir = 1;
}
if (sc->is_emu10k1) {
iocfg = emu_rd_nolock(sc, EMU_HCFG, 4);
emu_wr_nolock(sc, EMU_HCFG, iocfg | EMU_HCFG_GPOUT2, 4);
DELAY(500);
emu_wr_nolock(sc, EMU_HCFG, iocfg | EMU_HCFG_GPOUT1 | EMU_HCFG_GPOUT2, 4);
DELAY(100);
emu_wr_nolock(sc, EMU_HCFG, iocfg, 4);
device_printf(sc->dev, "SB Live! IR MIDI events enabled.\n");
sc->enable_ir = 1;
}
}
/*
2012-01-15 13:36:47 +00:00
* emu_timer_ - HW timer management
*/
int
emu_timer_create(struct emu_sc_info *sc)
{
int i, timer;
timer = -1;
mtx_lock(&sc->lock);
for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
if (sc->timer[i] == 0) {
sc->timer[i] = -1; /* disable it */
timer = i;
mtx_unlock(&sc->lock);
return (timer);
}
mtx_unlock(&sc->lock);
return (-1);
}
int
emu_timer_set(struct emu_sc_info *sc, int timer, int delay)
{
int i;
if (timer < 0)
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
return (-1);
RANGE(delay, 16, 1024);
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1);
mtx_lock(&sc->lock);
sc->timer[timer] = delay;
for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
if (sc->timerinterval > sc->timer[i])
sc->timerinterval = sc->timer[i];
/* XXX */
emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2);
mtx_unlock(&sc->lock);
return (timer);
}
int
emu_timer_enable(struct emu_sc_info *sc, int timer, int go)
{
uint32_t x;
int ena_int;
int i;
if (timer < 0)
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
return (-1);
RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1);
mtx_lock(&sc->lock);
if ((go == 1) && (sc->timer[timer] < 0))
sc->timer[timer] = -sc->timer[timer];
if ((go == 0) && (sc->timer[timer] > 0))
sc->timer[timer] = -sc->timer[timer];
ena_int = 0;
for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) {
if (sc->timerinterval > sc->timer[i])
sc->timerinterval = sc->timer[i];
if (sc->timer[i] > 0)
ena_int = 1;
}
emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2);
if (ena_int == 1) {
x = emu_rd(sc, EMU_INTE, 4);
x |= EMU_INTE_INTERTIMERENB;
emu_wr(sc, EMU_INTE, x, 4);
} else {
x = emu_rd(sc, EMU_INTE, 4);
x &= ~EMU_INTE_INTERTIMERENB;
emu_wr(sc, EMU_INTE, x, 4);
}
mtx_unlock(&sc->lock);
return (0);
}
int
emu_timer_clear(struct emu_sc_info *sc, int timer)
{
if (timer < 0)
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
return (-1);
RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1);
emu_timer_enable(sc, timer, 0);
mtx_lock(&sc->lock);
if (sc->timer[timer] != 0)
sc->timer[timer] = 0;
mtx_unlock(&sc->lock);
return (timer);
}
/*
2012-01-15 13:36:47 +00:00
* emu_intr_ - HW interrupt handler management
*/
int
emu_intr_register(struct emu_sc_info *sc, uint32_t inte_mask, uint32_t intr_mask, uint32_t(*func) (void *softc, uint32_t irq), void *isc)
{
int i;
uint32_t x;
mtx_lock(&sc->lock);
for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
if (sc->ihandler[i].inte_mask == 0) {
sc->ihandler[i].inte_mask = inte_mask;
sc->ihandler[i].intr_mask = intr_mask;
sc->ihandler[i].softc = isc;
sc->ihandler[i].irq_func = func;
x = emu_rd(sc, EMU_INTE, 4);
x |= inte_mask;
emu_wr(sc, EMU_INTE, x, 4);
mtx_unlock(&sc->lock);
if (sc->dbg_level > 1)
device_printf(sc->dev, "ihandle %d registered\n", i);
return (i);
}
mtx_unlock(&sc->lock);
if (sc->dbg_level > 1)
device_printf(sc->dev, "ihandle not registered\n");
return (-1);
}
int
emu_intr_unregister(struct emu_sc_info *sc, int hnumber)
{
uint32_t x;
int i;
mtx_lock(&sc->lock);
if (sc->ihandler[hnumber].inte_mask == 0) {
mtx_unlock(&sc->lock);
return (-1);
}
x = emu_rd(sc, EMU_INTE, 4);
x &= ~sc->ihandler[hnumber].inte_mask;
sc->ihandler[hnumber].inte_mask = 0;
sc->ihandler[hnumber].intr_mask = 0;
sc->ihandler[hnumber].softc = NULL;
sc->ihandler[hnumber].irq_func = NULL;
/* other interrupt handlers may use this EMU_INTE value */
for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
if (sc->ihandler[i].inte_mask != 0)
x |= sc->ihandler[i].inte_mask;
emu_wr(sc, EMU_INTE, x, 4);
mtx_unlock(&sc->lock);
return (hnumber);
}
static void
emu_intr(void *p)
{
struct emu_sc_info *sc = (struct emu_sc_info *)p;
uint32_t stat, ack;
int i;
for (;;) {
stat = emu_rd(sc, EMU_IPR, 4);
ack = 0;
if (stat == 0)
break;
emu_wr(sc, EMU_IPR, stat, 4);
for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) {
if ((((sc->ihandler[i].intr_mask) & stat) != 0) &&
(((void *)sc->ihandler[i].irq_func) != NULL)) {
ack |= sc->ihandler[i].irq_func(sc->ihandler[i].softc,
(sc->ihandler[i].intr_mask) & stat);
}
}
if (sc->dbg_level > 1)
if (stat & (~ack))
device_printf(sc->dev, "Unhandled interrupt: %08x\n", stat & (~ack));
}
if ((sc->is_ca0102) || (sc->is_ca0108))
for (;;) {
stat = emu_rd(sc, EMU_IPR2, 4);
ack = 0;
if (stat == 0)
break;
emu_wr(sc, EMU_IPR2, stat, 4);
if (sc->dbg_level > 1)
device_printf(sc->dev, "EMU_IPR2: %08x\n", stat);
2012-01-15 13:36:47 +00:00
break; /* to avoid infinite loop. should be removed
* after completion of P16V interface. */
}
if (sc->is_ca0102)
for (;;) {
stat = emu_rd(sc, EMU_IPR3, 4);
ack = 0;
if (stat == 0)
break;
emu_wr(sc, EMU_IPR3, stat, 4);
if (sc->dbg_level > 1)
device_printf(sc->dev, "EMU_IPR3: %08x\n", stat);
break; /* to avoid infinite loop. should be removed
* after completion of S/PDIF interface */
}
}
/*
* Get data from private emu10kx structure for PCM buffer allocation.
* Used by PCM code only.
*/
bus_dma_tag_t
emu_gettag(struct emu_sc_info *sc)
{
return (sc->mem.dmat);
}
static void
emu_setmap(void *arg, bus_dma_segment_t * segs, int nseg, int error)
{
bus_addr_t *phys = (bus_addr_t *) arg;
*phys = error ? 0 : (bus_addr_t) segs->ds_addr;
if (bootverbose) {
printf("emu10kx: setmap (%lx, %lx), nseg=%d, error=%d\n",
(unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
nseg, error);
}
}
static void *
emu_malloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr,
bus_dmamap_t *map)
{
void *dmabuf;
int error;
*addr = 0;
if ((error = bus_dmamem_alloc(mem->dmat, &dmabuf, BUS_DMA_NOWAIT, map))) {
if (mem->card->dbg_level > 2)
device_printf(mem->card->dev, "emu_malloc: failed to alloc DMA map: %d\n", error);
return (NULL);
}
if ((error = bus_dmamap_load(mem->dmat, *map, dmabuf, sz, emu_setmap, addr, 0)) || !*addr) {
if (mem->card->dbg_level > 2)
device_printf(mem->card->dev, "emu_malloc: failed to load DMA memory: %d\n", error);
bus_dmamem_free(mem->dmat, dmabuf, *map);
return (NULL);
}
return (dmabuf);
}
static void
emu_free(struct emu_mem *mem, void *dmabuf, bus_dmamap_t map)
{
bus_dmamap_unload(mem->dmat, map);
bus_dmamem_free(mem->dmat, dmabuf, map);
}
static void *
emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char *owner)
{
uint32_t blksz, start, idx, ofs, tmp, found;
struct emu_memblk *blk;
void *membuf;
blksz = sz / EMUPAGESIZE;
if (sz > (blksz * EMUPAGESIZE))
blksz++;
if (blksz > EMU_MAX_BUFSZ / EMUPAGESIZE) {
if (mem->card->dbg_level > 2)
device_printf(mem->card->dev, "emu_memalloc: memory request tool large\n");
return (NULL);
}
/* find a free block in the bitmap */
found = 0;
start = 1;
while (!found && start + blksz < EMU_MAXPAGES) {
found = 1;
for (idx = start; idx < start + blksz; idx++)
if (mem->bmap[idx >> 3] & (1 << (idx & 7)))
found = 0;
if (!found)
start++;
}
if (!found) {
if (mem->card->dbg_level > 2)
device_printf(mem->card->dev, "emu_memalloc: no free space in bitmap\n");
return (NULL);
}
blk = malloc(sizeof(*blk), M_DEVBUF, M_NOWAIT);
if (blk == NULL) {
if (mem->card->dbg_level > 2)
device_printf(mem->card->dev, "emu_memalloc: buffer allocation failed\n");
return (NULL);
}
bzero(blk, sizeof(*blk));
membuf = emu_malloc(mem, sz, &blk->buf_addr, &blk->buf_map);
*addr = blk->buf_addr;
if (membuf == NULL) {
if (mem->card->dbg_level > 2)
device_printf(mem->card->dev, "emu_memalloc: can't setup HW memory\n");
free(blk, M_DEVBUF);
return (NULL);
}
blk->buf = membuf;
blk->pte_start = start;
blk->pte_size = blksz;
strncpy(blk->owner, owner, 15);
blk->owner[15] = '\0';
ofs = 0;
for (idx = start; idx < start + blksz; idx++) {
mem->bmap[idx >> 3] |= 1 << (idx & 7);
tmp = (uint32_t) (blk->buf_addr + ofs);
mem->ptb_pages[idx] = (tmp << 1) | idx;
ofs += EMUPAGESIZE;
}
SLIST_INSERT_HEAD(&mem->blocks, blk, link);
return (membuf);
}
static int
emu_memfree(struct emu_mem *mem, void *membuf)
{
uint32_t idx, tmp;
struct emu_memblk *blk, *i;
blk = NULL;
SLIST_FOREACH(i, &mem->blocks, link) {
if (i->buf == membuf)
blk = i;
}
if (blk == NULL)
return (EINVAL);
SLIST_REMOVE(&mem->blocks, blk, emu_memblk, link);
emu_free(mem, membuf, blk->buf_map);
tmp = (uint32_t) (mem->silent_page_addr) << 1;
for (idx = blk->pte_start; idx < blk->pte_start + blk->pte_size; idx++) {
mem->bmap[idx >> 3] &= ~(1 << (idx & 7));
mem->ptb_pages[idx] = tmp | idx;
}
free(blk, M_DEVBUF);
return (0);
}
static int
emu_memstart(struct emu_mem *mem, void *membuf)
{
struct emu_memblk *blk, *i;
blk = NULL;
SLIST_FOREACH(i, &mem->blocks, link) {
if (i->buf == membuf)
blk = i;
}
if (blk == NULL)
return (-1);
return (blk->pte_start);
}
static uint32_t
emu_rate_to_pitch(uint32_t rate)
{
static uint32_t 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 char 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
};
int i;
if (rate == 0)
return (0);
rate *= 11185; /* Scale 48000 to 0x20002380 */
for (i = 31; i > 0; i--) {
if (rate & 0x80000000) { /* Detect leading "1" */
return (((uint32_t) (i - 15) << 20) +
logMagTable[0x7f & (rate >> 24)] +
(0x7f & (rate >> 17)) *
logSlopeTable[0x7f & (rate >> 24)]);
}
rate <<= 1;
}
/* NOTREACHED */
return (0);
}
static uint32_t
emu_rate_to_linearpitch(uint32_t rate)
{
rate = (rate << 8) / 375;
return ((rate >> 1) + (rate & 1));
}
struct emu_voice *
emu_valloc(struct emu_sc_info *sc)
{
struct emu_voice *v;
int i;
v = NULL;
mtx_lock(&sc->lock);
for (i = 0; i < NUM_G && sc->voice[i].busy; i++);
if (i < NUM_G) {
v = &sc->voice[i];
v->busy = 1;
}
mtx_unlock(&sc->lock);
return (v);
}
void
emu_vfree(struct emu_sc_info *sc, struct emu_voice *v)
{
int i, r;
mtx_lock(&sc->lock);
for (i = 0; i < NUM_G; i++) {
if (v == &sc->voice[i] && sc->voice[i].busy) {
v->busy = 0;
/*
* XXX What we should do with mono channels?
* See -pcm.c emupchan_init for other side of
* this problem
*/
if (v->slave != NULL)
r = emu_memfree(&sc->mem, v->vbuf);
}
}
mtx_unlock(&sc->lock);
}
int
emu_vinit(struct emu_sc_info *sc, struct emu_voice *m, struct emu_voice *s,
uint32_t sz, struct snd_dbuf *b)
{
void *vbuf;
bus_addr_t tmp_addr;
vbuf = emu_memalloc(&sc->mem, sz, &tmp_addr, "vinit");
if (vbuf == NULL) {
if(sc->dbg_level > 2)
device_printf(sc->dev, "emu_memalloc returns NULL in enu_vinit\n");
return (ENOMEM);
}
if (b != NULL)
sndbuf_setup(b, vbuf, sz);
m->start = emu_memstart(&sc->mem, vbuf) * EMUPAGESIZE;
if (m->start < 0) {
if(sc->dbg_level > 2)
device_printf(sc->dev, "emu_memstart returns (-1) in enu_vinit\n");
emu_memfree(&sc->mem, vbuf);
return (ENOMEM);
}
m->end = m->start + sz;
m->speed = 0;
m->b16 = 0;
m->stereo = 0;
m->running = 0;
m->ismaster = 1;
m->vol = 0xff;
m->buf = tmp_addr;
m->vbuf = vbuf;
m->slave = s;
if (s != NULL) {
s->start = m->start;
s->end = m->end;
s->speed = 0;
s->b16 = 0;
s->stereo = 0;
s->running = 0;
s->ismaster = 0;
s->vol = m->vol;
s->buf = m->buf;
s->vbuf = NULL;
s->slave = NULL;
}
return (0);
}
void
emu_vsetup(struct emu_voice *v, int fmt, int spd)
{
if (fmt) {
v->b16 = (fmt & AFMT_16BIT) ? 1 : 0;
Sound Mega-commit. Expect further cleanup until code freeze. For a slightly thorough explaination, please refer to [1] http://people.freebsd.org/~ariff/SOUND_4.TXT.html . Summary of changes includes: 1 Volume Per-Channel (vpc). Provides private / standalone volume control unique per-stream pcm channel without touching master volume / pcm. Applications can directly use SNDCTL_DSP_[GET|SET][PLAY|REC]VOL, or for backwards compatibility, SOUND_MIXER_PCM through the opened dsp device instead of /dev/mixer. Special "bypass" mode is enabled through /dev/mixer which will automatically detect if the adjustment is made through /dev/mixer and forward its request to this private volume controller. Changes to this volume object will not interfere with other channels. Requirements: - SNDCTL_DSP_[GET|SET][PLAY|REC]_VOL are newer ioctls (OSSv4) which require specific application modifications (preferred). - No modifications required for using bypass mode, so applications like mplayer or xmms should work out of the box. Kernel hints: - hint.pcm.%d.vpc (0 = disable vpc). Kernel sysctls: - hw.snd.vpc_mixer_bypass (default: 1). Enable or disable /dev/mixer bypass mode. - hw.snd.vpc_autoreset (default: 1). By default, closing/opening /dev/dsp will reset the volume back to 0 db gain/attenuation. Setting this to 0 will preserve its settings across device closing/opening. - hw.snd.vpc_reset (default: 0). Panic/reset button to reset all volume settings back to 0 db. - hw.snd.vpc_0db (default: 45). 0 db relative to linear mixer value. 2 High quality fixed-point Bandlimited SINC sampling rate converter, based on Julius O'Smith's Digital Audio Resampling - http://ccrma.stanford.edu/~jos/resample/. It includes a filter design script written in awk (the clumsiest joke I've ever written) - 100% 32bit fixed-point, 64bit accumulator. - Possibly among the fastest (if not fastest) of its kind. - Resampling quality is tunable, either runtime or during kernel compilation (FEEDER_RATE_PRESETS). - Quality can be further customized during kernel compilation by defining FEEDER_RATE_PRESETS in /etc/make.conf. Kernel sysctls: - hw.snd.feeder_rate_quality. 0 - Zero-order Hold (ZOH). Fastest, bad quality. 1 - Linear Interpolation (LINEAR). Slightly slower than ZOH, better quality but still does not eliminate aliasing. 2 - (and above) - Sinc Interpolation(SINC). Best quality. SINC quality always start from 2 and above. Rough quality comparisons: - http://people.freebsd.org/~ariff/z_comparison/ 3 Bit-perfect mode. Bypasses all feeder/dsp effects. Pure sound will be directly fed into the hardware. 4 Parametric (compile time) Software Equalizer (Bass/Treble mixer). Can be customized by defining FEEDER_EQ_PRESETS in /etc/make.conf. 5 Transparent/Adaptive Virtual Channel. Now you don't have to disable vchans in order to make digital format pass through. It also makes vchans more dynamic by choosing a better format/rate among all the concurrent streams, which means that dev.pcm.X.play.vchanformat/rate becomes sort of optional. 6 Exclusive Stream, with special open() mode O_EXCL. This will "mute" other concurrent vchan streams and only allow a single channel with O_EXCL set to keep producing sound. Other Changes: * most feeder_* stuffs are compilable in userland. Let's not speculate whether we should go all out for it (save that for FreeBSD 16.0-RELEASE). * kobj signature fixups, thanks to Andriy Gapon <avg@freebsd.org> * pull out channel mixing logic out of vchan.c and create its own feeder_mixer for world justice. * various refactoring here and there, for good or bad. * activation of few more OSSv4 ioctls() (see [1] above). * opt_snd.h for possible compile time configuration: (mostly for debugging purposes, don't try these at home) SND_DEBUG SND_DIAGNOSTIC SND_FEEDER_MULTIFORMAT SND_FEEDER_FULL_MULTIFORMAT SND_FEEDER_RATE_HP SND_PCM_64 SND_OLDSTEREO Manual page updates are on the way. Tested by: joel, Olivier SMEDTS <olivier at gid0 d org>, too many unsung / unnamed heroes.
2009-06-07 19:12:08 +00:00
v->stereo = (AFMT_CHANNEL(fmt) > 1) ? 1 : 0;
if (v->slave != NULL) {
v->slave->b16 = v->b16;
v->slave->stereo = v->stereo;
}
}
if (spd) {
v->speed = spd;
if (v->slave != NULL)
v->slave->speed = v->speed;
}
}
void
emu_vroute(struct emu_sc_info *sc, struct emu_route *rt, struct emu_voice *v)
{
int i;
for (i = 0; i < 8; i++) {
v->routing[i] = rt->routing_left[i];
v->amounts[i] = rt->amounts_left[i];
}
if ((v->stereo) && (v->ismaster == 0))
for (i = 0; i < 8; i++) {
v->routing[i] = rt->routing_right[i];
v->amounts[i] = rt->amounts_right[i];
}
if ((v->stereo) && (v->slave != NULL))
emu_vroute(sc, rt, v->slave);
}
void
emu_vwrite(struct emu_sc_info *sc, struct emu_voice *v)
{
int s;
uint32_t start, val, silent_page;
s = (v->stereo ? 1 : 0) + (v->b16 ? 1 : 0);
v->sa = v->start >> s;
v->ea = v->end >> s;
if (v->stereo) {
emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, EMU_CHAN_CPF_STEREO_MASK);
} else {
emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, 0);
}
val = v->stereo ? 28 : 30;
val *= v->b16 ? 1 : 2;
start = v->sa + val;
if (sc->is_emu10k1) {
emu_wrptr(sc, v->vnum, EMU_CHAN_FXRT, ((v->routing[3] << 12) |
(v->routing[2] << 8) |
(v->routing[1] << 4) |
(v->routing[0] << 0)) << 16);
} else {
emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT1, (v->routing[3] << 24) |
(v->routing[2] << 16) |
(v->routing[1] << 8) |
(v->routing[0] << 0));
emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT2, (v->routing[7] << 24) |
(v->routing[6] << 16) |
(v->routing[5] << 8) |
(v->routing[4] << 0));
emu_wrptr(sc, v->vnum, EMU_A_CHAN_SENDAMOUNTS, (v->amounts[7] << 24) |
(v->amounts[6] << 26) |
(v->amounts[5] << 8) |
(v->amounts[4] << 0));
}
emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX, (v->amounts[0] << 8) | (v->amounts[1] << 0));
emu_wrptr(sc, v->vnum, EMU_CHAN_DSL, v->ea | (v->amounts[3] << 24));
emu_wrptr(sc, v->vnum, EMU_CHAN_PSST, v->sa | (v->amounts[2] << 24));
emu_wrptr(sc, v->vnum, EMU_CHAN_CCCA, start | (v->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT));
emu_wrptr(sc, v->vnum, EMU_CHAN_Z1, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_Z2, 0);
silent_page = ((uint32_t) (sc->mem.silent_page_addr) << 1) | EMU_CHAN_MAP_PTI_MASK;
emu_wrptr(sc, v->vnum, EMU_CHAN_MAPA, silent_page);
emu_wrptr(sc, v->vnum, EMU_CHAN_MAPB, silent_page);
emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, EMU_CHAN_CVCF_CURRFILTER_MASK);
emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, EMU_CHAN_VTFT_FILTERTARGET_MASK);
emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDM, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSM, EMU_CHAN_DCYSUSM_DECAYTIME_MASK);
emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL1, 0x8000);
emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL2, 0x8000);
emu_wrptr(sc, v->vnum, EMU_CHAN_FMMOD, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_TREMFRQ, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_FM2FRQ2, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVAL, 0x8000);
emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDV, EMU_CHAN_ATKHLDV_HOLDTIME_MASK | EMU_CHAN_ATKHLDV_ATTACKTIME_MASK);
emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVOL, 0x8000);
emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_FILTERAMOUNT, 0x7f);
emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_PITCHAMOUNT, 0);
if ((v->stereo) && (v->slave != NULL))
emu_vwrite(sc, v->slave);
}
static void
emu_vstop(struct emu_sc_info *sc, char channel, int enable)
{
int reg;
reg = (channel & 0x20) ? EMU_SOLEH : EMU_SOLEL;
channel &= 0x1f;
reg |= 1 << 24;
reg |= channel << 16;
emu_wrptr(sc, 0, reg, enable);
}
void
emu_vtrigger(struct emu_sc_info *sc, struct emu_voice *v, int go)
{
uint32_t pitch_target, initial_pitch;
uint32_t cra, cs, ccis;
uint32_t sample, i;
if (go) {
cra = 64;
cs = v->stereo ? 4 : 2;
ccis = v->stereo ? 28 : 30;
ccis *= v->b16 ? 1 : 2;
sample = v->b16 ? 0x00000000 : 0x80808080;
for (i = 0; i < cs; i++)
emu_wrptr(sc, v->vnum, EMU_CHAN_CD0 + i, sample);
emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_READADDRESS, cra);
emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, ccis);
emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xff00);
emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0xffffffff);
emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0xffffffff);
emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSV, 0x00007f7f);
emu_vstop(sc, v->vnum, 0);
pitch_target = emu_rate_to_linearpitch(v->speed);
initial_pitch = emu_rate_to_pitch(v->speed) >> 8;
emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, pitch_target);
emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, pitch_target);
emu_wrptr(sc, v->vnum, EMU_CHAN_IP, initial_pitch);
} else {
emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, 0);
emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xffff);
emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0x0000ffff);
emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0x0000ffff);
emu_wrptr(sc, v->vnum, EMU_CHAN_IP, 0);
emu_vstop(sc, v->vnum, 1);
}
if ((v->stereo) && (v->slave != NULL))
emu_vtrigger(sc, v->slave, go);
}
int
emu_vpos(struct emu_sc_info *sc, struct emu_voice *v)
{
int s, ptr;
s = (v->b16 ? 1 : 0) + (v->stereo ? 1 : 0);
ptr = (emu_rdptr(sc, v->vnum, EMU_CHAN_CCCA_CURRADDR) - (v->start >> s)) << s;
return (ptr & ~0x0000001f);
}
/* fx */
static void
emu_wrefx(struct emu_sc_info *sc, unsigned int pc, unsigned int data)
{
emu_wrptr(sc, 0, sc->code_base + pc, data);
}
static void
emu_addefxop(struct emu_sc_info *sc, unsigned int op, unsigned int z, unsigned int w, unsigned int x, unsigned int y, uint32_t * pc)
{
if ((*pc) + 1 > sc->code_size) {
device_printf(sc->dev, "DSP CODE OVERRUN: attept to write past code_size (pc=%d)\n", (*pc));
return;
}
emu_wrefx(sc, (*pc) * 2, (x << sc->high_operand_shift) | y);
emu_wrefx(sc, (*pc) * 2 + 1, (op << sc->opcode_shift) | (z << sc->high_operand_shift) | w);
(*pc)++;
}
static int
sysctl_emu_mixer_control(SYSCTL_HANDLER_ARGS)
{
struct emu_sc_info *sc;
int mixer_id;
int new_vol;
int err;
sc = arg1;
mixer_id = arg2;
new_vol = emumix_get_volume(sc, mixer_id);
err = sysctl_handle_int(oidp, &new_vol, 0, req);
if (err || req->newptr == NULL)
return (err);
if (new_vol < 0 || new_vol > 100)
return (EINVAL);
emumix_set_volume(sc, mixer_id, new_vol);
return (0);
}
static int
emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id, uint32_t defvolume)
{
int volgpr;
char sysctl_name[32];
volgpr = emu_rm_gpr_alloc(sc->rm, 1);
emumix_set_fxvol(sc, volgpr, defvolume);
/*
* Mixer controls with NULL mix_name are handled
* by AC97 emulation code or PCM mixer.
*/
if (mix_name != NULL) {
/*
* Temporary sysctls should start with underscore,
* see freebsd-current mailing list, emu10kx driver
* discussion around 2006-05-24.
*/
snprintf(sysctl_name, 32, "_%s", mix_name);
SYSCTL_ADD_PROC(sc->ctx,
SYSCTL_CHILDREN(sc->root),
OID_AUTO, sysctl_name,
CTLTYPE_INT | CTLFLAG_RW, sc, mix_id,
sysctl_emu_mixer_control, "I", "");
}
return (volgpr);
}
static int
sysctl_emu_digitalswitch_control(SYSCTL_HANDLER_ARGS)
{
struct emu_sc_info *sc;
int new_val;
int err;
sc = arg1;
new_val = (sc->mode == MODE_DIGITAL) ? 1 : 0;
err = sysctl_handle_int(oidp, &new_val, 0, req);
if (err || req->newptr == NULL)
return (err);
if (new_val < 0 || new_val > 1)
return (EINVAL);
switch (new_val) {
case 0:
emumix_set_mode(sc, MODE_ANALOG);
break;
case 1:
emumix_set_mode(sc, MODE_DIGITAL);
break;
}
return (0);
}
static void
emu_digitalswitch(struct emu_sc_info *sc)
{
/* XXX temporary? */
SYSCTL_ADD_PROC(sc->ctx,
SYSCTL_CHILDREN(sc->root),
OID_AUTO, "_digital",
CTLTYPE_INT | CTLFLAG_RW, sc, 0,
sysctl_emu_digitalswitch_control, "I", "Enable digital output");
return;
}
/*
* Allocate cache GPRs that will hold mixed output channels
* and clear it on every DSP run.
*/
#define EFX_CACHE(CACHE_IDX) do { \
sc->cache_gpr[CACHE_IDX] = emu_rm_gpr_alloc(sc->rm, 1); \
emu_addefxop(sc, ACC3, \
GPR(sc->cache_gpr[CACHE_IDX]), \
DSP_CONST(0), \
DSP_CONST(0), \
DSP_CONST(0), \
&pc); \
} while (0)
/* Allocate GPR for volume control and route sound: OUT = OUT + IN * VOL */
#define EFX_ROUTE(TITLE, INP_NR, IN_GPR_IDX, OUT_CACHE_IDX, DEF) do { \
sc->mixer_gpr[IN_GPR_IDX] = emu_addefxmixer(sc, TITLE, IN_GPR_IDX, DEF); \
sc->mixer_volcache[IN_GPR_IDX] = DEF; \
emu_addefxop(sc, MACS, \
GPR(sc->cache_gpr[OUT_CACHE_IDX]), \
GPR(sc->cache_gpr[OUT_CACHE_IDX]), \
INP_NR, \
GPR(sc->mixer_gpr[IN_GPR_IDX]), \
&pc); \
} while (0)
/* allocate GPR, OUT = IN * VOL */
#define EFX_OUTPUT(TITLE, OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR, DEF) do { \
sc->mixer_gpr[OUT_GPR_IDX] = emu_addefxmixer(sc, TITLE, OUT_GPR_IDX, DEF); \
sc->mixer_volcache[OUT_GPR_IDX] = DEF; \
emu_addefxop(sc, MACS, \
OUTP(OUTP_NR), \
DSP_CONST(0), \
GPR(sc->cache_gpr[OUT_CACHE_IDX]), \
GPR(sc->mixer_gpr[OUT_GPR_IDX]), \
&pc); \
} while (0)
/* like EFX_OUTPUT, but don't allocate mixer gpr */
#define EFX_OUTPUTD(OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR) do { \
emu_addefxop(sc, MACS, \
OUTP(OUTP_NR), \
DSP_CONST(0), \
GPR(sc->cache_gpr[OUT_CACHE_IDX]), \
GPR(sc->mixer_gpr[OUT_GPR_IDX]), \
&pc); \
} while (0)
/* skip next OPCOUNT instructions if FLAG != 0 */
#define EFX_SKIP(OPCOUNT, FLAG_GPR) do { \
emu_addefxop(sc, MACS, \
DSP_CONST(0), \
GPR(sc->mute_gpr[FLAG_GPR]), \
DSP_CONST(0), \
DSP_CONST(0), \
&pc); \
emu_addefxop(sc, SKIP, \
DSP_CCR, \
DSP_CCR, \
COND_NEQ_ZERO, \
OPCOUNT, \
&pc); \
} while (0)
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
#define EFX_COPY(TO, FROM) do { \
emu_addefxop(sc, ACC3, \
TO, \
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
DSP_CONST(0), \
DSP_CONST(0), \
FROM, \
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
&pc); \
} while (0)
static void
emu_initefx(struct emu_sc_info *sc)
{
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
unsigned int i;
uint32_t pc;
/* stop DSP */
if (sc->is_emu10k1) {
emu_wrptr(sc, 0, EMU_DBG, EMU_DBG_SINGLE_STEP);
} else {
emu_wrptr(sc, 0, EMU_A_DBG, EMU_A_DBG_SINGLE_STEP);
}
/* code size is in instructions */
pc = 0;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
for (i = 0; i < sc->code_size; i++) {
if (sc->is_emu10k1) {
emu_addefxop(sc, ACC3, DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), &pc);
} else {
emu_addefxop(sc, SKIP, DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0xf), DSP_CONST(0x0), &pc);
}
}
/* allocate GPRs for mute switches (EFX_SKIP). Mute by default */
for (i = 0; i < NUM_MUTE; i++) {
sc->mute_gpr[i] = emu_rm_gpr_alloc(sc->rm, 1);
emumix_set_gpr(sc, sc->mute_gpr[i], 1);
}
emu_digitalswitch(sc);
pc = 0;
/*
* DSP code below is not good, because:
* 1. It can be written smaller, if it can use DSP accumulator register
* instead of cache_gpr[].
* 2. It can be more careful when volume is 100%, because in DSP
* x*0x7fffffff may not be equal to x !
*/
/* clean outputs */
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
for (i = 0; i < 16 ; i++) {
emu_addefxop(sc, ACC3, OUTP(i), DSP_CONST(0), DSP_CONST(0), DSP_CONST(0), &pc);
}
if (sc->is_emu10k1) {
EFX_CACHE(C_FRONT_L);
EFX_CACHE(C_FRONT_R);
EFX_CACHE(C_REC_L);
EFX_CACHE(C_REC_R);
/* fx0 to front/record, 100%/muted by default */
EFX_ROUTE("pcm_front_l", FX(0), M_FX0_FRONT_L, C_FRONT_L, 100);
EFX_ROUTE("pcm_front_r", FX(1), M_FX1_FRONT_R, C_FRONT_R, 100);
EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0);
/* in0, from AC97 codec output */
EFX_ROUTE("ac97_front_l", INP(IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE("ac97_front_r", INP(IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE("ac97_rec_l", INP(IN_AC97_L), M_IN0_REC_L, C_REC_L, 0);
EFX_ROUTE("ac97_rec_r", INP(IN_AC97_R), M_IN0_REC_R, C_REC_R, 0);
/* in1, from CD S/PDIF */
/* XXX EFX_SKIP 4 assumes that each EFX_ROUTE is one DSP op */
EFX_SKIP(4, CDSPDIFMUTE);
EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0);
if (sc->dbg_level > 0) {
/* in2, ZoomVide (???) */
EFX_ROUTE("zoom_front_l", INP(IN_ZOOM_L), M_IN2_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE("zoom_front_r", INP(IN_ZOOM_R), M_IN2_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE("zoom_rec_l", INP(IN_ZOOM_L), M_IN2_REC_L, C_REC_L, 0);
EFX_ROUTE("zoom_rec_r", INP(IN_ZOOM_R), M_IN2_REC_R, C_REC_R, 0);
}
/* in3, TOSLink */
EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_REC_R, C_REC_R, 0);
/* in4, LineIn */
EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_REC_R, C_REC_R, 0);
/* in5, on-card S/PDIF */
EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_REC_R, C_REC_R, 0);
/* in6, Line2 on Live!Drive */
EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_REC_R, C_REC_R, 0);
if (sc->dbg_level > 0) {
/* in7, unknown */
EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE("in7_rec_l", INP(0xE), M_IN7_REC_L, C_REC_L, 0);
EFX_ROUTE("in7_rec_r", INP(0xF), M_IN7_REC_R, C_REC_R, 0);
}
/* analog and digital */
EFX_OUTPUT("master_front_l", C_FRONT_L, M_MASTER_FRONT_L, OUT_AC97_L, 100);
EFX_OUTPUT("master_front_r", C_FRONT_R, M_MASTER_FRONT_R, OUT_AC97_R, 100);
/* S/PDIF */
EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_TOSLINK_L);
EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_TOSLINK_R);
/* Headphones */
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_HEADPHONE_L);
EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_HEADPHONE_R);
/* rec output to "ADC" */
EFX_OUTPUT("master_rec_l", C_REC_L, M_MASTER_REC_L, OUT_ADC_REC_L, 100);
EFX_OUTPUT("master_rec_r", C_REC_R, M_MASTER_REC_R, OUT_ADC_REC_R, 100);
if (!(sc->mch_disabled)) {
/*
* Additional channel volume is controlled by mixer in
* emu_dspmixer_set() in -pcm.c
*/
/* fx2/3 (pcm1) to rear */
EFX_CACHE(C_REAR_L);
EFX_CACHE(C_REAR_R);
EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100);
EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100);
EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, OUT_REAR_L, 100);
EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, OUT_REAR_R, 100);
if (sc->has_51) {
/* fx4 (pcm2) to center */
EFX_CACHE(C_CENTER);
EFX_ROUTE(NULL, FX(4), M_FX4_CENTER, C_CENTER, 100);
EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100);
/* XXX in digital mode (default) this should be muted because
this output is shared with digital out */
EFX_SKIP(1, ANALOGMUTE);
EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER);
/* fx5 (pcm3) to sub */
EFX_CACHE(C_SUB);
EFX_ROUTE(NULL, FX(5), M_FX5_SUBWOOFER, C_SUB, 100);
EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100);
/* XXX in digital mode (default) this should be muted because
this output is shared with digital out */
EFX_SKIP(1, ANALOGMUTE);
EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB);
}
} else {
/* SND_EMU10KX_MULTICHANNEL_DISABLED */
EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_REAR_L, OUT_REAR_L, 57); /* 75%*75% */
EFX_OUTPUT(NULL, C_FRONT_R, M_MASTER_REAR_R, OUT_REAR_R, 57); /* 75%*75% */
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
#if 0
/* XXX 5.1 does not work */
if (sc->has_51) {
/* (fx0+fx1)/2 to center */
EFX_CACHE(C_CENTER);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_CENTER]),
GPR(sc->cache_gpr[C_CENTER]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_L]),
&pc);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_CENTER]),
GPR(sc->cache_gpr[C_CENTER]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_R]),
&pc);
EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100);
/* XXX in digital mode (default) this should be muted because
this output is shared with digital out */
EFX_SKIP(1, ANALOGMUTE);
EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER);
/* (fx0+fx1)/2 to sub */
EFX_CACHE(C_SUB);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_CENTER]),
GPR(sc->cache_gpr[C_CENTER]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_L]),
&pc);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_CENTER]),
GPR(sc->cache_gpr[C_CENTER]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_R]),
&pc);
/* XXX add lowpass filter here */
EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100);
/* XXX in digital mode (default) this should be muted because
this output is shared with digital out */
EFX_SKIP(1, ANALOGMUTE);
EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB);
}
#endif
} /* !mch_disabled */
if (sc->mch_rec) {
/*
* MCH RECORDING , hight 16 slots. On 5.1 cards first 4 slots
* are used as outputs and already filled with data
*/
/*
* XXX On Live! cards stream does not begin at zero offset.
* It can be HW, driver or sound buffering problem.
* Use sync substream (offset 0x3E) to let userland find
* correct data.
*/
/*
* Substream map (in byte offsets, each substream is 2 bytes):
* 0x00..0x1E - outputs
* 0x20..0x3E - FX, inputs and sync stream
*/
/* First 2 channels (offset 0x20,0x22) are empty */
for(i = (sc->has_51 ? 2 : 0); i < 2; i++)
EFX_COPY(FX2(i), DSP_CONST(0));
/* PCM Playback monitoring, offset 0x24..0x2A */
for(i = 0; i < 4; i++)
EFX_COPY(FX2(i+2), FX(i));
/* Copy of some inputs, offset 0x2C..0x3C */
for(i = 0; i < 9; i++)
EFX_COPY(FX2(i+8), INP(i));
/* sync data (0xc0de, offset 0x3E) */
sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1);
emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000);
EFX_COPY(FX2(15), GPR(sc->dummy_gpr));
} /* mch_rec */
} else /* emu10k2 and later */ {
EFX_CACHE(C_FRONT_L);
EFX_CACHE(C_FRONT_R);
EFX_CACHE(C_REC_L);
EFX_CACHE(C_REC_R);
/* fx0 to front/record, 100%/muted by default */
/*
* FRONT_[L|R] is controlled by AC97 emulation in
* emu_ac97_[read|write]_emulation in -pcm.c
*/
EFX_ROUTE(NULL, FX(0), M_FX0_FRONT_L, C_FRONT_L, 100);
EFX_ROUTE(NULL, FX(1), M_FX1_FRONT_R, C_FRONT_R, 100);
EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0);
/* in0, from AC97 codec output */
EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 100);
EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 100);
EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_REC_R, C_REC_R, 0);
/* in1, from CD S/PDIF */
EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0);
/* in2, optical & coax S/PDIF on AudigyDrive*/
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
/* XXX Should be muted when GPRSCS valid stream == 0 */
EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_REC_R, C_REC_R, 0);
if (sc->dbg_level > 0) {
/* in3, unknown */
EFX_ROUTE("in3_front_l", INP(0x6), M_IN3_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE("in3_front_r", INP(0x7), M_IN3_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE("in3_rec_l", INP(0x6), M_IN3_REC_L, C_REC_L, 0);
EFX_ROUTE("in3_rec_r", INP(0x7), M_IN3_REC_R, C_REC_R, 0);
}
/* in4, LineIn 2 on AudigyDrive */
EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_REC_R, C_REC_R, 0);
/* in5, on-card S/PDIF */
EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_REC_R, C_REC_R, 0);
/* in6, AUX2 on AudigyDrive */
EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_REC_L, C_REC_L, 0);
EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_REC_R, C_REC_R, 0);
if (sc->dbg_level > 0) {
/* in7, unknown */
EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0);
EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0);
EFX_ROUTE("in7_rec_l", INP(0xE), M_IN7_REC_L, C_REC_L, 0);
EFX_ROUTE("in7_rec_r", INP(0xF), M_IN7_REC_R, C_REC_R, 0);
}
/* front output to headphones and alog and digital *front */
/* volume controlled by AC97 emulation */
EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_FRONT_L, 100);
EFX_OUTPUT(NULL, C_FRONT_R, M_MASTER_FRONT_R, A_OUT_A_FRONT_R, 100);
EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_FRONT_L);
EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_FRONT_R);
EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_HPHONE_L);
EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_HPHONE_R);
/* rec output to "ADC" */
/* volume controlled by AC97 emulation */
EFX_OUTPUT(NULL, C_REC_L, M_MASTER_REC_L, A_OUT_ADC_REC_L, 100);
EFX_OUTPUT(NULL, C_REC_R, M_MASTER_REC_R, A_OUT_ADC_REC_R, 100);
if (!(sc->mch_disabled)) {
/*
* Additional channel volume is controlled by mixer in
* emu_dspmixer_set() in -pcm.c
*/
/* fx2/3 (pcm1) to rear */
EFX_CACHE(C_REAR_L);
EFX_CACHE(C_REAR_R);
EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100);
EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100);
EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, A_OUT_A_REAR_L, 100);
EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, A_OUT_A_REAR_R, 100);
EFX_OUTPUTD(C_REAR_L, M_MASTER_REAR_L, A_OUT_D_REAR_L);
EFX_OUTPUTD(C_REAR_R, M_MASTER_REAR_R, A_OUT_D_REAR_R);
/* fx4 (pcm2) to center */
EFX_CACHE(C_CENTER);
EFX_ROUTE(NULL, FX(4), M_FX4_CENTER, C_CENTER, 100);
EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, A_OUT_D_CENTER, 100);
#if 0
/*
* XXX in digital mode (default) this should be muted
* because this output is shared with digital out
*/
EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_OUT_A_CENTER);
#endif
/* fx5 (pcm3) to sub */
EFX_CACHE(C_SUB);
EFX_ROUTE(NULL, FX(5), M_FX5_SUBWOOFER, C_SUB, 100);
EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, A_OUT_D_SUB, 100);
#if 0
/*
* XXX in digital mode (default) this should be muted
* because this output is shared with digital out
*/
EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB);
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
#endif
if (sc->has_71) {
/* XXX this will broke headphones on AudigyDrive */
/* fx6/7 (pcm4) to side */
EFX_CACHE(C_SIDE_L);
EFX_CACHE(C_SIDE_R);
EFX_ROUTE(NULL, FX(6), M_FX6_SIDE_L, C_SIDE_L, 100);
EFX_ROUTE(NULL, FX(7), M_FX7_SIDE_R, C_SIDE_R, 100);
EFX_OUTPUT(NULL, C_SIDE_L, M_MASTER_SIDE_L, A_OUT_A_SIDE_L, 100);
EFX_OUTPUT(NULL, C_SIDE_R, M_MASTER_SIDE_R, A_OUT_A_SIDE_R, 100);
EFX_OUTPUTD(C_SIDE_L, M_MASTER_SIDE_L, A_OUT_D_SIDE_L);
EFX_OUTPUTD(C_SIDE_R, M_MASTER_SIDE_R, A_OUT_D_SIDE_R);
}
} else { /* mch_disabled */
EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_REAR_L);
EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_A_REAR_R);
EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_REAR_L);
EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_REAR_R);
if (sc->has_51) {
/* (fx0+fx1)/2 to center */
EFX_CACHE(C_CENTER);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_CENTER]),
GPR(sc->cache_gpr[C_CENTER]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_L]),
&pc);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_CENTER]),
GPR(sc->cache_gpr[C_CENTER]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_R]),
&pc);
EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, A_OUT_D_CENTER, 100);
/* XXX in digital mode (default) this should be muted because
this output is shared with digital out */
EFX_SKIP(1, ANALOGMUTE);
EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_OUT_A_CENTER);
/* (fx0+fx1)/2 to sub */
EFX_CACHE(C_SUB);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_SUB]),
GPR(sc->cache_gpr[C_SUB]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_L]),
&pc);
emu_addefxop(sc, MACS,
GPR(sc->cache_gpr[C_SUB]),
GPR(sc->cache_gpr[C_SUB]),
DSP_CONST(0xd), /* = 1/2 */
GPR(sc->cache_gpr[C_FRONT_R]),
&pc);
/* XXX add lowpass filter here */
EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, A_OUT_D_SUB, 100);
/* XXX in digital mode (default) this should be muted because
this output is shared with digital out */
EFX_SKIP(1, ANALOGMUTE);
EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB);
}
} /* mch_disabled */
if (sc->mch_rec) {
/* MCH RECORDING, high 32 slots */
/*
* Stream map (in byte offsets):
* 0x00..0x3E - outputs
* 0x40..0x7E - FX, inputs
* each substream is 2 bytes.
*/
/*
* XXX Audigy 2 Value cards (and, possibly,
* Audigy 4) write some unknown data in place of
* some outputs (offsets 0x20..0x3F) and one
* input (offset 0x7E).
*/
/* PCM Playback monitoring, offsets 0x40..0x5E */
for(i = 0; i < 16; i++)
EFX_COPY(FX2(i), FX(i));
/* Copy of all inputs, offsets 0x60..0x7E */
for(i = 0; i < 16; i++)
EFX_COPY(FX2(i+16), INP(i));
#if 0
/* XXX Audigy seems to work correct and does not need this */
/* sync data (0xc0de), offset 0x7E */
sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1);
emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000);
EFX_COPY(FX2(31), GPR(sc->dummy_gpr));
#endif
} /* mch_rec */
}
sc->routing_code_end = pc;
/* start DSP */
if (sc->is_emu10k1) {
emu_wrptr(sc, 0, EMU_DBG, 0);
} else {
emu_wrptr(sc, 0, EMU_A_DBG, 0);
}
}
/* /dev/em10kx */
static d_open_t emu10kx_open;
static d_close_t emu10kx_close;
static d_read_t emu10kx_read;
static struct cdevsw emu10kx_cdevsw = {
.d_open = emu10kx_open,
.d_close = emu10kx_close,
.d_read = emu10kx_read,
.d_name = "emu10kx",
.d_version = D_VERSION,
};
static int
emu10kx_open(struct cdev *i_dev, int flags __unused, int mode __unused, struct thread *td __unused)
{
int error;
struct emu_sc_info *sc;
sc = i_dev->si_drv1;
mtx_lock(&sc->emu10kx_lock);
if (sc->emu10kx_isopen) {
mtx_unlock(&sc->emu10kx_lock);
return (EBUSY);
}
sc->emu10kx_isopen = 1;
mtx_unlock(&sc->emu10kx_lock);
if (sbuf_new(&sc->emu10kx_sbuf, NULL, 4096, 0) == NULL) {
error = ENXIO;
goto out;
}
sc->emu10kx_bufptr = 0;
error = (emu10kx_prepare(sc, &sc->emu10kx_sbuf) > 0) ? 0 : ENOMEM;
out:
if (error) {
mtx_lock(&sc->emu10kx_lock);
sc->emu10kx_isopen = 0;
mtx_unlock(&sc->emu10kx_lock);
}
return (error);
}
static int
emu10kx_close(struct cdev *i_dev, int flags __unused, int mode __unused, struct thread *td __unused)
{
struct emu_sc_info *sc;
sc = i_dev->si_drv1;
mtx_lock(&sc->emu10kx_lock);
if (!(sc->emu10kx_isopen)) {
mtx_unlock(&sc->emu10kx_lock);
return (EBADF);
}
sbuf_delete(&sc->emu10kx_sbuf);
sc->emu10kx_isopen = 0;
mtx_unlock(&sc->emu10kx_lock);
return (0);
}
static int
emu10kx_read(struct cdev *i_dev, struct uio *buf, int flag __unused)
{
int l, err;
struct emu_sc_info *sc;
sc = i_dev->si_drv1;
mtx_lock(&sc->emu10kx_lock);
if (!(sc->emu10kx_isopen)) {
mtx_unlock(&sc->emu10kx_lock);
return (EBADF);
}
mtx_unlock(&sc->emu10kx_lock);
l = min(buf->uio_resid, sbuf_len(&sc->emu10kx_sbuf) - sc->emu10kx_bufptr);
err = (l > 0) ? uiomove(sbuf_data(&sc->emu10kx_sbuf) + sc->emu10kx_bufptr, l, buf) : 0;
sc->emu10kx_bufptr += l;
return (err);
}
static int
emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s)
{
int i;
sbuf_printf(s, "FreeBSD EMU10Kx Audio Driver\n");
sbuf_printf(s, "\nHardware resource usage:\n");
sbuf_printf(s, "DSP General Purpose Registers: %d used, %d total\n", sc->rm->num_used, sc->rm->num_gprs);
sbuf_printf(s, "DSP Instruction Registers: %d used, %d total\n", sc->routing_code_end, sc->code_size);
sbuf_printf(s, "Card supports");
if (sc->has_ac97) {
sbuf_printf(s, " AC97 codec");
} else {
sbuf_printf(s, " NO AC97 codec");
}
if (sc->has_51) {
if (sc->has_71)
sbuf_printf(s, " and 7.1 output");
else
sbuf_printf(s, " and 5.1 output");
}
if (sc->is_emu10k1)
sbuf_printf(s, ", SBLive! DSP code");
if (sc->is_emu10k2)
sbuf_printf(s, ", Audigy DSP code");
if (sc->is_ca0102)
sbuf_printf(s, ", Audigy DSP code with Audigy2 hacks");
if (sc->is_ca0108)
sbuf_printf(s, ", Audigy DSP code with Audigy2Value hacks");
sbuf_printf(s, "\n");
if (sc->broken_digital)
sbuf_printf(s, "Digital mode unsupported\n");
sbuf_printf(s, "\nInstalled devices:\n");
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
for (i = 0; i < RT_COUNT; i++)
if (sc->pcm[i] != NULL)
if (device_is_attached(sc->pcm[i])) {
sbuf_printf(s, "%s on %s\n", device_get_desc(sc->pcm[i]), device_get_nameunit(sc->pcm[i]));
}
if (sc->midi[0] != NULL)
if (device_is_attached(sc->midi[0])) {
sbuf_printf(s, "EMU10Kx MIDI Interface\n");
sbuf_printf(s, "\tOn-card connector on %s\n", device_get_nameunit(sc->midi[0]));
}
if (sc->midi[1] != NULL)
if (device_is_attached(sc->midi[1])) {
sbuf_printf(s, "\tOn-Drive connector on %s\n", device_get_nameunit(sc->midi[1]));
}
if (sc->midi[0] != NULL)
if (device_is_attached(sc->midi[0])) {
sbuf_printf(s, "\tIR receiver MIDI events %s\n", sc->enable_ir ? "enabled" : "disabled");
}
sbuf_printf(s, "Card is in %s mode\n", (sc->mode == MODE_ANALOG) ? "analog" : "digital");
sbuf_finish(s);
return (sbuf_len(s));
}
/* INIT & UNINIT */
static int
emu10kx_dev_init(struct emu_sc_info *sc)
{
int unit;
mtx_init(&sc->emu10kx_lock, device_get_nameunit(sc->dev), "kxdevlock", 0);
unit = device_get_unit(sc->dev);
Sound Mega-commit. Expect further cleanup until code freeze. For a slightly thorough explaination, please refer to [1] http://people.freebsd.org/~ariff/SOUND_4.TXT.html . Summary of changes includes: 1 Volume Per-Channel (vpc). Provides private / standalone volume control unique per-stream pcm channel without touching master volume / pcm. Applications can directly use SNDCTL_DSP_[GET|SET][PLAY|REC]VOL, or for backwards compatibility, SOUND_MIXER_PCM through the opened dsp device instead of /dev/mixer. Special "bypass" mode is enabled through /dev/mixer which will automatically detect if the adjustment is made through /dev/mixer and forward its request to this private volume controller. Changes to this volume object will not interfere with other channels. Requirements: - SNDCTL_DSP_[GET|SET][PLAY|REC]_VOL are newer ioctls (OSSv4) which require specific application modifications (preferred). - No modifications required for using bypass mode, so applications like mplayer or xmms should work out of the box. Kernel hints: - hint.pcm.%d.vpc (0 = disable vpc). Kernel sysctls: - hw.snd.vpc_mixer_bypass (default: 1). Enable or disable /dev/mixer bypass mode. - hw.snd.vpc_autoreset (default: 1). By default, closing/opening /dev/dsp will reset the volume back to 0 db gain/attenuation. Setting this to 0 will preserve its settings across device closing/opening. - hw.snd.vpc_reset (default: 0). Panic/reset button to reset all volume settings back to 0 db. - hw.snd.vpc_0db (default: 45). 0 db relative to linear mixer value. 2 High quality fixed-point Bandlimited SINC sampling rate converter, based on Julius O'Smith's Digital Audio Resampling - http://ccrma.stanford.edu/~jos/resample/. It includes a filter design script written in awk (the clumsiest joke I've ever written) - 100% 32bit fixed-point, 64bit accumulator. - Possibly among the fastest (if not fastest) of its kind. - Resampling quality is tunable, either runtime or during kernel compilation (FEEDER_RATE_PRESETS). - Quality can be further customized during kernel compilation by defining FEEDER_RATE_PRESETS in /etc/make.conf. Kernel sysctls: - hw.snd.feeder_rate_quality. 0 - Zero-order Hold (ZOH). Fastest, bad quality. 1 - Linear Interpolation (LINEAR). Slightly slower than ZOH, better quality but still does not eliminate aliasing. 2 - (and above) - Sinc Interpolation(SINC). Best quality. SINC quality always start from 2 and above. Rough quality comparisons: - http://people.freebsd.org/~ariff/z_comparison/ 3 Bit-perfect mode. Bypasses all feeder/dsp effects. Pure sound will be directly fed into the hardware. 4 Parametric (compile time) Software Equalizer (Bass/Treble mixer). Can be customized by defining FEEDER_EQ_PRESETS in /etc/make.conf. 5 Transparent/Adaptive Virtual Channel. Now you don't have to disable vchans in order to make digital format pass through. It also makes vchans more dynamic by choosing a better format/rate among all the concurrent streams, which means that dev.pcm.X.play.vchanformat/rate becomes sort of optional. 6 Exclusive Stream, with special open() mode O_EXCL. This will "mute" other concurrent vchan streams and only allow a single channel with O_EXCL set to keep producing sound. Other Changes: * most feeder_* stuffs are compilable in userland. Let's not speculate whether we should go all out for it (save that for FreeBSD 16.0-RELEASE). * kobj signature fixups, thanks to Andriy Gapon <avg@freebsd.org> * pull out channel mixing logic out of vchan.c and create its own feeder_mixer for world justice. * various refactoring here and there, for good or bad. * activation of few more OSSv4 ioctls() (see [1] above). * opt_snd.h for possible compile time configuration: (mostly for debugging purposes, don't try these at home) SND_DEBUG SND_DIAGNOSTIC SND_FEEDER_MULTIFORMAT SND_FEEDER_FULL_MULTIFORMAT SND_FEEDER_RATE_HP SND_PCM_64 SND_OLDSTEREO Manual page updates are on the way. Tested by: joel, Olivier SMEDTS <olivier at gid0 d org>, too many unsung / unnamed heroes.
2009-06-07 19:12:08 +00:00
sc->cdev = make_dev(&emu10kx_cdevsw, PCMMINOR(unit), UID_ROOT, GID_WHEEL, 0640, "emu10kx%d", unit);
if (sc->cdev != NULL) {
sc->cdev->si_drv1 = sc;
return (0);
}
return (ENXIO);
}
static int
emu10kx_dev_uninit(struct emu_sc_info *sc)
{
mtx_lock(&sc->emu10kx_lock);
if (sc->emu10kx_isopen) {
mtx_unlock(&sc->emu10kx_lock);
return (EBUSY);
}
if (sc->cdev)
destroy_dev(sc->cdev);
sc->cdev = NULL;
mtx_destroy(&sc->emu10kx_lock);
return (0);
}
/* resource manager */
int
emu_rm_init(struct emu_sc_info *sc)
{
int i;
int maxcount;
struct emu_rm *rm;
rm = malloc(sizeof(struct emu_rm), M_DEVBUF, M_NOWAIT | M_ZERO);
if (rm == NULL) {
return (ENOMEM);
}
sc->rm = rm;
rm->card = sc;
maxcount = sc->num_gprs;
rm->num_used = 0;
mtx_init(&(rm->gpr_lock), device_get_nameunit(sc->dev), "gpr alloc", MTX_DEF);
rm->num_gprs = (maxcount < EMU_MAX_GPR ? maxcount : EMU_MAX_GPR);
for (i = 0; i < rm->num_gprs; i++)
rm->allocmap[i] = 0;
/* pre-allocate gpr[0] */
rm->allocmap[0] = 1;
rm->last_free_gpr = 1;
return (0);
}
int
emu_rm_uninit(struct emu_sc_info *sc)
{
int i;
if (sc->dbg_level > 1) {
mtx_lock(&(sc->rm->gpr_lock));
for (i = 1; i < sc->rm->last_free_gpr; i++)
if (sc->rm->allocmap[i] > 0)
device_printf(sc->dev, "rm: gpr %d not free before uninit\n", i);
mtx_unlock(&(sc->rm->gpr_lock));
}
mtx_destroy(&(sc->rm->gpr_lock));
free(sc->rm, M_DEVBUF);
return (0);
}
static int
emu_rm_gpr_alloc(struct emu_rm *rm, int count)
{
int i, j;
int allocated_gpr;
allocated_gpr = rm->num_gprs;
/* try fast way first */
mtx_lock(&(rm->gpr_lock));
if (rm->last_free_gpr + count <= rm->num_gprs) {
allocated_gpr = rm->last_free_gpr;
rm->last_free_gpr += count;
rm->allocmap[allocated_gpr] = count;
for (i = 1; i < count; i++)
rm->allocmap[allocated_gpr + i] = -(count - i);
} else {
/* longer */
i = 0;
allocated_gpr = rm->num_gprs;
while (i < rm->last_free_gpr - count) {
if (rm->allocmap[i] > 0) {
i += rm->allocmap[i];
} else {
allocated_gpr = i;
for (j = 1; j < count; j++) {
if (rm->allocmap[i + j] != 0)
allocated_gpr = rm->num_gprs;
}
if (allocated_gpr == i)
break;
}
}
if (allocated_gpr + count < rm->last_free_gpr) {
rm->allocmap[allocated_gpr] = count;
for (i = 1; i < count; i++)
rm->allocmap[allocated_gpr + i] = -(count - i);
}
}
if (allocated_gpr == rm->num_gprs)
allocated_gpr = (-1);
if (allocated_gpr >= 0)
rm->num_used += count;
mtx_unlock(&(rm->gpr_lock));
return (allocated_gpr);
}
/* mixer */
void
emumix_set_mode(struct emu_sc_info *sc, int mode)
{
uint32_t a_iocfg;
uint32_t hcfg;
uint32_t tmp;
switch (mode) {
case MODE_DIGITAL:
/* FALLTHROUGH */
case MODE_ANALOG:
break;
default:
return;
}
hcfg = EMU_HCFG_AUDIOENABLE | EMU_HCFG_AUTOMUTE;
a_iocfg = 0;
if (sc->rev >= 6)
hcfg |= EMU_HCFG_JOYENABLE;
if (sc->is_emu10k1)
hcfg |= EMU_HCFG_LOCKTANKCACHE_MASK;
else
hcfg |= EMU_HCFG_CODECFMT_I2S | EMU_HCFG_JOYENABLE;
if (mode == MODE_DIGITAL) {
if (sc->broken_digital) {
device_printf(sc->dev, "Digital mode is reported as broken on this card.\n");
}
a_iocfg |= EMU_A_IOCFG_GPOUT1;
hcfg |= EMU_HCFG_GPOUT0;
}
if (mode == MODE_ANALOG)
emumix_set_spdif_mode(sc, SPDIF_MODE_PCM);
if (sc->is_emu10k2)
a_iocfg |= 0x80; /* XXX */
if ((sc->is_ca0102) || (sc->is_ca0108))
/*
* Setting EMU_A_IOCFG_DISABLE_ANALOG will do opposite things
* on diffrerent cards.
* "don't disable analog outs" on Audigy 2 (ca0102/ca0108)
* "disable analog outs" on Audigy (emu10k2)
*/
a_iocfg |= EMU_A_IOCFG_DISABLE_ANALOG;
if (sc->is_ca0108)
a_iocfg |= 0x20; /* XXX */
/* Mute analog center & subwoofer before mode change */
if (mode == MODE_DIGITAL)
emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 1);
emu_wr(sc, EMU_HCFG, hcfg, 4);
if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
tmp = emu_rd(sc, EMU_A_IOCFG, 2);
tmp = a_iocfg;
emu_wr(sc, EMU_A_IOCFG, tmp, 2);
}
/* Unmute if we have changed mode to analog. */
if (mode == MODE_ANALOG)
emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 0);
sc->mode = mode;
}
void
emumix_set_spdif_mode(struct emu_sc_info *sc, int mode)
{
uint32_t spcs;
switch (mode) {
case SPDIF_MODE_PCM:
break;
case SPDIF_MODE_AC3:
device_printf(sc->dev, "AC3 mode does not work and disabled\n");
return;
default:
return;
}
spcs = EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 |
EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC |
EMU_SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 |
EMU_SPCS_EMPHASIS_NONE | EMU_SPCS_COPYRIGHT;
mode = SPDIF_MODE_PCM;
emu_wrptr(sc, 0, EMU_SPCS0, spcs);
emu_wrptr(sc, 0, EMU_SPCS1, spcs);
emu_wrptr(sc, 0, EMU_SPCS2, spcs);
}
#define L2L_POINTS 10
static int l2l_df[L2L_POINTS] = {
0x572C5CA, /* 100..90 */
0x3211625, /* 90..80 */
0x1CC1A76, /* 80..70 */
0x108428F, /* 70..60 */
0x097C70A, /* 60..50 */
0x0572C5C, /* 50..40 */
0x0321162, /* 40..30 */
0x01CC1A7, /* 30..20 */
0x0108428, /* 20..10 */
0x016493D /* 10..0 */
};
static int l2l_f[L2L_POINTS] = {
0x4984461A, /* 90 */
0x2A3968A7, /* 80 */
0x18406003, /* 70 */
0x0DEDC66D, /* 60 */
0x07FFFFFF, /* 50 */
0x04984461, /* 40 */
0x02A3968A, /* 30 */
0x01840600, /* 20 */
0x00DEDC66, /* 10 */
0x00000000 /* 0 */
};
static int
log2lin(int log_t)
{
int lin_t;
int idx, lin;
if (log_t <= 0) {
lin_t = 0x00000000;
return (lin_t);
}
if (log_t >= 100) {
lin_t = 0x7fffffff;
return (lin_t);
}
idx = (L2L_POINTS - 1) - log_t / (L2L_POINTS);
lin = log_t % (L2L_POINTS);
lin_t = l2l_df[idx] * lin + l2l_f[idx];
return (lin_t);
}
void
emumix_set_fxvol(struct emu_sc_info *sc, unsigned gpr, int32_t vol)
{
vol = log2lin(vol);
emumix_set_gpr(sc, gpr, vol);
}
void
emumix_set_gpr(struct emu_sc_info *sc, unsigned gpr, int32_t val)
{
if (sc->dbg_level > 1)
if (gpr == 0) {
device_printf(sc->dev, "Zero gpr write access\n");
#ifdef KDB
kdb_backtrace();
#endif
return;
}
emu_wrptr(sc, 0, GPR(gpr), val);
}
void
emumix_set_volume(struct emu_sc_info *sc, int mixer_idx, int volume)
{
RANGE(volume, 0, 100);
if (mixer_idx < NUM_MIXERS) {
sc->mixer_volcache[mixer_idx] = volume;
emumix_set_fxvol(sc, sc->mixer_gpr[mixer_idx], volume);
}
}
int
emumix_get_volume(struct emu_sc_info *sc, int mixer_idx)
{
if ((mixer_idx < NUM_MIXERS) && (mixer_idx >= 0))
return (sc->mixer_volcache[mixer_idx]);
return (-1);
}
/* Init CardBus part */
static int
emu_cardbus_init(struct emu_sc_info *sc)
{
/*
* XXX May not need this if we have EMU_IPR3 handler.
* Is it a real init calls, or EMU_IPR3 interrupt acknowledgments?
* Looks much like "(data << 16) | register".
*/
emu_wr_cbptr(sc, (0x00d0 << 16) | 0x0000);
emu_wr_cbptr(sc, (0x00d0 << 16) | 0x0001);
emu_wr_cbptr(sc, (0x00d0 << 16) | 0x005f);
emu_wr_cbptr(sc, (0x00d0 << 16) | 0x007f);
emu_wr_cbptr(sc, (0x0090 << 16) | 0x007f);
return (0);
}
/* Probe and attach the card */
static int
emu_init(struct emu_sc_info *sc)
{
uint32_t ch, tmp;
uint32_t spdif_sr;
uint32_t ac97slot;
int def_mode;
int i;
/* disable audio and lock cache */
emu_wr(sc, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE, 4);
/* reset recording buffers */
emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
emu_wrptr(sc, 0, EMU_MICBA, 0);
emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
emu_wrptr(sc, 0, EMU_FXBA, 0);
emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
emu_wrptr(sc, 0, EMU_ADCBA, 0);
/* disable channel interrupt */
emu_wr(sc, EMU_INTE, EMU_INTE_INTERTIMERENB | EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE, 4);
emu_wrptr(sc, 0, EMU_CLIEL, 0);
emu_wrptr(sc, 0, EMU_CLIEH, 0);
emu_wrptr(sc, 0, EMU_SOLEL, 0);
emu_wrptr(sc, 0, EMU_SOLEH, 0);
/* disable P16V and S/PDIF interrupts */
if ((sc->is_ca0102) || (sc->is_ca0108))
emu_wr(sc, EMU_INTE2, 0, 4);
if (sc->is_ca0102)
emu_wr(sc, EMU_INTE3, 0, 4);
/* init phys inputs and outputs */
ac97slot = 0;
if (sc->has_51)
ac97slot = EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE;
if (sc->has_71)
ac97slot = EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE | EMU_AC97SLOT_REAR_LEFT | EMU_AC97SLOT_REAR_RIGHT;
if (sc->is_emu10k2)
ac97slot |= 0x40;
emu_wrptr(sc, 0, EMU_AC97SLOT, ac97slot);
if (sc->is_emu10k2) /* XXX for later cards? */
emu_wrptr(sc, 0, EMU_SPBYPASS, 0xf00); /* What will happen if
* we write 1 here? */
if (bus_dma_tag_create( /* parent */ bus_get_dma_tag(sc->dev),
/* alignment */ 2, /* boundary */ 0,
/* lowaddr */ (1U << 31) - 1, /* can only access 0-2gb */
/* highaddr */ BUS_SPACE_MAXADDR,
/* filter */ NULL, /* filterarg */ NULL,
/* maxsize */ EMU_MAX_BUFSZ, /* nsegments */ 1, /* maxsegz */ 0x3ffff,
/* flags */ 0, /* lockfunc */ busdma_lock_mutex,
/* lockarg */ &Giant, &(sc->mem.dmat)) != 0) {
device_printf(sc->dev, "unable to create dma tag\n");
bus_dma_tag_destroy(sc->mem.dmat);
return (ENOMEM);
}
sc->mem.card = sc;
SLIST_INIT(&sc->mem.blocks);
sc->mem.ptb_pages = emu_malloc(&sc->mem, EMU_MAXPAGES * sizeof(uint32_t), &sc->mem.ptb_pages_addr, &sc->mem.ptb_map);
if (sc->mem.ptb_pages == NULL)
return (ENOMEM);
sc->mem.silent_page = emu_malloc(&sc->mem, EMUPAGESIZE, &sc->mem.silent_page_addr, &sc->mem.silent_map);
if (sc->mem.silent_page == NULL) {
emu_free(&sc->mem, sc->mem.ptb_pages, sc->mem.ptb_map);
return (ENOMEM);
}
/* Clear page with silence & setup all pointers to this page */
bzero(sc->mem.silent_page, EMUPAGESIZE);
tmp = (uint32_t) (sc->mem.silent_page_addr) << 1;
for (i = 0; i < EMU_MAXPAGES; i++)
sc->mem.ptb_pages[i] = tmp | i;
for (ch = 0; ch < NUM_G; ch++) {
emu_wrptr(sc, ch, EMU_CHAN_MAPA, tmp | EMU_CHAN_MAP_PTI_MASK);
emu_wrptr(sc, ch, EMU_CHAN_MAPB, tmp | EMU_CHAN_MAP_PTI_MASK);
}
emu_wrptr(sc, 0, EMU_PTB, (sc->mem.ptb_pages_addr));
emu_wrptr(sc, 0, EMU_TCB, 0); /* taken from original driver */
emu_wrptr(sc, 0, EMU_TCBS, 0); /* taken from original driver */
/* init envelope engine */
for (ch = 0; ch < NUM_G; ch++) {
emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, 0);
emu_wrptr(sc, ch, EMU_CHAN_IP, 0);
emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0xffff);
emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0xffff);
emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
emu_wrptr(sc, ch, EMU_CHAN_CCR, 0);
emu_wrptr(sc, ch, EMU_CHAN_PSST, 0);
emu_wrptr(sc, ch, EMU_CHAN_DSL, 0x10);
emu_wrptr(sc, ch, EMU_CHAN_CCCA, 0);
emu_wrptr(sc, ch, EMU_CHAN_Z1, 0);
emu_wrptr(sc, ch, EMU_CHAN_Z2, 0);
emu_wrptr(sc, ch, EMU_CHAN_FXRT, 0xd01c0000);
emu_wrptr(sc, ch, EMU_CHAN_ATKHLDM, 0);
emu_wrptr(sc, ch, EMU_CHAN_DCYSUSM, 0);
emu_wrptr(sc, ch, EMU_CHAN_IFATN, 0xffff);
emu_wrptr(sc, ch, EMU_CHAN_PEFE, 0);
emu_wrptr(sc, ch, EMU_CHAN_FMMOD, 0);
emu_wrptr(sc, ch, EMU_CHAN_TREMFRQ, 24); /* 1 Hz */
emu_wrptr(sc, ch, EMU_CHAN_FM2FRQ2, 24); /* 1 Hz */
emu_wrptr(sc, ch, EMU_CHAN_TEMPENV, 0);
/*** these are last so OFF prevents writing ***/
emu_wrptr(sc, ch, EMU_CHAN_LFOVAL2, 0);
emu_wrptr(sc, ch, EMU_CHAN_LFOVAL1, 0);
emu_wrptr(sc, ch, EMU_CHAN_ATKHLDV, 0);
emu_wrptr(sc, ch, EMU_CHAN_ENVVOL, 0);
emu_wrptr(sc, ch, EMU_CHAN_ENVVAL, 0);
if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
emu_wrptr(sc, ch, 0x4c, 0x0);
emu_wrptr(sc, ch, 0x4d, 0x0);
emu_wrptr(sc, ch, 0x4e, 0x0);
emu_wrptr(sc, ch, 0x4f, 0x0);
emu_wrptr(sc, ch, EMU_A_CHAN_FXRT1, 0x3f3f3f3f);
emu_wrptr(sc, ch, EMU_A_CHAN_FXRT2, 0x3f3f3f3f);
emu_wrptr(sc, ch, EMU_A_CHAN_SENDAMOUNTS, 0x0);
}
}
emumix_set_spdif_mode(sc, SPDIF_MODE_PCM);
if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108))
emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, EMU_A_SPDIF_48000);
/*
* CAxxxx cards needs additional setup:
* 1. Set I2S capture sample rate to 96000
* 2. Disable P16v / P17v proceesing
* 3. Allow EMU10K DSP inputs
*/
if ((sc->is_ca0102) || (sc->is_ca0108)) {
spdif_sr = emu_rdptr(sc, 0, EMU_A_SPDIF_SAMPLERATE);
spdif_sr &= 0xfffff1ff;
spdif_sr |= EMU_A_I2S_CAPTURE_96000;
emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, spdif_sr);
/* Disable P16v processing */
emu_wr_p16vptr(sc, 0, EMU_A2_SRCSel, 0x14);
/* Setup P16v/P17v sound routing */
if (sc->is_ca0102)
emu_wr_p16vptr(sc, 0, EMU_A2_SRCMULTI_ENABLE, 0xFF00FF00);
else {
emu_wr_p16vptr(sc, 0, EMU_A2_MIXER_I2S_ENABLE, 0xFF000000);
emu_wr_p16vptr(sc, 0, EMU_A2_MIXER_SPDIF_ENABLE, 0xFF000000);
tmp = emu_rd(sc, EMU_A_IOCFG, 2);
emu_wr(sc, EMU_A_IOCFG, tmp & ~0x8, 2);
}
}
emu_initefx(sc);
def_mode = MODE_ANALOG;
if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108))
def_mode = MODE_DIGITAL;
if (((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) && (sc->broken_digital)) {
device_printf(sc->dev, "Audigy card initialized in analog mode.\n");
def_mode = MODE_ANALOG;
}
emumix_set_mode(sc, def_mode);
if (bootverbose) {
tmp = emu_rd(sc, EMU_HCFG, 4);
device_printf(sc->dev, "Card Configuration ( 0x%08x )\n", tmp);
device_printf(sc->dev, "Card Configuration ( & 0xff000000 ) : %s%s%s%s%s%s%s%s\n",
(tmp & 0x80000000 ? "[Legacy MPIC] " : ""),
(tmp & 0x40000000 ? "[0x40] " : ""),
(tmp & 0x20000000 ? "[0x20] " : ""),
(tmp & 0x10000000 ? "[0x10] " : ""),
(tmp & 0x08000000 ? "[0x08] " : ""),
(tmp & 0x04000000 ? "[0x04] " : ""),
(tmp & 0x02000000 ? "[0x02] " : ""),
(tmp & 0x01000000 ? "[0x01]" : " "));
device_printf(sc->dev, "Card Configuration ( & 0x00ff0000 ) : %s%s%s%s%s%s%s%s\n",
(tmp & 0x00800000 ? "[0x80] " : ""),
(tmp & 0x00400000 ? "[0x40] " : ""),
(tmp & 0x00200000 ? "[Legacy INT] " : ""),
(tmp & 0x00100000 ? "[0x10] " : ""),
(tmp & 0x00080000 ? "[0x08] " : ""),
(tmp & 0x00040000 ? "[Codec4] " : ""),
(tmp & 0x00020000 ? "[Codec2] " : ""),
(tmp & 0x00010000 ? "[I2S Codec]" : " "));
device_printf(sc->dev, "Card Configuration ( & 0x0000ff00 ) : %s%s%s%s%s%s%s%s\n",
(tmp & 0x00008000 ? "[0x80] " : ""),
(tmp & 0x00004000 ? "[GPINPUT0] " : ""),
(tmp & 0x00002000 ? "[GPINPUT1] " : ""),
(tmp & 0x00001000 ? "[GPOUT0] " : ""),
(tmp & 0x00000800 ? "[GPOUT1] " : ""),
(tmp & 0x00000400 ? "[GPOUT2] " : ""),
(tmp & 0x00000200 ? "[Joystick] " : ""),
(tmp & 0x00000100 ? "[0x01]" : " "));
device_printf(sc->dev, "Card Configuration ( & 0x000000ff ) : %s%s%s%s%s%s%s%s\n",
(tmp & 0x00000080 ? "[0x80] " : ""),
(tmp & 0x00000040 ? "[0x40] " : ""),
(tmp & 0x00000020 ? "[0x20] " : ""),
(tmp & 0x00000010 ? "[AUTOMUTE] " : ""),
(tmp & 0x00000008 ? "[LOCKSOUNDCACHE] " : ""),
(tmp & 0x00000004 ? "[LOCKTANKCACHE] " : ""),
(tmp & 0x00000002 ? "[MUTEBUTTONENABLE] " : ""),
(tmp & 0x00000001 ? "[AUDIOENABLE]" : " "));
if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
tmp = emu_rd(sc, EMU_A_IOCFG, 2);
device_printf(sc->dev, "Audigy Card Configuration ( 0x%04x )\n", tmp);
device_printf(sc->dev, "Audigy Card Configuration ( & 0xff00 )");
printf(" : %s%s%s%s%s%s%s%s\n",
(tmp & 0x8000 ? "[Rear Speakers] " : ""),
(tmp & 0x4000 ? "[Front Speakers] " : ""),
(tmp & 0x2000 ? "[0x20] " : ""),
(tmp & 0x1000 ? "[0x10] " : ""),
(tmp & 0x0800 ? "[0x08] " : ""),
(tmp & 0x0400 ? "[0x04] " : ""),
(tmp & 0x0200 ? "[0x02] " : ""),
(tmp & 0x0100 ? "[AudigyDrive Phones]" : " "));
device_printf(sc->dev, "Audigy Card Configuration ( & 0x00ff )");
printf(" : %s%s%s%s%s%s%s%s\n",
(tmp & 0x0080 ? "[0x80] " : ""),
(tmp & 0x0040 ? "[Mute AnalogOut] " : ""),
(tmp & 0x0020 ? "[0x20] " : ""),
(tmp & 0x0010 ? "[0x10] " : ""),
(tmp & 0x0008 ? "[0x08] " : ""),
(tmp & 0x0004 ? "[GPOUT0] " : ""),
(tmp & 0x0002 ? "[GPOUT1] " : ""),
(tmp & 0x0001 ? "[GPOUT2]" : " "));
} /* is_emu10k2 or ca* */
} /* bootverbose */
return (0);
}
static int
emu_uninit(struct emu_sc_info *sc)
{
uint32_t ch;
struct emu_memblk *blk;
emu_wr(sc, EMU_INTE, 0, 4);
for (ch = 0; ch < NUM_G; ch++)
emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, 0);
for (ch = 0; ch < NUM_G; ch++) {
emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0);
emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0);
emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
}
/* disable audio and lock cache */
emu_wr(sc, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE, 4);
emu_wrptr(sc, 0, EMU_PTB, 0);
/* reset recording buffers */
emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
emu_wrptr(sc, 0, EMU_MICBA, 0);
emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
emu_wrptr(sc, 0, EMU_FXBA, 0);
emu_wrptr(sc, 0, EMU_FXWC, 0);
emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
emu_wrptr(sc, 0, EMU_ADCBA, 0);
emu_wrptr(sc, 0, EMU_TCB, 0);
emu_wrptr(sc, 0, EMU_TCBS, 0);
/* disable channel interrupt */
emu_wrptr(sc, 0, EMU_CLIEL, 0);
emu_wrptr(sc, 0, EMU_CLIEH, 0);
emu_wrptr(sc, 0, EMU_SOLEL, 0);
emu_wrptr(sc, 0, EMU_SOLEH, 0);
if (!SLIST_EMPTY(&sc->mem.blocks))
device_printf(sc->dev, "warning: memblock list not empty\n");
SLIST_FOREACH(blk, &sc->mem.blocks, link)
if (blk != NULL)
device_printf(sc->dev, "lost %d for %s\n", blk->pte_size, blk->owner);
emu_free(&sc->mem, sc->mem.ptb_pages, sc->mem.ptb_map);
emu_free(&sc->mem, sc->mem.silent_page, sc->mem.silent_map);
return (0);
}
static int
emu_read_ivar(device_t bus, device_t dev, int ivar_index, uintptr_t * result)
{
struct sndcard_func *func = device_get_ivars(dev);
struct emu_sc_info *sc = device_get_softc(bus);
if (func==NULL)
return (ENOMEM);
if (sc == NULL)
return (ENOMEM);
switch (ivar_index) {
case EMU_VAR_FUNC:
*result = func->func;
break;
case EMU_VAR_ROUTE:
if (func->varinfo == NULL)
return (ENOMEM);
*result = ((struct emu_pcminfo *)func->varinfo)->route;
break;
case EMU_VAR_ISEMU10K1:
*result = sc->is_emu10k1;
break;
case EMU_VAR_MCH_DISABLED:
*result = sc->mch_disabled;
break;
case EMU_VAR_MCH_REC:
*result = sc->mch_rec;
break;
default:
return (ENOENT);
}
return (0);
}
static int
emu_write_ivar(device_t bus __unused, device_t dev __unused,
int ivar_index, uintptr_t value __unused)
{
switch (ivar_index) {
case 0:
return (EINVAL);
default:
return (ENOENT);
}
}
static int
emu_pci_probe(device_t dev)
{
struct sbuf *s;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
unsigned int thiscard = 0;
uint16_t vendor;
vendor = pci_read_config(dev, PCIR_DEVVENDOR, /* bytes */ 2);
if (vendor != 0x1102)
return (ENXIO); /* Not Creative */
thiscard = emu_getcard(dev);
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
if (thiscard == 0)
return (ENXIO);
s = sbuf_new(NULL, NULL, 4096, 0);
if (s == NULL)
return (ENOMEM);
sbuf_printf(s, "Creative %s [%s]", emu_cards[thiscard].desc, emu_cards[thiscard].SBcode);
sbuf_finish(s);
device_set_desc_copy(dev, sbuf_data(s));
sbuf_delete(s);
return (BUS_PROBE_DEFAULT);
}
static int
emu_pci_attach(device_t dev)
{
struct sndcard_func *func;
struct emu_sc_info *sc;
struct emu_pcminfo *pcminfo;
#if 0
struct emu_midiinfo *midiinfo;
#endif
int i;
int device_flags;
char status[255];
int error = ENXIO;
int unit;
sc = device_get_softc(dev);
unit = device_get_unit(dev);
/* Get configuration */
sc->ctx = device_get_sysctl_ctx(dev);
if (sc->ctx == NULL)
goto bad;
sc->root = device_get_sysctl_tree(dev);
if (sc->root == NULL)
goto bad;
if (resource_int_value("emu10kx", unit, "multichannel_disabled", &(sc->mch_disabled)))
RANGE(sc->mch_disabled, 0, 1);
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "multichannel_disabled", CTLFLAG_RD, &(sc->mch_disabled), 0, "Multichannel playback setting");
if (resource_int_value("emu10kx", unit, "multichannel_recording", &(sc->mch_rec)))
RANGE(sc->mch_rec, 0, 1);
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "multichannel_recording", CTLFLAG_RD, &(sc->mch_rec), 0, "Multichannel recording setting");
if (resource_int_value("emu10kx", unit, "debug", &(sc->dbg_level)))
RANGE(sc->mch_rec, 0, 2);
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "debug", CTLFLAG_RW, &(sc->dbg_level), 0, "Debug level");
/* Fill in the softc. */
mtx_init(&sc->lock, device_get_nameunit(dev), "bridge conf", MTX_DEF);
mtx_init(&sc->rw, device_get_nameunit(dev), "exclusive io", MTX_DEF);
sc->dev = dev;
sc->type = pci_get_devid(dev);
sc->rev = pci_get_revid(dev);
sc->enable_ir = 0;
sc->has_ac97 = 0;
sc->has_51 = 0;
sc->has_71 = 0;
sc->broken_digital = 0;
sc->is_emu10k1 = 0;
sc->is_emu10k2 = 0;
sc->is_ca0102 = 0;
sc->is_ca0108 = 0;
sc->is_cardbus = 0;
device_flags = emu_cards[emu_getcard(dev)].flags;
if (device_flags & HAS_51)
sc->has_51 = 1;
if (device_flags & HAS_71) {
sc->has_51 = 1;
sc->has_71 = 1;
}
if (device_flags & IS_EMU10K1)
sc->is_emu10k1 = 1;
if (device_flags & IS_EMU10K2)
sc->is_emu10k2 = 1;
if (device_flags & IS_CA0102)
sc->is_ca0102 = 1;
if (device_flags & IS_CA0108)
sc->is_ca0108 = 1;
if ((sc->is_emu10k2) && (sc->rev == 4)) {
sc->is_emu10k2 = 0;
sc->is_ca0102 = 1; /* for unknown Audigy 2 cards */
}
if ((sc->is_ca0102 == 1) || (sc->is_ca0108 == 1))
if (device_flags & IS_CARDBUS)
sc->is_cardbus = 1;
if ((sc->is_emu10k1 + sc->is_emu10k2 + sc->is_ca0102 + sc->is_ca0108) != 1) {
device_printf(sc->dev, "Unable to detect HW chipset\n");
goto bad;
}
if (device_flags & BROKEN_DIGITAL)
sc->broken_digital = 1;
if (device_flags & HAS_AC97)
sc->has_ac97 = 1;
sc->opcode_shift = 0;
if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
sc->opcode_shift = 24;
sc->high_operand_shift = 12;
/* DSP map */
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
/* sc->fx_base = 0x0 */
sc->input_base = 0x40;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
/* sc->p16vinput_base = 0x50; */
sc->output_base = 0x60;
sc->efxc_base = 0x80;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
/* sc->output32h_base = 0xa0; */
/* sc->output32l_base = 0xb0; */
sc->dsp_zero = 0xc0;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
/* 0xe0...0x100 are unknown */
/* sc->tram_base = 0x200 */
/* sc->tram_addr_base = 0x300 */
sc->gpr_base = EMU_A_FXGPREGBASE;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
sc->num_gprs = 0x200;
sc->code_base = EMU_A_MICROCODEBASE;
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
sc->code_size = 0x800 / 2; /* 0x600-0xdff, 2048 words,
* 1024 instructions */
sc->mchannel_fx = 8;
sc->num_fxbuses = 16;
sc->num_inputs = 8;
sc->num_outputs = 16;
sc->address_mask = EMU_A_PTR_ADDR_MASK;
}
if (sc->is_emu10k1) {
sc->has_51 = 0; /* We don't support 5.1 sound on SB Live! 5.1 */
sc->opcode_shift = 20;
sc->high_operand_shift = 10;
sc->code_base = EMU_MICROCODEBASE;
sc->code_size = 0x400 / 2; /* 0x400-0x7ff, 1024 words,
* 512 instructions */
sc->gpr_base = EMU_FXGPREGBASE;
sc->num_gprs = 0x100;
sc->input_base = 0x10;
sc->output_base = 0x20;
/*
* XXX 5.1 Analog outputs are inside efxc address space!
2012-11-07 07:00:59 +00:00
* They use output+0x11/+0x12 (=efxc+1/+2).
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
* Don't use this efx registers for recording on SB Live! 5.1!
*/
sc->efxc_base = 0x30;
sc->dsp_zero = 0x40;
sc->mchannel_fx = 0;
sc->num_fxbuses = 8;
sc->num_inputs = 8;
sc->num_outputs = 16;
sc->address_mask = EMU_PTR_ADDR_MASK;
}
if (sc->opcode_shift == 0)
goto bad;
pci_enable_busmaster(dev);
i = PCIR_BAR(0);
sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &i, RF_ACTIVE);
if (sc->reg == NULL) {
device_printf(dev, "unable to map register space\n");
goto bad;
}
sc->st = rman_get_bustag(sc->reg);
sc->sh = rman_get_bushandle(sc->reg);
for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
sc->timer[i] = 0; /* disable it */
i = 0;
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE | RF_SHAREABLE);
Sound Mega-commit. Expect further cleanup until code freeze. For a slightly thorough explaination, please refer to [1] http://people.freebsd.org/~ariff/SOUND_4.TXT.html . Summary of changes includes: 1 Volume Per-Channel (vpc). Provides private / standalone volume control unique per-stream pcm channel without touching master volume / pcm. Applications can directly use SNDCTL_DSP_[GET|SET][PLAY|REC]VOL, or for backwards compatibility, SOUND_MIXER_PCM through the opened dsp device instead of /dev/mixer. Special "bypass" mode is enabled through /dev/mixer which will automatically detect if the adjustment is made through /dev/mixer and forward its request to this private volume controller. Changes to this volume object will not interfere with other channels. Requirements: - SNDCTL_DSP_[GET|SET][PLAY|REC]_VOL are newer ioctls (OSSv4) which require specific application modifications (preferred). - No modifications required for using bypass mode, so applications like mplayer or xmms should work out of the box. Kernel hints: - hint.pcm.%d.vpc (0 = disable vpc). Kernel sysctls: - hw.snd.vpc_mixer_bypass (default: 1). Enable or disable /dev/mixer bypass mode. - hw.snd.vpc_autoreset (default: 1). By default, closing/opening /dev/dsp will reset the volume back to 0 db gain/attenuation. Setting this to 0 will preserve its settings across device closing/opening. - hw.snd.vpc_reset (default: 0). Panic/reset button to reset all volume settings back to 0 db. - hw.snd.vpc_0db (default: 45). 0 db relative to linear mixer value. 2 High quality fixed-point Bandlimited SINC sampling rate converter, based on Julius O'Smith's Digital Audio Resampling - http://ccrma.stanford.edu/~jos/resample/. It includes a filter design script written in awk (the clumsiest joke I've ever written) - 100% 32bit fixed-point, 64bit accumulator. - Possibly among the fastest (if not fastest) of its kind. - Resampling quality is tunable, either runtime or during kernel compilation (FEEDER_RATE_PRESETS). - Quality can be further customized during kernel compilation by defining FEEDER_RATE_PRESETS in /etc/make.conf. Kernel sysctls: - hw.snd.feeder_rate_quality. 0 - Zero-order Hold (ZOH). Fastest, bad quality. 1 - Linear Interpolation (LINEAR). Slightly slower than ZOH, better quality but still does not eliminate aliasing. 2 - (and above) - Sinc Interpolation(SINC). Best quality. SINC quality always start from 2 and above. Rough quality comparisons: - http://people.freebsd.org/~ariff/z_comparison/ 3 Bit-perfect mode. Bypasses all feeder/dsp effects. Pure sound will be directly fed into the hardware. 4 Parametric (compile time) Software Equalizer (Bass/Treble mixer). Can be customized by defining FEEDER_EQ_PRESETS in /etc/make.conf. 5 Transparent/Adaptive Virtual Channel. Now you don't have to disable vchans in order to make digital format pass through. It also makes vchans more dynamic by choosing a better format/rate among all the concurrent streams, which means that dev.pcm.X.play.vchanformat/rate becomes sort of optional. 6 Exclusive Stream, with special open() mode O_EXCL. This will "mute" other concurrent vchan streams and only allow a single channel with O_EXCL set to keep producing sound. Other Changes: * most feeder_* stuffs are compilable in userland. Let's not speculate whether we should go all out for it (save that for FreeBSD 16.0-RELEASE). * kobj signature fixups, thanks to Andriy Gapon <avg@freebsd.org> * pull out channel mixing logic out of vchan.c and create its own feeder_mixer for world justice. * various refactoring here and there, for good or bad. * activation of few more OSSv4 ioctls() (see [1] above). * opt_snd.h for possible compile time configuration: (mostly for debugging purposes, don't try these at home) SND_DEBUG SND_DIAGNOSTIC SND_FEEDER_MULTIFORMAT SND_FEEDER_FULL_MULTIFORMAT SND_FEEDER_RATE_HP SND_PCM_64 SND_OLDSTEREO Manual page updates are on the way. Tested by: joel, Olivier SMEDTS <olivier at gid0 d org>, too many unsung / unnamed heroes.
2009-06-07 19:12:08 +00:00
if ((sc->irq == NULL) || bus_setup_intr(dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV,
NULL,
emu_intr, sc, &sc->ih)) {
device_printf(dev, "unable to map interrupt\n");
goto bad;
}
if (emu_rm_init(sc) != 0) {
device_printf(dev, "unable to create resource manager\n");
goto bad;
}
if (sc->is_cardbus)
if (emu_cardbus_init(sc) != 0) {
device_printf(dev, "unable to initialize CardBus interface\n");
goto bad;
}
if (emu_init(sc) != 0) {
device_printf(dev, "unable to initialize the card\n");
goto bad;
}
if (emu10kx_dev_init(sc) != 0) {
device_printf(dev, "unable to create control device\n");
goto bad;
}
Use uintmax_t (typedef'd to rman_res_t type) for rman ranges. On some architectures, u_long isn't large enough for resource definitions. Particularly, powerpc and arm allow 36-bit (or larger) physical addresses, but type `long' is only 32-bit. This extends rman's resources to uintmax_t. With this change, any resource can feasibly be placed anywhere in physical memory (within the constraints of the driver). Why uintmax_t and not something machine dependent, or uint64_t? Though it's possible for uintmax_t to grow, it's highly unlikely it will become 128-bit on 32-bit architectures. 64-bit architectures should have plenty of RAM to absorb the increase on resource sizes if and when this occurs, and the number of resources on memory-constrained systems should be sufficiently small as to not pose a drastic overhead. That being said, uintmax_t was chosen for source clarity. If it's specified as uint64_t, all printf()-like calls would either need casts to uintmax_t, or be littered with PRI*64 macros. Casts to uintmax_t aren't horrible, but it would also bake into the API for resource_list_print_type() either a hidden assumption that entries get cast to uintmax_t for printing, or these calls would need the PRI*64 macros. Since source code is meant to be read more often than written, I chose the clearest path of simply using uintmax_t. Tested on a PowerPC p5020-based board, which places all device resources in 0xfxxxxxxxx, and has 8GB RAM. Regression tested on qemu-system-i386 Regression tested on qemu-system-mips (malta profile) Tested PAE and devinfo on virtualbox (live CD) Special thanks to bz for his testing on ARM. Reviewed By: bz, jhb (previous) Relnotes: Yes Sponsored by: Alex Perez/Inertial Computing Differential Revision: https://reviews.freebsd.org/D4544
2016-03-18 01:28:41 +00:00
snprintf(status, 255, "rev %d at io 0x%jx irq %jd", sc->rev, rman_get_start(sc->reg), rman_get_start(sc->irq));
/* Voices */
for (i = 0; i < NUM_G; i++) {
sc->voice[i].vnum = i;
sc->voice[i].slave = NULL;
sc->voice[i].busy = 0;
sc->voice[i].ismaster = 0;
sc->voice[i].running = 0;
sc->voice[i].b16 = 0;
sc->voice[i].stereo = 0;
sc->voice[i].speed = 0;
sc->voice[i].start = 0;
sc->voice[i].end = 0;
}
/* PCM Audio */
for (i = 0; i < RT_COUNT; i++)
sc->pcm[i] = NULL;
/* FRONT */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (pcminfo == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo->card = sc;
pcminfo->route = RT_FRONT;
func->func = SCF_PCM;
func->varinfo = pcminfo;
sc->pcm[RT_FRONT] = device_add_child(dev, "pcm", -1);
device_set_ivars(sc->pcm[RT_FRONT], func);
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
if (!(sc->mch_disabled)) {
/* REAR */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (pcminfo == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo->card = sc;
pcminfo->route = RT_REAR;
func->func = SCF_PCM;
func->varinfo = pcminfo;
sc->pcm[RT_REAR] = device_add_child(dev, "pcm", -1);
device_set_ivars(sc->pcm[RT_REAR], func);
if (sc->has_51) {
/* CENTER */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (pcminfo == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo->card = sc;
pcminfo->route = RT_CENTER;
func->func = SCF_PCM;
func->varinfo = pcminfo;
sc->pcm[RT_CENTER] = device_add_child(dev, "pcm", -1);
device_set_ivars(sc->pcm[RT_CENTER], func);
/* SUB */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (pcminfo == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo->card = sc;
pcminfo->route = RT_SUB;
func->func = SCF_PCM;
func->varinfo = pcminfo;
sc->pcm[RT_SUB] = device_add_child(dev, "pcm", -1);
device_set_ivars(sc->pcm[RT_SUB], func);
}
if (sc->has_71) {
/* SIDE */
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (pcminfo == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo->card = sc;
pcminfo->route = RT_SIDE;
func->func = SCF_PCM;
func->varinfo = pcminfo;
sc->pcm[RT_SIDE] = device_add_child(dev, "pcm", -1);
device_set_ivars(sc->pcm[RT_SIDE], func);
}
} /* mch_disabled */
if (sc->mch_rec) {
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (pcminfo == NULL) {
error = ENOMEM;
goto bad;
}
pcminfo->card = sc;
pcminfo->route = RT_MCHRECORD;
func->func = SCF_PCM;
func->varinfo = pcminfo;
sc->pcm[RT_MCHRECORD] = device_add_child(dev, "pcm", -1);
device_set_ivars(sc->pcm[RT_MCHRECORD], func);
} /*mch_rec */
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
for (i = 0; i < 2; i++)
sc->midi[i] = NULL;
/* MIDI has some memory mangament and (possible) locking problems */
#if 0
/* Midi Interface 1: Live!, Audigy, Audigy 2 */
if ((sc->is_emu10k1) || (sc->is_emu10k2) || (sc->is_ca0102)) {
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (midiinfo == NULL) {
error = ENOMEM;
goto bad;
}
midiinfo->card = sc;
if (sc->is_emu10k2 || (sc->is_ca0102)) {
midiinfo->port = EMU_A_MUDATA1;
midiinfo->portnr = 1;
}
if (sc->is_emu10k1) {
midiinfo->port = MUDATA;
midiinfo->portnr = 1;
}
func->func = SCF_MIDI;
func->varinfo = midiinfo;
sc->midi[0] = device_add_child(dev, "midi", -1);
device_set_ivars(sc->midi[0], func);
}
/* Midi Interface 2: Audigy, Audigy 2 (on AudigyDrive) */
if (sc->is_emu10k2 || (sc->is_ca0102)) {
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
if (func == NULL) {
error = ENOMEM;
goto bad;
}
midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
if (midiinfo == NULL) {
error = ENOMEM;
goto bad;
}
midiinfo->card = sc;
midiinfo->port = EMU_A_MUDATA2;
midiinfo->portnr = 2;
func->func = SCF_MIDI;
func->varinfo = midiinfo;
sc->midi[1] = device_add_child(dev, "midi", -1);
device_set_ivars(sc->midi[1], func);
}
#endif
return (bus_generic_attach(dev));
bad:
/* XXX can we just call emu_pci_detach here? */
if (sc->cdev)
emu10kx_dev_uninit(sc);
if (sc->rm != NULL)
emu_rm_uninit(sc);
if (sc->reg)
bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
if (sc->ih)
bus_teardown_intr(dev, sc->irq, sc->ih);
if (sc->irq)
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
mtx_destroy(&sc->rw);
mtx_destroy(&sc->lock);
return (error);
}
static int
emu_pci_detach(device_t dev)
{
struct emu_sc_info *sc;
struct sndcard_func *func;
int devcount, i;
device_t *childlist;
int r = 0;
sc = device_get_softc(dev);
Extend the emu10kx driver. With the words of the author: ---snip--- New features: 1. Optional multichannel recording (32 channels on Live!, 64 channels on Audigy). All channels are 16bit/48000Hz/mono, format is fixed. Half of them are copied from sound output, another half can be used to record any data from DSP. What should be recorded is hardcoded in DSP code. In this version it records dummy data, but can be used to record all DSP inputs, for example.. Because there are no support of more-than-stereo sound streams multichannell stream is presented as one 32(64)*48000 Hz 16bit mono stream. Channel map: SB Live! (4.0/5.1) offset (words) substream 0x00 Front L 0x01 Front R 0x02 Digital Front L 0x03 Digital Front R 0x04 Digital Center 0x05 Digital Sub 0x06 Headphones L 0x07 Headphones R 0x08 Rear L 0x09 Rear R 0x0A ADC (multi-rate recording) L 0x0B ADC (multi-rate recording) R 0x0C unused 0x0D unused 0x0E unused 0x0F unused 0x10 Analog Center (Live! 5.1) / dummy (Live! 4.0) 0x11 Analog Sub (Live! 5.1) / dummy (Live! 4.0) 0x12..-0x1F dummy Audigy / Audigy 2 / Audigy 2 Value / Audigy 4 offset (words) substream 0x00 Digital Front L 0x01 Digital Front R 0x02 Digital Center 0x03 Digital Sub 0x04 Digital Side L (7.1 cards) / Headphones L (5.1 cards) 0x05 Digital Side R (7.1 cards) / Headphones R (5.1 cards) 0x06 Digital Rear L 0x07 Digital Rear R 0x08 Front L 0x09 Front R 0x0A Center 0x0B Sub 0x0C Side L 0x0D Side R 0x0E Rear L 0x0F Rear R 0x10 output to AC97 input L (muted) 0x11 output to AC97 input R (muted) 0x12 unused 0x13 unused 0x14 unused 0x15 unused 0x16 ADC (multi-rate recording) L 0x17 ADC (multi-rate recording) R 0x18 unused 0x19 unused 0x1A unused 0x1B unused 0x1C unused 0x1D unused 0x1E unused 0x1F unused 0x20..0x3F dummy Fixes: 1. Do not assign negative values to variables used to index emu_cards array. This array was never accessed when index is negative, but Alexander (netchild@) told me that Coverity does not like it. After this change emu_cards[0] should never be used to identify valid sound card. 2. Fix off-by-one errors in interrupt manager. Add more checks there. 3. Fixes to sound buffering code now allows driver to use large playback buffers. 4. Fix memory allocation bug when multichannel recording is not enabled. 5. Fix interrupt timeout when recording with low bitrate (8kHz). Hardware: 1. Add one more known Audigy ZS card to list. Add two cards with PCI IDs betwen old known cards and new one. Other changes: 1. Do not use ALL CAPS in messages. Incomplete code: 1. Automute S/PDIF when S/PDIF signal is lost. Tested on i386 only, gcc 3.4.6 & gcc41/gcc42 (syntax only). ---snip--- This commits enables a little bit of debugging output when the driver is loaded as a module. I did a cross-build test for amd64. The code has some style issues, this will be addressed later. The multichannel recording part is some work in progress to allow playing around with it until the generic sound code is better able to handle multichannel streams. This is supposed to fix CID: 171187 Found by: Coverity Prevent Submitted by: Yuriy Tsibizov <Yuriy.Tsibizov@gfk.ru>
2007-01-06 18:59:35 +00:00
for (i = 0; i < RT_COUNT; i++) {
if (sc->pcm[i] != NULL) {
func = device_get_ivars(sc->pcm[i]);
if (func != NULL && func->func == SCF_PCM) {
device_set_ivars(sc->pcm[i], NULL);
free(func->varinfo, M_DEVBUF);
free(func, M_DEVBUF);
}
r = device_delete_child(dev, sc->pcm[i]);
if (r) return (r);
}
}
if (sc->midi[0] != NULL) {
func = device_get_ivars(sc->midi[0]);
if (func != NULL && func->func == SCF_MIDI) {
device_set_ivars(sc->midi[0], NULL);
free(func->varinfo, M_DEVBUF);
free(func, M_DEVBUF);
}
r = device_delete_child(dev, sc->midi[0]);
if (r) return (r);
}
if (sc->midi[1] != NULL) {
func = device_get_ivars(sc->midi[1]);
if (func != NULL && func->func == SCF_MIDI) {
device_set_ivars(sc->midi[1], NULL);
free(func->varinfo, M_DEVBUF);
free(func, M_DEVBUF);
}
r = device_delete_child(dev, sc->midi[1]);
if (r) return (r);
}
if (device_get_children(dev, &childlist, &devcount) == 0)
for (i = 0; i < devcount - 1; i++) {
device_printf(dev, "removing stale child %d (unit %d)\n", i, device_get_unit(childlist[i]));
func = device_get_ivars(childlist[i]);
if (func != NULL && (func->func == SCF_MIDI || func->func == SCF_PCM)) {
device_set_ivars(childlist[i], NULL);
free(func->varinfo, M_DEVBUF);
free(func, M_DEVBUF);
}
device_delete_child(dev, childlist[i]);
}
if (childlist != NULL)
free(childlist, M_TEMP);
r = emu10kx_dev_uninit(sc);
if (r)
return (r);
/* shutdown chip */
emu_uninit(sc);
emu_rm_uninit(sc);
if (sc->mem.dmat)
bus_dma_tag_destroy(sc->mem.dmat);
if (sc->reg)
bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
bus_teardown_intr(dev, sc->irq, sc->ih);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
mtx_destroy(&sc->rw);
mtx_destroy(&sc->lock);
return (bus_generic_detach(dev));
}
/* add suspend, resume */
static device_method_t emu_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, emu_pci_probe),
DEVMETHOD(device_attach, emu_pci_attach),
DEVMETHOD(device_detach, emu_pci_detach),
/* Bus methods */
DEVMETHOD(bus_read_ivar, emu_read_ivar),
DEVMETHOD(bus_write_ivar, emu_write_ivar),
DEVMETHOD_END
};
static driver_t emu_driver = {
"emu10kx",
emu_methods,
sizeof(struct emu_sc_info),
NULL,
0,
NULL
};
static int
emu_modevent(module_t mod __unused, int cmd, void *data __unused)
{
int err = 0;
switch (cmd) {
case MOD_LOAD:
break; /* Success */
case MOD_UNLOAD:
case MOD_SHUTDOWN:
/* XXX Should we check state of pcm & midi subdevices here? */
break; /* Success */
default:
err = EINVAL;
break;
}
return (err);
}
static devclass_t emu_devclass;
DRIVER_MODULE(snd_emu10kx, pci, emu_driver, emu_devclass, emu_modevent, NULL);
MODULE_VERSION(snd_emu10kx, SND_EMU10KX_PREFVER);