patch-2.1.126 linux/drivers/sound/sb_audio.c
Next file: linux/drivers/sound/sb_common.c
Previous file: linux/drivers/sound/sb.h
Back to the patch index
Back to the overall index
- Lines: 360
- Date:
Sat Oct 17 15:33:46 1998
- Orig file:
v2.1.125/linux/drivers/sound/sb_audio.c
- Orig date:
Thu Jul 16 18:09:27 1998
diff -u --recursive --new-file v2.1.125/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c
@@ -15,6 +15,10 @@
*
* 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>
@@ -47,7 +51,7 @@
restore_flags(flags);
return -EBUSY;
}
- if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
+ if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
{
if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit"))
{
@@ -59,6 +63,10 @@
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 */
@@ -84,9 +92,11 @@
{
sb_devc *devc = audio_devs[dev]->devc;
- audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma = devc->dma8;
+ audio_devs[dev]->dmap_out->dma = devc->dma8;
+ audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ?
+ devc->dma16 : devc->dma8;
- if (devc->dma16 != -1 && devc->dma16 != devc->dma8)
+ if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
sound_close_dma(devc->dma16);
/* For ALS007, turn DSP output back on if closing the device for read */
@@ -104,20 +114,34 @@
{
sb_devc *devc = audio_devs[dev]->devc;
- devc->trg_buf = buf;
- devc->trg_bytes = nr_bytes;
- devc->trg_intrflag = intrflag;
- devc->irq_mode = IMODE_OUTPUT;
+ 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;
+ }
}
static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag)
{
sb_devc *devc = audio_devs[dev]->devc;
- devc->trg_buf = buf;
- devc->trg_bytes = count;
- devc->trg_intrflag = intrflag;
- devc->irq_mode = IMODE_INPUT;
+ 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;
+ }
}
/*
@@ -830,9 +854,17 @@
{
sb_devc *devc = audio_devs[dev]->devc;
- audio_devs[dev]->dmap_out->dma =
- audio_devs[dev]->dmap_in->dma =
- devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
+ 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;
+ }
devc->trigger_bits = 0;
return 0;
@@ -842,8 +874,17 @@
{
sb_devc *devc = audio_devs[dev]->devc;
- audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma =
- devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8;
+ 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;
+ }
devc->trigger_bits = 0;
return 0;
@@ -854,9 +895,23 @@
{
unsigned long flags, cnt;
sb_devc *devc = audio_devs[dev]->devc;
+ unsigned long bits;
- devc->irq_mode = IMODE_OUTPUT;
- devc->intr_active = 1;
+ 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);
cnt = count;
if (devc->bits == AFMT_S16_LE)
@@ -878,6 +933,8 @@
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);
}
@@ -886,8 +943,13 @@
unsigned long flags, cnt;
sb_devc *devc = audio_devs[dev]->devc;
- devc->irq_mode = IMODE_INPUT;
- devc->intr_active = 1;
+ 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;
+ }
cnt = count;
if (devc->bits == AFMT_S16_LE)
@@ -916,29 +978,125 @@
{
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
{
- 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;
+ 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;
+ }
}
+
static struct audio_driver sb1_audio_driver = /* SB1.x */
{
sb_audio_open,
@@ -1050,7 +1208,7 @@
sb16_audio_prepare_for_output,
sb1_audio_halt_xfer,
NULL, /* local_qlen */
- NULL, /* copy_from_user */
+ sb16_copy_from_user, /* copy_from_user */
NULL,
NULL,
sb16_audio_trigger,
@@ -1086,6 +1244,7 @@
struct audio_driver *driver = &sb1_audio_driver;
+ devc->duplex = 0;
switch (devc->model)
{
case MDL_SB1: /* SB1.0 or SB 1.5 */
@@ -1124,6 +1283,10 @@
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;
@@ -1136,7 +1299,9 @@
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)) < 0)
+ devc->dma8,
+ (devc->dma8 != devc->dma16 && devc->dma16 != -1)
+ ? devc->dma16 : devc->dma8)) < 0)
{
printk(KERN_ERR "Sound Blaster: unable to install audio.\n");
return;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov