You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.

===================================================================


ChangeSet@1.651, 2002-10-01 14:44:13+02:00, perex@suse.cz
  ALSA update 2002/09/06 :
    - VIA686 and VIA8233 driver merge to VIA82xx
    - ioctl32 fixes
    - fixed OOPS in snd_pcm_sgbuf_delete (not initialized)
    - I2C - call hw_stop() before returning at the error pointer
    - AC'97 codec - added more AC97 IDs by Laszlo Melis
    - CS46xx - mutex initialization fix
    - ENS1371 - added one more card to S/PDIF capabilities
    - intel8x0
      - fixed secondary and third codec indexes
    - PPC Keywest - initialize MCS in loop until it succeeds
    - PPC Tumbler - the initial support for snapper (TAS3004) on some tibook
    - USB Audio - mixer fixes


 b/include/sound/sndmagic.h           |    3 
 b/include/sound/version.h            |    2 
 b/sound/core/Makefile                |    3 
 b/sound/core/ioctl32/hwdep32.c       |    2 
 b/sound/core/ioctl32/ioctl32.c       |  118 +--
 b/sound/core/ioctl32/ioctl32.h       |   22 
 b/sound/core/ioctl32/pcm32.c         |  104 +-
 b/sound/core/oss/mixer_oss.c         |    8 
 b/sound/core/pcm_sgbuf.c             |    3 
 b/sound/core/seq/Makefile            |    2 
 b/sound/core/seq/oss/seq_oss_synth.c |    4 
 b/sound/drivers/mpu401/Makefile      |    2 
 b/sound/i2c/i2c.c                    |   21 
 b/sound/pci/Config.help              |    7 
 b/sound/pci/Config.in                |    3 
 b/sound/pci/Makefile                 |    6 
 b/sound/pci/ac97/Makefile            |    3 
 b/sound/pci/ac97/ac97_codec.c        |   12 
 b/sound/pci/ac97/ac97_id.h           |    1 
 b/sound/pci/cs4281.c                 |   17 
 b/sound/pci/cs46xx/cs46xx_lib.c      |    3 
 b/sound/pci/ens1370.c                |    1 
 b/sound/pci/es1938.c                 |    4 
 b/sound/pci/es1968.c                 |    4 
 b/sound/pci/ice1712.c                |  129 ++-
 b/sound/pci/intel8x0.c               |   27 
 b/sound/pci/rme32.c                  |    8 
 b/sound/pci/via82xx.c                | 1345 +++++++++++++++++++++++++++++++++++
 b/sound/ppc/keywest.c                |    5 
 b/sound/ppc/pmac.c                   |   12 
 b/sound/ppc/pmac.h                   |    3 
 b/sound/ppc/powermac.c               |    6 
 b/sound/ppc/tumbler.c                |  299 ++++++-
 b/sound/ppc/tumbler_volume.h         |   66 +
 b/sound/usb/usbaudio.c               |   39 -
 b/sound/usb/usbmixer.c               |   66 +
 sound/pci/via686.c                   | 1232 --------------------------------
 sound/pci/via8233.c                  | 1022 --------------------------
 38 files changed, 2047 insertions(+), 2567 deletions(-)


diff -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h
--- a/include/sound/sndmagic.h	Tue Oct  1 17:08:34 2002
+++ b/include/sound/sndmagic.h	Tue Oct  1 17:08:34 2002
@@ -113,7 +113,7 @@
 #define intel8x0_t_magic			0xa15a2a01
 #define es1968_t_magic				0xa15a2b01
 #define esschan_t_magic				0xa15a2b02
-#define via686a_t_magic				0xa15a2c01
+#define via82xx_t_magic				0xa15a2c01
 #define pdplus_t_magic				0xa15a2d01
 #define cmipci_t_magic				0xa15a2e01
 #define ymfpci_t_magic				0xa15a2f01
@@ -126,7 +126,6 @@
 #define m3_dma_t_magic				0xa15a3202
 #define nm256_t_magic				0xa15a3301
 #define nm256_dma_t_magic			0xa15a3302
-#define via8233_t_magic				0xa15a3401
 #define pmac_t_magic				0xa15a3501
 #define ali_t_magic				0xa15a3601
 #define mtpav_t_magic				0xa15a3701
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Tue Oct  1 17:08:34 2002
+++ b/include/sound/version.h	Tue Oct  1 17:08:34 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc3"
-#define CONFIG_SND_DATE " (Mon Aug 26 16:28:35 2002 UTC)"
+#define CONFIG_SND_DATE " (Fri Sep 06 15:06:56 2002 UTC)"
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	Tue Oct  1 17:08:34 2002
+++ b/sound/core/Makefile	Tue Oct  1 17:08:34 2002
@@ -78,8 +78,7 @@
 obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd.o
 obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_VIA686) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_VIA8233) += snd-pcm.o snd-timer.o snd.o
+obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
 obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-pcm.o
 obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
 obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
diff -Nru a/sound/core/ioctl32/hwdep32.c b/sound/core/ioctl32/hwdep32.c
--- a/sound/core/ioctl32/hwdep32.c	Tue Oct  1 17:08:34 2002
+++ b/sound/core/ioctl32/hwdep32.c	Tue Oct  1 17:08:34 2002
@@ -28,7 +28,5 @@
 struct ioctl32_mapper hwdep_mappers[] = {
 	{ SNDRV_HWDEP_IOCTL_PVERSION, NULL },
 	{ SNDRV_HWDEP_IOCTL_INFO, NULL },
-	{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
-	{ SNDRV_CTL_IOCTL_HWDEP_INFO, NULL },
 	{ 0 },
 };
diff -Nru a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c
--- a/sound/core/ioctl32/ioctl32.c	Tue Oct  1 17:08:34 2002
+++ b/sound/core/ioctl32/ioctl32.c	Tue Oct  1 17:08:34 2002
@@ -47,14 +47,10 @@
 	int err;
 	struct ioctl32_mapper *m;
 
-	lock_kernel();
 	for (m = mappers; m->cmd; m++) {
 		err = register_ioctl32_conversion(m->cmd, m->handler);
-		if (err < 0) {
-			unlock_kernel();
-			return err;
-		}
-		m->registered++;
+		if (err >= 0)
+			m->registered++;
 	}
 	return 0;
 }
@@ -63,14 +59,12 @@
 {
 	struct ioctl32_mapper *m;
 
-	lock_kernel();
 	for (m = mappers; m->cmd; m++) {
 		if (m->registered) {
 			unregister_ioctl32_conversion(m->cmd);
 			m->registered = 0;
 		}
 	}
-	unlock_kernel();
 }
 
 
@@ -100,36 +94,32 @@
 {
 	struct sndrv_ctl_elem_list32 data32;
 	struct sndrv_ctl_elem_list data;
-	mm_segment_t oldseg = get_fs();
+	mm_segment_t oldseg;
 	int err;
 
-	set_fs(KERNEL_DS);
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
-		err = -EFAULT;
-		goto __err;
-	}
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
 	memset(&data, 0, sizeof(data));
 	data.offset = data32.offset;
 	data.space = data32.space;
 	data.used = data32.used;
 	data.count = data32.count;
 	data.pids = A(data32.pids);
+	oldseg = get_fs();
+	set_fs(KERNEL_DS);
 	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	set_fs(oldseg);
 	if (err < 0)
-		goto __err;
+		return err;
 	/* copy the result */
 	data32.offset = data.offset;
 	data32.space = data.space;
 	data32.used = data.used;
 	data32.count = data.count;
 	//data.pids = data.pids;
-	if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
-		err = -EFAULT;
-		goto __err;
-	}
- __err:
-	set_fs(oldseg);
-	return err;
+	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
+		return -EFAULT;
+	return 0;
 }
 
 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
@@ -171,22 +161,22 @@
 	struct sndrv_ctl_elem_info data;
 	struct sndrv_ctl_elem_info32 data32;
 	int err;
-	mm_segment_t oldseg = get_fs();
+	mm_segment_t oldseg;
 
-	set_fs(KERNEL_DS);
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
-		err = -EFAULT;
-		goto __err;
-	}
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
 	memset(&data, 0, sizeof(data));
 	data.id = data32.id;
 	/* we need to copy the item index.
 	 * hope this doesn't break anything..
 	 */
 	data.value.enumerated.item = data32.value.enumerated.item;
+	oldseg = get_fs();
+	set_fs(KERNEL_DS);
 	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	set_fs(oldseg);
 	if (err < 0)
-		goto __err;
+		return err;
 	/* restore info to 32bit */
 	data32.id = data.id;
 	data32.type = data.type;
@@ -215,10 +205,8 @@
 		break;
 	}
 	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
-		err = -EFAULT;
- __err:
-	set_fs(oldseg);
-	return err;
+		return -EFAULT;
+	return 0;
 }
 
 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
@@ -281,26 +269,20 @@
 	struct sndrv_ctl_elem_value32 data32;
 	int err, i;
 	int type;
-	mm_segment_t oldseg = get_fs();
-
-	set_fs(KERNEL_DS);
+	mm_segment_t oldseg;
 
 	/* FIXME: check the sane ioctl.. */
 
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
-		err = -EFAULT;
-		goto __err;
-	}
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
 	memset(&data, 0, sizeof(data));
 	data.id = data32.id;
 	data.indirect = data32.indirect;
 	if (data.indirect) /* FIXME: this is not correct for long arrays */
 		data.value.integer.value_ptr = (void*)TO_PTR(data32.value.integer.value_ptr);
 	type = get_ctl_type(file, &data.id);
-	if (type < 0) {
-		err = type;
-		goto __err;
-	}
+	if (type < 0)
+		return type;
 	if (! data.indirect) {
 		switch (type) {
 		case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
@@ -329,9 +311,12 @@
 		}
 	}
 
+	oldseg = get_fs();
+	set_fs(KERNEL_DS);
 	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	set_fs(oldseg);
 	if (err < 0)
-		goto __err;
+		return err;
 	/* restore info to 32bit */
 	if (! data.indirect) {
 		switch (type) {
@@ -360,10 +345,8 @@
 		}
 	}
 	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
-		err = -EFAULT;
- __err:
-	set_fs(oldseg);
-	return err;
+		return -EFAULT;
+	return 0;
 }
 
 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
@@ -392,6 +375,7 @@
 	{ SNDRV_CTL_IOCTL_ELEM_LOCK, NULL },
 	{ SNDRV_CTL_IOCTL_ELEM_UNLOCK, NULL },
 	{ SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, NULL },
+	{ SNDRV_CTL_IOCTL_HWDEP_INFO, NULL },
 	{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
 	{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
 	{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
@@ -427,37 +411,13 @@
 
 static int __init snd_ioctl32_init(void)
 {
-	int err;
-	
-	err = snd_ioctl32_register(control_mappers);
-	if (err < 0)
-		return err;
-	err = snd_ioctl32_register(pcm_mappers);
-	if (err < 0) {
-		snd_ioctl32_done();
-		return err;
-	}
-	err = snd_ioctl32_register(rawmidi_mappers);
-	if (err < 0) {
-		snd_ioctl32_done();
-		return err;
-	}
-	err = snd_ioctl32_register(timer_mappers);
-	if (err < 0) {
-		snd_ioctl32_done();
-		return err;
-	}
-	err = snd_ioctl32_register(hwdep_mappers);
-	if (err < 0) {
-		snd_ioctl32_done();
-		return err;
-	}
+	snd_ioctl32_register(control_mappers);
+	snd_ioctl32_register(pcm_mappers);
+	snd_ioctl32_register(rawmidi_mappers);
+	snd_ioctl32_register(timer_mappers);
+	snd_ioctl32_register(hwdep_mappers);
 #ifdef CONFIG_SND_SEQUENCER
-	err = snd_ioctl32_register(seq_mappers);
-	if (err < 0) {
-		snd_ioctl32_done();
-		return err;
-	}
+	snd_ioctl32_register(seq_mappers);
 #endif
 	return 0;
 }
diff -Nru a/sound/core/ioctl32/ioctl32.h b/sound/core/ioctl32/ioctl32.h
--- a/sound/core/ioctl32/ioctl32.h	Tue Oct  1 17:08:34 2002
+++ b/sound/core/ioctl32/ioctl32.h	Tue Oct  1 17:08:34 2002
@@ -60,27 +60,23 @@
 {\
 	struct sndrv_##type##32 data32;\
 	struct sndrv_##type data;\
-	mm_segment_t oldseg = get_fs();\
+	mm_segment_t oldseg;\
 	int err;\
-	set_fs(KERNEL_DS);\
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {\
-		err = -EFAULT;\
-		goto __err;\
-	}\
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))\
+		return -EFAULT;\
 	memset(&data, 0, sizeof(data));\
 	convert_from_32(type, &data, &data32);\
+	oldseg = get_fs();\
+	set_fs(KERNEL_DS);\
 	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);\
 	if (err < 0) \
-		goto __err;\
+		return err;\
 	if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\
 		convert_to_32(type, &data32, &data);\
-		if (copy_to_user((void*)arg, &data32, sizeof(data32))) {\
-			err = -EFAULT;\
-			goto __err;\
-		}\
+		if (copy_to_user((void*)arg, &data32, sizeof(data32)))\
+			return -EFAULT;\
 	}\
- __err: set_fs(oldseg);\
-	return err;\
+	return 0;\
 }
 
 #define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \
diff -Nru a/sound/core/ioctl32/pcm32.c b/sound/core/ioctl32/pcm32.c
--- a/sound/core/ioctl32/pcm32.c	Tue Oct  1 17:08:34 2002
+++ b/sound/core/ioctl32/pcm32.c	Tue Oct  1 17:08:34 2002
@@ -189,30 +189,26 @@
 {
 	struct sndrv_xferi32 data32;
 	struct sndrv_xferi data;
-	mm_segment_t oldseg = get_fs();
+	mm_segment_t oldseg;
 	int err;
 
-	set_fs(KERNEL_DS);
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
-		err = -EFAULT;
-		goto __err;
-	}
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
 	memset(&data, 0, sizeof(data));
 	data.result = data32.result;
 	data.buf = A(data32.buf);
 	data.frames = data32.frames;
+	oldseg = get_fs();
+	set_fs(KERNEL_DS);
 	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	set_fs(oldseg);
 	if (err < 0)
-		goto __err;
+		return err;
 	/* copy the result */
 	data32.result = data.result;
-	if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
-		err = -EFAULT;
-		goto __err;
-	}
- __err:
-	set_fs(oldseg);
-	return err;
+	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
+		return -EFAULT;
+	return 0;
 }
 
 
@@ -237,9 +233,7 @@
 	void *bufs[128];
 	int err = 0, ch, i;
 	u32 *bufptr;
-	mm_segment_t oldseg = get_fs();
-
-	set_fs(KERNEL_DS);
+	mm_segment_t oldseg;
 
 	/* FIXME: need to check whether fop->ioctl is sane */
 
@@ -250,41 +244,31 @@
 	/* check validty of the command */
 	switch (native_ctl) {
 	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK) {
-			err = -EINVAL;
-			goto __err;
-		}
-		if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
-			err = -EBADFD;
-			goto __err;
-		}
+		if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK)
+			return -EINVAL;
+		if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
+			return -EBADFD;
 		break;
 	case SNDRV_PCM_IOCTL_READN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE) {
-			err = -EINVAL;
-			goto __err;
-		}
+		if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE)
+			return -EINVAL;
 		break;
 	}
-	if ((ch = substream->runtime->channels) > 128) {
-		err = -EINVAL;
-		goto __err;
-	}
-	if (get_user(data32.frames, &srcptr->frames)) {
-		err = -EFAULT;
-		goto __err;
-	}
+	if ((ch = substream->runtime->channels) > 128)
+		return -EINVAL;
+	if (get_user(data32.frames, &srcptr->frames))
+		return -EFAULT;
 	__get_user(data32.bufs, &srcptr->bufs);
 	bufptr = (u32*)TO_PTR(data32.bufs);
 	for (i = 0; i < ch; i++) {
 		u32 ptr;
-		if (get_user(ptr, bufptr)) {
-			err = -EFAULT;
-			goto __err;
-		}
+		if (get_user(ptr, bufptr))
+			return -EFAULT;
 		bufs[ch] = (void*)TO_PTR(ptr);
 		bufptr++;
 	}
+	oldseg = get_fs();
+	set_fs(KERNEL_DS);
 	switch (native_ctl) {
 	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
 		err = snd_pcm_lib_writev(substream, bufs, data32.frames);
@@ -293,14 +277,12 @@
 		err = snd_pcm_lib_readv(substream, bufs, data32.frames);
 		break;
 	}
-	
+	set_fs(oldseg);
 	if (err < 0)
-		goto __err;
+		return err;
 	if (put_user(err, &srcptr->result))
-		err = -EFAULT;
- __err:
-	set_fs(oldseg);
-	return err < 0 ? err : 0;
+		return -EFAULT;
+	return 0;
 }
 
 
@@ -363,24 +345,22 @@
 {
 	struct sndrv_pcm_hw_params_old32 data32;
 	struct sndrv_pcm_hw_params data;
-	mm_segment_t oldseg = get_fs();
+	mm_segment_t oldseg;
 	int err;
-	set_fs(KERNEL_DS);
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
-		err = -EFAULT;
-		goto __err;
-	}
+
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
 	snd_pcm_hw_convert_from_old_params(&data, &data32);
+	oldseg = get_fs();
+	set_fs(KERNEL_DS);
 	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	set_fs(oldseg);
 	if (err < 0)
-		goto __err;
+		return err;
 	snd_pcm_hw_convert_to_old_params(&data32, &data);
-	if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
-	  err = -EFAULT;
-	  goto __err;
-	}
- __err: set_fs(oldseg);
-	return err;
+	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
+		return  -EFAULT;
+	return 0;
 }
 
 
@@ -450,10 +430,6 @@
 	{ SNDRV_PCM_IOCTL_READN_FRAMES32, AP(pcm_readn) },
 	{ SNDRV_PCM_IOCTL_LINK, NULL },
 	{ SNDRV_PCM_IOCTL_UNLINK, NULL },
-
-	{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
-	{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
-	{ SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
 
 	{ 0 },
 };
diff -Nru a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
--- a/sound/core/oss/mixer_oss.c	Tue Oct  1 17:08:34 2002
+++ b/sound/core/oss/mixer_oss.c	Tue Oct  1 17:08:34 2002
@@ -1169,10 +1169,14 @@
 			return err;
 		}
 		mixer->card = card;
-		strcpy(mixer->name, name);
+		if (*card->mixername) {
+			strncpy(mixer->name, card->mixername, sizeof(mixer->name) - 1);
+			mixer->name[sizeof(mixer->name)-1] = 0;
+		} else
+			strcpy(mixer->name, name);
 		snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
 				      card->number,
-				      name);
+				      mixer->name);
 		for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
 			mixer->slots[idx].number = idx;
 		card->mixer_oss = mixer;
diff -Nru a/sound/core/pcm_sgbuf.c b/sound/core/pcm_sgbuf.c
--- a/sound/core/pcm_sgbuf.c	Tue Oct  1 17:08:34 2002
+++ b/sound/core/pcm_sgbuf.c	Tue Oct  1 17:08:34 2002
@@ -80,6 +80,9 @@
 {
 	struct snd_sg_buf *sgbuf;
 
+	/* return in case, when sgbuf is not initialized */
+	if (substream->dma_private == NULL)
+		return -EINVAL;
 	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
 	sgbuf_shrink(sgbuf, 0);
 	if (sgbuf->table)
diff -Nru a/sound/core/seq/Makefile b/sound/core/seq/Makefile
--- a/sound/core/seq/Makefile	Tue Oct  1 17:08:34 2002
+++ b/sound/core/seq/Makefile	Tue Oct  1 17:08:34 2002
@@ -67,7 +67,7 @@
 obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_INTEL8X0) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(CONFIG_SND_VIA686) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
+obj-$(CONFIG_SND_VIA82XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_CS46XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_EMU10K1) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-virmidi.o
diff -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
--- a/sound/core/seq/oss/seq_oss_synth.c	Tue Oct  1 17:08:34 2002
+++ b/sound/core/seq/oss/seq_oss_synth.c	Tue Oct  1 17:08:34 2002
@@ -146,6 +146,8 @@
 	debug_printk(("synth %s registered %d\n", rec->name, i));
 	spin_unlock_irqrestore(&register_lock, flags);
 	dev->driver_data = rec;
+	if (i < SNDRV_CARDS)
+		snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, i, rec->name);
 	return 0;
 }
 
@@ -176,6 +178,8 @@
 		max_synth_devs = index + 1;
 	}
 	spin_unlock_irqrestore(&register_lock, flags);
+	if (rec->seq_device < SNDRV_CARDS)
+		snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device, NULL);
 
 	snd_use_lock_sync(&rec->use_lock);
 	kfree(rec);
diff -Nru a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile
--- a/sound/drivers/mpu401/Makefile	Tue Oct  1 17:08:34 2002
+++ b/sound/drivers/mpu401/Makefile	Tue Oct  1 17:08:34 2002
@@ -35,7 +35,7 @@
 obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_VIA686) += snd-mpu401-uart.o
+obj-$(CONFIG_SND_VIA82XX) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_TRIDENT) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_YMFPCI) += snd-mpu401-uart.o
diff -Nru a/sound/i2c/i2c.c b/sound/i2c/i2c.c
--- a/sound/i2c/i2c.c	Tue Oct  1 17:08:34 2002
+++ b/sound/i2c/i2c.c	Tue Oct  1 17:08:34 2002
@@ -260,11 +260,15 @@
 	if (device->flags & SND_I2C_DEVICE_ADDRTEN)
 		return -EIO;		/* not yet implemented */
 	snd_i2c_bit_start(bus);
-	if ((err = snd_i2c_bit_sendbyte(bus, device->addr << 1)) < 0)
+	if ((err = snd_i2c_bit_sendbyte(bus, device->addr << 1)) < 0) {
+		snd_i2c_bit_hw_stop(bus);
 		return err;
+	}
 	while (count-- > 0) {
-		if ((err = snd_i2c_bit_sendbyte(bus, *bytes++)) < 0)
+		if ((err = snd_i2c_bit_sendbyte(bus, *bytes++)) < 0) {
+			snd_i2c_bit_hw_stop(bus);
 			return err;
+		}
 		res++;
 	}
 	snd_i2c_bit_stop(bus);
@@ -279,11 +283,15 @@
 	if (device->flags & SND_I2C_DEVICE_ADDRTEN)
 		return -EIO;		/* not yet implemented */
 	snd_i2c_bit_start(bus);
-	if ((err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1)) < 0)
+	if ((err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1)) < 0) {
+		snd_i2c_bit_hw_stop(bus);
 		return err;
+	}
 	while (count-- > 0) {
-		if ((err = snd_i2c_bit_readbyte(bus, count == 0)) < 0)
+		if ((err = snd_i2c_bit_readbyte(bus, count == 0)) < 0) {
+			snd_i2c_bit_hw_stop(bus);
 			return err;
+		}
 		*bytes++ = (unsigned char)err;
 		res++;
 	}
@@ -300,10 +308,9 @@
 	if (addr & 0x7f80)	/* invalid address */
 		return -EINVAL;
 	snd_i2c_bit_start(bus);
-	if ((err = snd_i2c_bit_sendbyte(bus, addr << 1)) < 0)
-		return err;
+	err = snd_i2c_bit_sendbyte(bus, addr << 1);
 	snd_i2c_bit_stop(bus);
-	return 1;		/* present */
+	return err;
 }
 
 EXPORT_SYMBOL(snd_i2c_bus_create);
diff -Nru a/sound/pci/Config.help b/sound/pci/Config.help
--- a/sound/pci/Config.help	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/Config.help	Tue Oct  1 17:08:34 2002
@@ -82,8 +82,5 @@
 CONFIG_SND_SONICVIBES
   Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
 
-CONFIG_SND_VIA686
-  Say 'Y' or 'M' to include support for VIA VT82C686A/B South Bridge.
-
-CONFIG_SND_VIA8233
-  Say 'Y' or 'M' to include support for VIA VT8233 South Bridge.
+CONFIG_SND_VIA82XX
+  Say 'Y' or 'M' to include support for VIA VT82C686A/B, VT8233 South Bridge.
diff -Nru a/sound/pci/Config.in b/sound/pci/Config.in
--- a/sound/pci/Config.in	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/Config.in	Tue Oct  1 17:08:34 2002
@@ -27,8 +27,7 @@
 dep_tristate 'ICEnsemble ICE1712 (Envy24)' CONFIG_SND_ICE1712 $CONFIG_SND
 dep_tristate 'Intel i810/i820/i830/i840/MX440 integrated audio' CONFIG_SND_INTEL8X0 $CONFIG_SND
 dep_tristate 'S3 SonicVibes' CONFIG_SND_SONICVIBES $CONFIG_SND
-dep_tristate 'VIA 82C686A/B South Bridge' CONFIG_SND_VIA686 $CONFIG_SND
-dep_tristate 'VIA 8233 South Bridge' CONFIG_SND_VIA8233 $CONFIG_SND
+dep_tristate 'VIA 82C686A/B, 8233 South Bridge' CONFIG_SND_VIA82XX $CONFIG_SND
 
 # define gameport if necessary
 if [ "$CONFIG_INPUT_GAMEPORT" != "n" ]; then
diff -Nru a/sound/pci/Makefile b/sound/pci/Makefile
--- a/sound/pci/Makefile	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/Makefile	Tue Oct  1 17:08:34 2002
@@ -17,8 +17,7 @@
 snd-rme32-objs := rme32.o
 snd-rme96-objs := rme96.o
 snd-sonicvibes-objs := sonicvibes.o
-snd-via686-objs := via686.o
-snd-via8233-objs := via8233.o
+snd-via82xx-objs := via82xx.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ALS4000) += snd-als4000.o
@@ -35,8 +34,7 @@
 obj-$(CONFIG_SND_RME32) += snd-rme32.o
 obj-$(CONFIG_SND_RME96) += snd-rme96.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
-obj-$(CONFIG_SND_VIA686) += snd-via686.o
-obj-$(CONFIG_SND_VIA8233) += snd-via8233.o
+obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o
 
 obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/
 
diff -Nru a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile
--- a/sound/pci/ac97/Makefile	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/ac97/Makefile	Tue Oct  1 17:08:34 2002
@@ -17,8 +17,7 @@
 obj-$(CONFIG_SND_ICE1712) += snd-ac97-codec.o
 obj-$(CONFIG_SND_INTEL8X0) += snd-ac97-codec.o
 obj-$(CONFIG_SND_MAESTRO3) += snd-ac97-codec.o
-obj-$(CONFIG_SND_VIA686) += snd-ac97-codec.o
-obj-$(CONFIG_SND_VIA8233) += snd-ac97-codec.o
+obj-$(CONFIG_SND_VIA82XX) += snd-ac97-codec.o
 obj-$(CONFIG_SND_ALI5451) += snd-ac97-codec.o
 obj-$(CONFIG_SND_CS46XX) += snd-ac97-codec.o
 obj-$(CONFIG_SND_EMU10K1) += snd-ac97-codec.o
diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
--- a/sound/pci/ac97/ac97_codec.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/ac97/ac97_codec.c	Tue Oct  1 17:08:34 2002
@@ -65,6 +65,7 @@
 { 0x41445300, 0xffffff00, "Analog Devices",	NULL },
 { 0x414c4300, 0xffffff00, "Realtek",		NULL },
 { 0x414c4700, 0xffffff00, "Avance Logic",	NULL },
+{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL },
 { 0x43525900, 0xffffff00, "Cirrus Logic",	NULL },
 { 0x43585400, 0xffffff00, "Conexant",           NULL },
 { 0x45838300, 0xffffff00, "ESS Technology",	NULL },
@@ -95,6 +96,7 @@
 { 0x41445360, 0xffffffff, "AD1885",		patch_ad1885 },
 { 0x41445361, 0xffffffff, "AD1886",		patch_ad1886 },
 { 0x41445362, 0xffffffff, "AD1887",		patch_ad1881 },
+{ 0x41445363, 0xffffffff, "AD1886A",		patch_ad1881 },
 { 0x41445372, 0xffffffff, "AD1981A",		patch_ad1881 },
 { 0x414c4300, 0xfffffff0, "RL5306",	 	NULL },
 { 0x414c4310, 0xfffffff0, "RL5382", 		NULL },
@@ -104,6 +106,8 @@
 { 0x414c4730, 0xffffffff, "ALC101",		NULL },
 { 0x414c4740, 0xfffffff0, "ALC202",		NULL },
 { 0x414c4750, 0xfffffff0, "ALC250",		NULL },
+{ 0x434d4941, 0xffffffff, "CMI9738",		NULL },
+{ 0x434d4961, 0xffffffff, "CMI9739",		NULL },
 { 0x43525900, 0xfffffff8, "CS4297",		NULL },
 { 0x43525910, 0xfffffff8, "CS4297A",		patch_cirrus_spdif },
 { 0x43525920, 0xfffffff8, "CS4294/4298",	NULL },
@@ -122,6 +126,8 @@
 { 0x4e534331, 0xffffffff, "LM4549",		NULL },
 { 0x53494c22, 0xffffffff, "Si3036",		NULL },
 { 0x53494c23, 0xffffffff, "Si3038",		NULL },
+{ 0x54524102, 0xffffffff, "TR28022",		NULL },
+{ 0x54524106, 0xffffffff, "TR28026",		NULL },
 { 0x54524108, 0xffffffff, "TR28028",		patch_tritech_tr28028 }, // added by xin jin [07/09/99]
 { 0x54524123, 0xffffffff, "TR28602",		NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL },
@@ -130,14 +136,19 @@
 { 0x574d4c00, 0xffffffff, "WM9701A",		patch_wolfson00 },
 { 0x574d4c03, 0xffffffff, "WM9703/9707",	patch_wolfson03 },
 { 0x574d4c04, 0xffffffff, "WM9704 (quad)",	patch_wolfson04 },
+{ 0x574d4c05, 0xffffffff, "WM9705",		NULL },	// patch?
 { 0x594d4800, 0xffffffff, "YMF743",		NULL },
+{ 0x594d4802, 0xffffffff, "YMF752",		NULL },
+{ 0x594d4803, 0xffffffff, "YMF753",		NULL },
 { 0x83847600, 0xffffffff, "STAC9700/83/84",	NULL },
 { 0x83847604, 0xffffffff, "STAC9701/3/4/5",	NULL },
 { 0x83847605, 0xffffffff, "STAC9704",		NULL },
 { 0x83847608, 0xffffffff, "STAC9708/11",	patch_sigmatel_stac9708 },
 { 0x83847609, 0xffffffff, "STAC9721/23",	patch_sigmatel_stac9721 },
 { 0x83847644, 0xffffffff, "STAC9744",		patch_sigmatel_stac9744 },
+{ 0x83847650, 0xffffffff, "STAC9750/51",	NULL },	// patch?
 { 0x83847656, 0xffffffff, "STAC9756/57",	patch_sigmatel_stac9756 },
+{ 0x83847666, 0xffffffff, "STAC9766/67",	NULL }, // patch?
 { 0, 	      0,	  NULL,			NULL }
 };
 
@@ -201,6 +212,7 @@
 		return 1;
 	case AC97_ID_AD1885:	/* AD1885 */
 	case AC97_ID_AD1886:	/* AD1886 */
+	case AC97_ID_AD1886A:	/* AD1886A - !!verify!! --jk */
 	case AC97_ID_AD1887:	/* AD1887 - !!verify!! --jk */
 		if (reg == 0x5a)
 			return 1;
diff -Nru a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h
--- a/sound/pci/ac97/ac97_id.h	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/ac97/ac97_id.h	Tue Oct  1 17:08:34 2002
@@ -30,6 +30,7 @@
 #define AC97_ID_AD1885		0x41445360
 #define AC97_ID_AD1886		0x41445361
 #define AC97_ID_AD1887		0x41445362
+#define AC97_ID_AD1886A		0x41445363
 #define AC97_ID_TR28028		0x54524108
 #define AC97_ID_STAC9700	0x83847600
 #define AC97_ID_STAC9704	0x83847604
diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c
--- a/sound/pci/cs4281.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/cs4281.c	Tue Oct  1 17:08:34 2002
@@ -629,6 +629,9 @@
 	cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return -ENXIO);
 	int count;
 	unsigned short result;
+	// FIXME: volatile is necessary in the following due to a bug of
+	// some gcc versions
+	volatile int ac97_num = ((volatile ac97_t *)ac97)->num;
 
 	/*
 	 *  1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
@@ -639,7 +642,7 @@
 	 *  6. Read ACSTS = Status Register = 464h, check VSTS bit
 	 */
 
-	snd_cs4281_peekBA0(chip, ac97->num ? BA0_ACSDA2 : BA0_ACSDA);
+	snd_cs4281_peekBA0(chip, ac97_num ? BA0_ACSDA2 : BA0_ACSDA);
 
 	/*
 	 *  Setup the AC97 control registers on the CS461x to send the
@@ -658,7 +661,7 @@
 	snd_cs4281_pokeBA0(chip, BA0_ACCDA, 0);
 	snd_cs4281_pokeBA0(chip, BA0_ACCTL, BA0_ACCTL_DCV | BA0_ACCTL_CRW |
 					    BA0_ACCTL_VFRM | BA0_ACCTL_ESYN |
-			   (ac97->num ? BA0_ACCTL_TC : 0));
+			   (ac97_num ? BA0_ACCTL_TC : 0));
 
 
 	/*
@@ -691,7 +694,7 @@
 		 *  ACSTS = Status Register = 464h
 		 *  VSTS - Valid Status
 		 */
-		if (snd_cs4281_peekBA0(chip, ac97->num ? BA0_ACSTS2 : BA0_ACSTS) & BA0_ACSTS_VSTS)
+		if (snd_cs4281_peekBA0(chip, ac97_num ? BA0_ACSTS2 : BA0_ACSTS) & BA0_ACSTS_VSTS)
 			goto __ok2;
 		udelay(10);
 	}
@@ -705,7 +708,7 @@
 	 *  Read the data returned from the AC97 register.
 	 *  ACSDA = Status Data Register = 474h
 	 */
-	result = snd_cs4281_peekBA0(chip, ac97->num ? BA0_ACSDA2 : BA0_ACSDA);
+	result = snd_cs4281_peekBA0(chip, ac97_num ? BA0_ACSDA2 : BA0_ACSDA);
 
       __end:
 	return result;
@@ -2107,7 +2110,8 @@
 
 	/* remember the status registers */
 	for (i = 0; number_of(saved_regs); i++)
-		chip->suspend_regs[i] = snd_cs4281_peekBA0(chip, saved_regs[i]);
+		if (saved_regs[i])
+			chip->suspend_regs[i] = snd_cs4281_peekBA0(chip, saved_regs[i]);
 
 	/* Turn off the serial ports. */
 	snd_cs4281_pokeBA0(chip, BA0_SERMC, 0);
@@ -2150,7 +2154,8 @@
 
 	/* restore the status registers */
 	for (i = 0; number_of(saved_regs); i++)
-		snd_cs4281_pokeBA0(chip, saved_regs[i], chip->suspend_regs[i]);
+		if (saved_regs[i])
+			snd_cs4281_pokeBA0(chip, saved_regs[i], chip->suspend_regs[i]);
 
 	if (chip->ac97)
 		snd_ac97_resume(chip->ac97);
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/cs46xx/cs46xx_lib.c	Tue Oct  1 17:08:34 2002
@@ -3239,6 +3239,9 @@
 	if (chip == NULL)
 		return -ENOMEM;
 	spin_lock_init(&chip->reg_lock);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	init_MUTEX(&chip->spos_mutex);
+#endif
 	chip->card = card;
 	chip->pci = pci;
 	chip->capt.hw_size = PAGE_SIZE;
diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c
--- a/sound/pci/ens1370.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/ens1370.c	Tue Oct  1 17:08:34 2002
@@ -1298,6 +1298,7 @@
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_CT5880_A },
+	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_ES1373_8 },
 	{ .vid = PCI_ANY_ID, .did = PCI_ANY_ID }
 };
 
diff -Nru a/sound/pci/es1938.c b/sound/pci/es1938.c
--- a/sound/pci/es1938.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/es1938.c	Tue Oct  1 17:08:34 2002
@@ -1,5 +1,5 @@
 /*
- *  Driver for ESS Solo-1 (ES1938, ES1946) soundcard
+ *  Driver for ESS Solo-1 (ES1938, ES1946, ES1969) soundcard
  *  Copyright (c) by Jaromir Koutek <miri@punknet.cz>,
  *                   Jaroslav Kysela <perex@suse.cz>,
  *                   Thomas Sailer <sailer@ife.ee.ethz.ch>,
@@ -70,6 +70,8 @@
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
 MODULE_DEVICES("{{ESS,ES1938},"
+                "{ESS,ES1946},"
+                "{ESS,ES1969},"
 		"{TerraTec,128i PCI}}");
 
 #ifndef PCI_VENDOR_ID_ESS
diff -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c
--- a/sound/pci/es1968.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/es1968.c	Tue Oct  1 17:08:34 2002
@@ -2501,11 +2501,13 @@
 
 static int snd_es1968_free(es1968_t *chip)
 {
+	if (chip->res_io_port)
+		snd_es1968_reset(chip);
+
 	snd_es1968_set_acpi(chip, ACPI_D3);
 	chip->master_switch = NULL;
 	chip->master_volume = NULL;
 	if (chip->res_io_port) {
-		snd_es1968_reset(chip);
 		release_resource(chip->res_io_port);
 		kfree_nocheck(chip->res_io_port);
 	}
diff -Nru a/sound/pci/ice1712.c b/sound/pci/ice1712.c
--- a/sound/pci/ice1712.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/ice1712.c	Tue Oct  1 17:08:34 2002
@@ -414,7 +414,8 @@
 #define ICE1712_6FIRE_TX2		0x40	/* MIDI2 */
 #define ICE1712_6FIRE_RX2		0x80	/* MIDI2 */
 
-#define ICE1712_6FIRE_CS8427_ADDR	(0x22>>1) /* ?? */
+#define ICE1712_6FIRE_PCF9554_ADDR	(0x40>>1)
+#define ICE1712_6FIRE_CS8427_ADDR	(0x22>>1)
 
 /*
  * DMA mode values
@@ -509,7 +510,7 @@
 	snd_i2c_device_t *cs8404;	/* CS8404A I2C device */
 	snd_i2c_device_t *cs8427;	/* CS8427 I2C device */
 	snd_i2c_device_t *pcf8574[2];	/* PCF8574 Output/Input (EWS88MT) */
-	snd_i2c_device_t *pcf8575;	/* PCF8575 (EWS88D) */
+	snd_i2c_device_t *pcf8575;	/* PCF8575 (EWS88D) / PCF9554 (6Fire) */
 	
 	unsigned char cs8403_spdif_bits;
 	unsigned char cs8403_spdif_stream_bits;
@@ -2411,14 +2412,13 @@
 		ac97.read = snd_ice1712_ac97_read;
 		ac97.private_data = ice;
 		ac97.private_free = snd_ice1712_mixer_free_ac97;
-		if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) {
+		if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0)
 			printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n");
-			// return err;
-		} else {
+		else {
 			if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0)
 				return err;
+			return 0;
 		}
-		return 0;
 	}
 	/* hmm.. can we have both consumer and pro ac97 mixers? */
 	if (! (ice->eeprom.aclink & ICE1712_CFG_PRO_I2S)) {
@@ -2428,11 +2428,10 @@
 		ac97.read = snd_ice1712_pro_ac97_read;
 		ac97.private_data = ice;
 		ac97.private_free = snd_ice1712_mixer_free_ac97;
-		if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) {
+		if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0)
 			printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
-			// return err;
-		}
-		return 0;
+		else
+			return 0;
 	}
 	/* I2S mixer only */
 	strcat(ice->card->mixername, "ICE1712 - multitrack");
@@ -3111,7 +3110,7 @@
 
 static int snd_ice1712_ewx_io_sense_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){
 
-	static char *texts[4] = {
+	static char *texts[2] = {
 		"+4dBu", "-10dBV",
 	};
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -3354,26 +3353,32 @@
  * DMX 6Fire controls
  */
 
-#if 0 // XXX not working yet
-static int snd_ice1712_6fire_read_pca(ice1712_t *ice)
+#define PCF9554_REG_INPUT	0
+#define PCF9554_REG_OUTPUT	1
+#define PCF9554_REG_POLARITY	2
+#define PCF9554_REG_CONFIG	3
+
+static int snd_ice1712_6fire_read_pca(ice1712_t *ice, unsigned char reg)
 {
 	unsigned char byte;
 	snd_i2c_lock(ice->i2c);
-	byte = 0; /* read port */
+	byte = reg;
 	snd_i2c_sendbytes(ice->pcf8575, &byte, 1);
+	byte = 0;
 	if (snd_i2c_readbytes(ice->pcf8575, &byte, 1) != 1) {
 		snd_i2c_unlock(ice->i2c);
+		printk("cannot read pca\n");
 		return -EIO;
 	}
 	snd_i2c_unlock(ice->i2c);
 	return byte;
 }
 
-static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char data)
+static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char reg, unsigned char data)
 {
 	unsigned char bytes[2];
 	snd_i2c_lock(ice->i2c);
-	bytes[0] = 1; /* write port */
+	bytes[0] = reg;
 	bytes[1] = data;
 	if (snd_i2c_sendbytes(ice->pcf8575, bytes, 2) != 2) {
 		snd_i2c_unlock(ice->i2c);
@@ -3399,7 +3404,7 @@
 	int invert = (kcontrol->private_value >> 8) & 1;
 	int data;
 	
-	if ((data = snd_ice1712_6fire_read_pca(ice)) < 0)
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
 		return data;
 	data = (data >> shift) & 1;
 	if (invert)
@@ -3415,7 +3420,7 @@
 	int invert = (kcontrol->private_value >> 8) & 1;
 	int data, ndata;
 	
-	if ((data = snd_ice1712_6fire_read_pca(ice)) < 0)
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
 		return data;
 	ndata = data & ~(1 << shift);
 	if (ucontrol->value.integer.value[0])
@@ -3423,27 +3428,77 @@
 	if (invert)
 		ndata ^= (1 << shift);
 	if (data != ndata) {
-		snd_ice1712_6fire_write_pca(ice, (unsigned char)ndata);
+		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
 		return 1;
 	}
 	return 0;
 }
 
-#define DMX6FIRE_CONTROL(xiface, xname, xshift, xinvert, xaccess) \
-{ .iface = xiface,\
+static int snd_ice1712_6fire_select_input_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[4] = {
+		"Internal", "Front Input", "Rear Input", "Wave Table"
+	};
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 4;
+	if (uinfo->value.enumerated.item >= 4)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+     
+static int snd_ice1712_6fire_select_input_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int data;
+	
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
+		return data;
+	ucontrol->value.integer.value[0] = data & 3;
+	return 0;
+}
+
+static int snd_ice1712_6fire_select_input_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
+	int data, ndata;
+	
+	if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
+		return data;
+	ndata = data & ~3;
+	ndata |= (ucontrol->value.integer.value[0] & 3);
+	if (data != ndata) {
+		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
+		return 1;
+	}
+	return 0;
+}
+
+
+#define DMX6FIRE_CONTROL(xname, xshift, xinvert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
   .name = xname,\
-  .access = xaccess,\
   .info = snd_ice1712_6fire_control_info,\
   .get = snd_ice1712_6fire_control_get,\
   .put = snd_ice1712_6fire_control_put,\
   .private_value = xshift | (xinvert << 8),\
 }
 
-static snd_kcontrol_new_t snd_ice1712_6fire_led __devinitdata =
-DMX6FIRE_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "Breakbox LED", 6, 0, 0);
-
-#endif // XXX not working yet
-
+static snd_kcontrol_new_t snd_ice1712_6fire_controls[] __devinitdata = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Analog Input Select",
+		.info = snd_ice1712_6fire_select_input_info,
+		.get = snd_ice1712_6fire_select_input_get,
+		.put = snd_ice1712_6fire_select_input_put,
+	},
+	DMX6FIRE_CONTROL("Front Digital Input Switch", 2, 0),
+	// DMX6FIRE_CONTROL("Master Clock Select", 3, 0),
+	DMX6FIRE_CONTROL("Optical Digital Input Switch", 4, 0),
+	DMX6FIRE_CONTROL("Phono Analog Input Switch", 5, 0),
+	DMX6FIRE_CONTROL("Breakbox LED", 6, 0),
+};
 
 /*
  *
@@ -3808,14 +3863,16 @@
 			}
 			break;
 		case ICE1712_SUBDEVICE_DMX6FIRE:
-#if 0 // XXX not working yet
-			if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", 0x40>>1, &ice->pcf8575)) < 0)
+			if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->pcf8575)) < 0) {
+				snd_printk("PCF9554 initialization failed\n");
 				return err;
-			if ((err = snd_cs8427_create(ice->i2c, 0x11, &ice->cs8427)) < 0) {
+			}
+#if 0 // XXX not working...
+			if ((err = snd_cs8427_create(ice->i2c, ICE1712_6FIRE_CS8427_ADDR, &ice->cs8427)) < 0) {
 				snd_printk("CS8427 initialization failed\n");
 				return err;
 			}
-#endif // XXX not working yet
+#endif
 			break;
 		case ICE1712_SUBDEVICE_EWS88MT:
 			if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->cs8404)) < 0)
@@ -4052,11 +4109,11 @@
 		}
 		break;
 	case ICE1712_SUBDEVICE_DMX6FIRE:
-#if 0 // XXX not working yet
-		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_6fire_led, ice));
-		if (err < 0)
-			return err;
-#endif
+		for (idx = 0; idx < sizeof(snd_ice1712_6fire_controls)/sizeof(snd_ice1712_6fire_controls[0]); idx++) {
+			err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_6fire_controls[idx], ice));
+			if (err < 0)
+				return err;
+		}
 		break;
 	}
 
diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
--- a/sound/pci/intel8x0.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/intel8x0.c	Tue Oct  1 17:08:34 2002
@@ -326,10 +326,6 @@
 	char ac97_name[32];
 	char ctrl_name[32];
 
-	unsigned long dma_playback_size;
-	unsigned long dma_capture_size;
-	unsigned long dma_mic_size;
-
 	int irq;
 
 	unsigned int mmio;
@@ -428,7 +424,7 @@
 	if (chip->bm_mmio)
 		writeb(val, chip->remap_bmaddr + offset);
 	else
-		return outb(val, chip->bmaddr + offset);
+		outb(val, chip->bmaddr + offset);
 }
 
 static void iputword(intel8x0_t *chip, u32 offset, u16 val)
@@ -436,7 +432,7 @@
 	if (chip->bm_mmio)
 		writew(val, chip->remap_bmaddr + offset);
 	else
-		return outw(val, chip->bmaddr + offset);
+		outw(val, chip->bmaddr + offset);
 }
 
 static void iputdword(intel8x0_t *chip, u32 offset, u32 val)
@@ -444,7 +440,7 @@
 	if (chip->bm_mmio)
 		writel(val, chip->remap_bmaddr + offset);
 	else
-		return outl(val, chip->bmaddr + offset);
+		outl(val, chip->bmaddr + offset);
 }
 
 /*
@@ -464,7 +460,7 @@
 	if (chip->mmio)
 		writew(val, chip->remap_addr + offset);
 	else
-		return outw(val, chip->addr + offset);
+		outw(val, chip->addr + offset);
 }
 
 /*
@@ -1583,6 +1579,7 @@
 	if (codecs < 2)
 		goto __skip_secondary;
 	for (i = 1; i < codecs; i++) {
+		ac97.num = i;
 		if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
 			return err;
 		chip->ac97[i] = x97;
@@ -1995,7 +1992,13 @@
 	snd_intel8x0_setup_periods(chip, ichdev);
 	port = ichdev->reg_offset;
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM); /* trigger */
+	/* trigger */
+	if (chip->device_type != DEVICE_ALI)
+		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM);
+	else {
+		iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
+		iputbyte(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
+	}
 	do_gettimeofday(&start_time);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 #if 0
@@ -2014,7 +2017,10 @@
 		pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << 1;
 	pos += ichdev->position;
 	do_gettimeofday(&stop_time);
-	iputbyte(chip, port + ICH_REG_OFF_CR, 0); /* stop */
+	/* stop */
+	if (chip->device_type == DEVICE_ALI)
+		iputbyte(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8));
+	iputbyte(chip, port + ICH_REG_OFF_CR, 0);
 	/* reset whole DMA things */
 	while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH))
 		;
