|
@@ -106,9 +106,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
unsigned int mixreg, rate, size, count;
|
|
unsigned int mixreg, rate, size, count;
|
|
|
|
+ unsigned char format;
|
|
|
|
+ unsigned char stereo = runtime->channels > 1;
|
|
|
|
+ int dma;
|
|
|
|
|
|
rate = runtime->rate;
|
|
rate = runtime->rate;
|
|
switch (chip->hardware) {
|
|
switch (chip->hardware) {
|
|
|
|
+ case SB_HW_JAZZ16:
|
|
|
|
+ if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
|
|
|
|
+ if (chip->mode & SB_MODE_CAPTURE_16)
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ else
|
|
|
|
+ chip->mode |= SB_MODE_PLAYBACK_16;
|
|
|
|
+ }
|
|
|
|
+ chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
|
|
|
|
+ break;
|
|
case SB_HW_PRO:
|
|
case SB_HW_PRO:
|
|
if (runtime->channels > 1) {
|
|
if (runtime->channels > 1) {
|
|
if (snd_BUG_ON(rate != SB8_RATE(11025) &&
|
|
if (snd_BUG_ON(rate != SB8_RATE(11025) &&
|
|
@@ -133,11 +145,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
|
|
default:
|
|
default:
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
+ if (chip->mode & SB_MODE_PLAYBACK_16) {
|
|
|
|
+ format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
|
|
|
|
+ dma = chip->dma16;
|
|
|
|
+ } else {
|
|
|
|
+ format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
|
|
|
|
+ chip->mode |= SB_MODE_PLAYBACK_8;
|
|
|
|
+ dma = chip->dma8;
|
|
|
|
+ }
|
|
size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
|
|
size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
|
|
count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
|
|
count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
|
|
spin_lock_irqsave(&chip->reg_lock, flags);
|
|
spin_lock_irqsave(&chip->reg_lock, flags);
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
|
|
- if (runtime->channels > 1) {
|
|
|
|
|
|
+ if (chip->hardware == SB_HW_JAZZ16)
|
|
|
|
+ snd_sbdsp_command(chip, format);
|
|
|
|
+ else if (stereo) {
|
|
/* set playback stereo mode */
|
|
/* set playback stereo mode */
|
|
spin_lock(&chip->mixer_lock);
|
|
spin_lock(&chip->mixer_lock);
|
|
mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
|
|
mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
|
|
@@ -147,15 +169,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
|
|
/* Soundblaster hardware programming reference guide, 3-23 */
|
|
/* Soundblaster hardware programming reference guide, 3-23 */
|
|
snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
|
|
snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
|
|
runtime->dma_area[0] = 0x80;
|
|
runtime->dma_area[0] = 0x80;
|
|
- snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE);
|
|
|
|
|
|
+ snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
|
|
/* force interrupt */
|
|
/* force interrupt */
|
|
- chip->mode = SB_MODE_HALT;
|
|
|
|
snd_sbdsp_command(chip, SB_DSP_OUTPUT);
|
|
snd_sbdsp_command(chip, SB_DSP_OUTPUT);
|
|
snd_sbdsp_command(chip, 0);
|
|
snd_sbdsp_command(chip, 0);
|
|
snd_sbdsp_command(chip, 0);
|
|
snd_sbdsp_command(chip, 0);
|
|
}
|
|
}
|
|
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
|
|
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
|
|
- if (runtime->channels > 1) {
|
|
|
|
|
|
+ if (stereo) {
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
|
|
spin_lock(&chip->mixer_lock);
|
|
spin_lock(&chip->mixer_lock);
|
|
/* save output filter status and turn it off */
|
|
/* save output filter status and turn it off */
|
|
@@ -168,13 +189,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den);
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den);
|
|
}
|
|
}
|
|
if (chip->playback_format != SB_DSP_OUTPUT) {
|
|
if (chip->playback_format != SB_DSP_OUTPUT) {
|
|
|
|
+ if (chip->mode & SB_MODE_PLAYBACK_16)
|
|
|
|
+ count /= 2;
|
|
count--;
|
|
count--;
|
|
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
|
|
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
|
|
snd_sbdsp_command(chip, count & 0xff);
|
|
snd_sbdsp_command(chip, count & 0xff);
|
|
snd_sbdsp_command(chip, count >> 8);
|
|
snd_sbdsp_command(chip, count >> 8);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
- snd_dma_program(chip->dma8, runtime->dma_addr,
|
|
|
|
|
|
+ snd_dma_program(dma, runtime->dma_addr,
|
|
size, DMA_MODE_WRITE | DMA_AUTOINIT);
|
|
size, DMA_MODE_WRITE | DMA_AUTOINIT);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -212,7 +235,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
- chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -234,9 +256,21 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
unsigned int mixreg, rate, size, count;
|
|
unsigned int mixreg, rate, size, count;
|
|
|
|
+ unsigned char format;
|
|
|
|
+ unsigned char stereo = runtime->channels > 1;
|
|
|
|
+ int dma;
|
|
|
|
|
|
rate = runtime->rate;
|
|
rate = runtime->rate;
|
|
switch (chip->hardware) {
|
|
switch (chip->hardware) {
|
|
|
|
+ case SB_HW_JAZZ16:
|
|
|
|
+ if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
|
|
|
|
+ if (chip->mode & SB_MODE_PLAYBACK_16)
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ else
|
|
|
|
+ chip->mode |= SB_MODE_CAPTURE_16;
|
|
|
|
+ }
|
|
|
|
+ chip->capture_format = SB_DSP_LO_INPUT_AUTO;
|
|
|
|
+ break;
|
|
case SB_HW_PRO:
|
|
case SB_HW_PRO:
|
|
if (runtime->channels > 1) {
|
|
if (runtime->channels > 1) {
|
|
if (snd_BUG_ON(rate != SB8_RATE(11025) &&
|
|
if (snd_BUG_ON(rate != SB8_RATE(11025) &&
|
|
@@ -262,14 +296,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
|
|
default:
|
|
default:
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
+ if (chip->mode & SB_MODE_CAPTURE_16) {
|
|
|
|
+ format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
|
|
|
|
+ dma = chip->dma16;
|
|
|
|
+ } else {
|
|
|
|
+ format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
|
|
|
|
+ chip->mode |= SB_MODE_CAPTURE_8;
|
|
|
|
+ dma = chip->dma8;
|
|
|
|
+ }
|
|
size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
|
|
size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
|
|
count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
|
|
count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
|
|
spin_lock_irqsave(&chip->reg_lock, flags);
|
|
spin_lock_irqsave(&chip->reg_lock, flags);
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
|
|
- if (runtime->channels > 1)
|
|
|
|
|
|
+ if (chip->hardware == SB_HW_JAZZ16)
|
|
|
|
+ snd_sbdsp_command(chip, format);
|
|
|
|
+ else if (stereo)
|
|
snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
|
|
snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
|
|
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
|
|
snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
|
|
- if (runtime->channels > 1) {
|
|
|
|
|
|
+ if (stereo) {
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
|
|
spin_lock(&chip->mixer_lock);
|
|
spin_lock(&chip->mixer_lock);
|
|
/* save input filter status and turn it off */
|
|
/* save input filter status and turn it off */
|
|
@@ -282,13 +326,15 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den);
|
|
snd_sbdsp_command(chip, 256 - runtime->rate_den);
|
|
}
|
|
}
|
|
if (chip->capture_format != SB_DSP_INPUT) {
|
|
if (chip->capture_format != SB_DSP_INPUT) {
|
|
|
|
+ if (chip->mode & SB_MODE_PLAYBACK_16)
|
|
|
|
+ count /= 2;
|
|
count--;
|
|
count--;
|
|
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
|
|
snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
|
|
snd_sbdsp_command(chip, count & 0xff);
|
|
snd_sbdsp_command(chip, count & 0xff);
|
|
snd_sbdsp_command(chip, count >> 8);
|
|
snd_sbdsp_command(chip, count >> 8);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
- snd_dma_program(chip->dma8, runtime->dma_addr,
|
|
|
|
|
|
+ snd_dma_program(dma, runtime->dma_addr,
|
|
size, DMA_MODE_READ | DMA_AUTOINIT);
|
|
size, DMA_MODE_READ | DMA_AUTOINIT);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -328,7 +374,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
|
|
snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
|
- chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT;
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -339,13 +384,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
|
|
|
|
|
|
snd_sb_ack_8bit(chip);
|
|
snd_sb_ack_8bit(chip);
|
|
switch (chip->mode) {
|
|
switch (chip->mode) {
|
|
- case SB_MODE_PLAYBACK_8: /* ok.. playback is active */
|
|
|
|
|
|
+ case SB_MODE_PLAYBACK_16: /* ok.. playback is active */
|
|
|
|
+ if (chip->hardware != SB_HW_JAZZ16)
|
|
|
|
+ break;
|
|
|
|
+ /* fallthru */
|
|
|
|
+ case SB_MODE_PLAYBACK_8:
|
|
substream = chip->playback_substream;
|
|
substream = chip->playback_substream;
|
|
runtime = substream->runtime;
|
|
runtime = substream->runtime;
|
|
if (chip->playback_format == SB_DSP_OUTPUT)
|
|
if (chip->playback_format == SB_DSP_OUTPUT)
|
|
snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
|
|
snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
|
|
snd_pcm_period_elapsed(substream);
|
|
snd_pcm_period_elapsed(substream);
|
|
break;
|
|
break;
|
|
|
|
+ case SB_MODE_CAPTURE_16:
|
|
|
|
+ if (chip->hardware != SB_HW_JAZZ16)
|
|
|
|
+ break;
|
|
|
|
+ /* fallthru */
|
|
case SB_MODE_CAPTURE_8:
|
|
case SB_MODE_CAPTURE_8:
|
|
substream = chip->capture_substream;
|
|
substream = chip->capture_substream;
|
|
runtime = substream->runtime;
|
|
runtime = substream->runtime;
|
|
@@ -361,10 +414,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs
|
|
{
|
|
{
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
size_t ptr;
|
|
size_t ptr;
|
|
|
|
+ int dma;
|
|
|
|
|
|
- if (chip->mode != SB_MODE_PLAYBACK_8)
|
|
|
|
|
|
+ if (chip->mode & SB_MODE_PLAYBACK_8)
|
|
|
|
+ dma = chip->dma8;
|
|
|
|
+ else if (chip->mode & SB_MODE_PLAYBACK_16)
|
|
|
|
+ dma = chip->dma16;
|
|
|
|
+ else
|
|
return 0;
|
|
return 0;
|
|
- ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size);
|
|
|
|
|
|
+ ptr = snd_dma_pointer(dma, chip->p_dma_size);
|
|
return bytes_to_frames(substream->runtime, ptr);
|
|
return bytes_to_frames(substream->runtime, ptr);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -372,10 +430,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst
|
|
{
|
|
{
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
struct snd_sb *chip = snd_pcm_substream_chip(substream);
|
|
size_t ptr;
|
|
size_t ptr;
|
|
|
|
+ int dma;
|
|
|
|
|
|
- if (chip->mode != SB_MODE_CAPTURE_8)
|
|
|
|
|
|
+ if (chip->mode & SB_MODE_CAPTURE_8)
|
|
|
|
+ dma = chip->dma8;
|
|
|
|
+ else if (chip->mode & SB_MODE_CAPTURE_16)
|
|
|
|
+ dma = chip->dma16;
|
|
|
|
+ else
|
|
return 0;
|
|
return 0;
|
|
- ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size);
|
|
|
|
|
|
+ ptr = snd_dma_pointer(dma, chip->c_dma_size);
|
|
return bytes_to_frames(substream->runtime, ptr);
|
|
return bytes_to_frames(substream->runtime, ptr);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -446,6 +509,13 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
|
|
runtime->hw = snd_sb8_capture;
|
|
runtime->hw = snd_sb8_capture;
|
|
}
|
|
}
|
|
switch (chip->hardware) {
|
|
switch (chip->hardware) {
|
|
|
|
+ case SB_HW_JAZZ16:
|
|
|
|
+ runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
|
|
|
|
+ runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;
|
|
|
|
+ runtime->hw.rate_min = 4000;
|
|
|
|
+ runtime->hw.rate_max = 50000;
|
|
|
|
+ runtime->hw.channels_max = 2;
|
|
|
|
+ break;
|
|
case SB_HW_PRO:
|
|
case SB_HW_PRO:
|
|
runtime->hw.rate_max = 44100;
|
|
runtime->hw.rate_max = 44100;
|
|
runtime->hw.channels_max = 2;
|
|
runtime->hw.channels_max = 2;
|
|
@@ -468,6 +538,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream)
|
|
}
|
|
}
|
|
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
|
snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
|
&hw_constraints_clock);
|
|
&hw_constraints_clock);
|
|
|
|
+ if (chip->dma8 > 3 || chip->dma16 >= 0) {
|
|
|
|
+ snd_pcm_hw_constraint_step(runtime, 0,
|
|
|
|
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);
|
|
|
|
+ snd_pcm_hw_constraint_step(runtime, 0,
|
|
|
|
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);
|
|
|
|
+ runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;
|
|
|
|
+ runtime->hw.period_bytes_max = 128 * 1024 * 1024;
|
|
|
|
+ }
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -480,6 +558,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream)
|
|
chip->capture_substream = NULL;
|
|
chip->capture_substream = NULL;
|
|
spin_lock_irqsave(&chip->open_lock, flags);
|
|
spin_lock_irqsave(&chip->open_lock, flags);
|
|
chip->open &= ~SB_OPEN_PCM;
|
|
chip->open &= ~SB_OPEN_PCM;
|
|
|
|
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
|
+ chip->mode &= ~SB_MODE_PLAYBACK;
|
|
|
|
+ else
|
|
|
|
+ chip->mode &= ~SB_MODE_CAPTURE;
|
|
spin_unlock_irqrestore(&chip->open_lock, flags);
|
|
spin_unlock_irqrestore(&chip->open_lock, flags);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -515,6 +597,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
|
|
struct snd_card *card = chip->card;
|
|
struct snd_card *card = chip->card;
|
|
struct snd_pcm *pcm;
|
|
struct snd_pcm *pcm;
|
|
int err;
|
|
int err;
|
|
|
|
+ size_t max_prealloc = 64 * 1024;
|
|
|
|
|
|
if (rpcm)
|
|
if (rpcm)
|
|
*rpcm = NULL;
|
|
*rpcm = NULL;
|
|
@@ -527,9 +610,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
|
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
|
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
|
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
|
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
|
|
|
|
|
|
|
|
+ if (chip->dma8 > 3 || chip->dma16 >= 0)
|
|
|
|
+ max_prealloc = 128 * 1024;
|
|
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
|
|
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
|
|
snd_dma_isa_data(),
|
|
snd_dma_isa_data(),
|
|
- 64*1024, 64*1024);
|
|
|
|
|
|
+ 64*1024, max_prealloc);
|
|
|
|
|
|
if (rpcm)
|
|
if (rpcm)
|
|
*rpcm = pcm;
|
|
*rpcm = pcm;
|