diff -uNr sound.org/.objects sound/.objects
--- sound.org/.objects	Thu Aug  1 00:00:00 1996
+++ sound/.objects	Sun Mar 30 15:24:50 1997
@@ -65,7 +65,7 @@
 endif
 
 ifdef CONFIG_SBDSP
-	OBJS := $(OBJS) sb_card.o sb_common.o sb_audio.o sb_mixer.o sb_midi.o
+	OBJS := $(OBJS) sb_card.o sb_common.o sb_audio.o sb_mixer.o sb_midi.o es1488.o
 endif
 
 ifdef CONFIG_SEQUENCER
diff -uNr sound.org/audio.c sound/audio.c
--- sound.org/audio.c	Wed Oct 30 22:09:56 1996
+++ sound/audio.c	Sun Mar 30 20:46:28 1997
@@ -326,7 +326,12 @@
 	  translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
 	}
 
-      memcpy_tofs (&(buf)[p], dmabuf, l);
+      if (!audio_devs[dev]->d->copy_from_user)
+	{
+	  memcpy_tofs(&(buf)[p], dmabuf, l);
+	}
+      else
+	audio_devs[dev]->d->copy_from_user(dev, dmabuf, 0, buf, p, -l);
 
       DMAbuf_rmchars (dev, buf_no, l);
 
diff -uNr sound.org/es1488.S sound/es1488.S
--- sound.org/es1488.S	Thu Jan  1 09:00:00 1970
+++ sound/es1488.S	Sun Mar 30 15:21:08 1997
@@ -0,0 +1,65 @@
+	.text
+	.globl	es1488_memcpy_fromfs
+es1488_memcpy_fromfs:
+	pushl	%ebp
+	movl	%esp,%ebp
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	pushl	%esi
+	pushl	%edi
+	movl	8(%ebp),%edi		/* dst */
+	movl	12(%ebp),%esi		/* src */
+	movl	16(%ebp),%edx		/* len */
+	mov	$0x80008000,%ebx	/* mask */
+	cld
+
+	cmpl	$3,%edx			/* len <= 3 ? */
+	jbe	9f
+	movl	%edi,%ecx
+	negl	%ecx
+	andl	$3,%ecx
+	jnz	5f			/* not aligned ? */
+1:
+	movl	%edx,%ecx
+	shrl	$2,%ecx			/* 4byte/loop */
+	jecxz	3f
+2:					/* main loop */
+	fs; lodsl %esi
+	xorl	%ebx,%eax
+	stosl	%edi
+	loop	2b
+3:
+	andl	$3,%edx			/* rest ? */
+	jnz	7f
+4:
+	popl	%edi
+	popl	%esi
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	popl	%ebp
+	ret
+5:					/* align head */
+	subl	%ecx,%edx
+6:
+	fs; lodsb %esi
+	xorb	%bl,%al
+	stosb	%edi
+	rorl	$8,%ebx
+	loop	6b
+	jmp	1b
+7:					/* rest bytes */
+	mov	%edx,%ecx
+8:
+	fs; lodsb %esi
+	xorb	%bl,%al
+	stosb	%edi
+	rorl	$8,%ebx
+	loop	8b
+	jmp	4b
+9:					/* len <= 3 */
+	mov	%edx,%ecx
+	jecxz	4b
+	jmp	8b
+	.end
diff -uNr sound.org/sb.h sound/sb.h
--- sound.org/sb.h	Sun Jul 21 12:33:48 1996
+++ sound/sb.h	Sun Mar 16 15:31:45 1997
@@ -5,8 +5,12 @@
 #define DSP_STATUS	(devc->base + 0xC)
 #define DSP_DATA_AVAIL	(devc->base + 0xE)
 #define DSP_DATA_AVL16	(devc->base + 0xF)
-#define MIXER_ADDR	(devc->base + 0x4)
-#define MIXER_DATA	(devc->base + 0x5)
+#define MIXER_ADDR	(devc->base + sb_mixer_addr)
+#define MIXER_DATA	(devc->base + sb_mixer_data)
+# define ES1488_MIXER_ADDR	0x2
+# define ES1488_MIXER_DATA	0x3
+# define SB_MIXER_ADDR		0x4
+# define SB_MIXER_DATA		0x5
 #define OPL3_LEFT	(devc->base + 0x0)
 #define OPL3_RIGHT	(devc->base + 0x2)
 #define OPL3_BOTH	(devc->base + 0x8)
