>>   If my patch for pcm/ESS sound chip apply to FreeBSD, may I send-pr
>> with old-config style?
>>   Yes, current pcm sound driver is old-config, but "Cameron Grant"
>> <[EMAIL PROTECTED]> is working to newbuslize.

  I create patch for 4-current sys/i386/isa/snd. It fix for
pcm/ESS-ISA sound driver.

  All ESS-ISA specific changes are quoted in (d->bd_flags & BD_F_ESS).

MIHIRA Sanpei Yoshiro

diff -uNr snd.org/CARDS snd/CARDS
--- snd.org/CARDS       Wed Aug 11 10:36:53 1999
+++ snd/CARDS   Wed Aug 11 10:21:33 1999
@@ -357,3 +357,4 @@
 
 
 --------------------------------------------------------------------
+$Id$
diff -uNr snd.org/README snd/README
--- snd.org/README      Wed Aug 11 10:36:53 1999
+++ snd/README  Wed Aug 11 10:21:33 1999
@@ -222,3 +222,5 @@
 the product. Too bad that no one of the chip/card manufacturers I
 have contacted by email regarding missing or inconsistent documentation
 on their products did even care to reply to my messages.
+
+$Id$
diff -uNr snd.org/ad1848.c snd/ad1848.c
--- snd.org/ad1848.c    Wed Aug 11 10:36:53 1999
+++ snd/ad1848.c        Wed Aug 11 10:21:33 1999
@@ -40,6 +40,10 @@
  *     http://www.opti.com/    for the OPTi931
  */
 
+/*
+ *     $Id$
+ */
+
 #include <i386/isa/snd/sound.h>
 #if NPCM > 0
 
diff -uNr snd.org/clones.c snd/clones.c
--- snd.org/clones.c    Wed Aug 11 10:36:53 1999
+++ snd/clones.c        Wed Aug 11 10:21:33 1999
@@ -33,6 +33,10 @@
  * in the Voxware 3.5 distribution.
  */
 
+/*
+ *     $Id$
+ */
+
 #include <i386/isa/snd/sound.h>
 #if NPCM > 0
 
diff -uNr snd.org/dmabuf.c snd/dmabuf.c
--- snd.org/dmabuf.c    Wed Aug 11 10:36:53 1999
+++ snd/dmabuf.c        Wed Aug 11 10:21:33 1999
@@ -31,7 +31,12 @@
  *
  */
 
+/*
+ *    $Id$
+ */
+
 #include <i386/isa/snd/sound.h>
+#include <i386/isa/snd/sbcard.h>
 #include <i386/isa/snd/ulaw.h>
 
 #define MIN_CHUNK_SIZE 256     /* for uiomove etc. */
@@ -183,12 +188,13 @@
         * This happens if the size has changed _and_ the new size
         * is smaller, or it matches the blocksize.
         */