@@ -2279,6 +2285,7 @@
 	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia NForce" },
 	{ 0x746d, "AMD AMD8111" },
 	{ 0x7445, "AMD AMD768" },
+	{ 0x5455, "ALi M5455" },
 	{ 0, 0 },
 };
 
diff -Nru a/sound/pci/rme32.c b/sound/pci/rme32.c
--- a/sound/pci/rme32.c	Tue Oct  1 17:08:34 2002
+++ b/sound/pci/rme32.c	Tue Oct  1 17:08:34 2002
@@ -1517,10 +1517,8 @@
 snd_rme32_info_inputtype_control(snd_kcontrol_t * kcontrol,
 				 snd_ctl_elem_info_t * uinfo)
 {
-	static char *_texts[5] =
-	    { "Optical", "Coaxial", "Internal", "XLR" };
 	rme32_t *rme32 = _snd_kcontrol_chip(kcontrol);
-	char *texts[4] = { _texts[0], _texts[1], _texts[2], _texts[3] };
+	static char *texts[4] = { "Optical", "Coaxial", "Internal", "XLR" };
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
@@ -1614,8 +1612,8 @@
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->value.enumerated.items = 4;
-	if (uinfo->value.enumerated.item > 4) {
-		uinfo->value.enumerated.item = 4;
+	if (uinfo->value.enumerated.item > 3) {
+		uinfo->value.enumerated.item = 3;
 	}
 	strcpy(uinfo->value.enumerated.name,
 	       texts[uinfo->value.enumerated.item]);
diff -Nru a/sound/pci/via686.c b/sound/pci/via686.c
--- a/sound/pci/via686.c	Tue Oct  1 17:08:34 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1232 +0,0 @@
-/*
- *   ALSA driver for VIA VT82C686A (South Bridge)
- *
- *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */      
-
-#include <sound/driver.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_sgbuf.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <sound/ac97_codec.h>
-#include <sound/mpu401.h>
-#define SNDRV_GET_ID
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
-MODULE_DESCRIPTION("VIA VT82C686A");
-MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{VIA,VT82C686A,pci},{VIA,VT82C686B}}");
-
-static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
-static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
-static long snd_mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
-static int snd_ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
-
-MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_index, "Index value for VIA 82C686A bridge.");
-MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
-MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
-MODULE_PARM_DESC(snd_id, "ID string for VIA 82C686A bridge.");
-MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
-MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_enable, "Enable audio part of VIA 82C686A bridge.");
-MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
-MODULE_PARM_DESC(snd_mpu_port, "MPU-401 port.");
-MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_PORT_DESC);
-MODULE_PARM(snd_ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
-MODULE_PARM_DESC(snd_ac97_clock, "AC'97 codec clock (default 48000Hz).");
-MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
-
-/*
- *  Direct registers
- */
-
-#ifndef PCI_DEVICE_ID_VIA_82C686_5
-#define PCI_DEVICE_ID_VIA_82C686_5	0x3058
-#endif
-
-#define VIAREG(via, x) ((via)->port + VIA_REG_##x)
-
-/* offsets */
-#define VIA_REG_OFFSET_STATUS		0x00	/* byte - channel status */
-#define   VIA_REG_STAT_ACTIVE		0x80	/* RO */
-#define   VIA_REG_STAT_PAUSED		0x40	/* RO */
-#define   VIA_REG_STAT_TRIGGER_QUEUED	0x08	/* RO */
-#define   VIA_REG_STAT_STOPPED		0x04	/* RWC */
-#define   VIA_REG_STAT_EOL		0x02	/* RWC */
-#define   VIA_REG_STAT_FLAG		0x01	/* RWC */
-#define VIA_REG_OFFSET_CONTROL		0x01	/* byte - channel control */
-#define   VIA_REG_CTRL_START		0x80	/* WO */
-#define   VIA_REG_CTRL_TERMINATE	0x40	/* WO */
-#define   VIA_REG_CTRL_PAUSE		0x08	/* RW */
-#define   VIA_REG_CTRL_RESET		0x01	/* RW - probably reset? undocumented */
-#define VIA_REG_OFFSET_TYPE		0x02	/* byte - channel type */
-#define   VIA_REG_TYPE_AUTOSTART	0x80	/* RW - autostart at EOL */
-#define   VIA_REG_TYPE_16BIT		0x20	/* RW */
-#define   VIA_REG_TYPE_STEREO		0x10	/* RW */
-#define   VIA_REG_TYPE_INT_LLINE	0x00
-#define   VIA_REG_TYPE_INT_LSAMPLE	0x04
-#define   VIA_REG_TYPE_INT_LESSONE	0x08
-#define   VIA_REG_TYPE_INT_MASK		0x0c
-#define   VIA_REG_TYPE_INT_EOL		0x02
-#define   VIA_REG_TYPE_INT_FLAG		0x01
-#define VIA_REG_OFFSET_TABLE_PTR	0x04	/* dword - channel table pointer */
-#define VIA_REG_OFFSET_CURR_PTR		0x04	/* dword - channel current pointer */
-#define VIA_REG_OFFSET_CURR_COUNT	0x0c	/* dword - channel current count */
-/* playback block */
-#define VIA_REG_PLAYBACK_STATUS		0x00	/* byte - channel status */
-#define VIA_REG_PLAYBACK_CONTROL	0x01	/* byte - channel control */
-#define VIA_REG_PLAYBACK_TYPE		0x02	/* byte - channel type */
-#define VIA_REG_PLAYBACK_TABLE_PTR	0x04	/* dword - channel table pointer */
-#define VIA_REG_PLAYBACK_CURR_PTR	0x04	/* dword - channel current pointer */
-#define VIA_REG_PLAYBACK_CURR_COUNT	0x0c	/* dword - channel current count */
-/* capture block */
-#define VIA_REG_CAPTURE_STATUS		0x10	/* byte - channel status */
-#define VIA_REG_CAPTURE_CONTROL		0x11	/* byte - channel control */
-#define VIA_REG_CAPTURE_TYPE		0x12	/* byte - channel type */
-#define VIA_REG_CAPTURE_TABLE_PTR	0x14	/* dword - channel table pointer */
-#define VIA_REG_CAPTURE_CURR_PTR	0x14	/* dword - channel current pointer */
-#define VIA_REG_CAPTURE_CURR_COUNT	0x1c	/* dword - channel current count */
-/* FM block */
-#define VIA_REG_FM_STATUS		0x20	/* byte - channel status */
-#define VIA_REG_FM_CONTROL		0x21	/* byte - channel control */
-#define VIA_REG_FM_TYPE			0x22	/* byte - channel type */
-#define VIA_REG_FM_TABLE_PTR		0x24	/* dword - channel table pointer */
-#define VIA_REG_FM_CURR_PTR		0x24	/* dword - channel current pointer */
-#define VIA_REG_FM_CURR_COUNT		0x2c	/* dword - channel current count */
-/* AC'97 */
-#define VIA_REG_AC97			0x80	/* dword */
-#define   VIA_REG_AC97_CODEC_ID_MASK	(3<<30)
-#define   VIA_REG_AC97_CODEC_ID_SHIFT	30
-#define   VIA_REG_AC97_CODEC_ID_PRIMARY	0x00
-#define   VIA_REG_AC97_CODEC_ID_SECONDARY 0x01
-#define   VIA_REG_AC97_SECONDARY_VALID	(1<<27)
-#define   VIA_REG_AC97_PRIMARY_VALID	(1<<25)
-#define   VIA_REG_AC97_BUSY		(1<<24)
-#define   VIA_REG_AC97_READ		(1<<23)
-#define   VIA_REG_AC97_CMD_SHIFT	16
-#define   VIA_REG_AC97_CMD_MASK		0x7e
-#define   VIA_REG_AC97_DATA_SHIFT	0
-#define   VIA_REG_AC97_DATA_MASK	0xffff
-#define VIA_REG_SGD_SHADOW		0x84	/* dword */
-
-#define VIA_TBL_BIT_FLAG	0x40000000
-#define VIA_TBL_BIT_EOL		0x80000000
-
-/*
- * pcm stream
- */
-
-typedef struct {
-	unsigned long reg_offset;
-        snd_pcm_substream_t *substream;
-	int running;
-        unsigned int size;
-        unsigned int fragsize;
-	unsigned int frags;
-	unsigned int lastptr;
-	unsigned int lastcount;
-	unsigned int page_per_frag;
-	unsigned int curidx;
-	unsigned int tbl_entries;	/* number of descriptor table entries */
-	unsigned int tbl_size;		/* size of a table entry */
-	u32 *table; /* physical address + flag */
-	dma_addr_t table_addr;
-} viadev_t;
-
-
-static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
-			   struct pci_dev *pci)
-{
-	int i, size;
-	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
-
-	if (dev->table) {
-		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
-		dev->table = NULL;
-	}
-
-	/* allocate buffer descriptor lists */
-	if (dev->fragsize < PAGE_SIZE) {
-		dev->tbl_size = dev->fragsize;
-		dev->tbl_entries = dev->frags;
-		dev->page_per_frag = 1;
-	} else {
-		dev->tbl_size = PAGE_SIZE;
-		dev->tbl_entries = sgbuf->pages;
-		dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
-	}
-	/* the start of each lists must be aligned to 8 bytes,
-	 * but the kernel pages are much bigger, so we don't care
-	 */
-	dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
-	if (! dev->table)
-		return -ENOMEM;
-
-	if (dev->tbl_size < PAGE_SIZE) {
-		for (i = 0; i < dev->tbl_entries; i++)
-			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
-	} else {
-		for (i = 0; i < dev->tbl_entries; i++)
-			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
-	}
-	size = dev->size;
-	for (i = 0; i < dev->tbl_entries - 1; i++) {
-		dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
-		size -= dev->tbl_size;
-	}
-	dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
-
-	return 0;
-}
-
-
-static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
-			    struct pci_dev *pci)
-{
-	if (dev->table) {
-		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
-		dev->table = NULL;
-	}
-}
-
-
-/*
- */
-
-typedef struct _snd_via686a via686a_t;
-#define chip_t via686a_t
-
-struct _snd_via686a {
-	int irq;
-
-	unsigned long port;
-	struct resource *res_port;
-	unsigned char revision;
-
-	unsigned char old_legacy;
-	unsigned char old_legacy_cfg;
-
-	struct pci_dev *pci;
-	snd_card_t *card;
-
-	snd_pcm_t *pcm;
-	/*snd_pcm_t *pcm_fm;*/
-	viadev_t playback;
-	viadev_t capture;
-	/*viadev_t playback_fm;*/
-
-	snd_rawmidi_t *rmidi;
-
-	ac97_t *ac97;
-	unsigned int ac97_clock;
-	unsigned int ac97_secondary;	/* secondary AC'97 codec is present */
-
-	spinlock_t reg_lock;
-	snd_info_entry_t *proc_entry;
-};
-
-static struct pci_device_id snd_via686a_ids[] __devinitdata = {
-	{ 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },	/* 686A */
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, snd_via686a_ids);
-
-/*
- *  Basic I/O
- */
-
-static inline unsigned int snd_via686a_codec_xread(via686a_t *chip)
-{
-	return inl(VIAREG(chip, AC97));
-}
- 
-static inline void snd_via686a_codec_xwrite(via686a_t *chip, unsigned int val)
-{
-	outl(val, VIAREG(chip, AC97));
-}
- 
-static int snd_via686a_codec_ready(via686a_t *chip, int secondary)
-{
-	unsigned int timeout = 1000;	/* 1ms */
-	unsigned int val;
-	
-	while (timeout-- > 0) {
-		udelay(1);
-		if (!((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_BUSY))
-			return val & 0xffff;
-	}
-	snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via686a_codec_xread(chip));
-	return -EIO;
-}
- 
-static int snd_via686a_codec_valid(via686a_t *chip, int secondary)
-{
-	unsigned int timeout = 1000;	/* 1ms */
-	unsigned int val;
-	unsigned int stat = !secondary ? VIA_REG_AC97_PRIMARY_VALID :
-					 VIA_REG_AC97_SECONDARY_VALID;
-	
-	while (timeout-- > 0) {
-		udelay(1);
-		if ((val = snd_via686a_codec_xread(chip)) & stat)
-			return val & 0xffff;
-	}
-	snd_printk("codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via686a_codec_xread(chip));
-	return -EIO;
-}
- 
-static void snd_via686a_codec_wait(ac97_t *ac97)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
-	int err;
-	err = snd_via686a_codec_ready(chip, ac97->num);
-	/* here we need to wait fairly for long time.. */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/2);
-}
-
-static void snd_via686a_codec_write(ac97_t *ac97,
-				    unsigned short reg,
-				    unsigned short val)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
-	unsigned int xval;
-	
-	xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;
-	xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
-	xval |= reg << VIA_REG_AC97_CMD_SHIFT;
-	xval |= val << VIA_REG_AC97_DATA_SHIFT;
-	spin_lock(&chip->reg_lock);
-	snd_via686a_codec_xwrite(chip, xval);
-	snd_via686a_codec_ready(chip, ac97->num);
-	spin_unlock(&chip->reg_lock);
-}
-
-static unsigned short snd_via686a_codec_read(ac97_t *ac97, unsigned short reg)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return ~0);
-	unsigned int xval, val = 0xffff;
-	int again = 0;
-
-	xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;
-	xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
-	xval = (!ac97->num ? VIA_REG_AC97_PRIMARY_VALID : VIA_REG_AC97_SECONDARY_VALID);
-	xval |= VIA_REG_AC97_READ;
-	xval |= reg << VIA_REG_AC97_CMD_SHIFT;
-	spin_lock(&chip->reg_lock);
-      	while (1) {
-      		if (again++ > 3) {
-		        spin_unlock(&chip->reg_lock);
-		      	return 0xffff;
-		}
-		snd_via686a_codec_xwrite(chip, xval);
-		if (snd_via686a_codec_ready(chip, ac97->num) < 0)
-			continue;
-		if (snd_via686a_codec_valid(chip, ac97->num) >= 0) {
-			udelay(25);
-			val = snd_via686a_codec_xread(chip);
-			break;
-		}
-	}
-	spin_unlock(&chip->reg_lock);
-	return val & 0xffff;
-}
-
-#if 0
-static void snd_via686a_channel_print(via686a_t *chip, viadev_t *viadev)
-{
-	unsigned long port = chip->port + viadev->reg_offset;
-
-	printk("[0x%x] status = 0x%x, control = 0x%x, type = 0x%x, ptr = 0x%x, count = 0x%x\n",
-			port,
-			inb(port + VIA_REG_OFFSET_STATUS),
-			inb(port + VIA_REG_OFFSET_CONTROL),
-			inb(port + VIA_REG_OFFSET_TYPE),
-			inl(port + VIA_REG_OFFSET_CURR_PTR),
-			inl(port + VIA_REG_OFFSET_CURR_COUNT));
-}
-#endif
-
-static void snd_via686a_channel_reset(via686a_t *chip, viadev_t *viadev)
-{
-	unsigned long port = chip->port + viadev->reg_offset;
-
-	outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET, port + VIA_REG_OFFSET_CONTROL);
-	udelay(50);
-	outb(0x00, port + VIA_REG_OFFSET_CONTROL);
-	outb(0xff, port + VIA_REG_OFFSET_STATUS);
-	outb(0x00, port + VIA_REG_OFFSET_TYPE);
-	outl(0, port + VIA_REG_OFFSET_CURR_PTR);
-}
-
-static int snd_via686a_trigger(via686a_t *chip, viadev_t *viadev, int cmd)
-{
-	unsigned char val = 0;
-	unsigned long port = chip->port + viadev->reg_offset;
-	
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		val = VIA_REG_CTRL_START;
-		viadev->running = 1;
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		val = VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET;
-		viadev->running = 0;
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		val = VIA_REG_CTRL_PAUSE;
-		viadev->running = 1;
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		val = 0;
-		viadev->running = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-	outb(val, port + VIA_REG_OFFSET_CONTROL);
-	if (cmd == SNDRV_PCM_TRIGGER_STOP)
-		snd_via686a_channel_reset(chip, viadev);
-	return 0;
-}
-
-
-static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
-				      snd_pcm_substream_t *substream)
-{
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	unsigned long port = chip->port + viadev->reg_offset;
-	int v, err;
-
-	viadev->size = snd_pcm_lib_buffer_bytes(substream);
-	viadev->fragsize = snd_pcm_lib_period_bytes(substream);
-	viadev->frags = runtime->periods;
-	viadev->lastptr = ~0;
-	viadev->lastcount = ~0;
-	viadev->curidx = 0;
-
-	/* the period size must be in power of 2 */
-	v = ld2(viadev->fragsize);
-	if (viadev->fragsize != (1 << v)) {
-		snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
-		return -EINVAL;
-	}
-
-	snd_via686a_channel_reset(chip, viadev);
-
-	err = build_via_table(viadev, substream, chip->pci);
-	if (err < 0)
-		return err;
-
-	runtime->dma_bytes = viadev->size;
-	outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
-	outb(VIA_REG_TYPE_AUTOSTART |
-	     (runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
-	     (runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
-	     ((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
-	     VIA_REG_TYPE_INT_EOL |
-	     VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
-	return 0;
-}
-
-/*
- *  Interrupt handler
- */
-
-static inline void snd_via686a_update(via686a_t *chip, viadev_t *viadev)
-{
-	outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
-	if (viadev->substream && viadev->running) {
-		viadev->curidx++;
-		if (viadev->curidx >= viadev->page_per_frag) {
-			viadev->curidx = 0;
-			spin_unlock(&chip->reg_lock);
-			snd_pcm_period_elapsed(viadev->substream);
-			spin_lock(&chip->reg_lock);
-		}
-	}
-}
-
-static void snd_via686a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, dev_id, return);
-	unsigned int status;
-
-	spin_lock(&chip->reg_lock);
-	status = inl(VIAREG(chip, SGD_SHADOW));
-	if ((status & 0x00000077) == 0) {
-		spin_unlock(&chip->reg_lock);
-		if (chip->rmidi != NULL) {
-			snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
-		}
-		return;
-	}
-	if (inb(VIAREG(chip, PLAYBACK_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
-		snd_via686a_update(chip, &chip->playback);
-	if (inb(VIAREG(chip, CAPTURE_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
-		snd_via686a_update(chip, &chip->capture);
-	/*if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
-	  snd_via686a_update(chip, &chip->playback_fm);*/
-	spin_unlock(&chip->reg_lock);
-}
-
-/*
- *  PCM part
- */
-
-static int snd_via686a_playback_trigger(snd_pcm_substream_t * substream,
-					int cmd)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-
-	return snd_via686a_trigger(chip, &chip->playback, cmd);
-}
-
-static int snd_via686a_capture_trigger(snd_pcm_substream_t * substream,
-				       int cmd)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-
-	return snd_via686a_trigger(chip, &chip->capture, cmd);
-}
-
-static int snd_via686a_hw_params(snd_pcm_substream_t * substream,
-				 snd_pcm_hw_params_t * hw_params)
-{
-	return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
-}
-
-static int snd_via686a_hw_free(snd_pcm_substream_t * substream)
-{
-	return 0;
-}
-
-static int snd_via686a_playback_prepare(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	return snd_via686a_setup_periods(chip, &chip->playback, substream);
-}
-
-static int snd_via686a_capture_prepare(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
-	return snd_via686a_setup_periods(chip, &chip->capture, substream);
-}
-
-static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev)
-{
-	unsigned int val, ptr, count;
-	
-	ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset);
-	count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset);
-	if (ptr == viadev->lastptr && count > viadev->lastcount)
-		ptr += 8;
-	if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
-		return 0;
-	snd_assert(viadev->tbl_entries, return 0);
-	/* get index */
-	if (ptr <= (unsigned int)viadev->table_addr)
-		val = 0;
-	else
-		val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
-	if (val < viadev->tbl_entries - 1) {
-		val *= viadev->tbl_size;
-		val += viadev->tbl_size - count;
-	} else {
-		val *= viadev->tbl_size;
-		val += (viadev->size % viadev->tbl_size) + 1 - count;
-	}
-	viadev->lastptr = ptr;
-	viadev->lastcount = count;
-	// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
-	return val;
-}
-
-static snd_pcm_uframes_t snd_via686a_playback_pointer(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, snd_via686a_cur_ptr(chip, &chip->playback));
-}
-
-static snd_pcm_uframes_t snd_via686a_capture_pointer(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, snd_via686a_cur_ptr(chip, &chip->capture));
-}
-
-static snd_pcm_hardware_t snd_via686a_playback =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE),
-	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		0,
-	.rate_min =		8000,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	128 * 1024,
-	.period_bytes_min =	32,
-	.period_bytes_max =	128 * 1024,
-	.periods_min =		2,
-	.periods_max =		128,
-	.fifo_size =		0,
-};
-
-static snd_pcm_hardware_t snd_via686a_capture =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID),
-	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		0,
-	.rate_min =		8000,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	128 * 1024,
-	.period_bytes_min =	32,
-	.period_bytes_max =	128 * 1024,
-	.periods_min =		2,
-	.periods_max =		128,
-	.fifo_size =		0,
-};
-
-static int snd_via686a_playback_open(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err;
-
-	chip->playback.substream = substream;
-	runtime->hw = snd_via686a_playback;
-	runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
-	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
-		runtime->hw.rate_min = 48000;
-	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
-		return err;
-	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
-		return err;
-	/* we may remove following constaint when we modify table entries
-	   in interrupt */
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-		return err;
-	return 0;
-}
-
-static int snd_via686a_capture_open(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err;
-
-	chip->capture.substream = substream;
-	runtime->hw = snd_via686a_capture;
-	runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
-	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
-		runtime->hw.rate_min = 48000;
-	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
-		return err;
-	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
-		return err;
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-		return err;
-	return 0;
-}
-
-static int snd_via686a_playback_close(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-
-	clean_via_table(&chip->playback, substream, chip->pci);
-	snd_pcm_sgbuf_delete(substream);
-	chip->playback.substream = NULL;
-	return 0;
-}
-
-static int snd_via686a_capture_close(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-
-	clean_via_table(&chip->capture, substream, chip->pci);
-	snd_pcm_sgbuf_delete(substream);
-	chip->capture.substream = NULL;
-	return 0;
-}
-
-static snd_pcm_ops_t snd_via686a_playback_ops = {
-	.open =		snd_via686a_playback_open,
-	.close =	snd_via686a_playback_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_via686a_hw_params,
-	.hw_free =	snd_via686a_hw_free,
-	.prepare =	snd_via686a_playback_prepare,
-	.trigger =	snd_via686a_playback_trigger,
-	.pointer =	snd_via686a_playback_pointer,
-	.copy =		snd_pcm_sgbuf_ops_copy_playback,
-	.silence =	snd_pcm_sgbuf_ops_silence,
-	.page =		snd_pcm_sgbuf_ops_page,
-};
-
-static snd_pcm_ops_t snd_via686a_capture_ops = {
-	.open =		snd_via686a_capture_open,
-	.close =	snd_via686a_capture_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_via686a_hw_params,
-	.hw_free =	snd_via686a_hw_free,
-	.prepare =	snd_via686a_capture_prepare,
-	.trigger =	snd_via686a_capture_trigger,
-	.pointer =	snd_via686a_capture_pointer,
-	.copy =		snd_pcm_sgbuf_ops_copy_capture,
-	.silence =	snd_pcm_sgbuf_ops_silence,
-	.page =		snd_pcm_sgbuf_ops_page,
-};
-
-static void snd_via686a_pcm_free(snd_pcm_t *pcm)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, pcm->private_data, return);
-	chip->pcm = NULL;
-}
-
-static int __devinit snd_via686a_pcm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
-{
-	snd_pcm_t *pcm;
-	int err;
-
-	if (rpcm)
-		*rpcm = NULL;
-	err = snd_pcm_new(chip->card, "VIA 82C686A", device, 1, 1, &pcm);
-	if (err < 0)
-		return err;
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686a_playback_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686a_capture_ops);
-
-	pcm->private_data = chip;
-	pcm->private_free = snd_via686a_pcm_free;
-	pcm->info_flags = 0;
-	strcpy(pcm->name, "VIA 82C686A");
-	chip->pcm = pcm;
-
-	if (rpcm)
-		*rpcm = NULL;
-	return 0;
-}
-
-
-/*
- *  Mixer part
- */
-
-static void snd_via686a_mixer_free_ac97(ac97_t *ac97)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
-	chip->ac97 = NULL;
-}
-
-static int __devinit snd_via686a_mixer(via686a_t *chip)
-{
-	ac97_t ac97;
-	int err;
-
-	memset(&ac97, 0, sizeof(ac97));
-	ac97.write = snd_via686a_codec_write;
-	ac97.read = snd_via686a_codec_read;
-	ac97.wait = snd_via686a_codec_wait;
-	ac97.private_data = chip;
-	ac97.private_free = snd_via686a_mixer_free_ac97;
-	ac97.clock = chip->ac97_clock;
-	if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
-		return err;
-	return 0;
-}
-
-/*
- * joystick
- */
-
-static int snd_via686a_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
-	return 0;
-}
-
-static int snd_via686a_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	via686a_t *chip = snd_kcontrol_chip(kcontrol);
-	u16 val;
-
-	pci_read_config_word(chip->pci, 0x42, &val);
-	ucontrol->value.integer.value[0] = (val & 0x08) ? 1 : 0;
-	return 0;
-}
-
-static int snd_via686a_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
-{
-	via686a_t *chip = snd_kcontrol_chip(kcontrol);
-	u16 val, oval;
-
-	pci_read_config_word(chip->pci, 0x42, &oval);
-	val = oval & ~0x08;
-	if (ucontrol->value.integer.value[0])
-		val |= 0x08;
-	if (val != oval) {
-		pci_write_config_word(chip->pci, 0x42, val);
-		return 1;
-	}
-	return 0;
-}
-
-static snd_kcontrol_new_t snd_via686a_joystick_control __devinitdata = {
-	.name = "Joystick",
-	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
-	.info = snd_via686a_joystick_info,
-	.get = snd_via686a_joystick_get,
-	.put = snd_via686a_joystick_put,
-};
-
-/*
- *
- */
-
-static int __devinit snd_via686a_chip_init(via686a_t *chip)
-{
-	ac97_t ac97;
-	unsigned int val;
-	int max_count;
-	unsigned char pval;
-
-	memset(&ac97, 0, sizeof(ac97));
-	ac97.private_data = chip;
-
-#if 0 /* broken on K7M? */
-	/* disable all legacy ports */
-	pci_write_config_byte(chip->pci, 0x42, 0);
-#endif
-
-	/* cold reset only when link is down */
-	pci_read_config_byte(chip->pci, 0x40, &pval);
-	if ((pval & 0x01) == 0) {
-		/* deassert ACLink reset, force SYNC */
-		pci_write_config_byte(chip->pci, 0x41, 0xe0);
-		udelay(100);
-		pci_write_config_byte(chip->pci, 0x41, 0x00);
-		udelay(100);
-		/* ACLink on, deassert ACLink reset, VSR, SGD data out */
-		/* note - FM data out has trouble with non VRA codecs !! */
-		pci_write_config_byte(chip->pci, 0x41, 0xcc);
-		udelay(100);
-	}
-	
-	/* Make sure VRA is enabled, in case we didn't do a
-	 * complete codec reset, above */
-	pci_read_config_byte(chip->pci, 0x41, &pval);
-	if ((pval & 0xcc) != 0xcc) {
-		/* ACLink on, deassert ACLink reset, VSR, SGD data out */
-		/* note - FM data out has trouble with non VRA codecs !! */
-		pci_write_config_byte(chip->pci, 0x41, 0xcc);
-		udelay(100);
-	}
-
-	/* wait until codec ready */
-	max_count = ((3 * HZ) / 4) + 1;
-	do {
-		pci_read_config_byte(chip->pci, 0x40, &pval);
-		if (pval & 0x01) /* primary codec ready */
-			break;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-	} while (--max_count > 0);
-
-	if ((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_BUSY)
-		snd_printk("AC'97 codec is not ready [0x%x]\n", val);
-
-	/* and then reset codec.. */
-	snd_via686a_codec_write(&ac97, AC97_RESET, 0x0000);
-
-	/* check the primary codec */
-	snd_via686a_codec_xwrite(chip, VIA_REG_AC97_READ |
-				 VIA_REG_AC97_PRIMARY_VALID |
-				 (VIA_REG_AC97_CODEC_ID_PRIMARY << VIA_REG_AC97_CODEC_ID_SHIFT));
-	max_count = ((3 * HZ) / 4) + 1;
-	do {
-		if ((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_PRIMARY_VALID)
-			goto __ac97_ok1;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-	} while (--max_count > 0);
-	snd_printk("Primary AC'97 codec is not valid [0x%x]\n", val);
-
-      __ac97_ok1:
-#if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */
-	snd_via686a_codec_xwrite(chip, VIA_REG_AC97_READ |
-				 VIA_REG_AC97_SECONDARY_VALID |
-				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
-	max_count = ((3 * HZ) / 4) + 1;
-	snd_via686a_codec_xwrite(chip, VIA_REG_AC97_READ |
-				 VIA_REG_AC97_SECONDARY_VALID |
-				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
-	do {
-		if ((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) {
-			chip->ac97_secondary = 1;
-			goto __ac97_ok2;
-		}
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
-	} while (--max_count > 0);
-	/* This is ok, the most of motherboards have only one codec */
-
-      __ac97_ok2:
-#endif
-
-#if 0
-	{
-	unsigned char cmdb;
-
-	pci_read_config_byte(chip->pci, 0x40, &cmdb);
-	printk("PCI[0x40] = 0x%x\n", cmdb);
-	pci_read_config_byte(chip->pci, 0x42, &cmdb);
-	printk("PCI[0x42] = 0x%x\n", cmdb);
-	pci_read_config_byte(chip->pci, 0x43, &cmdb);
-	printk("PCI[0x43] = 0x%x\n", cmdb);
-	pci_read_config_byte(chip->pci, 0x44, &cmdb);
-	printk("PCI[0x44] = 0x%x\n", cmdb);
-	pci_read_config_byte(chip->pci, 0x48, &cmdb);
-	printk("PCI[0x48] = 0x%x\n", cmdb);
-	}
-#endif
-
-	/* route FM trap to IRQ, disable FM trap */
-	pci_write_config_byte(chip->pci, 0x48, 0);
-	
-	/* disable all GPI interrupts */
-	outl(0, chip->port + 0x8c);
-
-	/* disable interrupts */
-	snd_via686a_channel_reset(chip, &chip->playback);
-	snd_via686a_channel_reset(chip, &chip->capture);
-	/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
-	return 0;
-}
-
-static int snd_via686a_free(via686a_t *chip)
-{
-	if (chip->irq < 0)
-		goto __end_hw;
-	/* disable interrupts */
-	snd_via686a_channel_reset(chip, &chip->playback);
-	snd_via686a_channel_reset(chip, &chip->capture);
-	/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
-	/* --- */
-	synchronize_irq(chip->irq);
-      __end_hw:
-	if (chip->res_port) {
-		release_resource(chip->res_port);
-		kfree_nocheck(chip->res_port);
-	}
-	if (chip->irq >= 0)
-		free_irq(chip->irq, (void *)chip);
-	pci_write_config_byte(chip->pci, 0x42, chip->old_legacy);
-	pci_write_config_byte(chip->pci, 0x43, chip->old_legacy_cfg);
-	snd_magic_kfree(chip);
-	return 0;
-}
-
-static int snd_via686a_dev_free(snd_device_t *device)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, device->device_data, return -ENXIO);
-	return snd_via686a_free(chip);
-}
-
-static int __devinit snd_via686a_create(snd_card_t * card,
-				     struct pci_dev *pci,
-				     unsigned int ac97_clock,
-				     unsigned char old_legacy,
-				     unsigned char old_legacy_cfg,
-				     via686a_t ** r_via)
-{
-	via686a_t *chip;
-	int err;
-        static snd_device_ops_t ops = {
-		.dev_free =	snd_via686a_dev_free,
-        };
-
-	if ((err = pci_enable_device(pci)) < 0)
-		return err;
-
-	if ((chip = snd_magic_kcalloc(via686a_t, 0, GFP_KERNEL)) == NULL)
-		return -ENOMEM;
-
-	chip->old_legacy = old_legacy;
-	chip->old_legacy_cfg = old_legacy_cfg;
-
-	spin_lock_init(&chip->reg_lock);
-	chip->card = card;
-	chip->pci = pci;
-	chip->irq = -1;
-	chip->port = pci_resource_start(pci, 0);
-	if ((chip->res_port = request_region(chip->port, 256, "VIA686A")) == NULL) {
-		snd_via686a_free(chip);
-		snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->port, chip->port + 256 - 1);
-		return -EBUSY;
-	}
-	if (request_irq(pci->irq, snd_via686a_interrupt, SA_INTERRUPT|SA_SHIRQ, "VIA686A", (void *)chip)) {
-		snd_via686a_free(chip);
-		snd_printk("unable to grab IRQ %d\n", chip->irq);
-		return -EBUSY;
-	}
-	chip->irq = pci->irq;
-	if (ac97_clock >= 8000 && ac97_clock <= 48000)
-		chip->ac97_clock = ac97_clock;
-	pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
-	synchronize_irq(chip->irq);
-
-	/* initialize offsets */
-	chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
-	chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
-	/*chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;*/
-
-	if ((err = snd_via686a_chip_init(chip)) < 0) {
-		snd_via686a_free(chip);
-		return err;
-	}
-
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-		snd_via686a_free(chip);
-		return err;
-	}
-
-	*r_via = chip;
-	return 0;
-}
-
-static int __devinit snd_via686a_probe(struct pci_dev *pci,
-				       const struct pci_device_id *id)
-{
-	static int dev;
-	snd_card_t *card;
-	via686a_t *chip;
-	int pcm_dev = 0;
-	unsigned char legacy;
-	unsigned char legacy_cfg;
-	int rev_h = 0, err;
-
-	if (dev >= SNDRV_CARDS)
-		return -ENODEV;
-	if (!snd_enable[dev]) {
-		dev++;
-		return -ENOENT;
-	}
-
-	card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
-	if (card == NULL)
-		return -ENOMEM;
-
-	pci_read_config_byte(pci, 0x42, &legacy);
-	pci_read_config_byte(pci, 0x43, &legacy_cfg);
-
-	if ((err = snd_via686a_create(card,
-				      pci,
-				      snd_ac97_clock[dev],
-				      legacy,
-				      legacy_cfg,
-				      &chip)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-
-
-	if (snd_via686a_mixer(chip) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if (snd_via686a_pcm(chip, pcm_dev++, NULL) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-#if 0
-	if (snd_via686a_pcm_fm(chip, pcm_dev++, NULL) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-#endif
-
-	legacy |= 0x40;		/* disable MIDI */
-	legacy &= ~0x08;	/* disable joystick */
-	if (chip->revision >= 0x20) {
-		if (check_region(pci_resource_start(pci, 2), 4)) {
-			rev_h = 0;
-			legacy &= ~0x80;	/* disable PCI I/O 2 */
-		} else {
-			rev_h = 1;
-			legacy |= 0x80;		/* enable PCI I/O 2 */
-		}
-	}
-	pci_write_config_byte(pci, 0x42, legacy);
-	pci_write_config_byte(pci, 0x43, legacy_cfg);
-	if (rev_h && snd_mpu_port[dev] >= 0x200) {	/* force MIDI */
-		legacy |= 0x02;	/* enable MPU */
-		pci_write_config_dword(pci, 0x18, (snd_mpu_port[dev] & 0xfffc) | 0x01);
-	} else {
-		if (rev_h && (legacy & 0x02)) {
-			snd_mpu_port[dev] = pci_resource_start(pci, 2);
-			if (snd_mpu_port[dev] < 0x200)	/* bad value */
-				legacy &= ~0x02;	/* disable MIDI */
-		} else {
-			switch (snd_mpu_port[dev]) {	/* force MIDI */
-			case 0x300:
-			case 0x310:
-			case 0x320:
-			case 0x330:
-				legacy_cfg &= ~(3 << 2);
-				legacy_cfg |= (snd_mpu_port[dev] & 0x0030) >> 2;
-				legacy |= 0x02;
-				break;
-			default:			/* no, use BIOS settings */
-				if (legacy & 0x02)
-					snd_mpu_port[dev] = 0x300 + ((legacy_cfg & 0x000c) << 2);
-			}
-		}
-	}
-	pci_write_config_byte(pci, 0x42, legacy);
-	pci_write_config_byte(pci, 0x43, legacy_cfg);
-	if (legacy & 0x02) {
-		if (check_region(snd_mpu_port[dev], 2)) {
-			printk(KERN_WARNING "unable to get MPU-401 port at 0x%lx, skipping\n", snd_mpu_port[dev]);
-			legacy &= ~0x02;
-			pci_write_config_byte(pci, 0x42, legacy);
-			goto __skip_mpu;
-		}
-		if (snd_mpu401_uart_new(card, 0, MPU401_HW_VIA686A,
-					snd_mpu_port[dev], 0,
-					pci->irq, 0,
-					&chip->rmidi) < 0) {
-			printk(KERN_WARNING "unable to initialize MPU-401 at 0x%lx, skipping\n", snd_mpu_port[dev]);
-			legacy &= ~0x02;
-			pci_write_config_byte(pci, 0x42, legacy);
-			goto __skip_mpu;
-		}
-		legacy &= ~0x40;	/* enable MIDI interrupt */
-		pci_write_config_byte(pci, 0x42, legacy);
-	      __skip_mpu:
-		;
-	}
-	
-	/* card switches */
-	err = snd_ctl_add(card, snd_ctl_new1(&snd_via686a_joystick_control, chip));
-	if (err < 0) {
-		snd_card_free(card);
-		return err;
-	}
-
-	strcpy(card->driver, "VIA686A");
-	strcpy(card->shortname, "VIA 82C686A/B");
-	
-	sprintf(card->longname, "%s at 0x%lx, irq %d",
-		card->shortname, chip->port, chip->irq);
-
-	if ((err = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	pci_set_drvdata(pci, card);
-	dev++;
-	return 0;
-}
-
-static void __devexit snd_via686a_remove(struct pci_dev *pci)
-{
-	snd_card_free(pci_get_drvdata(pci));
-	pci_set_drvdata(pci, NULL);
-}
-
-static struct pci_driver driver = {
-	.name = "VIA 82C686A/B",
-	.id_table = snd_via686a_ids,
-	.probe = snd_via686a_probe,
-	.remove = __devexit_p(snd_via686a_remove),
-};
-
-static int __init alsa_card_via686a_init(void)
-{
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "VIA 82C686A soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
-}
-
-static void __exit alsa_card_via686a_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via686a_init)
-module_exit(alsa_card_via686a_exit)
-
-#ifndef MODULE
-
-/* format is: snd-via686a=snd_enable,snd_index,snd_id,
-			  snd_mpu_port,snd_ac97_clock */
-
-static int __init alsa_card_via686a_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
-	       get_option(&str,&snd_index[nr_dev]) == 2 &&
-	       get_id(&str,&snd_id[nr_dev]) == 2 &&
-	       get_option(&str,(int *)&snd_mpu_port[nr_dev]) == 2 &&
-	       get_option(&str,&snd_ac97_clock[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-via686a=", alsa_card_via686a_setup);
-
-#endif /* ifndef MODULE */
diff -Nru a/sound/pci/via8233.c b/sound/pci/via8233.c
--- a/sound/pci/via8233.c	Tue Oct  1 17:08:34 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1022 +0,0 @@
-/*
- *   ALSA driver for VIA VT8233 (South Bridge)
- *
- *	Copyright (c) 2000 Tjeerd.Mulder@fujitsu-siemens.com
- *	This driver is based on VIA686 code by Jaroslav Kysela <perex@suse.cz>
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */      
-
-#include <sound/driver.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_sgbuf.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <sound/ac97_codec.h>
-#include <sound/mpu401.h>
-#define SNDRV_GET_ID
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Tjeerd.Mulder@fujitsu-siemens.com");
-MODULE_DESCRIPTION("VIA VT8233");
-MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{VIA,VT8233,pci}}");
-
-static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
-static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
-static int snd_ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
-
-MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_index, "Index value for VIA 8233 bridge.");
-MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
-MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
-MODULE_PARM_DESC(snd_id, "ID string for VIA 8233 bridge.");
-MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
-MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_enable, "Enable audio part of VIA 8233 bridge.");
-MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(snd_ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
-MODULE_PARM_DESC(snd_ac97_clock, "AC'97 codec clock (default 48000Hz).");
-MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
-
-
-/*
- *  Direct registers
- */
-
-#ifndef PCI_DEVICE_ID_VIA_8233_5
-#define PCI_DEVICE_ID_VIA_8233_5	0x3059
-#endif
-
-/* revision numbers */
-#define VIA_REV_PRE_8233	0x10	/* not in market */
-#define VIA_REV_8233C		0x20	/* 2 rec, 4 pb, 1 multi-pb */
-#define VIA_REV_8233		0x30	/* 2 rec, 4 pb, 1 multi-pb, spdif */
-#define VIA_REV_8233A		0x40	/* 1 rec, 1 multi-pb, spdf */
-#define VIA_REV_8235		0x50	/* 2 rec, 4 pb, 1 multi-pb, spdif */
-
-#define VIAREG(via, x) ((via)->port + VIA_REG_##x)
-
-/* offsets */
-#define VIA_REG_OFFSET_STATUS		0x00	/* byte - channel status */
-#define   VIA_REG_STAT_ACTIVE		0x80	/* RO */
-#define   VIA_REG_STAT_TRIGGER_QUEUED	0x08	/* RO */
-#define   VIA_REG_STAT_STOPPED		0x04	/* RWC */
-#define   VIA_REG_STAT_EOL		0x02	/* RWC */
-#define   VIA_REG_STAT_FLAG		0x01	/* RWC */
-#define VIA_REG_OFFSET_CONTROL		0x01	/* byte - channel control */
-#define   VIA_REG_CTRL_START		0x80	/* WO */
-#define   VIA_REG_CTRL_TERMINATE	0x40	/* WO */
-#define   VIA_REG_CTRL_AUTOSTART	0x20
-#define   VIA_REG_CTRL_PAUSE		0x08	/* RW */
-#define   VIA_REG_CTRL_INT_STOP		0x04		
-#define   VIA_REG_CTRL_INT_EOL		0x02
-#define   VIA_REG_CTRL_INT_FLAG		0x01
-#define   VIA_REG_CTRL_INT (VIA_REG_CTRL_INT_FLAG | VIA_REG_CTRL_INT_EOL | VIA_REG_CTRL_AUTOSTART)
-#define VIA_REG_OFFSET_TABLE_PTR	0x04	/* dword - channel table pointer */
-#define VIA_REG_OFFSET_CURR_PTR		0x04	/* dword - channel current pointer */
-#define VIA_REG_OFFSET_STOP_IDX		0x08	/* dword - stop index, channel type, sample rate */
-#define   VIA_REG_TYPE_16BIT		0x00200000	/* RW */
-#define   VIA_REG_TYPE_STEREO		0x00100000	/* RW */
-#define VIA_REG_OFFSET_CURR_COUNT	0x0c	/* dword - channel current count (24 bit) */
-#define VIA_REG_OFFSET_CURR_INDEX	0x0f	/* byte - channel current index */
-
-#define VIA_NUM_OF_DMA_CHANNELS	2
-
-/* playback block (VT8233/8233C) - channels 0-3 (0-0x3f) */
-#define VIA_REG_PLAYBACK_STATUS		0x00	/* byte - channel status */
-#define VIA_REG_PLAYBACK_CONTROL	0x01	/* byte - channel control */
-#define VIA_REG_PLAYBACK_VOLUME_L	0x02	/* byte */
-#define VIA_REG_PLAYBACK_VOLUME_R	0x03	/* byte */
-#define VIA_REG_PLAYBACK_TABLE_PTR	0x04	/* dword - channel table pointer */
-#define VIA_REG_PLAYBACK_CURR_PTR	0x04	/* dword - channel current pointer */
-#define VIA_REG_PLAYBACK_STOP_IDX	0x08    /* dword - stop index, channel type, sample rate */
-#define VIA_REG_PLAYBACK_CURR_COUNT	0x0c	/* dword - channel current count (24 bit) */
-#define VIA_REG_PLAYBACK_CURR_INDEX	0x0f	/* byte - channel current index */
-
-/* multi-channel playback */
-#define VIA_REG_MULTPLAY_STATUS		0x40	/* byte - channel status */
-#define VIA_REG_MULTPLAY_CONTROL	0x41	/* byte - channel control */
-#define VIA_REG_MULTPLAY_FORMAT		0x42	/* byte - format and channels */
-#define   VIA_REG_MULTPLAY_FMT_8BIT	0x00
-#define   VIA_REG_MULTPLAY_FMT_16BIT	0x80
-#define   VIA_REG_MULTPLAY_FMT_CH_MASK	0x70	/* # channels << 4 (valid = 1,2,4,6) */
-#define VIA_REG_MULTPLAY_SCRATCH	0x43	/* byte - nop */
-#define VIA_REG_MULTPLAY_TABLE_PTR	0x44	/* dword - channel table pointer */
-#define VIA_REG_MULTPLAY_CURR_PTR	0x44	/* dword - channel current pointer */
-#define VIA_REG_MULTPLAY_STOP_IDX	0x48    /* dword - stop index, slots */
-#define VIA_REG_MULTPLAY_CURR_COUNT	0x4c	/* dword - channel current count (24 bit) */
-#define VIA_REG_MULTIPLAY_CURR_INDEX	0x4f	/* byte - channel current index */
-
-/* capture block */
-#define VIA_REG_CAPTURE_STATUS		0x60	/* byte - channel status */
-#define VIA_REG_CAPTURE_CONTROL		0x61	/* byte - channel control */
-#define VIA_REG_CAPTURE_FIFO		0x62	/* byte - bit 6 = fifo  enable */
-#define   VIA_REG_CAPTURE_FIFO_ENABLE	0x40
-#define VIA_REG_CAPTURE_CHANNEL		0x63	/* byte - input select */
-#define   VIA_REG_CAPTURE_CHANNEL_MIC	0x4
-#define   VIA_REG_CAPTURE_CHANNEL_LINE	0
-#define   VIA_REG_CAPTURE_SELECT_CODEC	0x03	/* recording source codec (0 = primary) */
-#define VIA_REG_CAPTURE_TABLE_PTR	0x64	/* dword - channel table pointer */
-#define VIA_REG_CAPTURE_CURR_PTR	0x64	/* dword - channel current pointer */
-#define VIA_REG_CAPTURE_STOP_IDX	0x68	/* dword - stop index */
-#define VIA_REG_CAPTURE_CURR_COUNT	0x6c	/* dword - channel current count (24 bit) */
-#define VIA_REG_CAPTURE_CURR_INDEX	0x6f	/* byte - channel current index */
-/* AC'97 */
-#define VIA_REG_AC97			0x80	/* dword */
-#define   VIA_REG_AC97_CODEC_ID_MASK	(3<<30)
-#define   VIA_REG_AC97_CODEC_ID_SHIFT	30
-#define   VIA_REG_AC97_SECONDARY_VALID	(1<<27)
-#define   VIA_REG_AC97_PRIMARY_VALID	(1<<25)
-#define   VIA_REG_AC97_ANY_VALID	(VIA_REG_AC97_PRIMARY_VALID | VIA_REG_AC97_SECONDARY_VALID | (1<<28)| (1<<29))
-#define   VIA_REG_AC97_BUSY		(1<<24)
-#define   VIA_REG_AC97_READ		(1<<23)
-#define   VIA_REG_AC97_CMD_SHIFT	16
-#define   VIA_REG_AC97_CMD_MASK		0x7e
-#define   VIA_REG_AC97_DATA_SHIFT	0
-#define   VIA_REG_AC97_DATA_MASK	0xffff
-#define VIA_REG_SGD_SHADOW		0x84	/* dword */
-
-#define VIA_TBL_BIT_FLAG	0x40000000
-#define VIA_TBL_BIT_EOL		0x80000000
-
-/*
- *  
- */
-
-typedef struct {
-	unsigned long reg_offset;
-        snd_pcm_substream_t *substream;
-	int running;
-        unsigned int size;
-        unsigned int fragsize;
-	unsigned int frags;
-	unsigned int page_per_frag;
-	unsigned int curidx;
-	unsigned int tbl_entries;	/* number of descriptor table entries */
-	unsigned int tbl_size;		/* size of a table entry */
-	u32 *table; /* physical address + flag */
-	dma_addr_t table_addr;
-} viadev_t;
-
-static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
-			   struct pci_dev *pci)
-{
-	int i, size;
-	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
-
-	if (dev->table) {
-		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
-		dev->table = NULL;
-	}
-
-	/* allocate buffer descriptor lists */
-	if (dev->fragsize < PAGE_SIZE) {
-		dev->tbl_size = dev->fragsize;
-		dev->tbl_entries = dev->frags;
-		dev->page_per_frag = 1;
-	} else {
-		dev->tbl_size = PAGE_SIZE;
-		dev->tbl_entries = sgbuf->pages;
-		dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
-	}
-	/* the start of each lists must be aligned to 8 bytes,
-	 * but the kernel pages are much bigger, so we don't care
-	 */
-	dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
-	if (! dev->table)
-		return -ENOMEM;
-
-	if (dev->tbl_size < PAGE_SIZE) {
-		for (i = 0; i < dev->tbl_entries; i++)
-			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
-	} else {
-		for (i = 0; i < dev->tbl_entries; i++)
-			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
-	}
-	size = dev->size;
-	for (i = 0; i < dev->tbl_entries - 1; i++) {
-		dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
-		size -= dev->tbl_size;
-	}
-	dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
-
-	return 0;
-}
-
-
-static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
-			    struct pci_dev *pci)
-{
-	if (dev->table) {
-		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
-		dev->table = NULL;
-	}
-}
-
-
-/*
- */
-
-typedef struct _snd_via8233 via8233_t;
-#define chip_t via8233_t
-
-struct _snd_via8233 {
-	int irq;
-
-	unsigned long port;
-	struct resource *res_port;
-	unsigned char revision;
-
-	struct pci_dev *pci;
-	snd_card_t *card;
-
-	snd_pcm_t *pcm;
-	viadev_t playback;
-	viadev_t capture;
-
-	ac97_t *ac97;
-	unsigned int ac97_clock;
-
-	spinlock_t reg_lock;
-	snd_info_entry_t *proc_entry;
-};
-
-static struct pci_device_id snd_via8233_ids[] __devinitdata = {
-	{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },	/* VT8233 */
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, snd_via8233_ids);
-
-/*
- *  Basic I/O
- */
-
-static inline unsigned int snd_via8233_codec_xread(via8233_t *chip)
-{
-	/* this acces should be atomic */
-	return inl(VIAREG(chip, AC97));
-}
- 
-static inline void snd_via8233_codec_xwrite(via8233_t *chip, unsigned int val)
-{
-	/* this acces should be atomic */
-	outl(val, VIAREG(chip, AC97));
-}
- 
-static int snd_via8233_codec_ready(via8233_t *chip, int secondary)
-{
-	int time;
-
-	time = 1000;
-	do {
-		udelay(1);
-		if ((snd_via8233_codec_xread(chip) & VIA_REG_AC97_BUSY) == 0)
-			return 0;
-	} while (time--);
-	snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via8233_codec_xread(chip));
-	return -EIO;
-}
- 
-static void snd_via8233_codec_write(ac97_t *ac97,
-				    unsigned short reg,
-				    unsigned short val)
-{
-	via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return);
-	unsigned int xval;
-	
-	xval = (ac97->num) << VIA_REG_AC97_CODEC_ID_SHIFT;
-	xval |= ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
-	xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
-	xval |= val << VIA_REG_AC97_DATA_SHIFT;
-	spin_lock(&chip->reg_lock);
-	snd_via8233_codec_ready(chip, ac97->num);
-	snd_via8233_codec_xwrite(chip, xval);
-	snd_via8233_codec_ready(chip, ac97->num);
-	spin_unlock(&chip->reg_lock);
-}
-
-static unsigned short snd_via8233_codec_read(ac97_t *ac97, unsigned short reg)
-{
-	via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return ~0);
-	unsigned int val;
-	int valid = ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
-	int i;
-	
-	val = (ac97->num) << VIA_REG_AC97_CODEC_ID_SHIFT;
-	val |= valid;
-	val |= VIA_REG_AC97_READ;
-	val |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
-	spin_lock(&chip->reg_lock);
-	snd_via8233_codec_ready(chip, ac97->num);
-	snd_via8233_codec_xwrite(chip, val);
-	snd_via8233_codec_ready(chip, ac97->num);
-	for (i=1000; i--;) {
-		val = snd_via8233_codec_xread(chip);
-		if (val & valid) {
-			spin_unlock(&chip->reg_lock);
-			return (unsigned short)val;
-		}
-	}
-	spin_unlock(&chip->reg_lock);
-	snd_printk("codec_read: codec %i is not valid [0x%x]\n", ac97->num, val);
-	/* have to return some value, this is better then 0 */
-	return ~0;
-}
-
-#if 0
-static void snd_via8233_channel_print(via8233_t *chip, viadev_t *viadev)
-{
-	unsigned long port = chip->port + viadev->reg_offset;
-
-	printk("[0x%x] status = 0x%x, control = 0x%x, type = 0x%x, ptr = 0x%x, count = 0x%x\n",
-			port,
-			inb(port + VIA_REG_OFFSET_STATUS),
-			inb(port + VIA_REG_OFFSET_CONTROL),
-			inl(port + VIA_REG_OFFSET_STOP_IDX),
-			inl(port + VIA_REG_OFFSET_CURR_PTR),
-			inl(port + VIA_REG_OFFSET_CURR_COUNT));
-}
-#endif
-
-static void snd_via8233_channel_reset(via8233_t *chip, viadev_t *viadev)
-{
-	unsigned long port = chip->port + viadev->reg_offset;
-
-	outb(VIA_REG_CTRL_TERMINATE, port + VIA_REG_OFFSET_CONTROL);
-	udelay(50);
-	/* disable interrupts */
-	outb(0, port + VIA_REG_OFFSET_CONTROL);
-	/* clear interrupts */
-	outb(0x3, port + VIA_REG_OFFSET_STATUS);
-}
-
-static int snd_via8233_trigger(via8233_t *chip, viadev_t *viadev, int cmd)
-{
-	unsigned char val;
-	unsigned long port = chip->port + viadev->reg_offset;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		val = VIA_REG_CTRL_INT | VIA_REG_CTRL_START;
-		viadev->running = 1;
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		val = VIA_REG_CTRL_TERMINATE;
-		viadev->running = 0;
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		val = VIA_REG_CTRL_INT | VIA_REG_CTRL_PAUSE;
-		viadev->running = 1;
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		val = VIA_REG_CTRL_INT;
-		viadev->running = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-	outb(val, port + VIA_REG_OFFSET_CONTROL);
-	if (cmd == SNDRV_PCM_TRIGGER_STOP)
-		snd_via8233_channel_reset(chip, viadev);
-	return 0;
-}
-
-static int snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
-				     snd_pcm_substream_t *substream)
-{
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	unsigned long port = chip->port + viadev->reg_offset;
-	int v, err;
-
-	viadev->size = snd_pcm_lib_buffer_bytes(substream);
-	viadev->fragsize = snd_pcm_lib_period_bytes(substream);
-	viadev->frags = runtime->periods;
-	viadev->curidx = 0;
-
-	/* the period size must be in power of 2 */
-	v = ld2(viadev->fragsize);
-	if (viadev->fragsize != (1 << v)) {
-		snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
-		return -EINVAL;
-	}
-
-	snd_via8233_channel_reset(chip, viadev);
-
-	err = build_via_table(viadev, substream, chip->pci);
-	if (err < 0)
-		return err;
-
-	runtime->dma_bytes = viadev->size;
-	outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
-	if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
-		unsigned int slots;
-		int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
-		fmt |= runtime->channels << 4;
-		outb(fmt, chip->port + VIA_REG_MULTPLAY_FORMAT);
-		/* set sample number to slot 3, 4, 7, 8, 6, 9 */
-		switch (runtime->channels) {
-		case 1: slots = (1<<0) | (1<<4); break;
-		case 2: slots = (1<<0) | (2<<4); break;
-		case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
-		case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
-		default: slots = 0; break;
-		}
-		/* STOP index is never reached */
-		outl(0xff000000 | slots, chip->port + VIA_REG_MULTPLAY_STOP_IDX);
-	} else {
-		outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
-		     (runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
-		     0xff000000,    /* STOP index is never reached */
-		     port + VIA_REG_OFFSET_STOP_IDX);
-	}
-	return 0;
-}
-
-/*
- *  Interrupt handler
- */
-
-static inline void snd_via8233_update(via8233_t *chip, viadev_t *viadev)
-{
-	outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
-	if (viadev->substream && viadev->running) {
-		viadev->curidx++;
-		if (viadev->curidx >= viadev->page_per_frag) {
-			viadev->curidx = 0;
-			spin_unlock(&chip->reg_lock);
-			snd_pcm_period_elapsed(viadev->substream);
-			spin_lock(&chip->reg_lock);
-		}
-	}
-}
-
-static void snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	via8233_t *chip = snd_magic_cast(via8233_t, dev_id, return);
-
-	spin_lock(&chip->reg_lock);
-	if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
-		snd_via8233_update(chip, &chip->playback);
-	if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
-		snd_via8233_update(chip, &chip->capture);
-	spin_unlock(&chip->reg_lock);
-}
-
-/*
- *  PCM part
- */
-
-static int snd_via8233_playback_trigger(snd_pcm_substream_t * substream,
-					int cmd)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-
-	return snd_via8233_trigger(chip, &chip->playback, cmd);
-}
-
-static int snd_via8233_capture_trigger(snd_pcm_substream_t * substream,
-				       int cmd)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-	return snd_via8233_trigger(chip, &chip->capture, cmd);
-}
-
-static int snd_via8233_hw_params(snd_pcm_substream_t * substream,
-					  snd_pcm_hw_params_t * hw_params)
-{
-	return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
-}
-
-static int snd_via8233_hw_free(snd_pcm_substream_t * substream)
-{
-	return 0;
-}
-
-static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	if (chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
-		unsigned int tmp;
-		/* I don't understand this stuff but its from the documentation and this way it works */
-		outb(0 , VIAREG(chip, PLAYBACK_VOLUME_L));
-		outb(0 , VIAREG(chip, PLAYBACK_VOLUME_R));
-		tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
-		outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
-	}
-	return snd_via8233_setup_periods(chip, &chip->playback, substream);
-}
-
-static int snd_via8233_capture_prepare(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
-	outb(VIA_REG_CAPTURE_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
-	outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
-	return snd_via8233_setup_periods(chip, &chip->capture, substream);
-}
-
-static inline unsigned int snd_via8233_cur_ptr(via8233_t *chip, viadev_t *viadev)
-{
-	unsigned int val, count;
-
-	count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
-	/* The via686a does not have this current index register,
-	 * this register makes life easier for us here. */
-	val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
-	if (val < viadev->tbl_entries - 1) {
-		val *= viadev->tbl_size;
-		val += viadev->tbl_size - count;
-	} else {
-		val *= viadev->tbl_size;
-		val += (viadev->size % viadev->tbl_size) + 1 - count;
-	}
-	// printk("pointer: ptr = 0x%x, count = 0x%x, val = 0x%x\n", ptr, count, val);
-	return val;
-}
-
-static snd_pcm_uframes_t snd_via8233_playback_pointer(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, snd_via8233_cur_ptr(chip, &chip->playback));
-}
-
-static snd_pcm_uframes_t snd_via8233_capture_pointer(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, snd_via8233_cur_ptr(chip, &chip->capture));
-}
-
-static snd_pcm_hardware_t snd_via8233_playback =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE),
-	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		0,
-	.rate_min =		8000,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		6,
-	.buffer_bytes_max =	128 * 1024,
-	.period_bytes_min =	32,
-	.period_bytes_max =	128 * 1024,
-	.periods_min =		2,
-	.periods_max =		128,
-	.fifo_size =		0,
-};
-
-static snd_pcm_hardware_t snd_via8233_capture =
-{
-	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID),
-	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
-	.rates =		0,
-	.rate_min =		8000,
-	.rate_max =		48000,
-	.channels_min =		1,
-	.channels_max =		2,
-	.buffer_bytes_max =	128 * 1024,
-	.period_bytes_min =	32,
-	.period_bytes_max =	128 * 1024,
-	.periods_min =		2,
-	.periods_max =		128,
-	.fifo_size =		0,
-};
-
-static unsigned int channels[] = {
-	1, 2, 4, 6
-};
-
-#define CHANNELS sizeof(channels) / sizeof(channels[0])
-
-static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
-	.count = CHANNELS,
-	.list = channels,
-	.mask = 0,
-};
-
-static int snd_via8233_playback_open(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err;
-
-	chip->playback.substream = substream;
-	runtime->hw = snd_via8233_playback;
-	runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
-	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
-		runtime->hw.rate_min = 48000;
-	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
-		return err;
-	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
-		return err;
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-		return err;
-	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
-	return 0;
-}
-
-static int snd_via8233_capture_open(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err;
-
-	chip->capture.substream = substream;
-	runtime->hw = snd_via8233_capture;
-	runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
-	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
-		runtime->hw.rate_min = 48000;
-	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
-		return err;
-	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
-		return err;
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-		return err;
-	return 0;
-}
-
-static int snd_via8233_playback_close(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-
-	snd_via8233_channel_reset(chip, &chip->playback);
-	clean_via_table(&chip->playback, substream, chip->pci);
-	snd_pcm_sgbuf_delete(substream);
-	chip->playback.substream = NULL;
-	return 0;
-}
-
-static int snd_via8233_capture_close(snd_pcm_substream_t * substream)
-{
-	via8233_t *chip = snd_pcm_substream_chip(substream);
-
-	snd_via8233_channel_reset(chip, &chip->capture);
-	clean_via_table(&chip->capture, substream, chip->pci);
-	snd_pcm_sgbuf_delete(substream);
-	chip->capture.substream = NULL;
-	return 0;
-}
-
-static snd_pcm_ops_t snd_via8233_playback_ops = {
-	.open =		snd_via8233_playback_open,
-	.close =	snd_via8233_playback_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_via8233_hw_params,
-	.hw_free =	snd_via8233_hw_free,
-	.prepare =	snd_via8233_playback_prepare,
-	.trigger =	snd_via8233_playback_trigger,
-	.pointer =	snd_via8233_playback_pointer,
-	.copy =		snd_pcm_sgbuf_ops_copy_playback,
-	.silence =	snd_pcm_sgbuf_ops_silence,
-	.page =		snd_pcm_sgbuf_ops_page,
-};
-
-static snd_pcm_ops_t snd_via8233_capture_ops = {
-	.open =		snd_via8233_capture_open,
-	.close =	snd_via8233_capture_close,
-	.ioctl =	snd_pcm_lib_ioctl,
-	.hw_params =	snd_via8233_hw_params,
-	.hw_free =	snd_via8233_hw_free,
-	.prepare =	snd_via8233_capture_prepare,
-	.trigger =	snd_via8233_capture_trigger,
-	.pointer =	snd_via8233_capture_pointer,
-	.copy =		snd_pcm_sgbuf_ops_copy_capture,
-	.silence =	snd_pcm_sgbuf_ops_silence,
-	.page =		snd_pcm_sgbuf_ops_page,
-};
-
-static void snd_via8233_pcm_free(snd_pcm_t *pcm)
-{
-	via8233_t *chip = snd_magic_cast(via8233_t, pcm->private_data, return);
-	chip->pcm = NULL;
-}
-
-static int __devinit snd_via8233_pcm(via8233_t *chip, int device, snd_pcm_t ** rpcm)
-{
-	snd_pcm_t *pcm;
-	int err;
-
-	if (rpcm)
-		*rpcm = NULL;
-	err = snd_pcm_new(chip->card, "VIA 8233", device, 1, 1, &pcm);
-	if (err < 0)
-		return err;
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops);
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
-
-	pcm->private_data = chip;
-	pcm->private_free = snd_via8233_pcm_free;
-	pcm->info_flags = 0;
-	strcpy(pcm->name, "VIA 8233");
-	chip->pcm = pcm;
-
-	if (rpcm)
-		*rpcm = NULL;
-	return 0;
-}
-
-/*
- *  Mixer part
- */
-
-static void snd_via8233_mixer_free_ac97(ac97_t *ac97)
-{
-	via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return);
-	chip->ac97 = NULL;
-}
-
-static int __devinit snd_via8233_mixer(via8233_t *chip)
-{
-	ac97_t ac97;
-	int err;
-
-	memset(&ac97, 0, sizeof(ac97));
-	ac97.write = snd_via8233_codec_write;
-	ac97.read = snd_via8233_codec_read;
-	ac97.private_data = chip;
-	ac97.private_free = snd_via8233_mixer_free_ac97;
-	ac97.clock = chip->ac97_clock;
-	if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
-		return err;
-	return 0;
-}
-
-/*
- *
- */
-
-static int __devinit snd_via8233_chip_init(via8233_t *chip)
-{
-	ac97_t ac97;
-	unsigned char stat;
-	int i;
-	
-	memset(&ac97, 0, sizeof(ac97));
-	ac97.private_data = chip;
-
-	/* deassert ACLink reset */
-	pci_write_config_byte(chip->pci, 0x41, 0x40);
-	udelay(100);
-	/* deassert ACLink reset, force SYNC (warm AC'97 reset) */
-	pci_write_config_byte(chip->pci, 0x41, 0x60);
-	udelay(2);
-	/* ACLink on, deassert ACLink reset, VSR, SGD data out */
-	pci_write_config_byte(chip->pci, 0x41, 0xcc);
-
-	/* Wait for codec ready to be accessed. */
-	for (i=HZ; i--; ) {
-		pci_read_config_byte(chip->pci, 0x40, &stat);
-		if (stat & 1)
-			break;
-		if (!i) {
-			snd_printk("chip_init: failed to access primary codec.\n");
-			return ~0;
-		}
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-	}
-	snd_via8233_codec_ready(chip, 0);
-	snd_via8233_codec_write(&ac97, AC97_RESET, 0x0000);
-	snd_via8233_codec_read(&ac97, 0);
-
-	/* disable interrupts */
-	snd_via8233_channel_reset(chip, &chip->playback);
-	snd_via8233_channel_reset(chip, &chip->capture);
-	return 0;
-}
-
-static int snd_via8233_free(via8233_t *chip)
-{
-	if (chip->irq < 0)
-		goto __end_hw;
-	/* disable interrupts */
-	snd_via8233_channel_reset(chip, &chip->playback);
-	snd_via8233_channel_reset(chip, &chip->capture);
-	/* --- */
-	synchronize_irq(chip->irq);
-      __end_hw:
-	if (chip->res_port) {
-		release_resource(chip->res_port);
-		kfree_nocheck(chip->res_port);
-	}
-	if (chip->irq >= 0)
-		free_irq(chip->irq, (void *)chip);
-	snd_magic_kfree(chip);
-	return 0;
-}
-
-static int snd_via8233_dev_free(snd_device_t *device)
-{
-	via8233_t *chip = snd_magic_cast(via8233_t, device->device_data, return -ENXIO);
-	return snd_via8233_free(chip);
-}
-
-static int __devinit snd_via8233_create(snd_card_t * card,
-				     struct pci_dev *pci,
-				     unsigned int ac97_clock,
-				     via8233_t ** r_via)
-{
-	via8233_t *chip;
-	int err;
-        static snd_device_ops_t ops = {
-		.dev_free =	snd_via8233_dev_free,
-        };
-
-	if ((err = pci_enable_device(pci)) < 0)
-		return err;
-
-	if ((chip = snd_magic_kcalloc(via8233_t, 0, GFP_KERNEL)) == NULL)
-		return -ENOMEM;
-
-	spin_lock_init(&chip->reg_lock);
-	chip->card = card;
-	chip->pci = pci;
-	chip->irq = -1;
-	chip->port = pci_resource_start(pci, 0);
-	if ((chip->res_port = request_region(chip->port, 256, "VIA8233")) == NULL) {
-		snd_via8233_free(chip);
-		snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->port, chip->port + 256 - 1);
-		return -EBUSY;
-	}
-	if (request_irq(pci->irq, snd_via8233_interrupt, SA_INTERRUPT|SA_SHIRQ, "VIA8233", (void *)chip)) {
-		snd_via8233_free(chip);
-		snd_printk("unable to grab IRQ %d\n", chip->irq);
-		return -EBUSY;
-	}
-	chip->irq = pci->irq;
-	if (ac97_clock >= 8000 && ac97_clock <= 48000)
-		chip->ac97_clock = ac97_clock;
-	pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
-	synchronize_irq(chip->irq);
-
-	/* initialize offsets */
-#if 0
-	chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS; /* this doesn't work on VIA8233A */
-#endif
-	/* we use multi-channel playback mode, since this mode is supported
-	 * by all VIA8233 models (and obviously suitable for our purpose).
-	 */
-	chip->playback.reg_offset = VIA_REG_MULTPLAY_STATUS;
-
-	chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
-
-	if ((err = snd_via8233_chip_init(chip)) < 0) {
-		snd_via8233_free(chip);
-		return err;
-	}
-
-	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
-		snd_via8233_free(chip);
-		return err;
-	}
-
-	/* The 8233 ac97 controller does not implement the master bit
-	 * in the pci command register. IMHO this is a violation of the PCI spec.
-	 * We call pci_set_master here because it does not hurt. */
-	pci_set_master(pci);
-
-	*r_via = chip;
-	return 0;
-}
-
-static int __devinit snd_via8233_probe(struct pci_dev *pci,
-				       const struct pci_device_id *id)
-{
-	static int dev;
-	snd_card_t *card;
-	via8233_t *chip;
-	int pcm_dev = 0;
-	int err;
-
-	if (dev >= SNDRV_CARDS)
-		return -ENODEV;
-	if (!snd_enable[dev]) {
-		dev++;
-		return -ENOENT;
-	}
-
-	card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
-	if (card == NULL)
-		return -ENOMEM;
-
-	if ((err = snd_via8233_create(card,
-				      pci,
-				      snd_ac97_clock[dev],
-				      &chip)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-
-
-	if (snd_via8233_mixer(chip) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if (snd_via8233_pcm(chip, pcm_dev++, NULL) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-
-	strcpy(card->driver, "VIA8233");
-	strcpy(card->shortname, "VIA 8233");
-	
-	sprintf(card->longname, "%s at 0x%lx, irq %d",
-		card->shortname, chip->port, chip->irq);
-
-	if ((err = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	pci_set_drvdata(pci, card);
-	dev++;
-	return 0;
-}
-
-static void __devexit snd_via8233_remove(struct pci_dev *pci)
-{
-	snd_card_free(pci_get_drvdata(pci));
-	pci_set_drvdata(pci, NULL);
-}
-
-static struct pci_driver driver = {
-	.name = "VIA 8233",
-	.id_table = snd_via8233_ids,
-	.probe = snd_via8233_probe,
-	.remove = __devexit_p(snd_via8233_remove),
-};
-
-static int __init alsa_card_via8233_init(void)
-{
-	int err;
-
-	if ((err = pci_module_init(&driver)) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "VIA 8233 soundcard not found or device busy\n");
-#endif
-		return err;
-	}
-	return 0;
-}
-
-static void __exit alsa_card_via8233_exit(void)
-{
-	pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via8233_init)
-module_exit(alsa_card_via8233_exit)
-
-#ifndef MODULE
-
-/* format is: snd-via8233=snd_enable,snd_index,snd_id,snd_ac97_clock */
-
-static int __init alsa_card_via8233_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
-	       get_option(&str,&snd_index[nr_dev]) == 2 &&
-	       get_id(&str,&snd_id[nr_dev]) == 2 &&
-	       get_option(&str,&snd_ac97_clock[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-via8233=", alsa_card_via8233_setup);
-
-#endif /* ifndef MODULE */
diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/via82xx.c	Tue Oct  1 17:08:34 2002
@@ -0,0 +1,1345 @@
+/*
+ *   ALSA driver for VIA VT82xx (South Bridge)
+ *
+ *   VT82C686A/B/C, VT8233A/C, VT8235
+ *
+ *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
+ *	                   Tjeerd.Mulder <Tjeerd.Mulder@fujitsu-siemens.com>
+ *                    2002 Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/ac97_codec.h>
+#include <sound/mpu401.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("VIA VT82xx audio");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/B/C}}");
+
+static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
+static long snd_mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
+static int snd_ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
+
+MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_index, "Index value for VIA 82xx bridge.");
+MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
+MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(snd_id, "ID string for VIA 82xx bridge.");
+MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
+MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_enable, "Enable audio part of VIA 82xx bridge.");
+MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+MODULE_PARM_DESC(snd_mpu_port, "MPU-401 port.");
+MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_PORT_DESC);
+MODULE_PARM(snd_ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+MODULE_PARM_DESC(snd_ac97_clock, "AC'97 codec clock (default 48000Hz).");
+MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
+
+
+/* pci ids */
+#ifndef PCI_DEVICE_ID_VIA_82C686_5
+#define PCI_DEVICE_ID_VIA_82C686_5	0x3058
+#endif
+#ifndef PCI_DEVICE_ID_VIA_8233_5
+#define PCI_DEVICE_ID_VIA_8233_5	0x3059
+#endif
+
+/* revision numbers for via8233 */
+#define VIA_REV_PRE_8233	0x10	/* not in market */
+#define VIA_REV_8233C		0x20	/* 2 rec, 4 pb, 1 multi-pb */
+#define VIA_REV_8233		0x30	/* 2 rec, 4 pb, 1 multi-pb, spdif */
+#define VIA_REV_8233A		0x40	/* 1 rec, 1 multi-pb, spdf */
+#define VIA_REV_8235		0x50	/* 2 rec, 4 pb, 1 multi-pb, spdif */
+
+/*
+ *  Direct registers
+ */
+
+#define VIAREG(via, x) ((via)->port + VIA_REG_##x)
+
+/* common offsets */
+#define VIA_REG_OFFSET_STATUS		0x00	/* byte - channel status */
+#define   VIA_REG_STAT_ACTIVE		0x80	/* RO */
+#define   VIA_REG_STAT_PAUSED		0x40	/* RO */
+#define   VIA_REG_STAT_TRIGGER_QUEUED	0x08	/* RO */
+#define   VIA_REG_STAT_STOPPED		0x04	/* RWC */
+#define   VIA_REG_STAT_EOL		0x02	/* RWC */
+#define   VIA_REG_STAT_FLAG		0x01	/* RWC */
+#define VIA_REG_OFFSET_CONTROL		0x01	/* byte - channel control */
+#define   VIA_REG_CTRL_START		0x80	/* WO */
+#define   VIA_REG_CTRL_TERMINATE	0x40	/* WO */
+#define   VIA_REG_CTRL_AUTOSTART	0x20
+#define   VIA_REG_CTRL_PAUSE		0x08	/* RW */
+#define   VIA_REG_CTRL_INT_STOP		0x04		
+#define   VIA_REG_CTRL_INT_EOL		0x02
+#define   VIA_REG_CTRL_INT_FLAG		0x01
+#define   VIA_REG_CTRL_RESET		0x01	/* RW - probably reset? undocumented */
+#define   VIA_REG_CTRL_INT (VIA_REG_CTRL_INT_FLAG | VIA_REG_CTRL_INT_EOL | VIA_REG_CTRL_AUTOSTART)
+#define VIA_REG_OFFSET_TYPE		0x02	/* byte - channel type (686 only) */
+#define   VIA_REG_TYPE_AUTOSTART	0x80	/* RW - autostart at EOL */
+#define   VIA_REG_TYPE_16BIT		0x20	/* RW */
+#define   VIA_REG_TYPE_STEREO		0x10	/* RW */
+#define   VIA_REG_TYPE_INT_LLINE	0x00
+#define   VIA_REG_TYPE_INT_LSAMPLE	0x04
+#define   VIA_REG_TYPE_INT_LESSONE	0x08
+#define   VIA_REG_TYPE_INT_MASK		0x0c
+#define   VIA_REG_TYPE_INT_EOL		0x02
+#define   VIA_REG_TYPE_INT_FLAG		0x01
+#define VIA_REG_OFFSET_TABLE_PTR	0x04	/* dword - channel table pointer */
+#define VIA_REG_OFFSET_CURR_PTR		0x04	/* dword - channel current pointer */
+#define VIA_REG_OFFSET_STOP_IDX		0x08	/* dword - stop index, channel type, sample rate */
+#define   VIA8233_REG_TYPE_16BIT	0x00200000	/* RW */
+#define   VIA8233_REG_TYPE_STEREO	0x00100000	/* RW */
+#define VIA_REG_OFFSET_CURR_COUNT	0x0c	/* dword - channel current count (24 bit) */
+#define VIA_REG_OFFSET_CURR_INDEX	0x0f	/* byte - channel current index */
+
+#define DEFINE_VIA_REGSET(name,val) \
+enum {\
+	VIA_REG_##name##_STATUS		= (val),\
+	VIA_REG_##name##_CONTROL	= (val) + 0x01,\
+	VIA_REG_##name##_TYPE		= (val) + 0x02,\
+	VIA_REG_##name##_TABLE_PTR	= (val) + 0x04,\
+	VIA_REG_##name##_CURR_PTR	= (val) + 0x04,\
+	VIA_REG_##name##_STOP_IDX	= (val) + 0x08,\
+	VIA_REG_##name##_CURR_COUNT	= (val) + 0x0c,\
+}
+
+/* playback block */
+DEFINE_VIA_REGSET(PLAYBACK, 0x00);
+DEFINE_VIA_REGSET(CAPTURE, 0x10);
+DEFINE_VIA_REGSET(FM, 0x20);
+
+/* AC'97 */
+#define VIA_REG_AC97			0x80	/* dword */
+#define   VIA_REG_AC97_CODEC_ID_MASK	(3<<30)
+#define   VIA_REG_AC97_CODEC_ID_SHIFT	30
+#define   VIA_REG_AC97_CODEC_ID_PRIMARY	0x00
+#define   VIA_REG_AC97_CODEC_ID_SECONDARY 0x01
+#define   VIA_REG_AC97_SECONDARY_VALID	(1<<27)
+#define   VIA_REG_AC97_PRIMARY_VALID	(1<<25)
+#define   VIA_REG_AC97_BUSY		(1<<24)
+#define   VIA_REG_AC97_READ		(1<<23)
+#define   VIA_REG_AC97_CMD_SHIFT	16
+#define   VIA_REG_AC97_CMD_MASK		0x7e
+#define   VIA_REG_AC97_DATA_SHIFT	0
+#define   VIA_REG_AC97_DATA_MASK	0xffff
+#define VIA_REG_SGD_SHADOW		0x84	/* dword */
+
+/* multi-channel and capture registers for via8233 */
+DEFINE_VIA_REGSET(MULTPLAY, 0x20);
+DEFINE_VIA_REGSET(CAPTURE_8233, 0x10);
+
+/* via8233-specific registers */
+#define VIA_REG_PLAYBACK_VOLUME_L	0x02	/* byte */
+#define VIA_REG_PLAYBACK_VOLUME_R	0x03	/* byte */
+#define VIA_REG_MULTPLAY_FORMAT		0x42	/* byte - format and channels */
+#define   VIA_REG_MULTPLAY_FMT_8BIT	0x00
+#define   VIA_REG_MULTPLAY_FMT_16BIT	0x80
+#define   VIA_REG_MULTPLAY_FMT_CH_MASK	0x70	/* # channels << 4 (valid = 1,2,4,6) */
+#define VIA_REG_CAPTURE_FIFO		0x62	/* byte - bit 6 = fifo  enable */
+#define   VIA_REG_CAPTURE_FIFO_ENABLE	0x40
+#define VIA_REG_CAPTURE_CHANNEL		0x63	/* byte - input select */
+#define   VIA_REG_CAPTURE_CHANNEL_MIC	0x4
+#define   VIA_REG_CAPTURE_CHANNEL_LINE	0
+#define   VIA_REG_CAPTURE_SELECT_CODEC	0x03	/* recording source codec (0 = primary) */
+
+#define VIA_TBL_BIT_FLAG	0x40000000
+#define VIA_TBL_BIT_EOL		0x80000000
+
+/*
+ * pcm stream
+ */
+
+typedef struct {
+	unsigned long reg_offset;
+        snd_pcm_substream_t *substream;
+	int running;
+        unsigned int size;
+        unsigned int fragsize;
+	unsigned int frags;
+	unsigned int lastptr;
+	unsigned int lastcount;
+	unsigned int page_per_frag;
+	unsigned int curidx;
+	unsigned int tbl_entries;	/* number of descriptor table entries */
+	unsigned int tbl_size;		/* size of a table entry */
+	u32 *table; /* physical address + flag */
+	dma_addr_t table_addr;
+} viadev_t;
+
+
+static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			   struct pci_dev *pci)
+{
+	int i, size;
+	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+
+	if (dev->table) {
+		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+
+	/* allocate buffer descriptor lists */
+	if (dev->fragsize < PAGE_SIZE) {
+		dev->tbl_size = dev->fragsize;
+		dev->tbl_entries = dev->frags;
+		dev->page_per_frag = 1;
+	} else {
+		dev->tbl_size = PAGE_SIZE;
+		dev->tbl_entries = sgbuf->pages;
+		dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
+	}
+	/* the start of each lists must be aligned to 8 bytes,
+	 * but the kernel pages are much bigger, so we don't care
+	 */
+	dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
+	if (! dev->table)
+		return -ENOMEM;
+
+	if (dev->tbl_size < PAGE_SIZE) {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
+	} else {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
+	}
+	size = dev->size;
+	for (i = 0; i < dev->tbl_entries - 1; i++) {
+		dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
+		size -= dev->tbl_size;
+	}
+	dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
+
+	return 0;
+}
+
+
+static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			    struct pci_dev *pci)
+{
+	if (dev->table) {
+		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+}
+
+
+/*
+ */
+
+enum { TYPE_VIA686, TYPE_VIA8233 };
+
+typedef struct _snd_via82xx via82xx_t;
+#define chip_t via82xx_t
+
+struct _snd_via82xx {
+	int irq;
+
+	unsigned long port;
+	struct resource *res_port;
+	int chip_type;
+	unsigned char revision;
+
+	unsigned char old_legacy;
+	unsigned char old_legacy_cfg;
+
+	struct pci_dev *pci;
+	snd_card_t *card;
+
+	snd_pcm_t *pcm;
+	viadev_t playback;
+	viadev_t capture;
+
+	snd_rawmidi_t *rmidi;
+
+	ac97_t *ac97;
+	unsigned int ac97_clock;
+	unsigned int ac97_secondary;	/* secondary AC'97 codec is present */
+
+	spinlock_t reg_lock;
+	spinlock_t ac97_lock;
+	snd_info_entry_t *proc_entry;
+};
+
+static struct pci_device_id snd_via82xx_ids[] __devinitdata = {
+	{ 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },	/* 686A */
+	{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },	/* VT8233 */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, snd_via82xx_ids);
+
+/*
+ *  Basic I/O
+ */
+
+static inline unsigned int snd_via82xx_codec_xread(via82xx_t *chip)
+{
+	return inl(VIAREG(chip, AC97));
+}
+ 
+static inline void snd_via82xx_codec_xwrite(via82xx_t *chip, unsigned int val)
+{
+	outl(val, VIAREG(chip, AC97));
+}
+ 
+static int snd_via82xx_codec_ready(via82xx_t *chip, int secondary)
+{
+	unsigned int timeout = 1000;	/* 1ms */
+	unsigned int val;
+	
+	while (timeout-- > 0) {
+		udelay(1);
+		if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
+			return val & 0xffff;
+	}
+	snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
+	return -EIO;
+}
+ 
+static int snd_via82xx_codec_valid(via82xx_t *chip, int secondary)
+{
+	unsigned int timeout = 1000;	/* 1ms */
+	unsigned int val;
+	unsigned int stat = !secondary ? VIA_REG_AC97_PRIMARY_VALID :
+					 VIA_REG_AC97_SECONDARY_VALID;
+	
+	while (timeout-- > 0) {
+		udelay(1);
+		if ((val = snd_via82xx_codec_xread(chip)) & stat)
+			return val & 0xffff;
+	}
+	snd_printk("codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
+	return -EIO;
+}
+ 
+static void snd_via82xx_codec_wait(ac97_t *ac97)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
+	int err;
+	err = snd_via82xx_codec_ready(chip, ac97->num);
+	/* here we need to wait fairly for long time.. */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/2);
+}
+
+static void snd_via82xx_codec_write(ac97_t *ac97,
+				    unsigned short reg,
+				    unsigned short val)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
+	unsigned int xval;
+	
+	xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;
+	xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
+	xval |= reg << VIA_REG_AC97_CMD_SHIFT;
+	xval |= val << VIA_REG_AC97_DATA_SHIFT;
+	spin_lock(&chip->ac97_lock);
+	snd_via82xx_codec_xwrite(chip, xval);
+	snd_via82xx_codec_ready(chip, ac97->num);
+	spin_unlock(&chip->ac97_lock);
+}
+
+static unsigned short snd_via82xx_codec_read(ac97_t *ac97, unsigned short reg)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return ~0);
+	unsigned int xval, val = 0xffff;
+	int again = 0;
+
+	xval = ac97->num << VIA_REG_AC97_CODEC_ID_SHIFT;
+	xval |= ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
+	xval |= VIA_REG_AC97_READ;
+	xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
+	spin_lock(&chip->ac97_lock);
+      	while (1) {
+      		if (again++ > 3) {
+		        spin_unlock(&chip->ac97_lock);
+		      	return 0xffff;
+		}
+		snd_via82xx_codec_xwrite(chip, xval);
+		if (snd_via82xx_codec_ready(chip, ac97->num) < 0)
+			continue;
+		if (snd_via82xx_codec_valid(chip, ac97->num) >= 0) {
+			udelay(25);
+			val = snd_via82xx_codec_xread(chip);
+			break;
+		}
+	}
+	spin_unlock(&chip->ac97_lock);
+	return val & 0xffff;
+}
+
+static void snd_via82xx_channel_reset(via82xx_t *chip, viadev_t *viadev)
+{
+	unsigned long port = chip->port + viadev->reg_offset;
+
+	outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET, port + VIA_REG_OFFSET_CONTROL);
+	udelay(50);
+	/* disable interrupts */
+	outb(0x00, port + VIA_REG_OFFSET_CONTROL);
+	/* clear interrupts */
+	outb(0x03, port + VIA_REG_OFFSET_STATUS);
+	outb(0x00, port + VIA_REG_OFFSET_TYPE); /* for via686 */
+	outl(0, port + VIA_REG_OFFSET_CURR_PTR);
+}
+
+static int snd_via82xx_trigger(via82xx_t *chip, viadev_t *viadev, int cmd)
+{
+	unsigned char val;
+	unsigned long port = chip->port + viadev->reg_offset;
+	
+	if (chip->chip_type == TYPE_VIA8233)
+		val = VIA_REG_CTRL_INT;
+	else
+		val = 0;
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		val |= VIA_REG_CTRL_START;
+		viadev->running = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		val = VIA_REG_CTRL_TERMINATE;
+		viadev->running = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		val |= VIA_REG_CTRL_PAUSE;
+		viadev->running = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		viadev->running = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	outb(val, port + VIA_REG_OFFSET_CONTROL);
+	if (cmd == SNDRV_PCM_TRIGGER_STOP)
+		snd_via82xx_channel_reset(chip, viadev);
+	return 0;
+}
+
+
+static int snd_via82xx_setup_periods(via82xx_t *chip, viadev_t *viadev,
+				     snd_pcm_substream_t *substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	unsigned long port = chip->port + viadev->reg_offset;
+	int v, err;
+
+	viadev->size = snd_pcm_lib_buffer_bytes(substream);
+	viadev->fragsize = snd_pcm_lib_period_bytes(substream);
+	viadev->frags = runtime->periods;
+	viadev->lastptr = ~0;
+	viadev->lastcount = ~0;
+	viadev->curidx = 0;
+
+	/* the period size must be in power of 2 */
+	v = ld2(viadev->fragsize);
+	if (viadev->fragsize != (1 << v)) {
+		snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
+		return -EINVAL;
+	}
+
+	snd_via82xx_channel_reset(chip, viadev);
+
+	err = build_via_table(viadev, substream, chip->pci);
+	if (err < 0)
+		return err;
+
+	runtime->dma_bytes = viadev->size;
+	outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
+	switch (chip->chip_type) {
+	case TYPE_VIA686:
+		outb(VIA_REG_TYPE_AUTOSTART |
+		     (runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
+		     (runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
+		     ((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
+		     VIA_REG_TYPE_INT_EOL |
+		     VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
+		break;
+	case TYPE_VIA8233:
+		if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
+			unsigned int slots;
+			int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
+			fmt |= runtime->channels << 4;
+			outb(fmt, port + VIA_REG_OFFSET_TYPE);
+			/* set sample number to slot 3, 4, 7, 8, 6, 9 */
+			switch (runtime->channels) {
+			case 1: slots = (1<<0) | (1<<4); break;
+			case 2: slots = (1<<0) | (2<<4); break;
+			case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
+			case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
+			default: slots = 0; break;
+			}
+			/* STOP index is never reached */
+			outl(0xff000000 | slots, port + VIA_REG_OFFSET_STOP_IDX);
+		} else {
+			outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) |
+			     (runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) |
+			     0xff000000,    /* STOP index is never reached */
+			     port + VIA_REG_OFFSET_STOP_IDX);
+		}
+		break;
+	}
+	return 0;
+}
+
+/*
+ *  Interrupt handler
+ */
+
+static inline void snd_via82xx_update(via82xx_t *chip, viadev_t *viadev)
+{
+	outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
+	if (viadev->substream && viadev->running) {
+		viadev->curidx++;
+		if (viadev->curidx >= viadev->page_per_frag) {
+			viadev->curidx = 0;
+			spin_unlock(&chip->reg_lock);
+			snd_pcm_period_elapsed(viadev->substream);
+			spin_lock(&chip->reg_lock);
+		}
+	}
+}
+
+static void snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, dev_id, return);
+	unsigned int status;
+
+	spin_lock(&chip->reg_lock);
+	if (chip->chip_type == TYPE_VIA686) {
+		/* check mpu401 interrupt */
+		status = inl(VIAREG(chip, SGD_SHADOW));
+		if ((status & 0x00000077) == 0) {
+			spin_unlock(&chip->reg_lock);
+			if (chip->rmidi != NULL)
+				snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+			return;
+		}
+	}
+	/* check status for each stream */
+	if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
+		snd_via82xx_update(chip, &chip->playback);
+	if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
+		snd_via82xx_update(chip, &chip->capture);
+	spin_unlock(&chip->reg_lock);
+}
+
+/*
+ *  PCM part
+ */
+
+static int snd_via82xx_playback_trigger(snd_pcm_substream_t * substream,
+					int cmd)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+
+	return snd_via82xx_trigger(chip, &chip->playback, cmd);
+}
+
+static int snd_via82xx_capture_trigger(snd_pcm_substream_t * substream,
+				       int cmd)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+
+	return snd_via82xx_trigger(chip, &chip->capture, cmd);
+}
+
+static int snd_via82xx_hw_params(snd_pcm_substream_t * substream,
+				 snd_pcm_hw_params_t * hw_params)
+{
+	return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
+}
+
+static int snd_via82xx_hw_free(snd_pcm_substream_t * substream)
+{
+	return 0;
+}
+
+static int snd_via82xx_playback_prepare(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
+	if (chip->chip_type == TYPE_VIA8233 &&
+	    chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
+		unsigned int tmp;
+		/* I don't understand this stuff but its from the documentation and this way it works */
+		outb(0 , VIAREG(chip, PLAYBACK_VOLUME_L));
+		outb(0 , VIAREG(chip, PLAYBACK_VOLUME_R));
+		tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
+		outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
+	}
+	return snd_via82xx_setup_periods(chip, &chip->playback, substream);
+}
+
+static int snd_via82xx_capture_prepare(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
+	if (chip->chip_type == TYPE_VIA8233) {
+		outb(VIA_REG_CAPTURE_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
+		outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
+	}
+	return snd_via82xx_setup_periods(chip, &chip->capture, substream);
+}
+
+static inline unsigned int snd_via82xx_cur_ptr(via82xx_t *chip, viadev_t *viadev)
+{
+	unsigned int val, ptr, count;
+	
+	ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset)/* & 0xffffff*/;
+	switch (chip->chip_type) {
+	case TYPE_VIA686:
+		count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset);
+		if (ptr == viadev->lastptr && count > viadev->lastcount)
+			ptr += 8;
+		if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
+			return 0;
+		snd_assert(viadev->tbl_entries, return 0);
+		/* get index */
+		if (ptr <= (unsigned int)viadev->table_addr)
+			val = 0;
+		else
+			val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
+		viadev->lastptr = ptr;
+		viadev->lastcount = count;
+		break;
+
+	case TYPE_VIA8233:
+	default:
+		count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
+		/* The via686a does not have this current index register,
+		 * this register makes life easier for us here. */
+		val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
+		break;
+	}
+
+	/* convert to the linear position */
+	if (val < viadev->tbl_entries - 1) {
+		val *= viadev->tbl_size;
+		val += viadev->tbl_size - count;
+	} else {
+		val *= viadev->tbl_size;
+		val += (viadev->size % viadev->tbl_size) + 1 - count;
+	}
+	// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
+	return val;
+}
+
+static snd_pcm_uframes_t snd_via82xx_playback_pointer(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	return bytes_to_frames(substream->runtime, snd_via82xx_cur_ptr(chip, &chip->playback));
+}
+
+static snd_pcm_uframes_t snd_via82xx_capture_pointer(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	return bytes_to_frames(substream->runtime, snd_via82xx_cur_ptr(chip, &chip->capture));
+}
+
+static snd_pcm_hardware_t snd_via82xx_playback =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID |
+				 SNDRV_PCM_INFO_PAUSE),
+	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		0,
+	.rate_min =		8000,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	128 * 1024,
+	.period_bytes_min =	32,
+	.period_bytes_max =	128 * 1024,
+	.periods_min =		2,
+	.periods_max =		128,
+	.fifo_size =		0,
+};
+
+static snd_pcm_hardware_t snd_via82xx_capture =
+{
+	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				 SNDRV_PCM_INFO_MMAP_VALID),
+	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+	.rates =		0,
+	.rate_min =		8000,
+	.rate_max =		48000,
+	.channels_min =		1,
+	.channels_max =		2,
+	.buffer_bytes_max =	128 * 1024,
+	.period_bytes_min =	32,
+	.period_bytes_max =	128 * 1024,
+	.periods_min =		2,
+	.periods_max =		128,
+	.fifo_size =		0,
+};
+
+static unsigned int channels[] = {
+	1, 2, 4, 6
+};
+
+#define CHANNELS sizeof(channels) / sizeof(channels[0])
+
+static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
+	.count = CHANNELS,
+	.list = channels,
+	.mask = 0,
+};
+
+static int snd_via82xx_playback_open(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	chip->playback.substream = substream;
+	runtime->hw = snd_via82xx_playback;
+	runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
+	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
+		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+	/* we may remove following constaint when we modify table entries
+	   in interrupt */
+#if 0
+	/* applying the following constraint together with the power-of-2 rule
+	 * above may result in too narrow space.
+	 * this one is not strictly necessary, so let's disable it.
+	 */
+	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+#endif
+	if (chip->chip_type == TYPE_VIA8233) {
+		runtime->hw.channels_max = 6;
+		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
+	}
+	return 0;
+}
+
+static int snd_via82xx_capture_open(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	chip->capture.substream = substream;
+	runtime->hw = snd_via82xx_capture;
+	runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
+	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
+		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+#if 0
+	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+#endif
+	return 0;
+}
+
+static int snd_via82xx_playback_close(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+
+	clean_via_table(&chip->playback, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
+	chip->playback.substream = NULL;
+	return 0;
+}
+
+static int snd_via82xx_capture_close(snd_pcm_substream_t * substream)
+{
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+
+	clean_via_table(&chip->capture, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
+	chip->capture.substream = NULL;
+	return 0;
+}
+
+static snd_pcm_ops_t snd_via82xx_playback_ops = {
+	.open =		snd_via82xx_playback_open,
+	.close =	snd_via82xx_playback_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_via82xx_hw_params,
+	.hw_free =	snd_via82xx_hw_free,
+	.prepare =	snd_via82xx_playback_prepare,
+	.trigger =	snd_via82xx_playback_trigger,
+	.pointer =	snd_via82xx_playback_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy_playback,
+	.silence =	snd_pcm_sgbuf_ops_silence,
+	.page =		snd_pcm_sgbuf_ops_page,
+};
+
+static snd_pcm_ops_t snd_via82xx_capture_ops = {
+	.open =		snd_via82xx_capture_open,
+	.close =	snd_via82xx_capture_close,
+	.ioctl =	snd_pcm_lib_ioctl,
+	.hw_params =	snd_via82xx_hw_params,
+	.hw_free =	snd_via82xx_hw_free,
+	.prepare =	snd_via82xx_capture_prepare,
+	.trigger =	snd_via82xx_capture_trigger,
+	.pointer =	snd_via82xx_capture_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy_capture,
+	.silence =	snd_pcm_sgbuf_ops_silence,
+	.page =		snd_pcm_sgbuf_ops_page,
+};
+
+static void snd_via82xx_pcm_free(snd_pcm_t *pcm)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, pcm->private_data, return);
+	chip->pcm = NULL;
+}
+
+static int __devinit snd_via82xx_pcm(via82xx_t *chip, int device, snd_pcm_t ** rpcm)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if (rpcm)
+		*rpcm = NULL;
+	err = snd_pcm_new(chip->card, chip->card->shortname, device, 1, 1, &pcm);
+	if (err < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via82xx_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via82xx_capture_ops);
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_via82xx_pcm_free;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, chip->card->shortname);
+	chip->pcm = pcm;
+
+	if (rpcm)
+		*rpcm = NULL;
+	return 0;
+}
+
+
+/*
+ *  Mixer part
+ */
+
+static void snd_via82xx_mixer_free_ac97(ac97_t *ac97)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
+	chip->ac97 = NULL;
+}
+
+static int __devinit snd_via82xx_mixer(via82xx_t *chip)
+{
+	ac97_t ac97;
+	int err;
+
+	memset(&ac97, 0, sizeof(ac97));
+	ac97.write = snd_via82xx_codec_write;
+	ac97.read = snd_via82xx_codec_read;
+	ac97.wait = snd_via82xx_codec_wait;
+	ac97.private_data = chip;
+	ac97.private_free = snd_via82xx_mixer_free_ac97;
+	ac97.clock = chip->ac97_clock;
+	if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
+		return err;
+	return 0;
+}
+
+/*
+ * joystick
+ */
+
+static int snd_via82xx_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_via82xx_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	via82xx_t *chip = snd_kcontrol_chip(kcontrol);
+	u16 val;
+
+	pci_read_config_word(chip->pci, 0x42, &val);
+	ucontrol->value.integer.value[0] = (val & 0x08) ? 1 : 0;
+	return 0;
+}
+
+static int snd_via82xx_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	via82xx_t *chip = snd_kcontrol_chip(kcontrol);
+	u16 val, oval;
+
+	pci_read_config_word(chip->pci, 0x42, &oval);
+	val = oval & ~0x08;
+	if (ucontrol->value.integer.value[0])
+		val |= 0x08;
+	if (val != oval) {
+		pci_write_config_word(chip->pci, 0x42, val);
+		return 1;
+	}
+	return 0;
+}
+
+static snd_kcontrol_new_t snd_via82xx_joystick_control __devinitdata = {
+	.name = "Joystick",
+	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
+	.info = snd_via82xx_joystick_info,
+	.get = snd_via82xx_joystick_get,
+	.put = snd_via82xx_joystick_put,
+};
+
+/*
+ *
+ */
+
+static int __devinit snd_via82xx_chip_init(via82xx_t *chip)
+{
+	ac97_t ac97;
+	unsigned int val;
+	int max_count;
+	unsigned char pval;
+
+	memset(&ac97, 0, sizeof(ac97));
+	ac97.private_data = chip;
+
+#if 0 /* broken on K7M? */
+	if (chip->chip_type == TYPE_VIA686)
+		/* disable all legacy ports */
+		pci_write_config_byte(chip->pci, 0x42, 0);
+#endif
+
+	/* deassert ACLink reset, force SYNC */
+	pci_write_config_byte(chip->pci, 0x41, 0xe0);
+	udelay(100);
+	/* deassert ACLink reset, force SYNC (warm AC'97 reset) */
+	pci_write_config_byte(chip->pci, 0x41, 0x60);
+	udelay(2);
+	/* pci_write_config_byte(chip->pci, 0x41, 0x00);
+	   udelay(100);
+	*/
+	/* ACLink on, deassert ACLink reset, VSR, SGD data out */
+	/* note - FM data out has trouble with non VRA codecs !! */
+	pci_write_config_byte(chip->pci, 0x41, 0xcc);
+	udelay(100);
+	
+	/* Make sure VRA is enabled, in case we didn't do a
+	 * complete codec reset, above */
+	pci_read_config_byte(chip->pci, 0x41, &pval);
+	if ((pval & 0xcc) != 0xcc) {
+		/* ACLink on, deassert ACLink reset, VSR, SGD data out */
+		/* note - FM data out has trouble with non VRA codecs !! */
+		pci_write_config_byte(chip->pci, 0x41, 0xcc);
+		udelay(100);
+	}
+
+	/* wait until codec ready */
+	max_count = ((3 * HZ) / 4) + 1;
+	do {
+		pci_read_config_byte(chip->pci, 0x40, &pval);
+		if (pval & 0x01) /* primary codec ready */
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	} while (--max_count > 0);
+
+	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
+		snd_printk("AC'97 codec is not ready [0x%x]\n", val);
+
+	/* and then reset codec.. */
+	snd_via82xx_codec_ready(chip, 0);
+	snd_via82xx_codec_write(&ac97, AC97_RESET, 0x0000);
+	snd_via82xx_codec_read(&ac97, 0);
+
+#if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */
+	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
+				 VIA_REG_AC97_SECONDARY_VALID |
+				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
+	max_count = ((3 * HZ) / 4) + 1;
+	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
+				 VIA_REG_AC97_SECONDARY_VALID |
+				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
+	do {
+		if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) {
+			chip->ac97_secondary = 1;
+			goto __ac97_ok2;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(1);
+	} while (--max_count > 0);
+	/* This is ok, the most of motherboards have only one codec */
+
+      __ac97_ok2:
+#endif
+
+	if (chip->chip_type == TYPE_VIA686) {
+		/* route FM trap to IRQ, disable FM trap */
+		pci_write_config_byte(chip->pci, 0x48, 0);
+		/* disable all GPI interrupts */
+		outl(0, chip->port + 0x8c);
+	}
+
+	/* disable interrupts */
+	snd_via82xx_channel_reset(chip, &chip->playback);
+	snd_via82xx_channel_reset(chip, &chip->capture);
+	return 0;
+}
+
+static int snd_via82xx_free(via82xx_t *chip)
+{
+	if (chip->irq < 0)
+		goto __end_hw;
+	/* disable interrupts */
+	snd_via82xx_channel_reset(chip, &chip->playback);
+	snd_via82xx_channel_reset(chip, &chip->capture);
+	/* --- */
+	synchronize_irq(chip->irq);
+      __end_hw:
+	if (chip->res_port) {
+		release_resource(chip->res_port);
+		kfree_nocheck(chip->res_port);
+	}
+	if (chip->irq >= 0)
+		free_irq(chip->irq, (void *)chip);
+	if (chip->chip_type == TYPE_VIA686) {
+		pci_write_config_byte(chip->pci, 0x42, chip->old_legacy);
+		pci_write_config_byte(chip->pci, 0x43, chip->old_legacy_cfg);
+	}
+	snd_magic_kfree(chip);
+	return 0;
+}
+
+static int snd_via82xx_dev_free(snd_device_t *device)
+{
+	via82xx_t *chip = snd_magic_cast(via82xx_t, device->device_data, return -ENXIO);
+	return snd_via82xx_free(chip);
+}
+
+static int __devinit snd_via82xx_create(snd_card_t * card,
+					struct pci_dev *pci,
+					int chip_type,
+					unsigned int ac97_clock,
+					via82xx_t ** r_via)
+{
+	via82xx_t *chip;
+	int err;
+        static snd_device_ops_t ops = {
+		.dev_free =	snd_via82xx_dev_free,
+        };
+
+	if ((err = pci_enable_device(pci)) < 0)
+		return err;
+
+	if ((chip = snd_magic_kcalloc(via82xx_t, 0, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	chip->chip_type = chip_type;
+
+	spin_lock_init(&chip->reg_lock);
+	spin_lock_init(&chip->ac97_lock);
+	chip->card = card;
+	chip->pci = pci;
+	chip->irq = -1;
+
+	pci_read_config_byte(pci, 0x42, &chip->old_legacy);
+	pci_read_config_byte(pci, 0x43, &chip->old_legacy_cfg);
+
+	chip->port = pci_resource_start(pci, 0);
+	if ((chip->res_port = request_region(chip->port, 256, card->driver)) == NULL) {
+		snd_via82xx_free(chip);
+		snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->port, chip->port + 256 - 1);
+		return -EBUSY;
+	}
+	if (request_irq(pci->irq, snd_via82xx_interrupt, SA_INTERRUPT|SA_SHIRQ,
+			card->driver, (void *)chip)) {
+		snd_via82xx_free(chip);
+		snd_printk("unable to grab IRQ %d\n", chip->irq);
+		return -EBUSY;
+	}
+	chip->irq = pci->irq;
+	if (ac97_clock >= 8000 && ac97_clock <= 48000)
+		chip->ac97_clock = ac97_clock;
+	pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
+	synchronize_irq(chip->irq);
+
+	/* initialize offsets */
+	switch (chip->chip_type) {
+	case TYPE_VIA686:
+		chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
+		chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
+		break;
+	case TYPE_VIA8233:
+		/* we use multi-channel playback mode, since this mode is supported
+		 * by all VIA8233 models (and obviously suitable for our purpose).
+		 */
+		chip->playback.reg_offset = VIA_REG_MULTPLAY_STATUS;
+		chip->capture.reg_offset = VIA_REG_CAPTURE_8233_STATUS;
+		break;
+	}
+
+	if ((err = snd_via82xx_chip_init(chip)) < 0) {
+		snd_via82xx_free(chip);
+		return err;
+	}
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+		snd_via82xx_free(chip);
+		return err;
+	}
+
+	/* The 8233 ac97 controller does not implement the master bit
+	 * in the pci command register. IMHO this is a violation of the PCI spec.
+	 * We call pci_set_master here because it does not hurt. */
+	pci_set_master(pci);
+
+	*r_via = chip;
+	return 0;
+}
+
+static int __devinit snd_via82xx_probe(struct pci_dev *pci,
+				       const struct pci_device_id *id)
+{
+	static int dev;
+	snd_card_t *card;
+	via82xx_t *chip;
+	int pcm_dev = 0;
+	int chip_type;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!snd_enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	chip_type = id->driver_data;
+	switch (chip_type) {
+	case TYPE_VIA686:
+		strcpy(card->driver, "VIA686A");
+		strcpy(card->shortname, "VIA 82C686A/B");
+		break;
+	case TYPE_VIA8233:
+		strcpy(card->driver, "VIA8233");
+		strcpy(card->shortname, "VIA 8233A/C");
+		break;
+	default:
+		snd_printk(KERN_ERR "invalid chip type %d\n", chip_type);
+		snd_card_free(card);
+		return -EINVAL;
+	}
+		
+	if ((err = snd_via82xx_create(card, pci, chip_type, snd_ac97_clock[dev], &chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+
+	if (snd_via82xx_mixer(chip) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	if (snd_via82xx_pcm(chip, pcm_dev++, NULL) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#if 0
+	if (snd_via82xx_pcm_fm(chip, pcm_dev++, NULL) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#endif
+
+	if (chip->chip_type == TYPE_VIA686) {
+		unsigned char legacy, legacy_cfg;
+		int rev_h = 0;
+		legacy = chip->old_legacy;
+		legacy_cfg = chip->old_legacy_cfg;
+		legacy |= 0x40;		/* disable MIDI */
+		legacy &= ~0x08;	/* disable joystick */
+		if (chip->revision >= 0x20) {
+			if (check_region(pci_resource_start(pci, 2), 4)) {
+				rev_h = 0;
+				legacy &= ~0x80;	/* disable PCI I/O 2 */
+			} else {
+				rev_h = 1;
+				legacy |= 0x80;		/* enable PCI I/O 2 */
+			}
+		}
+		pci_write_config_byte(pci, 0x42, legacy);
+		pci_write_config_byte(pci, 0x43, legacy_cfg);
+		if (rev_h && snd_mpu_port[dev] >= 0x200) {	/* force MIDI */
+			legacy |= 0x02;	/* enable MPU */
+			pci_write_config_dword(pci, 0x18, (snd_mpu_port[dev] & 0xfffc) | 0x01);
+		} else {
+			if (rev_h && (legacy & 0x02)) {
+				snd_mpu_port[dev] = pci_resource_start(pci, 2);
+				if (snd_mpu_port[dev] < 0x200)	/* bad value */
+					legacy &= ~0x02;	/* disable MIDI */
+			} else {
+				switch (snd_mpu_port[dev]) {	/* force MIDI */
+				case 0x300:
+				case 0x310:
+				case 0x320:
+				case 0x330:
+					legacy_cfg &= ~(3 << 2);
+					legacy_cfg |= (snd_mpu_port[dev] & 0x0030) >> 2;
+					legacy |= 0x02;
+					break;
+				default:			/* no, use BIOS settings */
+					if (legacy & 0x02)
+						snd_mpu_port[dev] = 0x300 + ((legacy_cfg & 0x000c) << 2);
+				}
+			}
+		}
+		pci_write_config_byte(pci, 0x42, legacy);
+		pci_write_config_byte(pci, 0x43, legacy_cfg);
+		if (legacy & 0x02) {
+			if (check_region(snd_mpu_port[dev], 2)) {
+				printk(KERN_WARNING "unable to get MPU-401 port at 0x%lx, skipping\n", snd_mpu_port[dev]);
+				legacy &= ~0x02;
+				pci_write_config_byte(pci, 0x42, legacy);
+				goto __skip_mpu;
+			}
+			if (snd_mpu401_uart_new(card, 0, MPU401_HW_VIA686A,
+						snd_mpu_port[dev], 0,
+						pci->irq, 0,
+						&chip->rmidi) < 0) {
+				printk(KERN_WARNING "unable to initialize MPU-401 at 0x%lx, skipping\n", snd_mpu_port[dev]);
+				legacy &= ~0x02;
+				pci_write_config_byte(pci, 0x42, legacy);
+				goto __skip_mpu;
+			}
+			legacy &= ~0x40;	/* enable MIDI interrupt */
+			pci_write_config_byte(pci, 0x42, legacy);
+		__skip_mpu:
+			;
+		}
+	
+		/* card switches */
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_via82xx_joystick_control, chip));
+		if (err < 0) {
+			snd_card_free(card);
+			return err;
+		}
+	}
+
+	sprintf(card->longname, "%s at 0x%lx, irq %d",
+		card->shortname, chip->port, chip->irq);
+
+	if ((err = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	pci_set_drvdata(pci, card);
+	dev++;
+	return 0;
+}
+
+static void __devexit snd_via82xx_remove(struct pci_dev *pci)
+{
+	snd_card_free(pci_get_drvdata(pci));
+	pci_set_drvdata(pci, NULL);
+}
+
+static struct pci_driver driver = {
+	.name = "VIA 82xx Audio",
+	.id_table = snd_via82xx_ids,
+	.probe = snd_via82xx_probe,
+	.remove = __devexit_p(snd_via82xx_remove),
+};
+
+static int __init alsa_card_via82xx_init(void)
+{
+	int err;
+
+	if ((err = pci_module_init(&driver)) < 0) {
+#ifdef MODULE
+		printk(KERN_ERR "VIA 82xx soundcard not found or device busy\n");
+#endif
+		return err;
+	}
+	return 0;
+}
+
+static void __exit alsa_card_via82xx_exit(void)
+{
+	pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_via82xx_init)
+module_exit(alsa_card_via82xx_exit)
+
+#ifndef MODULE
+
+/* format is: snd-via82xx=snd_enable,snd_index,snd_id,
+			  snd_mpu_port,snd_ac97_clock */
+
+static int __init alsa_card_via82xx_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
+	       get_option(&str,&snd_index[nr_dev]) == 2 &&
+	       get_id(&str,&snd_id[nr_dev]) == 2 &&
+	       get_option(&str,(int *)&snd_mpu_port[nr_dev]) == 2 &&
+	       get_option(&str,&snd_ac97_clock[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-via82xx=", alsa_card_via82xx_setup);
+
+#endif /* ifndef MODULE */
+ 
diff -Nru a/sound/ppc/keywest.c b/sound/ppc/keywest.c
--- a/sound/ppc/keywest.c	Tue Oct  1 17:08:34 2002
+++ b/sound/ppc/keywest.c	Tue Oct  1 17:08:34 2002
@@ -74,11 +74,14 @@
 	new_client->id = keywest_ctx->id++; /* Automatically unique */
 	keywest_ctx->client = new_client;
 
-	if ((err = keywest_ctx->init_client(keywest_ctx)) < 0)
+	if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) {
+		snd_printk(KERN_ERR "tumbler: cannot initialize the MCS\n");
 		goto __err;
+	}
 
 	/* Tell the i2c layer a new client has arrived */
 	if (i2c_attach_client(new_client)) {
+		snd_printk(KERN_ERR "tumbler: cannot attach i2c client\n");
 		err = -ENODEV;
 		goto __err;
 	}
diff -Nru a/sound/ppc/pmac.c b/sound/ppc/pmac.c
--- a/sound/ppc/pmac.c	Tue Oct  1 17:08:34 2002
+++ b/sound/ppc/pmac.c	Tue Oct  1 17:08:34 2002
@@ -1170,9 +1170,17 @@
 		// chip->can_byte_swap = 0; /* FIXME: check this */
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
-	if (device_is_compatible(sound, "tumbler") ||
-	    device_is_compatible(sound, "snapper")) {
+	if (device_is_compatible(sound, "tumbler")) {
 		chip->model = PMAC_TUMBLER;
+		chip->can_capture = 0;  /* no capture */
+		chip->can_duplex = 0;
+		// chip->can_byte_swap = 0; /* FIXME: check this */
+		chip->num_freqs = 2;
+		chip->freq_table = tumbler_freqs;
+		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
+	}
+	if (device_is_compatible(sound, "snapper")) {
+		chip->model = PMAC_SNAPPER;
 		chip->can_capture = 0;  /* no capture */
 		chip->can_duplex = 0;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
diff -Nru a/sound/ppc/pmac.h b/sound/ppc/pmac.h
--- a/sound/ppc/pmac.h	Tue Oct  1 17:08:34 2002
+++ b/sound/ppc/pmac.h	Tue Oct  1 17:08:34 2002
@@ -40,6 +40,7 @@
 #endif
 #endif
 #include <linux/nvram.h>
+#include <linux/tty.h>
 #include <linux/vt_kern.h>
 #include <asm/dbdma.h>
 #include <asm/prom.h>
@@ -115,7 +116,7 @@
  */
 
 enum snd_pmac_model {
-	PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER
+	PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, PMAC_SNAPPER
 };
 
 struct snd_pmac {
diff -Nru a/sound/ppc/powermac.c b/sound/ppc/powermac.c
--- a/sound/ppc/powermac.c	Tue Oct  1 17:08:34 2002
+++ b/sound/ppc/powermac.c	Tue Oct  1 17:08:34 2002
@@ -94,8 +94,10 @@
 			goto __error;
 		break;
 	case PMAC_TUMBLER:
-		strcpy(card->driver, "PMac Tumbler");
-		strcpy(card->shortname, "PowerMac Tumbler");
+	case PMAC_SNAPPER:
+		name_ext = chip->model == PMAC_TUMBLER ? "Tumbler" : "Snapper";
+		sprintf(card->driver, "PMac %s", name_ext);
+		sprintf(card->shortname, "PowerMac %s", name_ext);
 		sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
 			card->shortname, chip->device_id, chip->subframe);
 		if ((err = snd_pmac_tumbler_init(chip)) < 0)
diff -Nru a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
--- a/sound/ppc/tumbler.c	Tue Oct  1 17:08:34 2002
+++ b/sound/ppc/tumbler.c	Tue Oct  1 17:08:34 2002
@@ -1,5 +1,5 @@
 /*
- * PMac Tumbler lowlevel functions
+ * PMac Tumbler/Snapper lowlevel functions
  *
  * Copyright (c) by Takashi Iwai <tiwai@suse.de>
  *
@@ -46,17 +46,27 @@
 #define TAS_REG_VOL	0x04
 #define TAS_REG_TREBLE	0x05
 #define TAS_REG_BASS	0x06
-#define TAS_REG_INPUT1	0x07	/* pcm */
-#define TAS_REG_INPUT2	0x08	/* ??? */
+#define TAS_REG_INPUT1	0x07
+#define TAS_REG_INPUT2	0x08
 
+/* tas3001c */
 #define TAS_REG_PCM	TAS_REG_INPUT1
+ 
+/* tas3004 */
+#define TAS_REG_LMIX	TAS_REG_INPUT1
+#define TAS_REG_RMIX	TAS_REG_INPUT2
 
-#define TAS_MIXER_VOL_MAX	200
+/* mono volumes for tas3001c/tas3004 */
+enum {
+	VOL_IDX_PCM_MONO, /* tas3001c only */
+	VOL_IDX_BASS, VOL_IDX_TREBLE,
+	VOL_IDX_LAST_MONO
+};
 
+/* stereo volumes for tas3004 */
 enum {
-	VOL_IDX_PCM, VOL_IDX_BASS, VOL_IDX_TREBLE,
-	//VOL_IDX_ALTPCM,
-	VOL_IDX_LAST
+	VOL_IDX_PCM, VOL_IDX_PCM2, VOL_IDX_ADC,
+	VOL_IDX_LAST_MIX
 };
 
 typedef struct pmac_gpio {
@@ -77,7 +87,8 @@
 	int headphone_irq;
 	unsigned int master_vol[2];
 	unsigned int master_switch[2];
-	unsigned int mono_vol[VOL_IDX_LAST];
+	unsigned int mono_vol[VOL_IDX_LAST_MONO];
+	unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
 	int drc_range;
 	int drc_enable;
 } pmac_tumbler_t;
@@ -90,9 +101,16 @@
 
 static int tumbler_init_client(pmac_keywest_t *i2c)
 {
-       /* normal operation, SCLK=64fps, i2s output, i2s input, 16bit width */
-       return snd_pmac_keywest_write_byte(i2c, TAS_REG_MCS,
-                                          (1<<6)+(2<<4)+(2<<2)+0);
+	int err, count = 10;
+	do {
+		/* normal operation, SCLK=64fps, i2s output, i2s input, 16bit width */
+		err =  snd_pmac_keywest_write_byte(i2c, TAS_REG_MCS,
+						   (1<<6)+(2<<4)+(2<<2)+0);
+		if (err >= 0)
+			return err;
+		mdelay(10);
+	} while (count--);
+	return -ENXIO;
 }
 
 
@@ -245,8 +263,11 @@
 
 
 /*
- * dynamic range compression
+ * TAS3001c dynamic range compression
  */
+
+#define TAS3001_DRC_MAX		0x5f
+
 static int tumbler_set_drc(pmac_tumbler_t *mix)
 {
 	unsigned char val[2];
@@ -256,7 +277,7 @@
   
 	if (mix->drc_enable) {
 		val[0] = 0xc1; /* enable, 3:1 compression */
-		if (mix->drc_range > 0x5f)
+		if (mix->drc_range > TAS3001_DRC_MAX)
 			val[1] = 0xf0;
 		else if (mix->drc_range < 0)
 			val[1] = 0x91;
@@ -274,12 +295,49 @@
 	return 0;
 }
 
+/*
+ * TAS3004
+ */
+
+#define TAS3004_DRC_MAX		0xef
+
+static int snapper_set_drc(pmac_tumbler_t *mix)
+{
+	unsigned char val[6];
+
+	if (! mix->i2c.client)
+		return -ENODEV;
+  
+	if (mix->drc_enable)
+		val[0] = 0x50; /* 3:1 above threshold */
+	else
+		val[0] = 0x51; /* disabled */
+	val[1] = 0x02; /* 1:1 below threshold */
+	if (mix->drc_range > 0xef)
+		val[2] = 0xef;
+	else if (mix->drc_range < 0)
+		val[2] = 0x00;
+	else
+		val[2] = mix->drc_range;
+	val[3] = 0xb0;
+	val[4] = 0x60;
+	val[5] = 0xa0;
+
+	if (snd_pmac_keywest_write(&mix->i2c, TAS_REG_DRC, 6, val) < 0) {
+		snd_printk("failed to set DRC\n");  
+		return -EINVAL; 
+	}
+	return 0;
+}
+
 static int tumbler_info_drc_value(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 1;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 0x5f;
+	uinfo->value.integer.max =
+		chip->model == PMAC_TUMBLER ? TAS3001_DRC_MAX : TAS3004_DRC_MAX;
 	return 0;
 }
 
@@ -304,7 +362,10 @@
 	change = mix->drc_range != ucontrol->value.integer.value[0];
 	if (change) {
 		mix->drc_range = ucontrol->value.integer.value[0];
-		tumbler_set_drc(mix);
+		if (chip->model == PMAC_TUMBLER)
+			tumbler_set_drc(mix);
+		else
+			snapper_set_drc(mix);
 	}
 	return change;
 }
@@ -330,7 +391,10 @@
 	change = mix->drc_enable != ucontrol->value.integer.value[0];
 	if (change) {
 		mix->drc_enable = !!ucontrol->value.integer.value[0];
-		tumbler_set_drc(mix);
+		if (chip->model == PMAC_TUMBLER)
+			tumbler_set_drc(mix);
+		else
+			snapper_set_drc(mix);
 	}
 	return change;
 }
@@ -409,24 +473,15 @@
 	return change;
 }
 
+/* TAS3001c mono volumes */
 static struct tumbler_mono_vol tumbler_pcm_vol_info = {
-	.index = VOL_IDX_PCM,
+	.index = VOL_IDX_PCM_MONO,
 	.reg = TAS_REG_PCM,
 	.bytes = 3,
 	.max = number_of(mixer_volume_table),
 	.table = mixer_volume_table,
 };
 
-#if 0 // for what?
-static struct tumbler_mono_vol tumbler_altpcm_vol_info = {
-	.index = VOL_IDX_ALTPCM,
-	.reg = TAS_REG_INPUT2,
-	.bytes = 3,
-	.max = number_of(mixer_volume_table),
-	.table = mixer_volume_table,
-};
-#endif
-
 static struct tumbler_mono_vol tumbler_bass_vol_info = {
 	.index = VOL_IDX_BASS,
 	.reg = TAS_REG_BASS,
@@ -443,6 +498,24 @@
 	.table = treble_volume_table,
 };
 
+/* TAS3004 mono volumes */
+static struct tumbler_mono_vol snapper_bass_vol_info = {
+	.index = VOL_IDX_BASS,
+	.reg = TAS_REG_BASS,
+	.bytes = 1,
+	.max = number_of(snapper_bass_volume_table),
+	.table = snapper_bass_volume_table,
+};
+
+static struct tumbler_mono_vol snapper_treble_vol_info = {
+	.index = VOL_IDX_TREBLE,
+	.reg = TAS_REG_TREBLE,
+	.bytes = 1,
+	.max = number_of(snapper_treble_volume_table),
+	.table = snapper_treble_volume_table,
+};
+
+
 #define DEFINE_MONO(xname,type) { \
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
 	.name = xname, \
@@ -452,6 +525,95 @@
 	.private_value = (unsigned long)(&tumbler_##type##_vol_info), \
 }
 
+#define DEFINE_SNAPPER_MONO(xname,type) { \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
+	.name = xname, \
+	.info = tumbler_info_mono, \
+	.get = tumbler_get_mono, \
+	.put = tumbler_put_mono, \
+	.private_value = (unsigned long)(&snapper_##type##_vol_info), \
+}
+
+
+/*
+ * snapper mixer volumes
+ */
+
+static int snapper_set_mix_vol1(pmac_tumbler_t *mix, int idx, int ch, int reg)
+{
+	int i, j, vol;
+	unsigned char block[9];
+
+	vol = mix->mix_vol[idx][ch];
+	if (vol >= number_of(mixer_volume_table)) {
+		vol = number_of(mixer_volume_table) - 1;
+		mix->mix_vol[idx][ch] = vol;
+	}
+
+	for (i = 0; i < 3; i++) {
+		vol = mix->mix_vol[i][ch];
+		vol = mixer_volume_table[vol];
+		for (j = 0; j < 3; j++)
+			block[i * 3 + j] = (vol >> ((2 - j) * 8)) & 0xff;
+	}
+	if (snd_pmac_keywest_write(&mix->i2c, reg, 9, block) < 0) {
+		snd_printk("failed to set mono volume %d\n", reg);  
+		return -EINVAL; 
+	}
+	return 0;
+}
+
+static int snapper_set_mix_vol(pmac_tumbler_t *mix, int idx)
+{
+	if (! mix->i2c.client)
+		return -ENODEV;
+	if (snapper_set_mix_vol1(mix, idx, 0, TAS_REG_LMIX) < 0 ||
+	    snapper_set_mix_vol1(mix, idx, 1, TAS_REG_RMIX) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int snapper_info_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = number_of(mixer_volume_table) - 1;
+	return 0;
+}
+
+static int snapper_get_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	int idx = (int)kcontrol->private_value;
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	pmac_tumbler_t *mix;
+	if (! (mix = chip->mixer_data))
+		return -ENODEV;
+	ucontrol->value.integer.value[0] = mix->mix_vol[idx][0];
+	ucontrol->value.integer.value[1] = mix->mix_vol[idx][1];
+	return 0;
+}
+
+static int snapper_put_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	int idx = (int)kcontrol->private_value;
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	pmac_tumbler_t *mix;
+	int change;
+
+	if (! (mix = chip->mixer_data))
+		return -ENODEV;
+	change = mix->mix_vol[idx][0] != ucontrol->value.integer.value[0] ||
+		mix->mix_vol[idx][1] != ucontrol->value.integer.value[1];
+	if (change) {
+		mix->mix_vol[idx][0] = ucontrol->value.integer.value[0];
+		mix->mix_vol[idx][1] = ucontrol->value.integer.value[1];
+		snapper_set_mix_vol(mix, idx);
+	}
+	return change;
+}
+
+
 /*
  * mute switches
  */
@@ -487,6 +649,16 @@
 	return 0;
 }
 
+#define DEFINE_SNAPPER_MIX(xname,idx,ofs) { \
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
+	.name = xname, \
+	.info = snapper_info_mix, \
+	.get = snapper_get_mix, \
+	.put = snapper_put_mix, \
+	.index = idx,\
+	.private_value = ofs, \
+}
+
 
 /*
  */
@@ -506,7 +678,38 @@
 	DEFINE_MONO("Tone Control - Bass", bass),
 	DEFINE_MONO("Tone Control - Treble", treble),
 	DEFINE_MONO("PCM Playback Volume", pcm),
-	//  DEFINE_MONO("Mixer2 Playback Volume", altpcm),
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	  .name = "DRC Switch",
+	  .info = snd_pmac_boolean_mono_info,
+	  .get = tumbler_get_drc_switch,
+	  .put = tumbler_put_drc_switch
+	},
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	  .name = "DRC Range",
+	  .info = tumbler_info_drc_value,
+	  .get = tumbler_get_drc_value,
+	  .put = tumbler_put_drc_value
+	},
+};
+
+static snd_kcontrol_new_t snapper_mixers[] __initdata = {
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	  .name = "Master Playback Volume",
+	  .info = tumbler_info_master_volume,
+	  .get = tumbler_get_master_volume,
+	  .put = tumbler_put_master_volume
+	},
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	  .name = "Master Playback Switch",
+	  .info = snd_pmac_boolean_stereo_info,
+	  .get = tumbler_get_master_switch,
+	  .put = tumbler_put_master_switch
+	},
+	DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),
+	DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),
+	DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),
+	DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
+	DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "DRC Switch",
 	  .info = snd_pmac_boolean_mono_info,