@@ -40,6 +44,7 @@
 #define MDL_SMW		11	/* Logitech SoundMan Wave (Jazz16) */
 #define MDL_ESS		12	/* ESS ES688 and ES1688 */
 #define MDL_AZTECH	13	/* Aztech Sound Galaxy family */
+#define MDL_ES1488	14	/* ESS ES1488 */
 
 /*
  * Config flags
diff -uNr sound.org/sb_audio.c sound/sb_audio.c
--- sound.org/sb_audio.c	Sun Aug 25 00:24:42 1996
+++ sound/sb_audio.c	Sun Mar 30 20:44:45 1997
@@ -575,6 +575,161 @@
 }
 
 /*
+ * ES1488 specific routines
+ */
+
+static int es1488_8bit = 0;
+
+static int
+es1488_audio_set_speed(int dev, int speed)
+{
+  sb_devc *devc = audio_devs[dev]->devc;
+  int max_speed, s, tmp;
+
+  if (speed > 0){
+    if (speed < 4000)
+      speed = 4000;
+    else {
+      max_speed = (devc->bits == 16) ? 22050 : 44100;
+      if (speed > max_speed)
+	speed = max_speed;
+    }
+
+    s = speed * devc->channels;
+    devc->tconst = ((65536 - ((256000000 + s / 2) / s)) >> 8) & 0xff;
+    tmp = 256 - devc->tconst;
+    speed = ((1000000 + tmp / 2) / tmp) / devc->channels;
+    devc->speed = speed;
+  }
+  return devc->speed;
+}
+
+static unsigned int
+es1488_audio_set_bits(int dev, unsigned int bits)
+{
+  sb_devc *devc = audio_devs[dev]->devc;
+
+  if (bits != 0){
+    if (bits != 16)
+      bits = 8;
+    devc->bits = bits;
+    es1488_audio_set_speed(dev, devc->speed);
+  }
+  return devc->bits;
+}
+
+static void
+es1488_audio_output_block(int dev, unsigned long buf, int nr_bytes,
+			  int intrflag, int restart_dma)
+{
+  unsigned long   flags;
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned char   cmd;
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+  count--;
+  devc->irq_mode = IMODE_OUTPUT;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x48)){	/* DSP Block size */
+    sb_dsp_command (devc, (unsigned char) (count & 0xff));
+    sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff));
+
+    cmd = (devc->bits == 16) ? 0x1d : 0x1c;
+    if (!sb_dsp_command (devc, cmd))
+      printk ("SB(ES1488): Unable to start DAC(1)\n");
+  } else
+    printk ("SB(ES1488): Unable to start DAC(2)\n");
+  restore_flags (flags);
+  devc->intr_active = 1;
+}
+
+static void
+es1488_audio_start_input(int dev, unsigned long buf, int nr_bytes, 
+			 int intrflag, int restart_dma)
+{
+  unsigned long   flags;
+  int             count = nr_bytes;
+  sb_devc        *devc = audio_devs[dev]->devc;
+  unsigned char   cmd;
+
+  DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+  count--;
+  devc->irq_mode = IMODE_INPUT;
+
+  save_flags (flags);
+  cli ();
+  if (sb_dsp_command (devc, 0x48)){	/* DSP Block size */
+    sb_dsp_command (devc, (unsigned char) (count & 0xff));
+    sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff));
+
+    cmd = (devc->bits == 16) ? 0x2d : 0x2c;  /* 0x98 ? */
+    if (!sb_dsp_command (devc, cmd))
+      printk ("SB(ES1488): Unable to start ADC(1)\n");
+  } else
+    printk ("SB(ES1488) : Unable to start ADC(2)\n");
+  restore_flags (flags);
+
+  devc->intr_active = 1;
+}
+
+static void
+es1488_audio_trigger(int dev, int bits)
+{
+  sb_devc *devc = audio_devs[dev]->devc;
+
+  bits &= devc->irq_mode;
+
+  if (!bits)
+    sb_dsp_command (devc, 0xd0);	/* Halt DMA */
+  else {
+    switch (devc->irq_mode){
+    case IMODE_INPUT:
+      es1488_audio_start_input(dev, devc->trg_buf, devc->trg_bytes,
+			       devc->trg_intrflag, devc->trg_restart);
+      break;
+
+    case IMODE_OUTPUT:
+      es1488_audio_output_block(dev, devc->trg_buf, devc->trg_bytes,
+				devc->trg_intrflag, devc->trg_restart);
+      break;
+    }
+  }
+  devc->trigger_bits = bits;
+}
+
+static void
+es1488_copy_from_user(int dev, char *dma_buf, int buf_ptr,
+		      const char *buf, int p, int l)
+{
+  sb_devc *devc = audio_devs[dev]->devc;
+  int n;
+  unsigned char *s;
+  extern void es1488_memcpy_fromfs(char *, const char *, int);
+
+  if (l >= 0){ /* copy from user */
+    if (devc->bits == 16)
+      es1488_memcpy_fromfs(&dma_buf[buf_ptr], &(buf)[p], l);
+    else
+      memcpy_fromfs(&dma_buf[buf_ptr], &(buf)[p], l);
+  } else { /* copy to user */
+    l = -l;
+    if (devc->bits == 16){
+      /* convert to AFMT_S16_LE */
+      s = (unsigned char *)dma_buf + 1;
+      n = l >> 1;
+      while (--n >= 0){
+        *s ^= 0x80;
+        s += 2;
+      }
+    }
+    memcpy_tofs(&(buf)[p], dma_buf, l);
+  }
+}
+
+/*
  * ESS specific routines
  */
 