-       if (l != b->dl && (b->dl == 0 || l<b->dl || l == d->play_blocksize) ) {
+       if ((l != b->dl && (b->dl == 0 || l<b->dl || l == d->play_blocksize))
+           || (d->bd_flags & BD_F_ESS)) {
            /* for any reason, size has changed. Stop and restart */
            DEB(printf("wrintr: bsz change from %d to %d, rp %d rl %d\n",
                b->dl, l, b->rp, b->rl));
            DEB(printf("wrintr: dl %d -> %d\n", b->dl, l);)
-           if (b->dl != 0)
+           if (b->dl != 0 && ! (d->bd_flags & BD_F_ESS))
                d->callback(d, SND_CB_WR | SND_CB_STOP );
            /*
             * at high speed, it might well be that the count
@@ -281,12 +287,16 @@
            else
                timeout = 1 ;
             ret = tsleep( (caddr_t)b, PRIBIO|PCATCH, "dspwr", timeout);
-           if (ret == EINTR)
-               d->flags |= SND_F_ABORTING ;
+           if (ret == EINTR || ((d->bd_flags & BD_F_ESS) && timeout != 1 &&
+                               ret == EWOULDBLOCK && b->rl == b->bufsize)) {
+                d->flags |= SND_F_ABORTING ;
+               splx(s);
+               break;
+           }
            splx(s);
-           if (ret == EINTR || ret == ERESTART)
+           if (ret == ERESTART)
                break ;
-            continue;
+           continue;
         }
         splx(s);
 
@@ -319,7 +329,8 @@
         if ( b->dl == 0 ) /* dma was idle, restart it */
             dsp_wrintr(d) ;
         splx(s) ;
-       if (buf->uio_resid == 0 && (b->fp & (b->sample_size - 1)) == 0) {
+       if (buf->uio_resid == 0 && (b->fp & (b->sample_size - 1)) == 0 &&
+           ! (d->bd_flags & BD_F_ESS)) {
            /*
             * If data is correctly aligned, pad the region with
             * replicas of the last sample. l0 goes from current to
@@ -472,9 +483,13 @@
        int l = min(b->fl - 0x100, d->rec_blocksize);
        l &= DMA_ALIGN_MASK ; /* realign sizes */
        DEB(printf("rdintr: dl %d -> %d\n", b->dl, l);)
+#ifdef ESS_RECORD_WITH_NORMAL_DMA
+       if (l != b->dl || d->bd_flags & BD_F_ESS) {
+#else
        if (l != b->dl) {
+#endif
            /* for any reason, size has changed. Stop and restart */
-           if (b->dl > 0 )
+           if (b->dl > 0)
                d->callback(d, SND_CB_RD | SND_CB_STOP );
            b->dl = l ;
            d->callback(d, SND_CB_RD | SND_CB_START );
@@ -572,10 +587,14 @@
            else
                timeout = 1; /* maybe data will be ready earlier */
             ret = tsleep( (caddr_t)b, PRIBIO | PCATCH , "dsprd", timeout ) ;
-           if (ret == EINTR)
+           if (ret == EINTR || ((d->bd_flags & BD_F_ESS) && timeout != 1 &&
+                               ret == EWOULDBLOCK && b->fl == b->bufsize)) {
                d->flags |= SND_F_ABORTING ;
+               splx(s);
+               break;
+           }
            splx(s);
-           if (ret == EINTR || ret == ERESTART)
+           if (ret == ERESTART)
                break ;
             continue;
         }
@@ -719,8 +738,12 @@
     if ( b->dl ) {
        b->dl = 0 ;
        d->flags &= ~ SND_F_WRITING ;
-       if (d->callback)
+       if (d->callback) {
            d->callback(d, SND_CB_WR | SND_CB_ABORT);
+           if ((d->bd_flags & BD_F_ESS) && restart) {
+               d->callback(d, SND_CB_INIT);
+           }
+       }
        if (!d->special_dma)
            isa_dmastop(b->chan) ;
        dsp_wr_dmadone(d);
@@ -746,15 +769,19 @@
     if ( b->dl ) {
        b->dl = 0 ;
        d->flags &= ~ SND_F_READING ;
-       if (d->callback)
+       if (d->callback) {
            d->callback(d, SND_CB_RD | SND_CB_ABORT);
+           if ((d->bd_flags & BD_F_ESS) && restart) {
+               d->callback(d, SND_CB_INIT);
+           }
+       }
        if (!d->special_dma) 
            isa_dmastop(b->chan) ;
        dsp_rd_dmadone(d);
     }
     missing = b->rl ;
     if (!d->special_dma)
-        isa_dmadone(B_READ, b->buf, b->bufsize, b->chan);
+       isa_dmadone(B_READ, b->buf, b->bufsize, b->chan);
     reset_dbuf(b, restart ? SND_CHAN_RD : SND_CHAN_NONE);
     splx(s);
     return missing;
@@ -775,7 +802,9 @@
     snd_dbuf *b = &(d->dbuf_out) ;
 
     DEB(printf("snd_flush d->flags 0x%08x\n", d->flags));
-    dsp_rdabort(d, 0 /* no restart */);
+    if (! (d->bd_flags & BD_F_ESS) || (d->rec_fmt &&
+               (FULL_DUPLEX(d) || d->play_fmt == 0)))
+       dsp_rdabort(d, 0 /* no restart */);
     /* close write */
     while ( b->dl ) {
        /*
@@ -800,7 +829,8 @@
     }
     s = spltty(); /* should not be necessary... */
     d->flags &= ~SND_F_CLOSING ;
-    dsp_wrabort(d, 0 /* no restart */);
+    if (! (d->bd_flags & BD_F_ESS) || d->play_fmt)
+       dsp_wrabort(d, 0 /* no restart */);
     splx(s);
     return 0 ;
 }
diff -uNr snd.org/mss.h snd/mss.h
--- snd.org/mss.h       Wed Aug 11 10:36:53 1999
+++ snd/mss.h   Wed Aug 11 10:21:33 1999
@@ -9,6 +9,10 @@
  */
 
 /*
+ *     $Id$
+ */
+
+/*
  *
 
 The codec part of the board is seen as a set of 4 registers mapped
diff -uNr snd.org/sb_dsp.c snd/sb_dsp.c
--- snd.org/sb_dsp.c    Wed Aug 11 10:36:53 1999
+++ snd/sb_dsp.c        Wed Aug 11 10:21:33 1999
@@ -35,6 +35,10 @@
  */
 
 /*
+ *     $Id$
+ */
+
+/*
  * use this as a template file for board-specific drivers.
  * The next two lines (and the final #endif) are in all drivers:
  */
@@ -69,13 +73,14 @@
 
 static void sb_dsp_init(snddev_info *d, struct isa_device *dev);
 static void sb_mix_init(snddev_info *d);
-static int sb_mixer_set(snddev_info *d, int dev, int value);
+/* static int sb_mixer_set(snddev_info *d, int dev, int value); */
 static int dsp_speed(snddev_info *d);
 static void sb_mixer_reset(snddev_info *d);
 
 u_int sb_get_byte(int io_base);
 int ess_write(int io_base, u_char reg, int val);
 int ess_read(int io_base, u_char reg);
+void ess_cont_getmixer(int io_base, u_int port, u_char *buf, int num);
 
 /*
  * Then put here the descriptors for the various boards supported
@@ -322,6 +327,17 @@
        }
     }
     /* XXX previous location of ack... */
+    if (d->bd_flags & BD_F_ESS) {
+       /*
+        * A read from port 2xEh(following ack command) will reset
+        * any IRQ request on ESS chip. And dsp_??intr runs slow.
+        * Therefore interrupt will be dropped in original location.
+        */
+       if ( c & 2 )
+           inb(DSP_DATA_AVL16); /* 16-bit int ack */
+       if (c & 1)
+           inb(DSP_DATA_AVAIL);        /* 8-bit int ack */
+    }
     DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n",
        d->flags, reason, c));
     if ( reason & 1 ) { /* possibly a write interrupt */
@@ -332,11 +348,12 @@
        if ( d->dbuf_in.dl )
            dsp_rdintr(d);
     }
-    if ( c & 2 )
-       inb(DSP_DATA_AVL16); /* 16-bit int ack */
-    if (c & 1)
-       inb(DSP_DATA_AVAIL);    /* 8-bit int ack */
-
+    if (! (d->bd_flags & BD_F_ESS)) {
+       if ( c & 2 )
+           inb(DSP_DATA_AVL16); /* 16-bit int ack */
+       if (c & 1)
+           inb(DSP_DATA_AVAIL);        /* 8-bit int ack */
+    }
     /*
      * the sb16 might have multiple sources etc.
      */
@@ -364,6 +381,10 @@
 
     switch (reason & SND_CB_REASON_MASK) {
     case SND_CB_INIT : /* called with int enabled and no pending io */
+       if (d->bd_flags & BD_F_ESS) {
+           sb_reset_dsp(d->io_base);
+           sb_cmd(d->io_base, 0xc6); /* enable extended ESS mode */
+       }
        /*
         * set the speed
         */
@@ -430,66 +451,79 @@
                d->dbuf_in.chan = d->dbuf_out.chan;
                d->dbuf_out.chan = c ;
            }
-       }
-       else if (d->bd_flags & BD_F_ESS) {
-               u_char c;
-
-               DEB(printf("SND_CB_INIT, play_fmt == 0x%x, rec_fmt == 0x%x\n",
-                       (int) d->play_fmt, (int) d->rec_fmt));
-
-               /* autoinit DMA mode */
-               if (d->play_fmt)
-                       ess_write(d->io_base, 0xb8, 0x04);
-               else
-                       ess_write(d->io_base, 0xb8, 0x0e);
+       } else if (d->bd_flags & BD_F_ESS) {
+           u_char c ;
+           u_char *cmd_ofs;
+           if (d->play_fmt == 0) {
+               /* initialize for record */
+               static u_char cmd[] = {
+                   0x51,0xd0,0x71,0xf4,0x51,0x98,0x71,0xbc
+               };
+#if ESS_RECORD_WITH_NORMAL_DMA
+               ess_write(d->io_base, 0xb8, 0x0a); /* normal DMA */
+#else
+               ess_write(d->io_base, 0xb8, 0x0e);
+#endif
+               c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ;
+               if (! (d->flags & SND_F_STEREO))
+                   c++ ;
+               ess_write(d->io_base, 0xa8, c);
+               ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */
+               /*
+                * set format in b6, b7
+                */
+               cmd_ofs = cmd + ((d->flags & SND_F_STEREO) ? 4 : 0)
+                   + ((d->rec_fmt == AFMT_S16_LE) ? 2 : 0);
+               ess_write(d->io_base, 0xb7, cmd_ofs[0]);
+               ess_write(d->io_base, 0xb7, cmd_ofs[1]);
+               ess_write(d->io_base, 0xb1,
+                         (ess_read(d->io_base, 0xb1) & 0x0f) | 0x50);
+               ess_write(d->io_base, 0xb2,
+                         (ess_read(d->io_base, 0xb2) & 0x0f) | 0x50);
+           } else {
+               /* initialize for play */
+               static u_char cmd[] = {
+                   0x80,0x51,0xd0,0x00,0x71,0xf4,
+                   0x80,0x51,0x98,0x00,0x71,0xbc
+               };
+               ess_write(d->io_base, 0xb8, 0); /* normal DMA */
+               c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ;
+               if (! (d->flags & SND_F_STEREO))
+                   c++;
+               ess_write(d->io_base, 0xa8, c);
+               ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */
+               
+               cmd_ofs = cmd + ((d->flags & SND_F_STEREO) ? 6 : 0) 
+                   + ((d->play_fmt == AFMT_S16_LE) ? 3 : 0);
+               ess_write(d->io_base, 0xb6, cmd_ofs[0]);
+               ess_write(d->io_base, 0xb7, cmd_ofs[1]);
+               ess_write(d->io_base, 0xb7, cmd_ofs[2]);
 
-               c = (ess_read(d->io_base, 0xa8) & ~0x03) | 0x01;
-               if ((d->flags & SND_F_STEREO) == 0)
-                       c++;
-               ess_write(d->io_base, 0xa8, c); /* select mono/stereo */
-               ess_write(d->io_base, 0xb9, 2); /* demand 4 bytes/transfer */
-
-               switch (d->play_fmt ? d->play_fmt : d->rec_fmt) {
-               case AFMT_S16_LE:
-                       if (d->flags & SND_F_STEREO) {
-                               /* 16 bit stereo */
-                               if (d->play_fmt)
-                                       ess_write(d->io_base, 0xb6, 0x00);
-                               ess_write(d->io_base, 0xb7, 0x71);
-                               ess_write(d->io_base, 0xb7, 0xbc);
-                       }
-                       else {
-                               /* 16 bit mono */
-                               if (d->play_fmt)
-                                       ess_write(d->io_base, 0xb6, 0x00);
-                               ess_write(d->io_base, 0xb7, 0x71);
-                               ess_write(d->io_base, 0xb7, 0xf4);
-                       }
-                       break;
-               case AFMT_U8:
-                       if (d->flags & SND_F_STEREO) {
-                               /* 8 bit stereo */
-                               if (d->play_fmt)
-                                       ess_write(d->io_base, 0xb6, 0x80);
-                               ess_write(d->io_base, 0xb7, 0x51);
-                               ess_write(d->io_base, 0xb7, 0x98);
-                       }
-                       else {
-                               /* 8 bit mono */
-                               if (d->play_fmt)
-                                       ess_write(d->io_base, 0xb6, 0x80);
-                               ess_write(d->io_base, 0xb7, 0x51);
-                               ess_write(d->io_base, 0xb7, 0xd0);
-                       }
-                       break;
-               }
                ess_write(d->io_base, 0xb1,
-                         ess_read(d->io_base, 0xb1) | 0x50);
+                         (ess_read(d->io_base, 0xb1) & 0x0f) | 0x50);
                ess_write(d->io_base, 0xb2,
-                         ess_read(d->io_base, 0xb1) | 0x50);
+                         (ess_read(d->io_base, 0xb2) & 0x0f) | 0x50);
+           }
+       }
+       if (! (d->bd_flags & BD_F_ESS)) {
+           /*
+            * isa_dmastart will be called on the same channel
+            * with a half duplex device.
+            */
+           reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
+           reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
+       } else {
+           if (FULL_DUPLEX(d)) {
+               reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
+               reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
+           } else {
+               if (d->play_fmt) {
+                   reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
+               } else if (d->rec_fmt) {
+                   reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
+               }
+           }
        }
-       reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
-       reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
        break ;
 
     case SND_CB_START : /* called with int disabled */
@@ -547,18 +581,25 @@
            sb_cmd(d->io_base, c );
            sb_cmd3(d->io_base, c1 , l - 1) ;
        } else if (d->bd_flags & BD_F_ESS) {
-               u_long fmt = rd ? d->rec_fmt : d->play_fmt;
+           short c = -l;
+           u_char c1;
 
-               DEB(printf("SND_CB_START: %s (%d)\n", rd ? "rd" : "wr", l));
-               if (fmt == AFMT_S16_LE)
-                       l >>= 1;
-               l--;
-               if (!rd)
-                       sb_cmd(d->io_base, DSP_CMD_SPKON);
-               ess_write(d->io_base, 0xa4, l);
-               ess_write(d->io_base, 0xa5, l >> 8);
-               ess_write(d->io_base, 0xb8,
-                         ess_read(d->io_base, 0xb8) | (rd ? 0x0f : 0x05));
+           /*
+            * clear bit 0 of register B8h
+            */
+           c1 = ess_read(d->io_base, 0xb8) & 0xfe ;
+           ess_write(d->io_base, 0xb8, c1++);
+           /*
+            * update ESS Transfer Count Register
+            */
+           ess_write(d->io_base, 0xa4, (u_char)((u_short)c & 0xff));
+           ess_write(d->io_base, 0xa5, (u_char)((u_short)(c >> 8) & 0xff));
+           /*
+            * set bit 0 of register B8h
+            */
+           ess_write(d->io_base, 0xb8, c1);
+           if (! rd)
+               sb_cmd(d->io_base, DSP_CMD_SPKON);
        } else { /* SBPro -- stereo not supported */
            u_char c ;
            if (!rd)
@@ -589,10 +630,10 @@
     case SND_CB_STOP :
        {
            int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */
-               DEB(printf("SND_CB_XXX: reason 0x%x\n", reason));
-           if ( b->chan > 4
-                || (rd && d->rec_fmt == AFMT_S16_LE)
-                || (!rd && d->play_fmt == AFMT_S16_LE)
+           if (!(d->bd_flags & BD_F_ESS)
+               && (b->chan > 4
+               || (rd && d->rec_fmt == AFMT_S16_LE)
+               || (!rd && d->play_fmt == AFMT_S16_LE))
               )
                cmd = DSP_CMD_DMAPAUSE_16 ;
            if (d->bd_flags & BD_F_HISPEED) {
@@ -601,7 +642,22 @@
                    sb_cmd(d->io_base, 0xc6 ); /* enable extended ESS mode */
                d->flags |= SND_F_INIT ;
            } else {
-               sb_cmd(d->io_base, cmd); /* pause dma. */
+#ifdef ESS_IGNORE_PAUSE_COMMAND
+               if (d->bd_flags & BD_F_ESS) {
+                   DEB(u_char c1 ;
+                       c1 = ess_read(d->io_base, 0xb8) ;
+                       printf("CB_STOP: b8 0x%x\n", (u_int) c1);)
+                   if (rd) {
+#if ESS_RECORD_WITH_NORMAL_DMA
+                       ess_write(d->io_base, 0xb8, 0x0a);
+#else
+                       ess_write(d->io_base, 0xb8, 0x0e);
+#endif
+                   } else
+                       ess_write(d->io_base, 0xb8, 0x00);
+               } else
+#endif
+                   sb_cmd(d->io_base, cmd); /* pause dma. */
               /*
                * The above seems to have the undocumented side effect of
                * blocking the other side as well. If the other
@@ -669,6 +725,7 @@
     int i, x;
     char *fmt = NULL ;
     int        io_base = dev->id_iobase ;
+    u_char ess_ident[4];
 
     d->bd_id = 0 ;
 
@@ -761,25 +818,32 @@
                } else
                    DELAY(20);
            }
-
            if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) {
                /* the ESS488 can be treated as an SBPRO */
                printf("ESS488 (rev %d)\n", ess_minor & 0x0f);
                break ;
-           }
-               else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
-                       int rev = ess_minor & 0xf;
-
-                       if (rev >= 8)
-                               printf("ESS1868 (rev %d)\n", rev);
-                       else
-                               printf("ESS688 (rev %d)\n", rev);
-                       d->bd_flags |= BD_F_ESS;
-                       d->audio_fmt |= AFMT_S16_LE;
-
-                       /* enable extended ESS mode */
-                       sb_cmd(d->io_base, 0xc6);
-                       break;
+           } else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
+               int rev = ess_minor & 0xf ;
+               if ( rev >= 8 ) {
+                   ess_cont_getmixer(io_base, 0x40, ess_ident, sizeof(ess_ident));
+                   if (ess_ident[0] == 0x18) {
+                       sprintf(fmt, "ESS18%x %%d.%%d", ess_ident[1]);
+                       printf("ESS18%x (rev %d, native mode)\n", ess_ident[1], rev);
+                   } else {
+                       sprintf(fmt, "ESS Chip %%d.%%d");
+                       printf("ESS Chip (rev %d, %x%x, native mode)\n", rev, 
+ess_ident[0], ess_ident[1]);
+                   }
+               } else {
+                   sprintf(fmt, "ESS688 %%d.%%d");
+                   printf("ESS688 (rev %d, native mode)\n", rev);
+               }
+               d->audio_fmt |= AFMT_S16_LE;
+               d->bd_flags |= BD_F_ESS;
+               d->bd_flags &= ~BD_F_MIX_MASK ;
+               d->bd_flags |= BD_F_MIX_ESS688 ;
+               sb_reset_dsp(io_base);
+               sb_cmd(io_base, 0xc6);
+               break ;
            } else {
                printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n",
                        ess_major, ess_minor);
@@ -798,6 +862,7 @@
 static void
 sb_mix_init(snddev_info *d)
 {
+    u_int mixval;
     switch (d->bd_flags & BD_F_MIX_MASK) {
     case BD_F_MIX_CT1345 : /* SB 3.0 has 1345 mixer */
 
@@ -816,6 +881,20 @@
        d->mix_devs = SB16_MIXER_DEVICES ;
        d->mix_rec_devs = SB16_RECORDING_DEVICES ;
        d->mix_recsrc = SOUND_MASK_MIC ;
+       break ;
+
+    case BD_F_MIX_ESS688 : /* ESS688/ESS1868 mixer */
+
+       mixval = (u_int)sb_getmixer(d->io_base, ESS_VOLCTL);
+       if (mixval & 1) {
+           printf("%s: setting master volume control register"
+               "(compatibility mode)\n", d->name);
+           sb_setmixer(d->io_base, ESS_VOLCTL, mixval & ~1);
+       }
+       d->mix_devs = ESS_MIXER_DEVICES ;
+       d->mix_rec_devs = ESS_RECORDING_DEVICES ;
+       d->mix_recsrc = SOUND_MASK_MIC ;
+       break ;
     }
     sb_mixer_reset(d);
 }
@@ -931,6 +1010,20 @@
     return sb_get_byte(io_base);
 }
 
+void
+ess_cont_getmixer(int io_base, u_int port, u_char *buf, int num)
+{
+    int            val;
+    int     i;
+    u_long  flags;
+
+    flags = spltty();
+    outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff));   /* Select register */
+    for (i = 0; i < num; buf++, i++) {
+        *buf = inb(io_base + SB_MIX_DATA);
+    }
+    splx(flags);
+}
 
 /*
  * various utility functions for the DSP
@@ -1067,6 +1160,7 @@
     mask &= d->mix_rec_devs;
     switch (d->bd_flags & BD_F_MIX_MASK) {
     case BD_F_MIX_CT1345 :
+    case BD_F_MIX_ESS688 :
        if (mask == SOUND_MASK_LINE)
            recdev = 6 ;
        else if (mask == SOUND_MASK_CD)
@@ -1121,7 +1215,7 @@
     sb_set_recsrc(d, SOUND_MASK_MIC);
 }
 
-static int
+int
 sb_mixer_set(snddev_info *d, int dev, int value)
 {
     int left = value & 0x000000ff;
@@ -1159,6 +1253,9 @@
        break;
     case BD_F_MIX_CT1745 :
        iomap = &sb16_mix ;
+       break;
+    case BD_F_MIX_ESS688 :
+       iomap = &ess688_mix ;
        break;
     /* XXX how about the SG NX Pro, iomap = sgnxpro_mix */
     }