@@ -675,10 +878,17 @@
 	tumbler_reset_audio(chip);
 	if (mix->i2c.client)
 		tumbler_init_client(&mix->i2c);
-	tumbler_set_mono_volume(mix, &tumbler_pcm_vol_info);
-	tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
-	tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
-	// tumbler_set_mono_volume(mix, &tumbler_altpcm_vol_info);
+	if (chip->model == PMAC_TUMBLER) {
+		tumbler_set_mono_volume(mix, &tumbler_pcm_vol_info);
+		tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
+		tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
+	} else {
+		snapper_set_mix_vol(mix, VOL_IDX_PCM);
+		snapper_set_mix_vol(mix, VOL_IDX_PCM2);
+		snapper_set_mix_vol(mix, VOL_IDX_ADC);
+		tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
+		tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
+	}
 	tumbler_set_drc(mix);
 	tumbler_set_master_volume(mix);
 	if (chip->update_automute)
@@ -741,6 +951,7 @@
 	pmac_tumbler_t *mix;
 	u32 *paddr;
 	struct device_node *tas_node;
+	char *chipname;
 
 #ifdef CONFIG_KMOD
 	request_module("i2c-keywest");
@@ -770,18 +981,32 @@
 		mix->i2c.addr = TAS_I2C_ADDR;
 
 	mix->i2c.init_client = tumbler_init_client;