@@ -1043,6 +1198,27 @@
   sb1_audio_set_channels
 };
 
+static struct audio_driver es1488_audio_driver =	/* ES1488 */
+{
+  sb_audio_open,
+  sb_audio_close,
+  sb_set_output_parms,
+  sb_set_input_parms,
+  sb_audio_ioctl,
+  sb1_audio_prepare_for_input,
+  sb1_audio_prepare_for_output,
+  sb_audio_reset,
+  sb1_audio_halt_xfer,
+  NULL,				/* local_qlen */
+  es1488_copy_from_user,
+  NULL,
+  NULL,
+  es1488_audio_trigger,
+  es1488_audio_set_speed,
+  es1488_audio_set_bits,
+  sb1_audio_set_channels
+};
+
 static struct audio_driver sbpro_audio_driver =		/* SB Pro */
 {
   sb_audio_open,
@@ -1152,6 +1328,14 @@
       DDB (printk ("Will use SB2.01 (high speed) driver\n"));
       audio_flags = DMA_AUTOMODE;
       driver = &sb201_audio_driver;
+      break;
+
+    case MDL_ES1488:
+      DDB (printk ("Will use ES1488 driver\n"));
+      audio_flags = DMA_AUTOMODE;
+      if (!es1488_8bit)
+	format_mask |= AFMT_S16_LE;
+      driver = &es1488_audio_driver;
       break;
 
     case MDL_JAZZ:
diff -uNr sound.org/sb_common.c sound/sb_common.c
--- sound.org/sb_common.c	Sat Oct  5 16:38:37 1996
+++ sound/sb_common.c	Sun Mar 16 15:33:27 1997
@@ -33,6 +33,9 @@
 static unsigned char jazz_dma_bits[] =
 {0, 1, 0, 2, 0, 3, 0, 4};
 
+static int sb_mixer_addr = SB_MIXER_ADDR;
+static int sb_mixer_data = SB_MIXER_DATA;
+
 /*
  * Jazz16 chipset specific control variables
  */
@@ -207,7 +210,7 @@
   if (inb (DSP_READ) != 0xAA)
     return 0;			/* Sorry */
 
-  if (devc->model == MDL_ESS)
+  if (devc->model == MDL_ESS  ||  devc->model == MDL_ES1488)
     sb_dsp_command (devc, 0xc6);	/* Enable extended mode */
 
   return 1;
@@ -456,13 +459,21 @@
   if (ess_major == 0)
     return 0;
 
+  devc->model = MDL_ESS;
+  devc->submodel = ess_minor & 0x0f;
   if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
     {
-      sprintf (name, "ESS ES488 AudioDrive (rev %d)",
-	       ess_minor & 0x0f);
-      hw_config->name = name;
-      devc->model = MDL_SBPRO;
-      return 1;
+      if (devc->submodel >= 0x8){
+        sprintf (name, "ESS ES1488 AudioDrive (rev %d)",
+	         ess_minor & 0x0f);
+        devc->model = MDL_ES1488;
+        sb_mixer_addr = ES1488_MIXER_ADDR;
+        sb_mixer_data = ES1488_MIXER_DATA;
+      } else {
+        sprintf (name, "ESS ES488 AudioDrive (rev %d)",
+	         ess_minor & 0x0f);
+        devc->model = MDL_SBPRO;
+      }
     }
   else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
     {
@@ -473,9 +484,6 @@
   else
     strcpy (name, "Jazz16");
 
-  devc->model = MDL_ESS;
-  devc->submodel = ess_minor & 0x0f;
-
   hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1)));
   if (sound_nblocks < 1024)
     sound_nblocks++;;