diff -uNr snd.org/sbcard.h snd/sbcard.h
--- snd.org/sbcard.h    Wed Aug 11 10:36:53 1999
+++ snd/sbcard.h        Wed Aug 11 10:21:33 1999
@@ -2,6 +2,10 @@
  * file: sbcard.h
  */
 
+/*
+ *     $Id$
+ */
+
 typedef struct _sbdev_info {
 
 } sbdev_info ;
@@ -136,6 +140,7 @@
 #define        BD_F_MIX_CT1335 0x0010  /* CT1335               */
 #define        BD_F_MIX_CT1345 0x0020  /* CT1345               */
 #define        BD_F_MIX_CT1745 0x0030  /* CT1745               */
+#define        BD_F_MIX_ESS688 0x0040  /* ESS688/ESS1868 mixer */
 
 #define        BD_F_SB16       0x0100  /* this is a SB16 */
 #define        BD_F_SB16X      0x0200  /* this is a vibra16X or clone */
@@ -208,6 +213,14 @@
      SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
      SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
 
+#define ESS_MIXER_DEVICES      \
+    (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | \
+     SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \
+     SOUND_MASK_VOLUME)
+
+/* XXX I don't know;-) */
+#define ESS_RECORDING_DEVICES  SB16_RECORDING_DEVICES
+
 /*
  * Mixer registers
  * 
@@ -253,6 +266,10 @@
 #define SB16_IMASK_R   0x3e
 #define SB16_OMASK     0x3c
 
+/*
+ * ESS mixer cnotrol extension registers
+ */
+#define        ESS_VOLCTL      0x64
 
 #ifndef __SB_MIXER_C__
 mixer_tab       sbpro_mix;
