diff -Naur linux-2.6.22.orig/include/.pc/.version linux-2.6.22/include/.pc/.version
--- linux-2.6.22.orig/include/.pc/.version	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/.version	2007-08-31 20:42:35.000000000 +0200
@@ -0,0 +1 @@
+2
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/ak4xxx-adda.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/ak4xxx-adda.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/ak4xxx-adda.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/ak4xxx-adda.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,95 @@
+#ifndef __SOUND_AK4XXX_ADDA_H
+#define __SOUND_AK4XXX_ADDA_H
+
+/*
+ *   ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4381
+ *   AD and DA converters
+ *
+ *	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
+ *
+ */      
+
+#ifndef AK4XXX_MAX_CHIPS
+#define AK4XXX_MAX_CHIPS	4
+#endif
+
+struct snd_akm4xxx;
+
+struct snd_ak4xxx_ops {
+	void (*lock)(struct snd_akm4xxx *ak, int chip);
+	void (*unlock)(struct snd_akm4xxx *ak, int chip);
+	void (*write)(struct snd_akm4xxx *ak, int chip, unsigned char reg,
+		      unsigned char val);
+	void (*set_rate_val)(struct snd_akm4xxx *ak, unsigned int rate);
+};
+
+#define AK4XXX_IMAGE_SIZE	(AK4XXX_MAX_CHIPS * 16)	/* 64 bytes */
+
+/* DAC label and channels */
+struct snd_akm4xxx_dac_channel {
+	char *name;		/* mixer volume name */
+	unsigned int num_channels;
+};
+
+/* ADC labels and channels */
+struct snd_akm4xxx_adc_channel {
+	char *name;		/* capture gain volume label */
+	char *switch_name;	/* capture switch */
+	unsigned int num_channels;
+	char *selector_name;	/* capture source select label */
+	const char **input_names; /* capture source names (NULL terminated) */
+};
+
+struct snd_akm4xxx {
+	struct snd_card *card;
+	unsigned int num_adcs;			/* AK4524 or AK4528 ADCs */
+	unsigned int num_dacs;			/* AK4524 or AK4528 DACs */
+	unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */
+	unsigned char volumes[AK4XXX_IMAGE_SIZE]; /* saved volume values */
+	unsigned long private_value[AK4XXX_MAX_CHIPS];	/* helper for driver */
+	void *private_data[AK4XXX_MAX_CHIPS];		/* helper for driver */
+	/* template should fill the following fields */
+	unsigned int idx_offset;		/* control index offset */
+	enum {
+		SND_AK4524, SND_AK4528, SND_AK4529,
+		SND_AK4355, SND_AK4358, SND_AK4381,
+		SND_AK5365
+	} type;
+
+	/* (array) information of combined codecs */
+	const struct snd_akm4xxx_dac_channel *dac_info;
+	const struct snd_akm4xxx_adc_channel *adc_info;
+
+	struct snd_ak4xxx_ops ops;
+};
+
+void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
+		       unsigned char val);
+void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state);
+void snd_akm4xxx_init(struct snd_akm4xxx *ak);
+int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak);
+
+#define snd_akm4xxx_get(ak,chip,reg) \
+	(ak)->images[(chip) * 16 + (reg)]
+#define snd_akm4xxx_set(ak,chip,reg,val) \
+	((ak)->images[(chip) * 16 + (reg)] = (val))
+#define snd_akm4xxx_get_vol(ak,chip,reg) \
+	(ak)->volumes[(chip) * 16 + (reg)]
+#define snd_akm4xxx_set_vol(ak,chip,reg,val) \
+	((ak)->volumes[(chip) * 16 + (reg)] = (val))
+
+#endif /* __SOUND_AK4XXX_ADDA_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/asound.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/asound.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/asound.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/asound.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,918 @@
+/*
+ *  Advanced Linux Sound Architecture - ALSA - Driver
+ *  Copyright (c) 1994-2003 by Jaroslav Kysela <perex@suse.cz>,
+ *                             Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   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
+ *
+ */
+
+#ifndef __SOUND_ASOUND_H
+#define __SOUND_ASOUND_H
+
+#ifdef __KERNEL__
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <asm/byteorder.h>
+
+#ifdef  __LITTLE_ENDIAN
+#define SNDRV_LITTLE_ENDIAN
+#else
+#ifdef __BIG_ENDIAN
+#define SNDRV_BIG_ENDIAN
+#else
+#error "Unsupported endian..."
+#endif
+#endif
+
+#endif /* __KERNEL__ **/
+
+/*
+ *  protocol version
+ */
+
+#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor))
+#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff)
+#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff)
+#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff)
+#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) \
+	(SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || \
+	 (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && \
+	   SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion)))
+
+/****************************************************************************
+ *                                                                          *
+ *        Digital audio interface					    *
+ *                                                                          *
+ ****************************************************************************/
+
+struct snd_aes_iec958 {
+	unsigned char status[24];	/* AES/IEC958 channel status bits */
+	unsigned char subcode[147];	/* AES/IEC958 subcode bits */
+	unsigned char pad;		/* nothing */
+	unsigned char dig_subframe[4];	/* AES/IEC958 subframe bits */
+};
+
+/****************************************************************************
+ *                                                                          *
+ *      Section for driver hardware dependent interface - /dev/snd/hw?      *
+ *                                                                          *
+ ****************************************************************************/
+
+#define SNDRV_HWDEP_VERSION		SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
+enum {
+	SNDRV_HWDEP_IFACE_OPL2 = 0,
+	SNDRV_HWDEP_IFACE_OPL3,
+	SNDRV_HWDEP_IFACE_OPL4,
+	SNDRV_HWDEP_IFACE_SB16CSP,	/* Creative Signal Processor */
+	SNDRV_HWDEP_IFACE_EMU10K1,	/* FX8010 processor in EMU10K1 chip */
+	SNDRV_HWDEP_IFACE_YSS225,	/* Yamaha FX processor */
+	SNDRV_HWDEP_IFACE_ICS2115,	/* Wavetable synth */
+	SNDRV_HWDEP_IFACE_SSCAPE,	/* Ensoniq SoundScape ISA card (MC68EC000) */
+	SNDRV_HWDEP_IFACE_VX,		/* Digigram VX cards */
+	SNDRV_HWDEP_IFACE_MIXART,	/* Digigram miXart cards */
+	SNDRV_HWDEP_IFACE_USX2Y,	/* Tascam US122, US224 & US428 usb */
+	SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, /* EmuX wavetable */	
+	SNDRV_HWDEP_IFACE_BLUETOOTH,	/* Bluetooth audio */
+	SNDRV_HWDEP_IFACE_USX2Y_PCM,	/* Tascam US122, US224 & US428 rawusb pcm */
+	SNDRV_HWDEP_IFACE_PCXHR,	/* Digigram PCXHR */
+	SNDRV_HWDEP_IFACE_SB_RC,	/* SB Extigy/Audigy2NX remote control */
+
+	/* Don't forget to change the following: */
+	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC
+};
+
+struct snd_hwdep_info {
+	unsigned int device;		/* WR: device number */
+	int card;			/* R: card number */
+	unsigned char id[64];		/* ID (user selectable) */
+	unsigned char name[80];		/* hwdep name */
+	int iface;			/* hwdep interface */
+	unsigned char reserved[64];	/* reserved for future */
+};
+
+/* generic DSP loader */
+struct snd_hwdep_dsp_status {
+	unsigned int version;		/* R: driver-specific version */
+	unsigned char id[32];		/* R: driver-specific ID string */
+	unsigned int num_dsps;		/* R: number of DSP images to transfer */
+	unsigned int dsp_loaded;	/* R: bit flags indicating the loaded DSPs */
+	unsigned int chip_ready;	/* R: 1 = initialization finished */
+	unsigned char reserved[16];	/* reserved for future use */
+};
+
+struct snd_hwdep_dsp_image {
+	unsigned int index;		/* W: DSP index */
+	unsigned char name[64];		/* W: ID (e.g. file name) */
+	unsigned char __user *image;	/* W: binary image */
+	size_t length;			/* W: size of image in bytes */
+	unsigned long driver_data;	/* W: driver-specific data */
+};
+
+enum {
+	SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int),
+	SNDRV_HWDEP_IOCTL_INFO = _IOR ('H', 0x01, struct snd_hwdep_info),
+	SNDRV_HWDEP_IOCTL_DSP_STATUS = _IOR('H', 0x02, struct snd_hwdep_dsp_status),
+	SNDRV_HWDEP_IOCTL_DSP_LOAD   = _IOW('H', 0x03, struct snd_hwdep_dsp_image)
+};
+
+/*****************************************************************************
+ *                                                                           *
+ *             Digital Audio (PCM) interface - /dev/snd/pcm??                *
+ *                                                                           *
+ *****************************************************************************/
+
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 8)
+
+typedef unsigned long snd_pcm_uframes_t;
+typedef signed long snd_pcm_sframes_t;
+
+enum {
+	SNDRV_PCM_CLASS_GENERIC = 0,	/* standard mono or stereo device */
+	SNDRV_PCM_CLASS_MULTI,		/* multichannel device */
+	SNDRV_PCM_CLASS_MODEM,		/* software modem class */
+	SNDRV_PCM_CLASS_DIGITIZER,	/* digitizer class */
+	/* Don't forget to change the following: */
+	SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER,
+};
+
+enum {
+	SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, /* mono or stereo subdevices are mixed together */
+	SNDRV_PCM_SUBCLASS_MULTI_MIX,	/* multichannel subdevices are mixed together */
+	/* Don't forget to change the following: */
+	SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX,
+};
+
+enum {
+	SNDRV_PCM_STREAM_PLAYBACK = 0,
+	SNDRV_PCM_STREAM_CAPTURE,
+	SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
+};
+
+typedef int __bitwise snd_pcm_access_t;
+#define	SNDRV_PCM_ACCESS_MMAP_INTERLEAVED	((__force snd_pcm_access_t) 0) /* interleaved mmap */
+#define	SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED	((__force snd_pcm_access_t) 1) /* noninterleaved mmap */
+#define	SNDRV_PCM_ACCESS_MMAP_COMPLEX		((__force snd_pcm_access_t) 2) /* complex mmap */
+#define	SNDRV_PCM_ACCESS_RW_INTERLEAVED		((__force snd_pcm_access_t) 3) /* readi/writei */
+#define	SNDRV_PCM_ACCESS_RW_NONINTERLEAVED	((__force snd_pcm_access_t) 4) /* readn/writen */
+#define	SNDRV_PCM_ACCESS_LAST		SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
+
+typedef int __bitwise snd_pcm_format_t;
+#define	SNDRV_PCM_FORMAT_S8	((__force snd_pcm_format_t) 0)
+#define	SNDRV_PCM_FORMAT_U8	((__force snd_pcm_format_t) 1)
+#define	SNDRV_PCM_FORMAT_S16_LE	((__force snd_pcm_format_t) 2)
+#define	SNDRV_PCM_FORMAT_S16_BE	((__force snd_pcm_format_t) 3)
+#define	SNDRV_PCM_FORMAT_U16_LE	((__force snd_pcm_format_t) 4)
+#define	SNDRV_PCM_FORMAT_U16_BE	((__force snd_pcm_format_t) 5)
+#define	SNDRV_PCM_FORMAT_S24_LE	((__force snd_pcm_format_t) 6) /* low three bytes */
+#define	SNDRV_PCM_FORMAT_S24_BE	((__force snd_pcm_format_t) 7) /* low three bytes */
+#define	SNDRV_PCM_FORMAT_U24_LE	((__force snd_pcm_format_t) 8) /* low three bytes */
+#define	SNDRV_PCM_FORMAT_U24_BE	((__force snd_pcm_format_t) 9) /* low three bytes */
+#define	SNDRV_PCM_FORMAT_S32_LE	((__force snd_pcm_format_t) 10)
+#define	SNDRV_PCM_FORMAT_S32_BE	((__force snd_pcm_format_t) 11)
+#define	SNDRV_PCM_FORMAT_U32_LE	((__force snd_pcm_format_t) 12)
+#define	SNDRV_PCM_FORMAT_U32_BE	((__force snd_pcm_format_t) 13)
+#define	SNDRV_PCM_FORMAT_FLOAT_LE	((__force snd_pcm_format_t) 14) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define	SNDRV_PCM_FORMAT_FLOAT_BE	((__force snd_pcm_format_t) 15) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define	SNDRV_PCM_FORMAT_FLOAT64_LE	((__force snd_pcm_format_t) 16) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define	SNDRV_PCM_FORMAT_FLOAT64_BE	((__force snd_pcm_format_t) 17) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define	SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) /* IEC-958 subframe, Little Endian */
+#define	SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) /* IEC-958 subframe, Big Endian */
+#define	SNDRV_PCM_FORMAT_MU_LAW		((__force snd_pcm_format_t) 20)
+#define	SNDRV_PCM_FORMAT_A_LAW		((__force snd_pcm_format_t) 21)
+#define	SNDRV_PCM_FORMAT_IMA_ADPCM	((__force snd_pcm_format_t) 22)
+#define	SNDRV_PCM_FORMAT_MPEG		((__force snd_pcm_format_t) 23)
+#define	SNDRV_PCM_FORMAT_GSM		((__force snd_pcm_format_t) 24)
+#define	SNDRV_PCM_FORMAT_SPECIAL	((__force snd_pcm_format_t) 31)
+#define	SNDRV_PCM_FORMAT_S24_3LE	((__force snd_pcm_format_t) 32)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_S24_3BE	((__force snd_pcm_format_t) 33)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_U24_3LE	((__force snd_pcm_format_t) 34)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_U24_3BE	((__force snd_pcm_format_t) 35)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_S20_3LE	((__force snd_pcm_format_t) 36)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_S20_3BE	((__force snd_pcm_format_t) 37)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_U20_3LE	((__force snd_pcm_format_t) 38)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_U20_3BE	((__force snd_pcm_format_t) 39)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_S18_3LE	((__force snd_pcm_format_t) 40)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_S18_3BE	((__force snd_pcm_format_t) 41)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_U18_3LE	((__force snd_pcm_format_t) 42)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_U18_3BE	((__force snd_pcm_format_t) 43)	/* in three bytes */
+#define	SNDRV_PCM_FORMAT_LAST		SNDRV_PCM_FORMAT_U18_3BE
+
+#ifdef SNDRV_LITTLE_ENDIAN
+#define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_LE
+#define	SNDRV_PCM_FORMAT_U16		SNDRV_PCM_FORMAT_U16_LE
+#define	SNDRV_PCM_FORMAT_S24		SNDRV_PCM_FORMAT_S24_LE
+#define	SNDRV_PCM_FORMAT_U24		SNDRV_PCM_FORMAT_U24_LE
+#define	SNDRV_PCM_FORMAT_S32		SNDRV_PCM_FORMAT_S32_LE
+#define	SNDRV_PCM_FORMAT_U32		SNDRV_PCM_FORMAT_U32_LE
+#define	SNDRV_PCM_FORMAT_FLOAT		SNDRV_PCM_FORMAT_FLOAT_LE
+#define	SNDRV_PCM_FORMAT_FLOAT64	SNDRV_PCM_FORMAT_FLOAT64_LE
+#define	SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
+#endif
+#ifdef SNDRV_BIG_ENDIAN
+#define	SNDRV_PCM_FORMAT_S16		SNDRV_PCM_FORMAT_S16_BE
+#define	SNDRV_PCM_FORMAT_U16		SNDRV_PCM_FORMAT_U16_BE
+#define	SNDRV_PCM_FORMAT_S24		SNDRV_PCM_FORMAT_S24_BE
+#define	SNDRV_PCM_FORMAT_U24		SNDRV_PCM_FORMAT_U24_BE
+#define	SNDRV_PCM_FORMAT_S32		SNDRV_PCM_FORMAT_S32_BE
+#define	SNDRV_PCM_FORMAT_U32		SNDRV_PCM_FORMAT_U32_BE
+#define	SNDRV_PCM_FORMAT_FLOAT		SNDRV_PCM_FORMAT_FLOAT_BE
+#define	SNDRV_PCM_FORMAT_FLOAT64	SNDRV_PCM_FORMAT_FLOAT64_BE
+#define	SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
+#endif
+
+typedef int __bitwise snd_pcm_subformat_t;
+#define	SNDRV_PCM_SUBFORMAT_STD		((__force snd_pcm_subformat_t) 0)
+#define	SNDRV_PCM_SUBFORMAT_LAST	SNDRV_PCM_SUBFORMAT_STD
+
+#define SNDRV_PCM_INFO_MMAP		0x00000001	/* hardware supports mmap */
+#define SNDRV_PCM_INFO_MMAP_VALID	0x00000002	/* period data are valid during transfer */
+#define SNDRV_PCM_INFO_DOUBLE		0x00000004	/* Double buffering needed for PCM start/stop */
+#define SNDRV_PCM_INFO_BATCH		0x00000010	/* double buffering */
+#define SNDRV_PCM_INFO_INTERLEAVED	0x00000100	/* channels are interleaved */
+#define SNDRV_PCM_INFO_NONINTERLEAVED	0x00000200	/* channels are not interleaved */
+#define SNDRV_PCM_INFO_COMPLEX		0x00000400	/* complex frame organization (mmap only) */
+#define SNDRV_PCM_INFO_BLOCK_TRANSFER	0x00010000	/* hardware transfer block of samples */
+#define SNDRV_PCM_INFO_OVERRANGE	0x00020000	/* hardware supports ADC (capture) overrange detection */
+#define SNDRV_PCM_INFO_RESUME		0x00040000	/* hardware supports stream resume after suspend */
+#define SNDRV_PCM_INFO_PAUSE		0x00080000	/* pause ioctl is supported */
+#define SNDRV_PCM_INFO_HALF_DUPLEX	0x00100000	/* only half duplex */
+#define SNDRV_PCM_INFO_JOINT_DUPLEX	0x00200000	/* playback and capture stream are somewhat correlated */
+#define SNDRV_PCM_INFO_SYNC_START	0x00400000	/* pcm support some kind of sync go */
+
+typedef int __bitwise snd_pcm_state_t;
+#define	SNDRV_PCM_STATE_OPEN		((__force snd_pcm_state_t) 0) /* stream is open */
+#define	SNDRV_PCM_STATE_SETUP		((__force snd_pcm_state_t) 1) /* stream has a setup */
+#define	SNDRV_PCM_STATE_PREPARED	((__force snd_pcm_state_t) 2) /* stream is ready to start */
+#define	SNDRV_PCM_STATE_RUNNING		((__force snd_pcm_state_t) 3) /* stream is running */
+#define	SNDRV_PCM_STATE_XRUN		((__force snd_pcm_state_t) 4) /* stream reached an xrun */
+#define	SNDRV_PCM_STATE_DRAINING	((__force snd_pcm_state_t) 5) /* stream is draining */
+#define	SNDRV_PCM_STATE_PAUSED		((__force snd_pcm_state_t) 6) /* stream is paused */
+#define	SNDRV_PCM_STATE_SUSPENDED	((__force snd_pcm_state_t) 7) /* hardware is suspended */
+#define	SNDRV_PCM_STATE_DISCONNECTED	((__force snd_pcm_state_t) 8) /* hardware is disconnected */
+#define	SNDRV_PCM_STATE_LAST		SNDRV_PCM_STATE_DISCONNECTED
+
+enum {
+	SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
+	SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000,
+	SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000,
+};
+
+union snd_pcm_sync_id {
+	unsigned char id[16];
+	unsigned short id16[8];
+	unsigned int id32[4];
+};
+
+struct snd_pcm_info {
+	unsigned int device;		/* RO/WR (control): device number */
+	unsigned int subdevice;		/* RO/WR (control): subdevice number */
+	int stream;			/* RO/WR (control): stream direction */
+	int card;			/* R: card number */
+	unsigned char id[64];		/* ID (user selectable) */
+	unsigned char name[80];		/* name of this device */
+	unsigned char subname[32];	/* subdevice name */
+	int dev_class;			/* SNDRV_PCM_CLASS_* */
+	int dev_subclass;		/* SNDRV_PCM_SUBCLASS_* */
+	unsigned int subdevices_count;
+	unsigned int subdevices_avail;
+	union snd_pcm_sync_id sync;	/* hardware synchronization ID */
+	unsigned char reserved[64];	/* reserved for future... */
+};
+
+typedef int __bitwise snd_pcm_hw_param_t;
+#define	SNDRV_PCM_HW_PARAM_ACCESS	((__force snd_pcm_hw_param_t) 0) /* Access type */
+#define	SNDRV_PCM_HW_PARAM_FORMAT	((__force snd_pcm_hw_param_t) 1) /* Format */
+#define	SNDRV_PCM_HW_PARAM_SUBFORMAT	((__force snd_pcm_hw_param_t) 2) /* Subformat */
+#define	SNDRV_PCM_HW_PARAM_FIRST_MASK	SNDRV_PCM_HW_PARAM_ACCESS
+#define	SNDRV_PCM_HW_PARAM_LAST_MASK	SNDRV_PCM_HW_PARAM_SUBFORMAT
+
+#define	SNDRV_PCM_HW_PARAM_SAMPLE_BITS	((__force snd_pcm_hw_param_t) 8) /* Bits per sample */
+#define	SNDRV_PCM_HW_PARAM_FRAME_BITS	((__force snd_pcm_hw_param_t) 9) /* Bits per frame */
+#define	SNDRV_PCM_HW_PARAM_CHANNELS	((__force snd_pcm_hw_param_t) 10) /* Channels */
+#define	SNDRV_PCM_HW_PARAM_RATE		((__force snd_pcm_hw_param_t) 11) /* Approx rate */
+#define	SNDRV_PCM_HW_PARAM_PERIOD_TIME	((__force snd_pcm_hw_param_t) 12) /* Approx distance between interrupts in us */
+#define	SNDRV_PCM_HW_PARAM_PERIOD_SIZE	((__force snd_pcm_hw_param_t) 13) /* Approx frames between interrupts */
+#define	SNDRV_PCM_HW_PARAM_PERIOD_BYTES	((__force snd_pcm_hw_param_t) 14) /* Approx bytes between interrupts */
+#define	SNDRV_PCM_HW_PARAM_PERIODS	((__force snd_pcm_hw_param_t) 15) /* Approx interrupts per buffer */
+#define	SNDRV_PCM_HW_PARAM_BUFFER_TIME	((__force snd_pcm_hw_param_t) 16) /* Approx duration of buffer in us */
+#define	SNDRV_PCM_HW_PARAM_BUFFER_SIZE	((__force snd_pcm_hw_param_t) 17) /* Size of buffer in frames */
+#define	SNDRV_PCM_HW_PARAM_BUFFER_BYTES	((__force snd_pcm_hw_param_t) 18) /* Size of buffer in bytes */
+#define	SNDRV_PCM_HW_PARAM_TICK_TIME	((__force snd_pcm_hw_param_t) 19) /* Approx tick duration in us */
+#define	SNDRV_PCM_HW_PARAM_FIRST_INTERVAL	SNDRV_PCM_HW_PARAM_SAMPLE_BITS
+#define	SNDRV_PCM_HW_PARAM_LAST_INTERVAL	SNDRV_PCM_HW_PARAM_TICK_TIME
+
+#define SNDRV_PCM_HW_PARAMS_NORESAMPLE		(1<<0)	/* avoid rate resampling */
+
+struct snd_interval {
+	unsigned int min, max;
+	unsigned int openmin:1,
+		     openmax:1,
+		     integer:1,
+		     empty:1;
+};
+
+#define SNDRV_MASK_MAX	256
+
+struct snd_mask {
+	u_int32_t bits[(SNDRV_MASK_MAX+31)/32];
+};
+
+struct snd_pcm_hw_params {
+	unsigned int flags;
+	struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - 
+			       SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+	struct snd_mask mres[5];	/* reserved masks */
+	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
+				        SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+	struct snd_interval ires[9];	/* reserved intervals */
+	unsigned int rmask;		/* W: requested masks */
+	unsigned int cmask;		/* R: changed masks */
+	unsigned int info;		/* R: Info flags for returned setup */
+	unsigned int msbits;		/* R: used most significant bits */
+	unsigned int rate_num;		/* R: rate numerator */
+	unsigned int rate_den;		/* R: rate denominator */
+	snd_pcm_uframes_t fifo_size;	/* R: chip FIFO size in frames */
+	unsigned char reserved[64];	/* reserved for future */
+};
+
+enum {
+	SNDRV_PCM_TSTAMP_NONE = 0,
+	SNDRV_PCM_TSTAMP_MMAP,
+	SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_MMAP,
+};
+
+struct snd_pcm_sw_params {
+	int tstamp_mode;			/* timestamp mode */
+	unsigned int period_step;
+	unsigned int sleep_min;			/* min ticks to sleep */
+	snd_pcm_uframes_t avail_min;		/* min avail frames for wakeup */
+	snd_pcm_uframes_t xfer_align;		/* xfer size need to be a multiple */
+	snd_pcm_uframes_t start_threshold;	/* min hw_avail frames for automatic start */
+	snd_pcm_uframes_t stop_threshold;	/* min avail frames for automatic stop */
+	snd_pcm_uframes_t silence_threshold;	/* min distance from noise for silence filling */
+	snd_pcm_uframes_t silence_size;		/* silence block size */
+	snd_pcm_uframes_t boundary;		/* pointers wrap point */
+	unsigned char reserved[64];		/* reserved for future */
+};
+
+struct snd_pcm_channel_info {
+	unsigned int channel;
+	off_t offset;			/* mmap offset */
+	unsigned int first;		/* offset to first sample in bits */
+	unsigned int step;		/* samples distance in bits */
+};
+
+struct snd_pcm_status {
+	snd_pcm_state_t state;		/* stream state */
+	struct timespec trigger_tstamp;	/* time when stream was started/stopped/paused */
+	struct timespec tstamp;		/* reference timestamp */
+	snd_pcm_uframes_t appl_ptr;	/* appl ptr */
+	snd_pcm_uframes_t hw_ptr;	/* hw ptr */
+	snd_pcm_sframes_t delay;	/* current delay in frames */
+	snd_pcm_uframes_t avail;	/* number of frames available */
+	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
+	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
+	snd_pcm_state_t suspended_state; /* suspended stream state */
+	unsigned char reserved[60];	/* must be filled with zero */
+};
+
+struct snd_pcm_mmap_status {
+	snd_pcm_state_t state;		/* RO: state - SNDRV_PCM_STATE_XXXX */
+	int pad1;			/* Needed for 64 bit alignment */
+	snd_pcm_uframes_t hw_ptr;	/* RO: hw ptr (0...boundary-1) */
+	struct timespec tstamp;		/* Timestamp */
+	snd_pcm_state_t suspended_state; /* RO: suspended stream state */
+};
+
+struct snd_pcm_mmap_control {
+	snd_pcm_uframes_t appl_ptr;	/* RW: appl ptr (0...boundary-1) */
+	snd_pcm_uframes_t avail_min;	/* RW: min available frames for wakeup */
+};
+
+#define SNDRV_PCM_SYNC_PTR_HWSYNC	(1<<0)	/* execute hwsync */
+#define SNDRV_PCM_SYNC_PTR_APPL		(1<<1)	/* get appl_ptr from driver (r/w op) */
+#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN	(1<<2)	/* get avail_min from driver */
+
+struct snd_pcm_sync_ptr {
+	unsigned int flags;
+	union {
+		struct snd_pcm_mmap_status status;
+		unsigned char reserved[64];
+	} s;
+	union {
+		struct snd_pcm_mmap_control control;
+		unsigned char reserved[64];
+	} c;
+};
+
+struct snd_xferi {
+	snd_pcm_sframes_t result;
+	void __user *buf;
+	snd_pcm_uframes_t frames;
+};
+
+struct snd_xfern {
+	snd_pcm_sframes_t result;
+	void __user * __user *bufs;
+	snd_pcm_uframes_t frames;
+};
+
+enum {
+	SNDRV_PCM_IOCTL_PVERSION = _IOR('A', 0x00, int),
+	SNDRV_PCM_IOCTL_INFO = _IOR('A', 0x01, struct snd_pcm_info),
+	SNDRV_PCM_IOCTL_TSTAMP = _IOW('A', 0x02, int),
+	SNDRV_PCM_IOCTL_HW_REFINE = _IOWR('A', 0x10, struct snd_pcm_hw_params),
+	SNDRV_PCM_IOCTL_HW_PARAMS = _IOWR('A', 0x11, struct snd_pcm_hw_params),
+	SNDRV_PCM_IOCTL_HW_FREE = _IO('A', 0x12),
+	SNDRV_PCM_IOCTL_SW_PARAMS = _IOWR('A', 0x13, struct snd_pcm_sw_params),
+	SNDRV_PCM_IOCTL_STATUS = _IOR('A', 0x20, struct snd_pcm_status),
+	SNDRV_PCM_IOCTL_DELAY = _IOR('A', 0x21, snd_pcm_sframes_t),
+	SNDRV_PCM_IOCTL_HWSYNC = _IO('A', 0x22),
+	SNDRV_PCM_IOCTL_SYNC_PTR = _IOWR('A', 0x23, struct snd_pcm_sync_ptr),
+	SNDRV_PCM_IOCTL_CHANNEL_INFO = _IOR('A', 0x32, struct snd_pcm_channel_info),
+	SNDRV_PCM_IOCTL_PREPARE = _IO('A', 0x40),
+	SNDRV_PCM_IOCTL_RESET = _IO('A', 0x41),
+	SNDRV_PCM_IOCTL_START = _IO('A', 0x42),
+	SNDRV_PCM_IOCTL_DROP = _IO('A', 0x43),
+	SNDRV_PCM_IOCTL_DRAIN = _IO('A', 0x44),
+	SNDRV_PCM_IOCTL_PAUSE = _IOW('A', 0x45, int),
+	SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, snd_pcm_uframes_t),
+	SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47),
+	SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48),
+	SNDRV_PCM_IOCTL_FORWARD = _IOW('A', 0x49, snd_pcm_uframes_t),
+	SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct snd_xferi),
+	SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, struct snd_xferi),
+	SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct snd_xfern),
+	SNDRV_PCM_IOCTL_READN_FRAMES = _IOR('A', 0x53, struct snd_xfern),
+	SNDRV_PCM_IOCTL_LINK = _IOW('A', 0x60, int),
+	SNDRV_PCM_IOCTL_UNLINK = _IO('A', 0x61),
+};
+
+/* Trick to make alsa-lib/acinclude.m4 happy */
+#define SNDRV_PCM_IOCTL_REWIND SNDRV_PCM_IOCTL_REWIND
+
+/*****************************************************************************
+ *                                                                           *
+ *                            MIDI v1.0 interface                            *
+ *                                                                           *
+ *****************************************************************************/
+
+/*
+ *  Raw MIDI section - /dev/snd/midi??
+ */
+
+#define SNDRV_RAWMIDI_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 0)
+
+enum {
+	SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
+	SNDRV_RAWMIDI_STREAM_INPUT,
+	SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT,
+};
+
+#define SNDRV_RAWMIDI_INFO_OUTPUT		0x00000001
+#define SNDRV_RAWMIDI_INFO_INPUT		0x00000002
+#define SNDRV_RAWMIDI_INFO_DUPLEX		0x00000004
+
+struct snd_rawmidi_info {
+	unsigned int device;		/* RO/WR (control): device number */
+	unsigned int subdevice;		/* RO/WR (control): subdevice number */
+	int stream;			/* WR: stream */
+	int card;			/* R: card number */
+	unsigned int flags;		/* SNDRV_RAWMIDI_INFO_XXXX */
+	unsigned char id[64];		/* ID (user selectable) */
+	unsigned char name[80];		/* name of device */
+	unsigned char subname[32];	/* name of active or selected subdevice */
+	unsigned int subdevices_count;
+	unsigned int subdevices_avail;
+	unsigned char reserved[64];	/* reserved for future use */
+};
+
+struct snd_rawmidi_params {
+	int stream;
+	size_t buffer_size;		/* queue size in bytes */
+	size_t avail_min;		/* minimum avail bytes for wakeup */
+	unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */
+	unsigned char reserved[16];	/* reserved for future use */
+};
+
+struct snd_rawmidi_status {
+	int stream;
+	struct timespec tstamp;		/* Timestamp */
+	size_t avail;			/* available bytes */
+	size_t xruns;			/* count of overruns since last status (in bytes) */
+	unsigned char reserved[16];	/* reserved for future use */
+};
+
+enum {
+	SNDRV_RAWMIDI_IOCTL_PVERSION = _IOR('W', 0x00, int),
+	SNDRV_RAWMIDI_IOCTL_INFO = _IOR('W', 0x01, struct snd_rawmidi_info),
+	SNDRV_RAWMIDI_IOCTL_PARAMS = _IOWR('W', 0x10, struct snd_rawmidi_params),
+	SNDRV_RAWMIDI_IOCTL_STATUS = _IOWR('W', 0x20, struct snd_rawmidi_status),
+	SNDRV_RAWMIDI_IOCTL_DROP = _IOW('W', 0x30, int),
+	SNDRV_RAWMIDI_IOCTL_DRAIN = _IOW('W', 0x31, int),
+};
+
+/*
+ *  Timer section - /dev/snd/timer
+ */
+
+#define SNDRV_TIMER_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 5)
+
+enum {
+	SNDRV_TIMER_CLASS_NONE = -1,
+	SNDRV_TIMER_CLASS_SLAVE = 0,
+	SNDRV_TIMER_CLASS_GLOBAL,
+	SNDRV_TIMER_CLASS_CARD,
+	SNDRV_TIMER_CLASS_PCM,
+	SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM,
+};
+
+/* slave timer classes */
+enum {
+	SNDRV_TIMER_SCLASS_NONE = 0,
+	SNDRV_TIMER_SCLASS_APPLICATION,
+	SNDRV_TIMER_SCLASS_SEQUENCER,		/* alias */
+	SNDRV_TIMER_SCLASS_OSS_SEQUENCER,	/* alias */
+	SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
+};
+
+/* global timers (device member) */
+#define SNDRV_TIMER_GLOBAL_SYSTEM	0
+#define SNDRV_TIMER_GLOBAL_RTC		1
+#define SNDRV_TIMER_GLOBAL_HPET		2
+
+/* info flags */
+#define SNDRV_TIMER_FLG_SLAVE		(1<<0)	/* cannot be controlled */
+
+struct snd_timer_id {
+	int dev_class;	
+	int dev_sclass;
+	int card;
+	int device;
+	int subdevice;
+};
+
+struct snd_timer_ginfo {
+	struct snd_timer_id tid;	/* requested timer ID */
+	unsigned int flags;		/* timer flags - SNDRV_TIMER_FLG_* */
+	int card;			/* card number */
+	unsigned char id[64];		/* timer identification */
+	unsigned char name[80];		/* timer name */
+	unsigned long reserved0;	/* reserved for future use */
+	unsigned long resolution;	/* average period resolution in ns */
+	unsigned long resolution_min;	/* minimal period resolution in ns */
+	unsigned long resolution_max;	/* maximal period resolution in ns */
+	unsigned int clients;		/* active timer clients */
+	unsigned char reserved[32];
+};
+
+struct snd_timer_gparams {
+	struct snd_timer_id tid;	/* requested timer ID */
+	unsigned long period_num;	/* requested precise period duration (in seconds) - numerator */
+	unsigned long period_den;	/* requested precise period duration (in seconds) - denominator */
+	unsigned char reserved[32];
+};
+
+struct snd_timer_gstatus {
+	struct snd_timer_id tid;	/* requested timer ID */
+	unsigned long resolution;	/* current period resolution in ns */
+	unsigned long resolution_num;	/* precise current period resolution (in seconds) - numerator */
+	unsigned long resolution_den;	/* precise current period resolution (in seconds) - denominator */
+	unsigned char reserved[32];
+};
+
+struct snd_timer_select {
+	struct snd_timer_id id;	/* bind to timer ID */
+	unsigned char reserved[32];	/* reserved */
+};
+
+struct snd_timer_info {
+	unsigned int flags;		/* timer flags - SNDRV_TIMER_FLG_* */
+	int card;			/* card number */
+	unsigned char id[64];		/* timer identificator */
+	unsigned char name[80];		/* timer name */
+	unsigned long reserved0;	/* reserved for future use */
+	unsigned long resolution;	/* average period resolution in ns */
+	unsigned char reserved[64];	/* reserved */
+};
+
+#define SNDRV_TIMER_PSFLG_AUTO		(1<<0)	/* auto start, otherwise one-shot */
+#define SNDRV_TIMER_PSFLG_EXCLUSIVE	(1<<1)	/* exclusive use, precise start/stop/pause/continue */
+#define SNDRV_TIMER_PSFLG_EARLY_EVENT	(1<<2)	/* write early event to the poll queue */
+
+struct snd_timer_params {
+	unsigned int flags;		/* flags - SNDRV_MIXER_PSFLG_* */
+	unsigned int ticks;		/* requested resolution in ticks */
+	unsigned int queue_size;	/* total size of queue (32-1024) */
+	unsigned int reserved0;		/* reserved, was: failure locations */
+	unsigned int filter;		/* event filter (bitmask of SNDRV_TIMER_EVENT_*) */
+	unsigned char reserved[60];	/* reserved */
+};
+
+struct snd_timer_status {
+	struct timespec tstamp;		/* Timestamp - last update */
+	unsigned int resolution;	/* current period resolution in ns */
+	unsigned int lost;		/* counter of master tick lost */
+	unsigned int overrun;		/* count of read queue overruns */
+	unsigned int queue;		/* used queue size */
+	unsigned char reserved[64];	/* reserved */
+};
+
+enum {
+	SNDRV_TIMER_IOCTL_PVERSION = _IOR('T', 0x00, int),
+	SNDRV_TIMER_IOCTL_NEXT_DEVICE = _IOWR('T', 0x01, struct snd_timer_id),
+	SNDRV_TIMER_IOCTL_TREAD = _IOW('T', 0x02, int),
+	SNDRV_TIMER_IOCTL_GINFO = _IOWR('T', 0x03, struct snd_timer_ginfo),
+	SNDRV_TIMER_IOCTL_GPARAMS = _IOW('T', 0x04, struct snd_timer_gparams),
+	SNDRV_TIMER_IOCTL_GSTATUS = _IOWR('T', 0x05, struct snd_timer_gstatus),
+	SNDRV_TIMER_IOCTL_SELECT = _IOW('T', 0x10, struct snd_timer_select),
+	SNDRV_TIMER_IOCTL_INFO = _IOR('T', 0x11, struct snd_timer_info),
+	SNDRV_TIMER_IOCTL_PARAMS = _IOW('T', 0x12, struct snd_timer_params),
+	SNDRV_TIMER_IOCTL_STATUS = _IOR('T', 0x14, struct snd_timer_status),
+	/* The following four ioctls are changed since 1.0.9 due to confliction */
+	SNDRV_TIMER_IOCTL_START = _IO('T', 0xa0),
+	SNDRV_TIMER_IOCTL_STOP = _IO('T', 0xa1),
+	SNDRV_TIMER_IOCTL_CONTINUE = _IO('T', 0xa2),
+	SNDRV_TIMER_IOCTL_PAUSE = _IO('T', 0xa3),
+};
+
+struct snd_timer_read {
+	unsigned int resolution;
+	unsigned int ticks;
+};
+
+enum {
+	SNDRV_TIMER_EVENT_RESOLUTION = 0,	/* val = resolution in ns */
+	SNDRV_TIMER_EVENT_TICK,			/* val = ticks */
+	SNDRV_TIMER_EVENT_START,		/* val = resolution in ns */
+	SNDRV_TIMER_EVENT_STOP,			/* val = 0 */
+	SNDRV_TIMER_EVENT_CONTINUE,		/* val = resolution in ns */
+	SNDRV_TIMER_EVENT_PAUSE,		/* val = 0 */
+	SNDRV_TIMER_EVENT_EARLY,		/* val = 0, early event */
+	SNDRV_TIMER_EVENT_SUSPEND,		/* val = 0 */
+	SNDRV_TIMER_EVENT_RESUME,		/* val = resolution in ns */
+	/* master timer events for slave timer instances */
+	SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
+	SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
+	SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
+	SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
+	SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
+	SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
+};
+
+struct snd_timer_tread {
+	int event;
+	struct timespec tstamp;
+	unsigned int val;
+};
+
+/****************************************************************************
+ *                                                                          *
+ *        Section for driver control interface - /dev/snd/control?          *
+ *                                                                          *
+ ****************************************************************************/
+
+#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 4)
+
+struct snd_ctl_card_info {
+	int card;			/* card number */
+	int pad;			/* reserved for future (was type) */
+	unsigned char id[16];		/* ID of card (user selectable) */
+	unsigned char driver[16];	/* Driver name */
+	unsigned char name[32];		/* Short name of soundcard */
+	unsigned char longname[80];	/* name + info text about soundcard */
+	unsigned char reserved_[16];	/* reserved for future (was ID of mixer) */
+	unsigned char mixername[80];	/* visual mixer identification */
+	unsigned char components[80];	/* card components / fine identification, delimited with one space (AC97 etc..) */
+	unsigned char reserved[48];	/* reserved for future */
+};
+
+typedef int __bitwise snd_ctl_elem_type_t;
+#define	SNDRV_CTL_ELEM_TYPE_NONE	((__force snd_ctl_elem_type_t) 0) /* invalid */
+#define	SNDRV_CTL_ELEM_TYPE_BOOLEAN	((__force snd_ctl_elem_type_t) 1) /* boolean type */
+#define	SNDRV_CTL_ELEM_TYPE_INTEGER	((__force snd_ctl_elem_type_t) 2) /* integer type */
+#define	SNDRV_CTL_ELEM_TYPE_ENUMERATED	((__force snd_ctl_elem_type_t) 3) /* enumerated type */
+#define	SNDRV_CTL_ELEM_TYPE_BYTES	((__force snd_ctl_elem_type_t) 4) /* byte array */
+#define	SNDRV_CTL_ELEM_TYPE_IEC958	((__force snd_ctl_elem_type_t) 5) /* IEC958 (S/PDIF) setup */
+#define	SNDRV_CTL_ELEM_TYPE_INTEGER64	((__force snd_ctl_elem_type_t) 6) /* 64-bit integer type */
+#define	SNDRV_CTL_ELEM_TYPE_LAST	SNDRV_CTL_ELEM_TYPE_INTEGER64
+
+typedef int __bitwise snd_ctl_elem_iface_t;
+#define	SNDRV_CTL_ELEM_IFACE_CARD	((__force snd_ctl_elem_iface_t) 0) /* global control */
+#define	SNDRV_CTL_ELEM_IFACE_HWDEP	((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */
+#define	SNDRV_CTL_ELEM_IFACE_MIXER	((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */
+#define	SNDRV_CTL_ELEM_IFACE_PCM	((__force snd_ctl_elem_iface_t) 3) /* PCM device */
+#define	SNDRV_CTL_ELEM_IFACE_RAWMIDI	((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */
+#define	SNDRV_CTL_ELEM_IFACE_TIMER	((__force snd_ctl_elem_iface_t) 5) /* timer device */
+#define	SNDRV_CTL_ELEM_IFACE_SEQUENCER	((__force snd_ctl_elem_iface_t) 6) /* sequencer client */
+#define	SNDRV_CTL_ELEM_IFACE_LAST	SNDRV_CTL_ELEM_IFACE_SEQUENCER
+
+#define SNDRV_CTL_ELEM_ACCESS_READ		(1<<0)
+#define SNDRV_CTL_ELEM_ACCESS_WRITE		(1<<1)
+#define SNDRV_CTL_ELEM_ACCESS_READWRITE		(SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_VOLATILE		(1<<2)	/* control value may be changed without a notification */
+#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP		(1<<3)	/* when was control changed */
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READ		(1<<4)	/* TLV read is possible */
+#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE		(1<<5)	/* TLV write is possible */
+#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE	(SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
+#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND	(1<<6)	/* TLV command is possible */
+#define SNDRV_CTL_ELEM_ACCESS_INACTIVE		(1<<8)	/* control does actually nothing, but may be updated */
+#define SNDRV_CTL_ELEM_ACCESS_LOCK		(1<<9)	/* write lock */
+#define SNDRV_CTL_ELEM_ACCESS_OWNER		(1<<10)	/* write lock owner */
+#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK	(1<<28)	/* kernel use a TLV callback */ 
+#define SNDRV_CTL_ELEM_ACCESS_USER		(1<<29) /* user space element */
+#define SNDRV_CTL_ELEM_ACCESS_DINDIRECT		(1<<30)	/* indirect access for matrix dimensions in the info structure */
+#define SNDRV_CTL_ELEM_ACCESS_INDIRECT		(1<<31)	/* indirect access for element value in the value structure */
+
+/* for further details see the ACPI and PCI power management specification */
+#define SNDRV_CTL_POWER_D0		0x0000	/* full On */
+#define SNDRV_CTL_POWER_D1		0x0100	/* partial On */
+#define SNDRV_CTL_POWER_D2		0x0200	/* partial On */
+#define SNDRV_CTL_POWER_D3		0x0300	/* Off */
+#define SNDRV_CTL_POWER_D3hot		(SNDRV_CTL_POWER_D3|0x0000)	/* Off, with power */
+#define SNDRV_CTL_POWER_D3cold		(SNDRV_CTL_POWER_D3|0x0001)	/* Off, without power */
+
+struct snd_ctl_elem_id {
+	unsigned int numid;		/* numeric identifier, zero = invalid */
+	snd_ctl_elem_iface_t iface;	/* interface identifier */
+	unsigned int device;		/* device/client number */
+	unsigned int subdevice;		/* subdevice (substream) number */
+        unsigned char name[44];		/* ASCII name of item */
+	unsigned int index;		/* index of item */
+};
+
+struct snd_ctl_elem_list {
+	unsigned int offset;		/* W: first element ID to get */
+	unsigned int space;		/* W: count of element IDs to get */
+	unsigned int used;		/* R: count of element IDs set */
+	unsigned int count;		/* R: count of all elements */
+	struct snd_ctl_elem_id __user *pids; /* R: IDs */
+	unsigned char reserved[50];
+};
+
+struct snd_ctl_elem_info {
+	struct snd_ctl_elem_id id;	/* W: element ID */
+	snd_ctl_elem_type_t type;	/* R: value type - SNDRV_CTL_ELEM_TYPE_* */
+	unsigned int access;		/* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */
+	unsigned int count;		/* count of values */
+	pid_t owner;			/* owner's PID of this control */
+	union {
+		struct {
+			long min;		/* R: minimum value */
+			long max;		/* R: maximum value */
+			long step;		/* R: step (0 variable) */
+		} integer;
+		struct {
+			long long min;		/* R: minimum value */
+			long long max;		/* R: maximum value */
+			long long step;		/* R: step (0 variable) */
+		} integer64;
+		struct {
+			unsigned int items;	/* R: number of items */
+			unsigned int item;	/* W: item number */
+			char name[64];		/* R: value name */
+		} enumerated;
+		unsigned char reserved[128];
+	} value;
+	union {
+		unsigned short d[4];		/* dimensions */
+		unsigned short *d_ptr;		/* indirect */
+	} dimen;
+	unsigned char reserved[64-4*sizeof(unsigned short)];
+};
+
+struct snd_ctl_elem_value {
+	struct snd_ctl_elem_id id;	/* W: element ID */
+	unsigned int indirect: 1;	/* W: use indirect pointer (xxx_ptr member) */
+        union {
+		union {
+			long value[128];
+			long *value_ptr;
+		} integer;
+		union {
+			long long value[64];
+			long long *value_ptr;
+		} integer64;
+		union {
+			unsigned int item[128];
+			unsigned int *item_ptr;
+		} enumerated;
+		union {
+			unsigned char data[512];
+			unsigned char *data_ptr;
+		} bytes;
+		struct snd_aes_iec958 iec958;
+        } value;                /* RO */
+	struct timespec tstamp;
+        unsigned char reserved[128-sizeof(struct timespec)];
+};
+
+struct snd_ctl_tlv {
+        unsigned int numid;	/* control element numeric identification */
+        unsigned int length;	/* in bytes aligned to 4 */
+        unsigned int tlv[0];	/* first TLV */
+};
+
+enum {
+	SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
+	SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
+	SNDRV_CTL_IOCTL_ELEM_LIST = _IOWR('U', 0x10, struct snd_ctl_elem_list),
+	SNDRV_CTL_IOCTL_ELEM_INFO = _IOWR('U', 0x11, struct snd_ctl_elem_info),
+	SNDRV_CTL_IOCTL_ELEM_READ = _IOWR('U', 0x12, struct snd_ctl_elem_value),
+	SNDRV_CTL_IOCTL_ELEM_WRITE = _IOWR('U', 0x13, struct snd_ctl_elem_value),
+	SNDRV_CTL_IOCTL_ELEM_LOCK = _IOW('U', 0x14, struct snd_ctl_elem_id),
+	SNDRV_CTL_IOCTL_ELEM_UNLOCK = _IOW('U', 0x15, struct snd_ctl_elem_id),
+	SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS = _IOWR('U', 0x16, int),
+	SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
+	SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
+	SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
+	SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
+	SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv),
+	SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct snd_ctl_tlv),
+	SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
+	SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
+	SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
+	SNDRV_CTL_IOCTL_PCM_INFO = _IOWR('U', 0x31, struct snd_pcm_info),
+	SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE = _IOW('U', 0x32, int),
+	SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE = _IOWR('U', 0x40, int),
+	SNDRV_CTL_IOCTL_RAWMIDI_INFO = _IOWR('U', 0x41, struct snd_rawmidi_info),
+	SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE = _IOW('U', 0x42, int),
+	SNDRV_CTL_IOCTL_POWER = _IOWR('U', 0xd0, int),
+	SNDRV_CTL_IOCTL_POWER_STATE = _IOR('U', 0xd1, int),
+};
+
+/*
+ *  Read interface.
+ */
+
+enum sndrv_ctl_event_type {
+	SNDRV_CTL_EVENT_ELEM = 0,
+	SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM,
+};
+
+#define SNDRV_CTL_EVENT_MASK_VALUE	(1<<0)	/* element value was changed */
+#define SNDRV_CTL_EVENT_MASK_INFO	(1<<1)	/* element info was changed */
+#define SNDRV_CTL_EVENT_MASK_ADD	(1<<2)	/* element was added */
+#define SNDRV_CTL_EVENT_MASK_TLV	(1<<3)	/* element TLV tree was changed */
+#define SNDRV_CTL_EVENT_MASK_REMOVE	(~0U)	/* element was removed */
+
+struct snd_ctl_event {
+	int type;	/* event type - SNDRV_CTL_EVENT_* */
+	union {
+		struct {
+			unsigned int mask;
+			struct snd_ctl_elem_id id;
+		} elem;
+                unsigned char data8[60];
+        } data;
+};
+
+/*
+ *  Control names
+ */
+
+#define SNDRV_CTL_NAME_NONE				""
+#define SNDRV_CTL_NAME_PLAYBACK				"Playback "
+#define SNDRV_CTL_NAME_CAPTURE				"Capture "
+
+#define SNDRV_CTL_NAME_IEC958_NONE			""
+#define SNDRV_CTL_NAME_IEC958_SWITCH			"Switch"
+#define SNDRV_CTL_NAME_IEC958_VOLUME			"Volume"
+#define SNDRV_CTL_NAME_IEC958_DEFAULT			"Default"
+#define SNDRV_CTL_NAME_IEC958_MASK			"Mask"
+#define SNDRV_CTL_NAME_IEC958_CON_MASK			"Con Mask"
+#define SNDRV_CTL_NAME_IEC958_PRO_MASK			"Pro Mask"
+#define SNDRV_CTL_NAME_IEC958_PCM_STREAM		"PCM Stream"
+#define SNDRV_CTL_NAME_IEC958(expl,direction,what)	"IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
+
+/*
+ *
+ */
+
+struct snd_xferv {
+	const struct iovec *vector;
+	unsigned long count;
+};
+
+enum {
+	SNDRV_IOCTL_READV = _IOW('K', 0x00, struct snd_xferv),
+	SNDRV_IOCTL_WRITEV = _IOW('K', 0x01, struct snd_xferv),
+};
+
+#endif /* __SOUND_ASOUND_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/control.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/control.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/control.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/control.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,164 @@
+#ifndef __SOUND_CONTROL_H
+#define __SOUND_CONTROL_H
+
+/*
+ *  Header file for control interface
+ *  Copyright (c) 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/asound.h>
+
+#define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data)
+
+struct snd_kcontrol;
+typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
+typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
+typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
+typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
+				    int op_flag, /* 0=read,1=write,-1=command */
+				    unsigned int size,
+				    unsigned int __user *tlv);
+
+
+struct snd_kcontrol_new {
+	snd_ctl_elem_iface_t iface;	/* interface identifier */
+	unsigned int device;		/* device/client number */
+	unsigned int subdevice;		/* subdevice (substream) number */
+	unsigned char *name;		/* ASCII name of item */
+	unsigned int index;		/* index of item */
+	unsigned int access;		/* access rights */
+	unsigned int count;		/* count of same elements */
+	snd_kcontrol_info_t *info;
+	snd_kcontrol_get_t *get;
+	snd_kcontrol_put_t *put;
+	union {
+		snd_kcontrol_tlv_rw_t *c;
+		const unsigned int *p;
+	} tlv;
+	unsigned long private_value;
+};
+
+struct snd_kcontrol_volatile {
+	struct snd_ctl_file *owner;	/* locked */
+	pid_t owner_pid;
+	unsigned int access;	/* access rights */
+};
+
+struct snd_kcontrol {
+	struct list_head list;		/* list of controls */
+	struct snd_ctl_elem_id id;
+	unsigned int count;		/* count of same elements */
+	snd_kcontrol_info_t *info;
+	snd_kcontrol_get_t *get;
+	snd_kcontrol_put_t *put;
+	union {
+		snd_kcontrol_tlv_rw_t *c;
+		const unsigned int *p;
+	} tlv;
+	unsigned long private_value;
+	void *private_data;
+	void (*private_free)(struct snd_kcontrol *kcontrol);
+	struct snd_kcontrol_volatile vd[0];	/* volatile data */
+};
+
+#define snd_kcontrol(n) list_entry(n, struct snd_kcontrol, list)
+
+struct snd_kctl_event {
+	struct list_head list;	/* list of events */
+	struct snd_ctl_elem_id id;
+	unsigned int mask;
+};
+
+#define snd_kctl_event(n) list_entry(n, struct snd_kctl_event, list)
+
+struct snd_ctl_file {
+	struct list_head list;		/* list of all control files */
+	struct snd_card *card;
+	pid_t pid;
+	int prefer_pcm_subdevice;
+	int prefer_rawmidi_subdevice;
+	wait_queue_head_t change_sleep;
+	spinlock_t read_lock;
+	struct fasync_struct *fasync;
+	int subscribed;			/* read interface is activated */
+	struct list_head events;	/* waiting events for read */
+};
+
+#define snd_ctl_file(n) list_entry(n, struct snd_ctl_file, list)
+
+typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
+				      struct snd_ctl_file * control,
+				      unsigned int cmd, unsigned long arg);
+
+void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
+
+struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
+void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
+int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
+int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
+int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
+int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
+struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid);
+struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id);
+
+int snd_ctl_create(struct snd_card *card);
+
+int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
+int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
+#ifdef CONFIG_COMPAT
+int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);
+int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
+#else
+#define snd_ctl_register_ioctl_compat(fcn)
+#define snd_ctl_unregister_ioctl_compat(fcn)
+#endif
+
+int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control);
+int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, struct snd_ctl_elem_value *control);
+
+static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
+{
+	return id->numid - kctl->id.numid;
+}
+
+static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
+{
+	return id->index - kctl->id.index;
+}
+
+static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
+{
+	if (id->numid) {
+		return snd_ctl_get_ioffnum(kctl, id);
+	} else {
+		return snd_ctl_get_ioffidx(kctl, id);
+	}
+}
+
+static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id *dst_id,
+						    struct snd_kcontrol *src_kctl,
+						    unsigned int offset)
+{
+	*dst_id = src_kctl->id;
+	dst_id->index += offset;
+	dst_id->numid += offset;
+	return dst_id;
+}
+
+#endif	/* __SOUND_CONTROL_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/cs4231.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/cs4231.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/cs4231.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/cs4231.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,325 @@
+#ifndef __SOUND_CS4231_H
+#define __SOUND_CS4231_H
+
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Definitions for CS4231 & InterWave chips & compatible chips
+ *
+ *
+ *   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 "control.h"
+#include "pcm.h"
+#include "timer.h"
+
+/* IO ports */
+
+#define CS4231P(x)		(c_d_c_CS4231##x)
+
+#define c_d_c_CS4231REGSEL	0
+#define c_d_c_CS4231REG		1
+#define c_d_c_CS4231STATUS	2
+#define c_d_c_CS4231PIO		3
+
+/* codec registers */
+
+#define CS4231_LEFT_INPUT	0x00	/* left input control */
+#define CS4231_RIGHT_INPUT	0x01	/* right input control */
+#define CS4231_AUX1_LEFT_INPUT	0x02	/* left AUX1 input control */
+#define CS4231_AUX1_RIGHT_INPUT	0x03	/* right AUX1 input control */
+#define CS4231_AUX2_LEFT_INPUT	0x04	/* left AUX2 input control */
+#define CS4231_AUX2_RIGHT_INPUT	0x05	/* right AUX2 input control */
+#define CS4231_LEFT_OUTPUT	0x06	/* left output control register */
+#define CS4231_RIGHT_OUTPUT	0x07	/* right output control register */
+#define CS4231_PLAYBK_FORMAT	0x08	/* clock and data format - playback - bits 7-0 MCE */
+#define CS4231_IFACE_CTRL	0x09	/* interface control - bits 7-2 MCE */
+#define CS4231_PIN_CTRL		0x0a	/* pin control */
+#define CS4231_TEST_INIT	0x0b	/* test and initialization */
+#define CS4231_MISC_INFO	0x0c	/* miscellaneaous information */
+#define CS4231_LOOPBACK		0x0d	/* loopback control */
+#define CS4231_PLY_UPR_CNT	0x0e	/* playback upper base count */
+#define CS4231_PLY_LWR_CNT	0x0f	/* playback lower base count */
+#define CS4231_ALT_FEATURE_1	0x10	/* alternate #1 feature enable */
+#define AD1845_AF1_MIC_LEFT	0x10	/* alternate #1 feature + MIC left */
+#define CS4231_ALT_FEATURE_2	0x11	/* alternate #2 feature enable */
+#define AD1845_AF2_MIC_RIGHT	0x11	/* alternate #2 feature + MIC right */
+#define CS4231_LEFT_LINE_IN	0x12	/* left line input control */
+#define CS4231_RIGHT_LINE_IN	0x13	/* right line input control */
+#define CS4231_TIMER_LOW	0x14	/* timer low byte */
+#define CS4231_TIMER_HIGH	0x15	/* timer high byte */
+#define CS4231_LEFT_MIC_INPUT	0x16	/* left MIC input control register (InterWave only) */
+#define AD1845_UPR_FREQ_SEL	0x16	/* upper byte of frequency select */
+#define CS4231_RIGHT_MIC_INPUT	0x17	/* right MIC input control register (InterWave only) */
+#define AD1845_LWR_FREQ_SEL	0x17	/* lower byte of frequency select */
+#define CS4236_EXT_REG		0x17	/* extended register access */
+#define CS4231_IRQ_STATUS	0x18	/* irq status register */
+#define CS4231_LINE_LEFT_OUTPUT	0x19	/* left line output control register (InterWave only) */
+#define CS4231_VERSION		0x19	/* CS4231(A) - version values */
+#define CS4231_MONO_CTRL	0x1a	/* mono input/output control */
+#define CS4231_LINE_RIGHT_OUTPUT 0x1b	/* right line output control register (InterWave only) */
+#define AD1845_PWR_DOWN		0x1b	/* power down control */
+#define CS4235_LEFT_MASTER	0x1b	/* left master output control */
+#define CS4231_REC_FORMAT	0x1c	/* clock and data format - record - bits 7-0 MCE */
+#define CS4231_PLY_VAR_FREQ	0x1d	/* playback variable frequency */
+#define AD1845_CLOCK		0x1d	/* crystal clock select and total power down */
+#define CS4235_RIGHT_MASTER	0x1d	/* right master output control */
+#define CS4231_REC_UPR_CNT	0x1e	/* record upper count */
+#define CS4231_REC_LWR_CNT	0x1f	/* record lower count */
+
+/* definitions for codec register select port - CODECP( REGSEL ) */
+
+#define CS4231_INIT		0x80	/* CODEC is initializing */
+#define CS4231_MCE		0x40	/* mode change enable */
+#define CS4231_TRD		0x20	/* transfer request disable */
+
+/* definitions for codec status register - CODECP( STATUS ) */
+
+#define CS4231_GLOBALIRQ	0x01	/* IRQ is active */
+
+/* definitions for codec irq status */
+
+#define CS4231_PLAYBACK_IRQ	0x10
+#define CS4231_RECORD_IRQ	0x20
+#define CS4231_TIMER_IRQ	0x40
+#define CS4231_ALL_IRQS		0x70
+#define CS4231_REC_UNDERRUN	0x08
+#define CS4231_REC_OVERRUN	0x04
+#define CS4231_PLY_OVERRUN	0x02
+#define CS4231_PLY_UNDERRUN	0x01
+
+/* definitions for CS4231_LEFT_INPUT and CS4231_RIGHT_INPUT registers */
+
+#define CS4231_ENABLE_MIC_GAIN	0x20
+
+#define CS4231_MIXS_LINE	0x00
+#define CS4231_MIXS_AUX1	0x40
+#define CS4231_MIXS_MIC		0x80
+#define CS4231_MIXS_ALL		0xc0
+
+/* definitions for clock and data format register - CS4231_PLAYBK_FORMAT */
+
+#define CS4231_LINEAR_8		0x00	/* 8-bit unsigned data */
+#define CS4231_ALAW_8		0x60	/* 8-bit A-law companded */
+#define CS4231_ULAW_8		0x20	/* 8-bit U-law companded */
+#define CS4231_LINEAR_16	0x40	/* 16-bit twos complement data - little endian */
+#define CS4231_LINEAR_16_BIG	0xc0	/* 16-bit twos complement data - big endian */
+#define CS4231_ADPCM_16		0xa0	/* 16-bit ADPCM */
+#define CS4231_STEREO		0x10	/* stereo mode */
+/* bits 3-1 define frequency divisor */
+#define CS4231_XTAL1		0x00	/* 24.576 crystal */
+#define CS4231_XTAL2		0x01	/* 16.9344 crystal */
+
+/* definitions for interface control register - CS4231_IFACE_CTRL */
+
+#define CS4231_RECORD_PIO	0x80	/* record PIO enable */
+#define CS4231_PLAYBACK_PIO	0x40	/* playback PIO enable */
+#define CS4231_CALIB_MODE	0x18	/* calibration mode bits */
+#define CS4231_AUTOCALIB	0x08	/* auto calibrate */
+#define CS4231_SINGLE_DMA	0x04	/* use single DMA channel */
+#define CS4231_RECORD_ENABLE	0x02	/* record enable */
+#define CS4231_PLAYBACK_ENABLE	0x01	/* playback enable */
+
+/* definitions for pin control register - CS4231_PIN_CTRL */
+
+#define CS4231_IRQ_ENABLE	0x02	/* enable IRQ */
+#define CS4231_XCTL1		0x40	/* external control #1 */
+#define CS4231_XCTL0		0x80	/* external control #0 */
+
+/* definitions for test and init register - CS4231_TEST_INIT */
+
+#define CS4231_CALIB_IN_PROGRESS 0x20	/* auto calibrate in progress */
+#define CS4231_DMA_REQUEST	0x10	/* DMA request in progress */
+
+/* definitions for misc control register - CS4231_MISC_INFO */
+
+#define CS4231_MODE2		0x40	/* MODE 2 */
+#define CS4231_IW_MODE3		0x6c	/* MODE 3 - InterWave enhanced mode */
+#define CS4231_4236_MODE3	0xe0	/* MODE 3 - CS4236+ enhanced mode */
+
+/* definitions for alternate feature 1 register - CS4231_ALT_FEATURE_1 */
+
+#define	CS4231_DACZ		0x01	/* zero DAC when underrun */
+#define CS4231_TIMER_ENABLE	0x40	/* codec timer enable */
+#define CS4231_OLB		0x80	/* output level bit */
+
+/* definitions for Extended Registers - CS4236+ */
+
+#define CS4236_REG(i23val)	(((i23val << 2) & 0x10) | ((i23val >> 4) & 0x0f))
+#define CS4236_I23VAL(reg)	((((reg)&0xf) << 4) | (((reg)&0x10) >> 2) | 0x8)
+
+#define CS4236_LEFT_LINE	0x08	/* left LINE alternate volume */
+#define CS4236_RIGHT_LINE	0x18	/* right LINE alternate volume */
+#define CS4236_LEFT_MIC		0x28	/* left MIC volume */
+#define CS4236_RIGHT_MIC	0x38	/* right MIC volume */
+#define CS4236_LEFT_MIX_CTRL	0x48	/* synthesis and left input mixer control */
+#define CS4236_RIGHT_MIX_CTRL	0x58	/* right input mixer control */
+#define CS4236_LEFT_FM		0x68	/* left FM volume */
+#define CS4236_RIGHT_FM		0x78	/* right FM volume */
+#define CS4236_LEFT_DSP		0x88	/* left DSP serial port volume */
+#define CS4236_RIGHT_DSP	0x98	/* right DSP serial port volume */
+#define CS4236_RIGHT_LOOPBACK	0xa8	/* right loopback monitor volume */
+#define CS4236_DAC_MUTE		0xb8	/* DAC mute and IFSE enable */
+#define CS4236_ADC_RATE		0xc8	/* indenpendent ADC sample frequency */
+#define CS4236_DAC_RATE		0xd8	/* indenpendent DAC sample frequency */
+#define CS4236_LEFT_MASTER	0xe8	/* left master digital audio volume */
+#define CS4236_RIGHT_MASTER	0xf8	/* right master digital audio volume */
+#define CS4236_LEFT_WAVE	0x0c	/* left wavetable serial port volume */
+#define CS4236_RIGHT_WAVE	0x1c	/* right wavetable serial port volume */
+#define CS4236_VERSION		0x9c	/* chip version and ID */
+
+/* defines for codec.mode */
+
+#define CS4231_MODE_NONE	0x0000
+#define CS4231_MODE_PLAY	0x0001
+#define CS4231_MODE_RECORD	0x0002
+#define CS4231_MODE_TIMER	0x0004
+#define CS4231_MODE_OPEN	(CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER)
+
+/* defines for codec.hardware */
+
+#define CS4231_HW_DETECT        0x0000	/* let CS4231 driver detect chip */
+#define CS4231_HW_DETECT3	0x0001	/* allow mode 3 */
+#define CS4231_HW_TYPE_MASK	0xff00	/* type mask */
+#define CS4231_HW_CS4231_MASK   0x0100	/* CS4231 serie */
+#define CS4231_HW_CS4231        0x0100	/* CS4231 chip */
+#define CS4231_HW_CS4231A       0x0101	/* CS4231A chip */
+#define CS4231_HW_AD1845	0x0102	/* AD1845 chip */
+#define CS4231_HW_CS4232_MASK   0x0200	/* CS4232 serie (has control ports) */
+#define CS4231_HW_CS4232        0x0200	/* CS4232 */
+#define CS4231_HW_CS4232A       0x0201	/* CS4232A */
+#define CS4231_HW_CS4236	0x0202	/* CS4236 */
+#define CS4231_HW_CS4236B_MASK	0x0400	/* CS4236B serie (has extended control regs) */
+#define CS4231_HW_CS4235	0x0400	/* CS4235 - Crystal Clear (tm) stereo enhancement */
+#define CS4231_HW_CS4236B       0x0401	/* CS4236B */
+#define CS4231_HW_CS4237B       0x0402	/* CS4237B - SRS 3D */
+#define CS4231_HW_CS4238B	0x0403	/* CS4238B - QSOUND 3D */
+#define CS4231_HW_CS4239	0x0404	/* CS4239 - Crystal Clear (tm) stereo enhancement */
+/* compatible, but clones */
+#define CS4231_HW_INTERWAVE     0x1000	/* InterWave chip */
+#define CS4231_HW_OPL3SA2       0x1001	/* OPL3-SA2 chip */
+
+/* defines for codec.hwshare */
+#define CS4231_HWSHARE_IRQ	(1<<0)
+#define CS4231_HWSHARE_DMA1	(1<<1)
+#define CS4231_HWSHARE_DMA2	(1<<2)
+
+struct snd_cs4231 {
+	unsigned long port;		/* base i/o port */
+	struct resource *res_port;
+	unsigned long cport;		/* control base i/o port (CS4236) */
+	struct resource *res_cport;
+	int irq;			/* IRQ line */
+	int dma1;			/* playback DMA */
+	int dma2;			/* record DMA */
+	unsigned short version;		/* version of CODEC chip */
+	unsigned short mode;		/* see to CS4231_MODE_XXXX */
+	unsigned short hardware;	/* see to CS4231_HW_XXXX */
+	unsigned short hwshare;		/* shared resources */
+	unsigned short single_dma:1,	/* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */
+		       ebus_flag:1;	/* SPARC: EBUS present */
+
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+	struct snd_timer *timer;
+
+	unsigned char image[32];	/* registers image */
+	unsigned char eimage[32];	/* extended registers image */
+	unsigned char cimage[16];	/* control registers image */
+	int mce_bit;
+	int calibrate_mute;
+	int sw_3d_bit;
+	unsigned int p_dma_size;
+	unsigned int c_dma_size;
+
+	spinlock_t reg_lock;
+	struct mutex mce_mutex;
+	struct mutex open_mutex;
+
+	int (*rate_constraint) (struct snd_pcm_runtime *runtime);
+	void (*set_playback_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char pdfr);
+	void (*set_capture_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char cdfr);
+	void (*trigger) (struct snd_cs4231 *chip, unsigned int what, int start);
+#ifdef CONFIG_PM
+	void (*suspend) (struct snd_cs4231 *chip);
+	void (*resume) (struct snd_cs4231 *chip);
+#endif
+	void *dma_private_data;
+	int (*claim_dma) (struct snd_cs4231 *chip, void *dma_private_data, int dma);
+	int (*release_dma) (struct snd_cs4231 *chip, void *dma_private_data, int dma);
+};
+
+/* exported functions */
+
+void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val);
+unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg);
+void snd_cs4236_ext_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val);
+unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg);
+void snd_cs4231_mce_up(struct snd_cs4231 *chip);
+void snd_cs4231_mce_down(struct snd_cs4231 *chip);
+
+irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id);
+
+const char *snd_cs4231_chip_id(struct snd_cs4231 *chip);
+
+int snd_cs4231_create(struct snd_card *card,
+		      unsigned long port,
+		      unsigned long cport,
+		      int irq, int dma1, int dma2,
+		      unsigned short hardware,
+		      unsigned short hwshare,
+		      struct snd_cs4231 ** rchip);
+int snd_cs4231_pcm(struct snd_cs4231 * chip, int device, struct snd_pcm **rpcm);
+int snd_cs4231_timer(struct snd_cs4231 * chip, int device, struct snd_timer **rtimer);
+int snd_cs4231_mixer(struct snd_cs4231 * chip);
+
+int snd_cs4236_create(struct snd_card *card,
+		      unsigned long port,
+		      unsigned long cport,
+		      int irq, int dma1, int dma2,
+		      unsigned short hardware,
+		      unsigned short hwshare,
+		      struct snd_cs4231 ** rchip);
+int snd_cs4236_pcm(struct snd_cs4231 * chip, int device, struct snd_pcm **rpcm);
+int snd_cs4236_mixer(struct snd_cs4231 * chip);
+
+/*
+ *  mixer library
+ */
+
+#define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_cs4231_info_single, \
+  .get = snd_cs4231_get_single, .put = snd_cs4231_put_single, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+
+int snd_cs4231_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
+int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+
+#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_cs4231_info_double, \
+  .get = snd_cs4231_get_double, .put = snd_cs4231_put_double, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
+
+int snd_cs4231_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
+int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+
+#endif /* __SOUND_CS4231_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/cs46xx.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/cs46xx.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/cs46xx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/cs46xx.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,1744 @@
+#ifndef __SOUND_CS46XX_H
+#define __SOUND_CS46XX_H
+
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ *		     Cirrus Logic, Inc.
+ *  Definitions for Cirrus Logic CS46xx chips
+ *
+ *
+ *   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 "pcm.h"
+#include "pcm-indirect.h"
+#include "rawmidi.h"
+#include "ac97_codec.h"
+#include "cs46xx_dsp_spos.h"
+
+/*
+ *  Direct registers
+ */
+
+/*
+ *  The following define the offsets of the registers accessed via base address
+ *  register zero on the CS46xx part.
+ */
+#define BA0_HISR				0x00000000
+#define BA0_HSR0                                0x00000004
+#define BA0_HICR                                0x00000008
+#define BA0_DMSR                                0x00000100
+#define BA0_HSAR                                0x00000110
+#define BA0_HDAR                                0x00000114
+#define BA0_HDMR                                0x00000118
+#define BA0_HDCR                                0x0000011C
+#define BA0_PFMC                                0x00000200
+#define BA0_PFCV1                               0x00000204
+#define BA0_PFCV2                               0x00000208
+#define BA0_PCICFG00                            0x00000300
+#define BA0_PCICFG04                            0x00000304
+#define BA0_PCICFG08                            0x00000308
+#define BA0_PCICFG0C                            0x0000030C
+#define BA0_PCICFG10                            0x00000310
+#define BA0_PCICFG14                            0x00000314
+#define BA0_PCICFG18                            0x00000318
+#define BA0_PCICFG1C                            0x0000031C
+#define BA0_PCICFG20                            0x00000320
+#define BA0_PCICFG24                            0x00000324
+#define BA0_PCICFG28                            0x00000328
+#define BA0_PCICFG2C                            0x0000032C
+#define BA0_PCICFG30                            0x00000330
+#define BA0_PCICFG34                            0x00000334
+#define BA0_PCICFG38                            0x00000338
+#define BA0_PCICFG3C                            0x0000033C
+#define BA0_CLKCR1                              0x00000400
+#define BA0_CLKCR2                              0x00000404
+#define BA0_PLLM                                0x00000408
+#define BA0_PLLCC                               0x0000040C
+#define BA0_FRR                                 0x00000410 
+#define BA0_CFL1                                0x00000414
+#define BA0_CFL2                                0x00000418
+#define BA0_SERMC1                              0x00000420
+#define BA0_SERMC2                              0x00000424
+#define BA0_SERC1                               0x00000428
+#define BA0_SERC2                               0x0000042C
+#define BA0_SERC3                               0x00000430
+#define BA0_SERC4                               0x00000434
+#define BA0_SERC5                               0x00000438
+#define BA0_SERBSP                              0x0000043C
+#define BA0_SERBST                              0x00000440
+#define BA0_SERBCM                              0x00000444
+#define BA0_SERBAD                              0x00000448
+#define BA0_SERBCF                              0x0000044C
+#define BA0_SERBWP                              0x00000450
+#define BA0_SERBRP                              0x00000454
+#ifndef NO_CS4612
+#define BA0_ASER_FADDR                          0x00000458
+#endif
+#define BA0_ACCTL                               0x00000460
+#define BA0_ACSTS                               0x00000464
+#define BA0_ACOSV                               0x00000468
+#define BA0_ACCAD                               0x0000046C
+#define BA0_ACCDA                               0x00000470
+#define BA0_ACISV                               0x00000474
+#define BA0_ACSAD                               0x00000478
+#define BA0_ACSDA                               0x0000047C
+#define BA0_JSPT                                0x00000480
+#define BA0_JSCTL                               0x00000484
+#define BA0_JSC1                                0x00000488
+#define BA0_JSC2                                0x0000048C
+#define BA0_MIDCR                               0x00000490
+#define BA0_MIDSR                               0x00000494
+#define BA0_MIDWP                               0x00000498
+#define BA0_MIDRP                               0x0000049C
+#define BA0_JSIO                                0x000004A0
+#ifndef NO_CS4612
+#define BA0_ASER_MASTER                         0x000004A4
+#endif
+#define BA0_CFGI                                0x000004B0
+#define BA0_SSVID                               0x000004B4
+#define BA0_GPIOR                               0x000004B8
+#ifndef NO_CS4612
+#define BA0_EGPIODR                             0x000004BC
+#define BA0_EGPIOPTR                            0x000004C0
+#define BA0_EGPIOTR                             0x000004C4
+#define BA0_EGPIOWR                             0x000004C8
+#define BA0_EGPIOSR                             0x000004CC
+#define BA0_SERC6                               0x000004D0
+#define BA0_SERC7                               0x000004D4
+#define BA0_SERACC                              0x000004D8
+#define BA0_ACCTL2                              0x000004E0
+#define BA0_ACSTS2                              0x000004E4
+#define BA0_ACOSV2                              0x000004E8
+#define BA0_ACCAD2                              0x000004EC
+#define BA0_ACCDA2                              0x000004F0
+#define BA0_ACISV2                              0x000004F4
+#define BA0_ACSAD2                              0x000004F8
+#define BA0_ACSDA2                              0x000004FC
+#define BA0_IOTAC0                              0x00000500
+#define BA0_IOTAC1                              0x00000504
+#define BA0_IOTAC2                              0x00000508
+#define BA0_IOTAC3                              0x0000050C
+#define BA0_IOTAC4                              0x00000510
+#define BA0_IOTAC5                              0x00000514
+#define BA0_IOTAC6                              0x00000518
+#define BA0_IOTAC7                              0x0000051C
+#define BA0_IOTAC8                              0x00000520
+#define BA0_IOTAC9                              0x00000524
+#define BA0_IOTAC10                             0x00000528
+#define BA0_IOTAC11                             0x0000052C
+#define BA0_IOTFR0                              0x00000540
+#define BA0_IOTFR1                              0x00000544
+#define BA0_IOTFR2                              0x00000548
+#define BA0_IOTFR3                              0x0000054C
+#define BA0_IOTFR4                              0x00000550
+#define BA0_IOTFR5                              0x00000554
+#define BA0_IOTFR6                              0x00000558
+#define BA0_IOTFR7                              0x0000055C
+#define BA0_IOTFIFO                             0x00000580
+#define BA0_IOTRRD                              0x00000584
+#define BA0_IOTFP                               0x00000588
+#define BA0_IOTCR                               0x0000058C
+#define BA0_DPCID                               0x00000590
+#define BA0_DPCIA                               0x00000594
+#define BA0_DPCIC                               0x00000598
+#define BA0_PCPCIR                              0x00000600
+#define BA0_PCPCIG                              0x00000604
+#define BA0_PCPCIEN                             0x00000608
+#define BA0_EPCIPMC                             0x00000610
+#endif
+
+/*
+ *  The following define the offsets of the registers and memories accessed via
+ *  base address register one on the CS46xx part.
+ */
+#define BA1_SP_DMEM0                            0x00000000
+#define BA1_SP_DMEM1                            0x00010000
+#define BA1_SP_PMEM                             0x00020000
+#define BA1_SP_REG				0x00030000
+#define BA1_SPCR                                0x00030000
+#define BA1_DREG                                0x00030004
+#define BA1_DSRWP                               0x00030008
+#define BA1_TWPR                                0x0003000C
+#define BA1_SPWR                                0x00030010
+#define BA1_SPIR                                0x00030014
+#define BA1_FGR1                                0x00030020
+#define BA1_SPCS                                0x00030028
+#define BA1_SDSR                                0x0003002C
+#define BA1_FRMT                                0x00030030
+#define BA1_FRCC                                0x00030034
+#define BA1_FRSC                                0x00030038
+#define BA1_OMNI_MEM                            0x000E0000
+
+
+/*
+ *  The following defines are for the flags in the host interrupt status
+ *  register.
+ */
+#define HISR_VC_MASK                            0x0000FFFF
+#define HISR_VC0                                0x00000001
+#define HISR_VC1                                0x00000002
+#define HISR_VC2                                0x00000004
+#define HISR_VC3                                0x00000008
+#define HISR_VC4                                0x00000010
+#define HISR_VC5                                0x00000020
+#define HISR_VC6                                0x00000040
+#define HISR_VC7                                0x00000080
+#define HISR_VC8                                0x00000100
+#define HISR_VC9                                0x00000200
+#define HISR_VC10                               0x00000400
+#define HISR_VC11                               0x00000800
+#define HISR_VC12                               0x00001000
+#define HISR_VC13                               0x00002000
+#define HISR_VC14                               0x00004000
+#define HISR_VC15                               0x00008000
+#define HISR_INT0                               0x00010000
+#define HISR_INT1                               0x00020000
+#define HISR_DMAI                               0x00040000
+#define HISR_FROVR                              0x00080000
+#define HISR_MIDI                               0x00100000
+#ifdef NO_CS4612
+#define HISR_RESERVED                           0x0FE00000
+#else
+#define HISR_SBINT                              0x00200000
+#define HISR_RESERVED                           0x0FC00000
+#endif
+#define HISR_H0P                                0x40000000
+#define HISR_INTENA                             0x80000000
+
+/*
+ *  The following defines are for the flags in the host signal register 0.
+ */
+#define HSR0_VC_MASK                            0xFFFFFFFF
+#define HSR0_VC16                               0x00000001
+#define HSR0_VC17                               0x00000002
+#define HSR0_VC18                               0x00000004
+#define HSR0_VC19                               0x00000008
+#define HSR0_VC20                               0x00000010
+#define HSR0_VC21                               0x00000020
+#define HSR0_VC22                               0x00000040
+#define HSR0_VC23                               0x00000080
+#define HSR0_VC24                               0x00000100
+#define HSR0_VC25                               0x00000200
+#define HSR0_VC26                               0x00000400
+#define HSR0_VC27                               0x00000800
+#define HSR0_VC28                               0x00001000
+#define HSR0_VC29                               0x00002000
+#define HSR0_VC30                               0x00004000
+#define HSR0_VC31                               0x00008000
+#define HSR0_VC32                               0x00010000
+#define HSR0_VC33                               0x00020000
+#define HSR0_VC34                               0x00040000
+#define HSR0_VC35                               0x00080000
+#define HSR0_VC36                               0x00100000
+#define HSR0_VC37                               0x00200000
+#define HSR0_VC38                               0x00400000
+#define HSR0_VC39                               0x00800000
+#define HSR0_VC40                               0x01000000
+#define HSR0_VC41                               0x02000000
+#define HSR0_VC42                               0x04000000
+#define HSR0_VC43                               0x08000000
+#define HSR0_VC44                               0x10000000
+#define HSR0_VC45                               0x20000000
+#define HSR0_VC46                               0x40000000
+#define HSR0_VC47                               0x80000000
+
+/*
+ *  The following defines are for the flags in the host interrupt control
+ *  register.
+ */
+#define HICR_IEV                                0x00000001
+#define HICR_CHGM                               0x00000002
+
+/*
+ *  The following defines are for the flags in the DMA status register.
+ */
+#define DMSR_HP                                 0x00000001
+#define DMSR_HR                                 0x00000002
+#define DMSR_SP                                 0x00000004
+#define DMSR_SR                                 0x00000008
+
+/*
+ *  The following defines are for the flags in the host DMA source address
+ *  register.
+ */
+#define HSAR_HOST_ADDR_MASK                     0xFFFFFFFF
+#define HSAR_DSP_ADDR_MASK                      0x0000FFFF
+#define HSAR_MEMID_MASK                         0x000F0000
+#define HSAR_MEMID_SP_DMEM0                     0x00000000
+#define HSAR_MEMID_SP_DMEM1                     0x00010000
+#define HSAR_MEMID_SP_PMEM                      0x00020000
+#define HSAR_MEMID_SP_DEBUG                     0x00030000
+#define HSAR_MEMID_OMNI_MEM                     0x000E0000
+#define HSAR_END                                0x40000000
+#define HSAR_ERR                                0x80000000
+
+/*
+ *  The following defines are for the flags in the host DMA destination address
+ *  register.
+ */
+#define HDAR_HOST_ADDR_MASK                     0xFFFFFFFF
+#define HDAR_DSP_ADDR_MASK                      0x0000FFFF
+#define HDAR_MEMID_MASK                         0x000F0000
+#define HDAR_MEMID_SP_DMEM0                     0x00000000
+#define HDAR_MEMID_SP_DMEM1                     0x00010000
+#define HDAR_MEMID_SP_PMEM                      0x00020000
+#define HDAR_MEMID_SP_DEBUG                     0x00030000
+#define HDAR_MEMID_OMNI_MEM                     0x000E0000
+#define HDAR_END                                0x40000000
+#define HDAR_ERR                                0x80000000
+
+/*
+ *  The following defines are for the flags in the host DMA control register.
+ */
+#define HDMR_AC_MASK                            0x0000F000
+#define HDMR_AC_8_16                            0x00001000
+#define HDMR_AC_M_S                             0x00002000
+#define HDMR_AC_B_L                             0x00004000
+#define HDMR_AC_S_U                             0x00008000
+
+/*
+ *  The following defines are for the flags in the host DMA control register.
+ */
+#define HDCR_COUNT_MASK                         0x000003FF
+#define HDCR_DONE                               0x00004000
+#define HDCR_OPT                                0x00008000
+#define HDCR_WBD                                0x00400000
+#define HDCR_WBS                                0x00800000
+#define HDCR_DMS_MASK                           0x07000000
+#define HDCR_DMS_LINEAR                         0x00000000
+#define HDCR_DMS_16_DWORDS                      0x01000000
+#define HDCR_DMS_32_DWORDS                      0x02000000
+#define HDCR_DMS_64_DWORDS                      0x03000000
+#define HDCR_DMS_128_DWORDS                     0x04000000
+#define HDCR_DMS_256_DWORDS                     0x05000000
+#define HDCR_DMS_512_DWORDS                     0x06000000
+#define HDCR_DMS_1024_DWORDS                    0x07000000
+#define HDCR_DH                                 0x08000000
+#define HDCR_SMS_MASK                           0x70000000
+#define HDCR_SMS_LINEAR                         0x00000000
+#define HDCR_SMS_16_DWORDS                      0x10000000
+#define HDCR_SMS_32_DWORDS                      0x20000000
+#define HDCR_SMS_64_DWORDS                      0x30000000
+#define HDCR_SMS_128_DWORDS                     0x40000000
+#define HDCR_SMS_256_DWORDS                     0x50000000
+#define HDCR_SMS_512_DWORDS                     0x60000000
+#define HDCR_SMS_1024_DWORDS                    0x70000000
+#define HDCR_SH                                 0x80000000
+#define HDCR_COUNT_SHIFT                        0
+
+/*
+ *  The following defines are for the flags in the performance monitor control
+ *  register.
+ */
+#define PFMC_C1SS_MASK                          0x0000001F
+#define PFMC_C1EV                               0x00000020
+#define PFMC_C1RS                               0x00008000
+#define PFMC_C2SS_MASK                          0x001F0000
+#define PFMC_C2EV                               0x00200000
+#define PFMC_C2RS                               0x80000000
+#define PFMC_C1SS_SHIFT                         0
+#define PFMC_C2SS_SHIFT                         16
+#define PFMC_BUS_GRANT                          0
+#define PFMC_GRANT_AFTER_REQ                    1
+#define PFMC_TRANSACTION                        2
+#define PFMC_DWORD_TRANSFER                     3
+#define PFMC_SLAVE_READ                         4
+#define PFMC_SLAVE_WRITE                        5
+#define PFMC_PREEMPTION                         6
+#define PFMC_DISCONNECT_RETRY                   7
+#define PFMC_INTERRUPT                          8
+#define PFMC_BUS_OWNERSHIP                      9
+#define PFMC_TRANSACTION_LAG                    10
+#define PFMC_PCI_CLOCK                          11
+#define PFMC_SERIAL_CLOCK                       12
+#define PFMC_SP_CLOCK                           13
+
+/*
+ *  The following defines are for the flags in the performance counter value 1
+ *  register.
+ */
+#define PFCV1_PC1V_MASK                         0xFFFFFFFF
+#define PFCV1_PC1V_SHIFT                        0
+
+/*
+ *  The following defines are for the flags in the performance counter value 2
+ *  register.
+ */
+#define PFCV2_PC2V_MASK                         0xFFFFFFFF
+#define PFCV2_PC2V_SHIFT                        0
+
+/*
+ *  The following defines are for the flags in the clock control register 1.
+ */
+#define CLKCR1_OSCS                             0x00000001
+#define CLKCR1_OSCP                             0x00000002
+#define CLKCR1_PLLSS_MASK                       0x0000000C
+#define CLKCR1_PLLSS_SERIAL                     0x00000000
+#define CLKCR1_PLLSS_CRYSTAL                    0x00000004
+#define CLKCR1_PLLSS_PCI                        0x00000008
+#define CLKCR1_PLLSS_RESERVED                   0x0000000C
+#define CLKCR1_PLLP                             0x00000010
+#define CLKCR1_SWCE                             0x00000020
+#define CLKCR1_PLLOS                            0x00000040
+
+/*
+ *  The following defines are for the flags in the clock control register 2.
+ */
+#define CLKCR2_PDIVS_MASK                       0x0000000F
+#define CLKCR2_PDIVS_1                          0x00000001
+#define CLKCR2_PDIVS_2                          0x00000002
+#define CLKCR2_PDIVS_4                          0x00000004
+#define CLKCR2_PDIVS_7                          0x00000007
+#define CLKCR2_PDIVS_8                          0x00000008
+#define CLKCR2_PDIVS_16                         0x00000000
+
+/*
+ *  The following defines are for the flags in the PLL multiplier register.
+ */
+#define PLLM_MASK                               0x000000FF
+#define PLLM_SHIFT                              0
+
+/*
+ *  The following defines are for the flags in the PLL capacitor coefficient
+ *  register.
+ */
+#define PLLCC_CDR_MASK                          0x00000007
+#ifndef NO_CS4610
+#define PLLCC_CDR_240_350_MHZ                   0x00000000
+#define PLLCC_CDR_184_265_MHZ                   0x00000001
+#define PLLCC_CDR_144_205_MHZ                   0x00000002
+#define PLLCC_CDR_111_160_MHZ                   0x00000003
+#define PLLCC_CDR_87_123_MHZ                    0x00000004
+#define PLLCC_CDR_67_96_MHZ                     0x00000005
+#define PLLCC_CDR_52_74_MHZ                     0x00000006
+#define PLLCC_CDR_45_58_MHZ                     0x00000007
+#endif
+#ifndef NO_CS4612
+#define PLLCC_CDR_271_398_MHZ                   0x00000000
+#define PLLCC_CDR_227_330_MHZ                   0x00000001
+#define PLLCC_CDR_167_239_MHZ                   0x00000002
+#define PLLCC_CDR_150_215_MHZ                   0x00000003
+#define PLLCC_CDR_107_154_MHZ                   0x00000004
+#define PLLCC_CDR_98_140_MHZ                    0x00000005
+#define PLLCC_CDR_73_104_MHZ                    0x00000006
+#define PLLCC_CDR_63_90_MHZ                     0x00000007
+#endif
+#define PLLCC_LPF_MASK                          0x000000F8
+#ifndef NO_CS4610
+#define PLLCC_LPF_23850_60000_KHZ               0x00000000
+#define PLLCC_LPF_7960_26290_KHZ                0x00000008
+#define PLLCC_LPF_4160_10980_KHZ                0x00000018
+#define PLLCC_LPF_1740_4580_KHZ                 0x00000038
+#define PLLCC_LPF_724_1910_KHZ                  0x00000078
+#define PLLCC_LPF_317_798_KHZ                   0x000000F8
+#endif
+#ifndef NO_CS4612
+#define PLLCC_LPF_25580_64530_KHZ               0x00000000
+#define PLLCC_LPF_14360_37270_KHZ               0x00000008
+#define PLLCC_LPF_6100_16020_KHZ                0x00000018
+#define PLLCC_LPF_2540_6690_KHZ                 0x00000038
+#define PLLCC_LPF_1050_2780_KHZ                 0x00000078
+#define PLLCC_LPF_450_1160_KHZ                  0x000000F8
+#endif
+
+/*
+ *  The following defines are for the flags in the feature reporting register.
+ */
+#define FRR_FAB_MASK                            0x00000003
+#define FRR_MASK_MASK                           0x0000001C
+#ifdef NO_CS4612
+#define FRR_CFOP_MASK                           0x000000E0
+#else
+#define FRR_CFOP_MASK                           0x00000FE0
+#endif
+#define FRR_CFOP_NOT_DVD                        0x00000020
+#define FRR_CFOP_A3D                            0x00000040
+#define FRR_CFOP_128_PIN                        0x00000080
+#ifndef NO_CS4612
+#define FRR_CFOP_CS4280                         0x00000800
+#endif
+#define FRR_FAB_SHIFT                           0
+#define FRR_MASK_SHIFT                          2
+#define FRR_CFOP_SHIFT                          5
+
+/*
+ *  The following defines are for the flags in the configuration load 1
+ *  register.
+ */
+#define CFL1_CLOCK_SOURCE_MASK                  0x00000003
+#define CFL1_CLOCK_SOURCE_CS423X                0x00000000
+#define CFL1_CLOCK_SOURCE_AC97                  0x00000001
+#define CFL1_CLOCK_SOURCE_CRYSTAL               0x00000002
+#define CFL1_CLOCK_SOURCE_DUAL_AC97             0x00000003
+#define CFL1_VALID_DATA_MASK                    0x000000FF
+
+/*
+ *  The following defines are for the flags in the configuration load 2
+ *  register.
+ */
+#define CFL2_VALID_DATA_MASK                    0x000000FF
+
+/*
+ *  The following defines are for the flags in the serial port master control
+ *  register 1.
+ */
+#define SERMC1_MSPE                             0x00000001
+#define SERMC1_PTC_MASK                         0x0000000E
+#define SERMC1_PTC_CS423X                       0x00000000
+#define SERMC1_PTC_AC97                         0x00000002
+#define SERMC1_PTC_DAC                          0x00000004
+#define SERMC1_PLB                              0x00000010
+#define SERMC1_XLB                              0x00000020
+
+/*
+ *  The following defines are for the flags in the serial port master control
+ *  register 2.
+ */
+#define SERMC2_LROE                             0x00000001
+#define SERMC2_MCOE                             0x00000002
+#define SERMC2_MCDIV                            0x00000004
+
+/*
+ *  The following defines are for the flags in the serial port 1 configuration
+ *  register.
+ */
+#define SERC1_SO1EN                             0x00000001
+#define SERC1_SO1F_MASK                         0x0000000E
+#define SERC1_SO1F_CS423X                       0x00000000
+#define SERC1_SO1F_AC97                         0x00000002
+#define SERC1_SO1F_DAC                          0x00000004
+#define SERC1_SO1F_SPDIF                        0x00000006
+
+/*
+ *  The following defines are for the flags in the serial port 2 configuration
+ *  register.
+ */
+#define SERC2_SI1EN                             0x00000001
+#define SERC2_SI1F_MASK                         0x0000000E
+#define SERC2_SI1F_CS423X                       0x00000000
+#define SERC2_SI1F_AC97                         0x00000002
+#define SERC2_SI1F_ADC                          0x00000004
+#define SERC2_SI1F_SPDIF                        0x00000006
+
+/*
+ *  The following defines are for the flags in the serial port 3 configuration
+ *  register.
+ */
+#define SERC3_SO2EN                             0x00000001
+#define SERC3_SO2F_MASK                         0x00000006
+#define SERC3_SO2F_DAC                          0x00000000
+#define SERC3_SO2F_SPDIF                        0x00000002
+
+/*
+ *  The following defines are for the flags in the serial port 4 configuration
+ *  register.
+ */
+#define SERC4_SO3EN                             0x00000001
+#define SERC4_SO3F_MASK                         0x00000006
+#define SERC4_SO3F_DAC                          0x00000000
+#define SERC4_SO3F_SPDIF                        0x00000002
+
+/*
+ *  The following defines are for the flags in the serial port 5 configuration
+ *  register.
+ */
+#define SERC5_SI2EN                             0x00000001
+#define SERC5_SI2F_MASK                         0x00000006
+#define SERC5_SI2F_ADC                          0x00000000
+#define SERC5_SI2F_SPDIF                        0x00000002
+
+/*
+ *  The following defines are for the flags in the serial port backdoor sample
+ *  pointer register.
+ */
+#define SERBSP_FSP_MASK                         0x0000000F
+#define SERBSP_FSP_SHIFT                        0
+
+/*
+ *  The following defines are for the flags in the serial port backdoor status
+ *  register.
+ */
+#define SERBST_RRDY                             0x00000001
+#define SERBST_WBSY                             0x00000002
+
+/*
+ *  The following defines are for the flags in the serial port backdoor command
+ *  register.
+ */
+#define SERBCM_RDC                              0x00000001
+#define SERBCM_WRC                              0x00000002
+
+/*
+ *  The following defines are for the flags in the serial port backdoor address
+ *  register.
+ */
+#ifdef NO_CS4612
+#define SERBAD_FAD_MASK                         0x000000FF
+#else
+#define SERBAD_FAD_MASK                         0x000001FF
+#endif
+#define SERBAD_FAD_SHIFT                        0
+
+/*
+ *  The following defines are for the flags in the serial port backdoor
+ *  configuration register.
+ */
+#define SERBCF_HBP                              0x00000001
+
+/*
+ *  The following defines are for the flags in the serial port backdoor write
+ *  port register.
+ */
+#define SERBWP_FWD_MASK                         0x000FFFFF
+#define SERBWP_FWD_SHIFT                        0
+
+/*
+ *  The following defines are for the flags in the serial port backdoor read
+ *  port register.
+ */
+#define SERBRP_FRD_MASK                         0x000FFFFF
+#define SERBRP_FRD_SHIFT                        0
+
+/*
+ *  The following defines are for the flags in the async FIFO address register.
+ */
+#ifndef NO_CS4612
+#define ASER_FADDR_A1_MASK                      0x000001FF
+#define ASER_FADDR_EN1                          0x00008000
+#define ASER_FADDR_A2_MASK                      0x01FF0000
+#define ASER_FADDR_EN2                          0x80000000
+#define ASER_FADDR_A1_SHIFT                     0
+#define ASER_FADDR_A2_SHIFT                     16
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 control register.
+ */
+#define ACCTL_RSTN                              0x00000001
+#define ACCTL_ESYN                              0x00000002
+#define ACCTL_VFRM                              0x00000004
+#define ACCTL_DCV                               0x00000008
+#define ACCTL_CRW                               0x00000010
+#define ACCTL_ASYN                              0x00000020
+#ifndef NO_CS4612
+#define ACCTL_TC                                0x00000040
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 status register.
+ */
+#define ACSTS_CRDY                              0x00000001
+#define ACSTS_VSTS                              0x00000002
+#ifndef NO_CS4612
+#define ACSTS_WKUP                              0x00000004
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 output slot valid
+ *  register.
+ */
+#define ACOSV_SLV3                              0x00000001
+#define ACOSV_SLV4                              0x00000002
+#define ACOSV_SLV5                              0x00000004
+#define ACOSV_SLV6                              0x00000008
+#define ACOSV_SLV7                              0x00000010
+#define ACOSV_SLV8                              0x00000020
+#define ACOSV_SLV9                              0x00000040
+#define ACOSV_SLV10                             0x00000080
+#define ACOSV_SLV11                             0x00000100
+#define ACOSV_SLV12                             0x00000200
+
+/*
+ *  The following defines are for the flags in the AC97 command address
+ *  register.
+ */
+#define ACCAD_CI_MASK                           0x0000007F
+#define ACCAD_CI_SHIFT                          0
+
+/*
+ *  The following defines are for the flags in the AC97 command data register.
+ */
+#define ACCDA_CD_MASK                           0x0000FFFF
+#define ACCDA_CD_SHIFT                          0
+
+/*
+ *  The following defines are for the flags in the AC97 input slot valid
+ *  register.
+ */
+#define ACISV_ISV3                              0x00000001
+#define ACISV_ISV4                              0x00000002
+#define ACISV_ISV5                              0x00000004
+#define ACISV_ISV6                              0x00000008
+#define ACISV_ISV7                              0x00000010
+#define ACISV_ISV8                              0x00000020
+#define ACISV_ISV9                              0x00000040
+#define ACISV_ISV10                             0x00000080
+#define ACISV_ISV11                             0x00000100
+#define ACISV_ISV12                             0x00000200
+
+/*
+ *  The following defines are for the flags in the AC97 status address
+ *  register.
+ */
+#define ACSAD_SI_MASK                           0x0000007F
+#define ACSAD_SI_SHIFT                          0
+
+/*
+ *  The following defines are for the flags in the AC97 status data register.
+ */
+#define ACSDA_SD_MASK                           0x0000FFFF
+#define ACSDA_SD_SHIFT                          0
+
+/*
+ *  The following defines are for the flags in the joystick poll/trigger
+ *  register.
+ */
+#define JSPT_CAX                                0x00000001
+#define JSPT_CAY                                0x00000002
+#define JSPT_CBX                                0x00000004
+#define JSPT_CBY                                0x00000008
+#define JSPT_BA1                                0x00000010
+#define JSPT_BA2                                0x00000020
+#define JSPT_BB1                                0x00000040
+#define JSPT_BB2                                0x00000080
+
+/*
+ *  The following defines are for the flags in the joystick control register.
+ */
+#define JSCTL_SP_MASK                           0x00000003
+#define JSCTL_SP_SLOW                           0x00000000
+#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
+#define JSCTL_SP_MEDIUM_FAST                    0x00000002
+#define JSCTL_SP_FAST                           0x00000003
+#define JSCTL_ARE                               0x00000004
+
+/*
+ *  The following defines are for the flags in the joystick coordinate pair 1
+ *  readback register.
+ */
+#define JSC1_Y1V_MASK                           0x0000FFFF
+#define JSC1_X1V_MASK                           0xFFFF0000
+#define JSC1_Y1V_SHIFT                          0
+#define JSC1_X1V_SHIFT                          16
+
+/*
+ *  The following defines are for the flags in the joystick coordinate pair 2
+ *  readback register.
+ */
+#define JSC2_Y2V_MASK                           0x0000FFFF
+#define JSC2_X2V_MASK                           0xFFFF0000
+#define JSC2_Y2V_SHIFT                          0
+#define JSC2_X2V_SHIFT                          16
+
+/*
+ *  The following defines are for the flags in the MIDI control register.
+ */
+#define MIDCR_TXE                               0x00000001	/* Enable transmitting. */
+#define MIDCR_RXE                               0x00000002	/* Enable receiving. */
+#define MIDCR_RIE                               0x00000004	/* Interrupt upon tx ready. */
+#define MIDCR_TIE                               0x00000008	/* Interrupt upon rx ready. */
+#define MIDCR_MLB                               0x00000010	/* Enable midi loopback. */
+#define MIDCR_MRST                              0x00000020	/* Reset interface. */
+
+/*
+ *  The following defines are for the flags in the MIDI status register.
+ */
+#define MIDSR_TBF                               0x00000001	/* Tx FIFO is full. */
+#define MIDSR_RBE                               0x00000002	/* Rx FIFO is empty. */
+
+/*
+ *  The following defines are for the flags in the MIDI write port register.
+ */
+#define MIDWP_MWD_MASK                          0x000000FF
+#define MIDWP_MWD_SHIFT                         0
+
+/*
+ *  The following defines are for the flags in the MIDI read port register.
+ */
+#define MIDRP_MRD_MASK                          0x000000FF
+#define MIDRP_MRD_SHIFT                         0
+
+/*
+ *  The following defines are for the flags in the joystick GPIO register.
+ */
+#define JSIO_DAX                                0x00000001
+#define JSIO_DAY                                0x00000002
+#define JSIO_DBX                                0x00000004
+#define JSIO_DBY                                0x00000008
+#define JSIO_AXOE                               0x00000010
+#define JSIO_AYOE                               0x00000020
+#define JSIO_BXOE                               0x00000040
+#define JSIO_BYOE                               0x00000080
+
+/*
+ *  The following defines are for the flags in the master async/sync serial
+ *  port enable register.
+ */
+#ifndef NO_CS4612
+#define ASER_MASTER_ME                          0x00000001
+#endif
+
+/*
+ *  The following defines are for the flags in the configuration interface
+ *  register.
+ */
+#define CFGI_CLK                                0x00000001
+#define CFGI_DOUT                               0x00000002
+#define CFGI_DIN_EEN                            0x00000004
+#define CFGI_EELD                               0x00000008
+
+/*
+ *  The following defines are for the flags in the subsystem ID and vendor ID
+ *  register.
+ */
+#define SSVID_VID_MASK                          0x0000FFFF
+#define SSVID_SID_MASK                          0xFFFF0000
+#define SSVID_VID_SHIFT                         0
+#define SSVID_SID_SHIFT                         16
+
+/*
+ *  The following defines are for the flags in the GPIO pin interface register.
+ */
+#define GPIOR_VOLDN                             0x00000001
+#define GPIOR_VOLUP                             0x00000002
+#define GPIOR_SI2D                              0x00000004
+#define GPIOR_SI2OE                             0x00000008
+
+/*
+ *  The following defines are for the flags in the extended GPIO pin direction
+ *  register.
+ */
+#ifndef NO_CS4612
+#define EGPIODR_GPOE0                           0x00000001
+#define EGPIODR_GPOE1                           0x00000002
+#define EGPIODR_GPOE2                           0x00000004
+#define EGPIODR_GPOE3                           0x00000008
+#define EGPIODR_GPOE4                           0x00000010
+#define EGPIODR_GPOE5                           0x00000020
+#define EGPIODR_GPOE6                           0x00000040
+#define EGPIODR_GPOE7                           0x00000080
+#define EGPIODR_GPOE8                           0x00000100
+#endif
+
+/*
+ *  The following defines are for the flags in the extended GPIO pin polarity/
+ *  type register.
+ */
+#ifndef NO_CS4612
+#define EGPIOPTR_GPPT0                          0x00000001
+#define EGPIOPTR_GPPT1                          0x00000002
+#define EGPIOPTR_GPPT2                          0x00000004
+#define EGPIOPTR_GPPT3                          0x00000008
+#define EGPIOPTR_GPPT4                          0x00000010
+#define EGPIOPTR_GPPT5                          0x00000020
+#define EGPIOPTR_GPPT6                          0x00000040
+#define EGPIOPTR_GPPT7                          0x00000080
+#define EGPIOPTR_GPPT8                          0x00000100
+#endif
+
+/*
+ *  The following defines are for the flags in the extended GPIO pin sticky
+ *  register.
+ */
+#ifndef NO_CS4612
+#define EGPIOTR_GPS0                            0x00000001
+#define EGPIOTR_GPS1                            0x00000002
+#define EGPIOTR_GPS2                            0x00000004
+#define EGPIOTR_GPS3                            0x00000008
+#define EGPIOTR_GPS4                            0x00000010
+#define EGPIOTR_GPS5                            0x00000020
+#define EGPIOTR_GPS6                            0x00000040
+#define EGPIOTR_GPS7                            0x00000080
+#define EGPIOTR_GPS8                            0x00000100
+#endif
+
+/*
+ *  The following defines are for the flags in the extended GPIO ping wakeup
+ *  register.
+ */
+#ifndef NO_CS4612
+#define EGPIOWR_GPW0                            0x00000001
+#define EGPIOWR_GPW1                            0x00000002
+#define EGPIOWR_GPW2                            0x00000004
+#define EGPIOWR_GPW3                            0x00000008
+#define EGPIOWR_GPW4                            0x00000010
+#define EGPIOWR_GPW5                            0x00000020
+#define EGPIOWR_GPW6                            0x00000040
+#define EGPIOWR_GPW7                            0x00000080
+#define EGPIOWR_GPW8                            0x00000100
+#endif
+
+/*
+ *  The following defines are for the flags in the extended GPIO pin status
+ *  register.
+ */
+#ifndef NO_CS4612
+#define EGPIOSR_GPS0                            0x00000001
+#define EGPIOSR_GPS1                            0x00000002
+#define EGPIOSR_GPS2                            0x00000004
+#define EGPIOSR_GPS3                            0x00000008
+#define EGPIOSR_GPS4                            0x00000010
+#define EGPIOSR_GPS5                            0x00000020
+#define EGPIOSR_GPS6                            0x00000040
+#define EGPIOSR_GPS7                            0x00000080
+#define EGPIOSR_GPS8                            0x00000100
+#endif
+
+/*
+ *  The following defines are for the flags in the serial port 6 configuration
+ *  register.
+ */
+#ifndef NO_CS4612
+#define SERC6_ASDO2EN                           0x00000001
+#endif
+
+/*
+ *  The following defines are for the flags in the serial port 7 configuration
+ *  register.
+ */
+#ifndef NO_CS4612
+#define SERC7_ASDI2EN                           0x00000001
+#define SERC7_POSILB                            0x00000002
+#define SERC7_SIPOLB                            0x00000004
+#define SERC7_SOSILB                            0x00000008
+#define SERC7_SISOLB                            0x00000010
+#endif
+
+/*
+ *  The following defines are for the flags in the serial port AC link
+ *  configuration register.
+ */
+#ifndef NO_CS4612
+#define SERACC_CHIP_TYPE_MASK                  0x00000001
+#define SERACC_CHIP_TYPE_1_03                  0x00000000
+#define SERACC_CHIP_TYPE_2_0                   0x00000001
+#define SERACC_TWO_CODECS                      0x00000002
+#define SERACC_MDM                             0x00000004
+#define SERACC_HSP                             0x00000008
+#define SERACC_ODT                             0x00000010 /* only CS4630 */
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 control register 2.
+ */
+#ifndef NO_CS4612
+#define ACCTL2_RSTN                             0x00000001
+#define ACCTL2_ESYN                             0x00000002
+#define ACCTL2_VFRM                             0x00000004
+#define ACCTL2_DCV                              0x00000008
+#define ACCTL2_CRW                              0x00000010
+#define ACCTL2_ASYN                             0x00000020
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 status register 2.
+ */
+#ifndef NO_CS4612
+#define ACSTS2_CRDY                             0x00000001
+#define ACSTS2_VSTS                             0x00000002
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 output slot valid
+ *  register 2.
+ */
+#ifndef NO_CS4612
+#define ACOSV2_SLV3                             0x00000001
+#define ACOSV2_SLV4                             0x00000002
+#define ACOSV2_SLV5                             0x00000004
+#define ACOSV2_SLV6                             0x00000008
+#define ACOSV2_SLV7                             0x00000010
+#define ACOSV2_SLV8                             0x00000020
+#define ACOSV2_SLV9                             0x00000040
+#define ACOSV2_SLV10                            0x00000080
+#define ACOSV2_SLV11                            0x00000100
+#define ACOSV2_SLV12                            0x00000200
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 command address
+ *  register 2.
+ */
+#ifndef NO_CS4612
+#define ACCAD2_CI_MASK                          0x0000007F
+#define ACCAD2_CI_SHIFT                         0
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 command data register
+ *  2.
+ */
+#ifndef NO_CS4612
+#define ACCDA2_CD_MASK                          0x0000FFFF
+#define ACCDA2_CD_SHIFT                         0  
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 input slot valid
+ *  register 2.
+ */
+#ifndef NO_CS4612
+#define ACISV2_ISV3                             0x00000001
+#define ACISV2_ISV4                             0x00000002
+#define ACISV2_ISV5                             0x00000004
+#define ACISV2_ISV6                             0x00000008
+#define ACISV2_ISV7                             0x00000010
+#define ACISV2_ISV8                             0x00000020
+#define ACISV2_ISV9                             0x00000040
+#define ACISV2_ISV10                            0x00000080
+#define ACISV2_ISV11                            0x00000100
+#define ACISV2_ISV12                            0x00000200
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 status address
+ *  register 2.
+ */
+#ifndef NO_CS4612
+#define ACSAD2_SI_MASK                          0x0000007F
+#define ACSAD2_SI_SHIFT                         0
+#endif
+
+/*
+ *  The following defines are for the flags in the AC97 status data register 2.
+ */
+#ifndef NO_CS4612
+#define ACSDA2_SD_MASK                          0x0000FFFF
+#define ACSDA2_SD_SHIFT                         0
+#endif
+
+/*
+ *  The following defines are for the flags in the I/O trap address and control
+ *  registers (all 12).
+ */
+#ifndef NO_CS4612
+#define IOTAC_SA_MASK                           0x0000FFFF
+#define IOTAC_MSK_MASK                          0x000F0000
+#define IOTAC_IODC_MASK                         0x06000000
+#define IOTAC_IODC_16_BIT                       0x00000000
+#define IOTAC_IODC_10_BIT                       0x02000000
+#define IOTAC_IODC_12_BIT                       0x04000000
+#define IOTAC_WSPI                              0x08000000
+#define IOTAC_RSPI                              0x10000000
+#define IOTAC_WSE                               0x20000000
+#define IOTAC_WE                                0x40000000
+#define IOTAC_RE                                0x80000000
+#define IOTAC_SA_SHIFT                          0
+#define IOTAC_MSK_SHIFT                         16
+#endif
+
+/*
+ *  The following defines are for the flags in the I/O trap fast read registers
+ *  (all 8).
+ */
+#ifndef NO_CS4612
+#define IOTFR_D_MASK                            0x0000FFFF
+#define IOTFR_A_MASK                            0x000F0000
+#define IOTFR_R_MASK                            0x0F000000
+#define IOTFR_ALL                               0x40000000
+#define IOTFR_VL                                0x80000000
+#define IOTFR_D_SHIFT                           0
+#define IOTFR_A_SHIFT                           16
+#define IOTFR_R_SHIFT                           24
+#endif
+
+/*
+ *  The following defines are for the flags in the I/O trap FIFO register.
+ */
+#ifndef NO_CS4612
+#define IOTFIFO_BA_MASK                         0x00003FFF
+#define IOTFIFO_S_MASK                          0x00FF0000
+#define IOTFIFO_OF                              0x40000000
+#define IOTFIFO_SPIOF                           0x80000000
+#define IOTFIFO_BA_SHIFT                        0
+#define IOTFIFO_S_SHIFT                         16
+#endif
+
+/*
+ *  The following defines are for the flags in the I/O trap retry read data
+ *  register.
+ */
+#ifndef NO_CS4612
+#define IOTRRD_D_MASK                           0x0000FFFF
+#define IOTRRD_RDV                              0x80000000
+#define IOTRRD_D_SHIFT                          0
+#endif
+
+/*
+ *  The following defines are for the flags in the I/O trap FIFO pointer
+ *  register.
+ */
+#ifndef NO_CS4612
+#define IOTFP_CA_MASK                           0x00003FFF
+#define IOTFP_PA_MASK                           0x3FFF0000
+#define IOTFP_CA_SHIFT                          0
+#define IOTFP_PA_SHIFT                          16
+#endif
+
+/*
+ *  The following defines are for the flags in the I/O trap control register.
+ */
+#ifndef NO_CS4612
+#define IOTCR_ITD                               0x00000001
+#define IOTCR_HRV                               0x00000002
+#define IOTCR_SRV                               0x00000004
+#define IOTCR_DTI                               0x00000008
+#define IOTCR_DFI                               0x00000010
+#define IOTCR_DDP                               0x00000020
+#define IOTCR_JTE                               0x00000040
+#define IOTCR_PPE                               0x00000080
+#endif
+
+/*
+ *  The following defines are for the flags in the direct PCI data register.
+ */
+#ifndef NO_CS4612
+#define DPCID_D_MASK                            0xFFFFFFFF
+#define DPCID_D_SHIFT                           0
+#endif
+
+/*
+ *  The following defines are for the flags in the direct PCI address register.
+ */
+#ifndef NO_CS4612
+#define DPCIA_A_MASK                            0xFFFFFFFF
+#define DPCIA_A_SHIFT                           0
+#endif
+
+/*
+ *  The following defines are for the flags in the direct PCI command register.
+ */
+#ifndef NO_CS4612
+#define DPCIC_C_MASK                            0x0000000F
+#define DPCIC_C_IOREAD                          0x00000002
+#define DPCIC_C_IOWRITE                         0x00000003
+#define DPCIC_BE_MASK                           0x000000F0
+#endif
+
+/*
+ *  The following defines are for the flags in the PC/PCI request register.
+ */
+#ifndef NO_CS4612
+#define PCPCIR_RDC_MASK                         0x00000007
+#define PCPCIR_C_MASK                           0x00007000
+#define PCPCIR_REQ                              0x00008000
+#define PCPCIR_RDC_SHIFT                        0
+#define PCPCIR_C_SHIFT                          12
+#endif
+
+/*
+ *  The following defines are for the flags in the PC/PCI grant register.
+ */ 
+#ifndef NO_CS4612
+#define PCPCIG_GDC_MASK                         0x00000007
+#define PCPCIG_VL                               0x00008000
+#define PCPCIG_GDC_SHIFT                        0
+#endif
+
+/*
+ *  The following defines are for the flags in the PC/PCI master enable
+ *  register.
+ */
+#ifndef NO_CS4612
+#define PCPCIEN_EN                              0x00000001
+#endif
+
+/*
+ *  The following defines are for the flags in the extended PCI power
+ *  management control register.
+ */
+#ifndef NO_CS4612
+#define EPCIPMC_GWU                             0x00000001
+#define EPCIPMC_FSPC                            0x00000002
+#endif 
+
+/*
+ *  The following defines are for the flags in the SP control register.
+ */
+#define SPCR_RUN                                0x00000001
+#define SPCR_STPFR                              0x00000002
+#define SPCR_RUNFR                              0x00000004
+#define SPCR_TICK                               0x00000008
+#define SPCR_DRQEN                              0x00000020
+#define SPCR_RSTSP                              0x00000040
+#define SPCR_OREN                               0x00000080
+#ifndef NO_CS4612
+#define SPCR_PCIINT                             0x00000100
+#define SPCR_OINTD                              0x00000200
+#define SPCR_CRE                                0x00008000
+#endif
+
+/*
+ *  The following defines are for the flags in the debug index register.
+ */
+#define DREG_REGID_MASK                         0x0000007F
+#define DREG_DEBUG                              0x00000080
+#define DREG_RGBK_MASK                          0x00000700
+#define DREG_TRAP                               0x00000800
+#if !defined(NO_CS4612)
+#if !defined(NO_CS4615)
+#define DREG_TRAPX                              0x00001000
+#endif
+#endif
+#define DREG_REGID_SHIFT                        0
+#define DREG_RGBK_SHIFT                         8
+#define DREG_RGBK_REGID_MASK                    0x0000077F
+#define DREG_REGID_R0                           0x00000010
+#define DREG_REGID_R1                           0x00000011
+#define DREG_REGID_R2                           0x00000012
+#define DREG_REGID_R3                           0x00000013
+#define DREG_REGID_R4                           0x00000014
+#define DREG_REGID_R5                           0x00000015
+#define DREG_REGID_R6                           0x00000016
+#define DREG_REGID_R7                           0x00000017
+#define DREG_REGID_R8                           0x00000018
+#define DREG_REGID_R9                           0x00000019
+#define DREG_REGID_RA                           0x0000001A
+#define DREG_REGID_RB                           0x0000001B
+#define DREG_REGID_RC                           0x0000001C
+#define DREG_REGID_RD                           0x0000001D
+#define DREG_REGID_RE                           0x0000001E
+#define DREG_REGID_RF                           0x0000001F
+#define DREG_REGID_RA_BUS_LOW                   0x00000020
+#define DREG_REGID_RA_BUS_HIGH                  0x00000038
+#define DREG_REGID_YBUS_LOW                     0x00000050
+#define DREG_REGID_YBUS_HIGH                    0x00000058
+#define DREG_REGID_TRAP_0                       0x00000100
+#define DREG_REGID_TRAP_1                       0x00000101
+#define DREG_REGID_TRAP_2                       0x00000102
+#define DREG_REGID_TRAP_3                       0x00000103
+#define DREG_REGID_TRAP_4                       0x00000104
+#define DREG_REGID_TRAP_5                       0x00000105
+#define DREG_REGID_TRAP_6                       0x00000106
+#define DREG_REGID_TRAP_7                       0x00000107
+#define DREG_REGID_INDIRECT_ADDRESS             0x0000010E
+#define DREG_REGID_TOP_OF_STACK                 0x0000010F
+#if !defined(NO_CS4612)
+#if !defined(NO_CS4615)
+#define DREG_REGID_TRAP_8                       0x00000110
+#define DREG_REGID_TRAP_9                       0x00000111
+#define DREG_REGID_TRAP_10                      0x00000112
+#define DREG_REGID_TRAP_11                      0x00000113
+#define DREG_REGID_TRAP_12                      0x00000114
+#define DREG_REGID_TRAP_13                      0x00000115
+#define DREG_REGID_TRAP_14                      0x00000116
+#define DREG_REGID_TRAP_15                      0x00000117
+#define DREG_REGID_TRAP_16                      0x00000118
+#define DREG_REGID_TRAP_17                      0x00000119
+#define DREG_REGID_TRAP_18                      0x0000011A
+#define DREG_REGID_TRAP_19                      0x0000011B
+#define DREG_REGID_TRAP_20                      0x0000011C
+#define DREG_REGID_TRAP_21                      0x0000011D
+#define DREG_REGID_TRAP_22                      0x0000011E
+#define DREG_REGID_TRAP_23                      0x0000011F
+#endif
+#endif
+#define DREG_REGID_RSA0_LOW                     0x00000200
+#define DREG_REGID_RSA0_HIGH                    0x00000201
+#define DREG_REGID_RSA1_LOW                     0x00000202
+#define DREG_REGID_RSA1_HIGH                    0x00000203
+#define DREG_REGID_RSA2                         0x00000204
+#define DREG_REGID_RSA3                         0x00000205
+#define DREG_REGID_RSI0_LOW                     0x00000206
+#define DREG_REGID_RSI0_HIGH                    0x00000207
+#define DREG_REGID_RSI1                         0x00000208
+#define DREG_REGID_RSI2                         0x00000209
+#define DREG_REGID_SAGUSTATUS                   0x0000020A
+#define DREG_REGID_RSCONFIG01_LOW               0x0000020B
+#define DREG_REGID_RSCONFIG01_HIGH              0x0000020C
+#define DREG_REGID_RSCONFIG23_LOW               0x0000020D
+#define DREG_REGID_RSCONFIG23_HIGH              0x0000020E
+#define DREG_REGID_RSDMA01E                     0x0000020F
+#define DREG_REGID_RSDMA23E                     0x00000210
+#define DREG_REGID_RSD0_LOW                     0x00000211
+#define DREG_REGID_RSD0_HIGH                    0x00000212
+#define DREG_REGID_RSD1_LOW                     0x00000213
+#define DREG_REGID_RSD1_HIGH                    0x00000214
+#define DREG_REGID_RSD2_LOW                     0x00000215
+#define DREG_REGID_RSD2_HIGH                    0x00000216
+#define DREG_REGID_RSD3_LOW                     0x00000217
+#define DREG_REGID_RSD3_HIGH                    0x00000218
+#define DREG_REGID_SRAR_HIGH                    0x0000021A
+#define DREG_REGID_SRAR_LOW                     0x0000021B
+#define DREG_REGID_DMA_STATE                    0x0000021C
+#define DREG_REGID_CURRENT_DMA_STREAM           0x0000021D
+#define DREG_REGID_NEXT_DMA_STREAM              0x0000021E
+#define DREG_REGID_CPU_STATUS                   0x00000300
+#define DREG_REGID_MAC_MODE                     0x00000301
+#define DREG_REGID_STACK_AND_REPEAT             0x00000302
+#define DREG_REGID_INDEX0                       0x00000304
+#define DREG_REGID_INDEX1                       0x00000305
+#define DREG_REGID_DMA_STATE_0_3                0x00000400
+#define DREG_REGID_DMA_STATE_4_7                0x00000404
+#define DREG_REGID_DMA_STATE_8_11               0x00000408
+#define DREG_REGID_DMA_STATE_12_15              0x0000040C
+#define DREG_REGID_DMA_STATE_16_19              0x00000410
+#define DREG_REGID_DMA_STATE_20_23              0x00000414
+#define DREG_REGID_DMA_STATE_24_27              0x00000418
+#define DREG_REGID_DMA_STATE_28_31              0x0000041C
+#define DREG_REGID_DMA_STATE_32_35              0x00000420
+#define DREG_REGID_DMA_STATE_36_39              0x00000424
+#define DREG_REGID_DMA_STATE_40_43              0x00000428
+#define DREG_REGID_DMA_STATE_44_47              0x0000042C
+#define DREG_REGID_DMA_STATE_48_51              0x00000430
+#define DREG_REGID_DMA_STATE_52_55              0x00000434
+#define DREG_REGID_DMA_STATE_56_59              0x00000438
+#define DREG_REGID_DMA_STATE_60_63              0x0000043C
+#define DREG_REGID_DMA_STATE_64_67              0x00000440
+#define DREG_REGID_DMA_STATE_68_71              0x00000444
+#define DREG_REGID_DMA_STATE_72_75              0x00000448
+#define DREG_REGID_DMA_STATE_76_79              0x0000044C
+#define DREG_REGID_DMA_STATE_80_83              0x00000450
+#define DREG_REGID_DMA_STATE_84_87              0x00000454
+#define DREG_REGID_DMA_STATE_88_91              0x00000458
+#define DREG_REGID_DMA_STATE_92_95              0x0000045C
+#define DREG_REGID_TRAP_SELECT                  0x00000500
+#define DREG_REGID_TRAP_WRITE_0                 0x00000500
+#define DREG_REGID_TRAP_WRITE_1                 0x00000501
+#define DREG_REGID_TRAP_WRITE_2                 0x00000502
+#define DREG_REGID_TRAP_WRITE_3                 0x00000503
+#define DREG_REGID_TRAP_WRITE_4                 0x00000504
+#define DREG_REGID_TRAP_WRITE_5                 0x00000505
+#define DREG_REGID_TRAP_WRITE_6                 0x00000506
+#define DREG_REGID_TRAP_WRITE_7                 0x00000507
+#if !defined(NO_CS4612)
+#if !defined(NO_CS4615)
+#define DREG_REGID_TRAP_WRITE_8                 0x00000510
+#define DREG_REGID_TRAP_WRITE_9                 0x00000511
+#define DREG_REGID_TRAP_WRITE_10                0x00000512
+#define DREG_REGID_TRAP_WRITE_11                0x00000513
+#define DREG_REGID_TRAP_WRITE_12                0x00000514
+#define DREG_REGID_TRAP_WRITE_13                0x00000515
+#define DREG_REGID_TRAP_WRITE_14                0x00000516
+#define DREG_REGID_TRAP_WRITE_15                0x00000517
+#define DREG_REGID_TRAP_WRITE_16                0x00000518
+#define DREG_REGID_TRAP_WRITE_17                0x00000519
+#define DREG_REGID_TRAP_WRITE_18                0x0000051A
+#define DREG_REGID_TRAP_WRITE_19                0x0000051B
+#define DREG_REGID_TRAP_WRITE_20                0x0000051C
+#define DREG_REGID_TRAP_WRITE_21                0x0000051D
+#define DREG_REGID_TRAP_WRITE_22                0x0000051E
+#define DREG_REGID_TRAP_WRITE_23                0x0000051F
+#endif
+#endif
+#define DREG_REGID_MAC0_ACC0_LOW                0x00000600
+#define DREG_REGID_MAC0_ACC1_LOW                0x00000601
+#define DREG_REGID_MAC0_ACC2_LOW                0x00000602
+#define DREG_REGID_MAC0_ACC3_LOW                0x00000603
+#define DREG_REGID_MAC1_ACC0_LOW                0x00000604
+#define DREG_REGID_MAC1_ACC1_LOW                0x00000605
+#define DREG_REGID_MAC1_ACC2_LOW                0x00000606
+#define DREG_REGID_MAC1_ACC3_LOW                0x00000607
+#define DREG_REGID_MAC0_ACC0_MID                0x00000608
+#define DREG_REGID_MAC0_ACC1_MID                0x00000609
+#define DREG_REGID_MAC0_ACC2_MID                0x0000060A
+#define DREG_REGID_MAC0_ACC3_MID                0x0000060B
+#define DREG_REGID_MAC1_ACC0_MID                0x0000060C
+#define DREG_REGID_MAC1_ACC1_MID                0x0000060D
+#define DREG_REGID_MAC1_ACC2_MID                0x0000060E
+#define DREG_REGID_MAC1_ACC3_MID                0x0000060F
+#define DREG_REGID_MAC0_ACC0_HIGH               0x00000610
+#define DREG_REGID_MAC0_ACC1_HIGH               0x00000611
+#define DREG_REGID_MAC0_ACC2_HIGH               0x00000612
+#define DREG_REGID_MAC0_ACC3_HIGH               0x00000613
+#define DREG_REGID_MAC1_ACC0_HIGH               0x00000614
+#define DREG_REGID_MAC1_ACC1_HIGH               0x00000615
+#define DREG_REGID_MAC1_ACC2_HIGH               0x00000616
+#define DREG_REGID_MAC1_ACC3_HIGH               0x00000617
+#define DREG_REGID_RSHOUT_LOW                   0x00000620
+#define DREG_REGID_RSHOUT_MID                   0x00000628
+#define DREG_REGID_RSHOUT_HIGH                  0x00000630
+
+/*
+ *  The following defines are for the flags in the DMA stream requestor write
+ */
+#define DSRWP_DSR_MASK                          0x0000000F
+#define DSRWP_DSR_BG_RQ                         0x00000001
+#define DSRWP_DSR_PRIORITY_MASK                 0x00000006
+#define DSRWP_DSR_PRIORITY_0                    0x00000000
+#define DSRWP_DSR_PRIORITY_1                    0x00000002
+#define DSRWP_DSR_PRIORITY_2                    0x00000004
+#define DSRWP_DSR_PRIORITY_3                    0x00000006
+#define DSRWP_DSR_RQ_PENDING                    0x00000008
+
+/*
+ *  The following defines are for the flags in the trap write port register.
+ */
+#define TWPR_TW_MASK                            0x0000FFFF
+#define TWPR_TW_SHIFT                           0
+
+/*
+ *  The following defines are for the flags in the stack pointer write
+ *  register.
+ */
+#define SPWR_STKP_MASK                          0x0000000F
+#define SPWR_STKP_SHIFT                         0
+
+/*
+ *  The following defines are for the flags in the SP interrupt register.
+ */
+#define SPIR_FRI                                0x00000001
+#define SPIR_DOI                                0x00000002
+#define SPIR_GPI2                               0x00000004
+#define SPIR_GPI3                               0x00000008
+#define SPIR_IP0                                0x00000010
+#define SPIR_IP1                                0x00000020
+#define SPIR_IP2                                0x00000040
+#define SPIR_IP3                                0x00000080
+
+/*
+ *  The following defines are for the flags in the functional group 1 register.
+ */
+#define FGR1_F1S_MASK                           0x0000FFFF
+#define FGR1_F1S_SHIFT                          0
+
+/*
+ *  The following defines are for the flags in the SP clock status register.
+ */
+#define SPCS_FRI                                0x00000001
+#define SPCS_DOI                                0x00000002
+#define SPCS_GPI2                               0x00000004
+#define SPCS_GPI3                               0x00000008
+#define SPCS_IP0                                0x00000010
+#define SPCS_IP1                                0x00000020
+#define SPCS_IP2                                0x00000040
+#define SPCS_IP3                                0x00000080
+#define SPCS_SPRUN                              0x00000100
+#define SPCS_SLEEP                              0x00000200
+#define SPCS_FG                                 0x00000400
+#define SPCS_ORUN                               0x00000800
+#define SPCS_IRQ                                0x00001000
+#define SPCS_FGN_MASK                           0x0000E000
+#define SPCS_FGN_SHIFT                          13
+
+/*
+ *  The following defines are for the flags in the SP DMA requestor status
+ *  register.
+ */
+#define SDSR_DCS_MASK                           0x000000FF
+#define SDSR_DCS_SHIFT                          0
+#define SDSR_DCS_NONE                           0x00000007
+
+/*
+ *  The following defines are for the flags in the frame timer register.
+ */
+#define FRMT_FTV_MASK                           0x0000FFFF
+#define FRMT_FTV_SHIFT                          0
+
+/*
+ *  The following defines are for the flags in the frame timer current count
+ *  register.
+ */
+#define FRCC_FCC_MASK                           0x0000FFFF
+#define FRCC_FCC_SHIFT                          0
+
+/*
+ *  The following defines are for the flags in the frame timer save count
+ *  register.
+ */
+#define FRSC_FCS_MASK                           0x0000FFFF
+#define FRSC_FCS_SHIFT                          0
+
+/*
+ *  The following define the various flags stored in the scatter/gather
+ *  descriptors.
+ */
+#define DMA_SG_NEXT_ENTRY_MASK                  0x00000FF8
+#define DMA_SG_SAMPLE_END_MASK                  0x0FFF0000
+#define DMA_SG_SAMPLE_END_FLAG                  0x10000000
+#define DMA_SG_LOOP_END_FLAG                    0x20000000
+#define DMA_SG_SIGNAL_END_FLAG                  0x40000000
+#define DMA_SG_SIGNAL_PAGE_FLAG                 0x80000000
+#define DMA_SG_NEXT_ENTRY_SHIFT                 3
+#define DMA_SG_SAMPLE_END_SHIFT                 16
+
+/*
+ *  The following define the offsets of the fields within the on-chip generic
+ *  DMA requestor.
+ */
+#define DMA_RQ_CONTROL1                         0x00000000
+#define DMA_RQ_CONTROL2                         0x00000004
+#define DMA_RQ_SOURCE_ADDR                      0x00000008
+#define DMA_RQ_DESTINATION_ADDR                 0x0000000C
+#define DMA_RQ_NEXT_PAGE_ADDR                   0x00000010
+#define DMA_RQ_NEXT_PAGE_SGDESC                 0x00000014
+#define DMA_RQ_LOOP_START_ADDR                  0x00000018
+#define DMA_RQ_POST_LOOP_ADDR                   0x0000001C
+#define DMA_RQ_PAGE_MAP_ADDR                    0x00000020
+
+/*
+ *  The following defines are for the flags in the first control word of the
+ *  on-chip generic DMA requestor.
+ */
+#define DMA_RQ_C1_COUNT_MASK                    0x000003FF
+#define DMA_RQ_C1_DESTINATION_SCATTER           0x00001000
+#define DMA_RQ_C1_SOURCE_GATHER                 0x00002000
+#define DMA_RQ_C1_DONE_FLAG                     0x00004000
+#define DMA_RQ_C1_OPTIMIZE_STATE                0x00008000
+#define DMA_RQ_C1_SAMPLE_END_STATE_MASK         0x00030000
+#define DMA_RQ_C1_FULL_PAGE                     0x00000000
+#define DMA_RQ_C1_BEFORE_SAMPLE_END             0x00010000
+#define DMA_RQ_C1_PAGE_MAP_ERROR                0x00020000
+#define DMA_RQ_C1_AT_SAMPLE_END                 0x00030000
+#define DMA_RQ_C1_LOOP_END_STATE_MASK           0x000C0000
+#define DMA_RQ_C1_NOT_LOOP_END                  0x00000000
+#define DMA_RQ_C1_BEFORE_LOOP_END               0x00040000
+#define DMA_RQ_C1_2PAGE_LOOP_BEGIN              0x00080000
+#define DMA_RQ_C1_LOOP_BEGIN                    0x000C0000
+#define DMA_RQ_C1_PAGE_MAP_MASK                 0x00300000
+#define DMA_RQ_C1_PM_NONE_PENDING               0x00000000
+#define DMA_RQ_C1_PM_NEXT_PENDING               0x00100000
+#define DMA_RQ_C1_PM_RESERVED                   0x00200000
+#define DMA_RQ_C1_PM_LOOP_NEXT_PENDING          0x00300000
+#define DMA_RQ_C1_WRITEBACK_DEST_FLAG           0x00400000
+#define DMA_RQ_C1_WRITEBACK_SRC_FLAG            0x00800000
+#define DMA_RQ_C1_DEST_SIZE_MASK                0x07000000
+#define DMA_RQ_C1_DEST_LINEAR                   0x00000000
+#define DMA_RQ_C1_DEST_MOD16                    0x01000000
+#define DMA_RQ_C1_DEST_MOD32                    0x02000000
+#define DMA_RQ_C1_DEST_MOD64                    0x03000000
+#define DMA_RQ_C1_DEST_MOD128                   0x04000000
+#define DMA_RQ_C1_DEST_MOD256                   0x05000000
+#define DMA_RQ_C1_DEST_MOD512                   0x06000000
+#define DMA_RQ_C1_DEST_MOD1024                  0x07000000
+#define DMA_RQ_C1_DEST_ON_HOST                  0x08000000
+#define DMA_RQ_C1_SOURCE_SIZE_MASK              0x70000000
+#define DMA_RQ_C1_SOURCE_LINEAR                 0x00000000
+#define DMA_RQ_C1_SOURCE_MOD16                  0x10000000
+#define DMA_RQ_C1_SOURCE_MOD32                  0x20000000
+#define DMA_RQ_C1_SOURCE_MOD64                  0x30000000
+#define DMA_RQ_C1_SOURCE_MOD128                 0x40000000
+#define DMA_RQ_C1_SOURCE_MOD256                 0x50000000
+#define DMA_RQ_C1_SOURCE_MOD512                 0x60000000
+#define DMA_RQ_C1_SOURCE_MOD1024                0x70000000
+#define DMA_RQ_C1_SOURCE_ON_HOST                0x80000000
+#define DMA_RQ_C1_COUNT_SHIFT                   0
+
+/*
+ *  The following defines are for the flags in the second control word of the
+ *  on-chip generic DMA requestor.
+ */
+#define DMA_RQ_C2_VIRTUAL_CHANNEL_MASK          0x0000003F
+#define DMA_RQ_C2_VIRTUAL_SIGNAL_MASK           0x00000300
+#define DMA_RQ_C2_NO_VIRTUAL_SIGNAL             0x00000000
+#define DMA_RQ_C2_SIGNAL_EVERY_DMA              0x00000100
+#define DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG        0x00000200
+#define DMA_RQ_C2_SIGNAL_DEST_PINGPONG          0x00000300
+#define DMA_RQ_C2_AUDIO_CONVERT_MASK            0x0000F000
+#define DMA_RQ_C2_AC_NONE                       0x00000000
+#define DMA_RQ_C2_AC_8_TO_16_BIT                0x00001000
+#define DMA_RQ_C2_AC_MONO_TO_STEREO             0x00002000
+#define DMA_RQ_C2_AC_ENDIAN_CONVERT             0x00004000
+#define DMA_RQ_C2_AC_SIGNED_CONVERT             0x00008000
+#define DMA_RQ_C2_LOOP_END_MASK                 0x0FFF0000
+#define DMA_RQ_C2_LOOP_MASK                     0x30000000
+#define DMA_RQ_C2_NO_LOOP                       0x00000000
+#define DMA_RQ_C2_ONE_PAGE_LOOP                 0x10000000
+#define DMA_RQ_C2_TWO_PAGE_LOOP                 0x20000000
+#define DMA_RQ_C2_MULTI_PAGE_LOOP               0x30000000
+#define DMA_RQ_C2_SIGNAL_LOOP_BACK              0x40000000
+#define DMA_RQ_C2_SIGNAL_POST_BEGIN_PAGE        0x80000000
+#define DMA_RQ_C2_VIRTUAL_CHANNEL_SHIFT         0
+#define DMA_RQ_C2_LOOP_END_SHIFT                16
+
+/*
+ *  The following defines are for the flags in the source and destination words
+ *  of the on-chip generic DMA requestor.
+ */
+#define DMA_RQ_SD_ADDRESS_MASK                  0x0000FFFF
+#define DMA_RQ_SD_MEMORY_ID_MASK                0x000F0000
+#define DMA_RQ_SD_SP_PARAM_ADDR                 0x00000000
+#define DMA_RQ_SD_SP_SAMPLE_ADDR                0x00010000
+#define DMA_RQ_SD_SP_PROGRAM_ADDR               0x00020000
+#define DMA_RQ_SD_SP_DEBUG_ADDR                 0x00030000
+#define DMA_RQ_SD_OMNIMEM_ADDR                  0x000E0000
+#define DMA_RQ_SD_END_FLAG                      0x40000000
+#define DMA_RQ_SD_ERROR_FLAG                    0x80000000
+#define DMA_RQ_SD_ADDRESS_SHIFT                 0
+
+/*
+ *  The following defines are for the flags in the page map address word of the
+ *  on-chip generic DMA requestor.
+ */
+#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_MASK   0x00000FF8
+#define DMA_RQ_PMA_PAGE_TABLE_MASK              0xFFFFF000
+#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_SHIFT  3
+#define DMA_RQ_PMA_PAGE_TABLE_SHIFT             12
+
+#define BA1_VARIDEC_BUF_1       0x000
+
+#define BA1_PDTC                0x0c0    /* BA1_PLAY_DMA_TRANSACTION_COUNT_REG */
+#define BA1_PFIE                0x0c4    /* BA1_PLAY_FORMAT_&_INTERRUPT_ENABLE_REG */
+#define BA1_PBA                 0x0c8    /* BA1_PLAY_BUFFER_ADDRESS */
+#define BA1_PVOL                0x0f8    /* BA1_PLAY_VOLUME_REG */
+#define BA1_PSRC                0x288    /* BA1_PLAY_SAMPLE_RATE_CORRECTION_REG */
+#define BA1_PCTL                0x2a4    /* BA1_PLAY_CONTROL_REG */
+#define BA1_PPI                 0x2b4    /* BA1_PLAY_PHASE_INCREMENT_REG */
+
+#define BA1_CCTL                0x064    /* BA1_CAPTURE_CONTROL_REG */
+#define BA1_CIE                 0x104    /* BA1_CAPTURE_INTERRUPT_ENABLE_REG */
+#define BA1_CBA                 0x10c    /* BA1_CAPTURE_BUFFER_ADDRESS */
+#define BA1_CSRC                0x2c8    /* BA1_CAPTURE_SAMPLE_RATE_CORRECTION_REG */
+#define BA1_CCI                 0x2d8    /* BA1_CAPTURE_COEFFICIENT_INCREMENT_REG */
+#define BA1_CD                  0x2e0    /* BA1_CAPTURE_DELAY_REG */
+#define BA1_CPI                 0x2f4    /* BA1_CAPTURE_PHASE_INCREMENT_REG */
+#define BA1_CVOL                0x2f8    /* BA1_CAPTURE_VOLUME_REG */
+
+#define BA1_CFG1                0x134    /* BA1_CAPTURE_FRAME_GROUP_1_REG */
+#define BA1_CFG2                0x138    /* BA1_CAPTURE_FRAME_GROUP_2_REG */
+#define BA1_CCST                0x13c    /* BA1_CAPTURE_CONSTANT_REG */
+#define BA1_CSPB                0x340    /* BA1_CAPTURE_SPB_ADDRESS */
+
+/*
+ *
+ */
+
+#define CS46XX_MODE_OUTPUT	(1<<0)	 /* MIDI UART - output */ 
+#define CS46XX_MODE_INPUT	(1<<1)	 /* MIDI UART - input */
+
+/*
+ *
+ */
+
+#define SAVE_REG_MAX             0x10
+#define POWER_DOWN_ALL         0x7f0f
+
+/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+#define MAX_NR_AC97				            4
+#define CS46XX_PRIMARY_CODEC_INDEX          0
+#define CS46XX_SECONDARY_CODEC_INDEX		1
+#define CS46XX_SECONDARY_CODEC_OFFSET		0x80
+#define CS46XX_DSP_CAPTURE_CHANNEL          1
+
+/* capture */
+#define CS46XX_DSP_CAPTURE_CHANNEL          1
+
+/* mixer */
+#define CS46XX_MIXER_SPDIF_INPUT_ELEMENT    1
+#define CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT   2
+
+
+struct snd_cs46xx_pcm {
+	struct snd_dma_buffer hw_buf;
+  
+	unsigned int ctl;
+	unsigned int shift;	/* Shift count to trasform frames in bytes */
+	struct snd_pcm_indirect pcm_rec;
+	struct snd_pcm_substream *substream;
+
+	struct dsp_pcm_channel_descriptor * pcm_channel;
+
+	int pcm_channel_id;    /* Fron Rear, Center Lfe  ... */
+};
+
+struct snd_cs46xx_region {
+	char name[24];
+	unsigned long base;
+	void __iomem *remap_addr;
+	unsigned long size;
+	struct resource *resource;
+};
+
+struct snd_cs46xx {
+	int irq;
+	unsigned long ba0_addr;
+	unsigned long ba1_addr;
+	union {
+		struct {
+			struct snd_cs46xx_region ba0;
+			struct snd_cs46xx_region data0;
+			struct snd_cs46xx_region data1;
+			struct snd_cs46xx_region pmem;
+			struct snd_cs46xx_region reg;
+		} name;
+		struct snd_cs46xx_region idx[5];
+	} region;
+
+	unsigned int mode;
+	
+	struct {
+		struct snd_dma_buffer hw_buf;
+
+		unsigned int ctl;
+		unsigned int shift;	/* Shift count to trasform frames in bytes */
+		struct snd_pcm_indirect pcm_rec;
+		struct snd_pcm_substream *substream;
+	} capt;
+
+
+	int nr_ac97_codecs;
+	struct snd_ac97_bus *ac97_bus;
+	struct snd_ac97 *ac97[MAX_NR_AC97];
+
+	struct pci_dev *pci;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+
+	struct snd_rawmidi *rmidi;
+	struct snd_rawmidi_substream *midi_input;
+	struct snd_rawmidi_substream *midi_output;
+
+	spinlock_t reg_lock;
+	unsigned int midcr;
+	unsigned int uartm;
+
+	int amplifier;
+	void (*amplifier_ctrl)(struct snd_cs46xx *, int);
+	void (*active_ctrl)(struct snd_cs46xx *, int);
+  	void (*mixer_init)(struct snd_cs46xx *);
+
+	int acpi_port;
+	struct snd_kcontrol *eapd_switch; /* for amplifier hack */
+	int accept_valid;	/* accept mmap valid (for OSS) */
+	int in_suspend;
+
+	struct gameport *gameport;
+
+#ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
+	int current_gpio;
+#endif
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	struct mutex spos_mutex;
+
+	struct dsp_spos_instance * dsp_spos_instance;
+
+	struct snd_pcm *pcm_rear;
+	struct snd_pcm *pcm_center_lfe;
+	struct snd_pcm *pcm_iec958;
+#else /* for compatibility */
+	struct snd_cs46xx_pcm *playback_pcm;
+	unsigned int play_ctl;
+#endif
+};
+
+int snd_cs46xx_create(struct snd_card *card,
+		      struct pci_dev *pci,
+		      int external_amp, int thinkpad,
+		      struct snd_cs46xx **rcodec);
+int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state);
+int snd_cs46xx_resume(struct pci_dev *pci);
+
+int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
+int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
+int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
+int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
+int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device);
+int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rmidi);
+int snd_cs46xx_start_dsp(struct snd_cs46xx *chip);
+int snd_cs46xx_gameport(struct snd_cs46xx *chip);
+
+#endif /* __SOUND_CS46XX_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/cs46xx_dsp_spos.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/cs46xx_dsp_spos.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/cs46xx_dsp_spos.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/cs46xx_dsp_spos.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,230 @@
+/*
+ *  The driver for the Cirrus Logic's Sound Fusion CS46XX based soundcards
+ *  Copyright (c) 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
+ *
+ */
+
+#ifndef __CS46XX_DSP_SPOS_H__
+#define __CS46XX_DSP_SPOS_H__
+
+#include "cs46xx_dsp_scb_types.h"
+#include "cs46xx_dsp_task_types.h"
+
+#define SYMBOL_CONSTANT  0x0
+#define SYMBOL_SAMPLE    0x1
+#define SYMBOL_PARAMETER 0x2
+#define SYMBOL_CODE      0x3
+
+#define SEGTYPE_SP_PROGRAM              0x00000001
+#define SEGTYPE_SP_PARAMETER            0x00000002
+#define SEGTYPE_SP_SAMPLE               0x00000003
+#define SEGTYPE_SP_COEFFICIENT          0x00000004
+
+#define DSP_SPOS_UU      0x0deadul     /* unused */
+#define DSP_SPOS_DC      0x0badul      /* don't care */
+#define DSP_SPOS_DC_DC   0x0bad0badul  /* don't care */
+#define DSP_SPOS_UUUU    0xdeadc0edul  /* unused */
+#define DSP_SPOS_UUHI    0xdeadul
+#define DSP_SPOS_UULO    0xc0edul
+#define DSP_SPOS_DCDC    0x0badf1d0ul  /* don't care */
+#define DSP_SPOS_DCDCHI  0x0badul
+#define DSP_SPOS_DCDCLO  0xf1d0ul
+
+#define DSP_MAX_TASK_NAME   60
+#define DSP_MAX_SYMBOL_NAME 100
+#define DSP_MAX_SCB_NAME    60
+#define DSP_MAX_SCB_DESC    200
+#define DSP_MAX_TASK_DESC   50
+
+#define DSP_MAX_PCM_CHANNELS 32
+#define DSP_MAX_SRC_NR       14
+
+#define DSP_PCM_MAIN_CHANNEL        1
+#define DSP_PCM_REAR_CHANNEL        2
+#define DSP_PCM_CENTER_LFE_CHANNEL  3
+#define DSP_PCM_S71_CHANNEL         4 /* surround 7.1 */
+#define DSP_IEC958_CHANNEL          5
+
+#define DSP_SPDIF_STATUS_OUTPUT_ENABLED       1
+#define DSP_SPDIF_STATUS_PLAYBACK_OPEN        2
+#define DSP_SPDIF_STATUS_HW_ENABLED           4
+#define DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED   8
+
+struct dsp_symbol_entry {
+	u32 address;
+	char symbol_name[DSP_MAX_SYMBOL_NAME];
+	int symbol_type;
+
+	/* initialized by driver */
+	struct dsp_module_desc * module;
+	int deleted;
+};
+
+struct dsp_symbol_desc {
+	int nsymbols;
+
+	struct dsp_symbol_entry *symbols;
+
+	/* initialized by driver */
+	int highest_frag_index;
+};
+
+struct dsp_segment_desc {
+	int segment_type;
+	u32 offset;
+	u32 size;
+	u32 * data;
+};
+
+struct dsp_module_desc {
+	char * module_name;
+	struct dsp_symbol_desc symbol_table;
+	int nsegments;
+	struct dsp_segment_desc * segments;
+
+	/* initialized by driver */
+	u32 overlay_begin_address;
+	u32 load_address;
+	int nfixups;
+};
+
+struct dsp_scb_descriptor {
+	char scb_name[DSP_MAX_SCB_NAME];
+	u32 address;
+	int index;
+
+	struct dsp_scb_descriptor * sub_list_ptr;
+	struct dsp_scb_descriptor * next_scb_ptr;
+	struct dsp_scb_descriptor * parent_scb_ptr;
+
+	struct dsp_symbol_entry * task_entry;
+	struct dsp_symbol_entry * scb_symbol;
+
+	struct snd_info_entry *proc_info;
+	int ref_count;
+	spinlock_t lock;
+
+	int deleted;
+};
+
+struct dsp_task_descriptor {
+	char task_name[DSP_MAX_TASK_NAME];
+	int size;
+	u32 address;
+	int index;
+};
+
+struct dsp_pcm_channel_descriptor {
+	int active;
+	int src_slot;
+	int pcm_slot;
+	u32 sample_rate;
+	u32 unlinked;
+	struct dsp_scb_descriptor * pcm_reader_scb;
+	struct dsp_scb_descriptor * src_scb;
+	struct dsp_scb_descriptor * mixer_scb;
+
+	void * private_data;
+};
+
+struct dsp_spos_instance {
+	struct dsp_symbol_desc symbol_table; /* currently availble loaded symbols in SP */
+
+	int nmodules;
+	struct dsp_module_desc * modules; /* modules loaded into SP */
+
+	struct dsp_segment_desc code;
+
+	/* Main PCM playback mixer */
+	struct dsp_scb_descriptor * master_mix_scb;
+	u16 dac_volume_right;
+	u16 dac_volume_left;
+
+	/* Rear/surround PCM playback mixer */
+	struct dsp_scb_descriptor * rear_mix_scb;
+
+	/* Center/LFE mixer */
+	struct dsp_scb_descriptor * center_lfe_mix_scb;
+
+	int npcm_channels;
+	int nsrc_scb;
+	struct dsp_pcm_channel_descriptor pcm_channels[DSP_MAX_PCM_CHANNELS];
+	int src_scb_slots[DSP_MAX_SRC_NR];
+
+	/* cache this symbols */
+	struct dsp_symbol_entry * null_algorithm; /* used by PCMreaderSCB's */
+	struct dsp_symbol_entry * s16_up;         /* used by SRCtaskSCB's */
+
+	/* proc fs */  
+	struct snd_card *snd_card;
+	struct snd_info_entry * proc_dsp_dir;
+	struct snd_info_entry * proc_sym_info_entry;
+	struct snd_info_entry * proc_modules_info_entry;
+	struct snd_info_entry * proc_parameter_dump_info_entry;
+	struct snd_info_entry * proc_sample_dump_info_entry;
+
+	/* SCB's descriptors */
+	int nscb;
+	int scb_highest_frag_index;
+	struct dsp_scb_descriptor scbs[DSP_MAX_SCB_DESC];
+	struct snd_info_entry * proc_scb_info_entry;
+	struct dsp_scb_descriptor * the_null_scb;
+
+	/* Task's descriptors */
+	int ntask;
+	struct dsp_task_descriptor tasks[DSP_MAX_TASK_DESC];
+	struct snd_info_entry * proc_task_info_entry;
+
+	/* SPDIF status */
+	int spdif_status_out;
+	int spdif_status_in;
+	u16 spdif_input_volume_right;
+	u16 spdif_input_volume_left;
+	/* spdif channel status,
+	   left right and user validity bits */
+	unsigned int spdif_csuv_default;
+	unsigned int spdif_csuv_stream;
+
+	/* SPDIF input sample rate converter */
+	struct dsp_scb_descriptor * spdif_in_src;
+	/* SPDIF input asynch. receiver */
+	struct dsp_scb_descriptor * asynch_rx_scb;
+
+	/* Capture record mixer SCB */
+	struct dsp_scb_descriptor * record_mixer_scb;
+    
+	/* CODEC input SCB */
+	struct dsp_scb_descriptor * codec_in_scb;
+
+	/* reference snooper */
+	struct dsp_scb_descriptor * ref_snoop_scb;
+
+	/* SPDIF output  PCM reference  */
+	struct dsp_scb_descriptor * spdif_pcm_input_scb;
+
+	/* asynch TX task */
+	struct dsp_scb_descriptor * asynch_tx_scb;
+
+	/* record sources */
+	struct dsp_scb_descriptor * pcm_input;
+	struct dsp_scb_descriptor * adc_input;
+
+	int spdif_in_sample_rate;
+};
+
+#endif /* __DSP_SPOS_H__ */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/emu10k1.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/emu10k1.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/emu10k1.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/emu10k1.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,1993 @@
+#ifndef __SOUND_EMU10K1_H
+#define __SOUND_EMU10K1_H
+
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
+ *		     Creative Labs, Inc.
+ *  Definitions for EMU10K1 (SB Live!) chips
+ *
+ *
+ *   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
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <sound/pcm.h>
+#include <sound/rawmidi.h>
+#include <sound/hwdep.h>
+#include <sound/ac97_codec.h>
+#include <sound/util_mem.h>
+#include <sound/pcm-indirect.h>
+#include <sound/timer.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+/* ------------------- DEFINES -------------------- */
+
+#define EMUPAGESIZE     4096
+#define MAXREQVOICES    8
+#define MAXPAGES        8192
+#define RESERVED        0
+#define NUM_MIDI        16
+#define NUM_G           64              /* use all channels */
+#define NUM_FXSENDS     4
+#define NUM_EFX_PLAYBACK    16
+
+/* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */
+#define EMU10K1_DMA_MASK	0x7fffffffUL	/* 31bit */
+#define AUDIGY_DMA_MASK		0x7fffffffUL	/* 31bit FIXME - 32 should work? */
+						/* See ALSA bug #1276 - rlrevell */
+
+#define TMEMSIZE        256*1024
+#define TMEMSIZEREG     4
+
+#define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL))
+
+// Audigy specify registers are prefixed with 'A_'
+
+/************************************************************************************************/
+/* PCI function 0 registers, address = <val> + PCIBASE0						*/
+/************************************************************************************************/
+
+#define PTR			0x00		/* Indexed register set pointer register	*/
+						/* NOTE: The CHANNELNUM and ADDRESS words can	*/
+						/* be modified independently of each other.	*/
+#define PTR_CHANNELNUM_MASK	0x0000003f	/* For each per-channel register, indicates the	*/
+						/* channel number of the register to be		*/
+						/* accessed.  For non per-channel registers the	*/
+						/* value should be set to zero.			*/
+#define PTR_ADDRESS_MASK	0x07ff0000	/* Register index				*/
+#define A_PTR_ADDRESS_MASK	0x0fff0000
+
+#define DATA			0x04		/* Indexed register set data register		*/
+
+#define IPR			0x08		/* Global interrupt pending register		*/
+						/* Clear pending interrupts by writing a 1 to	*/
+						/* the relevant bits and zero to the other bits	*/
+#define IPR_P16V		0x80000000	/* Bit set when the CA0151 P16V chip wishes
+						   to interrupt */
+#define IPR_GPIOMSG		0x20000000	/* GPIO message interrupt (RE'd, still not sure 
+						   which INTE bits enable it)			*/
+
+/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1)			*/
+#define IPR_A_MIDITRANSBUFEMPTY2 0x10000000	/* MIDI UART transmit buffer empty		*/
+#define IPR_A_MIDIRECVBUFEMPTY2	0x08000000	/* MIDI UART receive buffer empty		*/
+
+#define IPR_SPDIFBUFFULL	0x04000000	/* SPDIF capture related, 10k2 only? (RE)	*/
+#define IPR_SPDIFBUFHALFFULL	0x02000000	/* SPDIF capture related? (RE)			*/
+
+#define IPR_SAMPLERATETRACKER	0x01000000	/* Sample rate tracker lock status change	*/
+#define IPR_FXDSP		0x00800000	/* Enable FX DSP interrupts			*/
+#define IPR_FORCEINT		0x00400000	/* Force Sound Blaster interrupt		*/
+#define IPR_PCIERROR		0x00200000	/* PCI bus error				*/
+#define IPR_VOLINCR		0x00100000	/* Volume increment button pressed		*/
+#define IPR_VOLDECR		0x00080000	/* Volume decrement button pressed		*/
+#define IPR_MUTE		0x00040000	/* Mute button pressed				*/
+#define IPR_MICBUFFULL		0x00020000	/* Microphone buffer full			*/
+#define IPR_MICBUFHALFFULL	0x00010000	/* Microphone buffer half full			*/
+#define IPR_ADCBUFFULL		0x00008000	/* ADC buffer full				*/
+#define IPR_ADCBUFHALFFULL	0x00004000	/* ADC buffer half full				*/
+#define IPR_EFXBUFFULL		0x00002000	/* Effects buffer full				*/
+#define IPR_EFXBUFHALFFULL	0x00001000	/* Effects buffer half full			*/
+#define IPR_GPSPDIFSTATUSCHANGE	0x00000800	/* GPSPDIF channel status change		*/
+#define IPR_CDROMSTATUSCHANGE	0x00000400	/* CD-ROM channel status change			*/
+#define IPR_INTERVALTIMER	0x00000200	/* Interval timer terminal count		*/
+#define IPR_MIDITRANSBUFEMPTY	0x00000100	/* MIDI UART transmit buffer empty		*/
+#define IPR_MIDIRECVBUFEMPTY	0x00000080	/* MIDI UART receive buffer empty		*/
+#define IPR_CHANNELLOOP		0x00000040	/* Channel (half) loop interrupt(s) pending	*/
+#define IPR_CHANNELNUMBERMASK	0x0000003f	/* When IPR_CHANNELLOOP is set, indicates the	*/
+						/* highest set channel in CLIPL, CLIPH, HLIPL,  */
+						/* or HLIPH.  When IP is written with CL set,	*/
+						/* the bit in H/CLIPL or H/CLIPH corresponding	*/
+						/* to the CIN value written will be cleared.	*/
+
+#define INTE			0x0c		/* Interrupt enable register			*/
+#define INTE_VIRTUALSB_MASK	0xc0000000	/* Virtual Soundblaster I/O port capture	*/
+#define INTE_VIRTUALSB_220	0x00000000	/* Capture at I/O base address 0x220-0x22f	*/
+#define INTE_VIRTUALSB_240	0x40000000	/* Capture at I/O base address 0x240		*/
+#define INTE_VIRTUALSB_260	0x80000000	/* Capture at I/O base address 0x260		*/
+#define INTE_VIRTUALSB_280	0xc0000000	/* Capture at I/O base address 0x280		*/
+#define INTE_VIRTUALMPU_MASK	0x30000000	/* Virtual MPU I/O port capture			*/
+#define INTE_VIRTUALMPU_300	0x00000000	/* Capture at I/O base address 0x300-0x301	*/
+#define INTE_VIRTUALMPU_310	0x10000000	/* Capture at I/O base address 0x310		*/
+#define INTE_VIRTUALMPU_320	0x20000000	/* Capture at I/O base address 0x320		*/
+#define INTE_VIRTUALMPU_330	0x30000000	/* Capture at I/O base address 0x330		*/
+#define INTE_MASTERDMAENABLE	0x08000000	/* Master DMA emulation at 0x000-0x00f		*/
+#define INTE_SLAVEDMAENABLE	0x04000000	/* Slave DMA emulation at 0x0c0-0x0df		*/
+#define INTE_MASTERPICENABLE	0x02000000	/* Master PIC emulation at 0x020-0x021		*/
+#define INTE_SLAVEPICENABLE	0x01000000	/* Slave PIC emulation at 0x0a0-0x0a1		*/
+#define INTE_VSBENABLE		0x00800000	/* Enable virtual Soundblaster			*/
+#define INTE_ADLIBENABLE	0x00400000	/* Enable AdLib emulation at 0x388-0x38b	*/
+#define INTE_MPUENABLE		0x00200000	/* Enable virtual MPU				*/
+#define INTE_FORCEINT		0x00100000	/* Continuously assert INTAN			*/
+
+#define INTE_MRHANDENABLE	0x00080000	/* Enable the "Mr. Hand" logic			*/
+						/* NOTE: There is no reason to use this under	*/
+						/* Linux, and it will cause odd hardware 	*/
+						/* behavior and possibly random segfaults and	*/
+						/* lockups if enabled.				*/
+
+/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1)			*/
+#define INTE_A_MIDITXENABLE2	0x00020000	/* Enable MIDI transmit-buffer-empty interrupts	*/
+#define INTE_A_MIDIRXENABLE2	0x00010000	/* Enable MIDI receive-buffer-empty interrupts	*/
+
+
+#define INTE_SAMPLERATETRACKER	0x00002000	/* Enable sample rate tracker interrupts	*/
+						/* NOTE: This bit must always be enabled       	*/
+#define INTE_FXDSPENABLE	0x00001000	/* Enable FX DSP interrupts			*/
+#define INTE_PCIERRORENABLE	0x00000800	/* Enable PCI bus error interrupts		*/
+#define INTE_VOLINCRENABLE	0x00000400	/* Enable volume increment button interrupts	*/
+#define INTE_VOLDECRENABLE	0x00000200	/* Enable volume decrement button interrupts	*/
+#define INTE_MUTEENABLE		0x00000100	/* Enable mute button interrupts		*/
+#define INTE_MICBUFENABLE	0x00000080	/* Enable microphone buffer interrupts		*/
+#define INTE_ADCBUFENABLE	0x00000040	/* Enable ADC buffer interrupts			*/
+#define INTE_EFXBUFENABLE	0x00000020	/* Enable Effects buffer interrupts		*/
+#define INTE_GPSPDIFENABLE	0x00000010	/* Enable GPSPDIF status interrupts		*/
+#define INTE_CDSPDIFENABLE	0x00000008	/* Enable CDSPDIF status interrupts		*/
+#define INTE_INTERVALTIMERENB	0x00000004	/* Enable interval timer interrupts		*/
+#define INTE_MIDITXENABLE	0x00000002	/* Enable MIDI transmit-buffer-empty interrupts	*/
+#define INTE_MIDIRXENABLE	0x00000001	/* Enable MIDI receive-buffer-empty interrupts	*/
+
+#define WC			0x10		/* Wall Clock register				*/
+#define WC_SAMPLECOUNTER_MASK	0x03FFFFC0	/* Sample periods elapsed since reset		*/
+#define WC_SAMPLECOUNTER	0x14060010
+#define WC_CURRENTCHANNEL	0x0000003F	/* Channel [0..63] currently being serviced	*/
+						/* NOTE: Each channel takes 1/64th of a sample	*/
+						/* period to be serviced.			*/
+
+#define HCFG			0x14		/* Hardware config register			*/
+						/* NOTE: There is no reason to use the legacy	*/
+						/* SoundBlaster emulation stuff described below	*/
+						/* under Linux, and all kinds of weird hardware	*/
+						/* behavior can result if you try.  Don't.	*/
+#define HCFG_LEGACYFUNC_MASK	0xe0000000	/* Legacy function number 			*/
+#define HCFG_LEGACYFUNC_MPU	0x00000000	/* Legacy MPU	 				*/
+#define HCFG_LEGACYFUNC_SB	0x40000000	/* Legacy SB					*/
+#define HCFG_LEGACYFUNC_AD	0x60000000	/* Legacy AD					*/
+#define HCFG_LEGACYFUNC_MPIC	0x80000000	/* Legacy MPIC					*/
+#define HCFG_LEGACYFUNC_MDMA	0xa0000000	/* Legacy MDMA					*/
+#define HCFG_LEGACYFUNC_SPCI	0xc0000000	/* Legacy SPCI					*/
+#define HCFG_LEGACYFUNC_SDMA	0xe0000000	/* Legacy SDMA					*/
+#define HCFG_IOCAPTUREADDR	0x1f000000	/* The 4 LSBs of the captured I/O address.	*/
+#define HCFG_LEGACYWRITE	0x00800000	/* 1 = write, 0 = read 				*/
+#define HCFG_LEGACYWORD		0x00400000	/* 1 = word, 0 = byte 				*/
+#define HCFG_LEGACYINT		0x00200000	/* 1 = legacy event captured. Write 1 to clear.	*/
+						/* NOTE: The rest of the bits in this register	*/
+						/* _are_ relevant under Linux.			*/
+#define HCFG_PUSH_BUTTON_ENABLE 0x00100000	/* Enables Volume Inc/Dec and Mute functions    */
+#define HCFG_BAUD_RATE		0x00080000	/* 0 = 48kHz, 1 = 44.1kHz			*/
+#define HCFG_EXPANDED_MEM	0x00040000	/* 1 = any 16M of 4G addr, 0 = 32M of 2G addr	*/
+#define HCFG_CODECFORMAT_MASK	0x00030000	/* CODEC format					*/
+
+/* Specific to Alice2, CA0102 */
+#define HCFG_CODECFORMAT_AC97_1	0x00000000	/* AC97 CODEC format -- Ver 1.03		*/
+#define HCFG_CODECFORMAT_AC97_2	0x00010000	/* AC97 CODEC format -- Ver 2.1			*/
+#define HCFG_AUTOMUTE_ASYNC	0x00008000	/* When set, the async sample rate convertors	*/
+						/* will automatically mute their output when	*/
+						/* they are not rate-locked to the external	*/
+						/* async audio source  				*/
+#define HCFG_AUTOMUTE_SPDIF	0x00004000	/* When set, the async sample rate convertors	*/
+						/* will automatically mute their output when	*/
+						/* the SPDIF V-bit indicates invalid audio	*/
+#define HCFG_EMU32_SLAVE	0x00002000	/* 0 = Master, 1 = Slave. Slave for EMU1010	*/
+#define HCFG_SLOW_RAMP		0x00001000	/* Increases Send Smoothing time constant	*/
+/* 0x00000800 not used on Alice2 */
+#define HCFG_PHASE_TRACK_MASK	0x00000700	/* When set, forces corresponding input to	*/
+						/* phase track the previous input.		*/
+						/* I2S0 can phase track the last S/PDIF input	*/
+#define HCFG_I2S_ASRC_ENABLE	0x00000070	/* When set, enables asynchronous sample rate   */
+						/* conversion for the corresponding		*/
+ 						/* I2S format input				*/
+/* Rest of HCFG 0x0000000f same as below. LOCKSOUNDCACHE etc.  */
+
+
+
+/* Older chips */
+#define HCFG_CODECFORMAT_AC97	0x00000000	/* AC97 CODEC format -- Primary Output		*/
+#define HCFG_CODECFORMAT_I2S	0x00010000	/* I2S CODEC format -- Secondary (Rear) Output	*/
+#define HCFG_GPINPUT0		0x00004000	/* External pin112				*/
+#define HCFG_GPINPUT1		0x00002000	/* External pin110				*/
+#define HCFG_GPOUTPUT_MASK	0x00001c00	/* External pins which may be controlled	*/
+#define HCFG_GPOUT0		0x00001000	/* External pin? (spdif enable on 5.1)		*/
+#define HCFG_GPOUT1		0x00000800	/* External pin? (IR)				*/
+#define HCFG_GPOUT2		0x00000400	/* External pin? (IR)				*/
+#define HCFG_JOYENABLE      	0x00000200	/* Internal joystick enable    			*/
+#define HCFG_PHASETRACKENABLE	0x00000100	/* Phase tracking enable			*/
+						/* 1 = Force all 3 async digital inputs to use	*/
+						/* the same async sample rate tracker (ZVIDEO)	*/
+#define HCFG_AC3ENABLE_MASK	0x000000e0	/* AC3 async input control - Not implemented	*/
+#define HCFG_AC3ENABLE_ZVIDEO	0x00000080	/* Channels 0 and 1 replace ZVIDEO		*/
+#define HCFG_AC3ENABLE_CDSPDIF	0x00000040	/* Channels 0 and 1 replace CDSPDIF		*/
+#define HCFG_AC3ENABLE_GPSPDIF  0x00000020      /* Channels 0 and 1 replace GPSPDIF             */
+#define HCFG_AUTOMUTE		0x00000010	/* When set, the async sample rate convertors	*/
+						/* will automatically mute their output when	*/
+						/* they are not rate-locked to the external	*/
+						/* async audio source  				*/
+#define HCFG_LOCKSOUNDCACHE	0x00000008	/* 1 = Cancel bustmaster accesses to soundcache */
+						/* NOTE: This should generally never be used.  	*/
+#define HCFG_LOCKTANKCACHE_MASK	0x00000004	/* 1 = Cancel bustmaster accesses to tankcache	*/
+						/* NOTE: This should generally never be used.  	*/
+#define HCFG_LOCKTANKCACHE	0x01020014
+#define HCFG_MUTEBUTTONENABLE	0x00000002	/* 1 = Master mute button sets AUDIOENABLE = 0.	*/
+						/* NOTE: This is a 'cheap' way to implement a	*/
+						/* master mute function on the mute button, and	*/
+						/* in general should not be used unless a more	*/
+						/* sophisticated master mute function has not	*/
+						/* been written.       				*/
+#define HCFG_AUDIOENABLE	0x00000001	/* 0 = CODECs transmit zero-valued samples	*/
+						/* Should be set to 1 when the EMU10K1 is	*/
+						/* completely initialized.			*/
+
+//For Audigy, MPU port move to 0x70-0x74 ptr register
+
+#define MUDATA			0x18		/* MPU401 data register (8 bits)       		*/
+
+#define MUCMD			0x19		/* MPU401 command register (8 bits)    		*/
+#define MUCMD_RESET		0xff		/* RESET command				*/
+#define MUCMD_ENTERUARTMODE	0x3f		/* Enter_UART_mode command			*/
+						/* NOTE: All other commands are ignored		*/
+
+#define MUSTAT			MUCMD		/* MPU401 status register (8 bits)     		*/
+#define MUSTAT_IRDYN		0x80		/* 0 = MIDI data or command ACK			*/
+#define MUSTAT_ORDYN		0x40		/* 0 = MUDATA can accept a command or data	*/
+
+#define A_IOCFG			0x18		/* GPIO on Audigy card (16bits)			*/
+#define A_GPINPUT_MASK		0xff00
+#define A_GPOUTPUT_MASK		0x00ff
+
+// Audigy output/GPIO stuff taken from the kX drivers
+#define A_IOCFG_GPOUT0		0x0044		/* analog/digital				*/
+#define A_IOCFG_DISABLE_ANALOG	0x0040		/* = 'enable' for Audigy2 (chiprev=4)		*/
+#define A_IOCFG_ENABLE_DIGITAL	0x0004
+#define A_IOCFG_ENABLE_DIGITAL_AUDIGY4	0x0080
+#define A_IOCFG_UNKNOWN_20      0x0020
+#define A_IOCFG_DISABLE_AC97_FRONT      0x0080  /* turn off ac97 front -> front (10k2.1)	*/
+#define A_IOCFG_GPOUT1		0x0002		/* IR? drive's internal bypass (?)		*/
+#define A_IOCFG_GPOUT2		0x0001		/* IR */
+#define A_IOCFG_MULTIPURPOSE_JACK	0x2000  /* center+lfe+rear_center (a2/a2ex)		*/
+                                                /* + digital for generic 10k2			*/
+#define A_IOCFG_DIGITAL_JACK    0x1000          /* digital for a2 platinum			*/
+#define A_IOCFG_FRONT_JACK      0x4000
+#define A_IOCFG_REAR_JACK       0x8000
+#define A_IOCFG_PHONES_JACK     0x0100          /* LiveDrive					*/
+
+/* outputs:
+ *	for audigy2 platinum:	0xa00
+ *	for a2 platinum ex:	0x1c00
+ *	for a1 platinum:	0x0
+ */
+
+#define TIMER			0x1a		/* Timer terminal count register		*/
+						/* NOTE: After the rate is changed, a maximum	*/
+						/* of 1024 sample periods should be allowed	*/
+						/* before the new rate is guaranteed accurate.	*/
+#define TIMER_RATE_MASK		0x000003ff	/* Timer interrupt rate in sample periods	*/
+						/* 0 == 1024 periods, [1..4] are not useful	*/
+#define TIMER_RATE		0x0a00001a
+
+#define AC97DATA		0x1c		/* AC97 register set data register (16 bit)	*/
+
+#define AC97ADDRESS		0x1e		/* AC97 register set address register (8 bit)	*/
+#define AC97ADDRESS_READY	0x80		/* Read-only bit, reflects CODEC READY signal	*/
+#define AC97ADDRESS_ADDRESS	0x7f		/* Address of indexed AC97 register		*/
+
+/* Available on the Audigy 2 and Audigy 4 only. This is the P16V chip. */
+#define PTR2			0x20		/* Indexed register set pointer register	*/
+#define DATA2			0x24		/* Indexed register set data register		*/
+#define IPR2			0x28		/* P16V interrupt pending register		*/
+#define IPR2_PLAYBACK_CH_0_LOOP      0x00001000 /* Playback Channel 0 loop                               */
+#define IPR2_PLAYBACK_CH_0_HALF_LOOP 0x00000100 /* Playback Channel 0 half loop                          */
+#define IPR2_CAPTURE_CH_0_LOOP       0x00100000 /* Capture Channel 0 loop                               */
+#define IPR2_CAPTURE_CH_0_HALF_LOOP  0x00010000 /* Capture Channel 0 half loop                          */
+						/* 0x00000100 Playback. Only in once per period.
+						 * 0x00110000 Capture. Int on half buffer.
+						 */
+#define INTE2			0x2c		/* P16V Interrupt enable register. 	*/
+#define INTE2_PLAYBACK_CH_0_LOOP      0x00001000 /* Playback Channel 0 loop                               */
+#define INTE2_PLAYBACK_CH_0_HALF_LOOP 0x00000100 /* Playback Channel 0 half loop                          */
+#define INTE2_PLAYBACK_CH_1_LOOP      0x00002000 /* Playback Channel 1 loop                               */
+#define INTE2_PLAYBACK_CH_1_HALF_LOOP 0x00000200 /* Playback Channel 1 half loop                          */
+#define INTE2_PLAYBACK_CH_2_LOOP      0x00004000 /* Playback Channel 2 loop                               */
+#define INTE2_PLAYBACK_CH_2_HALF_LOOP 0x00000400 /* Playback Channel 2 half loop                          */
+#define INTE2_PLAYBACK_CH_3_LOOP      0x00008000 /* Playback Channel 3 loop                               */
+#define INTE2_PLAYBACK_CH_3_HALF_LOOP 0x00000800 /* Playback Channel 3 half loop                          */
+#define INTE2_CAPTURE_CH_0_LOOP       0x00100000 /* Capture Channel 0 loop                               */
+#define INTE2_CAPTURE_CH_0_HALF_LOOP  0x00010000 /* Caputre Channel 0 half loop                          */
+#define HCFG2			0x34		/* Defaults: 0, win2000 sets it to 00004201 */
+						/* 0x00000000 2-channel output. */
+						/* 0x00000200 8-channel output. */
+						/* 0x00000004 pauses stream/irq fail. */
+						/* Rest of bits no nothing to sound output */
+						/* bit 0: Enable P16V audio.
+						 * bit 1: Lock P16V record memory cache.
+						 * bit 2: Lock P16V playback memory cache.
+						 * bit 3: Dummy record insert zero samples.
+						 * bit 8: Record 8-channel in phase.
+						 * bit 9: Playback 8-channel in phase.
+						 * bit 11-12: Playback mixer attenuation: 0=0dB, 1=-6dB, 2=-12dB, 3=Mute.
+						 * bit 13: Playback mixer enable.
+						 * bit 14: Route SRC48 mixer output to fx engine.
+						 * bit 15: Enable IEEE 1394 chip.
+						 */
+#define IPR3			0x38		/* Cdif interrupt pending register		*/
+#define INTE3			0x3c		/* Cdif interrupt enable register. 	*/
+/************************************************************************************************/
+/* PCI function 1 registers, address = <val> + PCIBASE1						*/
+/************************************************************************************************/
+
+#define JOYSTICK1		0x00		/* Analog joystick port register		*/
+#define JOYSTICK2		0x01		/* Analog joystick port register		*/
+#define JOYSTICK3		0x02		/* Analog joystick port register		*/
+#define JOYSTICK4		0x03		/* Analog joystick port register		*/
+#define JOYSTICK5		0x04		/* Analog joystick port register		*/
+#define JOYSTICK6		0x05		/* Analog joystick port register		*/
+#define JOYSTICK7		0x06		/* Analog joystick port register		*/
+#define JOYSTICK8		0x07		/* Analog joystick port register		*/
+
+/* When writing, any write causes JOYSTICK_COMPARATOR output enable to be pulsed on write.	*/
+/* When reading, use these bitfields: */
+#define JOYSTICK_BUTTONS	0x0f		/* Joystick button data				*/
+#define JOYSTICK_COMPARATOR	0xf0		/* Joystick comparator data			*/
+
+
+/********************************************************************************************************/
+/* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers			*/
+/********************************************************************************************************/
+
+#define CPF			0x00		/* Current pitch and fraction register			*/
+#define CPF_CURRENTPITCH_MASK	0xffff0000	/* Current pitch (linear, 0x4000 == unity pitch shift) 	*/
+#define CPF_CURRENTPITCH	0x10100000
+#define CPF_STEREO_MASK		0x00008000	/* 1 = Even channel interleave, odd channel locked	*/
+#define CPF_STOP_MASK		0x00004000	/* 1 = Current pitch forced to 0			*/
+#define CPF_FRACADDRESS_MASK	0x00003fff	/* Linear fractional address of the current channel	*/
+
+#define PTRX			0x01		/* Pitch target and send A/B amounts register		*/
+#define PTRX_PITCHTARGET_MASK	0xffff0000	/* Pitch target of specified channel			*/
+#define PTRX_PITCHTARGET	0x10100001
+#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00	/* Linear level of channel output sent to FX send bus A	*/
+#define PTRX_FXSENDAMOUNT_A	0x08080001
+#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff	/* Linear level of channel output sent to FX send bus B	*/
+#define PTRX_FXSENDAMOUNT_B	0x08000001
+
+#define CVCF			0x02		/* Current volume and filter cutoff register		*/
+#define CVCF_CURRENTVOL_MASK	0xffff0000	/* Current linear volume of specified channel		*/
+#define CVCF_CURRENTVOL		0x10100002
+#define CVCF_CURRENTFILTER_MASK	0x0000ffff	/* Current filter cutoff frequency of specified channel	*/
+#define CVCF_CURRENTFILTER	0x10000002
+
+#define VTFT			0x03		/* Volume target and filter cutoff target register	*/
+#define VTFT_VOLUMETARGET_MASK	0xffff0000	/* Volume target of specified channel			*/
+#define VTFT_VOLUMETARGET	0x10100003
+#define VTFT_FILTERTARGET_MASK	0x0000ffff	/* Filter cutoff target of specified channel		*/
+#define VTFT_FILTERTARGET	0x10000003
+
+#define Z1			0x05		/* Filter delay memory 1 register			*/
+
+#define Z2			0x04		/* Filter delay memory 2 register			*/
+
+#define PSST			0x06		/* Send C amount and loop start address register	*/
+#define PSST_FXSENDAMOUNT_C_MASK 0xff000000	/* Linear level of channel output sent to FX send bus C	*/
+
+#define PSST_FXSENDAMOUNT_C	0x08180006
+
+#define PSST_LOOPSTARTADDR_MASK	0x00ffffff	/* Loop start address of the specified channel		*/
+#define PSST_LOOPSTARTADDR	0x18000006
+
+#define DSL			0x07		/* Send D amount and loop start address register	*/
+#define DSL_FXSENDAMOUNT_D_MASK	0xff000000	/* Linear level of channel output sent to FX send bus D	*/
+
+#define DSL_FXSENDAMOUNT_D	0x08180007
+
+#define DSL_LOOPENDADDR_MASK	0x00ffffff	/* Loop end address of the specified channel		*/
+#define DSL_LOOPENDADDR		0x18000007
+
+#define CCCA			0x08		/* Filter Q, interp. ROM, byte size, cur. addr register */
+#define CCCA_RESONANCE		0xf0000000	/* Lowpass filter resonance (Q) height			*/
+#define CCCA_INTERPROMMASK	0x0e000000	/* Selects passband of interpolation ROM		*/
+						/* 1 == full band, 7 == lowpass				*/
+						/* ROM 0 is used when pitch shifting downward or less	*/
+						/* then 3 semitones upward.  Increasingly higher ROM	*/
+						/* numbers are used, typically in steps of 3 semitones,	*/
+						/* as upward pitch shifting is performed.		*/
+#define CCCA_INTERPROM_0	0x00000000	/* Select interpolation ROM 0				*/
+#define CCCA_INTERPROM_1	0x02000000	/* Select interpolation ROM 1				*/
+#define CCCA_INTERPROM_2	0x04000000	/* Select interpolation ROM 2				*/
+#define CCCA_INTERPROM_3	0x06000000	/* Select interpolation ROM 3				*/
+#define CCCA_INTERPROM_4	0x08000000	/* Select interpolation ROM 4				*/
+#define CCCA_INTERPROM_5	0x0a000000	/* Select interpolation ROM 5				*/
+#define CCCA_INTERPROM_6	0x0c000000	/* Select interpolation ROM 6				*/
+#define CCCA_INTERPROM_7	0x0e000000	/* Select interpolation ROM 7				*/
+#define CCCA_8BITSELECT		0x01000000	/* 1 = Sound memory for this channel uses 8-bit samples	*/
+#define CCCA_CURRADDR_MASK	0x00ffffff	/* Current address of the selected channel		*/
+#define CCCA_CURRADDR		0x18000008
+
+#define CCR			0x09		/* Cache control register				*/
+#define CCR_CACHEINVALIDSIZE	0x07190009
+#define CCR_CACHEINVALIDSIZE_MASK	0xfe000000	/* Number of invalid samples cache for this channel    	*/
+#define CCR_CACHELOOPFLAG	0x01000000	/* 1 = Cache has a loop service pending			*/
+#define CCR_INTERLEAVEDSAMPLES	0x00800000	/* 1 = A cache service will fetch interleaved samples	*/
+#define CCR_WORDSIZEDSAMPLES	0x00400000	/* 1 = A cache service will fetch word sized samples	*/
+#define CCR_READADDRESS		0x06100009
+#define CCR_READADDRESS_MASK	0x003f0000	/* Location of cache just beyond current cache service	*/
+#define CCR_LOOPINVALSIZE	0x0000fe00	/* Number of invalid samples in cache prior to loop	*/
+						/* NOTE: This is valid only if CACHELOOPFLAG is set	*/
+#define CCR_LOOPFLAG		0x00000100	/* Set for a single sample period when a loop occurs	*/
+#define CCR_CACHELOOPADDRHI	0x000000ff	/* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set	*/
+
+#define CLP			0x0a		/* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */
+						/* NOTE: This register is normally not used		*/
+#define CLP_CACHELOOPADDR	0x0000ffff	/* Cache loop address (DSL_LOOPSTARTADDR [0..15])	*/
+
+#define FXRT			0x0b		/* Effects send routing register			*/
+						/* NOTE: It is illegal to assign the same routing to	*/
+						/* two effects sends.					*/
+#define FXRT_CHANNELA		0x000f0000	/* Effects send bus number for channel's effects send A	*/
+#define FXRT_CHANNELB		0x00f00000	/* Effects send bus number for channel's effects send B	*/
+#define FXRT_CHANNELC		0x0f000000	/* Effects send bus number for channel's effects send C	*/
+#define FXRT_CHANNELD		0xf0000000	/* Effects send bus number for channel's effects send D	*/
+
+#define A_HR			0x0b	/* High Resolution. 24bit playback from host to DSP. */
+#define MAPA			0x0c		/* Cache map A						*/
+
+#define MAPB			0x0d		/* Cache map B						*/
+
+#define MAP_PTE_MASK		0xffffe000	/* The 19 MSBs of the PTE indexed by the PTI		*/
+#define MAP_PTI_MASK		0x00001fff	/* The 13 bit index to one of the 8192 PTE dwords      	*/
+
+/* 0x0e, 0x0f: Not used */
+
+#define ENVVOL			0x10		/* Volume envelope register				*/
+#define ENVVOL_MASK		0x0000ffff	/* Current value of volume envelope state variable	*/  
+						/* 0x8000-n == 666*n usec delay	       			*/
+
+#define ATKHLDV 		0x11		/* Volume envelope hold and attack register		*/
+#define ATKHLDV_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
+#define ATKHLDV_HOLDTIME_MASK	0x00007f00	/* Envelope hold time (127-n == n*88.2msec)		*/
+#define ATKHLDV_ATTACKTIME_MASK	0x0000007f	/* Envelope attack time, log encoded			*/
+						/* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec	*/
+
+#define DCYSUSV 		0x12		/* Volume envelope sustain and decay register		*/
+#define DCYSUSV_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
+#define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
+#define DCYSUSV_CHANNELENABLE_MASK 0x00000080	/* 1 = Inhibit envelope engine from writing values in	*/
+						/* this channel and from writing to pitch, filter and	*/
+						/* volume targets.					*/
+#define DCYSUSV_DECAYTIME_MASK	0x0000007f	/* Volume envelope decay time, log encoded     		*/
+						/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+
+#define LFOVAL1 		0x13		/* Modulation LFO value					*/
+#define LFOVAL_MASK		0x0000ffff	/* Current value of modulation LFO state variable	*/
+						/* 0x8000-n == 666*n usec delay				*/
+
+#define ENVVAL			0x14		/* Modulation envelope register				*/
+#define ENVVAL_MASK		0x0000ffff	/* Current value of modulation envelope state variable 	*/
+						/* 0x8000-n == 666*n usec delay				*/
+
+#define ATKHLDM			0x15		/* Modulation envelope hold and attack register		*/
+#define ATKHLDM_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
+#define ATKHLDM_HOLDTIME	0x00007f00	/* Envelope hold time (127-n == n*42msec)		*/
+#define ATKHLDM_ATTACKTIME	0x0000007f	/* Envelope attack time, log encoded			*/
+						/* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec		*/
+
+#define DCYSUSM			0x16		/* Modulation envelope decay and sustain register	*/
+#define DCYSUSM_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
+#define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
+#define DCYSUSM_DECAYTIME_MASK	0x0000007f	/* Envelope decay time, log encoded			*/
+						/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+
+#define LFOVAL2 		0x17		/* Vibrato LFO register					*/
+#define LFOVAL2_MASK		0x0000ffff	/* Current value of vibrato LFO state variable 		*/
+						/* 0x8000-n == 666*n usec delay				*/
+
+#define IP			0x18		/* Initial pitch register				*/
+#define IP_MASK			0x0000ffff	/* Exponential initial pitch shift			*/
+						/* 4 bits of octave, 12 bits of fractional octave	*/
+#define IP_UNITY		0x0000e000	/* Unity pitch shift					*/
+
+#define IFATN			0x19		/* Initial filter cutoff and attenuation register	*/
+#define IFATN_FILTERCUTOFF_MASK	0x0000ff00	/* Initial filter cutoff frequency in exponential units	*/
+						/* 6 most significant bits are semitones		*/
+						/* 2 least significant bits are fractions		*/
+#define IFATN_FILTERCUTOFF	0x08080019
+#define IFATN_ATTENUATION_MASK	0x000000ff	/* Initial attenuation in 0.375dB steps			*/
+#define IFATN_ATTENUATION	0x08000019
+
+
+#define PEFE			0x1a		/* Pitch envelope and filter envelope amount register	*/
+#define PEFE_PITCHAMOUNT_MASK	0x0000ff00	/* Pitch envlope amount					*/
+						/* Signed 2's complement, +/- one octave peak extremes	*/
+#define PEFE_PITCHAMOUNT	0x0808001a
+#define PEFE_FILTERAMOUNT_MASK	0x000000ff	/* Filter envlope amount				*/
+						/* Signed 2's complement, +/- six octaves peak extremes */
+#define PEFE_FILTERAMOUNT	0x0800001a
+#define FMMOD			0x1b		/* Vibrato/filter modulation from LFO register		*/
+#define FMMOD_MODVIBRATO	0x0000ff00	/* Vibrato LFO modulation depth				*/
+						/* Signed 2's complement, +/- one octave extremes	*/
+#define FMMOD_MOFILTER		0x000000ff	/* Filter LFO modulation depth				*/
+						/* Signed 2's complement, +/- three octave extremes	*/
+
+
+#define TREMFRQ 		0x1c		/* Tremolo amount and modulation LFO frequency register	*/
+#define TREMFRQ_DEPTH		0x0000ff00	/* Tremolo depth					*/
+						/* Signed 2's complement, with +/- 12dB extremes	*/
+
+#define TREMFRQ_FREQUENCY	0x000000ff	/* Tremolo LFO frequency				*/
+						/* ??Hz steps, maximum of ?? Hz.			*/
+#define FM2FRQ2 		0x1d		/* Vibrato amount and vibrato LFO frequency register	*/
+#define FM2FRQ2_DEPTH		0x0000ff00	/* Vibrato LFO vibrato depth				*/
+						/* Signed 2's complement, +/- one octave extremes	*/
+#define FM2FRQ2_FREQUENCY	0x000000ff	/* Vibrato LFO frequency				*/
+						/* 0.039Hz steps, maximum of 9.85 Hz.			*/
+
+#define TEMPENV 		0x1e		/* Tempory envelope register				*/
+#define TEMPENV_MASK		0x0000ffff	/* 16-bit value						*/
+						/* NOTE: All channels contain internal variables; do	*/
+						/* not write to these locations.			*/
+
+/* 0x1f: not used */
+
+#define CD0			0x20		/* Cache data 0 register				*/
+#define CD1			0x21		/* Cache data 1 register				*/
+#define CD2			0x22		/* Cache data 2 register				*/
+#define CD3			0x23		/* Cache data 3 register				*/
+#define CD4			0x24		/* Cache data 4 register				*/
+#define CD5			0x25		/* Cache data 5 register				*/
+#define CD6			0x26		/* Cache data 6 register				*/
+#define CD7			0x27		/* Cache data 7 register				*/
+#define CD8			0x28		/* Cache data 8 register				*/
+#define CD9			0x29		/* Cache data 9 register				*/
+#define CDA			0x2a		/* Cache data A register				*/
+#define CDB			0x2b		/* Cache data B register				*/
+#define CDC			0x2c		/* Cache data C register				*/
+#define CDD			0x2d		/* Cache data D register				*/
+#define CDE			0x2e		/* Cache data E register				*/
+#define CDF			0x2f		/* Cache data F register				*/
+
+/* 0x30-3f seem to be the same as 0x20-2f */
+
+#define PTB			0x40		/* Page table base register				*/
+#define PTB_MASK		0xfffff000	/* Physical address of the page table in host memory	*/
+
+#define TCB			0x41		/* Tank cache base register    				*/
+#define TCB_MASK		0xfffff000	/* Physical address of the bottom of host based TRAM	*/
+
+#define ADCCR			0x42		/* ADC sample rate/stereo control register		*/
+#define ADCCR_RCHANENABLE	0x00000010	/* Enables right channel for writing to the host       	*/
+#define ADCCR_LCHANENABLE	0x00000008	/* Enables left channel for writing to the host		*/
+						/* NOTE: To guarantee phase coherency, both channels	*/
+						/* must be disabled prior to enabling both channels.	*/
+#define A_ADCCR_RCHANENABLE	0x00000020
+#define A_ADCCR_LCHANENABLE	0x00000010
+
+#define A_ADCCR_SAMPLERATE_MASK 0x0000000F      /* Audigy sample rate convertor output rate		*/
+#define ADCCR_SAMPLERATE_MASK	0x00000007	/* Sample rate convertor output rate			*/
+#define ADCCR_SAMPLERATE_48	0x00000000	/* 48kHz sample rate					*/
+#define ADCCR_SAMPLERATE_44	0x00000001	/* 44.1kHz sample rate					*/
+#define ADCCR_SAMPLERATE_32	0x00000002	/* 32kHz sample rate					*/
+#define ADCCR_SAMPLERATE_24	0x00000003	/* 24kHz sample rate					*/
+#define ADCCR_SAMPLERATE_22	0x00000004	/* 22.05kHz sample rate					*/
+#define ADCCR_SAMPLERATE_16	0x00000005	/* 16kHz sample rate					*/
+#define ADCCR_SAMPLERATE_11	0x00000006	/* 11.025kHz sample rate				*/
+#define ADCCR_SAMPLERATE_8	0x00000007	/* 8kHz sample rate					*/
+#define A_ADCCR_SAMPLERATE_12	0x00000006	/* 12kHz sample rate					*/
+#define A_ADCCR_SAMPLERATE_11	0x00000007	/* 11.025kHz sample rate				*/
+#define A_ADCCR_SAMPLERATE_8	0x00000008	/* 8kHz sample rate					*/
+
+#define FXWC			0x43		/* FX output write channels register			*/
+						/* When set, each bit enables the writing of the	*/
+						/* corresponding FX output channel (internal registers  */
+						/* 0x20-0x3f) to host memory.  This mode of recording   */
+						/* is 16bit, 48KHz only. All 32 channels can be enabled */
+						/* simultaneously.					*/
+
+#define FXWC_DEFAULTROUTE_C     (1<<0)		/* left emu out? */
+#define FXWC_DEFAULTROUTE_B     (1<<1)		/* right emu out? */
+#define FXWC_DEFAULTROUTE_A     (1<<12)
+#define FXWC_DEFAULTROUTE_D     (1<<13)
+#define FXWC_ADCLEFT            (1<<18)
+#define FXWC_CDROMSPDIFLEFT     (1<<18)
+#define FXWC_ADCRIGHT           (1<<19)
+#define FXWC_CDROMSPDIFRIGHT    (1<<19)
+#define FXWC_MIC                (1<<20)
+#define FXWC_ZOOMLEFT           (1<<20)
+#define FXWC_ZOOMRIGHT          (1<<21)
+#define FXWC_SPDIFLEFT          (1<<22)		/* 0x00400000 */
+#define FXWC_SPDIFRIGHT         (1<<23)		/* 0x00800000 */
+
+#define A_TBLSZ			0x43	/* Effects Tank Internal Table Size. Only low byte or register used */
+
+#define TCBS			0x44		/* Tank cache buffer size register			*/
+#define TCBS_MASK		0x00000007	/* Tank cache buffer size field				*/
+#define TCBS_BUFFSIZE_16K	0x00000000
+#define TCBS_BUFFSIZE_32K	0x00000001
+#define TCBS_BUFFSIZE_64K	0x00000002
+#define TCBS_BUFFSIZE_128K	0x00000003
+#define TCBS_BUFFSIZE_256K	0x00000004
+#define TCBS_BUFFSIZE_512K	0x00000005
+#define TCBS_BUFFSIZE_1024K	0x00000006
+#define TCBS_BUFFSIZE_2048K	0x00000007
+
+#define MICBA			0x45		/* AC97 microphone buffer address register		*/
+#define MICBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define ADCBA			0x46		/* ADC buffer address register				*/
+#define ADCBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define FXBA			0x47		/* FX Buffer Address */
+#define FXBA_MASK		0xfffff000	/* 20 bit base address					*/
+
+#define A_HWM			0x48	/* High PCI Water Mark - word access, defaults to 3f */
+
+#define MICBS			0x49		/* Microphone buffer size register			*/
+
+#define ADCBS			0x4a		/* ADC buffer size register				*/
+
+#define FXBS			0x4b		/* FX buffer size register				*/
+
+/* register: 0x4c..4f: ffff-ffff current amounts, per-channel */
+
+/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */
+#define ADCBS_BUFSIZE_NONE	0x00000000
+#define ADCBS_BUFSIZE_384	0x00000001
+#define ADCBS_BUFSIZE_448	0x00000002
+#define ADCBS_BUFSIZE_512	0x00000003
+#define ADCBS_BUFSIZE_640	0x00000004
+#define ADCBS_BUFSIZE_768	0x00000005
+#define ADCBS_BUFSIZE_896	0x00000006
+#define ADCBS_BUFSIZE_1024	0x00000007
+#define ADCBS_BUFSIZE_1280	0x00000008
+#define ADCBS_BUFSIZE_1536	0x00000009
+#define ADCBS_BUFSIZE_1792	0x0000000a
+#define ADCBS_BUFSIZE_2048	0x0000000b
+#define ADCBS_BUFSIZE_2560	0x0000000c
+#define ADCBS_BUFSIZE_3072	0x0000000d
+#define ADCBS_BUFSIZE_3584	0x0000000e
+#define ADCBS_BUFSIZE_4096	0x0000000f
+#define ADCBS_BUFSIZE_5120	0x00000010
+#define ADCBS_BUFSIZE_6144	0x00000011
+#define ADCBS_BUFSIZE_7168	0x00000012
+#define ADCBS_BUFSIZE_8192	0x00000013
+#define ADCBS_BUFSIZE_10240	0x00000014
+#define ADCBS_BUFSIZE_12288	0x00000015
+#define ADCBS_BUFSIZE_14366	0x00000016
+#define ADCBS_BUFSIZE_16384	0x00000017
+#define ADCBS_BUFSIZE_20480	0x00000018
+#define ADCBS_BUFSIZE_24576	0x00000019
+#define ADCBS_BUFSIZE_28672	0x0000001a
+#define ADCBS_BUFSIZE_32768	0x0000001b
+#define ADCBS_BUFSIZE_40960	0x0000001c
+#define ADCBS_BUFSIZE_49152	0x0000001d
+#define ADCBS_BUFSIZE_57344	0x0000001e
+#define ADCBS_BUFSIZE_65536	0x0000001f
+
+/* Current Send B, A Amounts */
+#define A_CSBA			0x4c
+
+/* Current Send D, C Amounts */
+#define A_CSDC			0x4d
+
+/* Current Send F, E Amounts */
+#define A_CSFE			0x4e
+
+/* Current Send H, G Amounts */
+#define A_CSHG			0x4f
+
+
+#define CDCS			0x50		/* CD-ROM digital channel status register	*/
+
+#define GPSCS			0x51		/* General Purpose SPDIF channel status register*/
+
+#define DBG			0x52		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+
+/* S/PDIF Input C Channel Status */
+#define A_SPSC			0x52
+
+#define REG53			0x53		/* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+
+#define A_DBG			 0x53
+#define A_DBG_SINGLE_STEP	 0x00020000	/* Set to zero to start dsp */
+#define A_DBG_ZC		 0x40000000	/* zero tram counter */
+#define A_DBG_STEP_ADDR		 0x000003ff
+#define A_DBG_SATURATION_OCCURED 0x20000000
+#define A_DBG_SATURATION_ADDR	 0x0ffc0000
+
+// NOTE: 0x54,55,56: 64-bit
+#define SPCS0			0x54		/* SPDIF output Channel Status 0 register	*/
+
+#define SPCS1			0x55		/* SPDIF output Channel Status 1 register	*/
+
+#define SPCS2			0x56		/* SPDIF output Channel Status 2 register	*/
+
+#define SPCS_CLKACCYMASK	0x30000000	/* Clock accuracy				*/
+#define SPCS_CLKACCY_1000PPM	0x00000000	/* 1000 parts per million			*/
+#define SPCS_CLKACCY_50PPM	0x10000000	/* 50 parts per million				*/
+#define SPCS_CLKACCY_VARIABLE	0x20000000	/* Variable accuracy				*/
+#define SPCS_SAMPLERATEMASK	0x0f000000	/* Sample rate					*/
+#define SPCS_SAMPLERATE_44	0x00000000	/* 44.1kHz sample rate				*/
+#define SPCS_SAMPLERATE_48	0x02000000	/* 48kHz sample rate				*/
+#define SPCS_SAMPLERATE_32	0x03000000	/* 32kHz sample rate				*/
+#define SPCS_CHANNELNUMMASK	0x00f00000	/* Channel number				*/
+#define SPCS_CHANNELNUM_UNSPEC	0x00000000	/* Unspecified channel number			*/
+#define SPCS_CHANNELNUM_LEFT	0x00100000	/* Left channel					*/
+#define SPCS_CHANNELNUM_RIGHT	0x00200000	/* Right channel				*/
+#define SPCS_SOURCENUMMASK	0x000f0000	/* Source number				*/
+#define SPCS_SOURCENUM_UNSPEC	0x00000000	/* Unspecified source number			*/
+#define SPCS_GENERATIONSTATUS	0x00008000	/* Originality flag (see IEC-958 spec)		*/
+#define SPCS_CATEGORYCODEMASK	0x00007f00	/* Category code (see IEC-958 spec)		*/
+#define SPCS_MODEMASK		0x000000c0	/* Mode (see IEC-958 spec)			*/
+#define SPCS_EMPHASISMASK	0x00000038	/* Emphasis					*/
+#define SPCS_EMPHASIS_NONE	0x00000000	/* No emphasis					*/
+#define SPCS_EMPHASIS_50_15	0x00000008	/* 50/15 usec 2 channel				*/
+#define SPCS_COPYRIGHT		0x00000004	/* Copyright asserted flag -- do not modify	*/
+#define SPCS_NOTAUDIODATA	0x00000002	/* 0 = Digital audio, 1 = not audio		*/
+#define SPCS_PROFESSIONAL	0x00000001	/* 0 = Consumer (IEC-958), 1 = pro (AES3-1992)	*/
+
+/* 0x57: Not used */
+
+/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status      		*/
+#define CLIEL			0x58		/* Channel loop interrupt enable low register	*/
+
+#define CLIEH			0x59		/* Channel loop interrupt enable high register	*/
+
+#define CLIPL			0x5a		/* Channel loop interrupt pending low register	*/
+
+#define CLIPH			0x5b		/* Channel loop interrupt pending high register	*/
+
+#define SOLEL			0x5c		/* Stop on loop enable low register		*/
+
+#define SOLEH			0x5d		/* Stop on loop enable high register		*/
+
+#define SPBYPASS		0x5e		/* SPDIF BYPASS mode register			*/
+#define SPBYPASS_SPDIF0_MASK	0x00000003	/* SPDIF 0 bypass mode				*/
+#define SPBYPASS_SPDIF1_MASK	0x0000000c	/* SPDIF 1 bypass mode				*/
+/* bypass mode: 0 - DSP; 1 - SPDIF A, 2 - SPDIF B, 3 - SPDIF C					*/
+#define SPBYPASS_FORMAT		0x00000f00      /* If 1, SPDIF XX uses 24 bit, if 0 - 20 bit	*/
+
+#define AC97SLOT		0x5f            /* additional AC97 slots enable bits		*/
+#define AC97SLOT_REAR_RIGHT	0x01		/* Rear left */
+#define AC97SLOT_REAR_LEFT	0x02		/* Rear right */
+#define AC97SLOT_CNTR		0x10            /* Center enable */
+#define AC97SLOT_LFE		0x20            /* LFE enable */
+
+/* PCB Revision */
+#define A_PCB			0x5f
+
+// NOTE: 0x60,61,62: 64-bit
+#define CDSRCS			0x60		/* CD-ROM Sample Rate Converter status register	*/
+
+#define GPSRCS			0x61		/* General Purpose SPDIF sample rate cvt status */
+
+#define ZVSRCS			0x62		/* ZVideo sample rate converter status		*/
+						/* NOTE: This one has no SPDIFLOCKED field	*/
+						/* Assumes sample lock				*/
+
+/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS.			*/
+#define SRCS_SPDIFVALID		0x04000000	/* SPDIF stream valid				*/
+#define SRCS_SPDIFLOCKED	0x02000000	/* SPDIF stream locked				*/
+#define SRCS_RATELOCKED		0x01000000	/* Sample rate locked				*/
+#define SRCS_ESTSAMPLERATE	0x0007ffff	/* Do not modify this field.			*/
+
+/* Note that these values can vary +/- by a small amount                                        */
+#define SRCS_SPDIFRATE_44	0x0003acd9
+#define SRCS_SPDIFRATE_48	0x00040000
+#define SRCS_SPDIFRATE_96	0x00080000
+
+#define MICIDX                  0x63            /* Microphone recording buffer index register   */
+#define MICIDX_MASK             0x0000ffff      /* 16-bit value                                 */
+#define MICIDX_IDX		0x10000063
+
+#define ADCIDX			0x64		/* ADC recording buffer index register		*/
+#define ADCIDX_MASK		0x0000ffff	/* 16 bit index field				*/
+#define ADCIDX_IDX		0x10000064
+
+#define A_ADCIDX		0x63
+#define A_ADCIDX_IDX		0x10000063
+
+#define A_MICIDX		0x64
+#define A_MICIDX_IDX		0x10000064
+
+#define FXIDX			0x65		/* FX recording buffer index register		*/
+#define FXIDX_MASK		0x0000ffff	/* 16-bit value					*/
+#define FXIDX_IDX		0x10000065
+
+/* The 32-bit HLIx and HLIPx registers all have one bit per channel control/status      		*/
+#define HLIEL			0x66		/* Channel half loop interrupt enable low register	*/
+
+#define HLIEH			0x67		/* Channel half loop interrupt enable high register	*/
+
+#define HLIPL			0x68		/* Channel half loop interrupt pending low register	*/
+
+#define HLIPH			0x69		/* Channel half loop interrupt pending high register	*/
+
+/* S/PDIF Host Record Index (bypasses SRC) */
+#define A_SPRI			0x6a
+/* S/PDIF Host Record Address */
+#define A_SPRA			0x6b
+/* S/PDIF Host Record Control */
+#define A_SPRC			0x6c
+/* Delayed Interrupt Counter & Enable */
+#define A_DICE			0x6d
+/* Tank Table Base */
+#define A_TTB			0x6e
+/* Tank Delay Offset */
+#define A_TDOF			0x6f
+
+/* This is the MPU port on the card (via the game port)						*/
+#define A_MUDATA1		0x70
+#define A_MUCMD1		0x71
+#define A_MUSTAT1		A_MUCMD1
+
+/* This is the MPU port on the Audigy Drive 							*/
+#define A_MUDATA2		0x72
+#define A_MUCMD2		0x73
+#define A_MUSTAT2		A_MUCMD2	
+
+/* The next two are the Audigy equivalent of FXWC						*/
+/* the Audigy can record any output (16bit, 48kHz, up to 64 channel simultaneously) 		*/
+/* Each bit selects a channel for recording */
+#define A_FXWC1			0x74            /* Selects 0x7f-0x60 for FX recording           */
+#define A_FXWC2			0x75		/* Selects 0x9f-0x80 for FX recording           */
+
+/* Extended Hardware Control */
+#define A_SPDIF_SAMPLERATE	0x76		/* Set the sample rate of SPDIF output		*/
+#define A_SAMPLE_RATE		0x76		/* Various sample rate settings. */
+#define A_SAMPLE_RATE_NOT_USED  0x0ffc111e	/* Bits that are not used and cannot be set. 	*/
+#define A_SAMPLE_RATE_UNKNOWN	0xf0030001	/* Bits that can be set, but have unknown use. 	*/
+#define A_SPDIF_RATE_MASK	0x000000e0	/* Any other values for rates, just use 48000	*/
+#define A_SPDIF_48000		0x00000000
+#define A_SPDIF_192000		0x00000020
+#define A_SPDIF_96000		0x00000040
+#define A_SPDIF_44100		0x00000080
+
+#define A_I2S_CAPTURE_RATE_MASK	0x00000e00	/* This sets the capture PCM rate, but it is    */
+#define A_I2S_CAPTURE_48000	0x00000000	/* unclear if this sets the ADC rate as well.	*/
+#define A_I2S_CAPTURE_192000	0x00000200
+#define A_I2S_CAPTURE_96000	0x00000400
+#define A_I2S_CAPTURE_44100	0x00000800
+
+#define A_PCM_RATE_MASK		0x0000e000	/* This sets the playback PCM rate on the P16V	*/
+#define A_PCM_48000		0x00000000
+#define A_PCM_192000		0x00002000
+#define A_PCM_96000		0x00004000
+#define A_PCM_44100		0x00008000
+
+/* I2S0 Sample Rate Tracker Status */
+#define A_SRT3			0x77
+
+/* I2S1 Sample Rate Tracker Status */
+#define A_SRT4			0x78
+
+/* I2S2 Sample Rate Tracker Status */
+#define A_SRT5			0x79
+/* - default to 0x01080000 on my audigy 2 ZS --rlrevell	*/
+
+/* Tank Table DMA Address */
+#define A_TTDA			0x7a
+/* Tank Table DMA Data */
+#define A_TTDD			0x7b
+
+#define A_FXRT2			0x7c
+#define A_FXRT_CHANNELE		0x0000003f	/* Effects send bus number for channel's effects send E	*/
+#define A_FXRT_CHANNELF		0x00003f00	/* Effects send bus number for channel's effects send F	*/
+#define A_FXRT_CHANNELG		0x003f0000	/* Effects send bus number for channel's effects send G	*/
+#define A_FXRT_CHANNELH		0x3f000000	/* Effects send bus number for channel's effects send H	*/
+
+#define A_SENDAMOUNTS		0x7d
+#define A_FXSENDAMOUNT_E_MASK	0xFF000000
+#define A_FXSENDAMOUNT_F_MASK	0x00FF0000
+#define A_FXSENDAMOUNT_G_MASK	0x0000FF00
+#define A_FXSENDAMOUNT_H_MASK	0x000000FF
+/* 0x7c, 0x7e "high bit is used for filtering" */
+ 
+/* The send amounts for this one are the same as used with the emu10k1 */
+#define A_FXRT1			0x7e
+#define A_FXRT_CHANNELA		0x0000003f
+#define A_FXRT_CHANNELB		0x00003f00
+#define A_FXRT_CHANNELC		0x003f0000
+#define A_FXRT_CHANNELD		0x3f000000
+
+/* 0x7f: Not used */
+/* Each FX general purpose register is 32 bits in length, all bits are used			*/
+#define FXGPREGBASE		0x100		/* FX general purpose registers base       	*/
+#define A_FXGPREGBASE		0x400		/* Audigy GPRs, 0x400 to 0x5ff			*/
+
+#define A_TANKMEMCTLREGBASE	0x100		/* Tank memory control registers base - only for Audigy */
+#define A_TANKMEMCTLREG_MASK	0x1f		/* only 5 bits used - only for Audigy */
+
+/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is	*/
+/* decompressed back to 20 bits on a read.  There are a total of 160 locations, the last 32	*/
+/* locations are for external TRAM. 								*/
+#define TANKMEMDATAREGBASE	0x200		/* Tank memory data registers base     		*/
+#define TANKMEMDATAREG_MASK	0x000fffff	/* 20 bit tank audio data field			*/
+
+/* Combined address field and memory opcode or flag field.  160 locations, last 32 are external	*/
+#define TANKMEMADDRREGBASE	0x300		/* Tank memory address registers base		*/
+#define TANKMEMADDRREG_ADDR_MASK 0x000fffff	/* 20 bit tank address field			*/
+#define TANKMEMADDRREG_CLEAR	0x00800000	/* Clear tank memory				*/
+#define TANKMEMADDRREG_ALIGN	0x00400000	/* Align read or write relative to tank access	*/
+#define TANKMEMADDRREG_WRITE	0x00200000	/* Write to tank memory				*/
+#define TANKMEMADDRREG_READ	0x00100000	/* Read from tank memory			*/
+
+#define MICROCODEBASE		0x400		/* Microcode data base address			*/
+
+/* Each DSP microcode instruction is mapped into 2 doublewords 					*/
+/* NOTE: When writing, always write the LO doubleword first.  Reads can be in either order.	*/
+#define LOWORD_OPX_MASK		0x000ffc00	/* Instruction operand X			*/
+#define LOWORD_OPY_MASK		0x000003ff	/* Instruction operand Y			*/
+#define HIWORD_OPCODE_MASK	0x00f00000	/* Instruction opcode				*/
+#define HIWORD_RESULT_MASK	0x000ffc00	/* Instruction result				*/
+#define HIWORD_OPA_MASK		0x000003ff	/* Instruction operand A			*/
+
+
+/* Audigy Soundcard have a different instruction format */
+#define A_MICROCODEBASE		0x600
+#define A_LOWORD_OPY_MASK	0x000007ff
+#define A_LOWORD_OPX_MASK	0x007ff000
+#define A_HIWORD_OPCODE_MASK	0x0f000000
+#define A_HIWORD_RESULT_MASK	0x007ff000
+#define A_HIWORD_OPA_MASK	0x000007ff
+
+/************************************************************************************************/
+/* EMU1010m HANA FPGA registers									*/
+/************************************************************************************************/
+#define EMU_HANA_DESTHI		0x00	/* 0000xxx  3 bits Link Destination */
+#define EMU_HANA_DESTLO		0x01	/* 00xxxxx  5 bits */
+#define EMU_HANA_SRCHI		0x02	/* 0000xxx  3 bits Link Source */
+#define EMU_HANA_SRCLO		0x03	/* 00xxxxx  5 bits */
+#define EMU_HANA_DOCK_PWR	0x04	/* 000000x  1 bits Audio Dock power */
+#define EMU_HANA_DOCK_PWR_ON		0x01 /* Audio Dock power on */
+#define EMU_HANA_WCLOCK		0x05	/* 0000xxx  3 bits Word Clock source select  */
+					/* Must be written after power on to reset DLL */
+					/* One is unable to detect the Audio dock without this */
+#define EMU_HANA_WCLOCK_SRC_MASK	0x07
+#define EMU_HANA_WCLOCK_INT_48K		0x00
+#define EMU_HANA_WCLOCK_INT_44_1K	0x01
+#define EMU_HANA_WCLOCK_HANA_SPDIF_IN	0x02
+#define EMU_HANA_WCLOCK_HANA_ADAT_IN	0x03
+#define EMU_HANA_WCLOCK_SYNC_BNCN	0x04
+#define EMU_HANA_WCLOCK_2ND_HANA	0x05
+#define EMU_HANA_WCLOCK_SRC_RESERVED	0x06
+#define EMU_HANA_WCLOCK_OFF		0x07 /* For testing, forces fallback to DEFCLOCK */
+#define EMU_HANA_WCLOCK_MULT_MASK	0x18
+#define EMU_HANA_WCLOCK_1X		0x00
+#define EMU_HANA_WCLOCK_2X		0x08
+#define EMU_HANA_WCLOCK_4X		0x10
+#define EMU_HANA_WCLOCK_MULT_RESERVED	0x18
+
+#define EMU_HANA_DEFCLOCK	0x06	/* 000000x  1 bits Default Word Clock  */
+#define EMU_HANA_DEFCLOCK_48K		0x00
+#define EMU_HANA_DEFCLOCK_44_1K		0x01
+
+#define EMU_HANA_UNMUTE		0x07	/* 000000x  1 bits Mute all audio outputs  */
+#define EMU_MUTE			0x00
+#define EMU_UNMUTE			0x01
+
+#define EMU_HANA_FPGA_CONFIG	0x08	/* 00000xx  2 bits Config control of FPGAs  */
+#define EMU_HANA_FPGA_CONFIG_AUDIODOCK	0x01 /* Set in order to program FPGA on Audio Dock */
+#define EMU_HANA_FPGA_CONFIG_HANA	0x02 /* Set in order to program FPGA on Hana */
+
+#define EMU_HANA_IRQ_ENABLE	0x09	/* 000xxxx  4 bits IRQ Enable  */
+#define EMU_HANA_IRQ_WCLK_CHANGED	0x01
+#define EMU_HANA_IRQ_ADAT		0x02
+#define EMU_HANA_IRQ_DOCK		0x04
+#define EMU_HANA_IRQ_DOCK_LOST		0x08
+
+#define EMU_HANA_SPDIF_MODE	0x0a	/* 00xxxxx  5 bits SPDIF MODE  */
+#define EMU_HANA_SPDIF_MODE_TX_COMSUMER	0x00
+#define EMU_HANA_SPDIF_MODE_TX_PRO	0x01
+#define EMU_HANA_SPDIF_MODE_TX_NOCOPY	0x02
+#define EMU_HANA_SPDIF_MODE_RX_COMSUMER	0x00
+#define EMU_HANA_SPDIF_MODE_RX_PRO	0x04
+#define EMU_HANA_SPDIF_MODE_RX_NOCOPY	0x08
+#define EMU_HANA_SPDIF_MODE_RX_INVALID	0x10
+
+#define EMU_HANA_OPTICAL_TYPE	0x0b	/* 00000xx  2 bits ADAT or SPDIF in/out  */
+#define EMU_HANA_OPTICAL_IN_SPDIF	0x00
+#define EMU_HANA_OPTICAL_IN_ADAT	0x01
+#define EMU_HANA_OPTICAL_OUT_SPDIF	0x00
+#define EMU_HANA_OPTICAL_OUT_ADAT	0x02
+
+#define EMU_HANA_MIDI_IN		0x0c	/* 000000x  1 bit  Control MIDI  */
+#define EMU_HANA_MIDI_IN_FROM_HAMOA	0x00 /* HAMOA MIDI in to Alice 2 MIDI B */
+#define EMU_HANA_MIDI_IN_FROM_DOCK	0x01 /* Audio Dock MIDI in to Alice 2 MIDI B */
+
+#define EMU_HANA_DOCK_LEDS_1	0x0d	/* 000xxxx  4 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_1_MIDI1	0x01	/* MIDI 1 LED on */
+#define EMU_HANA_DOCK_LEDS_1_MIDI2	0x02	/* MIDI 2 LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_IN	0x04	/* SMPTE IN LED on */
+#define EMU_HANA_DOCK_LEDS_1_SMPTE_OUT	0x08	/* SMPTE OUT LED on */
+
+#define EMU_HANA_DOCK_LEDS_2	0x0e	/* 0xxxxxx  6 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_2_44K	0x01	/* 44.1 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_48K	0x02	/* 48 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_96K	0x04	/* 96 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_192K	0x08	/* 192 kHz LED on */
+#define EMU_HANA_DOCK_LEDS_2_LOCK	0x10	/* LOCK LED on */
+#define EMU_HANA_DOCK_LEDS_2_EXT	0x20	/* EXT LED on */
+
+#define EMU_HANA_DOCK_LEDS_3	0x0f	/* 0xxxxxx  6 bit  Audio Dock LEDs  */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_A	0x01	/* Mic A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_CLIP_B	0x02	/* Mic B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_A	0x04	/* Signal A Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_SIGNAL_B	0x08	/* Signal B Clip LED on */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_CLIP	0x10	/* Manual Clip detection */
+#define EMU_HANA_DOCK_LEDS_3_MANUAL_SIGNAL	0x20	/* Manual Signal detection */
+
+#define EMU_HANA_ADC_PADS	0x10	/* 0000xxx  3 bit  Audio Dock ADC 14dB pads */
+#define EMU_HANA_DOCK_ADC_PAD1	0x01	/* 14dB Attenuation on Audio Dock ADC 1 */
+#define EMU_HANA_DOCK_ADC_PAD2	0x02	/* 14dB Attenuation on Audio Dock ADC 2 */
+#define EMU_HANA_DOCK_ADC_PAD3	0x04	/* 14dB Attenuation on Audio Dock ADC 3 */
+#define EMU_HANA_0202_ADC_PAD1	0x08	/* 14dB Attenuation on 0202 ADC 1 */
+
+#define EMU_HANA_DOCK_MISC	0x11	/* 0xxxxxx  6 bit  Audio Dock misc bits */
+#define EMU_HANA_DOCK_DAC1_MUTE	0x01	/* DAC 1 Mute */
+#define EMU_HANA_DOCK_DAC2_MUTE	0x02	/* DAC 2 Mute */
+#define EMU_HANA_DOCK_DAC3_MUTE	0x04	/* DAC 3 Mute */
+#define EMU_HANA_DOCK_DAC4_MUTE	0x08	/* DAC 4 Mute */
+#define EMU_HANA_DOCK_PHONES_192_DAC1	0x00	/* DAC 1 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC2	0x10	/* DAC 2 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC3	0x20	/* DAC 3 Headphones source at 192kHz */
+#define EMU_HANA_DOCK_PHONES_192_DAC4	0x30	/* DAC 4 Headphones source at 192kHz */
+
+#define EMU_HANA_MIDI_OUT	0x12	/* 00xxxxx  5 bit  Source for each MIDI out port */
+#define EMU_HANA_MIDI_OUT_0202	0x01 /* 0202 MIDI from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK1	0x02 /* Audio Dock MIDI1 front, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_DOCK2	0x04 /* Audio Dock MIDI2 rear, from Alice 2. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_SYNC2	0x08 /* Sync card. Not the actual MIDI out jack. 0 = A, 1 = B */
+#define EMU_HANA_MIDI_OUT_LOOP	0x10 /* 0 = bits (3:0) normal. 1 = MIDI loopback enabled. */
+
+#define EMU_HANA_DAC_PADS	0x13	/* 00xxxxx  5 bit  DAC 14dB attenuation pads */
+#define EMU_HANA_DOCK_DAC_PAD1	0x01	/* 14dB Attenuation on AudioDock DAC 1. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD2	0x02	/* 14dB Attenuation on AudioDock DAC 2. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD3	0x04	/* 14dB Attenuation on AudioDock DAC 3. Left and Right */
+#define EMU_HANA_DOCK_DAC_PAD4	0x08	/* 14dB Attenuation on AudioDock DAC 4. Left and Right */
+#define EMU_HANA_0202_DAC_PAD1	0x10	/* 14dB Attenuation on 0202 DAC 1. Left and Right */
+
+/* 0x14 - 0x1f Unused R/W registers */
+#define EMU_HANA_IRQ_STATUS	0x20	/* 000xxxx  4 bits IRQ Status  */
+#if 0  /* Already defined for reg 0x09 IRQ_ENABLE */
+#define EMU_HANA_IRQ_WCLK_CHANGED	0x01
+#define EMU_HANA_IRQ_ADAT		0x02
+#define EMU_HANA_IRQ_DOCK		0x04
+#define EMU_HANA_IRQ_DOCK_LOST		0x08
+#endif
+
+#define EMU_HANA_OPTION_CARDS	0x21	/* 000xxxx  4 bits Presence of option cards */
+#define EMU_HANA_OPTION_HAMOA	0x01	/* HAMOA card present */
+#define EMU_HANA_OPTION_SYNC	0x02	/* Sync card present */
+#define EMU_HANA_OPTION_DOCK_ONLINE	0x04	/* Audio Dock online and FPGA configured */
+#define EMU_HANA_OPTION_DOCK_OFFLINE	0x08	/* Audio Dock online and FPGA not configured */
+
+#define EMU_HANA_ID		0x22	/* 1010101  7 bits ID byte & 0x7f = 0x55 */
+
+#define EMU_HANA_MAJOR_REV	0x23	/* 0000xxx  3 bit  Hana FPGA Major rev */
+#define EMU_HANA_MINOR_REV	0x24	/* 0000xxx  3 bit  Hana FPGA Minor rev */
+
+#define EMU_DOCK_MAJOR_REV	0x25	/* 0000xxx  3 bit  Audio Dock FPGA Major rev */
+#define EMU_DOCK_MINOR_REV	0x26	/* 0000xxx  3 bit  Audio Dock FPGA Minor rev */
+
+#define EMU_DOCK_BOARD_ID	0x27	/* 00000xx  2 bits Audio Dock ID pins */
+#define EMU_DOCK_BOARD_ID0	0x00	/* ID bit 0 */
+#define EMU_DOCK_BOARD_ID1	0x03	/* ID bit 1 */
+
+#define EMU_HANA_WC_SPDIF_HI	0x28	/* 0xxxxxx  6 bit  SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_SPDIF_LO	0x29	/* 0xxxxxx  6 bit  SPDIF IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_ADAT_HI	0x2a	/* 0xxxxxx  6 bit  ADAT IN Word clock, upper 6 bits */
+#define EMU_HANA_WC_ADAT_LO	0x2b	/* 0xxxxxx  6 bit  ADAT IN Word clock, lower 6 bits */
+
+#define EMU_HANA_WC_BNC_LO	0x2c	/* 0xxxxxx  6 bit  BNC IN Word clock, lower 6 bits */
+#define EMU_HANA_WC_BNC_HI	0x2d	/* 0xxxxxx  6 bit  BNC IN Word clock, upper 6 bits */
+
+#define EMU_HANA2_WC_SPDIF_HI	0x2e	/* 0xxxxxx  6 bit  HANA2 SPDIF IN Word clock, upper 6 bits */
+#define EMU_HANA2_WC_SPDIF_LO	0x2f	/* 0xxxxxx  6 bit  HANA2 SPDIF IN Word clock, lower 6 bits */
+/* 0x30 - 0x3f Unused Read only registers */
+
+/************************************************************************************************/
+/* EMU1010m HANA Destinations									*/
+/************************************************************************************************/
+#define EMU_DST_ALICE2_EMU32_0	0x000f	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_1	0x0000	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_2	0x0001	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_3	0x0002	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_4	0x0003	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_5	0x0004	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_6	0x0005	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_7	0x0006	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_8	0x0007	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_9	0x0008	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_A	0x0009	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_B	0x000a	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_C	0x000b	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_D	0x000c	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_E	0x000d	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_ALICE2_EMU32_F	0x000e	/* 16 EMU32 channels to Alice2 +0 to +0xf */
+#define EMU_DST_DOCK_DAC1_LEFT1	0x0100	/* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_LEFT2	0x0101	/* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_LEFT3	0x0102	/* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_LEFT4	0x0103	/* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT1	0x0104	/* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC1_RIGHT2	0x0105	/* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT3	0x0106	/* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC1_RIGHT4	0x0107	/* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT1	0x0108	/* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_LEFT2	0x0109	/* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_LEFT3	0x010a	/* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_LEFT4	0x010b	/* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT1	0x010c	/* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC2_RIGHT2	0x010d	/* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT3	0x010e	/* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC2_RIGHT4	0x010f	/* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT1	0x0110	/* Audio Dock DAC1 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_LEFT2	0x0111	/* Audio Dock DAC1 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_LEFT3	0x0112	/* Audio Dock DAC1 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_LEFT4	0x0113	/* Audio Dock DAC1 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_LEFT1	0x0112	/* Audio Dock PHONES Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_LEFT2	0x0113	/* Audio Dock PHONES Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT1	0x0114	/* Audio Dock DAC1 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC3_RIGHT2	0x0115	/* Audio Dock DAC1 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT3	0x0116	/* Audio Dock DAC1 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC3_RIGHT4	0x0117	/* Audio Dock DAC1 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_PHONES_RIGHT1	0x0116	/* Audio Dock PHONES Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_PHONES_RIGHT2	0x0117	/* Audio Dock PHONES Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT1	0x0118	/* Audio Dock DAC2 Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_LEFT2	0x0119	/* Audio Dock DAC2 Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_LEFT3	0x011a	/* Audio Dock DAC2 Left, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_LEFT4	0x011b	/* Audio Dock DAC2 Left, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_LEFT1	0x011a	/* Audio Dock SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_LEFT2	0x011b	/* Audio Dock SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT1	0x011c	/* Audio Dock DAC2 Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_DAC4_RIGHT2	0x011d	/* Audio Dock DAC2 Right, 2nd or 96kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT3	0x011e	/* Audio Dock DAC2 Right, 3rd or 192kHz */
+#define EMU_DST_DOCK_DAC4_RIGHT4	0x011f	/* Audio Dock DAC2 Right, 4th or 192kHz */
+#define EMU_DST_DOCK_SPDIF_RIGHT1	0x011e	/* Audio Dock SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_DOCK_SPDIF_RIGHT2	0x011f	/* Audio Dock SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_LEFT1	0x0200	/* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_LEFT2	0x0202	/* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_DST_HANA_SPDIF_RIGHT1	0x0201	/* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_DST_HANA_SPDIF_RIGHT2	0x0203	/* Hana SPDIF Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT1	0x0300	/* Hamoa DAC Left, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_LEFT2	0x0302	/* Hamoa DAC Left, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_LEFT3	0x0304	/* Hamoa DAC Left, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_LEFT4	0x0306	/* Hamoa DAC Left, 4th or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT1	0x0301	/* Hamoa DAC Right, 1st or 48kHz only */
+#define EMU_DST_HAMOA_DAC_RIGHT2	0x0303	/* Hamoa DAC Right, 2nd or 96kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT3	0x0305	/* Hamoa DAC Right, 3rd or 192kHz */
+#define EMU_DST_HAMOA_DAC_RIGHT4	0x0307	/* Hamoa DAC Right, 4th or 192kHz */
+#define EMU_DST_HANA_ADAT	0x0400	/* Hana ADAT 8 channel out +0 to +7 */
+#define EMU_DST_ALICE_I2S0_LEFT		0x0500	/* Alice2 I2S0 Left */
+#define EMU_DST_ALICE_I2S0_RIGHT	0x0501	/* Alice2 I2S0 Right */
+#define EMU_DST_ALICE_I2S1_LEFT		0x0600	/* Alice2 I2S1 Left */
+#define EMU_DST_ALICE_I2S1_RIGHT	0x0601	/* Alice2 I2S1 Right */
+#define EMU_DST_ALICE_I2S2_LEFT		0x0700	/* Alice2 I2S2 Left */
+#define EMU_DST_ALICE_I2S2_RIGHT	0x0701	/* Alice2 I2S2 Right */
+
+/************************************************************************************************/
+/* EMU1010m HANA Sources									*/
+/************************************************************************************************/
+#define EMU_SRC_SILENCE		0x0000	/* Silence */
+#define EMU_SRC_DOCK_MIC_A1	0x0100	/* Audio Dock Mic A, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_A2	0x0101	/* Audio Dock Mic A, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_A3	0x0102	/* Audio Dock Mic A, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_A4	0x0103	/* Audio Dock Mic A, 4th or 192kHz */
+#define EMU_SRC_DOCK_MIC_B1	0x0104	/* Audio Dock Mic B, 1st or 48kHz only */
+#define EMU_SRC_DOCK_MIC_B2	0x0105	/* Audio Dock Mic B, 2nd or 96kHz */
+#define EMU_SRC_DOCK_MIC_B3	0x0106	/* Audio Dock Mic B, 3rd or 192kHz */
+#define EMU_SRC_DOCK_MIC_B4	0x0107	/* Audio Dock Mic B, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT1	0x0108	/* Audio Dock ADC1 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_LEFT2	0x0109	/* Audio Dock ADC1 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT3	0x010a	/* Audio Dock ADC1 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_LEFT4	0x010b	/* Audio Dock ADC1 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT1	0x010c	/* Audio Dock ADC1 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC1_RIGHT2	0x010d	/* Audio Dock ADC1 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT3	0x010e	/* Audio Dock ADC1 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC1_RIGHT4	0x010f	/* Audio Dock ADC1 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT1	0x0110	/* Audio Dock ADC2 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_LEFT2	0x0111	/* Audio Dock ADC2 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT3	0x0112	/* Audio Dock ADC2 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_LEFT4	0x0113	/* Audio Dock ADC2 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT1	0x0114	/* Audio Dock ADC2 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC2_RIGHT2	0x0115	/* Audio Dock ADC2 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT3	0x0116	/* Audio Dock ADC2 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC2_RIGHT4	0x0117	/* Audio Dock ADC2 Right, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT1	0x0118	/* Audio Dock ADC3 Left, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_LEFT2	0x0119	/* Audio Dock ADC3 Left, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT3	0x011a	/* Audio Dock ADC3 Left, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_LEFT4	0x011b	/* Audio Dock ADC3 Left, 4th or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT1	0x011c	/* Audio Dock ADC3 Right, 1st or 48kHz only */
+#define EMU_SRC_DOCK_ADC3_RIGHT2	0x011d	/* Audio Dock ADC3 Right, 2nd or 96kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT3	0x011e	/* Audio Dock ADC3 Right, 3rd or 192kHz */
+#define EMU_SRC_DOCK_ADC3_RIGHT4	0x011f	/* Audio Dock ADC3 Right, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT1	0x0200	/* Hamoa ADC Left, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_LEFT2	0x0202	/* Hamoa ADC Left, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT3	0x0204	/* Hamoa ADC Left, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_LEFT4	0x0206	/* Hamoa ADC Left, 4th or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT1	0x0201	/* Hamoa ADC Right, 1st or 48kHz only */
+#define EMU_SRC_HAMOA_ADC_RIGHT2	0x0203	/* Hamoa ADC Right, 2nd or 96kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT3	0x0205	/* Hamoa ADC Right, 3rd or 192kHz */
+#define EMU_SRC_HAMOA_ADC_RIGHT4	0x0207	/* Hamoa ADC Right, 4th or 192kHz */
+#define EMU_SRC_ALICE_EMU32A		0x0300	/* Alice2 EMU32a 16 outputs. +0 to +0xf */
+#define EMU_SRC_ALICE_EMU32B		0x0310	/* Alice2 EMU32b 16 outputs. +0 to +0xf */
+#define EMU_SRC_HANA_ADAT	0x0400	/* Hana ADAT 8 channel in +0 to +7 */
+#define EMU_SRC_HANA_SPDIF_LEFT1	0x0500	/* Hana SPDIF Left, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_LEFT2	0x0502	/* Hana SPDIF Left, 2nd or 96kHz */
+#define EMU_SRC_HANA_SPDIF_RIGHT1	0x0501	/* Hana SPDIF Right, 1st or 48kHz only */
+#define EMU_SRC_HANA_SPDIF_RIGHT2	0x0503	/* Hana SPDIF Right, 2nd or 96kHz */
+/* 0x600 and 0x700 no used */
+
+/* ------------------- STRUCTURES -------------------- */
+
+enum {
+	EMU10K1_EFX,
+	EMU10K1_PCM,
+	EMU10K1_SYNTH,
+	EMU10K1_MIDI
+};
+
+struct snd_emu10k1;
+
+struct snd_emu10k1_voice {
+	struct snd_emu10k1 *emu;
+	int number;
+	unsigned int use: 1,
+	    pcm: 1,
+	    efx: 1,
+	    synth: 1,
+	    midi: 1;
+	void (*interrupt)(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice);
+
+	struct snd_emu10k1_pcm *epcm;
+};
+
+enum {
+	PLAYBACK_EMUVOICE,
+	PLAYBACK_EFX,
+	CAPTURE_AC97ADC,
+	CAPTURE_AC97MIC,
+	CAPTURE_EFX
+};
+
+struct snd_emu10k1_pcm {
+	struct snd_emu10k1 *emu;
+	int type;
+	struct snd_pcm_substream *substream;
+	struct snd_emu10k1_voice *voices[NUM_EFX_PLAYBACK];
+	struct snd_emu10k1_voice *extra;
+	unsigned short running;
+	unsigned short first_ptr;
+	struct snd_util_memblk *memblk;
+	unsigned int start_addr;
+	unsigned int ccca_start_addr;
+	unsigned int capture_ipr;	/* interrupt acknowledge mask */
+	unsigned int capture_inte;	/* interrupt enable mask */
+	unsigned int capture_ba_reg;	/* buffer address register */
+	unsigned int capture_bs_reg;	/* buffer size register */
+	unsigned int capture_idx_reg;	/* buffer index register */
+	unsigned int capture_cr_val;	/* control value */
+	unsigned int capture_cr_val2;	/* control value2 (for audigy) */
+	unsigned int capture_bs_val;	/* buffer size value */
+	unsigned int capture_bufsize;	/* buffer size in bytes */
+};
+
+struct snd_emu10k1_pcm_mixer {
+	/* mono, left, right x 8 sends (4 on emu10k1) */
+	unsigned char send_routing[3][8];
+	unsigned char send_volume[3][8];
+	unsigned short attn[3];
+	struct snd_emu10k1_pcm *epcm;
+};
+
+#define snd_emu10k1_compose_send_routing(route) \
+((route[0] | (route[1] << 4) | (route[2] << 8) | (route[3] << 12)) << 16)
+
+#define snd_emu10k1_compose_audigy_fxrt1(route) \
+((unsigned int)route[0] | ((unsigned int)route[1] << 8) | ((unsigned int)route[2] << 16) | ((unsigned int)route[3] << 24))
+
+#define snd_emu10k1_compose_audigy_fxrt2(route) \
+((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 24))
+
+struct snd_emu10k1_memblk {
+	struct snd_util_memblk mem;
+	/* private part */
+	int first_page, last_page, pages, mapped_page;
+	unsigned int map_locked;
+	struct list_head mapped_link;
+	struct list_head mapped_order_link;
+};
+
+#define snd_emu10k1_memblk_offset(blk)	(((blk)->mapped_page << PAGE_SHIFT) | ((blk)->mem.offset & (PAGE_SIZE - 1)))
+
+#define EMU10K1_MAX_TRAM_BLOCKS_PER_CODE	16
+
+struct snd_emu10k1_fx8010_ctl {
+	struct list_head list;		/* list link container */
+	unsigned int vcount;
+	unsigned int count;		/* count of GPR (1..16) */
+	unsigned short gpr[32];		/* GPR number(s) */
+	unsigned int value[32];
+	unsigned int min;		/* minimum range */
+	unsigned int max;		/* maximum range */
+	unsigned int translation;	/* translation type (EMU10K1_GPR_TRANSLATION*) */
+	struct snd_kcontrol *kcontrol;
+};
+
+typedef void (snd_fx8010_irq_handler_t)(struct snd_emu10k1 *emu, void *private_data);
+
+struct snd_emu10k1_fx8010_irq {
+	struct snd_emu10k1_fx8010_irq *next;
+	snd_fx8010_irq_handler_t *handler;
+	unsigned short gpr_running;
+	void *private_data;
+};
+
+struct snd_emu10k1_fx8010_pcm {
+	unsigned int valid: 1,
+		     opened: 1,
+		     active: 1;
+	unsigned int channels;		/* 16-bit channels count */
+	unsigned int tram_start;	/* initial ring buffer position in TRAM (in samples) */
+	unsigned int buffer_size;	/* count of buffered samples */
+	unsigned short gpr_size;		/* GPR containing size of ring buffer in samples (host) */
+	unsigned short gpr_ptr;		/* GPR containing current pointer in the ring buffer (host = reset, FX8010) */
+	unsigned short gpr_count;	/* GPR containing count of samples between two interrupts (host) */
+	unsigned short gpr_tmpcount;	/* GPR containing current count of samples to interrupt (host = set, FX8010) */
+	unsigned short gpr_trigger;	/* GPR containing trigger (activate) information (host) */
+	unsigned short gpr_running;	/* GPR containing info if PCM is running (FX8010) */
+	unsigned char etram[32];	/* external TRAM address & data */
+	struct snd_pcm_indirect pcm_rec;
+	unsigned int tram_pos;
+	unsigned int tram_shift;
+	struct snd_emu10k1_fx8010_irq *irq;
+};
+
+struct snd_emu10k1_fx8010 {
+	unsigned short fxbus_mask;	/* used FX buses (bitmask) */
+	unsigned short extin_mask;	/* used external inputs (bitmask) */
+	unsigned short extout_mask;	/* used external outputs (bitmask) */
+	unsigned short pad1;
+	unsigned int itram_size;	/* internal TRAM size in samples */
+	struct snd_dma_buffer etram_pages; /* external TRAM pages and size */
+	unsigned int dbg;		/* FX debugger register */
+	unsigned char name[128];
+	int gpr_size;			/* size of allocated GPR controls */
+	int gpr_count;			/* count of used kcontrols */
+	struct list_head gpr_ctl;	/* GPR controls */
+	struct mutex lock;
+	struct snd_emu10k1_fx8010_pcm pcm[8];
+	spinlock_t irq_lock;
+	struct snd_emu10k1_fx8010_irq *irq_handlers;
+};
+
+#define emu10k1_gpr_ctl(n) list_entry(n, struct snd_emu10k1_fx8010_ctl, list)
+
+struct snd_emu10k1_midi {
+	struct snd_emu10k1 *emu;
+	struct snd_rawmidi *rmidi;
+	struct snd_rawmidi_substream *substream_input;
+	struct snd_rawmidi_substream *substream_output;
+	unsigned int midi_mode;
+	spinlock_t input_lock;
+	spinlock_t output_lock;
+	spinlock_t open_lock;
+	int tx_enable, rx_enable;
+	int port;
+	int ipr_tx, ipr_rx;
+	void (*interrupt)(struct snd_emu10k1 *emu, unsigned int status);
+};
+
+struct snd_emu_chip_details {
+	u32 vendor;
+	u32 device;
+	u32 subsystem;
+	unsigned char revision;
+	unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */
+	unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */
+	unsigned char ca0102_chip;  /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */
+	unsigned char ca0108_chip;  /* Audigy 2 Value */
+	unsigned char ca_cardbus_chip; /* Audigy 2 ZS Notebook */
+	unsigned char ca0151_chip;  /* P16V */
+	unsigned char spk71;        /* Has 7.1 speakers */
+	unsigned char sblive51;	    /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */
+	unsigned char spdif_bug;    /* Has Spdif phasing bug */
+	unsigned char ac97_chip;    /* Has an AC97 chip: 1 = mandatory, 2 = optional */
+	unsigned char ecard;        /* APS EEPROM */
+	unsigned char emu1010;     /* EMU 1010m card */
+	unsigned char spi_dac;      /* SPI interface for DAC */
+	unsigned char i2c_adc;      /* I2C interface for ADC */
+	unsigned char adc_1361t;    /* Use Philips 1361T ADC */
+	const char *driver;
+	const char *name;
+	const char *id;		/* for backward compatibility - can be NULL if not needed */
+};
+
+struct snd_emu1010 {
+	unsigned int output_source[64];
+	unsigned int input_source[64];
+	unsigned int adc_pads; /* bit mask */
+	unsigned int dac_pads; /* bit mask */
+	unsigned int internal_clock; /* 44100 or 48000 */
+};
+
+struct snd_emu10k1 {
+	int irq;
+
+	unsigned long port;			/* I/O port number */
+	unsigned int tos_link: 1,		/* tos link detected */
+		rear_ac97: 1,			/* rear channels are on AC'97 */
+		enable_ir: 1;
+	unsigned int support_tlv :1;
+	/* Contains profile of card capabilities */
+	const struct snd_emu_chip_details *card_capabilities;
+	unsigned int audigy;			/* is Audigy? */
+	unsigned int revision;			/* chip revision */
+	unsigned int serial;			/* serial number */
+	unsigned short model;			/* subsystem id */
+	unsigned int card_type;			/* EMU10K1_CARD_* */
+	unsigned int ecard_ctrl;		/* ecard control bits */
+	unsigned long dma_mask;			/* PCI DMA mask */
+	int max_cache_pages;			/* max memory size / PAGE_SIZE */
+	struct snd_dma_buffer silent_page;	/* silent page */
+	struct snd_dma_buffer ptb_pages;	/* page table pages */
+	struct snd_dma_device p16v_dma_dev;
+	struct snd_dma_buffer p16v_buffer;
+
+	struct snd_util_memhdr *memhdr;		/* page allocation list */
+	struct snd_emu10k1_memblk *reserved_page;	/* reserved page */
+
+	struct list_head mapped_link_head;
+	struct list_head mapped_order_link_head;
+	void **page_ptr_table;
+	unsigned long *page_addr_table;
+	spinlock_t memblk_lock;
+
+	unsigned int spdif_bits[3];		/* s/pdif out setup */
+	unsigned int i2c_capture_source;
+	u8 i2c_capture_volume[4][2];
+
+	struct snd_emu10k1_fx8010 fx8010;		/* FX8010 info */
+	int gpr_base;
+	
+	struct snd_ac97 *ac97;
+
+	struct pci_dev *pci;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct snd_pcm *pcm_mic;
+	struct snd_pcm *pcm_efx;
+	struct snd_pcm *pcm_multi;
+	struct snd_pcm *pcm_p16v;
+
+	spinlock_t synth_lock;
+	void *synth;
+	int (*get_synth_voice)(struct snd_emu10k1 *emu);
+
+	spinlock_t reg_lock;
+	spinlock_t emu_lock;
+	spinlock_t voice_lock;
+
+	struct snd_emu10k1_voice voices[NUM_G];
+	struct snd_emu10k1_voice p16v_voices[4];
+	struct snd_emu10k1_voice p16v_capture_voice;
+	int p16v_device_offset;
+	u32 p16v_capture_source;
+	u32 p16v_capture_channel;
+        struct snd_emu1010 emu1010;
+	struct snd_emu10k1_pcm_mixer pcm_mixer[32];
+	struct snd_emu10k1_pcm_mixer efx_pcm_mixer[NUM_EFX_PLAYBACK];
+	struct snd_kcontrol *ctl_send_routing;
+	struct snd_kcontrol *ctl_send_volume;
+	struct snd_kcontrol *ctl_attn;
+	struct snd_kcontrol *ctl_efx_send_routing;
+	struct snd_kcontrol *ctl_efx_send_volume;
+	struct snd_kcontrol *ctl_efx_attn;
+
+	void (*hwvol_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
+	void (*capture_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
+	void (*capture_mic_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
+	void (*capture_efx_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
+	void (*spdif_interrupt)(struct snd_emu10k1 *emu, unsigned int status);
+	void (*dsp_interrupt)(struct snd_emu10k1 *emu);
+
+	struct snd_pcm_substream *pcm_capture_substream;
+	struct snd_pcm_substream *pcm_capture_mic_substream;
+	struct snd_pcm_substream *pcm_capture_efx_substream;
+	struct snd_pcm_substream *pcm_playback_efx_substream;
+
+	struct snd_timer *timer;
+
+	struct snd_emu10k1_midi midi;
+	struct snd_emu10k1_midi midi2; /* for audigy */
+
+	unsigned int efx_voices_mask[2];
+	unsigned int next_free_voice;
+
+#ifdef CONFIG_PM
+	unsigned int *saved_ptr;
+	unsigned int *saved_gpr;
+	unsigned int *tram_val_saved;
+	unsigned int *tram_addr_saved;
+	unsigned int *saved_icode;
+	unsigned int *p16v_saved;
+	unsigned int saved_a_iocfg, saved_hcfg;
+#endif
+
+};
+
+int snd_emu10k1_create(struct snd_card *card,
+		       struct pci_dev *pci,
+		       unsigned short extin_mask,
+		       unsigned short extout_mask,
+		       long max_cache_bytes,
+		       int enable_ir,
+		       uint subsystem,
+		       struct snd_emu10k1 ** remu);
+
+int snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_p16v_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_p16v_free(struct snd_emu10k1 * emu);
+int snd_p16v_mixer(struct snd_emu10k1 * emu);
+int snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_mixer(struct snd_emu10k1 * emu, int pcm_device, int multi_device);
+int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device);
+int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep);
+
+irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id);
+
+void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int voice);
+int snd_emu10k1_init_efx(struct snd_emu10k1 *emu);
+void snd_emu10k1_free_efx(struct snd_emu10k1 *emu);
+int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size);
+int snd_emu10k1_done(struct snd_emu10k1 * emu);
+
+/* I/O functions */
+unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
+void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
+unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn);
+void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
+int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
+int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value);
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value);
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src);
+unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
+void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
+void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
+void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum);
+void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait);
+static inline unsigned int snd_emu10k1_wc(struct snd_emu10k1 *emu) { return (inl(emu->port + WC) >> 6) & 0xfffff; }
+unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
+void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);
+unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);
+
+#ifdef CONFIG_PM
+void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu);
+void snd_emu10k1_resume_init(struct snd_emu10k1 *emu);
+void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu);
+int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu);
+void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu);
+void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu);
+void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu);
+int snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu);
+void snd_p16v_free_pm_buffer(struct snd_emu10k1 *emu);
+void snd_p16v_suspend(struct snd_emu10k1 *emu);
+void snd_p16v_resume(struct snd_emu10k1 *emu);
+#endif
+
+/* memory allocation */
+struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream);
+int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
+struct snd_util_memblk *snd_emu10k1_synth_alloc(struct snd_emu10k1 *emu, unsigned int size);
+int snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
+int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, int size);
+int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, const char __user *data, int size);
+int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk);
+
+/* voice allocation */
+int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int pair, struct snd_emu10k1_voice **rvoice);
+int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice);
+
+/* MIDI uart */
+int snd_emu10k1_midi(struct snd_emu10k1 * emu);
+int snd_emu10k1_audigy_midi(struct snd_emu10k1 * emu);
+
+/* proc interface */
+int snd_emu10k1_proc_init(struct snd_emu10k1 * emu);
+
+/* fx8010 irq handler */
+int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
+					    snd_fx8010_irq_handler_t *handler,
+					    unsigned char gpr_running,
+					    void *private_data,
+					    struct snd_emu10k1_fx8010_irq **r_irq);
+int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
+					      struct snd_emu10k1_fx8010_irq *irq);
+
+#endif /* __KERNEL__ */
+
+/*
+ * ---- FX8010 ----
+ */
+
+#define EMU10K1_CARD_CREATIVE			0x00000000
+#define EMU10K1_CARD_EMUAPS			0x00000001
+
+#define EMU10K1_FX8010_PCM_COUNT		8
+
+/* instruction set */
+#define iMAC0	 0x00	/* R = A + (X * Y >> 31)   ; saturation */
+#define iMAC1	 0x01	/* R = A + (-X * Y >> 31)  ; saturation */
+#define iMAC2	 0x02	/* R = A + (X * Y >> 31)   ; wraparound */
+#define iMAC3	 0x03	/* R = A + (-X * Y >> 31)  ; wraparound */
+#define iMACINT0 0x04	/* R = A + X * Y	   ; saturation */
+#define iMACINT1 0x05	/* R = A + X * Y	   ; wraparound (31-bit) */
+#define iACC3	 0x06	/* R = A + X + Y	   ; saturation */
+#define iMACMV   0x07	/* R = A, acc += X * Y >> 31 */
+#define iANDXOR  0x08	/* R = (A & X) ^ Y */
+#define iTSTNEG  0x09	/* R = (A >= Y) ? X : ~X */
+#define iLIMITGE 0x0a	/* R = (A >= Y) ? X : Y */
+#define iLIMITLT 0x0b	/* R = (A < Y) ? X : Y */
+#define iLOG	 0x0c	/* R = linear_data, A (log_data), X (max_exp), Y (format_word) */
+#define iEXP	 0x0d	/* R = log_data, A (linear_data), X (max_exp), Y (format_word) */
+#define iINTERP  0x0e	/* R = A + (X * (Y - A) >> 31)  ; saturation */
+#define iSKIP    0x0f	/* R = A (cc_reg), X (count), Y (cc_test) */
+
+/* GPRs */
+#define FXBUS(x)	(0x00 + (x))	/* x = 0x00 - 0x0f */
+#define EXTIN(x)	(0x10 + (x))	/* x = 0x00 - 0x0f */
+#define EXTOUT(x)	(0x20 + (x))	/* x = 0x00 - 0x0f physical outs -> FXWC low 16 bits */
+#define FXBUS2(x)	(0x30 + (x))	/* x = 0x00 - 0x0f copies of fx buses for capture -> FXWC high 16 bits */
+					/* NB: 0x31 and 0x32 are shared with Center/LFE on SB live 5.1 */
+
+#define C_00000000	0x40
+#define C_00000001	0x41
+#define C_00000002	0x42
+#define C_00000003	0x43
+#define C_00000004	0x44
+#define C_00000008	0x45
+#define C_00000010	0x46
+#define C_00000020	0x47
+#define C_00000100	0x48
+#define C_00010000	0x49
+#define C_00080000	0x4a
+#define C_10000000	0x4b
+#define C_20000000	0x4c
+#define C_40000000	0x4d
+#define C_80000000	0x4e
+#define C_7fffffff	0x4f
+#define C_ffffffff	0x50
+#define C_fffffffe	0x51
+#define C_c0000000	0x52
+#define C_4f1bbcdc	0x53
+#define C_5a7ef9db	0x54
+#define C_00100000	0x55		/* ?? */
+#define GPR_ACCU	0x56		/* ACCUM, accumulator */
+#define GPR_COND	0x57		/* CCR, condition register */
+#define GPR_NOISE0	0x58		/* noise source */
+#define GPR_NOISE1	0x59		/* noise source */
+#define GPR_IRQ		0x5a		/* IRQ register */
+#define GPR_DBAC	0x5b		/* TRAM Delay Base Address Counter */
+#define GPR(x)		(FXGPREGBASE + (x)) /* free GPRs: x = 0x00 - 0xff */
+#define ITRAM_DATA(x)	(TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */
+#define ETRAM_DATA(x)	(TANKMEMDATAREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */
+#define ITRAM_ADDR(x)	(TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0x7f */
+#define ETRAM_ADDR(x)	(TANKMEMADDRREGBASE + 0x80 + (x)) /* x = 0x00 - 0x1f */
+
+#define A_ITRAM_DATA(x)	(TANKMEMDATAREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */
+#define A_ETRAM_DATA(x)	(TANKMEMDATAREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */
+#define A_ITRAM_ADDR(x)	(TANKMEMADDRREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */
+#define A_ETRAM_ADDR(x)	(TANKMEMADDRREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */
+#define A_ITRAM_CTL(x)	(A_TANKMEMCTLREGBASE + 0x00 + (x)) /* x = 0x00 - 0xbf */
+#define A_ETRAM_CTL(x)	(A_TANKMEMCTLREGBASE + 0xc0 + (x)) /* x = 0x00 - 0x3f */
+
+#define A_FXBUS(x)	(0x00 + (x))	/* x = 0x00 - 0x3f FX buses */
+#define A_EXTIN(x)	(0x40 + (x))	/* x = 0x00 - 0x0f physical ins */
+#define A_P16VIN(x)	(0x50 + (x))	/* x = 0x00 - 0x0f p16v ins (A2 only) "EMU32 inputs" */
+#define A_EXTOUT(x)	(0x60 + (x))	/* x = 0x00 - 0x1f physical outs -> A_FXWC1 0x79-7f unknown   */
+#define A_FXBUS2(x)	(0x80 + (x))	/* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */
+#define A_EMU32OUTH(x)	(0xa0 + (x))	/* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */
+#define A_EMU32OUTL(x)	(0xb0 + (x))	/* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */
+#define A_GPR(x)	(A_FXGPREGBASE + (x))
+
+/* cc_reg constants */
+#define CC_REG_NORMALIZED C_00000001
+#define CC_REG_BORROW	C_00000002
+#define CC_REG_MINUS	C_00000004
+#define CC_REG_ZERO	C_00000008
+#define CC_REG_SATURATE	C_00000010
+#define CC_REG_NONZERO	C_00000100
+
+/* FX buses */
+#define FXBUS_PCM_LEFT		0x00
+#define FXBUS_PCM_RIGHT		0x01
+#define FXBUS_PCM_LEFT_REAR	0x02
+#define FXBUS_PCM_RIGHT_REAR	0x03
+#define FXBUS_MIDI_LEFT		0x04
+#define FXBUS_MIDI_RIGHT	0x05
+#define FXBUS_PCM_CENTER	0x06
+#define FXBUS_PCM_LFE		0x07
+#define FXBUS_PCM_LEFT_FRONT	0x08
+#define FXBUS_PCM_RIGHT_FRONT	0x09
+#define FXBUS_MIDI_REVERB	0x0c
+#define FXBUS_MIDI_CHORUS	0x0d
+#define FXBUS_PCM_LEFT_SIDE	0x0e
+#define FXBUS_PCM_RIGHT_SIDE	0x0f
+#define FXBUS_PT_LEFT		0x14
+#define FXBUS_PT_RIGHT		0x15
+
+/* Inputs */
+#define EXTIN_AC97_L	   0x00	/* AC'97 capture channel - left */
+#define EXTIN_AC97_R	   0x01	/* AC'97 capture channel - right */
+#define EXTIN_SPDIF_CD_L   0x02	/* internal S/PDIF CD - onboard - left */
+#define EXTIN_SPDIF_CD_R   0x03	/* internal S/PDIF CD - onboard - right */
+#define EXTIN_ZOOM_L	   0x04	/* Zoom Video I2S - left */
+#define EXTIN_ZOOM_R	   0x05	/* Zoom Video I2S - right */
+#define EXTIN_TOSLINK_L	   0x06	/* LiveDrive - TOSLink Optical - left */
+#define EXTIN_TOSLINK_R    0x07	/* LiveDrive - TOSLink Optical - right */
+#define EXTIN_LINE1_L	   0x08	/* LiveDrive - Line/Mic 1 - left */
+#define EXTIN_LINE1_R	   0x09	/* LiveDrive - Line/Mic 1 - right */
+#define EXTIN_COAX_SPDIF_L 0x0a	/* LiveDrive - Coaxial S/PDIF - left */
+#define EXTIN_COAX_SPDIF_R 0x0b /* LiveDrive - Coaxial S/PDIF - right */
+#define EXTIN_LINE2_L	   0x0c	/* LiveDrive - Line/Mic 2 - left */
+#define EXTIN_LINE2_R	   0x0d	/* LiveDrive - Line/Mic 2 - right */
+
+/* Outputs */
+#define EXTOUT_AC97_L	   0x00	/* AC'97 playback channel - left */
+#define EXTOUT_AC97_R	   0x01	/* AC'97 playback channel - right */
+#define EXTOUT_TOSLINK_L   0x02	/* LiveDrive - TOSLink Optical - left */
+#define EXTOUT_TOSLINK_R   0x03	/* LiveDrive - TOSLink Optical - right */
+#define EXTOUT_AC97_CENTER 0x04	/* SB Live 5.1 - center */
+#define EXTOUT_AC97_LFE	   0x05 /* SB Live 5.1 - LFE */
+#define EXTOUT_HEADPHONE_L 0x06	/* LiveDrive - Headphone - left */
+#define EXTOUT_HEADPHONE_R 0x07	/* LiveDrive - Headphone - right */
+#define EXTOUT_REAR_L	   0x08	/* Rear channel - left */
+#define EXTOUT_REAR_R	   0x09	/* Rear channel - right */
+#define EXTOUT_ADC_CAP_L   0x0a	/* ADC Capture buffer - left */
+#define EXTOUT_ADC_CAP_R   0x0b	/* ADC Capture buffer - right */
+#define EXTOUT_MIC_CAP	   0x0c	/* MIC Capture buffer */
+#define EXTOUT_AC97_REAR_L 0x0d	/* SB Live 5.1 (c) 2003 - Rear Left */
+#define EXTOUT_AC97_REAR_R 0x0e	/* SB Live 5.1 (c) 2003 - Rear Right */
+#define EXTOUT_ACENTER	   0x11 /* Analog Center */
+#define EXTOUT_ALFE	   0x12 /* Analog LFE */
+
+/* Audigy Inputs */
+#define A_EXTIN_AC97_L		0x00	/* AC'97 capture channel - left */
+#define A_EXTIN_AC97_R		0x01	/* AC'97 capture channel - right */
+#define A_EXTIN_SPDIF_CD_L	0x02	/* digital CD left */
+#define A_EXTIN_SPDIF_CD_R	0x03	/* digital CD left */
+#define A_EXTIN_OPT_SPDIF_L     0x04    /* audigy drive Optical SPDIF - left */
+#define A_EXTIN_OPT_SPDIF_R     0x05    /*                              right */ 
+#define A_EXTIN_LINE2_L		0x08	/* audigy drive line2/mic2 - left */
+#define A_EXTIN_LINE2_R		0x09	/*                           right */
+#define A_EXTIN_ADC_L		0x0a    /* Philips ADC - left */
+#define A_EXTIN_ADC_R		0x0b    /*               right */
+#define A_EXTIN_AUX2_L		0x0c	/* audigy drive aux2 - left */
+#define A_EXTIN_AUX2_R		0x0d	/*                   - right */
+
+/* Audigiy Outputs */
+#define A_EXTOUT_FRONT_L	0x00	/* digital front left */
+#define A_EXTOUT_FRONT_R	0x01	/*               right */
+#define A_EXTOUT_CENTER		0x02	/* digital front center */
+#define A_EXTOUT_LFE		0x03	/* digital front lfe */
+#define A_EXTOUT_HEADPHONE_L	0x04	/* headphone audigy drive left */
+#define A_EXTOUT_HEADPHONE_R	0x05	/*                        right */
+#define A_EXTOUT_REAR_L		0x06	/* digital rear left */
+#define A_EXTOUT_REAR_R		0x07	/*              right */
+#define A_EXTOUT_AFRONT_L	0x08	/* analog front left */
+#define A_EXTOUT_AFRONT_R	0x09	/*              right */
+#define A_EXTOUT_ACENTER	0x0a	/* analog center */
+#define A_EXTOUT_ALFE		0x0b	/* analog LFE */
+#define A_EXTOUT_ASIDE_L	0x0c	/* analog side left  - Audigy 2 ZS */
+#define A_EXTOUT_ASIDE_R	0x0d	/*             right - Audigy 2 ZS */
+#define A_EXTOUT_AREAR_L	0x0e	/* analog rear left */
+#define A_EXTOUT_AREAR_R	0x0f	/*             right */
+#define A_EXTOUT_AC97_L		0x10	/* AC97 left (front) */
+#define A_EXTOUT_AC97_R		0x11	/*      right */
+#define A_EXTOUT_ADC_CAP_L	0x16	/* ADC capture buffer left */
+#define A_EXTOUT_ADC_CAP_R	0x17	/*                    right */
+#define A_EXTOUT_MIC_CAP	0x18	/* Mic capture buffer */
+
+/* Audigy constants */
+#define A_C_00000000	0xc0
+#define A_C_00000001	0xc1
+#define A_C_00000002	0xc2
+#define A_C_00000003	0xc3
+#define A_C_00000004	0xc4
+#define A_C_00000008	0xc5
+#define A_C_00000010	0xc6
+#define A_C_00000020	0xc7
+#define A_C_00000100	0xc8
+#define A_C_00010000	0xc9
+#define A_C_00000800	0xca
+#define A_C_10000000	0xcb
+#define A_C_20000000	0xcc
+#define A_C_40000000	0xcd
+#define A_C_80000000	0xce
+#define A_C_7fffffff	0xcf
+#define A_C_ffffffff	0xd0
+#define A_C_fffffffe	0xd1
+#define A_C_c0000000	0xd2
+#define A_C_4f1bbcdc	0xd3
+#define A_C_5a7ef9db	0xd4
+#define A_C_00100000	0xd5
+#define A_GPR_ACCU	0xd6		/* ACCUM, accumulator */
+#define A_GPR_COND	0xd7		/* CCR, condition register */
+#define A_GPR_NOISE0	0xd8		/* noise source */
+#define A_GPR_NOISE1	0xd9		/* noise source */
+#define A_GPR_IRQ	0xda		/* IRQ register */
+#define A_GPR_DBAC	0xdb		/* TRAM Delay Base Address Counter - internal */
+#define A_GPR_DBACE	0xde		/* TRAM Delay Base Address Counter - external */
+
+/* definitions for debug register */
+#define EMU10K1_DBG_ZC			0x80000000	/* zero tram counter */
+#define EMU10K1_DBG_SATURATION_OCCURED	0x02000000	/* saturation control */
+#define EMU10K1_DBG_SATURATION_ADDR	0x01ff0000	/* saturation address */
+#define EMU10K1_DBG_SINGLE_STEP		0x00008000	/* single step mode */
+#define EMU10K1_DBG_STEP		0x00004000	/* start single step */
+#define EMU10K1_DBG_CONDITION_CODE	0x00003e00	/* condition code */
+#define EMU10K1_DBG_SINGLE_STEP_ADDR	0x000001ff	/* single step address */
+
+/* tank memory address line */
+#ifndef __KERNEL__
+#define TANKMEMADDRREG_ADDR_MASK 0x000fffff	/* 20 bit tank address field			*/
+#define TANKMEMADDRREG_CLEAR	 0x00800000	/* Clear tank memory				*/
+#define TANKMEMADDRREG_ALIGN	 0x00400000	/* Align read or write relative to tank access	*/
+#define TANKMEMADDRREG_WRITE	 0x00200000	/* Write to tank memory				*/
+#define TANKMEMADDRREG_READ	 0x00100000	/* Read from tank memory			*/
+#endif
+
+struct snd_emu10k1_fx8010_info {
+	unsigned int internal_tram_size;	/* in samples */
+	unsigned int external_tram_size;	/* in samples */
+	char fxbus_names[16][32];		/* names of FXBUSes */
+	char extin_names[16][32];		/* names of external inputs */
+	char extout_names[32][32];		/* names of external outputs */
+	unsigned int gpr_controls;		/* count of GPR controls */
+};
+
+#define EMU10K1_GPR_TRANSLATION_NONE		0
+#define EMU10K1_GPR_TRANSLATION_TABLE100	1
+#define EMU10K1_GPR_TRANSLATION_BASS		2
+#define EMU10K1_GPR_TRANSLATION_TREBLE		3
+#define EMU10K1_GPR_TRANSLATION_ONOFF		4
+
+struct snd_emu10k1_fx8010_control_gpr {
+	struct snd_ctl_elem_id id;		/* full control ID definition */
+	unsigned int vcount;		/* visible count */
+	unsigned int count;		/* count of GPR (1..16) */
+	unsigned short gpr[32];		/* GPR number(s) */
+	unsigned int value[32];		/* initial values */
+	unsigned int min;		/* minimum range */
+	unsigned int max;		/* maximum range */
+	unsigned int translation;	/* translation type (EMU10K1_GPR_TRANSLATION*) */
+	const unsigned int *tlv;
+};
+
+/* old ABI without TLV support */
+struct snd_emu10k1_fx8010_control_old_gpr {
+	struct snd_ctl_elem_id id;
+	unsigned int vcount;
+	unsigned int count;
+	unsigned short gpr[32];
+	unsigned int value[32];
+	unsigned int min;
+	unsigned int max;
+	unsigned int translation;
+};
+
+struct snd_emu10k1_fx8010_code {
+	char name[128];
+
+	DECLARE_BITMAP(gpr_valid, 0x200); /* bitmask of valid initializers */
+	u_int32_t __user *gpr_map;	  /* initializers */
+
+	unsigned int gpr_add_control_count; /* count of GPR controls to add/replace */
+	struct snd_emu10k1_fx8010_control_gpr __user *gpr_add_controls; /* GPR controls to add/replace */
+
+	unsigned int gpr_del_control_count; /* count of GPR controls to remove */
+	struct snd_ctl_elem_id __user *gpr_del_controls; /* IDs of GPR controls to remove */
+
+	unsigned int gpr_list_control_count; /* count of GPR controls to list */
+	unsigned int gpr_list_control_total; /* total count of GPR controls */
+	struct snd_emu10k1_fx8010_control_gpr __user *gpr_list_controls; /* listed GPR controls */
+
+	DECLARE_BITMAP(tram_valid, 0x100); /* bitmask of valid initializers */
+	u_int32_t __user *tram_data_map;  /* data initializers */
+	u_int32_t __user *tram_addr_map;  /* map initializers */
+
+	DECLARE_BITMAP(code_valid, 1024); /* bitmask of valid instructions */
+	u_int32_t __user *code;		  /* one instruction - 64 bits */
+};
+
+struct snd_emu10k1_fx8010_tram {
+	unsigned int address;		/* 31.bit == 1 -> external TRAM */
+	unsigned int size;		/* size in samples (4 bytes) */
+	unsigned int *samples;		/* pointer to samples (20-bit) */
+					/* NULL->clear memory */
+};
+
+struct snd_emu10k1_fx8010_pcm_rec {
+	unsigned int substream;		/* substream number */
+	unsigned int res1;		/* reserved */
+	unsigned int channels;		/* 16-bit channels count, zero = remove this substream */
+	unsigned int tram_start;	/* ring buffer position in TRAM (in samples) */
+	unsigned int buffer_size;	/* count of buffered samples */
+	unsigned short gpr_size;		/* GPR containing size of ringbuffer in samples (host) */
+	unsigned short gpr_ptr;		/* GPR containing current pointer in the ring buffer (host = reset, FX8010) */
+	unsigned short gpr_count;	/* GPR containing count of samples between two interrupts (host) */
+	unsigned short gpr_tmpcount;	/* GPR containing current count of samples to interrupt (host = set, FX8010) */
+	unsigned short gpr_trigger;	/* GPR containing trigger (activate) information (host) */
+	unsigned short gpr_running;	/* GPR containing info if PCM is running (FX8010) */
+	unsigned char pad;		/* reserved */
+	unsigned char etram[32];	/* external TRAM address & data (one per channel) */
+	unsigned int res2;		/* reserved */
+};
+
+#define SNDRV_EMU10K1_VERSION		SNDRV_PROTOCOL_VERSION(1, 0, 1)
+
+#define SNDRV_EMU10K1_IOCTL_INFO	_IOR ('H', 0x10, struct snd_emu10k1_fx8010_info)
+#define SNDRV_EMU10K1_IOCTL_CODE_POKE	_IOW ('H', 0x11, struct snd_emu10k1_fx8010_code)
+#define SNDRV_EMU10K1_IOCTL_CODE_PEEK	_IOWR('H', 0x12, struct snd_emu10k1_fx8010_code)
+#define SNDRV_EMU10K1_IOCTL_TRAM_SETUP	_IOW ('H', 0x20, int)
+#define SNDRV_EMU10K1_IOCTL_TRAM_POKE	_IOW ('H', 0x21, struct snd_emu10k1_fx8010_tram)
+#define SNDRV_EMU10K1_IOCTL_TRAM_PEEK	_IOWR('H', 0x22, struct snd_emu10k1_fx8010_tram)
+#define SNDRV_EMU10K1_IOCTL_PCM_POKE	_IOW ('H', 0x30, struct snd_emu10k1_fx8010_pcm_rec)
+#define SNDRV_EMU10K1_IOCTL_PCM_PEEK	_IOWR('H', 0x31, struct snd_emu10k1_fx8010_pcm_rec)
+#define SNDRV_EMU10K1_IOCTL_PVERSION	_IOR ('H', 0x40, int)
+#define SNDRV_EMU10K1_IOCTL_STOP	_IO  ('H', 0x80)
+#define SNDRV_EMU10K1_IOCTL_CONTINUE	_IO  ('H', 0x81)
+#define SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER _IO ('H', 0x82)
+#define SNDRV_EMU10K1_IOCTL_SINGLE_STEP	_IOW ('H', 0x83, int)
+#define SNDRV_EMU10K1_IOCTL_DBG_READ	_IOR ('H', 0x84, int)
+
+/* typedefs for compatibility to user-space */
+typedef struct snd_emu10k1_fx8010_info emu10k1_fx8010_info_t;
+typedef struct snd_emu10k1_fx8010_control_gpr emu10k1_fx8010_control_gpr_t;
+typedef struct snd_emu10k1_fx8010_code emu10k1_fx8010_code_t;
+typedef struct snd_emu10k1_fx8010_tram emu10k1_fx8010_tram_t;
+typedef struct snd_emu10k1_fx8010_pcm_rec emu10k1_fx8010_pcm_t;
+
+#endif	/* __SOUND_EMU10K1_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/hdspm.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/hdspm.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/hdspm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/hdspm.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,128 @@
+#ifndef __SOUND_HDSPM_H		/* -*- linux-c -*- */
+#define __SOUND_HDSPM_H
+/*
+ *   Copyright (C) 2003 Winfried Ritsch (IEM)
+ *   based on hdsp.h from Thomas Charbonnel (thomas@undata.org)
+ *                      
+ *    
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
+#define HDSPM_MAX_CHANNELS      64
+
+/* -------------------- IOCTL Peak/RMS Meters -------------------- */
+
+/* peam rms level structure like we get from hardware 
+  
+   maybe in future we can memory map it so I just copy it
+   to user on ioctl call now an dont change anything
+   rms are made out of low and high values
+   where (long) ????_rms = (????_rms_l >> 8) + ((????_rms_h & 0xFFFFFF00)<<24)
+   (i asume so from the code)
+*/
+
+struct hdspm_peak_rms {
+
+	unsigned int level_offset[1024];
+
+	unsigned int input_peak[64];
+	unsigned int playback_peak[64];
+	unsigned int output_peak[64];
+	unsigned int xxx_peak[64];	/* not used */
+
+	unsigned int reserved[256];	/* not used */
+
+	unsigned int input_rms_l[64];
+	unsigned int playback_rms_l[64];
+	unsigned int output_rms_l[64];
+	unsigned int xxx_rms_l[64];	/* not used */
+
+	unsigned int input_rms_h[64];
+	unsigned int playback_rms_h[64];
+	unsigned int output_rms_h[64];
+	unsigned int xxx_rms_h[64];	/* not used */
+};
+
+struct hdspm_peak_rms_ioctl {
+	struct hdspm_peak_rms *peak;
+};
+
+/* use indirect access due to the limit of ioctl bit size */
+#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct hdspm_peak_rms_ioctl)
+
+/* ------------ CONFIG block IOCTL ---------------------- */
+
+struct hdspm_config_info {
+	unsigned char pref_sync_ref;
+	unsigned char wordclock_sync_check;
+	unsigned char madi_sync_check;
+	unsigned int system_sample_rate;
+	unsigned int autosync_sample_rate;
+	unsigned char system_clock_mode;
+	unsigned char clock_source;
+	unsigned char autosync_ref;
+	unsigned char line_out;
+	unsigned int passthru;
+	unsigned int analog_out;
+};
+
+#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, struct hdspm_config_info)
+
+
+/* get Soundcard Version */
+
+struct hdspm_version {
+	unsigned short firmware_rev;
+};
+
+#define SNDRV_HDSPM_IOCTL_GET_VERSION _IOR('H', 0x43, struct hdspm_version)
+
+
+/* ------------- get Matrix Mixer IOCTL --------------- */
+
+/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = 32768 Bytes */
+
+/* organisation is 64 channelfader in a continous memory block */
+/* equivalent to hardware definition, maybe for future feature of mmap of them */
+/* each of 64 outputs has 64 infader and 64 outfader: 
+   Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */
+
+#define HDSPM_MIXER_CHANNELS HDSPM_MAX_CHANNELS
+
+struct hdspm_channelfader {
+	unsigned int in[HDSPM_MIXER_CHANNELS];
+	unsigned int pb[HDSPM_MIXER_CHANNELS];
+};
+
+struct hdspm_mixer {
+	struct hdspm_channelfader ch[HDSPM_MIXER_CHANNELS];
+};
+
+struct hdspm_mixer_ioctl {
+	struct hdspm_mixer *mixer;
+};
+
+/* use indirect access due to the limit of ioctl bit size */
+#define SNDRV_HDSPM_IOCTL_GET_MIXER _IOR('H', 0x44, struct hdspm_mixer_ioctl)
+
+/* typedefs for compatibility to user-space */
+typedef struct hdspm_peak_rms hdspm_peak_rms_t;
+typedef struct hdspm_config_info hdspm_config_info_t;
+typedef struct hdspm_version hdspm_version_t;
+typedef struct hdspm_channelfader snd_hdspm_channelfader_t;
+typedef struct hdspm_mixer hdspm_mixer_t;
+
+#endif				/* __SOUND_HDSPM_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/pcm.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/pcm.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/pcm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/pcm.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,1008 @@
+#ifndef __SOUND_PCM_H
+#define __SOUND_PCM_H
+
+/*
+ *  Digital Audio (PCM) abstract layer
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *                   Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   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/asound.h>
+#include <sound/memalloc.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/bitops.h>
+
+#define snd_pcm_substream_chip(substream) ((substream)->private_data)
+#define snd_pcm_chip(pcm) ((pcm)->private_data)
+
+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#include "pcm_oss.h"
+#endif
+
+/*
+ *  Hardware (lowlevel) section
+ */
+
+struct snd_pcm_hardware {
+	unsigned int info;		/* SNDRV_PCM_INFO_* */
+	u64 formats;			/* SNDRV_PCM_FMTBIT_* */
+	unsigned int rates;		/* SNDRV_PCM_RATE_* */
+	unsigned int rate_min;		/* min rate */
+	unsigned int rate_max;		/* max rate */
+	unsigned int channels_min;	/* min channels */
+	unsigned int channels_max;	/* max channels */
+	size_t buffer_bytes_max;	/* max buffer size */
+	size_t period_bytes_min;	/* min period size */
+	size_t period_bytes_max;	/* max period size */
+	unsigned int periods_min;	/* min # of periods */
+	unsigned int periods_max;	/* max # of periods */
+	size_t fifo_size;		/* fifo size in bytes */
+};
+
+struct snd_pcm_substream;
+
+struct snd_pcm_ops {
+	int (*open)(struct snd_pcm_substream *substream);
+	int (*close)(struct snd_pcm_substream *substream);
+	int (*ioctl)(struct snd_pcm_substream * substream,
+		     unsigned int cmd, void *arg);
+	int (*hw_params)(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params);
+	int (*hw_free)(struct snd_pcm_substream *substream);
+	int (*prepare)(struct snd_pcm_substream *substream);
+	int (*trigger)(struct snd_pcm_substream *substream, int cmd);
+	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
+	int (*copy)(struct snd_pcm_substream *substream, int channel,
+		    snd_pcm_uframes_t pos,
+		    void __user *buf, snd_pcm_uframes_t count);
+	int (*silence)(struct snd_pcm_substream *substream, int channel, 
+		       snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
+	struct page *(*page)(struct snd_pcm_substream *substream,
+			     unsigned long offset);
+	int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
+	int (*ack)(struct snd_pcm_substream *substream);
+};
+
+/*
+ *
+ */
+
+#define SNDRV_PCM_DEVICES		8
+
+#define SNDRV_PCM_IOCTL1_FALSE		((void *)0)
+#define SNDRV_PCM_IOCTL1_TRUE		((void *)1)
+
+#define SNDRV_PCM_IOCTL1_RESET		0
+#define SNDRV_PCM_IOCTL1_INFO		1
+#define SNDRV_PCM_IOCTL1_CHANNEL_INFO	2
+#define SNDRV_PCM_IOCTL1_GSTATE		3
+
+#define SNDRV_PCM_TRIGGER_STOP		0
+#define SNDRV_PCM_TRIGGER_START		1
+#define SNDRV_PCM_TRIGGER_PAUSE_PUSH	3
+#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE	4
+#define SNDRV_PCM_TRIGGER_SUSPEND	5
+#define SNDRV_PCM_TRIGGER_RESUME	6
+
+#define SNDRV_PCM_POS_XRUN		((snd_pcm_uframes_t)-1)
+
+/* If you change this don't forget to change rates[] table in pcm_native.c */
+#define SNDRV_PCM_RATE_5512		(1<<0)		/* 5512Hz */
+#define SNDRV_PCM_RATE_8000		(1<<1)		/* 8000Hz */
+#define SNDRV_PCM_RATE_11025		(1<<2)		/* 11025Hz */
+#define SNDRV_PCM_RATE_16000		(1<<3)		/* 16000Hz */
+#define SNDRV_PCM_RATE_22050		(1<<4)		/* 22050Hz */
+#define SNDRV_PCM_RATE_32000		(1<<5)		/* 32000Hz */
+#define SNDRV_PCM_RATE_44100		(1<<6)		/* 44100Hz */
+#define SNDRV_PCM_RATE_48000		(1<<7)		/* 48000Hz */
+#define SNDRV_PCM_RATE_64000		(1<<8)		/* 64000Hz */
+#define SNDRV_PCM_RATE_88200		(1<<9)		/* 88200Hz */
+#define SNDRV_PCM_RATE_96000		(1<<10)		/* 96000Hz */
+#define SNDRV_PCM_RATE_176400		(1<<11)		/* 176400Hz */
+#define SNDRV_PCM_RATE_192000		(1<<12)		/* 192000Hz */
+
+#define SNDRV_PCM_RATE_CONTINUOUS	(1<<30)		/* continuous range */
+#define SNDRV_PCM_RATE_KNOT		(1<<31)		/* supports more non-continuos rates */
+
+#define SNDRV_PCM_RATE_8000_44100	(SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\
+					 SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\
+					 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100)
+#define SNDRV_PCM_RATE_8000_48000	(SNDRV_PCM_RATE_8000_44100|SNDRV_PCM_RATE_48000)
+#define SNDRV_PCM_RATE_8000_96000	(SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_64000|\
+					 SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
+#define SNDRV_PCM_RATE_8000_192000	(SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\
+					 SNDRV_PCM_RATE_192000)
+#define SNDRV_PCM_FMTBIT_S8		(1ULL << SNDRV_PCM_FORMAT_S8)
+#define SNDRV_PCM_FMTBIT_U8		(1ULL << SNDRV_PCM_FORMAT_U8)
+#define SNDRV_PCM_FMTBIT_S16_LE		(1ULL << SNDRV_PCM_FORMAT_S16_LE)
+#define SNDRV_PCM_FMTBIT_S16_BE		(1ULL << SNDRV_PCM_FORMAT_S16_BE)
+#define SNDRV_PCM_FMTBIT_U16_LE		(1ULL << SNDRV_PCM_FORMAT_U16_LE)
+#define SNDRV_PCM_FMTBIT_U16_BE		(1ULL << SNDRV_PCM_FORMAT_U16_BE)
+#define SNDRV_PCM_FMTBIT_S24_LE		(1ULL << SNDRV_PCM_FORMAT_S24_LE)
+#define SNDRV_PCM_FMTBIT_S24_BE		(1ULL << SNDRV_PCM_FORMAT_S24_BE)
+#define SNDRV_PCM_FMTBIT_U24_LE		(1ULL << SNDRV_PCM_FORMAT_U24_LE)
+#define SNDRV_PCM_FMTBIT_U24_BE		(1ULL << SNDRV_PCM_FORMAT_U24_BE)
+#define SNDRV_PCM_FMTBIT_S32_LE		(1ULL << SNDRV_PCM_FORMAT_S32_LE)
+#define SNDRV_PCM_FMTBIT_S32_BE		(1ULL << SNDRV_PCM_FORMAT_S32_BE)
+#define SNDRV_PCM_FMTBIT_U32_LE		(1ULL << SNDRV_PCM_FORMAT_U32_LE)
+#define SNDRV_PCM_FMTBIT_U32_BE		(1ULL << SNDRV_PCM_FORMAT_U32_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT_LE	(1ULL << SNDRV_PCM_FORMAT_FLOAT_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT_BE	(1ULL << SNDRV_PCM_FORMAT_FLOAT_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_LE	(1ULL << SNDRV_PCM_FORMAT_FLOAT64_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_BE	(1ULL << SNDRV_PCM_FORMAT_FLOAT64_BE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE)
+#define SNDRV_PCM_FMTBIT_MU_LAW		(1ULL << SNDRV_PCM_FORMAT_MU_LAW)
+#define SNDRV_PCM_FMTBIT_A_LAW		(1ULL << SNDRV_PCM_FORMAT_A_LAW)
+#define SNDRV_PCM_FMTBIT_IMA_ADPCM	(1ULL << SNDRV_PCM_FORMAT_IMA_ADPCM)
+#define SNDRV_PCM_FMTBIT_MPEG		(1ULL << SNDRV_PCM_FORMAT_MPEG)
+#define SNDRV_PCM_FMTBIT_GSM		(1ULL << SNDRV_PCM_FORMAT_GSM)
+#define SNDRV_PCM_FMTBIT_SPECIAL	(1ULL << SNDRV_PCM_FORMAT_SPECIAL)
+#define SNDRV_PCM_FMTBIT_S24_3LE	(1ULL << SNDRV_PCM_FORMAT_S24_3LE)
+#define SNDRV_PCM_FMTBIT_U24_3LE	(1ULL << SNDRV_PCM_FORMAT_U24_3LE)
+#define SNDRV_PCM_FMTBIT_S24_3BE	(1ULL << SNDRV_PCM_FORMAT_S24_3BE)
+#define SNDRV_PCM_FMTBIT_U24_3BE	(1ULL << SNDRV_PCM_FORMAT_U24_3BE)
+#define SNDRV_PCM_FMTBIT_S20_3LE	(1ULL << SNDRV_PCM_FORMAT_S20_3LE)
+#define SNDRV_PCM_FMTBIT_U20_3LE	(1ULL << SNDRV_PCM_FORMAT_U20_3LE)
+#define SNDRV_PCM_FMTBIT_S20_3BE	(1ULL << SNDRV_PCM_FORMAT_S20_3BE)
+#define SNDRV_PCM_FMTBIT_U20_3BE	(1ULL << SNDRV_PCM_FORMAT_U20_3BE)
+#define SNDRV_PCM_FMTBIT_S18_3LE	(1ULL << SNDRV_PCM_FORMAT_S18_3LE)
+#define SNDRV_PCM_FMTBIT_U18_3LE	(1ULL << SNDRV_PCM_FORMAT_U18_3LE)
+#define SNDRV_PCM_FMTBIT_S18_3BE	(1ULL << SNDRV_PCM_FORMAT_S18_3BE)
+#define SNDRV_PCM_FMTBIT_U18_3BE	(1ULL << SNDRV_PCM_FORMAT_U18_3BE)
+
+#ifdef SNDRV_LITTLE_ENDIAN
+#define SNDRV_PCM_FMTBIT_S16		SNDRV_PCM_FMTBIT_S16_LE
+#define SNDRV_PCM_FMTBIT_U16		SNDRV_PCM_FMTBIT_U16_LE
+#define SNDRV_PCM_FMTBIT_S24		SNDRV_PCM_FMTBIT_S24_LE
+#define SNDRV_PCM_FMTBIT_U24		SNDRV_PCM_FMTBIT_U24_LE
+#define SNDRV_PCM_FMTBIT_S32		SNDRV_PCM_FMTBIT_S32_LE
+#define SNDRV_PCM_FMTBIT_U32		SNDRV_PCM_FMTBIT_U32_LE
+#define SNDRV_PCM_FMTBIT_FLOAT		SNDRV_PCM_FMTBIT_FLOAT_LE
+#define SNDRV_PCM_FMTBIT_FLOAT64	SNDRV_PCM_FMTBIT_FLOAT64_LE
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE
+#endif
+#ifdef SNDRV_BIG_ENDIAN
+#define SNDRV_PCM_FMTBIT_S16		SNDRV_PCM_FMTBIT_S16_BE
+#define SNDRV_PCM_FMTBIT_U16		SNDRV_PCM_FMTBIT_U16_BE
+#define SNDRV_PCM_FMTBIT_S24		SNDRV_PCM_FMTBIT_S24_BE
+#define SNDRV_PCM_FMTBIT_U24		SNDRV_PCM_FMTBIT_U24_BE
+#define SNDRV_PCM_FMTBIT_S32		SNDRV_PCM_FMTBIT_S32_BE
+#define SNDRV_PCM_FMTBIT_U32		SNDRV_PCM_FMTBIT_U32_BE
+#define SNDRV_PCM_FMTBIT_FLOAT		SNDRV_PCM_FMTBIT_FLOAT_BE
+#define SNDRV_PCM_FMTBIT_FLOAT64	SNDRV_PCM_FMTBIT_FLOAT64_BE
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE
+#endif
+
+struct snd_pcm_file {
+	struct snd_pcm_substream *substream;
+	int no_compat_mmap;
+};
+
+struct snd_pcm_hw_rule;
+typedef int (*snd_pcm_hw_rule_func_t)(struct snd_pcm_hw_params *params,
+				      struct snd_pcm_hw_rule *rule);
+
+struct snd_pcm_hw_rule {
+	unsigned int cond;
+	snd_pcm_hw_rule_func_t func;
+	int var;
+	int deps[4];
+	void *private;
+};
+
+struct snd_pcm_hw_constraints {
+	struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - 
+			 SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
+			     SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+	unsigned int rules_num;
+	unsigned int rules_all;
+	struct snd_pcm_hw_rule *rules;
+};
+
+static inline struct snd_mask *constrs_mask(struct snd_pcm_hw_constraints *constrs,
+					    snd_pcm_hw_param_t var)
+{
+	return &constrs->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK];
+}
+
+static inline struct snd_interval *constrs_interval(struct snd_pcm_hw_constraints *constrs,
+						    snd_pcm_hw_param_t var)
+{
+	return &constrs->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
+}
+
+struct snd_ratnum {
+	unsigned int num;
+	unsigned int den_min, den_max, den_step;
+};
+
+struct snd_ratden {
+	unsigned int num_min, num_max, num_step;
+	unsigned int den;
+};
+
+struct snd_pcm_hw_constraint_ratnums {
+	int nrats;
+	struct snd_ratnum *rats;
+};
+
+struct snd_pcm_hw_constraint_ratdens {
+	int nrats;
+	struct snd_ratden *rats;
+};
+
+struct snd_pcm_hw_constraint_list {
+	unsigned int count;
+	unsigned int *list;
+	unsigned int mask;
+};
+
+struct snd_pcm_runtime {
+	/* -- Status -- */
+	struct snd_pcm_substream *trigger_master;
+	struct timespec trigger_tstamp;	/* trigger timestamp */
+	int overrange;
+	snd_pcm_uframes_t avail_max;
+	snd_pcm_uframes_t hw_ptr_base;	/* Position at buffer restart */
+	snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time*/
+
+	/* -- HW params -- */
+	snd_pcm_access_t access;	/* access mode */
+	snd_pcm_format_t format;	/* SNDRV_PCM_FORMAT_* */
+	snd_pcm_subformat_t subformat;	/* subformat */
+	unsigned int rate;		/* rate in Hz */
+	unsigned int channels;		/* channels */
+	snd_pcm_uframes_t period_size;	/* period size */
+	unsigned int periods;		/* periods */
+	snd_pcm_uframes_t buffer_size;	/* buffer size */
+	unsigned int tick_time;		/* tick time */
+	snd_pcm_uframes_t min_align;	/* Min alignment for the format */
+	size_t byte_align;
+	unsigned int frame_bits;
+	unsigned int sample_bits;
+	unsigned int info;
+	unsigned int rate_num;
+	unsigned int rate_den;
+
+	/* -- SW params -- */
+	int tstamp_mode;		/* mmap timestamp is updated */
+  	unsigned int period_step;
+	unsigned int sleep_min;		/* min ticks to sleep */
+	snd_pcm_uframes_t xfer_align;	/* xfer size need to be a multiple */
+	snd_pcm_uframes_t start_threshold;
+	snd_pcm_uframes_t stop_threshold;
+	snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
+						noise is nearest than this */
+	snd_pcm_uframes_t silence_size;	/* Silence filling size */
+	snd_pcm_uframes_t boundary;	/* pointers wrap point */
+
+	snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
+	snd_pcm_uframes_t silence_filled; /* size filled with silence */
+
+	union snd_pcm_sync_id sync;	/* hardware synchronization ID */
+
+	/* -- mmap -- */
+	volatile struct snd_pcm_mmap_status *status;
+	volatile struct snd_pcm_mmap_control *control;
+
+	/* -- locking / scheduling -- */
+	wait_queue_head_t sleep;
+	struct timer_list tick_timer;
+	struct fasync_struct *fasync;
+
+	/* -- private section -- */
+	void *private_data;
+	void (*private_free)(struct snd_pcm_runtime *runtime);
+
+	/* -- hardware description -- */
+	struct snd_pcm_hardware hw;
+	struct snd_pcm_hw_constraints hw_constraints;
+
+	/* -- interrupt callbacks -- */
+	void (*transfer_ack_begin)(struct snd_pcm_substream *substream);
+	void (*transfer_ack_end)(struct snd_pcm_substream *substream);
+
+	/* -- timer -- */
+	unsigned int timer_resolution;	/* timer resolution */
+
+	/* -- DMA -- */           
+	unsigned char *dma_area;	/* DMA area */
+	dma_addr_t dma_addr;		/* physical bus address (not accessible from main CPU) */
+	size_t dma_bytes;		/* size of DMA area */
+
+	struct snd_dma_buffer *dma_buffer_p;	/* allocated buffer */
+
+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+	/* -- OSS things -- */
+	struct snd_pcm_oss_runtime oss;
+#endif
+};
+
+struct snd_pcm_group {		/* keep linked substreams */
+	spinlock_t lock;
+	struct list_head substreams;
+	int count;
+};
+
+struct snd_pcm_substream {
+	struct snd_pcm *pcm;
+	struct snd_pcm_str *pstr;
+	void *private_data;		/* copied from pcm->private_data */
+	int number;
+	char name[32];			/* substream name */
+	int stream;			/* stream (direction) */
+	char latency_id[20];		/* latency identifier */
+	size_t buffer_bytes_max;	/* limit ring buffer size */
+	struct snd_dma_buffer dma_buffer;
+	unsigned int dma_buf_id;
+	size_t dma_max;
+	/* -- hardware operations -- */
+	struct snd_pcm_ops *ops;
+	/* -- runtime information -- */
+	struct snd_pcm_runtime *runtime;
+        /* -- timer section -- */
+	struct snd_timer *timer;		/* timer */
+	unsigned timer_running: 1;	/* time is running */
+	spinlock_t timer_lock;
+	/* -- next substream -- */
+	struct snd_pcm_substream *next;
+	/* -- linked substreams -- */
+	struct list_head link_list;	/* linked list member */
+	struct snd_pcm_group self_group;	/* fake group for non linked substream (with substream lock inside) */
+	struct snd_pcm_group *group;		/* pointer to current group */
+	/* -- assigned files -- */
+	void *file;
+	int ref_count;
+	atomic_t mmap_count;
+	unsigned int f_flags;
+	void (*pcm_release)(struct snd_pcm_substream *);
+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+	/* -- OSS things -- */
+	struct snd_pcm_oss_substream oss;
+#endif
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+	struct snd_info_entry *proc_root;
+	struct snd_info_entry *proc_info_entry;
+	struct snd_info_entry *proc_hw_params_entry;
+	struct snd_info_entry *proc_sw_params_entry;
+	struct snd_info_entry *proc_status_entry;
+	struct snd_info_entry *proc_prealloc_entry;
+	struct snd_info_entry *proc_prealloc_max_entry;
+#endif
+	/* misc flags */
+	unsigned int hw_opened: 1;
+};
+
+#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
+
+
+struct snd_pcm_str {
+	int stream;				/* stream (direction) */
+	struct snd_pcm *pcm;
+	/* -- substreams -- */
+	unsigned int substream_count;
+	unsigned int substream_opened;
+	struct snd_pcm_substream *substream;
+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+	/* -- OSS things -- */
+	struct snd_pcm_oss_stream oss;
+#endif
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+	struct snd_info_entry *proc_root;
+	struct snd_info_entry *proc_info_entry;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+	unsigned int xrun_debug;	/* 0 = disabled, 1 = verbose, 2 = stacktrace */
+	struct snd_info_entry *proc_xrun_debug_entry;
+#endif
+#endif
+};
+
+struct snd_pcm {
+	struct snd_card *card;
+	struct list_head list;
+	unsigned int device;	/* device number */
+	unsigned int info_flags;
+	unsigned short dev_class;
+	unsigned short dev_subclass;
+	char id[64];
+	char name[80];
+	struct snd_pcm_str streams[2];
+	struct mutex open_mutex;
+	wait_queue_head_t open_wait;
+	void *private_data;
+	void (*private_free) (struct snd_pcm *pcm);
+	struct device *dev; /* actual hw device this belongs to */
+#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+	struct snd_pcm_oss oss;
+#endif
+};
+
+struct snd_pcm_notify {
+	int (*n_register) (struct snd_pcm * pcm);
+	int (*n_disconnect) (struct snd_pcm * pcm);
+	int (*n_unregister) (struct snd_pcm * pcm);
+	struct list_head list;
+};
+
+/*
+ *  Registering
+ */
+
+extern const struct file_operations snd_pcm_f_ops[2];
+
+int snd_pcm_new(struct snd_card *card, char *id, int device,
+		int playback_count, int capture_count,
+		struct snd_pcm **rpcm);
+int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count);
+
+int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree);
+
+/*
+ *  Native I/O
+ */
+
+extern rwlock_t snd_pcm_link_rwlock;
+
+int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
+int snd_pcm_info_user(struct snd_pcm_substream *substream,
+		      struct snd_pcm_info __user *info);
+int snd_pcm_status(struct snd_pcm_substream *substream,
+		   struct snd_pcm_status *status);
+int snd_pcm_start(struct snd_pcm_substream *substream);
+int snd_pcm_stop(struct snd_pcm_substream *substream, int status);
+int snd_pcm_drain_done(struct snd_pcm_substream *substream);
+#ifdef CONFIG_PM
+int snd_pcm_suspend(struct snd_pcm_substream *substream);
+int snd_pcm_suspend_all(struct snd_pcm *pcm);
+#endif
+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file,
+			   struct snd_pcm_substream **rsubstream);
+void snd_pcm_release_substream(struct snd_pcm_substream *substream);
+int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file,
+			     struct snd_pcm_substream **rsubstream);
+void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
+void snd_pcm_vma_notify_data(void *client, void *data);
+int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
+
+#if BITS_PER_LONG >= 64
+
+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
+{
+	*rem = *n % div;
+	*n /= div;
+}
+
+#elif defined(i386)
+
+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
+{
+	u_int32_t low, high;
+	low = *n & 0xffffffff;
+	high = *n >> 32;
+	if (high) {
+		u_int32_t high1 = high % div;
+		high /= div;
+		asm("divl %2":"=a" (low), "=d" (*rem):"rm" (div), "a" (low), "d" (high1));
+		*n = (u_int64_t)high << 32 | low;
+	} else {
+		*n = low / div;
+		*rem = low % div;
+	}
+}
+#else
+
+static inline void divl(u_int32_t high, u_int32_t low,
+			u_int32_t div,
+			u_int32_t *q, u_int32_t *r)
+{
+	u_int64_t n = (u_int64_t)high << 32 | low;
+	u_int64_t d = (u_int64_t)div << 31;
+	u_int32_t q1 = 0;
+	int c = 32;
+	while (n > 0xffffffffU) {
+		q1 <<= 1;
+		if (n >= d) {
+			n -= d;
+			q1 |= 1;
+		}
+		d >>= 1;
+		c--;
+	}
+	q1 <<= c;
+	if (n) {
+		low = n;
+		*q = q1 | (low / div);
+		*r = low % div;
+	} else {
+		*r = 0;
+		*q = q1;
+	}
+	return;
+}
+
+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
+{
+	u_int32_t low, high;
+	low = *n & 0xffffffff;
+	high = *n >> 32;
+	if (high) {
+		u_int32_t high1 = high % div;
+		u_int32_t low1 = low;
+		high /= div;
+		divl(high1, low1, div, &low, rem);
+		*n = (u_int64_t)high << 32 | low;
+	} else {
+		*n = low / div;
+		*rem = low % div;
+	}
+}
+#endif
+
+/*
+ *  PCM library
+ */
+
+static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream)
+{
+	return substream->group != &substream->self_group;
+}
+
+static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
+{
+	read_lock(&snd_pcm_link_rwlock);
+	spin_lock(&substream->self_group.lock);
+}
+
+static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
+{
+	spin_unlock(&substream->self_group.lock);
+	read_unlock(&snd_pcm_link_rwlock);
+}
+
+static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
+{
+	read_lock_irq(&snd_pcm_link_rwlock);
+	spin_lock(&substream->self_group.lock);
+}
+
+static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
+{
+	spin_unlock(&substream->self_group.lock);
+	read_unlock_irq(&snd_pcm_link_rwlock);
+}
+
+#define snd_pcm_stream_lock_irqsave(substream, flags) \
+do { \
+	read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \
+	spin_lock(&substream->self_group.lock); \
+} while (0)
+
+#define snd_pcm_stream_unlock_irqrestore(substream, flags) \
+do { \
+	spin_unlock(&substream->self_group.lock); \
+	read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \
+} while (0)
+
+#define snd_pcm_group_for_each_entry(s, substream) \
+	list_for_each_entry(s, &substream->group->substreams, link_list)
+
+static inline int snd_pcm_running(struct snd_pcm_substream *substream)
+{
+	return (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
+		(substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+		 substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
+}
+
+static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t size)
+{
+	return size * 8 / runtime->sample_bits;
+}
+
+static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime, ssize_t size)
+{
+	return size * 8 / runtime->frame_bits;
+}
+
+static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t size)
+{
+	return size * runtime->sample_bits / 8;
+}
+
+static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_sframes_t size)
+{
+	return size * runtime->frame_bits / 8;
+}
+
+static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes)
+{
+	return bytes % runtime->byte_align == 0;
+}
+
+static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return frames_to_bytes(runtime, runtime->buffer_size);
+}
+
+static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return frames_to_bytes(runtime, runtime->period_size);
+}
+
+/*
+ *  result is: 0 ... (boundary - 1)
+ */
+static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime)
+{
+	snd_pcm_sframes_t avail = runtime->status->hw_ptr + runtime->buffer_size - runtime->control->appl_ptr;
+	if (avail < 0)
+		avail += runtime->boundary;
+	else if ((snd_pcm_uframes_t) avail >= runtime->boundary)
+		avail -= runtime->boundary;
+	return avail;
+}
+
+/*
+ *  result is: 0 ... (boundary - 1)
+ */
+static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *runtime)
+{
+	snd_pcm_sframes_t avail = runtime->status->hw_ptr - runtime->control->appl_ptr;
+	if (avail < 0)
+		avail += runtime->boundary;
+	return avail;
+}
+
+static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime)
+{
+	return runtime->buffer_size - snd_pcm_playback_avail(runtime);
+}
+
+static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime *runtime)
+{
+	return runtime->buffer_size - snd_pcm_capture_avail(runtime);
+}
+
+/**
+ * snd_pcm_playback_ready - check whether the playback buffer is available
+ * @substream: the pcm substream instance
+ *
+ * Checks whether enough free space is available on the playback buffer.
+ *
+ * Returns non-zero if available, or zero if not.
+ */
+static inline int snd_pcm_playback_ready(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return snd_pcm_playback_avail(runtime) >= runtime->control->avail_min;
+}
+
+/**
+ * snd_pcm_capture_ready - check whether the capture buffer is available
+ * @substream: the pcm substream instance
+ *
+ * Checks whether enough capture data is available on the capture buffer.
+ *
+ * Returns non-zero if available, or zero if not.
+ */
+static inline int snd_pcm_capture_ready(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return snd_pcm_capture_avail(runtime) >= runtime->control->avail_min;
+}
+
+/**
+ * snd_pcm_playback_data - check whether any data exists on the playback buffer
+ * @substream: the pcm substream instance
+ *
+ * Checks whether any data exists on the playback buffer. If stop_threshold
+ * is bigger or equal to boundary, then this function returns always non-zero.
+ *
+ * Returns non-zero if exists, or zero if not.
+ */
+static inline int snd_pcm_playback_data(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	
+	if (runtime->stop_threshold >= runtime->boundary)
+		return 1;
+	return snd_pcm_playback_avail(runtime) < runtime->buffer_size;
+}
+
+/**
+ * snd_pcm_playback_empty - check whether the playback buffer is empty
+ * @substream: the pcm substream instance
+ *
+ * Checks whether the playback buffer is empty.
+ *
+ * Returns non-zero if empty, or zero if not.
+ */
+static inline int snd_pcm_playback_empty(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return snd_pcm_playback_avail(runtime) >= runtime->buffer_size;
+}
+
+/**
+ * snd_pcm_capture_empty - check whether the capture buffer is empty
+ * @substream: the pcm substream instance
+ *
+ * Checks whether the capture buffer is empty.
+ *
+ * Returns non-zero if empty, or zero if not.
+ */
+static inline int snd_pcm_capture_empty(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	return snd_pcm_capture_avail(runtime) == 0;
+}
+
+static inline void snd_pcm_trigger_done(struct snd_pcm_substream *substream, 
+					struct snd_pcm_substream *master)
+{
+	substream->runtime->trigger_master = master;
+}
+
+static inline int hw_is_mask(int var)
+{
+	return var >= SNDRV_PCM_HW_PARAM_FIRST_MASK &&
+		var <= SNDRV_PCM_HW_PARAM_LAST_MASK;
+}
+
+static inline int hw_is_interval(int var)
+{
+	return var >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL &&
+		var <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL;
+}
+
+static inline struct snd_mask *hw_param_mask(struct snd_pcm_hw_params *params,
+				     snd_pcm_hw_param_t var)
+{
+	return &params->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK];
+}
+
+static inline struct snd_interval *hw_param_interval(struct snd_pcm_hw_params *params,
+					     snd_pcm_hw_param_t var)
+{
+	return &params->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
+}
+
+static inline const struct snd_mask *hw_param_mask_c(const struct snd_pcm_hw_params *params,
+					     snd_pcm_hw_param_t var)
+{
+	return (const struct snd_mask *)hw_param_mask((struct snd_pcm_hw_params*) params, var);
+}
+
+static inline const struct snd_interval *hw_param_interval_c(const struct snd_pcm_hw_params *params,
+						     snd_pcm_hw_param_t var)
+{
+	return (const struct snd_interval *)hw_param_interval((struct snd_pcm_hw_params*) params, var);
+}
+
+#define params_access(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS))
+#define params_format(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT))
+#define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
+#define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min
+#define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min
+#define params_period_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min
+#define params_period_bytes(p) ((params_period_size(p)*snd_pcm_format_physical_width(params_format(p))*params_channels(p))/8)
+#define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min
+#define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min
+#define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min
+#define params_tick_time(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_TICK_TIME)->min
+
+
+int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v);
+void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c);
+void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c);
+void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b, 
+			  unsigned int k, struct snd_interval *c);
+void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
+			  const struct snd_interval *b, struct snd_interval *c);
+int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask);
+int snd_interval_ratnum(struct snd_interval *i,
+			unsigned int rats_count, struct snd_ratnum *rats,
+			unsigned int *nump, unsigned int *denp);
+
+void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
+void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var);
+int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
+
+int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
+
+int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream);
+int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream);
+
+int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
+			       u_int32_t mask);
+int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
+				 u_int64_t mask);
+int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
+				 unsigned int min, unsigned int max);
+int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var);
+int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, 
+			       unsigned int cond,
+			       snd_pcm_hw_param_t var,
+			       struct snd_pcm_hw_constraint_list *l);
+int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
+				  unsigned int cond,
+				  snd_pcm_hw_param_t var,
+				  struct snd_pcm_hw_constraint_ratnums *r);
+int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, 
+				  unsigned int cond,
+				  snd_pcm_hw_param_t var,
+				  struct snd_pcm_hw_constraint_ratdens *r);
+int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, 
+				 unsigned int cond,
+				 unsigned int width,
+				 unsigned int msbits);
+int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
+			       unsigned int cond,
+			       snd_pcm_hw_param_t var,
+			       unsigned long step);
+int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
+			       unsigned int cond,
+			       snd_pcm_hw_param_t var);
+int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime,
+			unsigned int cond,
+			int var,
+			snd_pcm_hw_rule_func_t func, void *private,
+			int dep, ...);
+
+int snd_pcm_format_signed(snd_pcm_format_t format);
+int snd_pcm_format_unsigned(snd_pcm_format_t format);
+int snd_pcm_format_linear(snd_pcm_format_t format);
+int snd_pcm_format_little_endian(snd_pcm_format_t format);
+int snd_pcm_format_big_endian(snd_pcm_format_t format);
+#if 0 /* just for DocBook */
+/**
+ * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
+ * @format: the format to check
+ *
+ * Returns 1 if the given PCM format is CPU-endian, 0 if
+ * opposite, or a negative error code if endian not specified.
+ */
+int snd_pcm_format_cpu_endian(snd_pcm_format_t format);
+#endif /* DocBook */
+#ifdef SNDRV_LITTLE_ENDIAN
+#define snd_pcm_format_cpu_endian(format) snd_pcm_format_little_endian(format)
+#else
+#define snd_pcm_format_cpu_endian(format) snd_pcm_format_big_endian(format)
+#endif
+int snd_pcm_format_width(snd_pcm_format_t format);			/* in bits */
+int snd_pcm_format_physical_width(snd_pcm_format_t format);		/* in bits */
+ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
+const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
+int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
+snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian);
+
+void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, struct snd_pcm_ops *ops);
+void snd_pcm_set_sync(struct snd_pcm_substream *substream);
+int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
+int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
+		      unsigned int cmd, void *arg);                      
+int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
+int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream);
+int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream);
+int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream);
+int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream);
+void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr);
+void snd_pcm_tick_prepare(struct snd_pcm_substream *substream);
+void snd_pcm_tick_set(struct snd_pcm_substream *substream, unsigned long ticks);
+void snd_pcm_tick_elapsed(struct snd_pcm_substream *substream);
+void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
+snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
+				    const void __user *buf,
+				    snd_pcm_uframes_t frames);
+snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream,
+				   void __user *buf, snd_pcm_uframes_t frames);
+snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
+				     void __user **bufs, snd_pcm_uframes_t frames);
+snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
+				    void __user **bufs, snd_pcm_uframes_t frames);
+
+int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime);
+
+static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream,
+					      struct snd_dma_buffer *bufp)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	if (bufp) {
+		runtime->dma_buffer_p = bufp;
+		runtime->dma_area = bufp->area;
+		runtime->dma_addr = bufp->addr;
+		runtime->dma_bytes = bufp->bytes;
+	} else {
+		runtime->dma_buffer_p = NULL;
+		runtime->dma_area = NULL;
+		runtime->dma_addr = 0;
+		runtime->dma_bytes = 0;
+	}
+}
+
+/*
+ *  Timer interface
+ */
+
+void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream);
+void snd_pcm_timer_init(struct snd_pcm_substream *substream);
+void snd_pcm_timer_done(struct snd_pcm_substream *substream);
+
+/*
+ *  Memory
+ */
+
+int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream);
+int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm);
+int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
+				  int type, struct device *data,
+				  size_t size, size_t max);
+int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
+					  int type, void *data,
+					  size_t size, size_t max);
+int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
+int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
+
+#define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_buffer_p->private_data)
+#define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size)
+#define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
+struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset);
+
+/* handle mmap counter - PCM mmap callback should handle this counter properly */
+static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
+{
+	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
+	atomic_inc(&substream->mmap_count);
+}
+
+static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
+{
+	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
+	atomic_dec(&substream->mmap_count);
+}
+
+/* mmap for io-memory area */
+#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA)
+#define SNDRV_PCM_INFO_MMAP_IOMEM	SNDRV_PCM_INFO_MMAP
+int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area);
+#else
+#define SNDRV_PCM_INFO_MMAP_IOMEM	0
+#define snd_pcm_lib_mmap_iomem	NULL
+#endif
+
+static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
+{
+	*max = dma < 4 ? 64 * 1024 : 128 * 1024;
+}
+
+/*
+ *  Misc
+ */
+
+#define SNDRV_PCM_DEFAULT_CON_SPDIF	(IEC958_AES0_CON_EMPHASIS_NONE|\
+					 (IEC958_AES1_CON_ORIGINAL<<8)|\
+					 (IEC958_AES1_CON_PCM_CODER<<8)|\
+					 (IEC958_AES3_CON_FS_48000<<24))
+
+#endif /* __SOUND_PCM_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/sb.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/sb.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/sb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/sb.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,366 @@
+#ifndef __SOUND_SB_H
+#define __SOUND_SB_H
+
+/*
+ *  Header file for SoundBlaster cards
+ *  Copyright (c) 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 "pcm.h"
+#include "rawmidi.h"
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+enum sb_hw_type {
+	SB_HW_AUTO,
+	SB_HW_10,
+	SB_HW_20,
+	SB_HW_201,
+	SB_HW_PRO,
+	SB_HW_16,
+	SB_HW_16CSP,		/* SB16 with CSP chip */
+	SB_HW_ALS100,		/* Avance Logic ALS100 chip */
+	SB_HW_ALS4000,		/* Avance Logic ALS4000 chip */
+	SB_HW_DT019X,		/* Diamond Tech. DT-019X / Avance Logic ALS-007 */
+};
+
+#define SB_OPEN_PCM			0x01
+#define SB_OPEN_MIDI_INPUT		0x02
+#define SB_OPEN_MIDI_OUTPUT		0x04
+#define SB_OPEN_MIDI_INPUT_TRIGGER	0x08
+#define SB_OPEN_MIDI_OUTPUT_TRIGGER	0x10
+
+#define SB_MODE_HALT		0x00
+#define SB_MODE_PLAYBACK_8	0x01
+#define SB_MODE_PLAYBACK_16	0x02
+#define SB_MODE_PLAYBACK	(SB_MODE_PLAYBACK_8 | SB_MODE_PLAYBACK_16)
+#define SB_MODE_CAPTURE_8	0x04
+#define SB_MODE_CAPTURE_16	0x08
+#define SB_MODE_CAPTURE		(SB_MODE_CAPTURE_8 | SB_MODE_CAPTURE_16)
+
+#define SB_RATE_LOCK_PLAYBACK	0x10
+#define SB_RATE_LOCK_CAPTURE	0x20
+#define SB_RATE_LOCK		(SB_RATE_LOCK_PLAYBACK | SB_RATE_LOCK_CAPTURE)
+
+#define SB_MPU_INPUT		1
+
+struct snd_sb {
+	unsigned long port;		/* base port of DSP chip */
+	struct resource *res_port;
+	unsigned long mpu_port;		/* MPU port for SB DSP 4.0+ */
+	int irq;			/* IRQ number of DSP chip */
+	int dma8;			/* 8-bit DMA */
+	int dma16;			/* 16-bit DMA */
+	unsigned short version;		/* version of DSP chip */
+	enum sb_hw_type hardware;	/* see to SB_HW_XXXX */
+
+	unsigned long alt_port;		/* alternate port (ALS4000) */
+	struct pci_dev *pci;		/* ALS4000 */
+
+	unsigned int open;		/* see to SB_OPEN_XXXX for sb8 */
+					/* also SNDRV_SB_CSP_MODE_XXX for sb16_csp */
+	unsigned int mode;		/* current mode of stream */
+	unsigned int force_mode16;	/* force 16-bit mode of streams */
+	unsigned int locked_rate;	/* sb16 duplex */
+	unsigned int playback_format;
+	unsigned int capture_format;
+	struct timer_list midi_timer;
+	unsigned int p_dma_size;
+	unsigned int p_period_size;
+	unsigned int c_dma_size;
+	unsigned int c_period_size;
+
+	spinlock_t mixer_lock;
+
+	char name[32];
+
+	void *csp; /* used only when CONFIG_SND_SB16_CSP is set */
+
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+
+	struct snd_rawmidi *rmidi;
+	struct snd_rawmidi_substream *midi_substream_input;
+	struct snd_rawmidi_substream *midi_substream_output;
+	irq_handler_t rmidi_callback;
+
+	spinlock_t reg_lock;
+	spinlock_t open_lock;
+	spinlock_t midi_input_lock;
+
+	struct snd_info_entry *proc_entry;
+
+#ifdef CONFIG_PM
+	unsigned char saved_regs[0x20];
+#endif
+};
+
+/* I/O ports */
+
+#define SBP(chip, x)		((chip)->port + s_b_SB_##x)
+#define SBP1(port, x)		((port) + s_b_SB_##x)
+
+#define s_b_SB_RESET		0x6
+#define s_b_SB_READ		0xa
+#define s_b_SB_WRITE		0xc
+#define s_b_SB_COMMAND		0xc
+#define s_b_SB_STATUS		0xc
+#define s_b_SB_DATA_AVAIL	0xe
+#define s_b_SB_DATA_AVAIL_16 	0xf
+#define s_b_SB_MIXER_ADDR	0x4
+#define s_b_SB_MIXER_DATA	0x5
+#define s_b_SB_OPL3_LEFT	0x0
+#define s_b_SB_OPL3_RIGHT	0x2
+#define s_b_SB_OPL3_BOTH	0x8
+
+#define SB_DSP_OUTPUT		0x14
+#define SB_DSP_INPUT		0x24
+#define SB_DSP_BLOCK_SIZE	0x48
+#define SB_DSP_HI_OUTPUT	0x91
+#define SB_DSP_HI_INPUT		0x99
+#define SB_DSP_LO_OUTPUT_AUTO	0x1c
+#define SB_DSP_LO_INPUT_AUTO	0x2c
+#define SB_DSP_HI_OUTPUT_AUTO	0x90
+#define SB_DSP_HI_INPUT_AUTO	0x98
+#define SB_DSP_IMMED_INT	0xf2
+#define SB_DSP_GET_VERSION	0xe1
+#define SB_DSP_SPEAKER_ON	0xd1
+#define SB_DSP_SPEAKER_OFF	0xd3
+#define SB_DSP_DMA8_OFF		0xd0
+#define SB_DSP_DMA8_ON		0xd4
+#define SB_DSP_DMA8_EXIT	0xda
+#define SB_DSP_DMA16_OFF	0xd5
+#define SB_DSP_DMA16_ON		0xd6
+#define SB_DSP_DMA16_EXIT	0xd9
+#define SB_DSP_SAMPLE_RATE	0x40
+#define SB_DSP_SAMPLE_RATE_OUT	0x41
+#define SB_DSP_SAMPLE_RATE_IN	0x42
+#define SB_DSP_MONO_8BIT	0xa0
+#define SB_DSP_MONO_16BIT	0xa4
+#define SB_DSP_STEREO_8BIT	0xa8
+#define SB_DSP_STEREO_16BIT	0xac
+
+#define SB_DSP_MIDI_INPUT_IRQ	0x31
+#define SB_DSP_MIDI_UART_IRQ	0x35
+#define SB_DSP_MIDI_OUTPUT	0x38
+
+#define SB_DSP4_OUT8_AI		0xc6
+#define SB_DSP4_IN8_AI		0xce
+#define SB_DSP4_OUT16_AI	0xb6
+#define SB_DSP4_IN16_AI		0xbe
+#define SB_DSP4_MODE_UNS_MONO	0x00
+#define SB_DSP4_MODE_SIGN_MONO	0x10
+#define SB_DSP4_MODE_UNS_STEREO	0x20
+#define SB_DSP4_MODE_SIGN_STEREO 0x30
+
+#define SB_DSP4_OUTPUT		0x3c
+#define SB_DSP4_INPUT_LEFT	0x3d
+#define SB_DSP4_INPUT_RIGHT	0x3e
+
+/* registers for SB 2.0 mixer */
+#define SB_DSP20_MASTER_DEV	0x02
+#define SB_DSP20_PCM_DEV	0x0A
+#define SB_DSP20_CD_DEV		0x08
+#define SB_DSP20_FM_DEV		0x06
+
+/* registers for SB PRO mixer */
+#define SB_DSP_MASTER_DEV	0x22
+#define SB_DSP_PCM_DEV		0x04
+#define SB_DSP_LINE_DEV		0x2e
+#define SB_DSP_CD_DEV		0x28
+#define SB_DSP_FM_DEV		0x26
+#define SB_DSP_MIC_DEV		0x0a
+#define SB_DSP_CAPTURE_SOURCE	0x0c
+#define SB_DSP_CAPTURE_FILT	0x0c
+#define SB_DSP_PLAYBACK_FILT	0x0e
+#define SB_DSP_STEREO_SW	0x0e
+
+#define SB_DSP_MIXS_MIC0	0x00	/* same as MIC */
+#define SB_DSP_MIXS_CD		0x01
+#define SB_DSP_MIXS_MIC		0x02
+#define SB_DSP_MIXS_LINE	0x03
+
+/* registers (only for left channel) for SB 16 mixer */
+#define SB_DSP4_MASTER_DEV	0x30
+#define SB_DSP4_BASS_DEV	0x46
+#define SB_DSP4_TREBLE_DEV	0x44
+#define SB_DSP4_SYNTH_DEV	0x34
+#define SB_DSP4_PCM_DEV		0x32
+#define SB_DSP4_SPEAKER_DEV	0x3b
+#define SB_DSP4_LINE_DEV	0x38
+#define SB_DSP4_MIC_DEV		0x3a
+#define SB_DSP4_OUTPUT_SW	0x3c
+#define SB_DSP4_CD_DEV		0x36
+#define SB_DSP4_IGAIN_DEV	0x3f
+#define SB_DSP4_OGAIN_DEV	0x41
+#define SB_DSP4_MIC_AGC		0x43
+
+/* additional registers for SB 16 mixer */
+#define SB_DSP4_IRQSETUP	0x80
+#define SB_DSP4_DMASETUP	0x81
+#define SB_DSP4_IRQSTATUS	0x82
+#define SB_DSP4_MPUSETUP	0x84
+
+#define SB_DSP4_3DSE		0x90
+
+/* Registers for DT-019x / ALS-007 mixer */
+#define SB_DT019X_MASTER_DEV	0x62
+#define SB_DT019X_PCM_DEV	0x64
+#define SB_DT019X_SYNTH_DEV	0x66
+#define SB_DT019X_CD_DEV	0x68
+#define SB_DT019X_MIC_DEV	0x6a
+#define SB_DT019X_SPKR_DEV	0x6a
+#define SB_DT019X_LINE_DEV	0x6e
+#define SB_DT019X_OUTPUT_SW2	0x4c
+#define SB_DT019X_CAPTURE_SW	0x6c
+
+#define SB_DT019X_CAP_CD	0x02
+#define SB_DT019X_CAP_MIC	0x04
+#define SB_DT019X_CAP_LINE	0x06
+#define SB_DT019X_CAP_SYNTH	0x07
+#define SB_DT019X_CAP_MAIN	0x07
+
+#define SB_ALS4000_MONO_IO_CTRL	0x4b
+#define SB_ALS4000_MIC_IN_GAIN	0x4d
+#define SB_ALS4000_FMDAC	0x4f
+#define SB_ALS4000_3D_SND_FX	0x50
+#define SB_ALS4000_3D_TIME_DELAY	0x51
+#define SB_ALS4000_3D_AUTO_MUTE	0x52
+#define SB_ALS4000_QSOUND	0xdb
+
+/* IRQ setting bitmap */
+#define SB_IRQSETUP_IRQ9	0x01
+#define SB_IRQSETUP_IRQ5	0x02
+#define SB_IRQSETUP_IRQ7	0x04
+#define SB_IRQSETUP_IRQ10	0x08
+
+/* IRQ types */
+#define SB_IRQTYPE_8BIT		0x01
+#define SB_IRQTYPE_16BIT	0x02
+#define SB_IRQTYPE_MPUIN	0x04
+
+/* DMA setting bitmap */
+#define SB_DMASETUP_DMA0	0x01
+#define SB_DMASETUP_DMA1	0x02
+#define SB_DMASETUP_DMA3	0x08
+#define SB_DMASETUP_DMA5	0x20
+#define SB_DMASETUP_DMA6	0x40
+#define SB_DMASETUP_DMA7	0x80
+
+/*
+ *
+ */
+
+static inline void snd_sb_ack_8bit(struct snd_sb *chip)
+{
+	inb(SBP(chip, DATA_AVAIL));
+}
+
+static inline void snd_sb_ack_16bit(struct snd_sb *chip)
+{
+	inb(SBP(chip, DATA_AVAIL_16));
+}
+
+/* sb_common.c */
+int snd_sbdsp_command(struct snd_sb *chip, unsigned char val);
+int snd_sbdsp_get_byte(struct snd_sb *chip);
+int snd_sbdsp_reset(struct snd_sb *chip);
+int snd_sbdsp_create(struct snd_card *card,
+		     unsigned long port,
+		     int irq,
+		     irq_handler_t irq_handler,
+		     int dma8, int dma16,
+		     unsigned short hardware,
+		     struct snd_sb **r_chip);
+/* sb_mixer.c */
+void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data);
+unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg);
+int snd_sbmixer_new(struct snd_sb *chip);
+#ifdef CONFIG_PM
+void snd_sbmixer_suspend(struct snd_sb *chip);
+void snd_sbmixer_resume(struct snd_sb *chip);
+#endif
+
+/* sb8_init.c */
+int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
+/* sb8.c */
+irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip);
+int snd_sb8_playback_open(struct snd_pcm_substream *substream);
+int snd_sb8_capture_open(struct snd_pcm_substream *substream);
+int snd_sb8_playback_close(struct snd_pcm_substream *substream);
+int snd_sb8_capture_close(struct snd_pcm_substream *substream);
+/* midi8.c */
+irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip);
+int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi);
+
+/* sb16_init.c */
+int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
+const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction);
+int snd_sb16dsp_configure(struct snd_sb *chip);
+/* sb16.c */
+irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id);
+
+/* exported mixer stuffs */
+enum {
+	SB_MIX_SINGLE,
+	SB_MIX_DOUBLE,
+	SB_MIX_INPUT_SW,
+	SB_MIX_CAPTURE_PRO,
+	SB_MIX_CAPTURE_DT019X
+};
+
+#define SB_MIXVAL_DOUBLE(left_reg, right_reg, left_shift, right_shift, mask) \
+  ((left_reg) | ((right_reg) << 8) | ((left_shift) << 16) | ((right_shift) << 19) | ((mask) << 24))
+#define SB_MIXVAL_SINGLE(reg, shift, mask) \
+  ((reg) | ((shift) << 16) | ((mask) << 24))
+#define SB_MIXVAL_INPUT_SW(reg1, reg2, left_shift, right_shift) \
+  ((reg1) | ((reg2) << 8) | ((left_shift) << 16) | ((right_shift) << 24))
+
+int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value);
+
+/* for ease of use */
+struct sbmix_elem {
+	const char *name;
+	int type;
+	unsigned long private_value;
+};
+
+#define SB_SINGLE(xname, reg, shift, mask) \
+{ .name = xname, \
+  .type = SB_MIX_SINGLE, \
+  .private_value = SB_MIXVAL_SINGLE(reg, shift, mask) }
+
+#define SB_DOUBLE(xname, left_reg, right_reg, left_shift, right_shift, mask) \
+{ .name = xname, \
+  .type = SB_MIX_DOUBLE, \
+  .private_value = SB_MIXVAL_DOUBLE(left_reg, right_reg, left_shift, right_shift, mask) }
+
+#define SB16_INPUT_SW(xname, reg1, reg2, left_shift, right_shift) \
+{ .name = xname, \
+  .type = SB_MIX_INPUT_SW, \
+  .private_value = SB_MIXVAL_INPUT_SW(reg1, reg2, left_shift, right_shift) }
+
+static inline int snd_sbmixer_add_ctl_elem(struct snd_sb *chip, const struct sbmix_elem *c)
+{
+	return snd_sbmixer_add_ctl(chip, c->name, 0, c->type, c->private_value);
+}
+
+#endif /* __SOUND_SB_H */
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/soc.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/soc.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/soc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/soc.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,463 @@
+/*
+ * linux/sound/soc.h -- ALSA SoC Layer
+ *
+ * Author:		Liam Girdwood
+ * Created:		Aug 11th 2005
+ * Copyright:	Wolfson Microelectronics. PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_SND_SOC_H
+#define __LINUX_SND_SOC_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/control.h>
+#include <sound/ac97_codec.h>
+
+#define SND_SOC_VERSION "0.13.1"
+
+/*
+ * Convenience kcontrol builders
+ */
+#define SOC_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) |\
+	((shift) << 12) | ((mask) << 16) | ((invert) << 24))
+#define SOC_SINGLE_VALUE_EXT(reg,mask,invert) ((reg) | ((mask) << 16) |\
+	((invert) << 31))
+#define SOC_SINGLE(xname, reg, shift, mask, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+	.put = snd_soc_put_volsw, \
+	.private_value =  SOC_SINGLE_VALUE(reg, shift, mask, invert) }
+#define SOC_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
+	.put = snd_soc_put_volsw, \
+	.private_value = (reg) | ((shift_left) << 8) | \
+		((shift_right) << 12) | ((mask) << 16) | ((invert) << 24) }
+#define SOC_DOUBLE_R(xname, reg_left, reg_right, shift, mask, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = snd_soc_info_volsw_2r, \
+	.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
+	.private_value = (reg_left) | ((shift) << 8)  | \
+		((mask) << 12) | ((invert) << 20) | ((reg_right) << 24) }
+#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
+{	.reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
+	.mask = xmask, .texts = xtexts }
+#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
+	SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
+#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
+{	.mask = xmask, .texts = xtexts }
+#define SOC_ENUM(xname, xenum) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
+	.info = snd_soc_info_enum_double, \
+	.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
+	.private_value = (unsigned long)&xenum }
+#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
+	 xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
+#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_bool_ext, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = xdata }
+#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_enum_ext, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = (unsigned long)&xenum }
+
+/*
+ * Digital Audio Interface (DAI) types
+ */
+#define SND_SOC_DAI_AC97	0x1
+#define SND_SOC_DAI_I2S		0x2
+#define SND_SOC_DAI_PCM		0x4
+#define SND_SOC_DAI_AC97_BUS	0x8	/* for custom i.e. non ac97_codec.c */
+
+/*
+ * DAI hardware audio formats
+ */
+#define SND_SOC_DAIFMT_I2S		0	/* I2S mode */
+#define SND_SOC_DAIFMT_RIGHT_J	1	/* Right justified mode */
+#define SND_SOC_DAIFMT_LEFT_J	2	/* Left Justified mode */
+#define SND_SOC_DAIFMT_DSP_A	3	/* L data msb after FRM or LRC */
+#define SND_SOC_DAIFMT_DSP_B	4	/* L data msb during FRM or LRC */
+#define SND_SOC_DAIFMT_AC97		5	/* AC97 */
+
+#define SND_SOC_DAIFMT_MSB 	SND_SOC_DAIFMT_LEFT_J
+#define SND_SOC_DAIFMT_LSB	SND_SOC_DAIFMT_RIGHT_J
+
+/*
+ * DAI Gating
+ */
+#define SND_SOC_DAIFMT_CONT			(0 << 4)	/* continuous clock */
+#define SND_SOC_DAIFMT_GATED		(1 << 4)	/* clock is gated when not Tx/Rx */
+
+/*
+ * DAI hardware signal inversions
+ */
+#define SND_SOC_DAIFMT_NB_NF		(0 << 8)	/* normal bit clock + frame */
+#define SND_SOC_DAIFMT_NB_IF		(1 << 8)	/* normal bclk + inv frm */
+#define SND_SOC_DAIFMT_IB_NF		(2 << 8)	/* invert bclk + nor frm */
+#define SND_SOC_DAIFMT_IB_IF		(3 << 8)	/* invert bclk + frm */
+
+/*
+ * DAI hardware clock masters
+ * This is wrt the codec, the inverse is true for the interface
+ * i.e. if the codec is clk and frm master then the interface is
+ * clk and frame slave.
+ */
+#define SND_SOC_DAIFMT_CBM_CFM	(0 << 12) /* codec clk & frm master */
+#define SND_SOC_DAIFMT_CBS_CFM	(1 << 12) /* codec clk slave & frm master */
+#define SND_SOC_DAIFMT_CBM_CFS	(2 << 12) /* codec clk master & frame slave */
+#define SND_SOC_DAIFMT_CBS_CFS	(3 << 12) /* codec clk & frm slave */
+
+#define SND_SOC_DAIFMT_FORMAT_MASK		0x000f
+#define SND_SOC_DAIFMT_CLOCK_MASK		0x00f0
+#define SND_SOC_DAIFMT_INV_MASK			0x0f00
+#define SND_SOC_DAIFMT_MASTER_MASK		0xf000
+
+
+/*
+ * Master Clock Directions
+ */
+#define SND_SOC_CLOCK_IN	0
+#define SND_SOC_CLOCK_OUT	1
+
+/*
+ * AC97 codec ID's bitmask
+ */
+#define SND_SOC_DAI_AC97_ID0	(1 << 0)
+#define SND_SOC_DAI_AC97_ID1	(1 << 1)
+#define SND_SOC_DAI_AC97_ID2	(1 << 2)
+#define SND_SOC_DAI_AC97_ID3	(1 << 3)
+
+struct snd_soc_device;
+struct snd_soc_pcm_stream;
+struct snd_soc_ops;
+struct snd_soc_dai_mode;
+struct snd_soc_pcm_runtime;
+struct snd_soc_codec_dai;
+struct snd_soc_cpu_dai;
+struct snd_soc_codec;
+struct snd_soc_machine_config;
+struct soc_enum;
+struct snd_soc_ac97_ops;
+struct snd_soc_clock_info;
+
+typedef int (*hw_write_t)(void *,const char* ,int);
+typedef int (*hw_read_t)(void *,char* ,int);
+
+extern struct snd_ac97_bus_ops soc_ac97_ops;
+
+/* pcm <-> DAI connect */
+void snd_soc_free_pcms(struct snd_soc_device *socdev);
+int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
+int snd_soc_register_card(struct snd_soc_device *socdev);
+
+/* set runtime hw params */
+int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
+	const struct snd_pcm_hardware *hw);
+
+/* codec IO */
+#define snd_soc_read(codec, reg) codec->read(codec, reg)
+#define snd_soc_write(codec, reg, value) codec->write(codec, reg, value)
+
+/* codec register bit access */
+int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned short mask, unsigned short value);
+int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned short mask, unsigned short value);
+
+int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
+	struct snd_ac97_bus_ops *ops, int num);
+void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
+
+/*
+ *Controls
+ */
+struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
+	void *data, char *long_name);
+int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol);
+
+/* SoC PCM stream information */
+struct snd_soc_pcm_stream {
+	char *stream_name;
+	u64 formats;			/* SNDRV_PCM_FMTBIT_* */
+	unsigned int rates;		/* SNDRV_PCM_RATE_* */
+	unsigned int rate_min;		/* min rate */
+	unsigned int rate_max;		/* max rate */
+	unsigned int channels_min;	/* min channels */
+	unsigned int channels_max;	/* max channels */
+	unsigned int active:1;		/* stream is in use */
+};
+
+/* SoC audio ops */
+struct snd_soc_ops {
+	int (*startup)(struct snd_pcm_substream *);
+	void (*shutdown)(struct snd_pcm_substream *);
+	int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
+	int (*hw_free)(struct snd_pcm_substream *);
+	int (*prepare)(struct snd_pcm_substream *);
+	int (*trigger)(struct snd_pcm_substream *, int);
+};
+
+/* ASoC codec DAI ops */
+struct snd_soc_codec_ops {
+	/* codec DAI clocking configuration */
+	int (*set_sysclk)(struct snd_soc_codec_dai *codec_dai,
+		int clk_id, unsigned int freq, int dir);
+	int (*set_pll)(struct snd_soc_codec_dai *codec_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out);
+	int (*set_clkdiv)(struct snd_soc_codec_dai *codec_dai,
+		int div_id, int div);
+
+	/* CPU DAI format configuration */
+	int (*set_fmt)(struct snd_soc_codec_dai *codec_dai,
+		unsigned int fmt);
+	int (*set_tdm_slot)(struct snd_soc_codec_dai *codec_dai,
+		unsigned int mask, int slots);
+	int (*set_tristate)(struct snd_soc_codec_dai *, int tristate);
+
+	/* digital mute */
+	int (*digital_mute)(struct snd_soc_codec_dai *, int mute);
+};
+
+/* ASoC cpu DAI ops */
+struct snd_soc_cpu_ops {
+	/* CPU DAI clocking configuration */
+	int (*set_sysclk)(struct snd_soc_cpu_dai *cpu_dai,
+		int clk_id, unsigned int freq, int dir);
+	int (*set_clkdiv)(struct snd_soc_cpu_dai *cpu_dai,
+		int div_id, int div);
+	int (*set_pll)(struct snd_soc_cpu_dai *cpu_dai,
+		int pll_id, unsigned int freq_in, unsigned int freq_out);
+
+	/* CPU DAI format configuration */
+	int (*set_fmt)(struct snd_soc_cpu_dai *cpu_dai,
+		unsigned int fmt);
+	int (*set_tdm_slot)(struct snd_soc_cpu_dai *cpu_dai,
+		unsigned int mask, int slots);
+	int (*set_tristate)(struct snd_soc_cpu_dai *, int tristate);
+};
+
+/* SoC Codec DAI */
+struct snd_soc_codec_dai {
+	char *name;
+	int id;
+	unsigned char type;
+
+	/* DAI capabilities */
+	struct snd_soc_pcm_stream playback;
+	struct snd_soc_pcm_stream capture;
+
+	/* DAI runtime info */
+	struct snd_soc_codec *codec;
+	unsigned int active;
+	unsigned char pop_wait:1;
+
+	/* ops */
+	struct snd_soc_ops ops;
+	struct snd_soc_codec_ops dai_ops;
+
+	/* DAI private data */
+	void *private_data;
+};
+
+/* SoC CPU DAI */
+struct snd_soc_cpu_dai {
+
+	/* DAI description */
+	char *name;
+	unsigned int id;
+	unsigned char type;
+
+	/* DAI callbacks */
+	int (*probe)(struct platform_device *pdev);
+	void (*remove)(struct platform_device *pdev);
+	int (*suspend)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+	int (*resume)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+
+	/* ops */
+	struct snd_soc_ops ops;
+	struct snd_soc_cpu_ops dai_ops;
+
+	/* DAI capabilities */
+	struct snd_soc_pcm_stream capture;
+	struct snd_soc_pcm_stream playback;
+
+	/* DAI runtime info */
+	struct snd_pcm_runtime *runtime;
+	unsigned char active:1;
+	void *dma_data;
+
+	/* DAI private data */
+	void *private_data;
+};
+
+/* SoC Audio Codec */
+struct snd_soc_codec {
+	char *name;
+	struct module *owner;
+	struct mutex mutex;
+
+	/* callbacks */
+	int (*dapm_event)(struct snd_soc_codec *codec, int event);
+
+	/* runtime */
+	struct snd_card *card;
+	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
+	unsigned int active;
+	unsigned int pcm_devs;
+	void *private_data;
+
+	/* codec IO */
+	void *control_data; /* codec control (i2c/3wire) data */
+	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+	hw_write_t hw_write;
+	hw_read_t hw_read;
+	void *reg_cache;
+	short reg_cache_size;
+	short reg_cache_step;
+
+	/* dapm */
+	struct list_head dapm_widgets;
+	struct list_head dapm_paths;
+	unsigned int dapm_state;
+	unsigned int suspend_dapm_state;
+	struct delayed_work delayed_work;
+
+	/* codec DAI's */
+	struct snd_soc_codec_dai *dai;
+	unsigned int num_dai;
+};
+
+/* codec device */
+struct snd_soc_codec_device {
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+	int (*suspend)(struct platform_device *pdev, pm_message_t state);
+	int (*resume)(struct platform_device *pdev);
+};
+
+/* SoC platform interface */
+struct snd_soc_platform {
+	char *name;
+
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+	int (*suspend)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+	int (*resume)(struct platform_device *pdev,
+		struct snd_soc_cpu_dai *cpu_dai);
+
+	/* pcm creation and destruction */
+	int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *,
+		struct snd_pcm *);
+	void (*pcm_free)(struct snd_pcm *);
+
+	/* platform stream ops */
+	struct snd_pcm_ops *pcm_ops;
+};
+
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_dai_link  {
+	char *name;			/* Codec name */
+	char *stream_name;		/* Stream name */
+
+	/* DAI */
+	struct snd_soc_codec_dai *codec_dai;
+	struct snd_soc_cpu_dai *cpu_dai;
+
+	/* machine stream operations */
+	struct snd_soc_ops *ops;
+
+	/* codec/machine specific init - e.g. add machine controls */
+	int (*init)(struct snd_soc_codec *codec);
+};
+
+/* SoC machine */
+struct snd_soc_machine {
+	char *name;
+
+	int (*probe)(struct platform_device *pdev);
+	int (*remove)(struct platform_device *pdev);
+
+	/* the pre and post PM functions are used to do any PM work before and
+	 * after the codec and DAI's do any PM work. */
+	int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
+	int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
+	int (*resume_pre)(struct platform_device *pdev);
+	int (*resume_post)(struct platform_device *pdev);
+
+	/* CPU <--> Codec DAI links  */
+	struct snd_soc_dai_link *dai_link;
+	int num_links;
+};
+
+/* SoC Device - the audio subsystem */
+struct snd_soc_device {
+	struct device *dev;
+	struct snd_soc_machine *machine;
+	struct snd_soc_platform *platform;
+	struct snd_soc_codec *codec;
+	struct snd_soc_codec_device *codec_dev;
+	struct delayed_work delayed_work;
+	void *codec_data;
+};
+
+/* runtime channel data */
+struct snd_soc_pcm_runtime {
+	struct snd_soc_dai_link *dai;
+	struct snd_soc_device *socdev;
+};
+
+/* enumerated kcontrol */
+struct soc_enum {
+	unsigned short reg;
+	unsigned short reg2;
+	unsigned char shift_l;
+	unsigned char shift_r;
+	unsigned int mask;
+	const char **texts;
+	void *dapm;
+};
+
+#endif
diff -Naur linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/wavefront_fx.h linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/wavefront_fx.h
--- linux-2.6.22.orig/include/.pc/alsa-include-20070818.patch/sound/wavefront_fx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/alsa-include-20070818.patch/sound/wavefront_fx.h	2007-07-09 01:32:17.000000000 +0200
@@ -0,0 +1,9 @@
+#ifndef __SOUND_WAVEFRONT_FX_H
+#define __SOUND_WAVEFRONT_FX_H
+
+extern int  snd_wavefront_fx_detect (snd_wavefront_t *);
+extern void snd_wavefront_fx_ioctl  (snd_synth_t *sdev, 
+				     unsigned int cmd, 
+				     unsigned long arg);
+
+#endif  __SOUND_WAVEFRONT_FX_H
diff -Naur linux-2.6.22.orig/include/.pc/applied-patches linux-2.6.22/include/.pc/applied-patches
--- linux-2.6.22.orig/include/.pc/applied-patches	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/.pc/applied-patches	2007-08-31 20:42:35.000000000 +0200
@@ -0,0 +1 @@
+alsa-include-20070818.patch
diff -Naur linux-2.6.22.orig/include/sound/ak4xxx-adda.h linux-2.6.22/include/sound/ak4xxx-adda.h
--- linux-2.6.22.orig/include/sound/ak4xxx-adda.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/ak4xxx-adda.h	2007-08-31 20:42:35.000000000 +0200
@@ -43,6 +43,7 @@
 struct snd_akm4xxx_dac_channel {
 	char *name;		/* mixer volume name */
 	unsigned int num_channels;
+	char *switch_name;		/* mixer switch*/
 };
 
 /* ADC labels and channels */
diff -Naur linux-2.6.22.orig/include/sound/asound.h linux-2.6.22/include/sound/asound.h
--- linux-2.6.22.orig/include/sound/asound.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/asound.h	2007-08-31 20:42:35.000000000 +0200
@@ -92,6 +92,7 @@
 	SNDRV_HWDEP_IFACE_USX2Y_PCM,	/* Tascam US122, US224 & US428 rawusb pcm */
 	SNDRV_HWDEP_IFACE_PCXHR,	/* Digigram PCXHR */
 	SNDRV_HWDEP_IFACE_SB_RC,	/* SB Extigy/Audigy2NX remote control */
+	SNDRV_HWDEP_IFACE_HDA,		/* HD-audio */
 
 	/* Don't forget to change the following: */
 	SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SB_RC
diff -Naur linux-2.6.22.orig/include/sound/control.h linux-2.6.22/include/sound/control.h
--- linux-2.6.22.orig/include/sound/control.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/control.h	2007-08-31 20:42:35.000000000 +0200
@@ -161,4 +161,12 @@
 	return dst_id;
 }
 
+/*
+ * Frequently used control callbacks
+ */
+int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo);
+int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo);
+
 #endif	/* __SOUND_CONTROL_H */
diff -Naur linux-2.6.22.orig/include/sound/cs4231.h linux-2.6.22/include/sound/cs4231.h
--- linux-2.6.22.orig/include/sound/cs4231.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/cs4231.h	2007-08-31 20:42:35.000000000 +0200
@@ -210,7 +210,7 @@
 #define CS4231_HW_CS4239	0x0404	/* CS4239 - Crystal Clear (tm) stereo enhancement */
 /* compatible, but clones */
 #define CS4231_HW_INTERWAVE     0x1000	/* InterWave chip */
-#define CS4231_HW_OPL3SA2       0x1001	/* OPL3-SA2 chip */
+#define CS4231_HW_OPL3SA2       0x1101	/* OPL3-SA2 chip, similar to cs4231 */
 
 /* defines for codec.hwshare */
 #define CS4231_HWSHARE_IRQ	(1<<0)
diff -Naur linux-2.6.22.orig/include/sound/cs46xx.h linux-2.6.22/include/sound/cs46xx.h
--- linux-2.6.22.orig/include/sound/cs46xx.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/cs46xx.h	2007-08-31 20:42:35.000000000 +0200
@@ -1723,6 +1723,10 @@
 	struct snd_cs46xx_pcm *playback_pcm;
 	unsigned int play_ctl;
 #endif
+
+#ifdef CONFIG_PM
+	u32 *saved_regs;
+#endif
 };
 
 int snd_cs46xx_create(struct snd_card *card,
diff -Naur linux-2.6.22.orig/include/sound/cs46xx_dsp_spos.h linux-2.6.22/include/sound/cs46xx_dsp_spos.h
--- linux-2.6.22.orig/include/sound/cs46xx_dsp_spos.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/cs46xx_dsp_spos.h	2007-08-31 20:42:35.000000000 +0200
@@ -107,6 +107,7 @@
 	char scb_name[DSP_MAX_SCB_NAME];
 	u32 address;
 	int index;
+	u32 *data;
 
 	struct dsp_scb_descriptor * sub_list_ptr;
 	struct dsp_scb_descriptor * next_scb_ptr;
@@ -127,6 +128,7 @@
 	int size;
 	u32 address;
 	int index;
+	u32 *data;
 };
 
 struct dsp_pcm_channel_descriptor {
diff -Naur linux-2.6.22.orig/include/sound/emu10k1.h linux-2.6.22/include/sound/emu10k1.h
--- linux-2.6.22.orig/include/sound/emu10k1.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/emu10k1.h	2007-08-31 20:42:35.000000000 +0200
@@ -1120,6 +1120,16 @@
 /************************************************************************************************/
 /* EMU1010m HANA Destinations									*/
 /************************************************************************************************/
+/* 32-bit destinations of signal in the Hana FPGA. Destinations are either
+ * physical outputs of Hana, or outputs going to Alice2 (audigy) for capture
+ * - 16 x EMU_DST_ALICE2_EMU32_X.
+ */
+/* EMU32 = 32-bit serial channel between Alice2 (audigy) and Hana (FPGA) */
+/* EMU_DST_ALICE2_EMU32_X - data channels from Hana to Alice2 used for capture.
+ * Which data is fed into a EMU_DST_ALICE2_EMU32_X channel in Hana depends on
+ * setup of mixer control for each destination - see emumixer.c -
+ * snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[]
+ */
 #define EMU_DST_ALICE2_EMU32_0	0x000f	/* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_1	0x0000	/* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_2	0x0001	/* 16 EMU32 channels to Alice2 +0 to +0xf */
@@ -1199,6 +1209,12 @@
 /************************************************************************************************/
 /* EMU1010m HANA Sources									*/
 /************************************************************************************************/
+/* 32-bit sources of signal in the Hana FPGA. The sources are routed to
+ * destinations using mixer control for each destination - see emumixer.c
+ * Sources are either physical inputs of FPGA,
+ * or outputs from Alice (audigy) - 16 x EMU_SRC_ALICE_EMU32A +
+ * 16 x EMU_SRC_ALICE_EMU32B
+ */
 #define EMU_SRC_SILENCE		0x0000	/* Silence */
 #define EMU_SRC_DOCK_MIC_A1	0x0100	/* Audio Dock Mic A, 1st or 48kHz only */
 #define EMU_SRC_DOCK_MIC_A2	0x0101	/* Audio Dock Mic A, 2nd or 96kHz */
@@ -1440,6 +1456,9 @@
 	unsigned int adc_pads; /* bit mask */
 	unsigned int dac_pads; /* bit mask */
 	unsigned int internal_clock; /* 44100 or 48000 */
+	unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
+	unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
+	struct task_struct *firmware_thread;
 };
 
 struct snd_emu10k1 {
@@ -1583,9 +1602,9 @@
 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
-int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value);
-int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value);
-int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src);
+int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value);
+int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value);
+int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src);
 unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc);
 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb);
 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb);
@@ -1730,6 +1749,8 @@
 #define A_FXBUS2(x)	(0x80 + (x))	/* x = 0x00 - 0x1f extra outs used for EFX capture -> A_FXWC2 */
 #define A_EMU32OUTH(x)	(0xa0 + (x))	/* x = 0x00 - 0x0f "EMU32_OUT_10 - _1F" - ??? */
 #define A_EMU32OUTL(x)	(0xb0 + (x))	/* x = 0x00 - 0x0f "EMU32_OUT_1 - _F" - ??? */
+#define A3_EMU32IN(x)	(0x160 + (x))	/* x = 0x00 - 0x3f "EMU32_IN_00 - _3F" - Only when .device = 0x0008 */
+#define A3_EMU32OUT(x)	(0x1E0 + (x))	/* x = 0x00 - 0x0f "EMU32_OUT_00 - _3F" - Only when .device = 0x0008 */
 #define A_GPR(x)	(A_FXGPREGBASE + (x))
 
 /* cc_reg constants */
diff -Naur linux-2.6.22.orig/include/sound/hda_hwdep.h linux-2.6.22/include/sound/hda_hwdep.h
--- linux-2.6.22.orig/include/sound/hda_hwdep.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/include/sound/hda_hwdep.h	2007-08-31 20:42:35.000000000 +0200
@@ -0,0 +1,44 @@
+/*
+ * HWDEP Interface for HD-audio codec
+ *
+ * Copyright (c) 2007 Takashi Iwai <tiwai@suse.de>
+ *
+ *  This driver 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 driver 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
+ */
+
+#ifndef __SOUND_HDA_HWDEP_H
+#define __SOUND_HDA_HWDEP_H
+
+#define HDA_HWDEP_VERSION	((1 << 16) | (0 << 8) | (0 << 0)) /* 1.0.0 */
+
+/* verb */
+#define HDA_REG_NID_SHIFT	24
+#define HDA_REG_VERB_SHIFT	8
+#define HDA_REG_VAL_SHIFT	0
+#define HDA_VERB(nid,verb,param)	((nid)<<24 | (verb)<<8 | (param))
+
+struct hda_verb_ioctl {
+	u32 verb;	/* HDA_VERB() */
+	u32 res;	/* response */
+};
+
+/*
+ * ioctls
+ */
+#define HDA_IOCTL_PVERSION		_IOR('H', 0x10, int)
+#define HDA_IOCTL_VERB_WRITE		_IOWR('H', 0x11, struct hda_verb_ioctl)
+#define HDA_IOCTL_GET_WCAP		_IOWR('H', 0x12, struct hda_verb_ioctl)
+
+#endif
diff -Naur linux-2.6.22.orig/include/sound/hdspm.h linux-2.6.22/include/sound/hdspm.h
--- linux-2.6.22.orig/include/sound/hdspm.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/hdspm.h	2007-08-31 20:42:35.000000000 +0200
@@ -1,4 +1,4 @@
-#ifndef __SOUND_HDSPM_H		/* -*- linux-c -*- */
+#ifndef __SOUND_HDSPM_H
 #define __SOUND_HDSPM_H
 /*
  *   Copyright (C) 2003 Winfried Ritsch (IEM)
@@ -61,7 +61,8 @@
 };
 
 /* use indirect access due to the limit of ioctl bit size */
-#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, struct hdspm_peak_rms_ioctl)
+#define SNDRV_HDSPM_IOCTL_GET_PEAK_RMS \
+	_IOR('H', 0x40, struct hdspm_peak_rms_ioctl)
 
 /* ------------ CONFIG block IOCTL ---------------------- */
 
@@ -79,7 +80,8 @@
 	unsigned int analog_out;
 };
 
-#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, struct hdspm_config_info)
+#define SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO \
+	_IOR('H', 0x41, struct hdspm_config_info)
 
 
 /* get Soundcard Version */
@@ -93,10 +95,14 @@
 
 /* ------------- get Matrix Mixer IOCTL --------------- */
 
-/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte = 32768 Bytes */
+/* MADI mixer: 64inputs+64playback in 64outputs = 8192 => *4Byte =
+ * 32768 Bytes
+ */
 
 /* organisation is 64 channelfader in a continous memory block */
-/* equivalent to hardware definition, maybe for future feature of mmap of them */
+/* equivalent to hardware definition, maybe for future feature of mmap of
+ * them
+ */
 /* each of 64 outputs has 64 infader and 64 outfader: 
    Ins to Outs mixer[out].in[in], Outstreams to Outs mixer[out].pb[pb] */
 
diff -Naur linux-2.6.22.orig/include/sound/pcm.h linux-2.6.22/include/sound/pcm.h
--- linux-2.6.22.orig/include/sound/pcm.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/pcm.h	2007-08-31 20:42:35.000000000 +0200
@@ -922,7 +922,10 @@
 snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
 				    void __user **bufs, snd_pcm_uframes_t frames);
 
+extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates;
+
 int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime);
+unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate);
 
 static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream,
 					      struct snd_dma_buffer *bufp)
diff -Naur linux-2.6.22.orig/include/sound/sb.h linux-2.6.22/include/sound/sb.h
--- linux-2.6.22.orig/include/sound/sb.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/sb.h	2007-08-31 20:42:35.000000000 +0200
@@ -38,6 +38,7 @@
 	SB_HW_ALS100,		/* Avance Logic ALS100 chip */
 	SB_HW_ALS4000,		/* Avance Logic ALS4000 chip */
 	SB_HW_DT019X,		/* Diamond Tech. DT-019X / Avance Logic ALS-007 */
+	SB_HW_CS5530,		/* Cyrix/NatSemi 5530 VSA1 */
 };
 
 #define SB_OPEN_PCM			0x01
diff -Naur linux-2.6.22.orig/include/sound/soc.h linux-2.6.22/include/sound/soc.h
--- linux-2.6.22.orig/include/sound/soc.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/soc.h	2007-08-31 20:42:35.000000000 +0200
@@ -201,8 +201,7 @@
 	struct snd_ctl_elem_info *uinfo);
 int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
-int snd_soc_info_bool_ext(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo);
+#define snd_soc_info_bool_ext		snd_ctl_boolean_mono
 int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
diff -Naur linux-2.6.22.orig/include/sound/wavefront_fx.h linux-2.6.22/include/sound/wavefront_fx.h
--- linux-2.6.22.orig/include/sound/wavefront_fx.h	2007-08-31 20:36:42.000000000 +0200
+++ linux-2.6.22/include/sound/wavefront_fx.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,9 +0,0 @@
-#ifndef __SOUND_WAVEFRONT_FX_H
-#define __SOUND_WAVEFRONT_FX_H
-
-extern int  snd_wavefront_fx_detect (snd_wavefront_t *);
-extern void snd_wavefront_fx_ioctl  (snd_synth_t *sdev, 
-				     unsigned int cmd, 
-				     unsigned long arg);
-
-#endif  __SOUND_WAVEFRONT_FX_H
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/Kconfig linux-2.6.22/sound/.pc/alsa-20070818.patch/Kconfig
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/Kconfig	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,107 @@
+# sound/Config.in
+#
+
+menu "Sound"
+	depends on HAS_IOMEM
+
+config SOUND
+	tristate "Sound card support"
+	help
+	  If you have a sound card in your computer, i.e. if it can say more
+	  than an occasional beep, say Y.  Be sure to have all the information
+	  about your sound card and its configuration down (I/O port,
+	  interrupt and DMA channel), because you will be asked for it.
+
+	  You want to read the Sound-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>. General information about
+	  the modular sound system is contained in the files
+	  <file:Documentation/sound/oss/Introduction>.  The file
+	  <file:Documentation/sound/oss/README.OSS> contains some slightly
+	  outdated but still useful information as well.  Newer sound
+	  driver documentation is found in <file:Documentation/sound/alsa/*>.
+
+	  If you have a PnP sound card and you want to configure it at boot
+	  time using the ISA PnP tools (read
+	  <http://www.roestock.demon.co.uk/isapnptools/>), then you need to
+	  compile the sound card support as a module and load that module
+	  after the PnP configuration is finished.  To do this, choose M here
+	  and read <file:Documentation/sound/oss/README.modules>; the module
+	  will be called soundcore.
+
+	  I'm told that even without a sound card, you can make your computer
+	  say more than an occasional beep, by programming the PC speaker.
+	  Kernel patches and supporting utilities to do that are in the pcsp
+	  package, available at <ftp://ftp.infradead.org/pub/pcsp/>.
+
+source "sound/oss/dmasound/Kconfig"
+
+if !M68K
+
+menu "Advanced Linux Sound Architecture"
+	depends on SOUND!=n
+
+config SND
+	tristate "Advanced Linux Sound Architecture"
+	depends on SOUND
+	help
+	  Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture),
+	  the new base sound system.
+
+	  For more information, see <http://www.alsa-project.org/>
+
+source "sound/core/Kconfig"
+
+source "sound/drivers/Kconfig"
+
+source "sound/isa/Kconfig"
+
+source "sound/pci/Kconfig"
+
+source "sound/ppc/Kconfig"
+
+source "sound/aoa/Kconfig"
+
+source "sound/arm/Kconfig"
+
+source "sound/mips/Kconfig"
+
+# the following will depend on the order of config.
+# here assuming USB is defined before ALSA
+source "sound/usb/Kconfig"
+
+# the following will depend on the order of config.
+# here assuming PCMCIA is defined before ALSA
+source "sound/pcmcia/Kconfig"
+
+source "sound/sparc/Kconfig"
+
+source "sound/parisc/Kconfig"
+
+source "sound/soc/Kconfig"
+
+endmenu
+
+menu "Open Sound System"
+	depends on SOUND!=n
+
+config SOUND_PRIME
+	tristate "Open Sound System (DEPRECATED)"
+	depends on SOUND
+	help
+	  Say 'Y' or 'M' to enable Open Sound System drivers.
+
+source "sound/oss/Kconfig"
+
+endmenu
+
+endif
+
+config AC97_BUS
+	tristate
+	help
+	  This is used to avoid config and link hard dependencies between the
+	  sound subsystem and other function drivers completely unrelated to
+	  sound although they're sharing the AC97 bus. Concerned drivers
+	  should "select" this.
+
+endmenu
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/Makefile linux-2.6.22/sound/.pc/alsa-20070818.patch/Makefile
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/Makefile	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,18 @@
+# Makefile for the Linux sound card driver
+#
+
+obj-$(CONFIG_SOUND) += soundcore.o
+obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
+obj-$(CONFIG_SOUND_PRIME) += oss/
+obj-$(CONFIG_DMASOUND) += oss/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
+obj-$(CONFIG_SND_AOA) += aoa/
+
+# This one must be compilable even if sound is configured out
+obj-$(CONFIG_AC97_BUS) += ac97_bus.o
+
+ifeq ($(CONFIG_SND),y)
+  obj-y += last.o
+endif
+
+soundcore-objs  := sound_core.o
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-onyx.c linux-2.6.22/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-onyx.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-onyx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-onyx.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,1122 @@
+/*
+ * Apple Onboard Audio driver for Onyx codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This is a driver for the pcm3052 codec chip (codenamed Onyx)
+ * that is present in newer Apple hardware (with digital output).
+ *
+ * The Onyx codec has the following connections (listed by the bit
+ * to be used in aoa_codec.connected):
+ *  0: analog output
+ *  1: digital output
+ *  2: line input
+ *  3: microphone input
+ * Note that even though I know of no machine that has for example
+ * the digital output connected but not the analog, I have handled
+ * all the different cases in the code so that this driver may serve
+ * as a good example of what to do.
+ *
+ * NOTE: This driver assumes that there's at most one chip to be
+ * 	 used with one alsa card, in form of creating all kinds
+ *	 of mixer elements without regard for their existence.
+ *	 But snd-aoa assumes that there's at most one card, so
+ *	 this means you can only have one onyx on a system. This
+ *	 should probably be fixed by changing the assumption of
+ *	 having just a single card on a system, and making the
+ *	 'card' pointer accessible to anyone who needs it instead
+ *	 of hiding it in the aoa_snd_* functions...
+ *
+ */
+#include <linux/delay.h>
+#include <linux/module.h>
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa");
+
+#include "snd-aoa-codec-onyx.h"
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+
+#define PFX "snd-aoa-codec-onyx: "
+
+struct onyx {
+	/* cache registers 65 to 80, they are write-only! */
+	u8			cache[16];
+	struct i2c_client	i2c;
+	struct aoa_codec	codec;
+	u32			initialised:1,
+				spdif_locked:1,
+				analog_locked:1,
+				original_mute:2;
+	int			open_count;
+	struct codec_info	*codec_info;
+
+	/* mutex serializes concurrent access to the device
+	 * and this structure.
+	 */
+	struct mutex mutex;
+};
+#define codec_to_onyx(c) container_of(c, struct onyx, codec)
+
+/* both return 0 if all ok, else on error */
+static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value)
+{
+	s32 v;
+
+	if (reg != ONYX_REG_CONTROL) {
+		*value = onyx->cache[reg-FIRSTREGISTER];
+		return 0;
+	}
+	v = i2c_smbus_read_byte_data(&onyx->i2c, reg);
+	if (v < 0)
+		return -1;
+	*value = (u8)v;
+	onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value;
+	return 0;
+}
+
+static int onyx_write_register(struct onyx *onyx, u8 reg, u8 value)
+{
+	int result;
+
+	result = i2c_smbus_write_byte_data(&onyx->i2c, reg, value);
+	if (!result)
+		onyx->cache[reg-FIRSTREGISTER] = value;
+	return result;
+}
+
+/* alsa stuff */
+
+static int onyx_dev_register(struct snd_device *dev)
+{
+	return 0;
+}
+
+static struct snd_device_ops ops = {
+	.dev_register = onyx_dev_register,
+};
+
+/* this is necessary because most alsa mixer programs
+ * can't properly handle the negative range */
+#define VOLUME_RANGE_SHIFT	128
+
+static int onyx_snd_vol_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = -128 + VOLUME_RANGE_SHIFT;
+	uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT;
+	return 0;
+}
+
+static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	s8 l, r;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+	onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+	mutex_unlock(&onyx->mutex);
+
+	ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT;
+	ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT;
+
+	return 0;
+}
+
+static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	s8 l, r;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l);
+	onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r);
+
+	if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] &&
+	    r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) {
+		mutex_unlock(&onyx->mutex);
+		return 0;
+	}
+
+	onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT,
+			    ucontrol->value.integer.value[0]
+			     - VOLUME_RANGE_SHIFT);
+	onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT,
+			    ucontrol->value.integer.value[1]
+			     - VOLUME_RANGE_SHIFT);
+	mutex_unlock(&onyx->mutex);
+
+	return 1;
+}
+
+static struct snd_kcontrol_new volume_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Master Playback Volume",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = onyx_snd_vol_info,
+	.get = onyx_snd_vol_get,
+	.put = onyx_snd_vol_put,
+};
+
+/* like above, this is necessary because a lot
+ * of alsa mixer programs don't handle ranges
+ * that don't start at 0 properly.
+ * even alsamixer is one of them... */
+#define INPUTGAIN_RANGE_SHIFT	(-3)
+
+static int onyx_snd_inputgain_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT;
+	uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT;
+	return 0;
+}
+
+static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 ig;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig);
+	mutex_unlock(&onyx->mutex);
+
+	ucontrol->value.integer.value[0] =
+		(ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT;
+
+	return 0;
+}
+
+static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 v, n;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+	n = v;
+	n &= ~ONYX_ADC_PGA_GAIN_MASK;
+	n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT)
+		& ONYX_ADC_PGA_GAIN_MASK;
+	onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n);
+	mutex_unlock(&onyx->mutex);
+
+	return n != v;
+}
+
+static struct snd_kcontrol_new inputgain_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Master Capture Volume",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = onyx_snd_inputgain_info,
+	.get = onyx_snd_inputgain_get,
+	.put = onyx_snd_inputgain_put,
+};
+
+static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = { "Line-In", "Microphone" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	s8 v;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+	mutex_unlock(&onyx->mutex);
+
+	ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC);
+
+	return 0;
+}
+
+static void onyx_set_capture_source(struct onyx *onyx, int mic)
+{
+	s8 v;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v);
+	v &= ~ONYX_ADC_INPUT_MIC;
+	if (mic)
+		v |= ONYX_ADC_INPUT_MIC;
+	onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v);
+	mutex_unlock(&onyx->mutex);
+}
+
+static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	onyx_set_capture_source(snd_kcontrol_chip(kcontrol),
+				ucontrol->value.enumerated.item[0]);
+	return 1;
+}
+
+static struct snd_kcontrol_new capture_source_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* If we name this 'Input Source', it properly shows up in
+	 * alsamixer as a selection, * but it's shown under the 
+	 * 'Playback' category.
+	 * If I name it 'Capture Source', it shows up in strange
+	 * ways (two bools of which one can be selected at a
+	 * time) but at least it's shown in the 'Capture'
+	 * category.
+	 * I was told that this was due to backward compatibility,
+	 * but I don't understand then why the mangling is *not*
+	 * done when I name it "Input Source".....
+	 */
+	.name = "Capture Source",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = onyx_snd_capture_source_info,
+	.get = onyx_snd_capture_source_get,
+	.put = onyx_snd_capture_source_put,
+};
+
+static int onyx_snd_mute_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 c;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c);
+	mutex_unlock(&onyx->mutex);
+
+	ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT);
+	ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT);
+
+	return 0;
+}
+
+static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 v = 0, c = 0;
+	int err = -EBUSY;
+
+	mutex_lock(&onyx->mutex);
+	if (onyx->analog_locked)
+		goto out_unlock;
+
+	onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+	c = v;
+	c &= ~(ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT);
+	if (!ucontrol->value.integer.value[0])
+		c |= ONYX_MUTE_LEFT;
+	if (!ucontrol->value.integer.value[1])
+		c |= ONYX_MUTE_RIGHT;
+	err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c);
+
+ out_unlock:
+	mutex_unlock(&onyx->mutex);
+
+	return !err ? (v != c) : err;
+}
+
+static struct snd_kcontrol_new mute_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Master Playback Switch",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = onyx_snd_mute_info,
+	.get = onyx_snd_mute_get,
+	.put = onyx_snd_mute_put,
+};
+
+
+static int onyx_snd_single_bit_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+#define FLAG_POLARITY_INVERT	1
+#define FLAG_SPDIFLOCK		2
+
+static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 c;
+	long int pv = kcontrol->private_value;
+	u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;
+	u8 address = (pv >> 8) & 0xff;
+	u8 mask = pv & 0xff;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, address, &c);
+	mutex_unlock(&onyx->mutex);
+
+	ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity;
+
+	return 0;
+}
+
+static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 v = 0, c = 0;
+	int err;
+	long int pv = kcontrol->private_value;
+	u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT;
+	u8 spdiflock = (pv >> 16) & FLAG_SPDIFLOCK;
+	u8 address = (pv >> 8) & 0xff;
+	u8 mask = pv & 0xff;
+
+	mutex_lock(&onyx->mutex);
+	if (spdiflock && onyx->spdif_locked) {
+		/* even if alsamixer doesn't care.. */
+		err = -EBUSY;
+		goto out_unlock;
+	}
+	onyx_read_register(onyx, address, &v);
+	c = v;
+	c &= ~(mask);
+	if (!!ucontrol->value.integer.value[0] ^ polarity)
+		c |= mask;
+	err = onyx_write_register(onyx, address, c);
+
+ out_unlock:
+	mutex_unlock(&onyx->mutex);
+
+	return !err ? (v != c) : err;
+}
+
+#define SINGLE_BIT(n, type, description, address, mask, flags)	 	\
+static struct snd_kcontrol_new n##_control = {				\
+	.iface = SNDRV_CTL_ELEM_IFACE_##type,				\
+	.name = description,						\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,			\
+	.info = onyx_snd_single_bit_info,				\
+	.get = onyx_snd_single_bit_get,					\
+	.put = onyx_snd_single_bit_put,					\
+	.private_value = (flags << 16) | (address << 8) | mask		\
+}
+
+SINGLE_BIT(spdif,
+	   MIXER,
+	   SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
+	   ONYX_REG_DIG_INFO4,
+	   ONYX_SPDIF_ENABLE,
+	   FLAG_SPDIFLOCK);
+SINGLE_BIT(ovr1,
+	   MIXER,
+	   "Oversampling Rate",
+	   ONYX_REG_DAC_CONTROL,
+	   ONYX_OVR1,
+	   0);
+SINGLE_BIT(flt0,
+	   MIXER,
+	   "Fast Digital Filter Rolloff",
+	   ONYX_REG_DAC_FILTER,
+	   ONYX_ROLLOFF_FAST,
+	   FLAG_POLARITY_INVERT);
+SINGLE_BIT(hpf,
+	   MIXER,
+	   "Highpass Filter",
+	   ONYX_REG_ADC_HPF_BYPASS,
+	   ONYX_HPF_DISABLE,
+	   FLAG_POLARITY_INVERT);
+SINGLE_BIT(dm12,
+	   MIXER,
+	   "Digital De-Emphasis",
+	   ONYX_REG_DAC_DEEMPH,
+	   ONYX_DIGDEEMPH_CTRL,
+	   0);
+
+static int onyx_spdif_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	/* datasheet page 30, all others are 0 */
+	ucontrol->value.iec958.status[0] = 0x3e;
+	ucontrol->value.iec958.status[1] = 0xff;
+
+	ucontrol->value.iec958.status[3] = 0x3f;
+	ucontrol->value.iec958.status[4] = 0x0f;
+	
+	return 0;
+}
+
+static struct snd_kcontrol_new onyx_spdif_mask = {
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+	.info =		onyx_spdif_info,
+	.get =		onyx_spdif_mask_get,
+};
+
+static int onyx_spdif_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 v;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+	ucontrol->value.iec958.status[0] = v & 0x3e;
+
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO2, &v);
+	ucontrol->value.iec958.status[1] = v;
+
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);
+	ucontrol->value.iec958.status[3] = v & 0x3f;
+
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+	ucontrol->value.iec958.status[4] = v & 0x0f;
+	mutex_unlock(&onyx->mutex);
+
+	return 0;
+}
+
+static int onyx_spdif_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	struct onyx *onyx = snd_kcontrol_chip(kcontrol);
+	u8 v;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v);
+	v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e);
+	onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v);
+
+	v = ucontrol->value.iec958.status[1];
+	onyx_write_register(onyx, ONYX_REG_DIG_INFO2, v);
+
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v);
+	v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f);
+	onyx_write_register(onyx, ONYX_REG_DIG_INFO3, v);
+
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+	v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f);
+	onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+	mutex_unlock(&onyx->mutex);
+
+	return 1;
+}
+
+static struct snd_kcontrol_new onyx_spdif_ctrl = {
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.info =		onyx_spdif_info,
+	.get =		onyx_spdif_get,
+	.put =		onyx_spdif_put,
+};
+
+/* our registers */
+
+static u8 register_map[] = {
+	ONYX_REG_DAC_ATTEN_LEFT,
+	ONYX_REG_DAC_ATTEN_RIGHT,
+	ONYX_REG_CONTROL,
+	ONYX_REG_DAC_CONTROL,
+	ONYX_REG_DAC_DEEMPH,
+	ONYX_REG_DAC_FILTER,
+	ONYX_REG_DAC_OUTPHASE,
+	ONYX_REG_ADC_CONTROL,
+	ONYX_REG_ADC_HPF_BYPASS,
+	ONYX_REG_DIG_INFO1,
+	ONYX_REG_DIG_INFO2,
+	ONYX_REG_DIG_INFO3,
+	ONYX_REG_DIG_INFO4
+};
+
+static u8 initial_values[ARRAY_SIZE(register_map)] = {
+	0x80, 0x80, /* muted */
+	ONYX_MRST | ONYX_SRST, /* but handled specially! */
+	ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT,
+	0, /* no deemphasis */
+	ONYX_DAC_FILTER_ALWAYS,
+	ONYX_OUTPHASE_INVERTED,
+	(-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/
+	ONYX_ADC_HPF_ALWAYS,
+	(1<<2),	/* pcm audio */
+	2,	/* category: pcm coder */
+	0,	/* sampling frequency 44.1 kHz, clock accuracy level II */
+	1	/* 24 bit depth */
+};
+
+/* reset registers of chip, either to initial or to previous values */
+static int onyx_register_init(struct onyx *onyx)
+{
+	int i;
+	u8 val;
+	u8 regs[sizeof(initial_values)];
+
+	if (!onyx->initialised) {
+		memcpy(regs, initial_values, sizeof(initial_values));
+		if (onyx_read_register(onyx, ONYX_REG_CONTROL, &val))
+			return -1;
+		val &= ~ONYX_SILICONVERSION;
+		val |= initial_values[3];
+		regs[3] = val;
+	} else {
+		for (i=0; i<sizeof(register_map); i++)
+			regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER];
+	}
+
+	for (i=0; i<sizeof(register_map); i++) {
+		if (onyx_write_register(onyx, register_map[i], regs[i]))
+			return -1;
+	}
+	onyx->initialised = 1;
+	return 0;
+}
+
+static struct transfer_info onyx_transfers[] = {
+	/* this is first so we can skip it if no input is present...
+	 * No hardware exists with that, but it's here as an example
+	 * of what to do :) */
+	{
+		/* analog input */
+		.formats = SNDRV_PCM_FMTBIT_S8 |
+			   SNDRV_PCM_FMTBIT_S16_BE |
+			   SNDRV_PCM_FMTBIT_S24_BE,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.transfer_in = 1,
+		.must_be_clock_source = 0,
+		.tag = 0,
+	},
+	{
+		/* if analog and digital are currently off, anything should go,
+		 * so this entry describes everything we can do... */
+		.formats = SNDRV_PCM_FMTBIT_S8 |
+			   SNDRV_PCM_FMTBIT_S16_BE |
+			   SNDRV_PCM_FMTBIT_S24_BE
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+			   | SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+#endif
+		,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.tag = 0,
+	},
+	{
+		/* analog output */
+		.formats = SNDRV_PCM_FMTBIT_S8 |
+			   SNDRV_PCM_FMTBIT_S16_BE |
+			   SNDRV_PCM_FMTBIT_S24_BE,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.transfer_in = 0,
+		.must_be_clock_source = 0,
+		.tag = 1,
+	},
+	{
+		/* digital pcm output, also possible for analog out */
+		.formats = SNDRV_PCM_FMTBIT_S8 |
+			   SNDRV_PCM_FMTBIT_S16_BE |
+			   SNDRV_PCM_FMTBIT_S24_BE,
+		.rates = SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 |
+			 SNDRV_PCM_RATE_48000,
+		.transfer_in = 0,
+		.must_be_clock_source = 0,
+		.tag = 2,
+	},
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+Once alsa gets supports for this kind of thing we can add it...
+	{
+		/* digital compressed output */
+		.formats =  SNDRV_PCM_FMTBIT_COMPRESSED_16BE,
+		.rates = SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 |
+			 SNDRV_PCM_RATE_48000,
+		.tag = 2,
+	},
+#endif
+	{}
+};
+
+static int onyx_usable(struct codec_info_item *cii,
+		       struct transfer_info *ti,
+		       struct transfer_info *out)
+{
+	u8 v;
+	struct onyx *onyx = cii->codec_data;
+	int spdif_enabled, analog_enabled;
+
+	mutex_lock(&onyx->mutex);
+	onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+	spdif_enabled = !!(v & ONYX_SPDIF_ENABLE);
+	onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+	analog_enabled = 
+		(v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT))
+		 != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT);
+	mutex_unlock(&onyx->mutex);
+
+	switch (ti->tag) {
+	case 0: return 1;
+	case 1:	return analog_enabled;
+	case 2: return spdif_enabled;
+	}
+	return 1;
+}
+
+static int onyx_prepare(struct codec_info_item *cii,
+			struct bus_info *bi,
+			struct snd_pcm_substream *substream)
+{
+	u8 v;
+	struct onyx *onyx = cii->codec_data;
+	int err = -EBUSY;
+
+	mutex_lock(&onyx->mutex);
+
+#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
+	if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
+		/* mute and lock analog output */
+		onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
+		if (onyx_write_register(onyx
+					ONYX_REG_DAC_CONTROL,
+					v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
+			goto out_unlock;
+		onyx->analog_locked = 1;
+		err = 0;
+		goto out_unlock;
+	}
+#endif
+	switch (substream->runtime->rate) {
+	case 32000:
+	case 44100:
+	case 48000:
+		/* these rates are ok for all outputs */
+		/* FIXME: program spdif channel control bits here so that
+		 *	  userspace doesn't have to if it only plays pcm! */
+		err = 0;
+		goto out_unlock;
+	default:
+		/* got some rate that the digital output can't do,
+		 * so disable and lock it */
+		onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v);
+		if (onyx_write_register(onyx,
+					ONYX_REG_DIG_INFO4,
+					v & ~ONYX_SPDIF_ENABLE))
+			goto out_unlock;
+		onyx->spdif_locked = 1;
+		err = 0;
+		goto out_unlock;
+	}
+
+ out_unlock:
+	mutex_unlock(&onyx->mutex);
+
+	return err;
+}
+
+static int onyx_open(struct codec_info_item *cii,
+		     struct snd_pcm_substream *substream)
+{
+	struct onyx *onyx = cii->codec_data;
+
+	mutex_lock(&onyx->mutex);
+	onyx->open_count++;
+	mutex_unlock(&onyx->mutex);
+
+	return 0;
+}
+
+static int onyx_close(struct codec_info_item *cii,
+		      struct snd_pcm_substream *substream)
+{
+	struct onyx *onyx = cii->codec_data;
+
+	mutex_lock(&onyx->mutex);
+	onyx->open_count--;
+	if (!onyx->open_count)
+		onyx->spdif_locked = onyx->analog_locked = 0;
+	mutex_unlock(&onyx->mutex);
+
+	return 0;
+}
+
+static int onyx_switch_clock(struct codec_info_item *cii,
+			     enum clock_switch what)
+{
+	struct onyx *onyx = cii->codec_data;
+
+	mutex_lock(&onyx->mutex);
+	/* this *MUST* be more elaborate later... */
+	switch (what) {
+	case CLOCK_SWITCH_PREPARE_SLAVE:
+		onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio);
+		break;
+	case CLOCK_SWITCH_SLAVE:
+		onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio);
+		break;
+	default: /* silence warning */
+		break;
+	}
+	mutex_unlock(&onyx->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int onyx_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+	struct onyx *onyx = cii->codec_data;
+	u8 v;
+	int err = -ENXIO;
+
+	mutex_lock(&onyx->mutex);
+	if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+		goto out_unlock;
+	onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV);
+	/* Apple does a sleep here but the datasheet says to do it on resume */
+	err = 0;
+ out_unlock:
+	mutex_unlock(&onyx->mutex);
+
+	return err;
+}
+
+static int onyx_resume(struct codec_info_item *cii)
+{
+	struct onyx *onyx = cii->codec_data;
+	u8 v;
+	int err = -ENXIO;
+
+	mutex_lock(&onyx->mutex);
+
+	/* reset codec */
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+	msleep(1);
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
+	msleep(1);
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+	msleep(1);
+
+	/* take codec out of suspend (if it still is after reset) */
+	if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v))
+		goto out_unlock;
+	onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV));
+	/* FIXME: should divide by sample rate, but 8k is the lowest we go */
+	msleep(2205000/8000);
+	/* reset all values */
+	onyx_register_init(onyx);
+	err = 0;
+ out_unlock:
+	mutex_unlock(&onyx->mutex);
+
+	return err;
+}
+
+#endif /* CONFIG_PM */
+
+static struct codec_info onyx_codec_info = {
+	.transfers = onyx_transfers,
+	.sysclock_factor = 256,
+	.bus_factor = 64,
+	.owner = THIS_MODULE,
+	.usable = onyx_usable,
+	.prepare = onyx_prepare,
+	.open = onyx_open,
+	.close = onyx_close,
+	.switch_clock = onyx_switch_clock,
+#ifdef CONFIG_PM
+	.suspend = onyx_suspend,
+	.resume = onyx_resume,
+#endif
+};
+
+static int onyx_init_codec(struct aoa_codec *codec)
+{
+	struct onyx *onyx = codec_to_onyx(codec);
+	struct snd_kcontrol *ctl;
+	struct codec_info *ci = &onyx_codec_info;
+	u8 v;
+	int err;
+
+	if (!onyx->codec.gpio || !onyx->codec.gpio->methods) {
+		printk(KERN_ERR PFX "gpios not assigned!!\n");
+		return -EINVAL;
+	}
+
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+	msleep(1);
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1);
+	msleep(1);
+	onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0);
+	msleep(1);
+	
+	if (onyx_register_init(onyx)) {
+		printk(KERN_ERR PFX "failed to initialise onyx registers\n");
+		return -ENODEV;
+	}
+
+	if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, onyx, &ops)) {
+		printk(KERN_ERR PFX "failed to create onyx snd device!\n");
+		return -ENODEV;
+	}
+
+	/* nothing connected? what a joke! */
+	if ((onyx->codec.connected & 0xF) == 0)
+		return -ENOTCONN;
+
+	/* if no inputs are present... */
+	if ((onyx->codec.connected & 0xC) == 0) {
+		if (!onyx->codec_info)
+			onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);
+		if (!onyx->codec_info)
+			return -ENOMEM;
+		ci = onyx->codec_info;
+		*ci = onyx_codec_info;
+		ci->transfers++;
+	}
+
+	/* if no outputs are present... */
+	if ((onyx->codec.connected & 3) == 0) {
+		if (!onyx->codec_info)
+			onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL);
+		if (!onyx->codec_info)
+			return -ENOMEM;
+		ci = onyx->codec_info;
+		/* this is fine as there have to be inputs
+		 * if we end up in this part of the code */
+		*ci = onyx_codec_info;
+		ci->transfers[1].formats = 0;
+	}
+
+	if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev,
+						   aoa_get_card(),
+						   ci, onyx)) {
+		printk(KERN_ERR PFX "error creating onyx pcm\n");
+		return -ENODEV;
+	}
+#define ADDCTL(n)							\
+	do {								\
+		ctl = snd_ctl_new1(&n, onyx);				\
+		if (ctl) {						\
+			ctl->id.device =				\
+				onyx->codec.soundbus_dev->pcm->device;	\
+			err = aoa_snd_ctl_add(ctl);			\
+			if (err)					\
+				goto error;				\
+		}							\
+	} while (0)
+
+	if (onyx->codec.soundbus_dev->pcm) {
+		/* give the user appropriate controls
+		 * depending on what inputs are connected */
+		if ((onyx->codec.connected & 0xC) == 0xC)
+			ADDCTL(capture_source_control);
+		else if (onyx->codec.connected & 4)
+			onyx_set_capture_source(onyx, 0);
+		else
+			onyx_set_capture_source(onyx, 1);
+		if (onyx->codec.connected & 0xC)
+			ADDCTL(inputgain_control);
+
+		/* depending on what output is connected,
+		 * give the user appropriate controls */
+		if (onyx->codec.connected & 1) {
+			ADDCTL(volume_control);
+			ADDCTL(mute_control);
+			ADDCTL(ovr1_control);
+			ADDCTL(flt0_control);
+			ADDCTL(hpf_control);
+			ADDCTL(dm12_control);
+			/* spdif control defaults to off */
+		}
+		if (onyx->codec.connected & 2) {
+			ADDCTL(onyx_spdif_mask);
+			ADDCTL(onyx_spdif_ctrl);
+		}
+		if ((onyx->codec.connected & 3) == 3)
+			ADDCTL(spdif_control);
+		/* if only S/PDIF is connected, enable it unconditionally */
+		if ((onyx->codec.connected & 3) == 2) {
+			onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v);
+			v |= ONYX_SPDIF_ENABLE;
+			onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v);
+		}
+	}
+#undef ADDCTL
+	printk(KERN_INFO PFX "attached to onyx codec via i2c\n");
+
+	return 0;
+ error:
+	onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
+	snd_device_free(aoa_get_card(), onyx);
+	return err;
+}
+
+static void onyx_exit_codec(struct aoa_codec *codec)
+{
+	struct onyx *onyx = codec_to_onyx(codec);
+
+	if (!onyx->codec.soundbus_dev) {
+		printk(KERN_ERR PFX "onyx_exit_codec called without soundbus_dev!\n");
+		return;
+	}
+	onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx);
+}
+
+static struct i2c_driver onyx_driver;
+
+static int onyx_create(struct i2c_adapter *adapter,
+		       struct device_node *node,
+		       int addr)
+{
+	struct onyx *onyx;
+	u8 dummy;
+
+	onyx = kzalloc(sizeof(struct onyx), GFP_KERNEL);
+
+	if (!onyx)
+		return -ENOMEM;
+
+	mutex_init(&onyx->mutex);
+	onyx->i2c.driver = &onyx_driver;
+	onyx->i2c.adapter = adapter;
+	onyx->i2c.addr = addr & 0x7f;
+	strlcpy(onyx->i2c.name, "onyx audio codec", I2C_NAME_SIZE);
+
+	if (i2c_attach_client(&onyx->i2c)) {
+		printk(KERN_ERR PFX "failed to attach to i2c\n");
+		goto fail;
+	}
+
+	/* we try to read from register ONYX_REG_CONTROL
+	 * to check if the codec is present */
+	if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) {
+		i2c_detach_client(&onyx->i2c);
+		printk(KERN_ERR PFX "failed to read control register\n");
+		goto fail;
+	}
+
+	strlcpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN);
+	onyx->codec.owner = THIS_MODULE;
+	onyx->codec.init = onyx_init_codec;
+	onyx->codec.exit = onyx_exit_codec;
+	onyx->codec.node = of_node_get(node);
+
+	if (aoa_codec_register(&onyx->codec)) {
+		i2c_detach_client(&onyx->i2c);
+		goto fail;
+	}
+	printk(KERN_DEBUG PFX "created and attached onyx instance\n");
+	return 0;
+ fail:
+	kfree(onyx);
+	return -EINVAL;
+}
+
+static int onyx_i2c_attach(struct i2c_adapter *adapter)
+{
+	struct device_node *busnode, *dev = NULL;
+	struct pmac_i2c_bus *bus;
+
+	bus = pmac_i2c_adapter_to_bus(adapter);
+	if (bus == NULL)
+		return -ENODEV;
+	busnode = pmac_i2c_get_bus_node(bus);
+
+	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
+		if (of_device_is_compatible(dev, "pcm3052")) {
+			const u32 *addr;
+			printk(KERN_DEBUG PFX "found pcm3052\n");
+			addr = of_get_property(dev, "reg", NULL);
+			if (!addr)
+				return -ENODEV;
+			return onyx_create(adapter, dev, (*addr)>>1);
+		}
+	}
+
+	/* if that didn't work, try desperate mode for older
+	 * machines that have stuff missing from the device tree */
+	
+	if (!of_device_is_compatible(busnode, "k2-i2c"))
+		return -ENODEV;
+
+	printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
+	/* probe both possible addresses for the onyx chip */
+	if (onyx_create(adapter, NULL, 0x46) == 0)
+		return 0;
+	return onyx_create(adapter, NULL, 0x47);
+}
+
+static int onyx_i2c_detach(struct i2c_client *client)
+{
+	struct onyx *onyx = container_of(client, struct onyx, i2c);
+	int err;
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+	aoa_codec_unregister(&onyx->codec);
+	of_node_put(onyx->codec.node);
+	if (onyx->codec_info)
+		kfree(onyx->codec_info);
+	kfree(onyx);
+	return 0;
+}
+
+static struct i2c_driver onyx_driver = {
+	.driver = {
+		.name = "aoa_codec_onyx",
+		.owner = THIS_MODULE,
+	},
+	.attach_adapter = onyx_i2c_attach,
+	.detach_client = onyx_i2c_detach,
+};
+
+static int __init onyx_init(void)
+{
+	return i2c_add_driver(&onyx_driver);
+}
+
+static void __exit onyx_exit(void)
+{
+	i2c_del_driver(&onyx_driver);
+}
+
+module_init(onyx_init);
+module_exit(onyx_exit);
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-tas.c linux-2.6.22/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-tas.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-tas.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/aoa/codecs/snd-aoa-codec-tas.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,1010 @@
+/*
+ * Apple Onboard Audio driver for tas codec
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ * Open questions:
+ *  - How to distinguish between 3004 and versions?
+ *
+ * FIXMEs:
+ *  - This codec driver doesn't honour the 'connected'
+ *    property of the aoa_codec struct, hence if
+ *    it is used in machines where not everything is
+ *    connected it will display wrong mixer elements.
+ *  - Driver assumes that the microphone is always
+ *    monaureal and connected to the right channel of
+ *    the input. This should also be a codec-dependent
+ *    flag, maybe the codec should have 3 different
+ *    bits for the three different possibilities how
+ *    it can be hooked up...
+ *    But as long as I don't see any hardware hooked
+ *    up that way...
+ *  - As Apple notes in their code, the tas3004 seems
+ *    to delay the right channel by one sample. You can
+ *    see this when for example recording stereo in
+ *    audacity, or recording the tas output via cable
+ *    on another machine (use a sinus generator or so).
+ *    I tried programming the BiQuads but couldn't
+ *    make the delay work, maybe someone can read the
+ *    datasheet and fix it. The relevant Apple comment
+ *    is in AppleTAS3004Audio.cpp lines 1637 ff. Note
+ *    that their comment describing how they program
+ *    the filters sucks...
+ *
+ * Other things:
+ *  - this should actually register *two* aoa_codec
+ *    structs since it has two inputs. Then it must
+ *    use the prepare callback to forbid running the
+ *    secondary output on a different clock.
+ *    Also, whatever bus knows how to do this must
+ *    provide two soundbus_dev devices and the fabric
+ *    must be able to link them correctly.
+ *
+ *    I don't even know if Apple ever uses the second
+ *    port on the tas3004 though, I don't think their
+ *    i2s controllers can even do it. OTOH, they all
+ *    derive the clocks from common clocks, so it
+ *    might just be possible. The framework allows the
+ *    codec to refine the transfer_info items in the
+ *    usable callback, so we can simply remove the
+ *    rates the second instance is not using when it
+ *    actually is in use.
+ *    Maybe we'll need to make the sound busses have
+ *    a 'clock group id' value so the codec can
+ *    determine if the two outputs can be driven at
+ *    the same time. But that is likely overkill, up
+ *    to the fabric to not link them up incorrectly,
+ *    and up to the hardware designer to not wire
+ *    them up in some weird unusable way.
+ */
+#include <stddef.h>
+#include <linux/i2c.h>
+#include <asm/pmac_low_i2c.h>
+#include <asm/prom.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("tas codec driver for snd-aoa");
+
+#include "snd-aoa-codec-tas.h"
+#include "snd-aoa-codec-tas-gain-table.h"
+#include "snd-aoa-codec-tas-basstreble.h"
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+#define PFX "snd-aoa-codec-tas: "
+
+
+struct tas {
+	struct aoa_codec	codec;
+	struct i2c_client	i2c;
+	u32			mute_l:1, mute_r:1 ,
+				controls_created:1 ,
+				drc_enabled:1,
+				hw_enabled:1;
+	u8			cached_volume_l, cached_volume_r;
+	u8			mixer_l[3], mixer_r[3];
+	u8			bass, treble;
+	u8			acr;
+	int			drc_range;
+	/* protects hardware access against concurrency from
+	 * userspace when hitting controls and during
+	 * codec init/suspend/resume */
+	struct mutex		mtx;
+};
+
+static int tas_reset_init(struct tas *tas);
+
+static struct tas *codec_to_tas(struct aoa_codec *codec)
+{
+	return container_of(codec, struct tas, codec);
+}
+
+static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data)
+{
+	if (len == 1)
+		return i2c_smbus_write_byte_data(&tas->i2c, reg, *data);
+	else
+		return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data);
+}
+
+static void tas3004_set_drc(struct tas *tas)
+{
+	unsigned char val[6];
+
+	if (tas->drc_enabled)
+		val[0] = 0x50; /* 3:1 above threshold */
+	else
+		val[0] = 0x51; /* disabled */
+	val[1] = 0x02; /* 1:1 below threshold */
+	if (tas->drc_range > 0xef)
+		val[2] = 0xef;
+	else if (tas->drc_range < 0)
+		val[2] = 0x00;
+	else
+		val[2] = tas->drc_range;
+	val[3] = 0xb0;
+	val[4] = 0x60;
+	val[5] = 0xa0;
+
+	tas_write_reg(tas, TAS_REG_DRC, 6, val);
+}
+
+static void tas_set_treble(struct tas *tas)
+{
+	u8 tmp;
+
+	tmp = tas3004_treble(tas->treble);
+	tas_write_reg(tas, TAS_REG_TREBLE, 1, &tmp);
+}
+
+static void tas_set_bass(struct tas *tas)
+{
+	u8 tmp;
+
+	tmp = tas3004_bass(tas->bass);
+	tas_write_reg(tas, TAS_REG_BASS, 1, &tmp);
+}
+
+static void tas_set_volume(struct tas *tas)
+{
+	u8 block[6];
+	int tmp;
+	u8 left, right;
+
+	left = tas->cached_volume_l;
+	right = tas->cached_volume_r;
+
+	if (left > 177) left = 177;
+	if (right > 177) right = 177;
+
+	if (tas->mute_l) left = 0;
+	if (tas->mute_r) right = 0;
+
+	/* analysing the volume and mixer tables shows
+	 * that they are similar enough when we shift
+	 * the mixer table down by 4 bits. The error
+	 * is miniscule, in just one item the error
+	 * is 1, at a value of 0x07f17b (mixer table
+	 * value is 0x07f17a) */
+	tmp = tas_gaintable[left];
+	block[0] = tmp>>20;
+	block[1] = tmp>>12;
+	block[2] = tmp>>4;
+	tmp = tas_gaintable[right];
+	block[3] = tmp>>20;
+	block[4] = tmp>>12;
+	block[5] = tmp>>4;
+	tas_write_reg(tas, TAS_REG_VOL, 6, block);
+}
+
+static void tas_set_mixer(struct tas *tas)
+{
+	u8 block[9];
+	int tmp, i;
+	u8 val;
+
+	for (i=0;i<3;i++) {
+		val = tas->mixer_l[i];
+		if (val > 177) val = 177;
+		tmp = tas_gaintable[val];
+		block[3*i+0] = tmp>>16;
+		block[3*i+1] = tmp>>8;
+		block[3*i+2] = tmp;
+	}
+	tas_write_reg(tas, TAS_REG_LMIX, 9, block);
+
+	for (i=0;i<3;i++) {
+		val = tas->mixer_r[i];
+		if (val > 177) val = 177;
+		tmp = tas_gaintable[val];
+		block[3*i+0] = tmp>>16;
+		block[3*i+1] = tmp>>8;
+		block[3*i+2] = tmp;
+	}
+	tas_write_reg(tas, TAS_REG_RMIX, 9, block);
+}
+
+/* alsa stuff */
+
+static int tas_dev_register(struct snd_device *dev)
+{
+	return 0;
+}
+
+static struct snd_device_ops ops = {
+	.dev_register = tas_dev_register,
+};
+
+static int tas_snd_vol_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 177;
+	return 0;
+}
+
+static int tas_snd_vol_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.integer.value[0] = tas->cached_volume_l;
+	ucontrol->value.integer.value[1] = tas->cached_volume_r;
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	if (tas->cached_volume_l == ucontrol->value.integer.value[0]
+	 && tas->cached_volume_r == ucontrol->value.integer.value[1]) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+
+	tas->cached_volume_l = ucontrol->value.integer.value[0];
+	tas->cached_volume_r = ucontrol->value.integer.value[1];
+	if (tas->hw_enabled)
+		tas_set_volume(tas);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+static struct snd_kcontrol_new volume_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Master Playback Volume",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = tas_snd_vol_info,
+	.get = tas_snd_vol_get,
+	.put = tas_snd_vol_put,
+};
+
+static int tas_snd_mute_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int tas_snd_mute_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.integer.value[0] = !tas->mute_l;
+	ucontrol->value.integer.value[1] = !tas->mute_r;
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	if (tas->mute_l == !ucontrol->value.integer.value[0]
+	 && tas->mute_r == !ucontrol->value.integer.value[1]) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+
+	tas->mute_l = !ucontrol->value.integer.value[0];
+	tas->mute_r = !ucontrol->value.integer.value[1];
+	if (tas->hw_enabled)
+		tas_set_volume(tas);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+static struct snd_kcontrol_new mute_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Master Playback Switch",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = tas_snd_mute_info,
+	.get = tas_snd_mute_get,
+	.put = tas_snd_mute_put,
+};
+
+static int tas_snd_mixer_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 177;
+	return 0;
+}
+
+static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->private_value;
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.integer.value[0] = tas->mixer_l[idx];
+	ucontrol->value.integer.value[1] = tas->mixer_r[idx];
+	mutex_unlock(&tas->mtx);
+
+	return 0;
+}
+
+static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+	int idx = kcontrol->private_value;
+
+	mutex_lock(&tas->mtx);
+	if (tas->mixer_l[idx] == ucontrol->value.integer.value[0]
+	 && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+
+	tas->mixer_l[idx] = ucontrol->value.integer.value[0];
+	tas->mixer_r[idx] = ucontrol->value.integer.value[1];
+
+	if (tas->hw_enabled)
+		tas_set_mixer(tas);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+#define MIXER_CONTROL(n,descr,idx)			\
+static struct snd_kcontrol_new n##_control = {		\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		\
+	.name = descr " Playback Volume",		\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,	\
+	.info = tas_snd_mixer_info,			\
+	.get = tas_snd_mixer_get,			\
+	.put = tas_snd_mixer_put,			\
+	.private_value = idx,				\
+}
+
+MIXER_CONTROL(pcm1, "PCM", 0);
+MIXER_CONTROL(monitor, "Monitor", 2);
+
+static int tas_snd_drc_range_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = TAS3004_DRC_MAX;
+	return 0;
+}
+
+static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.integer.value[0] = tas->drc_range;
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	if (tas->drc_range == ucontrol->value.integer.value[0]) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+
+	tas->drc_range = ucontrol->value.integer.value[0];
+	if (tas->hw_enabled)
+		tas3004_set_drc(tas);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+static struct snd_kcontrol_new drc_range_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "DRC Range",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = tas_snd_drc_range_info,
+	.get = tas_snd_drc_range_get,
+	.put = tas_snd_drc_range_put,
+};
+
+static int tas_snd_drc_switch_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *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 tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.integer.value[0] = tas->drc_enabled;
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	if (tas->drc_enabled == ucontrol->value.integer.value[0]) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+
+	tas->drc_enabled = ucontrol->value.integer.value[0];
+	if (tas->hw_enabled)
+		tas3004_set_drc(tas);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+static struct snd_kcontrol_new drc_switch_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "DRC Range Switch",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = tas_snd_drc_switch_info,
+	.get = tas_snd_drc_switch_get,
+	.put = tas_snd_drc_switch_put,
+};
+
+static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	static char *texts[] = { "Line-In", "Microphone" };
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B);
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+	int oldacr;
+
+	mutex_lock(&tas->mtx);
+	oldacr = tas->acr;
+
+	/*
+	 * Despite what the data sheet says in one place, the
+	 * TAS_ACR_B_MONAUREAL bit forces mono output even when
+	 * input A (line in) is selected.
+	 */
+	tas->acr &= ~(TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL);
+	if (ucontrol->value.enumerated.item[0])
+		tas->acr |= TAS_ACR_INPUT_B | TAS_ACR_B_MONAUREAL |
+		      TAS_ACR_B_MON_SEL_RIGHT;
+	if (oldacr == tas->acr) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+	if (tas->hw_enabled)
+		tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+static struct snd_kcontrol_new capture_source_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	/* If we name this 'Input Source', it properly shows up in
+	 * alsamixer as a selection, * but it's shown under the
+	 * 'Playback' category.
+	 * If I name it 'Capture Source', it shows up in strange
+	 * ways (two bools of which one can be selected at a
+	 * time) but at least it's shown in the 'Capture'
+	 * category.
+	 * I was told that this was due to backward compatibility,
+	 * but I don't understand then why the mangling is *not*
+	 * done when I name it "Input Source".....
+	 */
+	.name = "Capture Source",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = tas_snd_capture_source_info,
+	.get = tas_snd_capture_source_get,
+	.put = tas_snd_capture_source_put,
+};
+
+static int tas_snd_treble_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = TAS3004_TREBLE_MIN;
+	uinfo->value.integer.max = TAS3004_TREBLE_MAX;
+	return 0;
+}
+
+static int tas_snd_treble_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.integer.value[0] = tas->treble;
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_snd_treble_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	if (tas->treble == ucontrol->value.integer.value[0]) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+
+	tas->treble = ucontrol->value.integer.value[0];
+	if (tas->hw_enabled)
+		tas_set_treble(tas);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+static struct snd_kcontrol_new treble_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Treble",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = tas_snd_treble_info,
+	.get = tas_snd_treble_get,
+	.put = tas_snd_treble_put,
+};
+
+static int tas_snd_bass_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = TAS3004_BASS_MIN;
+	uinfo->value.integer.max = TAS3004_BASS_MAX;
+	return 0;
+}
+
+static int tas_snd_bass_get(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	ucontrol->value.integer.value[0] = tas->bass;
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_snd_bass_put(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct tas *tas = snd_kcontrol_chip(kcontrol);
+
+	mutex_lock(&tas->mtx);
+	if (tas->bass == ucontrol->value.integer.value[0]) {
+		mutex_unlock(&tas->mtx);
+		return 0;
+	}
+
+	tas->bass = ucontrol->value.integer.value[0];
+	if (tas->hw_enabled)
+		tas_set_bass(tas);
+	mutex_unlock(&tas->mtx);
+	return 1;
+}
+
+static struct snd_kcontrol_new bass_control = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Bass",
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.info = tas_snd_bass_info,
+	.get = tas_snd_bass_get,
+	.put = tas_snd_bass_put,
+};
+
+static struct transfer_info tas_transfers[] = {
+	{
+		/* input */
+		.formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
+			   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.transfer_in = 1,
+	},
+	{
+		/* output */
+		.formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE |
+			   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE,
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.transfer_in = 0,
+	},
+	{}
+};
+
+static int tas_usable(struct codec_info_item *cii,
+		      struct transfer_info *ti,
+		      struct transfer_info *out)
+{
+	return 1;
+}
+
+static int tas_reset_init(struct tas *tas)
+{
+	u8 tmp;
+
+	tas->codec.gpio->methods->all_amps_off(tas->codec.gpio);
+	msleep(5);
+	tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
+	msleep(5);
+	tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1);
+	msleep(20);
+	tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0);
+	msleep(10);
+	tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
+
+	tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT;
+	if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp))
+		goto outerr;
+
+	tas->acr |= TAS_ACR_ANALOG_PDOWN;
+	if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+		goto outerr;
+
+	tmp = 0;
+	if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp))
+		goto outerr;
+
+	tas3004_set_drc(tas);
+
+	/* Set treble & bass to 0dB */
+	tas->treble = TAS3004_TREBLE_ZERO;
+	tas->bass = TAS3004_BASS_ZERO;
+	tas_set_treble(tas);
+	tas_set_bass(tas);
+
+	tas->acr &= ~TAS_ACR_ANALOG_PDOWN;
+	if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr))
+		goto outerr;
+
+	return 0;
+ outerr:
+	return -ENODEV;
+}
+
+static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock)
+{
+	struct tas *tas = cii->codec_data;
+
+	switch(clock) {
+	case CLOCK_SWITCH_PREPARE_SLAVE:
+		/* Clocks are going away, mute mute mute */
+		tas->codec.gpio->methods->all_amps_off(tas->codec.gpio);
+		tas->hw_enabled = 0;
+		break;
+	case CLOCK_SWITCH_SLAVE:
+		/* Clocks are back, re-init the codec */
+		mutex_lock(&tas->mtx);
+		tas_reset_init(tas);
+		tas_set_volume(tas);
+		tas_set_mixer(tas);
+		tas->hw_enabled = 1;
+		tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio);
+		mutex_unlock(&tas->mtx);
+		break;
+	default:
+		/* doesn't happen as of now */
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* we are controlled via i2c and assume that is always up
+ * If that wasn't the case, we'd have to suspend once
+ * our i2c device is suspended, and then take note of that! */
+static int tas_suspend(struct tas *tas)
+{
+	mutex_lock(&tas->mtx);
+	tas->hw_enabled = 0;
+	tas->acr |= TAS_ACR_ANALOG_PDOWN;
+	tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr);
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+static int tas_resume(struct tas *tas)
+{
+	/* reset codec */
+	mutex_lock(&tas->mtx);
+	tas_reset_init(tas);
+	tas_set_volume(tas);
+	tas_set_mixer(tas);
+	tas->hw_enabled = 1;
+	mutex_unlock(&tas->mtx);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int _tas_suspend(struct codec_info_item *cii, pm_message_t state)
+{
+	return tas_suspend(cii->codec_data);
+}
+
+static int _tas_resume(struct codec_info_item *cii)
+{
+	return tas_resume(cii->codec_data);
+}
+#endif
+
+static struct codec_info tas_codec_info = {
+	.transfers = tas_transfers,
+	/* in theory, we can drive it at 512 too...
+	 * but so far the framework doesn't allow
+	 * for that and I don't see much point in it. */
+	.sysclock_factor = 256,
+	/* same here, could be 32 for just one 16 bit format */
+	.bus_factor = 64,
+	.owner = THIS_MODULE,
+	.usable = tas_usable,
+	.switch_clock = tas_switch_clock,
+#ifdef CONFIG_PM
+	.suspend = _tas_suspend,
+	.resume = _tas_resume,
+#endif
+};
+
+static int tas_init_codec(struct aoa_codec *codec)
+{
+	struct tas *tas = codec_to_tas(codec);
+	int err;
+
+	if (!tas->codec.gpio || !tas->codec.gpio->methods) {
+		printk(KERN_ERR PFX "gpios not assigned!!\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&tas->mtx);
+	if (tas_reset_init(tas)) {
+		printk(KERN_ERR PFX "tas failed to initialise\n");
+		mutex_unlock(&tas->mtx);
+		return -ENXIO;
+	}
+	tas->hw_enabled = 1;
+	mutex_unlock(&tas->mtx);
+
+	if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev,
+						   aoa_get_card(),
+						   &tas_codec_info, tas)) {
+		printk(KERN_ERR PFX "error attaching tas to soundbus\n");
+		return -ENODEV;
+	}
+
+	if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, tas, &ops)) {
+		printk(KERN_ERR PFX "failed to create tas snd device!\n");
+		return -ENODEV;
+	}
+	err = aoa_snd_ctl_add(snd_ctl_new1(&volume_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&mute_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&pcm1_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&monitor_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&capture_source_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&drc_range_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&drc_switch_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&treble_control, tas));
+	if (err)
+		goto error;
+
+	err = aoa_snd_ctl_add(snd_ctl_new1(&bass_control, tas));
+	if (err)
+		goto error;
+
+	return 0;
+ error:
+	tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
+	snd_device_free(aoa_get_card(), tas);
+	return err;
+}
+
+static void tas_exit_codec(struct aoa_codec *codec)
+{
+	struct tas *tas = codec_to_tas(codec);
+
+	if (!tas->codec.soundbus_dev)
+		return;
+	tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas);
+}
+	
+
+static struct i2c_driver tas_driver;
+
+static int tas_create(struct i2c_adapter *adapter,
+		       struct device_node *node,
+		       int addr)
+{
+	struct tas *tas;
+
+	tas = kzalloc(sizeof(struct tas), GFP_KERNEL);
+
+	if (!tas)
+		return -ENOMEM;
+
+	mutex_init(&tas->mtx);
+	tas->i2c.driver = &tas_driver;
+	tas->i2c.adapter = adapter;
+	tas->i2c.addr = addr;
+	/* seems that half is a saner default */
+	tas->drc_range = TAS3004_DRC_MAX / 2;
+	strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE);
+
+	if (i2c_attach_client(&tas->i2c)) {
+		printk(KERN_ERR PFX "failed to attach to i2c\n");
+		goto fail;
+	}
+
+	strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN);
+	tas->codec.owner = THIS_MODULE;
+	tas->codec.init = tas_init_codec;
+	tas->codec.exit = tas_exit_codec;
+	tas->codec.node = of_node_get(node);
+
+	if (aoa_codec_register(&tas->codec)) {
+		goto detach;
+	}
+	printk(KERN_DEBUG
+	       "snd-aoa-codec-tas: tas found, addr 0x%02x on %s\n",
+	       addr, node->full_name);
+	return 0;
+ detach:
+	i2c_detach_client(&tas->i2c);
+ fail:
+	mutex_destroy(&tas->mtx);
+	kfree(tas);
+	return -EINVAL;
+}
+
+static int tas_i2c_attach(struct i2c_adapter *adapter)
+{
+	struct device_node *busnode, *dev = NULL;
+	struct pmac_i2c_bus *bus;
+
+	bus = pmac_i2c_adapter_to_bus(adapter);
+	if (bus == NULL)
+		return -ENODEV;
+	busnode = pmac_i2c_get_bus_node(bus);
+
+	while ((dev = of_get_next_child(busnode, dev)) != NULL) {
+		if (of_device_is_compatible(dev, "tas3004")) {
+			const u32 *addr;
+			printk(KERN_DEBUG PFX "found tas3004\n");
+			addr = of_get_property(dev, "reg", NULL);
+			if (!addr)
+				continue;
+			return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
+		}
+		/* older machines have no 'codec' node with a 'compatible'
+		 * property that says 'tas3004', they just have a 'deq'
+		 * node without any such property... */
+		if (strcmp(dev->name, "deq") == 0) {
+			const u32 *_addr;
+			u32 addr;
+			printk(KERN_DEBUG PFX "found 'deq' node\n");
+			_addr = of_get_property(dev, "i2c-address", NULL);
+			if (!_addr)
+				continue;
+			addr = ((*_addr) >> 1) & 0x7f;
+			/* now, if the address doesn't match any of the two
+			 * that a tas3004 can have, we cannot handle this.
+			 * I doubt it ever happens but hey. */
+			if (addr != 0x34 && addr != 0x35)
+				continue;
+			return tas_create(adapter, dev, addr);
+		}
+	}
+	return -ENODEV;
+}
+
+static int tas_i2c_detach(struct i2c_client *client)
+{
+	struct tas *tas = container_of(client, struct tas, i2c);
+	int err;
+	u8 tmp = TAS_ACR_ANALOG_PDOWN;
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+	aoa_codec_unregister(&tas->codec);
+	of_node_put(tas->codec.node);
+
+	/* power down codec chip */
+	tas_write_reg(tas, TAS_REG_ACR, 1, &tmp);
+
+	mutex_destroy(&tas->mtx);
+	kfree(tas);
+	return 0;
+}
+
+static struct i2c_driver tas_driver = {
+	.driver = {
+		.name = "aoa_codec_tas",
+		.owner = THIS_MODULE,
+	},
+	.attach_adapter = tas_i2c_attach,
+	.detach_client = tas_i2c_detach,
+};
+
+static int __init tas_init(void)
+{
+	return i2c_add_driver(&tas_driver);
+}
+
+static void __exit tas_exit(void)
+{
+	i2c_del_driver(&tas_driver);
+}
+
+module_init(tas_init);
+module_exit(tas_exit);
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/aoa/fabrics/snd-aoa-fabric-layout.c linux-2.6.22/sound/.pc/alsa-20070818.patch/aoa/fabrics/snd-aoa-fabric-layout.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/aoa/fabrics/snd-aoa-fabric-layout.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/aoa/fabrics/snd-aoa-fabric-layout.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,1128 @@
+/*
+ * Apple Onboard Audio driver -- layout fabric
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPL v2, can be found in COPYING.
+ *
+ *
+ * This fabric module looks for sound codecs
+ * based on the layout-id property in the device tree.
+ *
+ */
+
+#include <asm/prom.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include "../aoa.h"
+#include "../soundbus/soundbus.h"
+
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa");
+
+#define MAX_CODECS_PER_BUS	2
+
+/* These are the connections the layout fabric
+ * knows about. It doesn't really care about the
+ * input ones, but I thought I'd separate them
+ * to give them proper names. The thing is that
+ * Apple usually will distinguish the active output
+ * by GPIOs, while the active input is set directly
+ * on the codec. Hence we here tell the codec what
+ * we think is connected. This information is hard-
+ * coded below ... */
+#define CC_SPEAKERS	(1<<0)
+#define CC_HEADPHONE	(1<<1)
+#define CC_LINEOUT	(1<<2)
+#define CC_DIGITALOUT	(1<<3)
+#define CC_LINEIN	(1<<4)
+#define CC_MICROPHONE	(1<<5)
+#define CC_DIGITALIN	(1<<6)
+/* pretty bogus but users complain...
+ * This is a flag saying that the LINEOUT
+ * should be renamed to HEADPHONE.
+ * be careful with input detection! */
+#define CC_LINEOUT_LABELLED_HEADPHONE	(1<<7)
+
+struct codec_connection {
+	/* CC_ flags from above */
+	int connected;
+	/* codec dependent bit to be set in the aoa_codec.connected field.
+	 * This intentionally doesn't have any generic flags because the
+	 * fabric has to know the codec anyway and all codecs might have
+	 * different connectors */
+	int codec_bit;
+};
+
+struct codec_connect_info {
+	char *name;
+	struct codec_connection *connections;
+};
+
+#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF	(1<<0)
+
+struct layout {
+	unsigned int layout_id;
+	struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
+	int flags;
+	
+	/* if busname is not assigned, we use 'Master' below,
+	 * so that our layout table doesn't need to be filled
+	 * too much.
+	 * We only assign these two if we expect to find more
+	 * than one soundbus, i.e. on those machines with
+	 * multiple layout-ids */
+	char *busname;
+	int pcmid;
+};
+
+MODULE_ALIAS("sound-layout-36");
+MODULE_ALIAS("sound-layout-41");
+MODULE_ALIAS("sound-layout-45");
+MODULE_ALIAS("sound-layout-47");
+MODULE_ALIAS("sound-layout-48");
+MODULE_ALIAS("sound-layout-49");
+MODULE_ALIAS("sound-layout-50");
+MODULE_ALIAS("sound-layout-51");
+MODULE_ALIAS("sound-layout-56");
+MODULE_ALIAS("sound-layout-57");
+MODULE_ALIAS("sound-layout-58");
+MODULE_ALIAS("sound-layout-60");
+MODULE_ALIAS("sound-layout-61");
+MODULE_ALIAS("sound-layout-62");
+MODULE_ALIAS("sound-layout-64");
+MODULE_ALIAS("sound-layout-65");
+MODULE_ALIAS("sound-layout-66");
+MODULE_ALIAS("sound-layout-67");
+MODULE_ALIAS("sound-layout-68");
+MODULE_ALIAS("sound-layout-69");
+MODULE_ALIAS("sound-layout-70");
+MODULE_ALIAS("sound-layout-72");
+MODULE_ALIAS("sound-layout-76");
+MODULE_ALIAS("sound-layout-80");
+MODULE_ALIAS("sound-layout-82");
+MODULE_ALIAS("sound-layout-84");
+MODULE_ALIAS("sound-layout-86");
+MODULE_ALIAS("sound-layout-90");
+MODULE_ALIAS("sound-layout-92");
+MODULE_ALIAS("sound-layout-94");
+MODULE_ALIAS("sound-layout-96");
+MODULE_ALIAS("sound-layout-98");
+MODULE_ALIAS("sound-layout-100");
+
+/* onyx with all but microphone connected */
+static struct codec_connection onyx_connections_nomic[] = {
+	{
+		.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_DIGITALOUT,
+		.codec_bit = 1,
+	},
+	{
+		.connected = CC_LINEIN,
+		.codec_bit = 2,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+/* onyx on machines without headphone */
+static struct codec_connection onyx_connections_noheadphones[] = {
+	{
+		.connected = CC_SPEAKERS | CC_LINEOUT |
+			     CC_LINEOUT_LABELLED_HEADPHONE,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_DIGITALOUT,
+		.codec_bit = 1,
+	},
+	/* FIXME: are these correct? probably not for all the machines
+	 * below ... If not this will need separating. */
+	{
+		.connected = CC_LINEIN,
+		.codec_bit = 2,
+	},
+	{
+		.connected = CC_MICROPHONE,
+		.codec_bit = 3,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+/* onyx on machines with real line-out */
+static struct codec_connection onyx_connections_reallineout[] = {
+	{
+		.connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_DIGITALOUT,
+		.codec_bit = 1,
+	},
+	{
+		.connected = CC_LINEIN,
+		.codec_bit = 2,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines without line out */
+static struct codec_connection tas_connections_nolineout[] = {
+	{
+		.connected = CC_SPEAKERS | CC_HEADPHONE,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_LINEIN,
+		.codec_bit = 2,
+	},
+	{
+		.connected = CC_MICROPHONE,
+		.codec_bit = 3,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines with neither line out nor line in */
+static struct codec_connection tas_connections_noline[] = {
+	{
+		.connected = CC_SPEAKERS | CC_HEADPHONE,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_MICROPHONE,
+		.codec_bit = 3,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines without microphone */
+static struct codec_connection tas_connections_nomic[] = {
+	{
+		.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_LINEIN,
+		.codec_bit = 2,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+/* tas on machines with everything connected */
+static struct codec_connection tas_connections_all[] = {
+	{
+		.connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_LINEIN,
+		.codec_bit = 2,
+	},
+	{
+		.connected = CC_MICROPHONE,
+		.codec_bit = 3,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection toonie_connections[] = {
+	{
+		.connected = CC_SPEAKERS | CC_HEADPHONE,
+		.codec_bit = 0,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_input[] = {
+	{
+		.connected = CC_DIGITALIN,
+		.codec_bit = 0,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_output[] = {
+	{
+		.connected = CC_DIGITALOUT,
+		.codec_bit = 1,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+static struct codec_connection topaz_inout[] = {
+	{
+		.connected = CC_DIGITALIN,
+		.codec_bit = 0,
+	},
+	{
+		.connected = CC_DIGITALOUT,
+		.codec_bit = 1,
+	},
+	{} /* terminate array by .connected == 0 */
+};
+
+static struct layout layouts[] = {
+	/* last PowerBooks (15" Oct 2005) */
+	{ .layout_id = 82,
+	  .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	  .codecs[1] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	/* PowerMac9,1 */
+	{ .layout_id = 60,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_reallineout,
+	  },
+	},
+	/* PowerMac9,1 */
+	{ .layout_id = 61,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	/* PowerBook5,7 */
+	{ .layout_id = 64,
+	  .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	},
+	/* PowerBook5,7 */
+	{ .layout_id = 65,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	/* PowerBook5,9 [17" Oct 2005] */
+	{ .layout_id = 84,
+	  .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	  .codecs[1] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	/* PowerMac8,1 */
+	{ .layout_id = 45,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	  .codecs[1] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	/* Quad PowerMac (analog in, analog/digital out) */
+	{ .layout_id = 68,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_nomic,
+	  },
+	},
+	/* Quad PowerMac (digital in) */
+	{ .layout_id = 69,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	  .busname = "digital in", .pcmid = 1 },
+	/* Early 2005 PowerBook (PowerBook 5,6) */
+	{ .layout_id = 70,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_nolineout,
+	  },
+	},
+	/* PowerBook 5,4 */
+	{ .layout_id = 51,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_nolineout,
+	  },
+	},
+	/* PowerBook6,7 */
+	{ .layout_id = 80,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_noline,
+	  },
+	},
+	/* PowerBook6,8 */
+	{ .layout_id = 72,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_nolineout,
+	  },
+	},
+	/* PowerMac8,2 */
+	{ .layout_id = 86,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_nomic,
+	  },
+	  .codecs[1] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	/* PowerBook6,7 */
+	{ .layout_id = 92,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_nolineout,
+	  },
+	},
+	/* PowerMac10,1 (Mac Mini) */
+	{ .layout_id = 58,
+	  .codecs[0] = {
+		.name = "toonie",
+		.connections = toonie_connections,
+	  },
+	},
+	{
+	  .layout_id = 96,
+	  .codecs[0] = {
+	  	.name = "onyx",
+	  	.connections = onyx_connections_noheadphones,
+	  },
+	},
+	/* unknown, untested, but this comes from Apple */
+	{ .layout_id = 41,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_all,
+	  },
+	},
+	{ .layout_id = 36,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_nomic,
+	  },
+	  .codecs[1] = {
+		.name = "topaz",
+		.connections = topaz_inout,
+	  },
+	},
+	{ .layout_id = 47,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	},
+	{ .layout_id = 48,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	{ .layout_id = 49,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_nomic,
+	  },
+	},
+	{ .layout_id = 50,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	{ .layout_id = 56,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	},
+	{ .layout_id = 57,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	{ .layout_id = 62,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	  .codecs[1] = {
+		.name = "topaz",
+		.connections = topaz_output,
+	  },
+	},
+	{ .layout_id = 66,
+	  .codecs[0] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	},
+	{ .layout_id = 67,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	},
+	{ .layout_id = 76,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_nomic,
+	  },
+	  .codecs[1] = {
+		.name = "topaz",
+		.connections = topaz_inout,
+	  },
+	},
+	{ .layout_id = 90,
+	  .codecs[0] = {
+		.name = "tas",
+		.connections = tas_connections_noline,
+	  },
+	},
+	{ .layout_id = 94,
+	  .codecs[0] = {
+		.name = "onyx",
+		/* but it has an external mic?? how to select? */
+		.connections = onyx_connections_noheadphones,
+	  },
+	},
+	{ .layout_id = 98,
+	  .codecs[0] = {
+		.name = "toonie",
+		.connections = toonie_connections,
+	  },
+	},
+	{ .layout_id = 100,
+	  .codecs[0] = {
+		.name = "topaz",
+		.connections = topaz_input,
+	  },
+	  .codecs[1] = {
+		.name = "onyx",
+		.connections = onyx_connections_noheadphones,
+	  },
+	},
+	{}
+};
+
+static struct layout *find_layout_by_id(unsigned int id)
+{
+	struct layout *l;
+
+	l = layouts;
+	while (l->layout_id) {
+		if (l->layout_id == id)
+			return l;
+		l++;
+	}
+	return NULL;
+}
+
+static void use_layout(struct layout *l)
+{
+	int i;
+
+	for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+		if (l->codecs[i].name) {
+			request_module("snd-aoa-codec-%s", l->codecs[i].name);
+		}
+	}
+	/* now we wait for the codecs to call us back */
+}
+
+struct layout_dev;
+
+struct layout_dev_ptr {
+	struct layout_dev *ptr;
+};
+
+struct layout_dev {
+	struct list_head list;
+	struct soundbus_dev *sdev;
+	struct device_node *sound;
+	struct aoa_codec *codecs[MAX_CODECS_PER_BUS];
+	struct layout *layout;
+	struct gpio_runtime gpio;
+
+	/* we need these for headphone/lineout detection */
+	struct snd_kcontrol *headphone_ctrl;
+	struct snd_kcontrol *lineout_ctrl;
+	struct snd_kcontrol *speaker_ctrl;
+	struct snd_kcontrol *headphone_detected_ctrl;
+	struct snd_kcontrol *lineout_detected_ctrl;
+
+	struct layout_dev_ptr selfptr_headphone;
+	struct layout_dev_ptr selfptr_lineout;
+
+	u32 have_lineout_detect:1,
+	    have_headphone_detect:1,
+	    switch_on_headphone:1,
+	    switch_on_lineout:1;
+};
+
+static LIST_HEAD(layouts_list);
+static int layouts_list_items;
+/* this can go away but only if we allow multiple cards,
+ * make the fabric handle all the card stuff, etc... */
+static struct layout_dev *layout_device;
+
+static int control_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+#define AMP_CONTROL(n, description)					\
+static int n##_control_get(struct snd_kcontrol *kcontrol,		\
+			   struct snd_ctl_elem_value *ucontrol)		\
+{									\
+	struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);	\
+	if (gpio->methods && gpio->methods->get_##n)			\
+		ucontrol->value.integer.value[0] =			\
+			gpio->methods->get_##n(gpio);			\
+	return 0;							\
+}									\
+static int n##_control_put(struct snd_kcontrol *kcontrol,		\
+			   struct snd_ctl_elem_value *ucontrol)		\
+{									\
+	struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol);	\
+	if (gpio->methods && gpio->methods->get_##n)			\
+		gpio->methods->set_##n(gpio,				\
+			ucontrol->value.integer.value[0]);		\
+	return 1;							\
+}									\
+static struct snd_kcontrol_new n##_ctl = {				\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,				\
+	.name = description,						\
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,                      \
+	.info = control_info,						\
+	.get = n##_control_get,						\
+	.put = n##_control_put,						\
+}
+
+AMP_CONTROL(headphone, "Headphone Switch");
+AMP_CONTROL(speakers, "Speakers Switch");
+AMP_CONTROL(lineout, "Line-Out Switch");
+
+static int detect_choice_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+
+	switch (kcontrol->private_value) {
+	case 0:
+		ucontrol->value.integer.value[0] = ldev->switch_on_headphone;
+		break;
+	case 1:
+		ucontrol->value.integer.value[0] = ldev->switch_on_lineout;
+		break;
+	default:
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int detect_choice_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+
+	switch (kcontrol->private_value) {
+	case 0:
+		ldev->switch_on_headphone = !!ucontrol->value.integer.value[0];
+		break;
+	case 1:
+		ldev->switch_on_lineout = !!ucontrol->value.integer.value[0];
+		break;
+	default:
+		return -ENODEV;
+	}
+	return 1;
+}
+
+static struct snd_kcontrol_new headphone_detect_choice = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Headphone Detect Autoswitch",
+	.info = control_info,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.get = detect_choice_get,
+	.put = detect_choice_put,
+	.private_value = 0,
+};
+
+static struct snd_kcontrol_new lineout_detect_choice = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Line-Out Detect Autoswitch",
+	.info = control_info,
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	.get = detect_choice_get,
+	.put = detect_choice_put,
+	.private_value = 1,
+};
+
+static int detected_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
+	int v;
+
+	switch (kcontrol->private_value) {
+	case 0:
+		v = ldev->gpio.methods->get_detect(&ldev->gpio,
+						   AOA_NOTIFY_HEADPHONE);
+		break;
+	case 1:
+		v = ldev->gpio.methods->get_detect(&ldev->gpio,
+						   AOA_NOTIFY_LINE_OUT);
+		break;
+	default:
+		return -ENODEV;
+	}
+	ucontrol->value.integer.value[0] = v;
+	return 0;
+}
+
+static struct snd_kcontrol_new headphone_detected = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Headphone Detected",
+	.info = control_info,
+	.access = SNDRV_CTL_ELEM_ACCESS_READ,
+	.get = detected_get,
+	.private_value = 0,
+};
+
+static struct snd_kcontrol_new lineout_detected = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Line-Out Detected",
+	.info = control_info,
+	.access = SNDRV_CTL_ELEM_ACCESS_READ,
+	.get = detected_get,
+	.private_value = 1,
+};
+
+static int check_codec(struct aoa_codec *codec,
+		       struct layout_dev *ldev,
+		       struct codec_connect_info *cci)
+{
+	const u32 *ref;
+	char propname[32];
+	struct codec_connection *cc;
+
+	/* if the codec has a 'codec' node, we require a reference */
+	if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
+		snprintf(propname, sizeof(propname),
+			 "platform-%s-codec-ref", codec->name);
+		ref = of_get_property(ldev->sound, propname, NULL);
+		if (!ref) {
+			printk(KERN_INFO "snd-aoa-fabric-layout: "
+				"required property %s not present\n", propname);
+			return -ENODEV;
+		}
+		if (*ref != codec->node->linux_phandle) {
+			printk(KERN_INFO "snd-aoa-fabric-layout: "
+				"%s doesn't match!\n", propname);
+			return -ENODEV;
+		}
+	} else {
+		if (layouts_list_items != 1) {
+			printk(KERN_INFO "snd-aoa-fabric-layout: "
+				"more than one soundbus, but no references.\n");
+			return -ENODEV;
+		}
+	}
+	codec->soundbus_dev = ldev->sdev;
+	codec->gpio = &ldev->gpio;
+
+	cc = cci->connections;
+	if (!cc)
+		return -EINVAL;
+
+	printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n");
+
+	codec->connected = 0;
+	codec->fabric_data = cc;
+
+	while (cc->connected) {
+		codec->connected |= 1<<cc->codec_bit;
+		cc++;
+	}
+
+	return 0;
+}
+
+static int layout_found_codec(struct aoa_codec *codec)
+{
+	struct layout_dev *ldev;
+	int i;
+
+	list_for_each_entry(ldev, &layouts_list, list) {
+		for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+			if (!ldev->layout->codecs[i].name)
+				continue;
+			if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) {
+				if (check_codec(codec,
+						ldev,
+						&ldev->layout->codecs[i]) == 0)
+					return 0;
+			}
+		}
+	}
+	return -ENODEV;
+}
+
+static void layout_remove_codec(struct aoa_codec *codec)
+{
+	int i;
+	/* here remove the codec from the layout dev's
+	 * codec reference */
+
+	codec->soundbus_dev = NULL;
+	codec->gpio = NULL;
+	for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+	}
+}
+
+static void layout_notify(void *data)
+{
+	struct layout_dev_ptr *dptr = data;
+	struct layout_dev *ldev;
+	int v, update;
+	struct snd_kcontrol *detected, *c;
+	struct snd_card *card = aoa_get_card();
+
+	ldev = dptr->ptr;
+	if (data == &ldev->selfptr_headphone) {
+		v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE);
+		detected = ldev->headphone_detected_ctrl;
+		update = ldev->switch_on_headphone;
+		if (update) {
+			ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
+			ldev->gpio.methods->set_headphone(&ldev->gpio, v);
+			ldev->gpio.methods->set_lineout(&ldev->gpio, 0);
+		}
+	} else if (data == &ldev->selfptr_lineout) {
+		v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT);
+		detected = ldev->lineout_detected_ctrl;
+		update = ldev->switch_on_lineout;
+		if (update) {
+			ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
+			ldev->gpio.methods->set_headphone(&ldev->gpio, 0);
+			ldev->gpio.methods->set_lineout(&ldev->gpio, v);
+		}
+	} else
+		return;
+
+	if (detected)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id);
+	if (update) {
+		c = ldev->headphone_ctrl;
+		if (c)
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+		c = ldev->speaker_ctrl;
+		if (c)
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+		c = ldev->lineout_ctrl;
+		if (c)
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
+	}
+}
+
+static void layout_attached_codec(struct aoa_codec *codec)
+{
+	struct codec_connection *cc;
+	struct snd_kcontrol *ctl;
+	int headphones, lineout;
+	struct layout_dev *ldev = layout_device;
+
+	/* need to add this codec to our codec array! */
+
+	cc = codec->fabric_data;
+
+	headphones = codec->gpio->methods->get_detect(codec->gpio,
+						      AOA_NOTIFY_HEADPHONE);
+ 	lineout = codec->gpio->methods->get_detect(codec->gpio,
+						   AOA_NOTIFY_LINE_OUT);
+
+	while (cc->connected) {
+		if (cc->connected & CC_SPEAKERS) {
+			if (headphones <= 0 && lineout <= 0)
+				ldev->gpio.methods->set_speakers(codec->gpio, 1);
+			ctl = snd_ctl_new1(&speakers_ctl, codec->gpio);
+			ldev->speaker_ctrl = ctl;
+			aoa_snd_ctl_add(ctl);
+		}
+		if (cc->connected & CC_HEADPHONE) {
+			if (headphones == 1)
+				ldev->gpio.methods->set_headphone(codec->gpio, 1);
+			ctl = snd_ctl_new1(&headphone_ctl, codec->gpio);
+			ldev->headphone_ctrl = ctl;
+			aoa_snd_ctl_add(ctl);
+			ldev->have_headphone_detect =
+				!ldev->gpio.methods
+					->set_notify(&ldev->gpio,
+						     AOA_NOTIFY_HEADPHONE,
+						     layout_notify,
+						     &ldev->selfptr_headphone);
+			if (ldev->have_headphone_detect) {
+				ctl = snd_ctl_new1(&headphone_detect_choice,
+						   ldev);
+				aoa_snd_ctl_add(ctl);
+				ctl = snd_ctl_new1(&headphone_detected,
+						   ldev);
+				ldev->headphone_detected_ctrl = ctl;
+				aoa_snd_ctl_add(ctl);
+			}
+		}
+		if (cc->connected & CC_LINEOUT) {
+			if (lineout == 1)
+				ldev->gpio.methods->set_lineout(codec->gpio, 1);
+			ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
+			if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+				strlcpy(ctl->id.name,
+					"Headphone Switch", sizeof(ctl->id.name));
+			ldev->lineout_ctrl = ctl;
+			aoa_snd_ctl_add(ctl);
+			ldev->have_lineout_detect =
+				!ldev->gpio.methods
+					->set_notify(&ldev->gpio,
+						     AOA_NOTIFY_LINE_OUT,
+						     layout_notify,
+						     &ldev->selfptr_lineout);
+			if (ldev->have_lineout_detect) {
+				ctl = snd_ctl_new1(&lineout_detect_choice,
+						   ldev);
+				if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+					strlcpy(ctl->id.name,
+						"Headphone Detect Autoswitch",
+						sizeof(ctl->id.name));
+				aoa_snd_ctl_add(ctl);
+				ctl = snd_ctl_new1(&lineout_detected,
+						   ldev);
+				if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
+					strlcpy(ctl->id.name,
+						"Headphone Detected",
+						sizeof(ctl->id.name));
+				ldev->lineout_detected_ctrl = ctl;
+				aoa_snd_ctl_add(ctl);
+			}
+		}
+		cc++;
+	}
+	/* now update initial state */
+	if (ldev->have_headphone_detect)
+		layout_notify(&ldev->selfptr_headphone);
+	if (ldev->have_lineout_detect)
+		layout_notify(&ldev->selfptr_lineout);
+}
+
+static struct aoa_fabric layout_fabric = {
+	.name = "SoundByLayout",
+	.owner = THIS_MODULE,
+	.found_codec = layout_found_codec,
+	.remove_codec = layout_remove_codec,
+	.attached_codec = layout_attached_codec,
+};
+
+static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
+{
+	struct device_node *sound = NULL;
+	const unsigned int *layout_id;
+	struct layout *layout;
+	struct layout_dev *ldev = NULL;
+	int err;
+
+	/* hm, currently we can only have one ... */
+	if (layout_device)
+		return -ENODEV;
+
+	/* by breaking out we keep a reference */
+	while ((sound = of_get_next_child(sdev->ofdev.node, sound))) {
+		if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
+			break;
+	}
+	if (!sound) return -ENODEV;
+
+	layout_id = of_get_property(sound, "layout-id", NULL);
+	if (!layout_id)
+		goto outnodev;
+	printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
+	       *layout_id);
+
+	layout = find_layout_by_id(*layout_id);
+	if (!layout) {
+		printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
+		goto outnodev;
+	}
+
+	ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL);
+	if (!ldev)
+		goto outnodev;
+
+	layout_device = ldev;
+	ldev->sdev = sdev;
+	ldev->sound = sound;
+	ldev->layout = layout;
+	ldev->gpio.node = sound->parent;
+	switch (layout->layout_id) {
+	case 41: /* that unknown machine no one seems to have */
+	case 51: /* PowerBook5,4 */
+	case 58: /* Mac Mini */
+		ldev->gpio.methods = ftr_gpio_methods;
+		printk(KERN_DEBUG
+		       "snd-aoa-fabric-layout: Using direct GPIOs\n");
+		break;
+	default:
+		ldev->gpio.methods = pmf_gpio_methods;
+		printk(KERN_DEBUG
+		       "snd-aoa-fabric-layout: Using PMF GPIOs\n");
+	}
+	ldev->selfptr_headphone.ptr = ldev;
+	ldev->selfptr_lineout.ptr = ldev;
+	sdev->ofdev.dev.driver_data = ldev;
+	list_add(&ldev->list, &layouts_list);
+	layouts_list_items++;
+
+	/* assign these before registering ourselves, so
+	 * callbacks that are done during registration
+	 * already have the values */
+	sdev->pcmid = ldev->layout->pcmid;
+	if (ldev->layout->busname) {
+		sdev->pcmname = ldev->layout->busname;
+	} else {
+		sdev->pcmname = "Master";
+	}
+
+	ldev->gpio.methods->init(&ldev->gpio);
+
+	err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
+	if (err && err != -EALREADY) {
+		printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
+				 " another fabric is active!\n");
+		goto outlistdel;
+	}
+
+	use_layout(layout);
+	ldev->switch_on_headphone = 1;
+	ldev->switch_on_lineout = 1;
+	return 0;
+ outlistdel:
+	/* we won't be using these then... */
+	ldev->gpio.methods->exit(&ldev->gpio);
+	/* reset if we didn't use it */
+	sdev->pcmname = NULL;
+	sdev->pcmid = -1;
+	list_del(&ldev->list);
+	layouts_list_items--;
+ outnodev:
+ 	of_node_put(sound);
+ 	layout_device = NULL;
+ 	kfree(ldev);
+	return -ENODEV;
+}
+
+static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
+{
+	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+	int i;
+
+	for (i=0; i<MAX_CODECS_PER_BUS; i++) {
+		if (ldev->codecs[i]) {
+			aoa_fabric_unlink_codec(ldev->codecs[i]);
+		}
+		ldev->codecs[i] = NULL;
+	}
+	list_del(&ldev->list);
+	layouts_list_items--;
+	of_node_put(ldev->sound);
+
+	ldev->gpio.methods->set_notify(&ldev->gpio,
+				       AOA_NOTIFY_HEADPHONE,
+				       NULL,
+				       NULL);
+	ldev->gpio.methods->set_notify(&ldev->gpio,
+				       AOA_NOTIFY_LINE_OUT,
+				       NULL,
+				       NULL);
+
+	ldev->gpio.methods->exit(&ldev->gpio);
+	layout_device = NULL;
+	kfree(ldev);
+	sdev->pcmid = -1;
+	sdev->pcmname = NULL;
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
+{
+	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+
+	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
+		ldev->gpio.methods->all_amps_off(&ldev->gpio);
+
+	return 0;
+}
+
+static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
+{
+	struct layout_dev *ldev = sdev->ofdev.dev.driver_data;
+
+	if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
+		ldev->gpio.methods->all_amps_restore(&ldev->gpio);
+
+	return 0;
+}
+#endif
+
+static struct soundbus_driver aoa_soundbus_driver = {
+	.name = "snd_aoa_soundbus_drv",
+	.owner = THIS_MODULE,
+	.probe = aoa_fabric_layout_probe,
+	.remove = aoa_fabric_layout_remove,
+#ifdef CONFIG_PM
+	.suspend = aoa_fabric_layout_suspend,
+	.resume = aoa_fabric_layout_resume,
+#endif
+	.driver = {
+		.owner = THIS_MODULE,
+	}
+};
+
+static int __init aoa_fabric_layout_init(void)
+{
+	int err;
+
+	err = soundbus_register_driver(&aoa_soundbus_driver);
+	if (err)
+		return err;
+	return 0;
+}
+
+static void __exit aoa_fabric_layout_exit(void)
+{
+	soundbus_unregister_driver(&aoa_soundbus_driver);
+	aoa_fabric_unregister(&layout_fabric);
+}
+
+module_init(aoa_fabric_layout_init);
+module_exit(aoa_fabric_layout_exit);
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/arm/sa11xx-uda1341.c linux-2.6.22/sound/.pc/alsa-20070818.patch/arm/sa11xx-uda1341.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/arm/sa11xx-uda1341.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/arm/sa11xx-uda1341.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,1012 @@
+/*
+ *  Driver for Philips UDA1341TS on Compaq iPAQ H3600 soundcard
+ *  Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License.
+ * 
+ * History:
+ *
+ * 2002-03-13   Tomas Kasparek  initial release - based on h3600-uda1341.c from OSS
+ * 2002-03-20   Tomas Kasparek  playback over ALSA is working
+ * 2002-03-28   Tomas Kasparek  playback over OSS emulation is working
+ * 2002-03-29   Tomas Kasparek  basic capture is working (native ALSA)
+ * 2002-03-29   Tomas Kasparek  capture is working (OSS emulation)
+ * 2002-04-04   Tomas Kasparek  better rates handling (allow non-standard rates)
+ * 2003-02-14   Brian Avery     fixed full duplex mode, other updates
+ * 2003-02-20   Tomas Kasparek  merged updates by Brian (except HAL)
+ * 2003-04-19   Jaroslav Kysela recoded DMA stuff to follow 2.4.18rmk3-hh24 kernel
+ *                              working suspend and resume
+ * 2003-04-28   Tomas Kasparek  updated work by Jaroslav to compile it under 2.5.x again
+ *                              merged HAL layer (patches from Brian)
+ */
+
+/* $Id: sa11xx-uda1341.c,v 1.27 2005/12/07 09:13:42 cladisch Exp $ */
+
+/***************************************************************************************************
+*
+* To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai
+* available in the Alsa doc section on the website		
+* 
+* A few notes to make things clearer. The UDA1341 is hooked up to Serial port 4 on the SA1100.
+* We are using  SSP mode to talk to the UDA1341. The UDA1341 bit & wordselect clocks are generated
+* by this UART. Unfortunately, the clock only runs if the transmit buffer has something in it.
+* So, if we are just recording, we feed the transmit DMA stream a bunch of 0x0000 so that the
+* transmit buffer is full and the clock keeps going. The zeroes come from FLUSH_BASE_PHYS which
+* is a mem loc that always decodes to 0's w/ no off chip access.
+*
+* Some alsa terminology:
+*	frame => num_channels * sample_size  e.g stereo 16 bit is 2 * 16 = 32 bytes
+*	period => the least number of bytes that will generate an interrupt e.g. we have a 1024 byte
+*             buffer and 4 periods in the runtime structure this means we'll get an int every 256
+*             bytes or 4 times per buffer.
+*             A number of the sizes are in frames rather than bytes, use frames_to_bytes and
+*             bytes_to_frames to convert.  The easiest way to tell the units is to look at the
+*             type i.e. runtime-> buffer_size is in frames and its type is snd_pcm_uframes_t
+*             
+*	Notes about the pointer fxn:
+*	The pointer fxn needs to return the offset into the dma buffer in frames.
+*	Interrupts must be blocked before calling the dma_get_pos fxn to avoid race with interrupts.
+*
+*	Notes about pause/resume
+*	Implementing this would be complicated so it's skipped.  The problem case is:
+*	A full duplex connection is going, then play is paused. At this point you need to start xmitting
+*	0's to keep the record active which means you cant just freeze the dma and resume it later you'd
+*	need to	save off the dma info, and restore it properly on a resume.  Yeach!
+*
+*	Notes about transfer methods:
+*	The async write calls fail.  I probably need to implement something else to support them?
+* 
+***************************************************************************************************/
+
+#include <sound/driver.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <asm/hardware.h>
+#include <asm/arch/h3600.h>
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+
+#ifdef CONFIG_H3600_HAL
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <asm/arch/h3600_hal.h>
+#endif
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include <linux/l3/l3.h>
+
+#undef DEBUG_MODE
+#undef DEBUG_FUNCTION_NAMES
+#include <sound/uda1341.h>
+
+/*
+ * FIXME: Is this enough as autodetection of 2.4.X-rmkY-hhZ kernels?
+ * We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this
+ * module for Familiar 0.6.1
+ */
+#ifdef CONFIG_H3600_HAL
+#define HH_VERSION 1
+#endif
+
+/* {{{ Type definitions */
+
+MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA");
+MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}");
+
+static char *id;	/* ID for this card */
+
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
+
+struct audio_stream {
+	char *id;		/* identification string */
+	int stream_id;		/* numeric identification */	
+	dma_device_t dma_dev;	/* device identifier for DMA */
+#ifdef HH_VERSION
+	dmach_t dmach;		/* dma channel identification */
+#else
+	dma_regs_t *dma_regs;	/* points to our DMA registers */
+#endif
+	unsigned int active:1;	/* we are using this stream for transfer now */
+	int period;		/* current transfer period */
+	int periods;		/* current count of periods registerd in the DMA engine */
+	int tx_spin;		/* are we recoding - flag used to do DMA trans. for sync */
+	unsigned int old_offset;
+	spinlock_t dma_lock;	/* for locking in DMA operations (see dma-sa1100.c in the kernel) */
+	struct snd_pcm_substream *stream;
+};
+
+struct sa11xx_uda1341 {
+	struct snd_card *card;
+	struct l3_client *uda1341;
+	struct snd_pcm *pcm;
+	long samplerate;
+	struct audio_stream s[2];	/* playback & capture */
+};
+
+static unsigned int rates[] = {
+	8000,  10666, 10985, 14647,
+	16000, 21970, 22050, 24000,
+	29400, 32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+	.count	= ARRAY_SIZE(rates),
+	.list	= rates,
+	.mask	= 0,
+};
+
+static struct platform_device *device;
+
+/* }}} */
+
+/* {{{ Clock and sample rate stuff */
+
+/*
+ * Stop-gap solution until rest of hh.org HAL stuff is merged.
+ */
+#define GPIO_H3600_CLK_SET0		GPIO_GPIO (12)
+#define GPIO_H3600_CLK_SET1		GPIO_GPIO (13)
+
+#ifdef CONFIG_SA1100_H3XXX
+#define	clr_sa11xx_uda1341_egpio(x)	clr_h3600_egpio(x)
+#define set_sa11xx_uda1341_egpio(x)	set_h3600_egpio(x)
+#else
+#error This driver could serve H3x00 handhelds only!
+#endif
+
+static void sa11xx_uda1341_set_audio_clock(long val)
+{
+	switch (val) {
+	case 24000: case 32000: case 48000:	/* 00: 12.288 MHz */
+		GPCR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
+		break;
+
+	case 22050: case 29400: case 44100:	/* 01: 11.2896 MHz */
+		GPSR = GPIO_H3600_CLK_SET0;
+		GPCR = GPIO_H3600_CLK_SET1;
+		break;
+
+	case 8000: case 10666: case 16000:	/* 10: 4.096 MHz */
+		GPCR = GPIO_H3600_CLK_SET0;
+		GPSR = GPIO_H3600_CLK_SET1;
+		break;
+
+	case 10985: case 14647: case 21970:	/* 11: 5.6245 MHz */
+		GPSR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
+		break;
+	}
+}
+
+static void sa11xx_uda1341_set_samplerate(struct sa11xx_uda1341 *sa11xx_uda1341, long rate)
+{
+	int clk_div = 0;
+	int clk=0;
+
+	/* We don't want to mess with clocks when frames are in flight */
+	Ser4SSCR0 &= ~SSCR0_SSE;
+	/* wait for any frame to complete */
+	udelay(125);
+
+	/*
+	 * We have the following clock sources:
+	 * 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz
+	 * Those can be divided either by 256, 384 or 512.
+	 * This makes up 12 combinations for the following samplerates...
+	 */
+	if (rate >= 48000)
+		rate = 48000;
+	else if (rate >= 44100)
+		rate = 44100;
+	else if (rate >= 32000)
+		rate = 32000;
+	else if (rate >= 29400)
+		rate = 29400;
+	else if (rate >= 24000)
+		rate = 24000;
+	else if (rate >= 22050)
+		rate = 22050;
+	else if (rate >= 21970)
+		rate = 21970;
+	else if (rate >= 16000)
+		rate = 16000;
+	else if (rate >= 14647)
+		rate = 14647;
+	else if (rate >= 10985)
+		rate = 10985;
+	else if (rate >= 10666)
+		rate = 10666;
+	else
+		rate = 8000;
+
+	/* Set the external clock generator */
+#ifdef CONFIG_H3600_HAL
+	h3600_audio_clock(rate);
+#else	
+	sa11xx_uda1341_set_audio_clock(rate);
+#endif
+
+	/* Select the clock divisor */
+	switch (rate) {
+	case 8000:
+	case 10985:
+	case 22050:
+	case 24000:
+		clk = F512;
+		clk_div = SSCR0_SerClkDiv(16);
+		break;
+	case 16000:
+	case 21970:
+	case 44100:
+	case 48000:
+		clk = F256;
+		clk_div = SSCR0_SerClkDiv(8);
+		break;
+	case 10666:
+	case 14647:
+	case 29400:
+	case 32000:
+		clk = F384;
+		clk_div = SSCR0_SerClkDiv(12);
+		break;
+	}
+
+	/* FMT setting should be moved away when other FMTs are added (FIXME) */
+	l3_command(sa11xx_uda1341->uda1341, CMD_FORMAT, (void *)LSB16);
+	
+	l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk);        
+	Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
+	sa11xx_uda1341->samplerate = rate;
+}
+
+/* }}} */
+
+/* {{{ HW init and shutdown */
+
+static void sa11xx_uda1341_audio_init(struct sa11xx_uda1341 *sa11xx_uda1341)
+{
+	unsigned long flags;
+
+	/* Setup DMA stuff */
+	sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].id = "UDA1341 out";
+	sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK;
+	sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev = DMA_Ser4SSPWr;
+
+	sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].id = "UDA1341 in";
+	sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE;
+	sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev = DMA_Ser4SSPRd;
+
+	/* Initialize the UDA1341 internal state */
+       
+	/* Setup the uarts */
+	local_irq_save(flags);
+	GAFR |= (GPIO_SSP_CLK);
+	GPDR &= ~(GPIO_SSP_CLK);
+	Ser4SSCR0 = 0;
+	Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
+	Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
+	Ser4SSCR0 |= SSCR0_SSE;
+	local_irq_restore(flags);
+
+	/* Enable the audio power */
+#ifdef CONFIG_H3600_HAL
+	h3600_audio_power(AUDIO_RATE_DEFAULT);
+#else
+	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
+	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
+	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
+#endif
+ 
+	/* Wait for the UDA1341 to wake up */
+	mdelay(1); //FIXME - was removed by Perex - Why?
+
+	/* Initialize the UDA1341 internal state */
+	l3_open(sa11xx_uda1341->uda1341);
+	
+	/* external clock configuration (after l3_open - regs must be initialized */
+	sa11xx_uda1341_set_samplerate(sa11xx_uda1341, sa11xx_uda1341->samplerate);
+
+	/* Wait for the UDA1341 to wake up */
+	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
+	mdelay(1);	
+
+	/* make the left and right channels unswapped (flip the WS latch) */
+	Ser4SSDR = 0;
+
+#ifdef CONFIG_H3600_HAL
+	h3600_audio_mute(0);
+#else	
+	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);        
+#endif     
+}
+
+static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341)
+{
+	/* mute on */
+#ifdef CONFIG_H3600_HAL
+	h3600_audio_mute(1);
+#else	
+	set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
+#endif
+	
+	/* disable the audio power and all signals leading to the audio chip */
+	l3_close(sa11xx_uda1341->uda1341);
+	Ser4SSCR0 = 0;
+	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
+
+	/* power off and mute off */
+	/* FIXME - is muting off necesary??? */
+#ifdef CONFIG_H3600_HAL
+	h3600_audio_power(0);
+	h3600_audio_mute(0);
+#else	
+	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
+	clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
+#endif	
+}
+
+/* }}} */
+
+/* {{{ DMA staff */
+
+/*
+ * these are the address and sizes used to fill the xmit buffer
+ * so we can get a clock in record only mode
+ */
+#define FORCE_CLOCK_ADDR		(dma_addr_t)FLUSH_BASE_PHYS
+#define FORCE_CLOCK_SIZE		4096 // was 2048
+
+// FIXME Why this value exactly - wrote comment
+#define DMA_BUF_SIZE	8176	/* <= MAX_DMA_SIZE from asm/arch-sa1100/dma.h */
+
+#ifdef HH_VERSION
+
+static int audio_dma_request(struct audio_stream *s, void (*callback)(void *, int))
+{
+	int ret;
+
+	ret = sa1100_request_dma(&s->dmach, s->id, s->dma_dev);
+	if (ret < 0) {
+		printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
+		return ret;
+	}
+	sa1100_dma_set_callback(s->dmach, callback);
+	return 0;
+}
+
+static inline void audio_dma_free(struct audio_stream *s)
+{
+	sa1100_free_dma(s->dmach);
+	s->dmach = -1;
+}
+
+#else
+
+static int audio_dma_request(struct audio_stream *s, void (*callback)(void *))
+{
+	int ret;
+
+	ret = sa1100_request_dma(s->dma_dev, s->id, callback, s, &s->dma_regs);
+	if (ret < 0)
+		printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
+	return ret;
+}
+
+static void audio_dma_free(struct audio_stream *s)
+{
+	sa1100_free_dma(s->dma_regs);
+	s->dma_regs = 0;
+}
+
+#endif
+
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+	struct snd_pcm_substream *substream = s->stream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int offset;
+	unsigned long flags;
+	dma_addr_t addr;
+	
+	// this must be called w/ interrupts locked out see dma-sa1100.c in the kernel
+	spin_lock_irqsave(&s->dma_lock, flags);
+#ifdef HH_VERSION	
+	sa1100_dma_get_current(s->dmach, NULL, &addr);
+#else
+	addr = sa1100_get_dma_pos((s)->dma_regs);
+#endif
+	offset = addr - runtime->dma_addr;
+	spin_unlock_irqrestore(&s->dma_lock, flags);
+	
+	offset = bytes_to_frames(runtime,offset);
+	if (offset >= runtime->buffer_size)
+		offset = 0;
+
+	return offset;
+}
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->dma_lock, flags);	
+	s->active = 0;
+	s->period = 0;
+	/* this stops the dma channel and clears the buffer ptrs */
+#ifdef HH_VERSION
+	sa1100_dma_flush_all(s->dmach);
+#else
+	sa1100_clear_dma(s->dma_regs);	
+#endif
+	spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+static void audio_process_dma(struct audio_stream *s)
+{
+	struct snd_pcm_substream *substream = s->stream;
+	struct snd_pcm_runtime *runtime;
+	unsigned int dma_size;		
+	unsigned int offset;
+	int ret;
+                
+	/* we are requested to process synchronization DMA transfer */
+	if (s->tx_spin) {
+		snd_assert(s->stream_id == SNDRV_PCM_STREAM_PLAYBACK, return);
+		/* fill the xmit dma buffers and return */
+#ifdef HH_VERSION
+		sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
+#else
+		while (1) {
+			ret = sa1100_start_dma(s->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
+			if (ret)
+				return;   
+		}
+#endif
+		return;
+	}
+
+	/* must be set here - only valid for running streams, not for forced_clock dma fills  */
+	runtime = substream->runtime;
+	while (s->active && s->periods < runtime->periods) {
+		dma_size = frames_to_bytes(runtime, runtime->period_size);
+		if (s->old_offset) {
+			/* a little trick, we need resume from old position */
+			offset = frames_to_bytes(runtime, s->old_offset - 1);
+			s->old_offset = 0;
+			s->periods = 0;
+			s->period = offset / dma_size;
+			offset %= dma_size;
+			dma_size = dma_size - offset;
+			if (!dma_size)
+				continue;		/* special case */
+		} else {
+			offset = dma_size * s->period;
+			snd_assert(dma_size <= DMA_BUF_SIZE, );
+		}
+#ifdef HH_VERSION
+		ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);
+		if (ret)
+			return; //FIXME
+#else
+		ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);
+		if (ret) {
+			printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);
+			return;
+		}
+#endif
+
+		s->period++;
+		s->period %= runtime->periods;
+		s->periods++;
+	}
+}
+
+#ifdef HH_VERSION
+static void audio_dma_callback(void *data, int size)
+#else
+static void audio_dma_callback(void *data)
+#endif
+{
+	struct audio_stream *s = data;
+        
+	/* 
+	 * If we are getting a callback for an active stream then we inform
+	 * the PCM middle layer we've finished a period
+	 */
+ 	if (s->active)
+		snd_pcm_period_elapsed(s->stream);
+
+	spin_lock(&s->dma_lock);
+	if (!s->tx_spin && s->periods > 0)
+		s->periods--;
+	audio_process_dma(s);
+	spin_unlock(&s->dma_lock);
+}
+
+/* }}} */
+
+/* {{{ PCM setting */
+
+/* {{{ trigger & timer */
+
+static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
+	int stream_id = substream->pstr->stream;
+	struct audio_stream *s = &chip->s[stream_id];
+	struct audio_stream *s1 = &chip->s[stream_id ^ 1];
+	int err = 0;
+
+	/* note local interrupts are already disabled in the midlevel code */
+	spin_lock(&s->dma_lock);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		/* now we need to make sure a record only stream has a clock */
+		if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
+			/* we need to force fill the xmit DMA with zeros */
+			s1->tx_spin = 1;
+			audio_process_dma(s1);
+		}
+		/* this case is when you were recording then you turn on a
+		 * playback stream so we stop (also clears it) the dma first,
+		 * clear the sync flag and then we let it turned on
+		 */		
+		else {
+ 			s->tx_spin = 0;
+ 		}
+
+		/* requested stream startup */
+		s->active = 1;
+		audio_process_dma(s);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		/* requested stream shutdown */
+		audio_stop_dma(s);
+		
+		/*
+		 * now we need to make sure a record only stream has a clock
+		 * so if we're stopping a playback with an active capture
+		 * we need to turn the 0 fill dma on for the xmit side
+		 */
+		if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) {
+			/* we need to force fill the xmit DMA with zeros */
+			s->tx_spin = 1;
+			audio_process_dma(s);
+		}
+		/*
+		 * we killed a capture only stream, so we should also kill
+		 * the zero fill transmit
+		 */
+		else {
+			if (s1->tx_spin) {
+				s1->tx_spin = 0;
+				audio_stop_dma(s1);
+			}
+		}
+		
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		s->active = 0;
+#ifdef HH_VERSION		
+		sa1100_dma_stop(s->dmach);
+#else
+		//FIXME - DMA API
+#endif		
+		s->old_offset = audio_get_dma_pos(s) + 1;
+#ifdef HH_VERSION		
+		sa1100_dma_flush_all(s->dmach);
+#else
+		//FIXME - DMA API
+#endif		
+		s->periods = 0;
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+		s->active = 1;
+		s->tx_spin = 0;
+		audio_process_dma(s);
+		if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
+			s1->tx_spin = 1;
+			audio_process_dma(s1);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+#ifdef HH_VERSION		
+		sa1100_dma_stop(s->dmach);
+#else
+		//FIXME - DMA API
+#endif
+		s->active = 0;
+		if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+			if (s1->active) {
+				s->tx_spin = 1;
+				s->old_offset = audio_get_dma_pos(s) + 1;
+#ifdef HH_VERSION				
+				sa1100_dma_flush_all(s->dmach);
+#else
+				//FIXME - DMA API
+#endif				
+				audio_process_dma(s);
+			}
+		} else {
+			if (s1->tx_spin) {
+				s1->tx_spin = 0;
+#ifdef HH_VERSION				
+				sa1100_dma_flush_all(s1->dmach);
+#else
+				//FIXME - DMA API
+#endif				
+			}
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		s->active = 1;
+		if (s->old_offset) {
+			s->tx_spin = 0;
+			audio_process_dma(s);
+			break;
+		}
+		if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
+			s1->tx_spin = 1;
+			audio_process_dma(s1);
+		}
+#ifdef HH_VERSION		
+		sa1100_dma_resume(s->dmach);
+#else
+		//FIXME - DMA API
+#endif
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	spin_unlock(&s->dma_lock);	
+	return err;
+}
+
+static int snd_sa11xx_uda1341_prepare(struct snd_pcm_substream *substream)
+{
+	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct audio_stream *s = &chip->s[substream->pstr->stream];
+        
+	/* set requested samplerate */
+	sa11xx_uda1341_set_samplerate(chip, runtime->rate);
+
+	/* set requestd format when available */
+	/* set FMT here !!! FIXME */
+
+	s->period = 0;
+	s->periods = 0;
+        
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(struct snd_pcm_substream *substream)
+{
+	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
+	return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+/* }}} */
+
+static struct snd_pcm_hardware snd_sa11xx_uda1341_capture =
+{
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+				   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
+				   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+				   SNDRV_PCM_RATE_KNOT),
+	.rate_min		= 8000,
+	.rate_max		= 48000,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 64*1024,
+	.period_bytes_min	= 64,
+	.period_bytes_max	= DMA_BUF_SIZE,
+	.periods_min		= 2,
+	.periods_max		= 255,
+	.fifo_size		= 0,
+};
+
+static struct snd_pcm_hardware snd_sa11xx_uda1341_playback =
+{
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                                   SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
+				   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+				   SNDRV_PCM_RATE_KNOT),
+	.rate_min		= 8000,
+	.rate_max		= 48000,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 64*1024,
+	.period_bytes_min	= 64,
+	.period_bytes_max	= DMA_BUF_SIZE,
+	.periods_min		= 2,
+	.periods_max		= 255,
+	.fifo_size		= 0,
+};
+
+static int snd_card_sa11xx_uda1341_open(struct snd_pcm_substream *substream)
+{
+	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int stream_id = substream->pstr->stream;
+	int err;
+
+	chip->s[stream_id].stream = substream;
+
+	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+		runtime->hw = snd_sa11xx_uda1341_playback;
+	else
+		runtime->hw = snd_sa11xx_uda1341_capture;
+	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)
+		return err;
+        
+	return 0;
+}
+
+static int snd_card_sa11xx_uda1341_close(struct snd_pcm_substream *substream)
+{
+	struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
+
+	chip->s[substream->pstr->stream].stream = NULL;
+	return 0;
+}
+
+/* {{{ HW params & free */
+
+static int snd_sa11xx_uda1341_hw_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *hw_params)
+{
+        
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+static int snd_sa11xx_uda1341_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/* }}} */
+
+static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops = {
+	.open			= snd_card_sa11xx_uda1341_open,
+	.close			= snd_card_sa11xx_uda1341_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params	        = snd_sa11xx_uda1341_hw_params,
+	.hw_free	        = snd_sa11xx_uda1341_hw_free,
+	.prepare		= snd_sa11xx_uda1341_prepare,
+	.trigger		= snd_sa11xx_uda1341_trigger,
+	.pointer		= snd_sa11xx_uda1341_pointer,
+};
+
+static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops = {
+	.open			= snd_card_sa11xx_uda1341_open,
+	.close			= snd_card_sa11xx_uda1341_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params	        = snd_sa11xx_uda1341_hw_params,
+	.hw_free	        = snd_sa11xx_uda1341_hw_free,
+	.prepare		= snd_sa11xx_uda1341_prepare,
+	.trigger		= snd_sa11xx_uda1341_trigger,
+	.pointer		= snd_sa11xx_uda1341_pointer,
+};
+
+static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0)
+		return err;
+
+	/*
+	 * this sets up our initial buffers and sets the dma_type to isa.
+	 * isa works but I'm not sure why (or if) it's the right choice
+	 * this may be too large, trying it for now
+	 */
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 
+					      snd_dma_isa_data(),
+					      64*1024, 64*1024);
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
+	pcm->private_data = sa11xx_uda1341;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "UDA1341 PCM");
+
+	sa11xx_uda1341_audio_init(sa11xx_uda1341);
+
+	/* setup DMA controller */
+	audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback);
+	audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback);
+
+	sa11xx_uda1341->pcm = pcm;
+
+	return 0;
+}
+
+/* }}} */
+
+/* {{{ module init & exit */
+
+#ifdef CONFIG_PM
+
+static int snd_sa11xx_uda1341_suspend(struct platform_device *devptr,
+				      pm_message_t state)
+{
+	struct snd_card *card = platform_get_drvdata(devptr);
+	struct sa11xx_uda1341 *chip = card->private_data;
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	snd_pcm_suspend_all(chip->pcm);
+#ifdef HH_VERSION
+	sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
+	sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
+#else
+	//FIXME
+#endif
+	l3_command(chip->uda1341, CMD_SUSPEND, NULL);
+	sa11xx_uda1341_audio_shutdown(chip);
+
+	return 0;
+}
+
+static int snd_sa11xx_uda1341_resume(struct platform_device *devptr)
+{
+	struct snd_card *card = platform_get_drvdata(devptr);
+	struct sa11xx_uda1341 *chip = card->private_data;
+
+	sa11xx_uda1341_audio_init(chip);
+	l3_command(chip->uda1341, CMD_RESUME, NULL);
+#ifdef HH_VERSION	
+	sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
+	sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
+#else
+	//FIXME
+#endif
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	return 0;
+}
+#endif /* COMFIG_PM */
+
+void snd_sa11xx_uda1341_free(struct snd_card *card)
+{
+	struct sa11xx_uda1341 *chip = card->private_data;
+
+	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+	audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+static int __init sa11xx_uda1341_probe(struct platform_device *devptr)
+{
+	int err;
+	struct snd_card *card;
+	struct sa11xx_uda1341 *chip;
+
+	/* register the soundcard */
+	card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct sa11xx_uda1341));
+	if (card == NULL)
+		return -ENOMEM;
+
+	chip = card->private_data;
+	spin_lock_init(&chip->s[0].dma_lock);
+	spin_lock_init(&chip->s[1].dma_lock);
+
+	card->private_free = snd_sa11xx_uda1341_free;
+	chip->card = card;
+	chip->samplerate = AUDIO_RATE_DEFAULT;
+
+	// mixer
+	if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341)))
+		goto nodev;
+
+	// PCM
+	if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0)
+		goto nodev;
+        
+	strcpy(card->driver, "UDA1341");
+	strcpy(card->shortname, "H3600 UDA1341TS");
+	sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");
+        
+	snd_card_set_dev(card, &devptr->dev);
+
+	if ((err = snd_card_register(card)) == 0) {
+		printk( KERN_INFO "iPAQ audio support initialized\n" );
+		platform_set_drvdata(devptr, card);
+		return 0;
+	}
+        
+ nodev:
+	snd_card_free(card);
+	return err;
+}
+
+static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr)
+{
+	snd_card_free(platform_get_drvdata(devptr));
+	platform_set_drvdata(devptr, NULL);
+	return 0;
+}
+
+#define SA11XX_UDA1341_DRIVER	"sa11xx_uda1341"
+
+static struct platform_driver sa11xx_uda1341_driver = {
+	.probe		= sa11xx_uda1341_probe,
+	.remove		= __devexit_p(sa11xx_uda1341_remove),
+#ifdef CONFIG_PM
+	.suspend	= snd_sa11xx_uda1341_suspend,
+	.resume		= snd_sa11xx_uda1341_resume,
+#endif
+	.driver		= {
+		.name	= SA11XX_UDA1341_DRIVER,
+	},
+};
+
+static int __init sa11xx_uda1341_init(void)
+{
+	int err;
+
+	if (!machine_is_h3xxx())
+		return -ENODEV;
+	if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)
+		return err;
+	device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);
+	if (!IS_ERR(device)) {
+		if (platform_get_drvdata(device))
+			return 0;
+		platform_device_unregister(device);
+		err = -ENODEV;
+	} else
+		err = PTR_ERR(device);
+	platform_driver_unregister(&sa11xx_uda1341_driver);
+	return err;
+}
+
+static void __exit sa11xx_uda1341_exit(void)
+{
+	platform_device_unregister(device);
+	platform_driver_unregister(&sa11xx_uda1341_driver);
+}
+
+module_init(sa11xx_uda1341_init);
+module_exit(sa11xx_uda1341_exit);
+
+/* }}} */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: t
+ * End:
+ */
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/Makefile linux-2.6.22/sound/.pc/alsa-20070818.patch/core/Makefile
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/core/Makefile	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,32 @@
+#
+# Makefile for ALSA
+# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-objs     := sound.o init.o memory.o info.o control.o misc.o device.o
+ifeq ($(CONFIG_ISA_DMA_API),y)
+snd-objs     += isadma.o
+endif
+ifeq ($(CONFIG_SND_OSSEMUL),y)
+snd-objs     += sound_oss.o info_oss.o
+endif
+
+snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
+		pcm_memory.o
+
+snd-page-alloc-objs := memalloc.o sgbuf.o
+
+snd-rawmidi-objs  := rawmidi.o
+snd-timer-objs    := timer.o
+snd-rtctimer-objs := rtctimer.o
+snd-hwdep-objs    := hwdep.o
+
+obj-$(CONFIG_SND) 		+= snd.o
+obj-$(CONFIG_SND_HWDEP)		+= snd-hwdep.o
+obj-$(CONFIG_SND_TIMER)		+= snd-timer.o
+obj-$(CONFIG_SND_RTCTIMER)	+= snd-rtctimer.o
+obj-$(CONFIG_SND_PCM)		+= snd-pcm.o snd-page-alloc.o
+obj-$(CONFIG_SND_RAWMIDI)	+= snd-rawmidi.o
+
+obj-$(CONFIG_SND_OSSEMUL)	+= oss/
+obj-$(CONFIG_SND_SEQUENCER)	+= seq/
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/control.c linux-2.6.22/sound/.pc/alsa-20070818.patch/core/control.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/control.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/core/control.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,1488 @@
+/*
+ *  Routines for driver control interface
+ *  Copyright (c) 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 <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/minors.h>
+#include <sound/info.h>
+#include <sound/control.h>
+
+/* max number of user-defined controls */
+#define MAX_USER_CONTROLS	32
+
+struct snd_kctl_ioctl {
+	struct list_head list;		/* list of all ioctls */
+	snd_kctl_ioctl_func_t fioctl;
+};
+
+static DECLARE_RWSEM(snd_ioctl_rwsem);
+static LIST_HEAD(snd_control_ioctls);
+#ifdef CONFIG_COMPAT
+static LIST_HEAD(snd_control_compat_ioctls);
+#endif
+
+static int snd_ctl_open(struct inode *inode, struct file *file)
+{
+	unsigned long flags;
+	struct snd_card *card;
+	struct snd_ctl_file *ctl;
+	int err;
+
+	card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
+	if (!card) {
+		err = -ENODEV;
+		goto __error1;
+	}
+	err = snd_card_file_add(card, file);
+	if (err < 0) {
+		err = -ENODEV;
+		goto __error1;
+	}
+	if (!try_module_get(card->module)) {
+		err = -EFAULT;
+		goto __error2;
+	}
+	ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
+	if (ctl == NULL) {
+		err = -ENOMEM;
+		goto __error;
+	}
+	INIT_LIST_HEAD(&ctl->events);
+	init_waitqueue_head(&ctl->change_sleep);
+	spin_lock_init(&ctl->read_lock);
+	ctl->card = card;
+	ctl->prefer_pcm_subdevice = -1;
+	ctl->prefer_rawmidi_subdevice = -1;
+	ctl->pid = current->pid;
+	file->private_data = ctl;
+	write_lock_irqsave(&card->ctl_files_rwlock, flags);
+	list_add_tail(&ctl->list, &card->ctl_files);
+	write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
+	return 0;
+
+      __error:
+	module_put(card->module);
+      __error2:
+	snd_card_file_remove(card, file);
+      __error1:
+      	return err;
+}
+
+static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
+{
+	struct snd_kctl_event *cread;
+	
+	spin_lock(&ctl->read_lock);
+	while (!list_empty(&ctl->events)) {
+		cread = snd_kctl_event(ctl->events.next);
+		list_del(&cread->list);
+		kfree(cread);
+	}
+	spin_unlock(&ctl->read_lock);
+}
+
+static int snd_ctl_release(struct inode *inode, struct file *file)
+{
+	unsigned long flags;
+	struct snd_card *card;
+	struct snd_ctl_file *ctl;
+	struct snd_kcontrol *control;
+	unsigned int idx;
+
+	ctl = file->private_data;
+	fasync_helper(-1, file, 0, &ctl->fasync);
+	file->private_data = NULL;
+	card = ctl->card;
+	write_lock_irqsave(&card->ctl_files_rwlock, flags);
+	list_del(&ctl->list);
+	write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
+	down_write(&card->controls_rwsem);
+	list_for_each_entry(control, &card->controls, list)
+		for (idx = 0; idx < control->count; idx++)
+			if (control->vd[idx].owner == ctl)
+				control->vd[idx].owner = NULL;
+	up_write(&card->controls_rwsem);
+	snd_ctl_empty_read_queue(ctl);
+	kfree(ctl);
+	module_put(card->module);
+	snd_card_file_remove(card, file);
+	return 0;
+}
+
+void snd_ctl_notify(struct snd_card *card, unsigned int mask,
+		    struct snd_ctl_elem_id *id)
+{
+	unsigned long flags;
+	struct snd_ctl_file *ctl;
+	struct snd_kctl_event *ev;
+	
+	snd_assert(card != NULL && id != NULL, return);
+	read_lock(&card->ctl_files_rwlock);
+#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+	card->mixer_oss_change_count++;
+#endif
+	list_for_each_entry(ctl, &card->ctl_files, list) {
+		if (!ctl->subscribed)
+			continue;
+		spin_lock_irqsave(&ctl->read_lock, flags);
+		list_for_each_entry(ev, &ctl->events, list) {
+			if (ev->id.numid == id->numid) {
+				ev->mask |= mask;
+				goto _found;
+			}
+		}
+		ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+		if (ev) {
+			ev->id = *id;
+			ev->mask = mask;
+			list_add_tail(&ev->list, &ctl->events);
+		} else {
+			snd_printk(KERN_ERR "No memory available to allocate event\n");
+		}
+	_found:
+		wake_up(&ctl->change_sleep);
+		spin_unlock_irqrestore(&ctl->read_lock, flags);
+		kill_fasync(&ctl->fasync, SIGIO, POLL_IN);
+	}
+	read_unlock(&card->ctl_files_rwlock);
+}
+
+EXPORT_SYMBOL(snd_ctl_notify);
+
+/**
+ * snd_ctl_new - create a control instance from the template
+ * @control: the control template
+ * @access: the default control access
+ *
+ * Allocates a new struct snd_kcontrol instance and copies the given template 
+ * to the new instance. It does not copy volatile data (access).
+ *
+ * Returns the pointer of the new instance, or NULL on failure.
+ */
+static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
+					unsigned int access)
+{
+	struct snd_kcontrol *kctl;
+	unsigned int idx;
+	
+	snd_assert(control != NULL, return NULL);
+	snd_assert(control->count > 0, return NULL);
+	kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
+	if (kctl == NULL) {
+		snd_printk(KERN_ERR "Cannot allocate control instance\n");
+		return NULL;
+	}
+	*kctl = *control;
+	for (idx = 0; idx < kctl->count; idx++)
+		kctl->vd[idx].access = access;
+	return kctl;
+}
+
+/**
+ * snd_ctl_new1 - create a control instance from the template
+ * @ncontrol: the initialization record
+ * @private_data: the private data to set
+ *
+ * Allocates a new struct snd_kcontrol instance and initialize from the given 
+ * template.  When the access field of ncontrol is 0, it's assumed as
+ * READWRITE access. When the count field is 0, it's assumes as one.
+ *
+ * Returns the pointer of the newly generated instance, or NULL on failure.
+ */
+struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
+				  void *private_data)
+{
+	struct snd_kcontrol kctl;
+	unsigned int access;
+	
+	snd_assert(ncontrol != NULL, return NULL);
+	snd_assert(ncontrol->info != NULL, return NULL);
+	memset(&kctl, 0, sizeof(kctl));
+	kctl.id.iface = ncontrol->iface;
+	kctl.id.device = ncontrol->device;
+	kctl.id.subdevice = ncontrol->subdevice;
+	if (ncontrol->name)
+		strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
+	kctl.id.index = ncontrol->index;
+	kctl.count = ncontrol->count ? ncontrol->count : 1;
+	access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
+		 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+				      SNDRV_CTL_ELEM_ACCESS_INACTIVE|
+		 		      SNDRV_CTL_ELEM_ACCESS_DINDIRECT|
+		 		      SNDRV_CTL_ELEM_ACCESS_INDIRECT|
+		 		      SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
+		 		      SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
+	kctl.info = ncontrol->info;
+	kctl.get = ncontrol->get;
+	kctl.put = ncontrol->put;
+	kctl.tlv.p = ncontrol->tlv.p;
+	kctl.private_value = ncontrol->private_value;
+	kctl.private_data = private_data;
+	return snd_ctl_new(&kctl, access);
+}
+
+EXPORT_SYMBOL(snd_ctl_new1);
+
+/**
+ * snd_ctl_free_one - release the control instance
+ * @kcontrol: the control instance
+ *
+ * Releases the control instance created via snd_ctl_new()
+ * or snd_ctl_new1().
+ * Don't call this after the control was added to the card.
+ */
+void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
+{
+	if (kcontrol) {
+		if (kcontrol->private_free)
+			kcontrol->private_free(kcontrol);
+		kfree(kcontrol);
+	}
+}
+
+EXPORT_SYMBOL(snd_ctl_free_one);
+
+static unsigned int snd_ctl_hole_check(struct snd_card *card,
+				       unsigned int count)
+{
+	struct snd_kcontrol *kctl;
+
+	list_for_each_entry(kctl, &card->controls, list) {
+		if ((kctl->id.numid <= card->last_numid &&
+		     kctl->id.numid + kctl->count > card->last_numid) ||
+		    (kctl->id.numid <= card->last_numid + count - 1 &&
+		     kctl->id.numid + kctl->count > card->last_numid + count - 1))
+		    	return card->last_numid = kctl->id.numid + kctl->count - 1;
+	}
+	return card->last_numid;
+}
+
+static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
+{
+	unsigned int last_numid, iter = 100000;
+
+	last_numid = card->last_numid;
+	while (last_numid != snd_ctl_hole_check(card, count)) {
+		if (--iter == 0) {
+			/* this situation is very unlikely */
+			snd_printk(KERN_ERR "unable to allocate new control numid\n");
+			return -ENOMEM;
+		}
+		last_numid = card->last_numid;
+	}
+	return 0;
+}
+
+/**
+ * snd_ctl_add - add the control instance to the card
+ * @card: the card instance
+ * @kcontrol: the control instance to add
+ *
+ * Adds the control instance created via snd_ctl_new() or
+ * snd_ctl_new1() to the given card. Assigns also an unique
+ * numid used for fast search.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ *
+ * It frees automatically the control which cannot be added.
+ */
+int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
+{
+	struct snd_ctl_elem_id id;
+	unsigned int idx;
+	int err = -EINVAL;
+
+	if (! kcontrol)
+		return err;
+	snd_assert(card != NULL, goto error);
+	snd_assert(kcontrol->info != NULL, goto error);
+	id = kcontrol->id;
+	down_write(&card->controls_rwsem);
+	if (snd_ctl_find_id(card, &id)) {
+		up_write(&card->controls_rwsem);
+		snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
+					id.iface,
+					id.device,
+					id.subdevice,
+					id.name,
+					id.index);
+		err = -EBUSY;
+		goto error;
+	}
+	if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
+		up_write(&card->controls_rwsem);
+		err = -ENOMEM;
+		goto error;
+	}
+	list_add_tail(&kcontrol->list, &card->controls);
+	card->controls_count += kcontrol->count;
+	kcontrol->id.numid = card->last_numid + 1;
+	card->last_numid += kcontrol->count;
+	up_write(&card->controls_rwsem);
+	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
+	return 0;
+
+ error:
+	snd_ctl_free_one(kcontrol);
+	return err;
+}
+
+EXPORT_SYMBOL(snd_ctl_add);
+
+/**
+ * snd_ctl_remove - remove the control from the card and release it
+ * @card: the card instance
+ * @kcontrol: the control instance to remove
+ *
+ * Removes the control from the card and then releases the instance.
+ * You don't need to call snd_ctl_free_one(). You must be in
+ * the write lock - down_write(&card->controls_rwsem).
+ * 
+ * Returns 0 if successful, or a negative error code on failure.
+ */
+int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
+{
+	struct snd_ctl_elem_id id;
+	unsigned int idx;
+
+	snd_assert(card != NULL && kcontrol != NULL, return -EINVAL);
+	list_del(&kcontrol->list);
+	card->controls_count -= kcontrol->count;
+	id = kcontrol->id;
+	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
+		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id);
+	snd_ctl_free_one(kcontrol);
+	return 0;
+}
+
+EXPORT_SYMBOL(snd_ctl_remove);
+
+/**
+ * snd_ctl_remove_id - remove the control of the given id and release it
+ * @card: the card instance
+ * @id: the control id to remove
+ *
+ * Finds the control instance with the given id, removes it from the
+ * card list and releases it.
+ * 
+ * Returns 0 if successful, or a negative error code on failure.
+ */
+int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
+{
+	struct snd_kcontrol *kctl;
+	int ret;
+
+	down_write(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, id);
+	if (kctl == NULL) {
+		up_write(&card->controls_rwsem);
+		return -ENOENT;
+	}
+	ret = snd_ctl_remove(card, kctl);
+	up_write(&card->controls_rwsem);
+	return ret;
+}
+
+EXPORT_SYMBOL(snd_ctl_remove_id);
+
+/**
+ * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it
+ * @file: active control handle
+ * @id: the control id to remove
+ *
+ * Finds the control instance with the given id, removes it from the
+ * card list and releases it.
+ * 
+ * Returns 0 if successful, or a negative error code on failure.
+ */
+static int snd_ctl_remove_unlocked_id(struct snd_ctl_file * file,
+				      struct snd_ctl_elem_id *id)
+{
+	struct snd_card *card = file->card;
+	struct snd_kcontrol *kctl;
+	int idx, ret;
+
+	down_write(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, id);
+	if (kctl == NULL) {
+		up_write(&card->controls_rwsem);
+		return -ENOENT;
+	}
+	for (idx = 0; idx < kctl->count; idx++)
+		if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
+			up_write(&card->controls_rwsem);
+			return -EBUSY;
+		}
+	ret = snd_ctl_remove(card, kctl);
+	up_write(&card->controls_rwsem);
+	return ret;
+}
+
+/**
+ * snd_ctl_rename_id - replace the id of a control on the card
+ * @card: the card instance
+ * @src_id: the old id
+ * @dst_id: the new id
+ *
+ * Finds the control with the old id from the card, and replaces the
+ * id with the new one.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ */
+int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
+		      struct snd_ctl_elem_id *dst_id)
+{
+	struct snd_kcontrol *kctl;
+
+	down_write(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, src_id);
+	if (kctl == NULL) {
+		up_write(&card->controls_rwsem);
+		return -ENOENT;
+	}
+	kctl->id = *dst_id;
+	kctl->id.numid = card->last_numid + 1;
+	card->last_numid += kctl->count;
+	up_write(&card->controls_rwsem);
+	return 0;
+}
+
+EXPORT_SYMBOL(snd_ctl_rename_id);
+
+/**
+ * snd_ctl_find_numid - find the control instance with the given number-id
+ * @card: the card instance
+ * @numid: the number-id to search
+ *
+ * Finds the control instance with the given number-id from the card.
+ *
+ * Returns the pointer of the instance if found, or NULL if not.
+ *
+ * The caller must down card->controls_rwsem before calling this function
+ * (if the race condition can happen).
+ */
+struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
+{
+	struct snd_kcontrol *kctl;
+
+	snd_assert(card != NULL && numid != 0, return NULL);
+	list_for_each_entry(kctl, &card->controls, list) {
+		if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
+			return kctl;
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(snd_ctl_find_numid);
+
+/**
+ * snd_ctl_find_id - find the control instance with the given id
+ * @card: the card instance
+ * @id: the id to search
+ *
+ * Finds the control instance with the given id from the card.
+ *
+ * Returns the pointer of the instance if found, or NULL if not.
+ *
+ * The caller must down card->controls_rwsem before calling this function
+ * (if the race condition can happen).
+ */
+struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
+				     struct snd_ctl_elem_id *id)
+{
+	struct snd_kcontrol *kctl;
+
+	snd_assert(card != NULL && id != NULL, return NULL);
+	if (id->numid != 0)
+		return snd_ctl_find_numid(card, id->numid);
+	list_for_each_entry(kctl, &card->controls, list) {
+		if (kctl->id.iface != id->iface)
+			continue;
+		if (kctl->id.device != id->device)
+			continue;
+		if (kctl->id.subdevice != id->subdevice)
+			continue;
+		if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)))
+			continue;
+		if (kctl->id.index > id->index)
+			continue;
+		if (kctl->id.index + kctl->count <= id->index)
+			continue;
+		return kctl;
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(snd_ctl_find_id);
+
+static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
+			     unsigned int cmd, void __user *arg)
+{
+	struct snd_ctl_card_info *info;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (! info)
+		return -ENOMEM;
+	down_read(&snd_ioctl_rwsem);
+	info->card = card->number;
+	strlcpy(info->id, card->id, sizeof(info->id));
+	strlcpy(info->driver, card->driver, sizeof(info->driver));
+	strlcpy(info->name, card->shortname, sizeof(info->name));
+	strlcpy(info->longname, card->longname, sizeof(info->longname));
+	strlcpy(info->mixername, card->mixername, sizeof(info->mixername));
+	strlcpy(info->components, card->components, sizeof(info->components));
+	up_read(&snd_ioctl_rwsem);
+	if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
+		kfree(info);
+		return -EFAULT;
+	}
+	kfree(info);
+	return 0;
+}
+
+static int snd_ctl_elem_list(struct snd_card *card,
+			     struct snd_ctl_elem_list __user *_list)
+{
+	struct list_head *plist;
+	struct snd_ctl_elem_list list;
+	struct snd_kcontrol *kctl;
+	struct snd_ctl_elem_id *dst, *id;
+	unsigned int offset, space, first, jidx;
+	
+	if (copy_from_user(&list, _list, sizeof(list)))
+		return -EFAULT;
+	offset = list.offset;
+	space = list.space;
+	first = 0;
+	/* try limit maximum space */
+	if (space > 16384)
+		return -ENOMEM;
+	if (space > 0) {
+		/* allocate temporary buffer for atomic operation */
+		dst = vmalloc(space * sizeof(struct snd_ctl_elem_id));
+		if (dst == NULL)
+			return -ENOMEM;
+		down_read(&card->controls_rwsem);
+		list.count = card->controls_count;
+		plist = card->controls.next;
+		while (plist != &card->controls) {
+			if (offset == 0)
+				break;
+			kctl = snd_kcontrol(plist);
+			if (offset < kctl->count)
+				break;
+			offset -= kctl->count;
+			plist = plist->next;
+		}
+		list.used = 0;
+		id = dst;
+		while (space > 0 && plist != &card->controls) {
+			kctl = snd_kcontrol(plist);
+			for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
+				snd_ctl_build_ioff(id, kctl, jidx);
+				id++;
+				space--;
+				list.used++;
+			}
+			plist = plist->next;
+			offset = 0;
+		}
+		up_read(&card->controls_rwsem);
+		if (list.used > 0 &&
+		    copy_to_user(list.pids, dst,
+				 list.used * sizeof(struct snd_ctl_elem_id))) {
+			vfree(dst);
+			return -EFAULT;
+		}
+		vfree(dst);
+	} else {
+		down_read(&card->controls_rwsem);
+		list.count = card->controls_count;
+		up_read(&card->controls_rwsem);
+	}
+	if (copy_to_user(_list, &list, sizeof(list)))
+		return -EFAULT;
+	return 0;
+}
+
+static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
+			     struct snd_ctl_elem_info *info)
+{
+	struct snd_card *card = ctl->card;
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_volatile *vd;
+	unsigned int index_offset;
+	int result;
+	
+	down_read(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, &info->id);
+	if (kctl == NULL) {
+		up_read(&card->controls_rwsem);
+		return -ENOENT;
+	}
+#ifdef CONFIG_SND_DEBUG
+	info->access = 0;
+#endif
+	result = kctl->info(kctl, info);
+	if (result >= 0) {
+		snd_assert(info->access == 0, );
+		index_offset = snd_ctl_get_ioff(kctl, &info->id);
+		vd = &kctl->vd[index_offset];
+		snd_ctl_build_ioff(&info->id, kctl, index_offset);
+		info->access = vd->access;
+		if (vd->owner) {
+			info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
+			if (vd->owner == ctl)
+				info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
+			info->owner = vd->owner_pid;
+		} else {
+			info->owner = -1;
+		}
+	}
+	up_read(&card->controls_rwsem);
+	return result;
+}
+
+static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
+				  struct snd_ctl_elem_info __user *_info)
+{
+	struct snd_ctl_elem_info info;
+	int result;
+
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	snd_power_lock(ctl->card);
+	result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
+	if (result >= 0)
+		result = snd_ctl_elem_info(ctl, &info);
+	snd_power_unlock(ctl->card);
+	if (result >= 0)
+		if (copy_to_user(_info, &info, sizeof(info)))
+			return -EFAULT;
+	return result;
+}
+
+int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control)
+{
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_volatile *vd;
+	unsigned int index_offset;
+	int result, indirect;
+
+	down_read(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, &control->id);
+	if (kctl == NULL) {
+		result = -ENOENT;
+	} else {
+		index_offset = snd_ctl_get_ioff(kctl, &control->id);
+		vd = &kctl->vd[index_offset];
+		indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
+		if (control->indirect != indirect) {
+			result = -EACCES;
+		} else {
+			if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {
+				snd_ctl_build_ioff(&control->id, kctl, index_offset);
+				result = kctl->get(kctl, control);
+			} else {
+				result = -EPERM;
+			}
+		}
+	}
+	up_read(&card->controls_rwsem);
+	return result;
+}
+
+EXPORT_SYMBOL(snd_ctl_elem_read);
+
+static int snd_ctl_elem_read_user(struct snd_card *card,
+				  struct snd_ctl_elem_value __user *_control)
+{
+	struct snd_ctl_elem_value *control;
+	int result;
+	
+	control = kmalloc(sizeof(*control), GFP_KERNEL);
+	if (control == NULL)
+		return -ENOMEM;	
+	if (copy_from_user(control, _control, sizeof(*control))) {
+		kfree(control);
+		return -EFAULT;
+	}
+	snd_power_lock(card);
+	result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+	if (result >= 0)
+		result = snd_ctl_elem_read(card, control);
+	snd_power_unlock(card);
+	if (result >= 0)
+		if (copy_to_user(_control, control, sizeof(*control)))
+			result = -EFAULT;
+	kfree(control);
+	return result;
+}
+
+int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
+		       struct snd_ctl_elem_value *control)
+{
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_volatile *vd;
+	unsigned int index_offset;
+	int result, indirect;
+
+	down_read(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, &control->id);
+	if (kctl == NULL) {
+		result = -ENOENT;
+	} else {
+		index_offset = snd_ctl_get_ioff(kctl, &control->id);
+		vd = &kctl->vd[index_offset];
+		indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
+		if (control->indirect != indirect) {
+			result = -EACCES;
+		} else {
+			if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
+			    kctl->put == NULL ||
+			    (file && vd->owner != NULL && vd->owner != file)) {
+				result = -EPERM;
+			} else {
+				snd_ctl_build_ioff(&control->id, kctl, index_offset);
+				result = kctl->put(kctl, control);
+			}
+			if (result > 0) {
+				up_read(&card->controls_rwsem);
+				snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &control->id);
+				return 0;
+			}
+		}
+	}
+	up_read(&card->controls_rwsem);
+	return result;
+}
+
+EXPORT_SYMBOL(snd_ctl_elem_write);
+
+static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
+				   struct snd_ctl_elem_value __user *_control)
+{
+	struct snd_ctl_elem_value *control;
+	struct snd_card *card;
+	int result;
+
+	control = kmalloc(sizeof(*control), GFP_KERNEL);
+	if (control == NULL)
+		return -ENOMEM;	
+	if (copy_from_user(control, _control, sizeof(*control))) {
+		kfree(control);
+		return -EFAULT;
+	}
+	card = file->card;
+	snd_power_lock(card);
+	result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+	if (result >= 0)
+		result = snd_ctl_elem_write(card, file, control);
+	snd_power_unlock(card);
+	if (result >= 0)
+		if (copy_to_user(_control, control, sizeof(*control)))
+			result = -EFAULT;
+	kfree(control);
+	return result;
+}
+
+static int snd_ctl_elem_lock(struct snd_ctl_file *file,
+			     struct snd_ctl_elem_id __user *_id)
+{
+	struct snd_card *card = file->card;
+	struct snd_ctl_elem_id id;
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_volatile *vd;
+	int result;
+	
+	if (copy_from_user(&id, _id, sizeof(id)))
+		return -EFAULT;
+	down_write(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, &id);
+	if (kctl == NULL) {
+		result = -ENOENT;
+	} else {
+		vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
+		if (vd->owner != NULL)
+			result = -EBUSY;
+		else {
+			vd->owner = file;
+			vd->owner_pid = current->pid;
+			result = 0;
+		}
+	}
+	up_write(&card->controls_rwsem);
+	return result;
+}
+
+static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
+			       struct snd_ctl_elem_id __user *_id)
+{
+	struct snd_card *card = file->card;
+	struct snd_ctl_elem_id id;
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_volatile *vd;
+	int result;
+	
+	if (copy_from_user(&id, _id, sizeof(id)))
+		return -EFAULT;
+	down_write(&card->controls_rwsem);
+	kctl = snd_ctl_find_id(card, &id);
+	if (kctl == NULL) {
+		result = -ENOENT;
+	} else {
+		vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
+		if (vd->owner == NULL)
+			result = -EINVAL;
+		else if (vd->owner != file)
+			result = -EPERM;
+		else {
+			vd->owner = NULL;
+			vd->owner_pid = 0;
+			result = 0;
+		}
+	}
+	up_write(&card->controls_rwsem);
+	return result;
+}
+
+struct user_element {
+	struct snd_ctl_elem_info info;
+	void *elem_data;		/* element data */
+	unsigned long elem_data_size;	/* size of element data in bytes */
+	void *tlv_data;			/* TLV data */
+	unsigned long tlv_data_size;	/* TLV data size */
+	void *priv_data;		/* private data (like strings for enumerated type) */
+	unsigned long priv_data_size;	/* size of private data in bytes */
+};
+
+static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	struct user_element *ue = kcontrol->private_data;
+
+	*uinfo = ue->info;
+	return 0;
+}
+
+static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct user_element *ue = kcontrol->private_data;
+
+	memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
+	return 0;
+}
+
+static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	int change;
+	struct user_element *ue = kcontrol->private_data;
+	
+	change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
+	if (change)
+		memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
+	return change;
+}
+
+static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
+				 int op_flag,
+				 unsigned int size,
+				 unsigned int __user *tlv)
+{
+	struct user_element *ue = kcontrol->private_data;
+	int change = 0;
+	void *new_data;
+
+	if (op_flag > 0) {
+		if (size > 1024 * 128)	/* sane value */
+			return -EINVAL;
+		new_data = kmalloc(size, GFP_KERNEL);
+		if (new_data == NULL)
+			return -ENOMEM;
+		if (copy_from_user(new_data, tlv, size)) {
+			kfree(new_data);
+			return -EFAULT;
+		}
+		change = ue->tlv_data_size != size;
+		if (!change)
+			change = memcmp(ue->tlv_data, new_data, size);
+		kfree(ue->tlv_data);
+		ue->tlv_data = new_data;
+		ue->tlv_data_size = size;
+	} else {
+		if (! ue->tlv_data_size || ! ue->tlv_data)
+			return -ENXIO;
+		if (size < ue->tlv_data_size)
+			return -ENOSPC;
+		if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
+			return -EFAULT;
+	}
+	return change;
+}
+
+static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
+{
+	struct user_element *ue = kcontrol->private_data;
+	if (ue->tlv_data)
+		kfree(ue->tlv_data);
+	kfree(ue);
+}
+
+static int snd_ctl_elem_add(struct snd_ctl_file *file,
+			    struct snd_ctl_elem_info *info, int replace)
+{
+	struct snd_card *card = file->card;
+	struct snd_kcontrol kctl, *_kctl;
+	unsigned int access;
+	long private_size;
+	struct user_element *ue;
+	int idx, err;
+	
+	if (card->user_ctl_count >= MAX_USER_CONTROLS)
+		return -ENOMEM;
+	if (info->count > 1024)
+		return -EINVAL;
+	access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
+		(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+				 SNDRV_CTL_ELEM_ACCESS_INACTIVE|
+				 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
+	info->id.numid = 0;
+	memset(&kctl, 0, sizeof(kctl));
+	down_write(&card->controls_rwsem);
+	_kctl = snd_ctl_find_id(card, &info->id);
+	err = 0;
+	if (_kctl) {
+		if (replace)
+			err = snd_ctl_remove(card, _kctl);
+		else
+			err = -EBUSY;
+	} else {
+		if (replace)
+			err = -ENOENT;
+	}
+	up_write(&card->controls_rwsem);
+	if (err < 0)
+		return err;
+	memcpy(&kctl.id, &info->id, sizeof(info->id));
+	kctl.count = info->owner ? info->owner : 1;
+	access |= SNDRV_CTL_ELEM_ACCESS_USER;
+	kctl.info = snd_ctl_elem_user_info;
+	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
+		kctl.get = snd_ctl_elem_user_get;
+	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
+		kctl.put = snd_ctl_elem_user_put;
+	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
+		kctl.tlv.c = snd_ctl_elem_user_tlv;
+		access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+	}
+	switch (info->type) {
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		private_size = sizeof(long);
+		if (info->count > 128)
+			return -EINVAL;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
+		private_size = sizeof(long long);
+		if (info->count > 64)
+			return -EINVAL;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_BYTES:
+		private_size = sizeof(unsigned char);
+		if (info->count > 512)
+			return -EINVAL;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_IEC958:
+		private_size = sizeof(struct snd_aes_iec958);
+		if (info->count != 1)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	private_size *= info->count;
+	ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
+	if (ue == NULL)
+		return -ENOMEM;
+	ue->info = *info;
+	ue->info.access = 0;
+	ue->elem_data = (char *)ue + sizeof(*ue);
+	ue->elem_data_size = private_size;
+	kctl.private_free = snd_ctl_elem_user_free;
+	_kctl = snd_ctl_new(&kctl, access);
+	if (_kctl == NULL) {
+		kfree(ue);
+		return -ENOMEM;
+	}
+	_kctl->private_data = ue;
+	for (idx = 0; idx < _kctl->count; idx++)
+		_kctl->vd[idx].owner = file;
+	err = snd_ctl_add(card, _kctl);
+	if (err < 0)
+		return err;
+
+	down_write(&card->controls_rwsem);
+	card->user_ctl_count++;
+	up_write(&card->controls_rwsem);
+
+	return 0;
+}
+
+static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
+				 struct snd_ctl_elem_info __user *_info, int replace)
+{
+	struct snd_ctl_elem_info info;
+	if (copy_from_user(&info, _info, sizeof(info)))
+		return -EFAULT;
+	return snd_ctl_elem_add(file, &info, replace);
+}
+
+static int snd_ctl_elem_remove(struct snd_ctl_file *file,
+			       struct snd_ctl_elem_id __user *_id)
+{
+	struct snd_ctl_elem_id id;
+	int err;
+
+	if (copy_from_user(&id, _id, sizeof(id)))
+		return -EFAULT;
+	err = snd_ctl_remove_unlocked_id(file, &id);
+	if (! err) {
+		struct snd_card *card = file->card;
+		down_write(&card->controls_rwsem);
+		card->user_ctl_count--;
+		up_write(&card->controls_rwsem);
+	}
+	return err;
+}
+
+static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
+{
+	int subscribe;
+	if (get_user(subscribe, ptr))
+		return -EFAULT;
+	if (subscribe < 0) {
+		subscribe = file->subscribed;
+		if (put_user(subscribe, ptr))
+			return -EFAULT;
+		return 0;
+	}
+	if (subscribe) {
+		file->subscribed = 1;
+		return 0;
+	} else if (file->subscribed) {
+		snd_ctl_empty_read_queue(file);
+		file->subscribed = 0;
+	}
+	return 0;
+}
+
+static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
+                             struct snd_ctl_tlv __user *_tlv,
+                             int op_flag)
+{
+	struct snd_card *card = file->card;
+	struct snd_ctl_tlv tlv;
+	struct snd_kcontrol *kctl;
+	struct snd_kcontrol_volatile *vd;
+	unsigned int len;
+	int err = 0;
+
+	if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
+		return -EFAULT;
+	if (tlv.length < sizeof(unsigned int) * 3)
+		return -EINVAL;
+	down_read(&card->controls_rwsem);
+	kctl = snd_ctl_find_numid(card, tlv.numid);
+	if (kctl == NULL) {
+		err = -ENOENT;
+		goto __kctl_end;
+	}
+	if (kctl->tlv.p == NULL) {
+		err = -ENXIO;
+		goto __kctl_end;
+	}
+	vd = &kctl->vd[tlv.numid - kctl->id.numid];
+	if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
+	    (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
+	    (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
+	    	err = -ENXIO;
+	    	goto __kctl_end;
+	}
+	if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+		if (file && vd->owner != NULL && vd->owner != file) {
+			err = -EPERM;
+			goto __kctl_end;
+		}
+		err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); 
+		if (err > 0) {
+			up_read(&card->controls_rwsem);
+			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
+			return 0;
+		}
+	} else {
+		if (op_flag) {
+			err = -ENXIO;
+			goto __kctl_end;
+		}
+		len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
+		if (tlv.length < len) {
+			err = -ENOMEM;
+			goto __kctl_end;
+		}
+		if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
+			err = -EFAULT;
+	}
+      __kctl_end:
+	up_read(&card->controls_rwsem);
+	return err;
+}
+
+static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct snd_ctl_file *ctl;
+	struct snd_card *card;
+	struct snd_kctl_ioctl *p;
+	void __user *argp = (void __user *)arg;
+	int __user *ip = argp;
+	int err;
+
+	ctl = file->private_data;
+	card = ctl->card;
+	snd_assert(card != NULL, return -ENXIO);
+	switch (cmd) {
+	case SNDRV_CTL_IOCTL_PVERSION:
+		return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
+	case SNDRV_CTL_IOCTL_CARD_INFO:
+		return snd_ctl_card_info(card, ctl, cmd, argp);
+	case SNDRV_CTL_IOCTL_ELEM_LIST:
+		return snd_ctl_elem_list(card, argp);
+	case SNDRV_CTL_IOCTL_ELEM_INFO:
+		return snd_ctl_elem_info_user(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_READ:
+		return snd_ctl_elem_read_user(card, argp);
+	case SNDRV_CTL_IOCTL_ELEM_WRITE:
+		return snd_ctl_elem_write_user(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_LOCK:
+		return snd_ctl_elem_lock(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
+		return snd_ctl_elem_unlock(ctl, argp);
+	case SNDRV_CTL_IOCTL_ELEM_ADD:
+		return snd_ctl_elem_add_user(ctl, argp, 0);
+	case SNDRV_CTL_IOCTL_ELEM_REPLACE:
+		return snd_ctl_elem_add_user(ctl, argp, 1);
+	case SNDRV_CTL_IOCTL_ELEM_REMOVE:
+		return snd_ctl_elem_remove(ctl, argp);
+	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
+		return snd_ctl_subscribe_events(ctl, ip);
+	case SNDRV_CTL_IOCTL_TLV_READ:
+		return snd_ctl_tlv_ioctl(ctl, argp, 0);
+	case SNDRV_CTL_IOCTL_TLV_WRITE:
+		return snd_ctl_tlv_ioctl(ctl, argp, 1);
+	case SNDRV_CTL_IOCTL_TLV_COMMAND:
+		return snd_ctl_tlv_ioctl(ctl, argp, -1);
+	case SNDRV_CTL_IOCTL_POWER:
+		return -ENOPROTOOPT;
+	case SNDRV_CTL_IOCTL_POWER_STATE:
+#ifdef CONFIG_PM
+		return put_user(card->power_state, ip) ? -EFAULT : 0;
+#else
+		return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
+#endif
+	}
+	down_read(&snd_ioctl_rwsem);
+	list_for_each_entry(p, &snd_control_ioctls, list) {
+		err = p->fioctl(card, ctl, cmd, arg);
+		if (err != -ENOIOCTLCMD) {
+			up_read(&snd_ioctl_rwsem);
+			return err;
+		}
+	}
+	up_read(&snd_ioctl_rwsem);
+	snd_printdd("unknown ioctl = 0x%x\n", cmd);
+	return -ENOTTY;
+}
+
+static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
+			    size_t count, loff_t * offset)
+{
+	struct snd_ctl_file *ctl;
+	int err = 0;
+	ssize_t result = 0;
+
+	ctl = file->private_data;
+	snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);
+	if (!ctl->subscribed)
+		return -EBADFD;
+	if (count < sizeof(struct snd_ctl_event))
+		return -EINVAL;
+	spin_lock_irq(&ctl->read_lock);
+	while (count >= sizeof(struct snd_ctl_event)) {
+		struct snd_ctl_event ev;
+		struct snd_kctl_event *kev;
+		while (list_empty(&ctl->events)) {
+			wait_queue_t wait;
+			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
+				err = -EAGAIN;
+				goto __end_lock;
+			}
+			init_waitqueue_entry(&wait, current);
+			add_wait_queue(&ctl->change_sleep, &wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irq(&ctl->read_lock);
+			schedule();
+			remove_wait_queue(&ctl->change_sleep, &wait);
+			if (signal_pending(current))
+				return -ERESTARTSYS;
+			spin_lock_irq(&ctl->read_lock);
+		}
+		kev = snd_kctl_event(ctl->events.next);
+		ev.type = SNDRV_CTL_EVENT_ELEM;
+		ev.data.elem.mask = kev->mask;
+		ev.data.elem.id = kev->id;
+		list_del(&kev->list);
+		spin_unlock_irq(&ctl->read_lock);
+		kfree(kev);
+		if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) {
+			err = -EFAULT;
+			goto __end;
+		}
+		spin_lock_irq(&ctl->read_lock);
+		buffer += sizeof(struct snd_ctl_event);
+		count -= sizeof(struct snd_ctl_event);
+		result += sizeof(struct snd_ctl_event);
+	}
+      __end_lock:
+	spin_unlock_irq(&ctl->read_lock);
+      __end:
+      	return result > 0 ? result : err;
+}
+
+static unsigned int snd_ctl_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask;
+	struct snd_ctl_file *ctl;
+
+	ctl = file->private_data;
+	if (!ctl->subscribed)
+		return 0;
+	poll_wait(file, &ctl->change_sleep, wait);
+
+	mask = 0;
+	if (!list_empty(&ctl->events))
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}
+
+/*
+ * register the device-specific control-ioctls.
+ * called from each device manager like pcm.c, hwdep.c, etc.
+ */
+static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
+{
+	struct snd_kctl_ioctl *pn;
+
+	pn = kzalloc(sizeof(struct snd_kctl_ioctl), GFP_KERNEL);
+	if (pn == NULL)
+		return -ENOMEM;
+	pn->fioctl = fcn;
+	down_write(&snd_ioctl_rwsem);
+	list_add_tail(&pn->list, lists);
+	up_write(&snd_ioctl_rwsem);
+	return 0;
+}
+
+int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
+}
+
+EXPORT_SYMBOL(snd_ctl_register_ioctl);
+
+#ifdef CONFIG_COMPAT
+int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
+}
+
+EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
+#endif
+
+/*
+ * de-register the device-specific control-ioctls.
+ */
+static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
+				     struct list_head *lists)
+{
+	struct snd_kctl_ioctl *p;
+
+	snd_assert(fcn != NULL, return -EINVAL);
+	down_write(&snd_ioctl_rwsem);
+	list_for_each_entry(p, lists, list) {
+		if (p->fioctl == fcn) {
+			list_del(&p->list);
+			up_write(&snd_ioctl_rwsem);
+			kfree(p);
+			return 0;
+		}
+	}
+	up_write(&snd_ioctl_rwsem);
+	snd_BUG();
+	return -EINVAL;
+}
+
+int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
+}
+
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
+
+#ifdef CONFIG_COMPAT
+int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
+{
+	return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
+}
+
+EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
+#endif
+
+static int snd_ctl_fasync(int fd, struct file * file, int on)
+{
+	struct snd_ctl_file *ctl;
+	int err;
+	ctl = file->private_data;
+	err = fasync_helper(fd, file, on, &ctl->fasync);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/*
+ * ioctl32 compat
+ */
+#ifdef CONFIG_COMPAT
+#include "control_compat.c"
+#else
+#define snd_ctl_ioctl_compat	NULL
+#endif
+
+/*
+ *  INIT PART
+ */
+
+static const struct file_operations snd_ctl_f_ops =
+{
+	.owner =	THIS_MODULE,
+	.read =		snd_ctl_read,
+	.open =		snd_ctl_open,
+	.release =	snd_ctl_release,
+	.poll =		snd_ctl_poll,
+	.unlocked_ioctl =	snd_ctl_ioctl,
+	.compat_ioctl =	snd_ctl_ioctl_compat,
+	.fasync =	snd_ctl_fasync,
+};
+
+/*
+ * registration of the control device
+ */
+static int snd_ctl_dev_register(struct snd_device *device)
+{
+	struct snd_card *card = device->device_data;
+	int err, cardnum;
+	char name[16];
+
+	snd_assert(card != NULL, return -ENXIO);
+	cardnum = card->number;
+	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+	sprintf(name, "controlC%i", cardnum);
+	if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
+				       &snd_ctl_f_ops, card, name)) < 0)
+		return err;
+	return 0;
+}
+
+/*
+ * disconnection of the control device
+ */
+static int snd_ctl_dev_disconnect(struct snd_device *device)
+{
+	struct snd_card *card = device->device_data;
+	struct snd_ctl_file *ctl;
+	int err, cardnum;
+
+	snd_assert(card != NULL, return -ENXIO);
+	cardnum = card->number;
+	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
+
+	down_read(&card->controls_rwsem);
+	list_for_each_entry(ctl, &card->ctl_files, list) {
+		wake_up(&ctl->change_sleep);
+		kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
+	}
+	up_read(&card->controls_rwsem);
+
+	if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
+					 card, -1)) < 0)
+		return err;
+	return 0;
+}
+
+/*
+ * free all controls
+ */
+static int snd_ctl_dev_free(struct snd_device *device)
+{
+	struct snd_card *card = device->device_data;
+	struct snd_kcontrol *control;
+
+	down_write(&card->controls_rwsem);
+	while (!list_empty(&card->controls)) {
+		control = snd_kcontrol(card->controls.next);
+		snd_ctl_remove(card, control);
+	}
+	up_write(&card->controls_rwsem);
+	return 0;
+}
+
+/*
+ * create control core:
+ * called from init.c
+ */
+int snd_ctl_create(struct snd_card *card)
+{
+	static struct snd_device_ops ops = {
+		.dev_free = snd_ctl_dev_free,
+		.dev_register =	snd_ctl_dev_register,
+		.dev_disconnect = snd_ctl_dev_disconnect,
+	};
+
+	snd_assert(card != NULL, return -ENXIO);
+	return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
+}
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/memalloc.c linux-2.6.22/sound/.pc/alsa-20070818.patch/core/memalloc.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/memalloc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/core/memalloc.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,646 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *                   Takashi Iwai <tiwai@suse.de>
+ * 
+ *  Generic memory allocators
+ *
+ *
+ *   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 <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <sound/memalloc.h>
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#endif
+
+
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("Memory allocator for ALSA system.");
+MODULE_LICENSE("GPL");
+
+
+/*
+ */
+
+void *snd_malloc_sgbuf_pages(struct device *device,
+                             size_t size, struct snd_dma_buffer *dmab,
+			     size_t *res_size);
+int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
+
+/*
+ */
+
+static DEFINE_MUTEX(list_mutex);
+static LIST_HEAD(mem_list_head);
+
+/* buffer preservation list */
+struct snd_mem_list {
+	struct snd_dma_buffer buffer;
+	unsigned int id;
+	struct list_head list;
+};
+
+/* id for pre-allocated buffers */
+#define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
+
+#ifdef CONFIG_SND_DEBUG
+#define __ASTRING__(x) #x
+#define snd_assert(expr, args...) do {\
+	if (!(expr)) {\
+		printk(KERN_ERR "snd-malloc: BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
+		args;\
+	}\
+} while (0)
+#else
+#define snd_assert(expr, args...) /**/
+#endif
+
+/*
+ *  Hacks
+ */
+
+#if defined(__i386__)
+/*
+ * A hack to allocate large buffers via dma_alloc_coherent()
+ *
+ * since dma_alloc_coherent always tries GFP_DMA when the requested
+ * pci memory region is below 32bit, it happens quite often that even
+ * 2 order of pages cannot be allocated.
+ *
+ * so in the following, we allocate at first without dma_mask, so that
+ * allocation will be done without GFP_DMA.  if the area doesn't match
+ * with the requested region, then realloate with the original dma_mask
+ * again.
+ *
+ * Really, we want to move this type of thing into dma_alloc_coherent()
+ * so dma_mask doesn't have to be messed with.
+ */
+
+static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
+					 dma_addr_t *dma_handle,
+					 gfp_t flags)
+{
+	void *ret;
+	u64 dma_mask, coherent_dma_mask;
+
+	if (dev == NULL || !dev->dma_mask)
+		return dma_alloc_coherent(dev, size, dma_handle, flags);
+	dma_mask = *dev->dma_mask;
+	coherent_dma_mask = dev->coherent_dma_mask;
+	*dev->dma_mask = 0xffffffff; 	/* do without masking */
+	dev->coherent_dma_mask = 0xffffffff; 	/* do without masking */
+	ret = dma_alloc_coherent(dev, size, dma_handle, flags);
+	*dev->dma_mask = dma_mask;	/* restore */
+	dev->coherent_dma_mask = coherent_dma_mask;	/* restore */
+	if (ret) {
+		/* obtained address is out of range? */
+		if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) {
+			/* reallocate with the proper mask */
+			dma_free_coherent(dev, size, ret, *dma_handle);
+			ret = dma_alloc_coherent(dev, size, dma_handle, flags);
+		}
+	} else {
+		/* wish to success now with the proper mask... */
+		if (dma_mask != 0xffffffffUL) {
+			/* allocation with GFP_ATOMIC to avoid the long stall */
+			flags &= ~GFP_KERNEL;
+			flags |= GFP_ATOMIC;
+			ret = dma_alloc_coherent(dev, size, dma_handle, flags);
+		}
+	}
+	return ret;
+}
+
+/* redefine dma_alloc_coherent for some architectures */
+#undef dma_alloc_coherent
+#define dma_alloc_coherent snd_dma_hack_alloc_coherent
+
+#endif /* arch */
+
+/*
+ *
+ *  Generic memory allocators
+ *
+ */
+
+static long snd_allocated_pages; /* holding the number of allocated pages */
+
+static inline void inc_snd_pages(int order)
+{
+	snd_allocated_pages += 1 << order;
+}
+
+static inline void dec_snd_pages(int order)
+{
+	snd_allocated_pages -= 1 << order;
+}
+
+/**
+ * snd_malloc_pages - allocate pages with the given size
+ * @size: the size to allocate in bytes
+ * @gfp_flags: the allocation conditions, GFP_XXX
+ *
+ * Allocates the physically contiguous pages with the given size.
+ *
+ * Returns the pointer of the buffer, or NULL if no enoguh memory.
+ */
+void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
+{
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(gfp_flags != 0, return NULL);
+	gfp_flags |= __GFP_COMP;	/* compound page lets parts be mapped */
+	pg = get_order(size);
+	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
+		inc_snd_pages(pg);
+	return res;
+}
+
+/**
+ * snd_free_pages - release the pages
+ * @ptr: the buffer pointer to release
+ * @size: the allocated buffer size
+ *
+ * Releases the buffer allocated via snd_malloc_pages().
+ */
+void snd_free_pages(void *ptr, size_t size)
+{
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	pg = get_order(size);
+	dec_snd_pages(pg);
+	free_pages((unsigned long) ptr, pg);
+}
+
+/*
+ *
+ *  Bus-specific memory allocators
+ *
+ */
+
+/* allocate the coherent DMA pages */
+static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
+{
+	int pg;
+	void *res;
+	gfp_t gfp_flags;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(dma != NULL, return NULL);
+	pg = get_order(size);
+	gfp_flags = GFP_KERNEL
+		| __GFP_COMP	/* compound page lets parts be mapped */
+		| __GFP_NORETRY /* don't trigger OOM-killer */
+		| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
+	res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
+	if (res != NULL)
+		inc_snd_pages(pg);
+
+	return res;
+}
+
+/* free the coherent DMA pages */
+static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
+			       dma_addr_t dma)
+{
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	pg = get_order(size);
+	dec_snd_pages(pg);
+	dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
+}
+
+#ifdef CONFIG_SBUS
+
+static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
+				   dma_addr_t *dma_addr)
+{
+	struct sbus_dev *sdev = (struct sbus_dev *)dev;
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(dma_addr != NULL, return NULL);
+	pg = get_order(size);
+	res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
+	if (res != NULL)
+		inc_snd_pages(pg);
+	return res;
+}
+
+static void snd_free_sbus_pages(struct device *dev, size_t size,
+				void *ptr, dma_addr_t dma_addr)
+{
+	struct sbus_dev *sdev = (struct sbus_dev *)dev;
+	int pg;
+
+	if (ptr == NULL)
+		return;
+	pg = get_order(size);
+	dec_snd_pages(pg);
+	sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
+}
+
+#endif /* CONFIG_SBUS */
+
+/*
+ *
+ *  ALSA generic memory management
+ *
+ */
+
+
+/**
+ * snd_dma_alloc_pages - allocate the buffer area according to the given type
+ * @type: the DMA buffer type
+ * @device: the device pointer
+ * @size: the buffer size to allocate
+ * @dmab: buffer allocation record to store the allocated data
+ *
+ * Calls the memory-allocator function for the corresponding
+ * buffer type.
+ * 
+ * Returns zero if the buffer with the given size is allocated successfuly,
+ * other a negative value at error.
+ */
+int snd_dma_alloc_pages(int type, struct device *device, size_t size,
+			struct snd_dma_buffer *dmab)
+{
+	snd_assert(size > 0, return -ENXIO);
+	snd_assert(dmab != NULL, return -ENXIO);
+
+	dmab->dev.type = type;
+	dmab->dev.dev = device;
+	dmab->bytes = 0;
+	switch (type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		dmab->area = snd_malloc_pages(size, (unsigned long)device);
+		dmab->addr = 0;
+		break;
+#ifdef CONFIG_SBUS
+	case SNDRV_DMA_TYPE_SBUS:
+		dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr);
+		break;
+#endif
+	case SNDRV_DMA_TYPE_DEV:
+		dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
+		break;
+	case SNDRV_DMA_TYPE_DEV_SG:
+		snd_malloc_sgbuf_pages(device, size, dmab, NULL);
+		break;
+	default:
+		printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
+		dmab->area = NULL;
+		dmab->addr = 0;
+		return -ENXIO;
+	}
+	if (! dmab->area)
+		return -ENOMEM;
+	dmab->bytes = size;
+	return 0;
+}
+
+/**
+ * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback
+ * @type: the DMA buffer type
+ * @device: the device pointer
+ * @size: the buffer size to allocate
+ * @dmab: buffer allocation record to store the allocated data
+ *
+ * Calls the memory-allocator function for the corresponding
+ * buffer type.  When no space is left, this function reduces the size and
+ * tries to allocate again.  The size actually allocated is stored in
+ * res_size argument.
+ * 
+ * Returns zero if the buffer with the given size is allocated successfuly,
+ * other a negative value at error.
+ */
+int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
+				 struct snd_dma_buffer *dmab)
+{
+	int err;
+
+	snd_assert(size > 0, return -ENXIO);
+	snd_assert(dmab != NULL, return -ENXIO);
+
+	while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
+		if (err != -ENOMEM)
+			return err;
+		size >>= 1;
+		if (size <= PAGE_SIZE)
+			return -ENOMEM;
+	}
+	if (! dmab->area)
+		return -ENOMEM;
+	return 0;
+}
+
+
+/**
+ * snd_dma_free_pages - release the allocated buffer
+ * @dmab: the buffer allocation record to release
+ *
+ * Releases the allocated buffer via snd_dma_alloc_pages().
+ */
+void snd_dma_free_pages(struct snd_dma_buffer *dmab)
+{
+	switch (dmab->dev.type) {
+	case SNDRV_DMA_TYPE_CONTINUOUS:
+		snd_free_pages(dmab->area, dmab->bytes);
+		break;
+#ifdef CONFIG_SBUS
+	case SNDRV_DMA_TYPE_SBUS:
+		snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
+		break;
+#endif
+	case SNDRV_DMA_TYPE_DEV:
+		snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
+		break;
+	case SNDRV_DMA_TYPE_DEV_SG:
+		snd_free_sgbuf_pages(dmab);
+		break;
+	default:
+		printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type);
+	}
+}
+
+
+/**
+ * snd_dma_get_reserved - get the reserved buffer for the given device
+ * @dmab: the buffer allocation record to store
+ * @id: the buffer id
+ *
+ * Looks for the reserved-buffer list and re-uses if the same buffer
+ * is found in the list.  When the buffer is found, it's removed from the free list.
+ *
+ * Returns the size of buffer if the buffer is found, or zero if not found.
+ */
+size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
+{
+	struct snd_mem_list *mem;
+
+	snd_assert(dmab, return 0);
+
+	mutex_lock(&list_mutex);
+	list_for_each_entry(mem, &mem_list_head, list) {
+		if (mem->id == id &&
+		    (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
+		     ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
+			struct device *dev = dmab->dev.dev;
+			list_del(&mem->list);
+			*dmab = mem->buffer;
+			if (dmab->dev.dev == NULL)
+				dmab->dev.dev = dev;
+			kfree(mem);
+			mutex_unlock(&list_mutex);
+			return dmab->bytes;
+		}
+	}
+	mutex_unlock(&list_mutex);
+	return 0;
+}
+
+/**
+ * snd_dma_reserve_buf - reserve the buffer
+ * @dmab: the buffer to reserve
+ * @id: the buffer id
+ *
+ * Reserves the given buffer as a reserved buffer.
+ * 
+ * Returns zero if successful, or a negative code at error.
+ */
+int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
+{
+	struct snd_mem_list *mem;
+
+	snd_assert(dmab, return -EINVAL);
+	mem = kmalloc(sizeof(*mem), GFP_KERNEL);
+	if (! mem)
+		return -ENOMEM;
+	mutex_lock(&list_mutex);
+	mem->buffer = *dmab;
+	mem->id = id;
+	list_add_tail(&mem->list, &mem_list_head);
+	mutex_unlock(&list_mutex);
+	return 0;
+}
+
+/*
+ * purge all reserved buffers
+ */
+static void free_all_reserved_pages(void)
+{
+	struct list_head *p;
+	struct snd_mem_list *mem;
+
+	mutex_lock(&list_mutex);
+	while (! list_empty(&mem_list_head)) {
+		p = mem_list_head.next;
+		mem = list_entry(p, struct snd_mem_list, list);
+		list_del(p);
+		snd_dma_free_pages(&mem->buffer);
+		kfree(mem);
+	}
+	mutex_unlock(&list_mutex);
+}
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * proc file interface
+ */
+#define SND_MEM_PROC_FILE	"driver/snd-page-alloc"
+static struct proc_dir_entry *snd_mem_proc;
+
+static int snd_mem_proc_read(char *page, char **start, off_t off,
+			     int count, int *eof, void *data)
+{
+	int len = 0;
+	long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
+	struct snd_mem_list *mem;
+	int devno;
+	static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
+
+	mutex_lock(&list_mutex);
+	len += snprintf(page + len, count - len,
+			"pages  : %li bytes (%li pages per %likB)\n",
+			pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
+	devno = 0;
+	list_for_each_entry(mem, &mem_list_head, list) {
+		devno++;
+		len += snprintf(page + len, count - len,
+				"buffer %d : ID %08x : type %s\n",
+				devno, mem->id, types[mem->buffer.dev.type]);
+		len += snprintf(page + len, count - len,
+				"  addr = 0x%lx, size = %d bytes\n",
+				(unsigned long)mem->buffer.addr, (int)mem->buffer.bytes);
+	}
+	mutex_unlock(&list_mutex);
+	return len;
+}
+
+/* FIXME: for pci only - other bus? */
+#ifdef CONFIG_PCI
+#define gettoken(bufp) strsep(bufp, " \t\n")
+
+static int snd_mem_proc_write(struct file *file, const char __user *buffer,
+			      unsigned long count, void *data)
+{
+	char buf[128];
+	char *token, *p;
+
+	if (count > ARRAY_SIZE(buf) - 1)
+		count = ARRAY_SIZE(buf) - 1;
+	if (copy_from_user(buf, buffer, count))
+		return -EFAULT;
+	buf[ARRAY_SIZE(buf) - 1] = '\0';
+
+	p = buf;
+	token = gettoken(&p);
+	if (! token || *token == '#')
+		return (int)count;
+	if (strcmp(token, "add") == 0) {
+		char *endp;
+		int vendor, device, size, buffers;
+		long mask;
+		int i, alloced;
+		struct pci_dev *pci;
+
+		if ((token = gettoken(&p)) == NULL ||
+		    (vendor = simple_strtol(token, NULL, 0)) <= 0 ||
+		    (token = gettoken(&p)) == NULL ||
+		    (device = simple_strtol(token, NULL, 0)) <= 0 ||
+		    (token = gettoken(&p)) == NULL ||
+		    (mask = simple_strtol(token, NULL, 0)) < 0 ||
+		    (token = gettoken(&p)) == NULL ||
+		    (size = memparse(token, &endp)) < 64*1024 ||
+		    size > 16*1024*1024 /* too big */ ||
+		    (token = gettoken(&p)) == NULL ||
+		    (buffers = simple_strtol(token, NULL, 0)) <= 0 ||
+		    buffers > 4) {
+			printk(KERN_ERR "snd-page-alloc: invalid proc write format\n");
+			return (int)count;
+		}
+		vendor &= 0xffff;
+		device &= 0xffff;
+
+		alloced = 0;
+		pci = NULL;
+		while ((pci = pci_get_device(vendor, device, pci)) != NULL) {
+			if (mask > 0 && mask < 0xffffffff) {
+				if (pci_set_dma_mask(pci, mask) < 0 ||
+				    pci_set_consistent_dma_mask(pci, mask) < 0) {
+					printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
+					return (int)count;
+				}
+			}
+			for (i = 0; i < buffers; i++) {
+				struct snd_dma_buffer dmab;
+				memset(&dmab, 0, sizeof(dmab));
+				if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
+							size, &dmab) < 0) {
+					printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
+					pci_dev_put(pci);
+					return (int)count;
+				}
+				snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
+			}
+			alloced++;
+		}
+		if (! alloced) {
+			for (i = 0; i < buffers; i++) {
+				struct snd_dma_buffer dmab;
+				memset(&dmab, 0, sizeof(dmab));
+				/* FIXME: We can allocate only in ZONE_DMA
+				 * without a device pointer!
+				 */
+				if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
+							size, &dmab) < 0) {
+					printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
+					break;
+				}
+				snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
+			}
+		}
+	} else if (strcmp(token, "erase") == 0)
+		/* FIXME: need for releasing each buffer chunk? */
+		free_all_reserved_pages();
+	else
+		printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n");
+	return (int)count;
+}
+#endif /* CONFIG_PCI */
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * module entry
+ */
+
+static int __init snd_mem_init(void)
+{
+#ifdef CONFIG_PROC_FS
+	snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL);
+	if (snd_mem_proc) {
+		snd_mem_proc->read_proc = snd_mem_proc_read;
+#ifdef CONFIG_PCI
+		snd_mem_proc->write_proc = snd_mem_proc_write;
+#endif
+	}
+#endif
+	return 0;
+}
+
+static void __exit snd_mem_exit(void)
+{
+	remove_proc_entry(SND_MEM_PROC_FILE, NULL);
+	free_all_reserved_pages();
+	if (snd_allocated_pages > 0)
+		printk(KERN_ERR "snd-malloc: Memory leak?  pages not freed = %li\n", snd_allocated_pages);
+}
+
+
+module_init(snd_mem_init)
+module_exit(snd_mem_exit)
+
+
+/*
+ * exports
+ */
+EXPORT_SYMBOL(snd_dma_alloc_pages);
+EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
+EXPORT_SYMBOL(snd_dma_free_pages);
+
+EXPORT_SYMBOL(snd_dma_get_reserved_buf);
+EXPORT_SYMBOL(snd_dma_reserve_buf);
+
+EXPORT_SYMBOL(snd_malloc_pages);
+EXPORT_SYMBOL(snd_free_pages);
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/Makefile linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/Makefile
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/Makefile	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,12 @@
+#
+# Makefile for ALSA
+# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-mixer-oss-objs := mixer_oss.o
+
+snd-pcm-oss-objs := pcm_oss.o pcm_plugin.o \
+		    io.o copy.o linear.o mulaw.o route.o rate.o
+
+obj-$(CONFIG_SND_MIXER_OSS) += snd-mixer-oss.o
+obj-$(CONFIG_SND_PCM_OSS) += snd-pcm-oss.o
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/copy.c linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/copy.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/copy.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/copy.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,92 @@
+/*
+ *  Linear conversion Plug-In
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library 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 Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "pcm_plugin.h"
+
+static snd_pcm_sframes_t copy_transfer(struct snd_pcm_plugin *plugin,
+			     const struct snd_pcm_plugin_channel *src_channels,
+			     struct snd_pcm_plugin_channel *dst_channels,
+			     snd_pcm_uframes_t frames)
+{
+	unsigned int channel;
+	unsigned int nchannels;
+
+	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
+	if (frames == 0)
+		return 0;
+	nchannels = plugin->src_format.channels;
+	for (channel = 0; channel < nchannels; channel++) {
+		snd_assert(src_channels->area.first % 8 == 0 &&
+			   src_channels->area.step % 8 == 0,
+			   return -ENXIO);
+		snd_assert(dst_channels->area.first % 8 == 0 &&
+			   dst_channels->area.step % 8 == 0,
+			   return -ENXIO);
+		if (!src_channels->enabled) {
+			if (dst_channels->wanted)
+				snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
+			dst_channels->enabled = 0;
+			continue;
+		}
+		dst_channels->enabled = 1;
+		snd_pcm_area_copy(&src_channels->area, 0, &dst_channels->area, 0, frames, plugin->src_format.format);
+		src_channels++;
+		dst_channels++;
+	}
+	return frames;
+}
+
+int snd_pcm_plugin_build_copy(struct snd_pcm_substream *plug,
+			      struct snd_pcm_plugin_format *src_format,
+			      struct snd_pcm_plugin_format *dst_format,
+			      struct snd_pcm_plugin **r_plugin)
+{
+	int err;
+	struct snd_pcm_plugin *plugin;
+	int width;
+
+	snd_assert(r_plugin != NULL, return -ENXIO);
+	*r_plugin = NULL;
+
+	snd_assert(src_format->format == dst_format->format, return -ENXIO);
+	snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
+	snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
+
+	width = snd_pcm_format_physical_width(src_format->format);
+	snd_assert(width > 0, return -ENXIO);
+
+	err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format,
+				   0, &plugin);
+	if (err < 0)
+		return err;
+	plugin->transfer = copy_transfer;
+	*r_plugin = plugin;
+	return 0;
+}
+
+#endif
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/io.c linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/io.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/io.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/io.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,139 @@
+/*
+ *  PCM I/O Plug-In Interface
+ *  Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library 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 Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+  
+#include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "pcm_plugin.h"
+
+#define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1)
+#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1)
+#define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1)
+#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1)
+
+/*
+ *  Basic io plugin
+ */
+ 
+static snd_pcm_sframes_t io_playback_transfer(struct snd_pcm_plugin *plugin,
+				    const struct snd_pcm_plugin_channel *src_channels,
+				    struct snd_pcm_plugin_channel *dst_channels,
+				    snd_pcm_uframes_t frames)
+{
+	snd_assert(plugin != NULL, return -ENXIO);
+	snd_assert(src_channels != NULL, return -ENXIO);
+	if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
+		return pcm_write(plugin->plug, src_channels->area.addr, frames);
+	} else {
+		int channel, channels = plugin->dst_format.channels;
+		void **bufs = (void**)plugin->extra_data;
+		snd_assert(bufs != NULL, return -ENXIO);
+		for (channel = 0; channel < channels; channel++) {
+			if (src_channels[channel].enabled)
+				bufs[channel] = src_channels[channel].area.addr;
+			else
+				bufs[channel] = NULL;
+		}
+		return pcm_writev(plugin->plug, bufs, frames);
+	}
+}
+ 
+static snd_pcm_sframes_t io_capture_transfer(struct snd_pcm_plugin *plugin,
+				   const struct snd_pcm_plugin_channel *src_channels,
+				   struct snd_pcm_plugin_channel *dst_channels,
+				   snd_pcm_uframes_t frames)
+{
+	snd_assert(plugin != NULL, return -ENXIO);
+	snd_assert(dst_channels != NULL, return -ENXIO);
+	if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
+		return pcm_read(plugin->plug, dst_channels->area.addr, frames);
+	} else {
+		int channel, channels = plugin->dst_format.channels;
+		void **bufs = (void**)plugin->extra_data;
+		snd_assert(bufs != NULL, return -ENXIO);
+		for (channel = 0; channel < channels; channel++) {
+			if (dst_channels[channel].enabled)
+				bufs[channel] = dst_channels[channel].area.addr;
+			else
+				bufs[channel] = NULL;
+		}
+		return pcm_readv(plugin->plug, bufs, frames);
+	}
+	return 0;
+}
+ 
+static snd_pcm_sframes_t io_src_channels(struct snd_pcm_plugin *plugin,
+			     snd_pcm_uframes_t frames,
+			     struct snd_pcm_plugin_channel **channels)
+{
+	int err;
+	unsigned int channel;
+	struct snd_pcm_plugin_channel *v;
+	err = snd_pcm_plugin_client_channels(plugin, frames, &v);
+	if (err < 0)
+		return err;
+	*channels = v;
+	if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
+		for (channel = 0; channel < plugin->src_format.channels; ++channel, ++v)
+			v->wanted = 1;
+	}
+	return frames;
+}
+
+int snd_pcm_plugin_build_io(struct snd_pcm_substream *plug,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_pcm_plugin **r_plugin)
+{
+	int err;
+	struct snd_pcm_plugin_format format;
+	struct snd_pcm_plugin *plugin;
+
+	snd_assert(r_plugin != NULL, return -ENXIO);
+	*r_plugin = NULL;
+	snd_assert(plug != NULL && params != NULL, return -ENXIO);
+	format.format = params_format(params);
+	format.rate = params_rate(params);
+	format.channels = params_channels(params);
+	err = snd_pcm_plugin_build(plug, "I/O io",
+				   &format, &format,
+				   sizeof(void *) * format.channels,
+				   &plugin);
+	if (err < 0)
+		return err;
+	plugin->access = params_access(params);
+	if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
+		plugin->transfer = io_playback_transfer;
+		if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED)
+			plugin->client_channels = io_src_channels;
+	} else {
+		plugin->transfer = io_capture_transfer;
+	}
+
+	*r_plugin = plugin;
+	return 0;
+}
+
+#endif
diff -Naur linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/linear.c linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/linear.c
--- linux-2.6.22.orig/sound/.pc/alsa-20070818.patch/core/oss/linear.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.22/sound/.pc/alsa-20070818.patch/core/oss/linear.c	2007-08-31 20:40:51.000000000 +0200
@@ -0,0 +1,163 @@
+/*
+ *  Linear conversion Plug-In
+ *  Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>,
+ *			  Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library 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
+ *   ME