-	mix->i2c.name = "TAS3001c";
+	if (chip->model == PMAC_TUMBLER) {
+		mix->i2c.name = "TAS3001c";
+		chipname = "Tumbler";
+	} else {
+		mix->i2c.name = "TAS3004";
+		chipname = "Snapper";
+	}
+
 	if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
 		return err;
 
 	/*
 	 * build mixers
 	 */
-	strcpy(chip->card->mixername, "PowerMac Tumbler");
+	sprintf(chip->card->mixername, "PowerMac %s", chipname);
 
-	for (i = 0; i < number_of(tumbler_mixers); i++) {
-		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip))) < 0)
-			return err;
+	if (chip->model == PMAC_TUMBLER) {
+		for (i = 0; i < number_of(tumbler_mixers); i++) {
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip))) < 0)
+				return err;
+		}
+	} else {
+		for (i = 0; i < number_of(snapper_mixers); i++) {
+			if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snapper_mixers[i], chip))) < 0)
+				return err;
+		}
 	}
 	chip->master_sw_ctl = snd_ctl_new1(&tumbler_hp_sw, chip);
 	if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
diff -Nru a/sound/ppc/tumbler_volume.h b/sound/ppc/tumbler_volume.h
--- a/sound/ppc/tumbler_volume.h	Tue Oct  1 17:08:34 2002
+++ b/sound/ppc/tumbler_volume.h	Tue Oct  1 17:08:34 2002
@@ -63,7 +63,7 @@
 	0x00071457, 0x00077fbb,	0x0007f17b,
 };
 