@@ -314,6 +331,23 @@
     PMIX_ENT(SOUND_MIXER_OGAIN,   0x41, 6, 2, 0x42, 6, 2)
 };
 
+mixer_tab       ess688_mix = {
+    PMIX_ENT(SOUND_MIXER_VOLUME,  0x32, 4, 4, 0x32, 0, 4),
+    PMIX_ENT(SOUND_MIXER_BASS,    0x00, 0, 0, 0x00, 0, 0),
+    PMIX_ENT(SOUND_MIXER_TREBLE,  0x00, 0, 0, 0x00, 0, 0),
+    PMIX_ENT(SOUND_MIXER_SYNTH,   0x36, 4, 4, 0x36, 0, 4),
+    PMIX_ENT(SOUND_MIXER_PCM,     0x14, 4, 4, 0x14, 0, 4),
+    PMIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 0, 3, 0x00, 0, 0),
+    PMIX_ENT(SOUND_MIXER_LINE,    0x3e, 4, 4, 0x3e, 0, 4),
+    PMIX_ENT(SOUND_MIXER_MIC,     0x1a, 4, 4, 0x1a, 0, 4),
+    PMIX_ENT(SOUND_MIXER_CD,      0x38, 4, 4, 0x38, 0, 4),
+    PMIX_ENT(SOUND_MIXER_IMIX,    0x00, 0, 0, 0x00, 0, 0),
+    PMIX_ENT(SOUND_MIXER_ALTPCM,  0x00, 0, 0, 0x00, 0, 0),
+    PMIX_ENT(SOUND_MIXER_RECLEV,  0x00, 0, 0, 0x00, 0, 0),
+    PMIX_ENT(SOUND_MIXER_IGAIN,   0x00, 0, 0, 0x00, 0, 0),
+    PMIX_ENT(SOUND_MIXER_OGAIN,   0x00, 0, 0, 0x00, 0, 0)
+};
+
 #ifdef SM_GAMES                        /* Master volume is lower and PCM & FM
                                 * volumes higher than with SB Pro. This
                                 * improves the sound quality */