@@ -485,6 +493,9 @@
 
   sb_dsp_reset (devc);		/* Turn on extended mode */
 
+  if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
+    return (1);
+
 /*
  *    Set IRQ configuration register
  */
@@ -643,6 +654,7 @@
 {
   sb_devc        *devc;
   char            name[100];
+  int             ess = 0;
 
 #ifndef NO_SB_IRQ_TEST
   int             n;
@@ -692,17 +704,19 @@
 	return;
       }
 
-  if ((devc->type == 0 || devc->type == MDL_ESS) &&
-      devc->major == 3 && devc->minor == 1)
+  if (devc->type == 0  ||  devc->type == MDL_ESS){
+    ess = ess_init (devc, hw_config);
+    if (devc->major == 3 && devc->minor == 1)
     {				/* Handle various chipsets which claim they are SB Pro compatible */
       if ((devc->type != 0 && devc->type != MDL_ESS) ||
-	  !ess_init (devc, hw_config))
+	  !ess)
 	if ((devc->type != 0 && devc->type != MDL_JAZZ &&
 	     devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config))
 	  {
 	    DDB (printk ("This is a genuine SB Pro\n"));
 	  }
     }
+  }
 
 #ifndef NO_SB_IRQ_TEST
   if (devc->major != 4 || devc->minor > 11) /* Not Sb16 v4.5 or v4.11 */
@@ -737,10 +751,12 @@
       break;
 
     case 2:			/* SB 2.x */
+      if (devc->model == 0){
       if (devc->minor == 0)
 	devc->model = hw_config->card_subtype = MDL_SB2;
       else
 	devc->model = hw_config->card_subtype = MDL_SB201;
+      }
       break;
 
     case 3:			/* SB Pro and most clones */
@@ -772,7 +788,8 @@
     }
 
   if (!(devc->caps & SB_NO_MIXER))
-    if (devc->major == 3 || devc->major == 4)
+    if (devc->major == 3 || devc->major == 4
+       || devc->model == MDL_ES1488)
       sb_mixer_init (devc);
 
 #ifdef CONFIG_MIDI
diff -uNr sound.org/sb_mixer.c sound/sb_mixer.c
--- sound.org/sb_mixer.c	Sun Aug 25 00:24:48 1996
+++ sound/sb_mixer.c	Sun Mar 30 19:19:38 1997
@@ -228,6 +228,7 @@
     case MDL_ESS:
     case MDL_JAZZ:
     case MDL_SMW:
+    case MDL_ES1488:
 
       if (devmask != SOUND_MASK_MIC &&
 	  devmask != SOUND_MASK_LINE &&
@@ -384,6 +385,13 @@
       devc->supported_devices = SBPRO_MIXER_DEVICES;
       devc->supported_rec_devices = SBPRO_RECORDING_DEVICES;
       devc->iomap = &sbpro_mix;
+      break;
+
+    case MDL_ES1488:
+      devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
+      devc->supported_devices = SBPRO_MIXER_DEVICES;
+      devc->supported_rec_devices = SBPRO_RECORDING_DEVICES;
+      devc->iomap = &es1488_mix;
       break;
 
     case MDL_ESS:
diff -uNr sound.org/sb_mixer.h sound/sb_mixer.h
--- sound.org/sb_mixer.h	Sun Jul 21 12:33:29 1996
+++ sound/sb_mixer.h	Sun Mar 30 18:56:55 1997
@@ -111,6 +111,20 @@
 MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0)
 };
+mixer_tab es1488_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,	0x32, 7, 4, 0x32, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,	0x36, 7, 4, 0x36, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,	0x14, 7, 4, 0x14, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,	0x3e, 7, 4, 0x3e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,	0x1a, 7, 4, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD,		0x38, 7, 4, 0x38, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0)
+};
 mixer_tab es688_mix = {
 MIX_ENT(SOUND_MIXER_VOLUME,	0x32, 7, 4, 0x32, 3, 4),
 MIX_ENT(SOUND_MIXER_BASS,	0x00, 0, 0, 0x00, 0, 0),