-/* treble table */
+/* treble table for TAS3001c */
 /* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
 static unsigned int treble_volume_table[] = {
 	0x96, 0x95, 0x94,
@@ -93,7 +93,7 @@
 	0x01,
 };
 
-/* bass table */
+/* bass table for TAS3001c */
 /* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
 static unsigned int bass_volume_table[] = {
 	0x86, 0x82, 0x7f,
@@ -186,3 +186,65 @@
 	0x5f4e52, 0x64f403, 0x6aef5d,
 	0x714575, 0x77fbaa, 0x7f17af,
 };
+
+
+/* treble table for TAS3004 */
+/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
+static unsigned int snapper_treble_volume_table[] = {
+	0x96, 0x95, 0x94,
+	0x93, 0x92, 0x91,
+	0x90, 0x8f, 0x8e,
+	0x8d, 0x8c, 0x8b,
+	0x8a, 0x89, 0x88,
+	0x87, 0x86, 0x85,
+	0x84, 0x83, 0x82,
+	0x81, 0x80, 0x7f,
+	0x7e, 0x7d, 0x7c,
+	0x7b, 0x7a, 0x79,
+	0x78, 0x77, 0x76,
+	0x75, 0x74, 0x73,
+	0x72, 0x71, 0x70,
+	0x6f, 0x6d, 0x6c,
+	0x6b, 0x69, 0x68,
+	0x67, 0x65, 0x63,
+	0x62, 0x60, 0x5d,
+	0x5b, 0x59, 0x56,
+	0x53, 0x51, 0x4d,
+	0x4a, 0x47, 0x43,
+	0x3f, 0x3b, 0x36,
+	0x31, 0x2c, 0x26,
+	0x20, 0x1a, 0x13,
+	0x08, 0x04, 0x01,
+	0x01,
+};
+
+/* bass table for TAS3004 */
+/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
+static unsigned int snapper_bass_volume_table[] = {
+	0x96, 0x95, 0x94,
+	0x93, 0x92, 0x91,
+	0x90, 0x8f, 0x8e,
+	0x8d, 0x8c, 0x8b,
+	0x8a, 0x89, 0x88,
+	0x87, 0x86, 0x85,
+	0x84, 0x83, 0x82,
+	0x81, 0x80, 0x7f,
+	0x7e, 0x7d, 0x7c,
+	0x7b, 0x7a, 0x79,
+	0x78, 0x77, 0x76,
+	0x75, 0x74, 0x73,
+	0x72, 0x71, 0x6f,
+	0x6e, 0x6d, 0x6b,
+	0x6a, 0x69, 0x67,
+	0x66, 0x65, 0x63,
+	0x62, 0x61, 0x5f,
+	0x5d, 0x5b, 0x58,
+	0x55, 0x52, 0x4f,
+	0x4c, 0x49, 0x46,
+	0x43, 0x3f, 0x3b,
+	0x37, 0x33, 0x2e,
+	0x29, 0x24, 0x1e,
+	0x18, 0x11, 0x0a,
+	0x01,
+};
+
diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c	Tue Oct  1 17:08:34 2002
+++ b/sound/usb/usbaudio.c	Tue Oct  1 17:08:34 2002
@@ -53,6 +53,8 @@
 static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