@@ -346,7 +380,7 @@
        0x4b4b,                 /* PCM */
        0x4b4b,                 /* PC Speaker */
        0x4b4b,                 /* Ext Line */
-       0x1010,                 /* Mic */
+       0x0000,                 /* Mic */
        0x4b4b,                 /* CD */
        0x4b4b,                 /* Recording monitor */
        0x4b4b,                 /* SB PCM */
diff -uNr snd.org/sound.c snd/sound.c
--- snd.org/sound.c     Wed Aug 11 10:36:53 1999
+++ snd/sound.c Wed Aug 11 10:21:33 1999
@@ -50,9 +50,14 @@
  *
  */
 
+/*
+ *     $Id$
+ */
+
 #include "opt_devfs.h"
 
 #include <i386/isa/snd/sound.h>
+#include <i386/isa/snd/sbcard.h>
 #ifdef DEVFS
 #include <sys/devfsext.h>
 #endif /* DEVFS */
@@ -145,6 +150,20 @@
            outb(0x371, 0xa9 ); /* use both dma chans */
        else
            outb(0x371, 0x8b ); /* use low dma chan */
+    } else if (d->bd_flags & BD_F_ESS) {
+       int i ;
+
+       DDB(printf("ESS: resume\n"));
+       sb_reset_dsp(d->io_base);
+       sb_cmd(d->io_base, 0xc6);
+
+       if (d->dbuf_out.dl)
+           dsp_wrabort(d, 1 /* restart */);
+       if (d->dbuf_in.dl)
+           dsp_rdabort(d, 1 /* restart */);
+
+       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+           sb_mixer_set(d, i, d->mix_levels[i]);
     }
        printf("Called APM sound resume hook for unit %d\n", (int)arg);
        return 0 ;
