Re: .wav output and SB16

Zlatko Calusic (Zlatko.Calusic@CARNet.hr)
11 Nov 1998 21:51:02 +0100


Dave Meyer <dmeyer@std.saic.com> writes:

> According to Michael K Vance:
> > Rik van Riel wrote:
> > > On Mon, 9 Nov 1998, Michael K Vance wrote:
> >
> > > This is because .wav and .au data includes special
> > > header data that can be used to configure the sound
> > - Programs (such as Quake--ahem) now have incredibly garbled output
>
> I've noticed this myself. Sound under quake is fine with 2.1.125ac3,
> but with 2.1.127 is complete gibberish.
>
> Dave

Sound Blaster full duplex patch added in 2.1.126, has broken sound in
Quake and other software.

You can use the following patch to remove SBFDX support and restore
sound behaviour in Quake. Patch was made for 2.1.126, but hopefully it
applies cleanly to 2.1.127. Enjoy!

Index: 126.6/drivers/sound/dev_table.h
--- 126.6/drivers/sound/dev_table.h Tue, 27 Oct 1998 14:47:22 +0100 zcalusic (linux-2.1/F/1_dev_table. 1.2 644)
+++ 126.17/drivers/sound/dev_table.h Mon, 09 Nov 1998 23:28:52 +0100 zcalusic (linux-2.1/F/1_dev_table. 1.2.2.1 644)
@@ -188,12 +188,8 @@
int (*prepare_for_output) (int dev, int bufsize, int nbufs);
void (*halt_io) (int dev);
int (*local_qlen)(int dev);
- void (*copy_user)(int dev,
- char *localbuf, int localoffs,
- const char *userbuf, int useroffs,
- int max_in, int max_out,
- int *used, int *returned,
- int len);
+ void (*copy_user)(int dev, char *localbuf, int localoffs,
+ const char *userbuf, int useroffs, int len);
void (*halt_input) (int dev);
void (*halt_output) (int dev);
void (*trigger) (int dev, int bits);
Index: 126.6/drivers/sound/sb.h
--- 126.6/drivers/sound/sb.h Tue, 27 Oct 1998 14:47:22 +0100 zcalusic (linux-2.1/F/3_sb.h 1.2 644)
+++ 126.17/drivers/sound/sb.h Mon, 09 Nov 1998 23:28:52 +0100 zcalusic (linux-2.1/F/3_sb.h 1.2.2.1 644)
@@ -87,14 +87,9 @@

/* State variables */
int opened;
- /* new audio fields for full duplex support */
- int fullduplex;
- int duplex;
int speed, bits, channels;
volatile int irq_ok;
volatile int intr_active, irq_mode;
- /* duplicate audio fields for full duplex support */
- volatile int intr_active_2, irq_mode_2;

/* Mixer fields */
int *levels;
@@ -110,13 +105,6 @@
int trg_bytes;
int trg_intrflag;
int trg_restart;
- /* duplicate audio fields for full duplex support */
- unsigned long trg_buf_2;
- int trigger_bits_2;
- int trg_bytes_2;
- int trg_intrflag_2;
- int trg_restart_2;
-
unsigned char tconst;
int my_dev;

Index: 126.6/drivers/sound/sb_common.c
--- 126.6/drivers/sound/sb_common.c Tue, 27 Oct 1998 14:47:22 +0100 zcalusic (linux-2.1/F/15_sb_common. 1.2 644)
+++ 126.17/drivers/sound/sb_common.c Mon, 09 Nov 1998 23:28:52 +0100 zcalusic (linux-2.1/F/15_sb_common. 1.2.2.1 644)
@@ -10,10 +10,7 @@
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
-/*
- * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts
- * for full duplex support ( only sb16 by now )
- */
+
#include <linux/config.h>
#include <linux/delay.h>
#include <asm/init.h>
@@ -143,7 +140,7 @@
if (!(src & 3))
return; /* Not a DSP interrupt */
}
- if (devc->intr_active && (!devc->fullduplex || (src & 0x01)))
+ if (devc->intr_active)
{
switch (devc->irq_mode)
{
@@ -168,17 +165,7 @@
/* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */
;
}
- } else if (devc->intr_active_2 && (src & 0x02)) {
- switch (devc->irq_mode_2)
- {
- case IMODE_OUTPUT:
- DMAbuf_outputintr (devc->dev, 1);
- break;
- case IMODE_INPUT:
- DMAbuf_inputintr (devc->dev);
- break;
- }
- }
+ }
/*
* Acknowledge interrupts
*/
Index: 126.6/drivers/sound/sb_audio.c
--- 126.6/drivers/sound/sb_audio.c Tue, 27 Oct 1998 14:47:22 +0100 zcalusic (linux-2.1/F/17_sb_audio.c 1.2 644)
+++ 126.17/drivers/sound/sb_audio.c Mon, 09 Nov 1998 23:28:52 +0100 zcalusic (linux-2.1/F/17_sb_audio.c 1.2.2.1 644)
@@ -15,10 +15,6 @@
*
* Status
* Mostly working. Weird uart bug causing irq storms
- *
- * Daniel J. Rodriksson: Changes to make sb16 work full duplex.
- * Maybe other 16 bit cards in this code could behave
- * the same.
*/