+static int snd_vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
+static int snd_pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
 
 MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_index, "Index value for the USB audio adapter.");
@@ -63,6 +65,27 @@
 MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_enable, "Enable USB audio adapter.");
 MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+MODULE_PARM(snd_vid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_vid, "Vendor ID for the USB audio device.");
+MODULE_PARM_SYNTAX(snd_vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
+MODULE_PARM(snd_pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_pid, "Product ID for the USB audio device.");
+MODULE_PARM_SYNTAX(snd_pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
+
+
+/*
+ * for using ASYNC unlink mode, define the following.
+ * this will make the driver quicker response for request to STOP-trigger,
+ * but it may cause oops by some unknown reason (bug of usb driver?),
+ * so turning off might be sure.
+ */
+/* #define SND_USE_ASYNC_UNLINK */
+
+#ifdef SND_USB_ASYNC_UNLINK
+#define UNLINK_FLAGS	USB_ASYNC_UNLINK
+#else
+#define UNLINK_FLAGS	0
+#endif
 
 
 /*
@@ -528,6 +551,10 @@
 
 	subs->running = 0;
 
+#ifndef SND_USB_ASYNC_UNLINK
+	if (in_interrupt())
+		return 0;
+#endif
 	alive = 0;
 	for (i = 0; i < subs->nurbs; i++) {
 		if (test_bit(i, &subs->active_mask)) {
@@ -545,7 +572,11 @@
 			}
 		}
 	}
+#ifdef SND_USB_ASYNC_UNLINK
 	return alive;
+#else
+	return 0;
+#endif
 }
 
 
@@ -803,7 +834,7 @@
 		}
 		u->urb->dev = subs->dev;
 		u->urb->pipe = subs->datapipe;
-		u->urb->transfer_flags = USB_ISO_ASAP | USB_ASYNC_UNLINK;
+		u->urb->transfer_flags = USB_ISO_ASAP | UNLINK_FLAGS;
 		u->urb->number_of_packets = u->packets;
 		u->urb->context = u;
 		u->urb->complete = snd_complete_urb;
@@ -825,7 +856,7 @@
 			u->urb->transfer_buffer_length = NRPACKS * 3;
 			u->urb->dev = subs->dev;
 			u->urb->pipe = subs->syncpipe;
-			u->urb->transfer_flags = USB_ISO_ASAP | USB_ASYNC_UNLINK;
+			u->urb->transfer_flags = USB_ISO_ASAP | UNLINK_FLAGS;
 			u->urb->number_of_packets = u->packets;
 			u->urb->context = u;
 			u->urb->complete = snd_complete_sync_urb;
@@ -2043,7 +2074,9 @@
 		 * now look for an empty slot and create a new card instance
 		 */
 		for (i = 0; i < SNDRV_CARDS; i++)
-			if (snd_enable[i] && ! usb_chip[i]) {
+			if (snd_enable[i] && ! usb_chip[i] &&
+			    (snd_vid[i] == -1 || snd_vid[i] == dev->descriptor.idVendor) &&
+			    (snd_pid[i] == -1 || snd_pid[i] == dev->descriptor.idProduct)) {
 				card = snd_card_new(snd_index[i], snd_id[i], THIS_MODULE, 0);
 				if (card == NULL) {
 					snd_printk(KERN_ERR "cannot create a card instance %d\n", i);
diff -Nru a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
--- a/sound/usb/usbmixer.c	Tue Oct  1 17:08:34 2002
+++ b/sound/usb/usbmixer.c	Tue Oct  1 17:08:34 2002
@@ -73,6 +73,7 @@
 	int channels;
 	int val_type;
 	int min, max;
+	unsigned int initialized: 1;
 };
 
 
@@ -498,6 +499,23 @@
 		uinfo->value.integer.min = 0;
 		uinfo->value.integer.max = 1;
 	} else {
+		if (! cval->initialized) {
+			int minchn = 0;
+			if (cval->cmask) {
+				int i;
+				for (i = 0; i < MAX_CHANNELS; i++)
+					if (cval->cmask & (1 << i)) {
+						minchn = i + 1;
+						break;
+					}
+			}
+			if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 ||
+			    get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0) {
+				snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, cval->control);
+				return -EINVAL;
+			}
+			cval->initialized = 1;
+		}
 		uinfo->value.integer.min = 0;
 		uinfo->value.integer.max = cval->max - cval->min;
 	}
@@ -515,8 +533,10 @@
 		for (c = 0; c < MAX_CHANNELS; c++) {
 			if (cval->cmask & (1 << c)) {
 				err = get_cur_mix_value(cval, c + 1, &val);
-				if (err < 0)
+				if (err < 0) {
+					printk("cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
 					return err;
+				}
 				val = get_relative_value(cval, val);
 				ucontrol->value.integer.value[cnt] = val;
 				cnt++;
@@ -525,8 +545,10 @@
 	} else {
 		/* master channel */
 		err = get_cur_mix_value(cval, 0, &val);
-		if (err < 0)
+		if (err < 0) {
+			printk("cannot get current value for control %d master ch: err = %d\n", cval->control, err);
 			return err;
+		}
 		val = get_relative_value(cval, val);
 		ucontrol->value.integer.value[0] = val;
 	}
@@ -592,6 +614,7 @@
 	int nameid = desc[desc[0] - 1];
 	snd_kcontrol_t *kctl;
 	usb_mixer_elem_info_t *cval;
+	int minchn = 0;
 
 	if (control == USB_FEATURE_GEQ) {
 		/* FIXME: not supported yet */
@@ -614,22 +637,25 @@
 	else {
 		int i, c = 0;
 		for (i = 0; i < 16; i++)
-			if (ctl_mask & (1 << i))
+			if (ctl_mask & (1 << i)) {
+				if (! minchn)
+					minchn = i + 1;
 				c++;
+			}
 		cval->channels = c;
 	}
 
 	/* get min/max values */
 	if (cval->val_type == USB_MIXER_BOOLEAN ||
-	    cval->val_type == USB_MIXER_INV_BOOLEAN)
+	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
 		cval->max = 1;
-	else {
-		if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | (ctl_mask ? 1 : 0), &cval->max) < 0 ||
-		    get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | (ctl_mask ? 1 : 0), &cval->min) < 0) {
+		cval->initialized = 1;
+	} else {
+		if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 ||
+		    get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0)
 			snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, control);
-			snd_magic_kfree(cval);
-			return;
-		}
+		else
+			cval->initialized = 1;
 	}
 
 	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