@@ -967,8 +986,21 @@
        break ;
     case SNDCTL_DSP_RESET:
        DEB(printf("dsp reset\n"));
-       dsp_wrabort(d, 1 /* restart */);
-       dsp_rdabort(d, 1 /* restart */);
+       if (! (d->bd_flags & BD_F_ESS)) {
+           dsp_wrabort(d, 1 /* restart */);
+           dsp_rdabort(d, 1 /* restart */);
+       } else {
+           if (FULL_DUPLEX(d)) {
+               dsp_wrabort(d, 1 /* restart */);
+               dsp_rdabort(d, 1 /* restart */);
+           } else {
+               if (d->play_fmt) {
+                   dsp_wrabort(d, 1 /* restart */);
+               } else if (d->rec_fmt) {
+                   dsp_rdabort(d, 1 /* restart */);
+               }
+           }
+       }
        break ;
 
     case SNDCTL_DSP_SYNC:
@@ -1035,8 +1067,19 @@
        if (d->rec_fmt)
            d->rec_fmt = *(int *)arg ;
        splx(s);
-       if (ask_init(d))
-           *(int *)arg = d->play_fmt ;
+       if (ask_init(d)) {
+           /*
+            * ioctl will fail if (half duplex) ESS is opened RDONLY.
+            */
+           if (d->bd_flags & BD_F_ESS) {
+               if (d->play_fmt)
+                   *(int *)arg = d->play_fmt ;
+               else if (d->rec_fmt)    /* XXX */
+                   *(int *)arg = d->rec_fmt ;
+           } else {
+               *(int *)arg = d->play_fmt ;
+           }
+       }
        break ;
 
     case SNDCTL_DSP_SUBDIVIDE:
diff -uNr snd.org/sound.h snd/sound.h
--- snd.org/sound.h     Wed Aug 11 10:36:53 1999
+++ snd/sound.h Wed Aug 11 10:21:33 1999
@@ -28,6 +28,10 @@
  *
  */
 
+/*
+ *     $Id$
+ */
+
 #ifdef KERNEL
 #include "pcm.h"
 #else
@@ -498,6 +502,7 @@
 int sb_reset_dsp (int io_base);
 void sb_setmixer (int io_base, u_int port, u_int value);
 int sb_getmixer (int io_base, u_int port);
+int sb_mixer_set (snddev_info *d, int dev, int value);
 
 #endif /* KERNEL */
 
@@ -526,3 +531,7 @@
 #define DV_PNP_SBCODEC 0x1
 
 #endif
+/*
+ *
+ */
+#define ESS_RECORD_WITH_NORMAL_DMA 0


To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message

Reply via email to