#include <linux/config.h>
@@ -51,7 +47,7 @@
restore_flags(flags);
return -EBUSY;
}
- if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
+ if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
{
if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit"))
{
@@ -63,10 +59,6 @@
restore_flags(flags);

devc->irq_mode = IMODE_NONE;
- devc->irq_mode_2 = IMODE_NONE;
- devc->intr_active_2 = 0;
- devc->fullduplex = devc->duplex &&
- ((mode & OPEN_READ) && (mode & OPEN_WRITE));
sb_dsp_reset(devc);

/* The ALS007 seems to require that the DSP be removed from the output */
@@ -92,11 +84,9 @@
{
sb_devc *devc = audio_devs[dev]->devc;

- audio_devs[dev]->dmap_out->dma = devc->dma8;
- audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ?
- devc->dma16 : devc->dma8;
+ audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma = devc->dma8;

- if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
+ if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
sound_close_dma(devc->dma16);

/* For ALS007, turn DSP output back on if closing the device for read */
@@ -114,34 +104,20 @@
{
sb_devc *devc = audio_devs[dev]->devc;

- if( !devc->fullduplex || devc->bits == AFMT_S16_LE) {
- devc->trg_buf = buf;
- devc->trg_bytes = nr_bytes;
- devc->trg_intrflag = intrflag;
- devc->irq_mode = IMODE_OUTPUT;
- } else {
- devc->trg_buf_2 = buf;
- devc->trg_bytes_2 = nr_bytes;
- devc->trg_intrflag_2 = intrflag;
- devc->irq_mode_2 = IMODE_OUTPUT;
- }
+ devc->trg_buf = buf;
+ devc->trg_bytes = nr_bytes;
+ devc->trg_intrflag = intrflag;
+ devc->irq_mode = IMODE_OUTPUT;
}

static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag)
{
sb_devc *devc = audio_devs[dev]->devc;

- if( !devc->fullduplex || devc->bits != AFMT_S16_LE) {
- devc->trg_buf = buf;
- devc->trg_bytes = count;
- devc->trg_intrflag = intrflag;
- devc->irq_mode = IMODE_INPUT;
- } else {
- devc->trg_buf_2 = buf;
- devc->trg_bytes_2 = count;
- devc->trg_intrflag_2 = intrflag;
- devc->irq_mode_2 = IMODE_INPUT;
- }
+ devc->trg_buf = buf;
+ devc->trg_bytes = count;
+ devc->trg_intrflag = intrflag;
+ devc->irq_mode = IMODE_INPUT;
}

/*
@@ -854,17 +830,9 @@
{
sb_devc *devc = audio_devs[dev]->devc;

- if( !devc->fullduplex) {
- audio_devs[dev]->dmap_out->dma =
- audio_devs[dev]->dmap_in->dma =
- devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
- } else if( devc->bits == AFMT_S16_LE) {
- audio_devs[dev]->dmap_out->dma = devc->dma8;
- audio_devs[dev]->dmap_in->dma = devc->dma16;
- } else {
- audio_devs[dev]->dmap_out->dma = devc->dma16;
- audio_devs[dev]->dmap_in->dma = devc->dma8;
- }
+ audio_devs[dev]->dmap_out->dma =
+ audio_devs[dev]->dmap_in->dma =
+ devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;

devc->trigger_bits = 0;
return 0;
@@ -874,17 +842,8 @@
{
sb_devc *devc = audio_devs[dev]->devc;

- if( !devc->fullduplex) {
- audio_devs[dev]->dmap_out->dma =
- audio_devs[dev]->dmap_in->dma =
- devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
- } else if( devc->bits == AFMT_S16_LE) {
- audio_devs[dev]->dmap_out->dma = devc->dma8;
- audio_devs[dev]->dmap_in->dma = devc->dma16;
- } else {
- audio_devs[dev]->dmap_out->dma = devc->dma16;
- audio_devs[dev]->dmap_in->dma = devc->dma8;
- }
+ audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma =
+ devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;

devc->trigger_bits = 0;
return 0;
@@ -895,23 +854,9 @@
{
unsigned long flags, cnt;
sb_devc *devc = audio_devs[dev]->devc;
- unsigned long bits;

- if( !devc->fullduplex || devc->bits == AFMT_S16_LE) {
- devc->irq_mode = IMODE_OUTPUT;
- devc->intr_active = 1;
- } else {
- devc->irq_mode_2 = IMODE_OUTPUT;
- devc->intr_active_2 = 1;
- }
-
- /* save value */
- save_flags (flags);
- cli ();
- bits = devc->bits;
- if( devc->fullduplex)
- devc->bits = (devc->bits == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE;
- restore_flags (flags);
+ devc->irq_mode = IMODE_OUTPUT;
+ devc->intr_active = 1;

cnt = count;
if (devc->bits == AFMT_S16_LE)
@@ -933,8 +878,6 @@
sb_dsp_command(devc, (unsigned char) (cnt & 0xff));
sb_dsp_command(devc, (unsigned char) (cnt >> 8));

- /* restore real value after all programming */
- devc->bits = bits;
restore_flags(flags);
}

@@ -943,13 +886,8 @@
unsigned long flags, cnt;
sb_devc *devc = audio_devs[dev]->devc;

- if( !devc->fullduplex || devc->bits != AFMT_S16_LE) {
- devc->irq_mode = IMODE_INPUT;
- devc->intr_active = 1;
- } else {
- devc->irq_mode_2 = IMODE_INPUT;
- devc->intr_active_2 = 1;
- }
+ devc->irq_mode = IMODE_INPUT;
+ devc->intr_active = 1;

cnt = count;
if (devc->bits == AFMT_S16_LE)
@@ -978,124 +916,28 @@
{
sb_devc *devc = audio_devs[dev]->devc;

- int bits_2 = bits & devc->irq_mode_2;
bits &= devc->irq_mode;

if (!bits)
sb_dsp_command(devc, 0xd0); /* Halt DMA */
else
{
- if( bits) {
- switch (devc->irq_mode)
- {
- case IMODE_INPUT:
- sb16_audio_start_input(dev, devc->trg_buf,
- devc->trg_bytes,
- devc->trg_intrflag);
- break;
-
- case IMODE_OUTPUT:
- sb16_audio_output_block(dev, devc->trg_buf,
- devc->trg_bytes,
- devc->trg_intrflag);
- break;
- }
- }
- if( bits_2) {
- switch (devc->irq_mode_2)
- {
- case IMODE_INPUT:
- sb16_audio_start_input (dev, devc->trg_buf_2,
- devc->trg_bytes_2,
- devc->trg_intrflag_2);
- break;
- case IMODE_OUTPUT:
- sb16_audio_output_block (dev, devc->trg_buf_2,
- devc->trg_bytes_2,
- devc->trg_intrflag_2);
- break;
- }
- }
- }
-
- devc->trigger_bits = bits | bits_2;
-}
-
-static unsigned char lbuf8[2048];
-static signed short *lbuf16 = (signed short *)lbuf8;
-#define LBUFCOPYSIZE 1024
-static void
-sb16_copy_from_user( int dev,
- char *localbuf, int localoffs,
- const char *userbuf, int useroffs,
- int max_in, int max_out,
- int *used, int *returned,
- int len)
-{
- sb_devc *devc = audio_devs[dev]->devc;
- int i, c, p, locallen;
- unsigned char *buf8;
- signed short *buf16;
-
- /* if not duplex no conversion */
- if( !devc->fullduplex) {
- copy_from_user( localbuf + localoffs, userbuf + useroffs, len);
- *used = len;
- *returned = len;
- } else if( devc->bits == AFMT_S16_LE) {
- /* 16 -> 8 */
- /* max_in >> 1, max number of samples in ( 16 bits ) */
- /* max_out, max number of samples out ( 8 bits ) */
- /* len, number of samples that will be taken ( 16 bits )*/
- /* c, count of samples remaining in buffer ( 16 bits )*/
- /* p, count of samples already processed ( 16 bits )*/
- len = ( (max_in >> 1) > max_out) ? max_out : (max_in >> 1);
- c = len;
- p = 0;
- buf8 = (unsigned char *)(localbuf + localoffs);
- while( c) {
- locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c);
- /* << 1 in order to get 16 bit samples */
- copy_from_user( lbuf16,
- userbuf+useroffs + (p << 1),
- locallen << 1);
- for( i = 0; i < locallen; i++) {
- buf8[p+i] = ~((lbuf16[i] >> 8) & 0xff) ^ 0x80;
- }
- c -= locallen; p += locallen;
- }
- /* used = ( samples * 16 bits size ) */
- *used = len << 1;
- /* returned = ( samples * 8 bits size ) */
- *returned = len;
- } else {
- /* 8 -> 16 */
- /* max_in, max number of samples in ( 8 bits ) */
- /* max_out >> 1, max number of samples out ( 16 bits ) */
- /* len, number of samples that will be taken ( 8 bits )*/
- /* c, count of samples remaining in buffer ( 8 bits )*/
- /* p, count of samples already processed ( 8 bits )*/
- len = max_in > (max_out >> 1) ? (max_out >> 1) : max_in;
- c = len;
- p = 0;
- buf16 = (signed short *)(localbuf + localoffs);
- while( c) {
- locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c);
- copy_from_user( lbuf8,
- userbuf+useroffs + p,
- locallen);
- for( i = 0; i < locallen; i++) {
- buf16[p+i] = (~lbuf8[i] ^ 0x80) << 8;
- }
- c -= locallen; p += locallen;
- }
- /* used = ( samples * 8 bits size ) */
- *used = len;
- /* returned = ( samples * 16 bits size ) */
- *returned = len << 1;
- }
-}
+ switch (devc->irq_mode)
+ {
+ case IMODE_INPUT:
+ sb16_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
+ devc->trg_intrflag);
+ break;
+
+ case IMODE_OUTPUT:
+ sb16_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
+ devc->trg_intrflag);
+ break;
+ }
+ }