@@ -759,6 +785,7 @@
 	int i, len;
 	snd_kcontrol_t *kctl;
 	usb_audio_term_t iterm;
+	int minchn = 0;
 
 	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
 	if (! cval)
@@ -776,16 +803,17 @@
 		if (check_matrix_bitmap(desc + 9 + num_ins, in_ch, i, num_outs)) {
 			cval->cmask |= (1 << i);
 			cval->channels++;
+			if (! minchn)
+				minchn = i + 1;
 		}
 	}
 
 	/* get min/max values */
-	if (get_ctl_value(cval, GET_MAX, ((in_ch+1) << 8) | 1, &cval->max) < 0 ||
-	    get_ctl_value(cval, GET_MIN, ((in_ch+1) << 8) | 1, &cval->min) < 0) {
+	if (get_ctl_value(cval, GET_MAX, ((in_ch+1) << 8) | minchn, &cval->max) < 0 ||
+	    get_ctl_value(cval, GET_MIN, ((in_ch+1) << 8) | minchn, &cval->min) < 0)
 		snd_printk(KERN_ERR "cannot get min/max values for mixer\n");
-		snd_magic_kfree(cval);
-		return;
-	}
+	else
+		cval->initialized = 1;
 
 	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
 	if (! kctl) {
@@ -994,11 +1022,10 @@
 
 		/* get min/max values */
 		if (get_ctl_value(cval, GET_MAX, cval->control, &cval->max) < 0 ||
-		    get_ctl_value(cval, GET_MIN, cval->control, &cval->min) < 0) {
+		    get_ctl_value(cval, GET_MIN, cval->control, &cval->min) < 0)
 			snd_printk(KERN_ERR "cannot get min/max values for proc/ext unit\n");
-			snd_magic_kfree(cval);
-			continue;
-		}
+		else
+			cval->initialized = 1;
 
 		kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
 		if (! kctl) {
@@ -1158,6 +1185,7 @@
 	cval->channels = 1;
 	cval->min = 1;
 	cval->max = num_ins;
+	cval->initialized = 1;
 
 	namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL);
 	if (! namelist) {

===================================================================


This BitKeeper patch contains the following changesets:
1.651
## Wrapped with gzip_uu ##


begin 664 bkpatch23038
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
/.]5Z<?/_`8.]>,K<<P$`
`
end