+ devc->trigger_bits = bits;
+}

static struct audio_driver sb1_audio_driver = /* SB1.x */
{
@@ -1208,7 +1050,7 @@
sb16_audio_prepare_for_output,
sb1_audio_halt_xfer,
NULL, /* local_qlen */
- sb16_copy_from_user, /* copy_from_user */
+ NULL, /* copy_from_user */
NULL,
NULL,
sb16_audio_trigger,
@@ -1244,7 +1086,6 @@

struct audio_driver *driver = &sb1_audio_driver;

- devc->duplex = 0;
switch (devc->model)
{
case MDL_SB1: /* SB1.0 or SB 1.5 */
@@ -1283,10 +1124,6 @@
DDB(printk("Will use SB16 driver\n"));
audio_flags = DMA_AUTOMODE;
format_mask |= AFMT_S16_LE;
- if( devc->dma8 != devc->dma16 && devc->dma16 != -1) {
- audio_flags |= DMA_DUPLEX;
- devc->duplex = 1;
- }
driver = &sb16_audio_driver;
break;

@@ -1299,9 +1136,7 @@
if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
name,driver, sizeof(struct audio_driver),
audio_flags, format_mask, devc,
- devc->dma8,
- (devc->dma8 != devc->dma16 && devc->dma16 != -1)
- ? devc->dma16 : devc->dma8)) < 0)
+ devc->dma8, devc->dma8)) < 0)
{
printk(KERN_ERR "Sound Blaster: unable to install audio.\n");
return;
Index: 126.6/drivers/sound/audio.c
--- 126.6/drivers/sound/audio.c Tue, 27 Oct 1998 14:47:22 +0100 zcalusic (linux-2.1/G/6_audio.c 1.2 644)
+++ 126.17/drivers/sound/audio.c Mon, 09 Nov 1998 23:28:52 +0100 zcalusic (linux-2.1/G/6_audio.c 1.2.2.1 644)
@@ -18,8 +18,6 @@
* lifetime as the rest in there and dynamic allocation saves
* 12k or so
* Thomas Sailer : use more logical O_NONBLOCK semantics
- * Daniel Rodriksson: reworked the use of the device specific copy_user
- * still generic
*/

#include <linux/config.h>
@@ -191,7 +189,7 @@

int audio_write(int dev, struct file *file, const char *buf, int count)
{
- int c, p, l, buf_size, used, returned;
+ int c, p, l, buf_size;
int err;
char *dma_buf;

@@ -228,8 +226,6 @@
if (l > buf_size)
l = buf_size;

- returned = l;
- used = l;
if (!audio_devs[dev]->d->copy_user)
{
if ((dma_buf + l) >
@@ -246,13 +242,7 @@
if(copy_from_user(dma_buf, &(buf)[p], l))
return -EFAULT;
}
- else audio_devs[dev]->d->copy_user ( dev,
- dma_buf, 0,
- buf, p,
- c, buf_size,
- &used, &returned,
- l);
- l = returned;
+ else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l);

if (audio_devs[dev]->local_conversion & CNV_MU_LAW)
{
@@ -262,8 +252,8 @@
sti();
translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l);
}
- c -= used;
- p += used;
+ c -= l;
+ p += l;
DMAbuf_move_wrpointer(dev, l);

}

-- 
Posted by Zlatko Calusic           E-mail: <Zlatko.Calusic@CARNet.hr>
---------------------------------------------------------------------
		   Recursive, adj.; see Recursive.

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/