Index: linux-2.6.11-rc2/sound/oss/Makefile
===================================================================
--- linux-2.6.11-rc2.orig/sound/oss/Makefile	2005-01-22 01:47:32.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/Makefile	2005-01-28 15:42:49.339280624 +0000
@@ -39,6 +39,8 @@
 obj-$(CONFIG_SOUND_AD1889)	+= ad1889.o ac97_codec.o
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
 obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
+obj-$(CONFIG_SOUND_CORGI)	+= pxa-i2s_corgi.o poodle_wm8731.o poodle_i2sc.o
+
 
 obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o ac97_codec.o
 ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
Index: linux-2.6.11-rc2/sound/oss/i2sc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/i2sc.h	2005-01-28 15:42:49.339280624 +0000
@@ -0,0 +1,49 @@
+/*
+ *  linux/indlude/asm-arm/arch-pxa/i2sc.h
+ *
+ *  Driver for I2c interface on Xscale
+ *
+ * Copyright (C) 2002 Steve Lin (stevelin168@hotmail.com)
+ *
+ * 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
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ */
+
+#define I2C_ISR_RWM	0x0001
+#define I2C_ISR_UB	0x0004
+#define I2C_ISR_ITE	0x0040
+#define I2C_ISR_IRF	0x0080
+#define I2C_ISR_ACK	0x0002
+#define I2C_ISR_IBB	0x0008
+//#define I2C_ISR_
+
+#define I2C_ICR_ALDIE	0x1000
+#define I2C_ICR_SADIE	0x2000
+#define I2C_ICR_SSDIE	0x0800
+#define I2C_ICR_BEIE	0x0400
+#define I2C_ICR_IRFIE	0x0200
+#define I2C_ICR_ITEIE	0x0100
+#define I2C_ICR_IUE		0x0040
+#define I2C_ICR_SCLE	0x0020
+#define I2C_ICR_TB		0x0008
+#define I2C_ICR_STOP	0x0002
+#define I2C_ICR_START	0x0001
+#define I2C_ICR_MA		0x0010
+#define I2C_ICR_IRF		0x0200
+#define I2C_ICR_ACK		0x0004
+#define I2C_ICR_UR		0x4000
+#define I2C_ICR_FM		0x8000
Index: linux-2.6.11-rc2/sound/oss/Kconfig
===================================================================
--- linux-2.6.11-rc2.orig/sound/oss/Kconfig	2005-01-22 01:48:48.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/Kconfig	2005-01-28 15:42:49.340280472 +0000
@@ -809,6 +809,10 @@
 	  Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file,
 	  starting from /.
 
+config SOUND_CORGI
+	tristate "Sound on the Sharp SL-C7xx Series"
+	depends on SOUND_OSS
+
 config SOUND_SB
 	tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support"
 	depends on SOUND_OSS
Index: linux-2.6.11-rc2/sound/oss/pxa-audio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/pxa-audio.h	2005-01-28 15:42:49.341280320 +0000
@@ -0,0 +1,55 @@
+/*
+ *  linux/drivers/sound/pxa-audio.h -- audio interface for the Cotula chip
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	Aug 15, 2001
+ *  Copyright:	MontaVista Software Inc.
+ *
+ *  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.
+ */
+
+typedef struct {
+	int offset;			/* current buffer position */
+	char *data; 	           	/* actual buffer */
+	pxa_dma_desc *dma_desc;	/* pointer to the starting desc */
+	int master;             	/* owner for buffer allocation, contain size whn true */
+} audio_buf_t;
+
+typedef struct {
+	char *name;			/* stream identifier */
+	audio_buf_t *buffers;   	/* pointer to audio buffer array */
+	u_int usr_frag;			/* user fragment index */
+	u_int dma_frag;			/* DMA fragment index */
+	u_int fragsize;			/* fragment size */
+	u_int nbfrags;			/* number of fragments */
+	u_int dma_ch;			/* DMA channel number */
+	dma_addr_t dma_desc_phys;	/* phys addr of descriptor ring */
+	u_int descs_per_frag;		/* nbr descriptors per fragment */
+	int bytecount;			/* nbr of processed bytes */
+	int fragcount;			/* nbr of fragment transitions */
+	struct semaphore sem;		/* account for fragment usage */
+	wait_queue_head_t frag_wq;	/* for poll(), etc. */
+	wait_queue_head_t stop_wq;	/* for users of DCSR_STOPIRQEN */
+	u_long dcmd;			/* DMA descriptor dcmd field */
+	volatile u32 *drcmr;		/* the DMA request channel to use */
+	u_long dev_addr;		/* device physical address for DMA */
+	int mapped:1;			/* mmap()'ed buffers */
+	int output:1;			/* 0 for input, 1 for output */
+} audio_stream_t;
+	
+typedef struct {
+	audio_stream_t *output_stream;
+	audio_stream_t *input_stream;
+	int dev_dsp;			/* audio device handle */
+	int rd_ref:1;           /* open reference for recording */
+	int wr_ref:1;           /* open reference for playback */
+	int (*client_ioctl)(struct inode *, struct file *, uint, ulong);
+	struct semaphore sem;		/* prevent races in attach/release */
+} audio_state_t;
+
+extern int pxa_audio_attach(struct inode *inode, struct file *file,
+				audio_state_t *state);
+extern void pxa_audio_clear_buf(audio_stream_t *s);
+
Index: linux-2.6.11-rc2/sound/oss/poodle_i2sc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/poodle_i2sc.c	2005-01-28 15:46:23.096784544 +0000
@@ -0,0 +1,317 @@
+/*
+ * linux/drivers/sound/poodle_i2sc.c
+ *
+ * I2C,I2S funstions for PXA (SHARP)
+ *
+ * Copyright (C) 2002  SHARP
+ *
+ * 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.
+ *
+ * Change Log
+ *
+ *
+*/
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/arch/hardware.h>
+#include <asm/mach/arch.h>
+#include "i2sc.h"
+
+#include "poodle_i2sc.h"
+#include <asm/arch/pxa-regs.h>
+
+/*** Some declarations ***********************************************/
+#define MY_TRACE	0
+
+#define DBG_ALWAYS	0
+#define DBG_LEVEL1	1
+#define DBG_LEVEL2	2
+#define DBG_LEVEL3	3
+
+#ifdef MY_TRACE
+#define I2C_DBGPRINT(level, x, args...)  if ( level <= MY_TRACE ) printk("%s: " x,__FUNCTION__ ,##args)
+#define I2S_DBGPRINT(level, x, args...)  if ( level <= MY_TRACE ) printk("%s: " x,__FUNCTION__ ,##args)
+#else
+#define I2C_DBGPRINT(level, x, args...)  if ( !level ) printk("%s: " x,__FUNCTION__ ,##args)
+#define I2S_DBGPRINT(level, x, args...)  if ( !level ) printk("%s: " x,__FUNCTION__ ,##args)
+#endif
+
+
+#define TRANSMIT_TIMEOUT	5	// 50msec
+#define RECIEVE_TIMEOUT		5	// 50msec
+
+#define ERR_SEND1		0x01
+#define ERR_SEND2		0x02
+#define ERR_SEND3		0x04
+/*** Some valiables **************************************************/
+static unsigned char isInUseI2C;
+static unsigned char isInUseI2S;
+
+
+
+/*** Open & Close ******************************************************/
+int i2c_open(unsigned char address)
+{
+  if ( isInUseI2C ) {
+    I2C_DBGPRINT( DBG_ALWAYS, "i2c device is busy now !\n");
+    return -EBUSY;
+  }
+
+  isInUseI2C = address;
+
+
+  CKEN |= CKEN14_I2C;		// clock enable
+
+  ICR = ICR_UR;		// Reset I2C Controler
+
+  mdelay(1);
+
+  ISAR = address+1;		// initialize SAR
+
+  //  CKEN |= CKEN14_I2C;		// clock enable
+
+  ICR = (ICR_IUE | ICR_SCLE);	// Setup
+  //  ICR |= ICR_FM;	// Set to FAST mode
+
+  return 0;
+}
+
+
+int i2c_close(unsigned char address)
+{
+  if ( isInUseI2C != address ) {
+    I2C_DBGPRINT(DBG_ALWAYS, "mismatch !\n");
+    return -EBUSY;
+  }
+
+  isInUseI2C = FALSE;
+
+  ICR = ICR_UR;		// Reset I2C Controler
+  ISR = 0;			// clear all ISR
+
+  // disable all I2C interrupts
+  ICR &= ~( ICR_SADIE | ICR_ALDIE | ICR_SSDIE | ICR_BEIE | ICR_IRFIE | ICR_ITEIE );
+
+  ISAR = 0x00;		// initialize SAR
+
+  CKEN &= ~CKEN14_I2C;		// clock disable
+
+  return 0;
+}
+
+#define SADIV_MASK	( 0x7f )
+
+int i2s_open(unsigned char id, unsigned int freq)
+{
+  int div;
+
+  if ( isInUseI2S ) {
+    I2S_DBGPRINT(DBG_ALWAYS, "i2s device is busy now !\n");
+    return -EBUSY;
+  }
+
+  //if ( freq == 8000 ) freq = 48000;
+
+  freq /= 1000;			// calc sampling freq.
+  if ( ( freq > 48 ) || ( freq < 8 ) ) return -EINVAL;
+  div = ( 147600 / ( freq*64*4 ) );
+
+  I2S_DBGPRINT(DBG_LEVEL2 , "div = %x\n",div);
+
+  isInUseI2S = id;
+
+  CKEN |= CKEN8_I2S;		// clock enable
+
+  SACR0 |= SACR0_RST;	// reset
+  SACR0 &= ~SACR0_ENB;	// disable module
+  SACR0 &= ~SACR0_RST;
+
+  SACR0 |= SACR0_BCKD;	// output BITCLK
+  SACR0 |= 0x7700;
+  SACR0 &= ~( SACR0_EFWR | SACR0_STRF );
+
+  SADR = 0x0000;
+  SADIV = ( div & SADIV_MASK );
+  SACR1 &= ~( SACR1_AMSL | SACR1_DREC | SACR1_DRPL | SACR1_ENLBF );
+
+  SACR0 |= SACR0_ENB;	// enable module
+
+  return 0;
+}
+
+
+int i2s_close(unsigned char id)
+{
+
+  if ( isInUseI2S != id ) {
+    I2S_DBGPRINT(DBG_ALWAYS, "mismatch !\n");
+    return -EBUSY;
+  }
+
+  isInUseI2S = FALSE;
+
+  SACR0 |= SACR0_RST;	// reset
+  SACR0 &= ~SACR0_ENB;	// disable module
+  SACR0 &= ~SACR0_RST;
+
+  CKEN &= ~CKEN8_I2S;		// clock disable
+
+  return 0;
+}
+
+
+/*** write & read  ******************************************************/
+int i2c_byte_write(unsigned char DeviceAdr,unsigned char RegisterAdr,unsigned char Data)
+{    	  
+	long start_time;
+	long err = 0;
+
+	udelay(20);
+
+	ICR |= ICR_SCLE;
+	ICR |= ICR_IUE;
+	ISR = ISR_ITE;
+
+	I2S_DBGPRINT(DBG_LEVEL2, "i2c_byte_write adr(%8x),reg(%8x),data(%8x)\n",DeviceAdr,RegisterAdr,Data);
+
+	//
+	// Send First Byte
+	//
+	IDBR = ( DeviceAdr << 1 );	// set data
+					// We have to set device , so we have to shift 1 bit.
+
+	ICR |= ICR_START;	// first data,  start = on, stop = off
+	ICR &= ~ICR_STOP;
+	ICR &= ~ICR_ALDIE;	// clear ALDIE
+	ICR |= ICR_TB;		// clear TB , transfer data !
+
+	start_time = jiffies;
+	while (1) {
+	  //schedule();
+	  if( !(ISR & ISR_RWM ) && (ISR & ISR_UB) && (ISR & ISR_ITE) ) {
+	    break;	// IDBR Transmit Empty = 1 and Unit Busy = 1 and R/nW = 0 , so break
+	  }
+	  if ( ( jiffies - start_time ) > TRANSMIT_TIMEOUT ) {
+	    I2C_DBGPRINT(DBG_ALWAYS, "time out1 %x\n",ISR);
+	    I2S_DBGPRINT(DBG_LEVEL1, "i2c_byte_write adr(%8x),reg(%8x),data(%8x)\n",DeviceAdr,RegisterAdr,Data);
+	    err |= ERR_SEND1;
+	    break;
+	  }
+	}
+	ISR = ISR_ITE;		// clear interrupt
+
+
+	//
+	// Send Second Byte
+	//
+	IDBR = RegisterAdr;		// set data	
+
+	ICR |= ICR_ALDIE;
+	ICR &= ~ICR_STOP;	// second data, start = off, stop = off
+	ICR &= ~ICR_START;
+	ICR |= ICR_TB;		// clear TB , transfer data !
+
+	start_time = jiffies;
+	while (1) {
+	  //schedule();
+	  if( !(ISR & ISR_RWM ) && (ISR & ISR_UB) && (ISR & ISR_ITE) ) {
+	    break;	// IDBR Transmit Empty = 1 and Unit Busy = 1 and R/nW = 0 , so break
+	  }
+	  if ( ( jiffies - start_time ) > TRANSMIT_TIMEOUT ) {
+	    I2C_DBGPRINT(DBG_ALWAYS, "time out2 %x\n",ISR);
+	    I2S_DBGPRINT(DBG_LEVEL1, "i2c_byte_write adr(%8x),reg(%8x),data(%8x)\n",DeviceAdr,RegisterAdr,Data);
+	    err |= ERR_SEND2;
+	    break;
+	  }
+	}
+	ISR = ISR_ITE;		// clear interrupt
+
+
+	//
+	// Send Third Byte
+	//
+	IDBR = Data;		// set data
+
+	ICR |= ICR_ALDIE;
+	ICR &= ~ICR_START;	// second data, start = off, stop = on
+	ICR |= ICR_STOP;
+	ICR |= ICR_TB;		// clear TB , transfer data !
+
+	start_time = jiffies;
+	while (1) {
+	  //schedule();
+	  if( !(ISR & ISR_RWM ) && (ISR & ISR_ITE) ) {
+	    break;	// IDBR Transmit Empty = 1 and R/nW = 0 , so break
+	  }
+	  if ( ( jiffies - start_time ) > TRANSMIT_TIMEOUT ) {
+	    I2C_DBGPRINT(DBG_ALWAYS, "time out3 %x\n",ISR);
+	    I2S_DBGPRINT(DBG_LEVEL1, "i2c_byte_write adr(%8x),reg(%8x),data(%8x)\n",DeviceAdr,RegisterAdr,Data);
+	    err |= ERR_SEND3;
+	    break;
+	  }
+	}
+	ISR = ISR_ITE;		// clear interrupt
+
+
+	ICR &= ~ICR_START;
+	ICR &= ~ICR_STOP;
+	ICR &= ~ICR_ALDIE;
+	ICR &= ~ICR_TB;
+
+#if 0
+	ICR &= ~ICR_IUE;
+	ICR &= ~ICR_SCLE;
+#endif	
+	return err;
+}
+
+
+/*** Config & Setup ******************************************************/
+int i2c_init(void)
+{
+  isInUseI2C = FALSE;
+
+  ICR = ICR_UR;		// Reset I2C Controler
+  ISR = 0;			// clear all ISR
+  ICR = 0;			// 
+
+  // disable all I2C interrupts
+  ICR &= ~( ICR_SADIE | ICR_ALDIE | ICR_SSDIE | ICR_BEIE | ICR_IRFIE | ICR_ITEIE );
+
+  ISAR = 0x00;		// initialize SAR
+
+  CKEN &= ~CKEN14_I2C;		// clock disable
+
+  return 0;
+}
+
+
+
+void i2c_suspend(void)
+{
+  ICR = ICR_UR;		// Reset I2C Controler
+  ISR = 0;			// clear all ISR
+
+  // disable all I2C interrupts
+  ICR &= ~( ICR_SADIE | ICR_ALDIE | ICR_SSDIE | ICR_BEIE | ICR_IRFIE | ICR_ITEIE );
+
+  ISAR = 0x00;		// initialize SAR
+
+  CKEN &= ~CKEN14_I2C;		// clock disable
+}
+
+
+void i2c_resume(void)
+{
+  i2c_init();
+}
Index: linux-2.6.11-rc2/sound/oss/poodle_wm8731.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/poodle_wm8731.c	2005-01-28 15:46:08.004078984 +0000
@@ -0,0 +1,696 @@
+/*
+ * linux/drivers/sound/poodle_wm8731.c
+ *
+ * wm8731 ctrl funstions for PXA (SHARP)
+ *
+ * Copyright (C) 2002  SHARP
+ *
+ * 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.
+ *
+ * Change Log
+ *
+ *
+*/
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/arch/hardware.h>
+#include <asm/mach/arch.h>
+//#include <asm/arch/i2sc.h>
+
+#include "poodle_audio.h"
+#include "poodle_wm8731.h"
+#include "poodle_i2sc.h"
+
+//#include <asm/sharp_apm.h>
+
+
+/*** Some declarations ***********************************************/
+#define MY_TRACE	0
+
+#define DBG_ALWAYS	0
+#define DBG_LEVEL1	1
+#define DBG_LEVEL2	2
+#define DBG_LEVEL3	3
+
+#ifdef MY_TRACE
+#define WM8731_DBGPRINT(level, x, args...)  if ( level <= MY_TRACE ) printk("%s: " x,__FUNCTION__ ,##args)
+#else
+#define WM8731_DBGPRINT(level, x, args...)  if ( !level ) printk("%s: " x,__FUNCTION__ ,##args)
+#endif
+
+#define OPEN_WAIT_CNT		10	// wwait time for i2c open.
+#define WM8731_I2C_ADDRESS	(unsigned char)0x01
+
+/*** Some valiables **************************************************/
+static int isInUseWM8731;
+unsigned short WM8731Regs[WM8731_REG_NUM];	// Except ResetReg
+
+
+#ifdef CONFIG_SOUND_CORGI
+extern int corgi_HPstatus;
+
+unsigned int wm8731_volume_in_HP[31] = {
+    0,  65,  90,  94,  97, 100, 101, 102, 103, 104, 105, 106, 107, 107, 108,
+  108, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 117
+};
+
+unsigned int wm8731_volume_out_HP[31] = {
+    0,  50,  65,  70,  75,  80,  84,  87,  90,  92,  94,  95,  97,  99, 100,
+  102, 104, 106, 108, 110, 111, 112, 113, 115, 116, 118, 120, 122, 125, 127
+};
+
+#else
+
+unsigned int wm8731_volume_in_HP[31] = {
+    0,  40,  48,  55,  61,  66,  70,  74,  78,  81,  84,  86,  89,  91,  94,
+   96,  98, 100, 101, 103, 105, 106, 108, 109, 111, 112, 113, 115, 116, 117
+};
+
+unsigned int wm8731_volume_out_HP[31] = {
+    0,  50,  58,  65,  71,  76,  80,  84,  88,  91,  94,  96,  99, 101, 104,
+  106, 108, 110, 111, 113, 115, 116, 118, 119, 121, 122, 123, 125, 126, 127
+};
+#endif
+
+static int wm8731_i2c_open(void);
+static void wm8731_i2c_write(unsigned char,unsigned short);
+static void wm8731_i2c_close(void);
+static int wm8731_setup(SOUND_SETTINGS *);
+static int wm8731_set_hp_vol_shadowreg(int,int);
+static int wm8731_set_linein_vol_shadowreg(int,int);
+static int wm8731_set_mic_boost_shadowreg(int);
+static void wm8731_set_mic_gain_boost_reg(unsigned char);
+static void wm8731_set_volume_reg(int,unsigned char);
+static int wm8731_set_input_volume(int,int);
+static void wm8731_set_freq_shadowreg(int freq);
+
+
+/*** Config & Setup ******************************************************/
+int wm8731_busy(void)
+{
+  return isInUseWM8731;
+}
+
+int wm8731_init(void)
+{
+  int i;
+  int err = 0;
+
+  isInUseWM8731 = FALSE;
+
+  for(i=0;i<WM8731_REG_NUM;i++)
+    WM8731Regs[i] = 0;
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+  wm8731_i2c_write(WM8731_ResetReg_ADR, 0);					// reset WM8731
+  mdelay(1);
+  wm8731_i2c_write(WM8731_PowDownCtl_ADR, ( PD_OSC | PD_CLK | PD_DAC | PD_ADC | PD_MIC | PD_LIN | PD_OUT )); // Power Down WM8731
+  wm8731_i2c_close();
+
+  return 0;
+}
+
+/*** I2C ctrl ************************************************************/
+static int wm8731_i2c_open(void)
+{
+  int err = 0,cnt = 0;
+  int start_time;
+
+  //  i2c_init();
+
+  while(1) {
+    err = i2c_open(WM8731_I2C_ADDRESS);
+    if ( !err ) break;
+    start_time = jiffies;
+    while (1) {
+      schedule();
+      if ( start_time - jiffies > 2 ) break;
+    }
+    cnt++;
+    if ( cnt > OPEN_WAIT_CNT ) {
+      return err;
+    } 
+  }
+  return err;
+}
+
+static void wm8731_i2c_write(unsigned char oreg, unsigned short odata)
+{
+  unsigned char adr,data;
+
+  adr = ( (oreg << 1) | ( (odata >> 8) & 1 ) );
+  data = odata & 0xff;
+  if ( i2c_byte_write( WM8731_DEVICE , adr, data ) ) {
+    WM8731_DBGPRINT( DBG_LEVEL1 , "i2c write error, retry !");
+    if ( i2c_byte_write( WM8731_DEVICE , adr, data ) ) {
+      WM8731_DBGPRINT( DBG_LEVEL1 , "error");
+    } else {
+      WM8731_DBGPRINT( DBG_LEVEL1 , "OK");
+    }
+  }
+
+}
+
+static void wm8731_i2c_close(void)
+{
+  i2c_close(WM8731_I2C_ADDRESS);
+}
+
+
+/*** Open & Close ******************************************************/
+
+int wm8731_open(SOUND_SETTINGS *settings)
+{
+  int i, err = 0;
+
+
+  WM8731_DBGPRINT(DBG_LEVEL2, "wm8731 open\n");
+
+  if ( isInUseWM8731 ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "wm8731 device is busy now !\n");
+    return -EBUSY;
+  }
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+
+  isInUseWM8731 = TRUE;
+
+  //lock_FCS(LOCK_FCS_SOUND, 1);
+
+  wm8731_i2c_write(WM8731_ResetReg_ADR, 0);			// reset WM8731
+  if ( wm8731_setup(settings) ) {				// set to shadow regs.
+    wm8731_i2c_close();
+    isInUseWM8731 = FALSE;
+    return 1;
+  }
+
+
+  wm8731_i2c_write(WM8731_PowDownCtl_ADR, WM8731Regs[WM8731_PowDownCtl_ADR]);	// Power Down WM8731
+
+  for(i=0;i<WM8731_REG_NUM;i++) {
+    if ( i == WM8731_PowDownCtl_ADR ) continue;	// PowerDown reg skip.
+    wm8731_i2c_write(i, WM8731Regs[i]);
+  }
+
+  // active
+  wm8731_i2c_write(WM8731_ActiveCtl_ADR, ( WM8731Regs[WM8731_ActiveCtl_ADR] | DIGITAL_IF_ACTIVE ) );
+
+  wm8731_i2c_close();
+
+
+
+  return 0;
+}
+
+
+int wm8731_close(void)
+{
+  int err;
+
+  WM8731_DBGPRINT(DBG_LEVEL2 ,"wm8731 close\n");
+
+  err = wm8731_suspend();
+
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not suspend wm8731\n");
+    return err;
+  }
+
+  isInUseWM8731 = FALSE;
+
+  //lock_FCS(LOCK_FCS_SOUND, 0);
+
+
+  return 0;
+}
+
+/*** Setup ***********************************************************/
+static const unsigned short CODEC_SETTINGS_PLAY[WM8731_REG_NUM] = {
+#if 1
+  ( INPUT_MUTE_ON | INIT_LINE_VOL ),
+  ( INPUT_MUTE_ON | INIT_LINE_VOL ),
+  ( INIT_HP_VOL ),
+  ( INIT_HP_VOL ),
+#else
+  ( SIMUL_UPDATE | INPUT_MUTE_ON | INIT_LINE_VOL ),
+  ( SIMUL_UPDATE | INPUT_MUTE_ON | INIT_LINE_VOL ),
+  ( SIMUL_UPDATE | INIT_HP_VOL ),
+  ( SIMUL_UPDATE | INIT_HP_VOL ),
+#endif
+  ( DAC_SELECT | SIDETONE_DISABLE | BYPASS_DISABLE | INPUT_LINE | MIC_MUTE_ON | MIC_BOOST_OFF ),
+  ( DPC_DAC_MUTE_OFF | DEEMPHASIS_MODE(0) | DPC_ADC_HPF_DISABLE ),
+  ( PD_OSC | PD_CLK | PD_ADC | PD_MIC | PD_LIN ),
+  ( SLAVE | LRSWAP_DISABLE | LRP_RIGHT_HIGH | IWL_16BIT | I2S_MODE ),
+  ( SRC_BOTH_44KHZ | SRC_OSR_256FS | SRC_NORMAL_MODE )
+};
+
+static const unsigned short CODEC_SETTINGS_REC[WM8731_REG_NUM] = {
+#if 1
+  ( INIT_LINE_VOL ),
+  ( INIT_LINE_VOL ),
+  ( INIT_HP_VOL ),
+  ( INIT_HP_VOL ),
+#else
+  ( SIMUL_UPDATE | INIT_LINE_VOL ),
+  ( SIMUL_UPDATE | INIT_LINE_VOL ),
+  ( SIMUL_UPDATE | INIT_HP_VOL ),
+  ( SIMUL_UPDATE | INIT_HP_VOL ),
+#endif
+  ( DAC_OFF | SIDETONE_DISABLE | BYPASS_DISABLE | INPUT_LINE | MIC_MUTE_ON | MIC_BOOST_ON ),
+  ( DPC_DAC_MUTE_OFF | DEEMPHASIS_MODE(0) | DPC_ADC_HPF_DISABLE ),
+  ( PD_OSC | PD_CLK | PD_DAC | PD_MIC ),
+  ( SLAVE | LRSWAP_DISABLE | LRP_RIGHT_HIGH | IWL_16BIT | I2S_MODE ),
+  ( SRC_BOTH_44KHZ | SRC_OSR_256FS | SRC_NORMAL_MODE )
+};
+
+static int wm8731_setup(SOUND_SETTINGS  *setting)
+{
+  int i, ret = 0;
+
+
+  if( setting == NULL ) return -1;
+
+  if ( !isInUseWM8731 ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "not opend !\n");
+    return -EINVAL;
+  }
+
+  switch( setting->mode&SOUND_MODE_MASK ){
+  case SOUND_PLAY_MODE:
+    // Copy initial value
+    for(i=0;i<WM8731_REG_NUM;i++)
+      WM8731Regs[i] = CODEC_SETTINGS_PLAY[i];
+    break;
+
+  case SOUND_REC_MODE:
+    {
+      // Copy initial value
+      for(i=0;i<WM8731_REG_NUM;i++)
+	WM8731Regs[i] = CODEC_SETTINGS_REC[i];
+
+      WM8731Regs[WM8731_AnalogAudioPath_ADR] &= ~MIC_MUTE_ON;
+      WM8731Regs[WM8731_AnalogAudioPath_ADR] |= INPUT_MIC;
+      WM8731Regs[WM8731_PowDownCtl_ADR] &= ~PD_MIC;
+      WM8731Regs[WM8731_PowDownCtl_ADR] |= PD_LIN;
+
+      // enable play , because we have to play while recording.
+      WM8731Regs[WM8731_AnalogAudioPath_ADR] |= DAC_SELECT;
+      WM8731Regs[WM8731_PowDownCtl_ADR] &= ~PD_DAC;
+	break;
+    }
+
+  default:
+    return -1;
+  }
+
+  wm8731_set_hp_vol_shadowreg(WM8731_LeftHdpOut_ADR, setting->output.left);	// vol setting
+  wm8731_set_hp_vol_shadowreg(WM8731_RightHdpOut_ADR, setting->output.right);
+
+  wm8731_set_linein_vol_shadowreg(WM8731_LeftLineIn_ADR, setting->input.left);	// vol setting
+  wm8731_set_linein_vol_shadowreg(WM8731_RightLineIn_ADR, setting->input.right);
+
+  wm8731_set_freq_shadowreg(setting->frequency);
+
+  return ret;
+}
+
+
+/*** Volume ***********************************************************/
+// for Output
+// update shadow regs.
+static int wm8731_set_hp_vol_shadowreg(int adr, int vol)
+{
+  unsigned short reg,volume;
+  int state;
+        
+  if ( vol == VOLUME_MUTE ) {
+    // mute
+    vol = 0;
+  }
+
+  if ( ( vol < 0 ) || ( vol > 100 ) ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "incorrect volume setting !\n");
+    return 0;
+  }
+
+  //  WM8731_DBGPRINT(DBG_ALWAYS, "vol(%d) = %d\n", ( ( 29 * vol ) / 100 ) ,vol);
+
+
+#ifdef CONFIG_SOUND_CORGI
+  state = corgi_HPstatus;
+#else
+  state = GPLR(GPIO_HP_IN) & GPIO_bit(GPIO_HP_IN);
+#endif
+
+  if ( !state ) { 	// Insert HP
+    vol = wm8731_volume_in_HP[ ( ( 29 * vol ) / 100 ) ];
+  } else {
+    vol = wm8731_volume_out_HP[ ( ( 29 * vol ) / 100 ) ];
+  }
+
+
+  if( ( vol >= MIN_HP_VOL ) && ( vol <= MAX_HP_VOL ) ) {
+    // set volume to shadow regs.
+    reg = WM8731Regs[adr];
+    volume = reg & HP_VOL_MASK;
+    if (volume != vol) {
+      reg = ( reg & ~HP_VOL_MASK ) | vol;
+      WM8731Regs[adr] = reg;
+      return 1;
+    }
+  } else {
+    // ignore
+  }
+
+  return 0;
+}
+
+// for Input
+// update shadow regs.
+static int wm8731_set_linein_vol_shadowreg(int adr, int vol)
+{
+  unsigned short reg,volume;
+       
+  if( vol == VOLUME_MUTE ) {
+    // mute
+    reg = WM8731Regs[adr];
+    if( !( reg & INPUT_MUTE_ON ) ) {
+      reg |= INPUT_MUTE_ON;
+      WM8731Regs[adr] = reg;
+      return 1;
+    }
+  } else if ( ( vol >= MIN_LINE_VOL ) && ( vol <= MAX_LINE_VOL ) ) {
+                // set volume
+    reg = WM8731Regs[adr];
+    volume = reg & LINE_VOL_MASK;
+    if ( ( reg & INPUT_MUTE_ON ) || ( volume != vol ) ) {
+      reg = ( reg & ~( INPUT_MUTE_ON | LINE_VOL_MASK ) ) | vol;
+      WM8731Regs[adr] = reg;
+      return 1;
+    }
+  } else {
+     // ignore
+  }
+  return 0;
+
+}
+
+
+// for MIC
+// update shadow regs.
+static int wm8731_set_mic_boost_shadowreg(int on)
+{
+  unsigned short reg;
+
+  reg = WM8731Regs[WM8731_AnalogAudioPath_ADR];
+
+  if ( on ) {
+    if ( reg & MIC_BOOST_ON ) {
+      return 0;			// already on
+    } else {
+      WM8731Regs[WM8731_AnalogAudioPath_ADR] |= MIC_BOOST_ON;
+      return 1;			// set to on
+    }
+  } else {
+    if ( reg & MIC_BOOST_ON ) {
+      WM8731Regs[WM8731_AnalogAudioPath_ADR] &= ~MIC_BOOST_ON;
+      return 1;			// set to off
+    } else {
+      return 0;			// already off
+    }
+  }
+
+}
+
+// for Freq.
+static void wm8731_set_freq_shadowreg(int freq)
+{
+  switch (freq) {
+  case 8000:
+      WM8731Regs[WM8731_SamplingCtl_ADR] = ( SRC_BOTH_48KHZ | SRC_OSR_256FS | SRC_NORMAL_MODE );
+      //WM8731Regs[WM8731_SamplingCtl_ADR] = ( SRC_BOTH_8KHZ | SRC_OSR_256FS | SRC_NORMAL_MODE );
+      break;
+
+  case 44100:
+      WM8731Regs[WM8731_SamplingCtl_ADR] = ( SRC_BOTH_44KHZ | SRC_OSR_256FS | SRC_NORMAL_MODE );
+      break;
+
+  case 48000:
+      WM8731Regs[WM8731_SamplingCtl_ADR] = ( SRC_BOTH_48KHZ | SRC_OSR_256FS | SRC_NORMAL_MODE );
+      break;
+
+  default:
+      WM8731Regs[WM8731_SamplingCtl_ADR] = ( SRC_BOTH_44KHZ | SRC_OSR_256FS | SRC_NORMAL_MODE );
+      break;
+  }
+
+}
+
+/**********************************/
+// for Output/Input
+// update wm8731 regs.
+static void wm8731_set_volume_reg(int adr, unsigned char modify)
+{
+  int i;
+  unsigned char mask;
+
+  mask = 0x01;
+
+  for( i=0;i<2;i++ ) {
+    if( modify & mask ) {
+      wm8731_i2c_write( adr+i , WM8731Regs[adr+i] );
+    }
+    mask <<= 1;
+  }
+  return;
+
+}
+
+
+// update wm8731 regs.
+static void wm8731_set_mic_gain_boost_reg(unsigned char modify)
+{
+  if( modify ) {
+    wm8731_i2c_write( WM8731_AnalogAudioPath_ADR , WM8731Regs[WM8731_AnalogAudioPath_ADR] );
+  }
+
+  return;
+}
+
+
+/**********************************/
+int wm8731_set_output_volume(int left, int right)
+{
+  unsigned char modify;
+  int err;
+
+        
+  if ( !isInUseWM8731 ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "not opened !\n");
+    return -EINVAL;
+  }
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+
+  modify = 0;
+
+  // Left volume
+  if( wm8731_set_hp_vol_shadowreg(WM8731_LeftHdpOut_ADR, left) != 0 ) {
+    modify |= 0x01;
+  }
+
+  // Right volume
+  if( wm8731_set_hp_vol_shadowreg(WM8731_RightHdpOut_ADR, right) != 0 ) {
+    modify |= 0x02;
+  }
+
+  // Setup
+  wm8731_set_volume_reg(WM8731_LeftHdpOut_ADR, modify);
+
+  wm8731_i2c_close();
+
+  return 0;
+}
+
+
+int wm8731_set_input_volume(int left, int right)
+{
+  unsigned char modify;
+  int err = 0;
+        
+  if ( !isInUseWM8731 ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "not opened !\n");
+    return -EINVAL;
+  }
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+
+  modify = 0;
+
+  // Left volume
+  if( wm8731_set_linein_vol_shadowreg(WM8731_LeftLineIn_ADR, left) != 0 ) {
+    modify |= 0x01;
+  }
+
+  // Right volume
+  if( wm8731_set_linein_vol_shadowreg(WM8731_RightLineIn_ADR, right) != 0 ) {
+    modify |= 0x02;
+  }
+
+  // Setup
+  wm8731_set_volume_reg(WM8731_LeftLineIn_ADR, modify);
+
+  wm8731_i2c_close();
+
+  return err;
+
+}
+
+
+int wm8731_set_mic_gain_boost(int on)
+{
+  unsigned char modify;
+  int err;
+
+
+  if ( !isInUseWM8731 ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "not opend !\n");
+    return -EINVAL;
+  }
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+
+  modify = 0;
+
+  if ( wm8731_set_mic_boost_shadowreg(on) != 0 ) {
+    modify |= 0x01;
+  }
+
+  // Setup
+  wm8731_set_mic_gain_boost_reg(modify);
+
+  wm8731_i2c_close();
+
+  return err;
+}
+
+
+int wm8731_set_freq(int freq)
+{
+  int err;
+
+
+  WM8731_DBGPRINT(DBG_LEVEL2, "freq = %d\n",freq);
+
+  if ( !isInUseWM8731 ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "not opened !\n");
+    return -EINVAL;
+  }
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+
+  wm8731_set_freq_shadowreg(freq);
+
+  // Setup
+  wm8731_i2c_write( WM8731_SamplingCtl_ADR , WM8731Regs[WM8731_SamplingCtl_ADR] );
+
+  wm8731_i2c_close();
+
+  return err;
+}
+
+
+/*** Suspend/Resume  ***********************************************************/
+int wm8731_suspend(void)
+{
+  int err = 0;
+
+  if ( !isInUseWM8731 ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "not opend !\n");
+    return -EINVAL;
+  }
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+
+  // deactive
+  wm8731_i2c_write(WM8731_ActiveCtl_ADR, 0 );
+  mdelay(1);
+
+  wm8731_i2c_write(WM8731_ResetReg_ADR, 0);					// reset WM8731
+  mdelay(1);
+  wm8731_i2c_write(WM8731_PowDownCtl_ADR, ( PD_OUT ));
+  mdelay(1);
+  wm8731_i2c_write(WM8731_PowDownCtl_ADR, ( PD_OSC | PD_CLK | PD_OUT | PD_DAC | PD_ADC | PD_MIC | PD_LIN )); // Power Down WM8731
+
+  wm8731_i2c_close();
+
+  return err;
+}
+
+
+int wm8731_resume(void)
+{
+  int i, err = 0;
+
+  err = wm8731_i2c_open();
+  if ( err ) {
+    WM8731_DBGPRINT(DBG_ALWAYS, "can not open i2c device\n");
+    return err;
+  }
+
+  wm8731_i2c_write(WM8731_PowDownCtl_ADR, WM8731Regs[WM8731_PowDownCtl_ADR]);	// Power Down WM8731
+
+  for(i=0;i<WM8731_REG_NUM;i++) {
+    if ( i == WM8731_PowDownCtl_ADR ) continue;	// PowerDown reg skip.
+    wm8731_i2c_write(i, WM8731Regs[i]);
+  }
+
+  // active
+  wm8731_i2c_write(WM8731_ActiveCtl_ADR, ( WM8731Regs[WM8731_ActiveCtl_ADR] | DIGITAL_IF_ACTIVE ) );
+
+  wm8731_i2c_close();
+
+
+  return 0;
+}
Index: linux-2.6.11-rc2/sound/oss/pxa-i2s_corgi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/pxa-i2s_corgi.c	2005-01-28 15:45:33.243363416 +0000
@@ -0,0 +1,3068 @@
+/*
+ * linux/drivers/sound/pxa-i2s.c
+ *
+ * 32bit sound driver for Cotulla (SHARP)
+ *
+ * Based on pxa-audio.c
+ * Based on dmasound_iris.c (IRIS)
+ *
+ *      
+ * Copyright (C) 2002  SHARP
+ *
+ * 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.
+ *
+ * Change Log
+ *	16-Jan-2003 SHARP sleep_on -> interruptible_sleep_on
+ *	14-Apr-2003 SHARP modify resume process & buzzer device
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+
+#include <asm/mach/arch.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/dma.h>
+#include <linux/delay.h>
+
+#include "pxa-audio.h"
+
+#include "poodle_audio.h"
+#include "poodle_wm8731.h"
+#include "poodle_i2sc.h"
+
+#include <asm/arch/corgi.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware/scoop.h>
+#include <linux/pm.h>
+
+/*** Some declarations ***********************************************/
+#define MY_TRACE	0
+
+#define DBG_ALWAYS	0
+#define DBG_LEVEL1	1
+#define DBG_LEVEL2	2
+#define DBG_LEVEL3	3
+
+#ifdef MY_TRACE
+#define PXAI2S_DBGPRINT(level, x, args...)  if ( level <= MY_TRACE ) printk("%s: " x,__FUNCTION__ ,##args)
+#else
+#define PXAI2S_DBGPRINT(level, x, args...)  if ( !level ) printk("%s: " x,__FUNCTION__ ,##args)
+#endif
+
+
+#define I2SSND_CORGI		1
+
+#define SND_DEV_STATUS		6  /* /dev/sndstat   for Compatible for Collie */
+
+#define AUDIO_NBFRAGS_DEFAULT	8
+#define AUDIO_FRAGSIZE_DEFAULT	8192
+
+#define MAX_DMA_SIZE		4096
+#define DMA_DESC_SIZE		sizeof(pxa_dma_desc)
+
+#define CORGI_DEFAULT_FREQUENCY	44100
+#define CORGI_I2S_ADDRESS		(unsigned char)0x01
+
+#define IOCTL_IN(arg, ret) \
+	do { int error = get_user(ret, (int *)(arg)); \
+		if (error) return error; \
+	} while (0)
+#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
+
+#define WAIT_INIT_PLAY	( ( 2 * 1000 ) / 10 )
+#define WAIT_PLAY1	( ( 50 ) / 10 )
+#define WAIT_PLAY2	( ( 30 ) / 10 )
+
+#define AUDIO_DATA	0x00
+
+
+enum { CORGI_HP_AUDIO=0, CORGI_HP_BUZZER, CORGI_HP_SOUNDER, CORGI_HP_HP, CORGI_HP_BOTH, CORGI_HP_MIC, CORGI_HP_HEADSET};
+
+#define AUDIO_BUFFER_SETUP_NOCLEAR	1
+//#undef AUDIO_BUFFER_SETUP_NOCLEAR
+#define AUDIO_ALWAYS_SP_ON			1
+//#undef AUDIO_ALWAYS_SP_ON
+//#define AUDIO_SP_DELAY_OFF		1
+#undef AUDIO_SP_DELAY_OFF
+#define DMA_NO_INITIALIZED		1
+//#undef DMA_NO_INITIALIZED
+#define ALARM_NO_MALLOC		1
+#define BUZZER_FORCE_CLOSE		1
+
+#ifdef AUDIO_SP_DELAY_OFF
+#define AUDIO_SP_DELAY_TIME	(HZ*15)
+#endif
+
+/* default combinations */
+#define DCMD_RXPCDR	(DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
+#define DCMD_RXMCDR	(DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
+#define DCMD_TXPCDR	(DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4)
+
+/* --- for AUDIO & REMOCON device --- */
+#define HPJACK_STATE_UNDETECT		(-1)
+#define HPJACK_STATE_NONE		(0)
+#define HPJACK_STATE_HEADPHONE		(1)
+#define HPJACK_STATE_REMOCON		(2)
+
+/**** valiables **********************************************************/
+#ifdef CONFIG_PM
+static struct pm_dev* pxa_sound_pm_dev;
+#endif
+
+static ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
+static ssize_t (*ct_read_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
+
+
+static DECLARE_WAIT_QUEUE_HEAD(hp_queue);
+static void corgi_hp_thread(void *private_);
+DECLARE_WORK(hp_proc, corgi_hp_thread, NULL);
+
+
+static int isPXAI2SReady = 0;
+static int isChkHPstatus = 0;
+int corgi_HPstatus = HPJACK_STATE_UNDETECT;
+
+static int corgi_intmode = 0;
+static int corgi_intmode_speed = 0;
+static int corgi_intmode_direct = 0;
+static short *int_data = NULL ;
+static short *int_data_org = NULL ;
+#if ALARM_NO_MALLOC
+static int corgi_intmode_cur = 0;
+static int corgi_intmode_step = 0;
+#endif
+#ifdef AUDIO_SP_DELAY_OFF
+struct timer_list speaker_timers;
+#endif
+
+#ifdef BUZZER_FORCE_CLOSE
+#define WAIT_BZ_RELEASE	( ( 2 * 1000 ) / 10 )
+static int buzzer_open = 0;
+static int buzzer_close = 0;
+#endif
+
+/**** Prototype *******************************************************/
+static void CorgiInit(void);
+static int CorgiSetVolume(int);
+static int CorgiSetStereo(int);
+static int CorgiSetFormat(int);
+static int CorgiSetGain(int);
+static int CorgiGetGain(void);
+static int CorgiSetFormat(int);
+static int CorgiGetVolume(void);
+static int CorgiSetFreq(int);
+static int mixer_ioctl( struct inode *, struct file *,unsigned int, unsigned long);
+static void corgi_hp_mode(int mode);
+static void corgi_intmode_mix(unsigned char *,int);
+#ifdef CONFIG_PM
+static int CorgiPMCallBack(struct pm_dev *,pm_request_t, void *);
+#endif
+#ifdef AUDIO_BUFFER_SETUP_NOCLEAR
+static int __audio_setup_buf(audio_stream_t * s, int is_clr);
+#endif
+#ifdef AUDIO_SP_DELAY_OFF
+static void corgi_sp_delay_off(void);
+static void corgi_sounder_timer(unsigned long dummy);
+#endif
+
+
+/**** Machine definitions ************************************************/
+typedef struct {
+	ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+	ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+} TRANS;
+
+typedef struct {
+	int type;
+	void (*init)(void);
+	void (*silence)(void);
+	int (*setFormat)(int);
+	int (*setVolume)(int);
+	int (*getVolume)(void);
+	int (*setStereo)(int);
+	int (*setBass)(int);
+	int (*setTreble)(int);
+	int (*setGain)(int);
+	int (*getGain)(void);
+	int (*setFreq)(int);
+	void (*play)(void);
+} PLATFORM;
+
+static PLATFORM machCorgi = {
+	I2SSND_CORGI,		// int type
+	CorgiInit,		// void  init(void)
+	NULL,			// void  silence(void)
+	CorgiSetFormat,	// int   setFormat(int)
+	CorgiSetVolume,	// int   setVolume(int)
+	CorgiGetVolume,	// int   getVolume(void)
+	CorgiSetStereo,	// int   setStereo(int)
+	NULL,			// int   setBass(int)
+	NULL,			// int   setTreble(int)
+	CorgiSetGain,		// int   setGain(int)
+	CorgiGetGain,		// int   getGain(void)
+	CorgiSetFreq,		// int   setFreq(int)
+	NULL,			// void  play(void)
+};
+
+
+/**** /dev/ setting ********************************************/
+/*	/dev/dsp	*/
+struct sound_settings {
+  PLATFORM  mach;	/* platform dependent things */
+  TRANS *trans;		/* supported translations */
+  TRANS *trans_read;	/* supported translations */
+
+  int format;		/* AFMT_* */
+  int stereo;		/* 0 = mono, 1 = stereo */
+  int size;		/* 8/16 bit*/
+  int freq;		/* freq */
+
+  int volume_left;	/* volume (range is 0 - 100%) */
+  int volume_right;
+  int gain_left;	/* input gain (range is 0 - 100%) */
+  int gain_right;
+
+  int bass;		/* tone (not support) */
+  int treble;
+
+  /* device independ */
+  int gain_shift;	/* input gain shift */
+  int gain;		/* input gain */
+  int hw_freq;		/* hw freq */
+
+};
+static struct sound_settings sound;
+
+/*	/dev/mixer	*/
+struct sound_mixer {
+  int dev_mixer;
+  int busy;
+};
+static struct sound_mixer pxa_i2s_codec;
+
+/*	/dev/sndstat	*/
+struct sound_state {
+  int dev_state;
+  int busy;
+  char buf[512];
+  int len, ptr;
+};
+static struct sound_state pxa_i2s_state;
+
+static audio_stream_t pxa_audio_out = {
+	name:			"I2S audio out",
+	dcmd:			DCMD_TXPCDR,
+	drcmr:			&DRCMRTXSADR,
+	dev_addr:		__PREG(SADR),
+};
+
+static audio_stream_t pxa_audio_in = {
+	name:			"I2S audio in",
+	dcmd:			DCMD_RXPCDR,
+	drcmr:			&DRCMRRXSADR,
+	dev_addr:		__PREG(SADR),
+};
+
+static audio_state_t pxa_audio_state = {
+	output_stream:		&pxa_audio_out,
+	input_stream:		&pxa_audio_in,
+	sem:			__MUTEX_INITIALIZER(pxa_audio_state.sem),
+};
+
+typedef struct _input_gain_t {
+  int shift;
+  int gain;
+} input_gain_t;
+
+static input_gain_t input_gain[7] = {
+  {  1 ,  0 },
+  {  2 ,  0 },
+  {  0 ,  1 },
+  {  1 ,  1 },
+  {  2 ,  1 },
+  {  3 ,  1 },
+  {  4 ,  1 }
+};
+
+#ifdef AUDIO_SP_DELAY_OFF
+static void corgi_sp_delay_off(void)
+{
+  if ( !corgi_HPstatus ) { 	// Not Insert HP
+	  del_timer(&speaker_timers);
+	  speaker_timers.function = corgi_sounder_timer;
+	  speaker_timers.expires = jiffies + AUDIO_SP_DELAY_TIME;
+	  add_timer(&speaker_timers);
+  }
+}
+
+static void corgi_sounder_timer(unsigned long dummy)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "Sounder off\n");
+	reset_scoop_gpio( CORGI_SCP_APM_ON );
+	del_timer(&speaker_timers);
+}
+#endif
+
+// FIXME !
+/**** data convert ****************************************************/
+
+/* 16 bit mu-law */
+
+static short ulaw2dma16[] = {
+	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
+	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
+	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
+	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
+	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
+	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
+	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
+	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
+	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
+	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
+	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
+	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
+	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
+	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
+	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
+	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
+	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
+	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
+	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
+	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
+	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
+	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
+	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
+	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
+	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
+	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
+	876,	844,	812,	780,	748,	716,	684,	652,
+	620,	588,	556,	524,	492,	460,	428,	396,
+	372,	356,	340,	324,	308,	292,	276,	260,
+	244,	228,	212,	196,	180,	164,	148,	132,
+	120,	112,	104,	96,	88,	80,	72,	64,
+	56,	48,	40,	32,	24,	16,	8,	0,
+};
+
+/* 16 bit A-law */
+
+static short alaw2dma16[] = {
+	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
+	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
+	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
+	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
+	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
+	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
+	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
+	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
+	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
+	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
+	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
+	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
+	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
+	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
+	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
+	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
+	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
+	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
+	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
+	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
+	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
+	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
+	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
+	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
+	344,	328,	376,	360,	280,	264,	312,	296,
+	472,	456,	504,	488,	408,	392,	440,	424,
+	88,	72,	120,	104,	24,	8,	56,	40,
+	216,	200,	248,	232,	152,	136,	184,	168,
+	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
+	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
+	688,	656,	752,	720,	560,	528,	624,	592,
+	944,	912,	1008,	976,	816,	784,	880,	848,
+};
+
+
+static ssize_t corgi_ct_law(const u_char *userPtr, size_t userCount,
+			     u_char frame[], ssize_t *frameUsed,
+			     ssize_t frameLeft)
+{
+	short *table = sound.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = sound.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+	  u_char data;
+	  if (get_user(data, userPtr++)) {
+	    return -EFAULT;
+	  }
+	  val = table[data];
+	  *p++ = val;		/* Left Ch. */
+	  if (stereo) {
+	    if (get_user(data, userPtr++)) {
+	      return -EFAULT;
+	    }
+	    val = table[data];
+	  }
+	  *p++ = val;		/* Right Ch. */
+	  count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t corgi_ct_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+  int ch = (sound.stereo)?2:1;
+  unsigned char *src = (unsigned char *)userPtr;
+  short *dstct = (short *)frame;
+  short tmpval;
+
+  if ( sound.freq != sound.hw_freq ) {
+    int frameMax = frameLeft >> 2;
+    int arrayMax = (userCount>>(ch-1));
+    int userMax = ( arrayMax * sound.hw_freq ) / sound.freq;
+    int samplingCount = min(frameMax,userMax);
+    int whichLimit = (samplingCount==frameMax)?1:0; // which is minimum?
+    short *dstend = (short*)((int)frame+samplingCount*2*2);
+    unsigned char *srcval;
+    int idx;
+      
+    int cur=0,step = (sound.freq << 8 ) / sound.hw_freq; // fixed point (x256)
+
+    while (dstct<dstend) {
+      idx = (cur>>8);
+      if (idx>=arrayMax) {
+		  idx=arrayMax-1;
+      }
+      srcval = &src[idx*ch];
+      if (get_user(tmpval,srcval)) {
+	return -EFAULT;
+      }
+      *dstct++ = (tmpval-128)<<8;
+      if (ch>1) srcval++;
+      if (get_user(tmpval,srcval)) {
+	return -EFAULT;
+      }
+      *dstct++ = (tmpval-128)<<8;
+      cur += step;
+    }
+
+    *frameUsed = samplingCount*2*2; // // dma is always stereo 16bit
+    if (whichLimit) { // dma limit
+      return (cur>>8)*ch; // byte
+    } else { // user buffer limit
+      return userCount; // byte
+    }
+
+  } else { // hw_freq == freq
+    int frameMax = frameLeft >> 2;
+    int userMax = userCount >> (ch-1);
+    int idx,samplingCount = min(frameMax,userMax);
+
+    for (idx=0; idx<samplingCount; idx++) {
+      if (get_user(tmpval,src)) {
+	return -EFAULT;
+      }
+      *dstct++ = (tmpval-128)<<8;
+      if (ch>1) src++;
+      if (get_user(tmpval,src++)) {
+	return -EFAULT;
+      }
+      *dstct++ = (tmpval-128)<<8;
+    }
+
+    *frameUsed = samplingCount * 2 * 2; // dma is always stereo 16bit
+    return samplingCount * ch;
+  }
+}
+
+
+static ssize_t corgi_ct_s16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+  int ch = (sound.stereo)?2:1;
+  short *src = (short *)userPtr;
+  short *dstct = (short *)frame;
+
+  if ( sound.freq != sound.hw_freq ) {
+    int frameMax = frameLeft >> 2;
+    int arrayMax = (userCount>>ch);
+    int userMax = ( arrayMax * sound.hw_freq ) / sound.freq;
+    int samplingCount = min(frameMax,userMax);
+    int whichLimit = (samplingCount==frameMax)?1:0; // which is minimum?
+    short *dstend = (short*)((int)frame+samplingCount*2*2);
+    short *srcval;
+    int idx;
+      
+    int cur=0,step = (sound.freq << 8 ) / sound.hw_freq; // fixed point (x256)
+
+    while (dstct<dstend) {
+      idx = (cur>>8);
+      if (idx>=arrayMax) {
+		  idx=arrayMax-1;
+      }
+      srcval = &src[idx*ch];
+      if (get_user(*dstct++,srcval)) {
+	return -EFAULT;
+      }
+      if (ch>1) srcval++;
+      if (get_user(*dstct++,srcval)) {
+	return -EFAULT;
+      }
+      cur += step;
+    }
+
+    *frameUsed = samplingCount*2*2; // // dma is always stereo 16bit
+    if (whichLimit) { // dma limit
+      return (cur>>8)*ch*2; // byte
+    } else { // user buffer limit
+      return userCount; // byte
+    }
+
+  } else { // hw_freq == freq
+    int frameMax = frameLeft >> 2;
+    int userMax = userCount >> ch;
+    int samplingCount = min(frameMax,userMax);
+
+    if (ch>1) { // stereo
+	if (copy_from_user(dstct,src,samplingCount * ch * 2)) {
+	    return -EFAULT;
+	}
+    } else { // mono
+	int idx;
+	for (idx=0; idx<samplingCount; idx++) {
+	  if (get_user(*dstct++,src) || get_user(*dstct++,src++)) {
+	    return -EFAULT;
+	  }
+	}
+    }
+
+    *frameUsed = samplingCount * 2 * 2; // dma is always stereo 16bit
+    return samplingCount * ch * 2;
+  }
+}
+
+static TRANS transCorgi = {
+  corgi_ct_law,corgi_ct_law,0,corgi_ct_u8,
+  0,0,corgi_ct_s16,0
+};
+
+/**** data convert for recording ****************************************************/
+
+static ssize_t corgi_ct_read_u8(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+  int ch = (sound.stereo)?2:1;
+  unsigned char *usrbuf = (unsigned char *)userPtr;
+  short *dmabuf = (short *)frame;
+  short tmpval;
+
+  if ( sound.freq != sound.hw_freq ) {
+    int arrayMax = (frameLeft >> 2);
+    int dmaMax = (arrayMax * sound.freq) / sound.hw_freq; // dma is always stereo 16bit
+    int userMax = userCount >> (ch-1); // 8bit
+    int samplingCount = min(dmaMax,userMax);
+    int whichLimit = (samplingCount==dmaMax)?1:0; // which is minimum?
+    unsigned char *usrend = (unsigned char*)((int)usrbuf+samplingCount*ch);
+    short *srcval;
+    int idx;
+    int cur=0,step = (sound.hw_freq << 8 ) / sound.freq; // fixed point (x256)
+    dmaMax = frameLeft>>2; // array max index
+
+    while (usrbuf<usrend) {
+      idx = (cur>>8);
+      if (idx>=arrayMax) { // over flow?
+	idx = arrayMax-1;
+      }
+      srcval = &dmabuf[idx*2];
+      tmpval = (*srcval>>(8-sound.gain_shift));
+      if (tmpval>127) tmpval = 127;
+      else if (tmpval<-128) tmpval = -128;
+      if (put_user((unsigned char)(tmpval+128),usrbuf++)) {
+	return -EFAULT;
+      }
+      srcval++;
+      if (ch>1) {
+	tmpval = (*srcval>>(8-sound.gain_shift));
+	if (tmpval>127) tmpval = 127;
+	else if (tmpval<-128) tmpval = -128;
+	if (put_user((unsigned char)(tmpval+128),usrbuf++)) {
+	  return -EFAULT;
+	}
+      }
+      cur += step;
+    }
+    *frameUsed = (whichLimit)?(frameLeft):((cur>>8) * 2 * 2); //  dma is always stereo
+    return samplingCount * ch;
+
+  } else { // hw_freq == freq
+    int dmaMax = frameLeft >> 2; // dma is always stereo
+    int userMax = userCount >> ch;
+    int ct,samplingCount = min(dmaMax,userMax);
+
+    for (ct=0; ct<samplingCount; ct++) {
+      tmpval = (*dmabuf>>(8-sound.gain_shift));
+      if (tmpval>127) tmpval = 127;
+      else if (tmpval<-128) tmpval = -128;
+      if (put_user((unsigned char)(tmpval+128),usrbuf++)) { // left channel
+	return -EFAULT;
+      }
+      dmabuf++;
+      if (ch>1) { // right channel
+	tmpval = (*dmabuf>>(8-sound.gain_shift));
+	if (tmpval>127) tmpval = 127;
+	else if (tmpval<-128) tmpval = -128;
+	if (put_user((unsigned char)(tmpval+128),usrbuf++)) {
+	  return -EFAULT;
+	}
+      }
+      dmabuf++;
+    }
+    *frameUsed = samplingCount * 2 * 2; // dma is always stereo
+    return samplingCount * ch;
+  }
+}
+
+static ssize_t corgi_ct_read_s16(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+  int ch = (sound.stereo)?2:1;
+  short *usrbuf = (short *)userPtr;
+  short *dmabuf = (short *)frame;
+
+  if ( sound.freq != sound.hw_freq ) {
+    int arrayMax = (frameLeft >> 2);
+    int dmaMax = (arrayMax * sound.freq) / sound.hw_freq; // dma is always stereo
+    int userMax = userCount >> ch;
+    int samplingCount = min(dmaMax,userMax);
+    int whichLimit = (samplingCount==dmaMax)?1:0; // which is minimum?
+    short *usrend = (short*)((int)usrbuf+samplingCount*ch*2);
+    short *srcval;
+    int idx;
+    int cur=0,step = (sound.hw_freq << 8 ) / sound.freq; // fixed point (x256)
+    dmaMax = frameLeft>>2; // array max index
+
+    while (usrbuf<usrend) {
+      idx = (cur>>8);
+      if (idx>=arrayMax) { // over flow?
+	idx = arrayMax-1;
+      }
+      srcval = &dmabuf[idx*2];
+      if (put_user((*srcval<<sound.gain_shift),usrbuf++)) {
+	return -EFAULT;
+      }
+      srcval++;
+      if (ch>1) {
+	if (put_user((*srcval<<sound.gain_shift),usrbuf++)) {
+	  return -EFAULT;
+	}
+      }
+      cur += step;
+    }
+    *frameUsed = (whichLimit)?(frameLeft):((cur>>8) * 2 * 2); //  dma is always stereo
+    return samplingCount * ch * 2;
+
+  } else { // hw_freq == freq
+    int dmaMax = frameLeft >> 2; // dma is always stereo
+    int userMax = userCount >> ch;
+    int ct,samplingCount = min(dmaMax,userMax);
+
+    for (ct=0; ct<samplingCount; ct++) {
+      if (put_user((*dmabuf<<sound.gain_shift),usrbuf++)) { // left channel
+	return -EFAULT;
+      }
+      dmabuf++;
+      if (ch>1) { // right channel
+	if (put_user((*dmabuf<<sound.gain_shift),usrbuf++)) {
+	  return -EFAULT;
+	}
+      }
+      dmabuf++;
+    }
+    *frameUsed = samplingCount * 2 * 2; // dma is always stereo
+    return samplingCount * ch * 2;
+  }
+}
+
+static TRANS transReadCorgi = {
+  0,0,0,corgi_ct_read_u8,
+  0,0,corgi_ct_read_s16,0
+};
+
+/**** low level stuff ****************************************************/
+
+/*** Common stuff ********************************************************/
+static inline int ioctl_return(int *addr, int value)
+{
+	if (value < 0) {
+		return(value);
+	}
+	return put_user(value, addr)? -EFAULT: 0;
+}
+
+static inline void corgi_i2s_write(unsigned int data)
+{
+  if ( SASR0 & SASR0_TUR )
+    SAICR = SASR0_TUR;
+  while( ( SASR0 & SASR0_TNF ) == 0 ) {};
+  SADR = data;
+}
+
+
+/*
+ * This function frees all buffers
+ */
+#define audio_clear_buf pxa_audio_clear_buf
+
+void pxa_audio_clear_buf(audio_stream_t * s)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int frag;
+
+	if (!s->buffers)
+		return;
+
+	/* Ensure DMA isn't running */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&s->stop_wq, &wait);
+	DCSR(s->dma_ch) = DCSR_STOPIRQEN;
+	schedule();
+	remove_wait_queue(&s->stop_wq, &wait);
+
+	/* free DMA buffers */
+	for (frag = 0; frag < s->nbfrags; frag++) {
+		audio_buf_t *b = &s->buffers[frag];
+		if (!b->master)
+			continue;
+		dma_free_coherent(NULL,b->master,b->data,  b->dma_desc->dsadr);
+	}
+
+	/* free descriptor ring */
+	if (s->buffers->dma_desc)
+		dma_free_coherent(NULL,  
+				s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE,s->buffers->dma_desc,
+				s->dma_desc_phys);
+
+	/* free buffer structure array */
+	kfree(s->buffers);
+	s->buffers = NULL;
+}
+
+/*
+ * This function allocates the DMA descriptor array and buffer data space
+ * according to the current number of fragments and fragment size.
+ */
+static int audio_setup_buf(audio_stream_t * s)
+#ifdef AUDIO_BUFFER_SETUP_NOCLEAR
+{
+	return __audio_setup_buf(s, 1);
+}
+
+static int __audio_setup_buf(audio_stream_t * s, int is_clr)
+#endif
+{
+	pxa_dma_desc *dma_desc;
+	dma_addr_t dma_desc_phys;
+	int nb_desc, frag, i, buf_size = 0;
+	char *dma_buf = NULL;
+	dma_addr_t dma_buf_phys = 0;
+
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "Enter audio_setup buffer\n");
+
+	if (s->buffers)
+		return -EBUSY;
+
+	/* Our buffer structure array */
+	s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
+	if (!s->buffers)
+		goto err;
+	memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags);
+
+	/* 
+	 * Our DMA descriptor array:
+	 * for Each fragment we have one checkpoint descriptor plus one 
+	 * descriptor per MAX_DMA_SIZE byte data blocks.
+	 */
+	nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags;
+	dma_desc = dma_alloc_coherent(NULL,
+				    nb_desc * DMA_DESC_SIZE,
+				    &dma_desc_phys,GFP_KERNEL);
+	if (!dma_desc)
+		goto err;
+	s->descs_per_frag = nb_desc / s->nbfrags;
+	s->buffers->dma_desc = dma_desc;
+	s->dma_desc_phys = dma_desc_phys;
+	for (i = 0; i < nb_desc - 1; i++)
+		dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE;
+	dma_desc[i].ddadr = dma_desc_phys;
+
+
+	/* Our actual DMA buffers */
+	for (frag = 0; frag < s->nbfrags; frag++) {
+		audio_buf_t *b = &s->buffers[frag];
+
+		/*
+		 * Let's allocate non-cached memory for DMA buffers.
+		 * We try to allocate all memory at once.
+		 * If this fails (a common reason is memory fragmentation),
+		 * then we'll try allocating smaller buffers.
+		 */
+		if (!buf_size) {
+			buf_size = (s->nbfrags - frag) * s->fragsize;
+			do {
+				dma_buf = dma_alloc_coherent(NULL,
+							   buf_size, 
+							   &dma_buf_phys,GFP_KERNEL);
+				if (!dma_buf)
+					buf_size -= s->fragsize;
+			} while (!dma_buf && buf_size);
+			if (!dma_buf)
+				goto err;
+			b->master = buf_size;
+#ifdef AUDIO_BUFFER_SETUP_NOCLEAR
+			if( is_clr ){
+				memzero(dma_buf, buf_size);
+			}
+#else
+			memzero(dma_buf, buf_size);
+#endif
+		}
+
+		/* 
+		 * Set up our checkpoint descriptor.  Since the count 
+		 * is always zero, we'll abuse the dsadr and dtadr fields
+		 * just in case this one is picked up by the hardware
+		 * while processing SOUND_DSP_GETPTR.
+		 */
+		dma_desc->dsadr = dma_buf_phys;
+		dma_desc->dtadr = dma_buf_phys;
+		dma_desc->dcmd = DCMD_ENDIRQEN;
+		if (s->output && !s->mapped)
+			dma_desc->ddadr |= DDADR_STOP;
+		b->dma_desc = dma_desc++;
+
+		/* set up the actual data descriptors */
+		for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) {
+			dma_desc[i].dsadr = (s->output) ?
+				(dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr;
+			dma_desc[i].dtadr = (s->output) ?
+				s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE);
+			dma_desc[i].dcmd = s->dcmd |
+				((s->fragsize < MAX_DMA_SIZE) ?
+					s->fragsize : MAX_DMA_SIZE);
+
+			PXAI2S_DBGPRINT(DBG_LEVEL3, "dsadr[%8x],dtadr[%8x],dcmd[%8x]\n",
+					dma_desc[i].dsadr,dma_desc[i].dtadr,dma_desc[i].dcmd);
+
+		}
+		dma_desc += i;
+
+		/* handle buffer pointers */
+		b->data = dma_buf;
+		dma_buf += s->fragsize;
+		dma_buf_phys += s->fragsize;
+		buf_size -= s->fragsize;
+	}
+
+	s->usr_frag = s->dma_frag = 0;
+	s->bytecount = 0;
+	s->fragcount = 0;
+	sema_init(&s->sem, (s->output) ? s->nbfrags : 0);
+	return 0;
+
+err:
+	PXAI2S_DBGPRINT(DBG_ALWAYS, "unable to allocate audio memory\n ");
+	audio_clear_buf(s);
+	return -ENOMEM;
+}
+
+/*
+ * Our DMA interrupt handler
+ */
+static void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs)
+{
+	audio_stream_t *s = dev_id;
+	u_int dcsr;
+
+	dcsr = DCSR(ch);
+	DCSR(ch) = dcsr & ~DCSR_STOPIRQEN;
+
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "dcsr(ch) = %8x(%d)\n",dcsr,ch);
+
+	if (!s->buffers) {
+	  PXAI2S_DBGPRINT(DBG_ALWAYS, "I2S DMA: wow... received IRQ for channel %d but no buffer exists\n", ch);
+	  return;
+	}
+
+	if (dcsr & DCSR_BUSERR)
+	  PXAI2S_DBGPRINT(DBG_ALWAYS, "I2S DMA: bus error interrupt on channel %d\n", ch);
+
+	if (dcsr & DCSR_ENDINTR) {
+		u_long cur_dma_desc;
+		u_int cur_dma_frag;
+
+		/* 
+		 * Find out which DMA desc is current.  Note that DDADR
+		 * points to the next desc, not the current one.
+		 */
+		cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE;
+
+		/*
+		 * Let the compiler nicely optimize constant divisors into
+		 * multiplications for the common cases which is much faster.
+		 * Common cases: x = 1 + (1 << y) for y = [0..3]
+		 */
+		switch (s->descs_per_frag) {
+		case 2:  cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break;
+		case 3:  cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break;
+		case 5:  cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break;
+		case 9:  cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break;
+		default: cur_dma_frag =
+			    cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE);
+		}
+
+		/* Account for possible wrap back of cur_dma_desc above */
+		if (cur_dma_frag >= s->nbfrags)
+			cur_dma_frag = s->nbfrags - 1;
+
+		while (s->dma_frag != cur_dma_frag) {
+			if (!s->mapped) {
+				/* 
+				 * This fragment is done - set the checkpoint
+				 * descriptor to STOP until it is gets
+				 * processed by the read or write function.
+				 */
+				s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP;
+				up(&s->sem);
+			}
+			if (++s->dma_frag >= s->nbfrags)
+				s->dma_frag = 0;
+
+			/* Accounting */
+			s->bytecount += s->fragsize;
+			s->fragcount++;
+		}
+
+		/* ... and for polling processes */
+		wake_up(&s->frag_wq);
+	}
+
+	if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE))
+		wake_up(&s->stop_wq);
+}
+
+/*
+ * Validate and sets up buffer fragments, etc.
+ */
+static int audio_set_fragments(audio_stream_t *s, int val)
+{
+	if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN)
+		return -EBUSY;
+	if (s->buffers)
+		audio_clear_buf(s);
+	s->nbfrags = (val >> 16) & 0x7FFF;
+	val &= 0xffff;
+	if (val < 5)
+		val = 5;
+	if (val > 15)
+		val = 15;
+	s->fragsize = 1 << val;
+	if (s->nbfrags < 2)
+		s->nbfrags = 2;
+	if (s->nbfrags * s->fragsize > 256 * 1024)
+		s->nbfrags = 256 * 1024 / s->fragsize;
+	if (audio_setup_buf(s))
+		return -ENOMEM;
+	return val|(s->nbfrags << 16);
+}
+
+
+/*
+ * The fops functions
+ */
+
+static int audio_write(struct file *file, const char *buffer,
+		       size_t count, loff_t * ppos)
+{
+	const char *buffer0 = buffer;
+	audio_state_t *state = (audio_state_t *)file->private_data;
+	audio_stream_t *s = state->output_stream;
+	int ret = 0;
+	ssize_t uUsed, bUsed, bLeft = 0;
+	u_char *dest;
+
+
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "Enter audio_write\n");
+
+	// wait playing int sound.
+	while(corgi_intmode_direct)
+	  schedule();
+	if (s->mapped)
+		return -ENXIO;
+		
+#ifdef AUDIO_BUFFER_SETUP_NOCLEAR
+	if (!s->buffers && __audio_setup_buf(s,0))
+		return -ENOMEM;
+#else
+	if (!s->buffers && audio_setup_buf(s))
+		return -ENOMEM;
+#endif
+
+
+	while (count > 0) {
+		audio_buf_t *b = &s->buffers[s->usr_frag];
+
+
+	        PXAI2S_DBGPRINT(DBG_LEVEL3, "audio_write count = %d\n",count);
+
+		/* Grab a fragment */
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			if (down_trylock(&s->sem))
+				break;
+		} else {
+			ret = -ERESTARTSYS;
+			if (down_interruptible(&s->sem))
+				break;
+		}
+
+		/* Feed the current buffer */
+		dest = b->data + b->offset;
+		bUsed = 0;
+		bLeft = s->fragsize - b->offset;
+
+		if (ct_func) {
+		  uUsed = ct_func(buffer, count, dest, &bUsed, bLeft);
+		} else {
+		  return -EFAULT;
+		}
+
+		if ( corgi_intmode ) {
+		  corgi_intmode_mix(dest,bUsed);
+		}
+
+		if (uUsed < 0) {
+		  up(&s->sem);
+		  return -EFAULT;
+		}
+		b->offset += bUsed;
+		buffer += uUsed;
+		count -= uUsed;
+
+		if (b->offset < s->fragsize) {
+			up(&s->sem);
+			break;
+		}
+		/* 
+		 * Activate DMA on current buffer.
+		 * We unlock this fragment's checkpoint descriptor and
+		 * kick DMA if it is idle.  Using checkpoint descriptors
+		 * allows for control operations without the need for 
+		 * stopping the DMA channel if it is already running.
+		 */
+		b->offset = 0;
+		b->dma_desc->ddadr &= ~DDADR_STOP;
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(s->dma_ch) & DCSR_RUN)){
+		  DDADR(s->dma_ch) = b->dma_desc->ddadr;
+		  DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+		  DDADR(s->dma_ch) = b->dma_desc->ddadr;
+		  DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#endif
+
+		/* move the index to the next fragment */
+		if (++s->usr_frag >= s->nbfrags)
+			s->usr_frag = 0;
+	}
+
+	if ((buffer - buffer0))
+		ret = buffer - buffer0;
+	return ret;
+}
+
+
+static int audio_read(struct file *file, char *buffer,
+		      size_t count, loff_t * ppos)
+{
+	char *buffer0 = buffer;
+	audio_state_t *state = file->private_data;
+	audio_stream_t *s = state->input_stream;
+	int ret = 0;
+	ssize_t uUsed, bUsed, bLeft = 0;
+	u_char *dest;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (s->mapped)
+		return -ENXIO;
+	if (!s->buffers && audio_setup_buf(s))
+		return -ENOMEM;
+
+	while (count > 0) {
+		audio_buf_t *b = &s->buffers[s->usr_frag];
+
+		/* prime DMA */
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(s->dma_ch) & DCSR_RUN)){
+			DDADR(s->dma_ch) = 
+				s->buffers[s->dma_frag].dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(s->dma_ch) = 
+				s->buffers[s->dma_frag].dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#endif
+
+		/* Wait for a buffer to become full */
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			if (down_trylock(&s->sem))
+				break;
+		} else {
+			ret = -ERESTARTSYS;
+			if (down_interruptible(&s->sem))
+				break;
+		}
+
+		/* Grab data from current buffer */
+
+		dest = b->data + b->offset;
+		bUsed = 0;
+		bLeft = s->fragsize - b->offset;
+
+		if (ct_read_func) {
+		  uUsed = ct_read_func(buffer, count, dest, &bUsed, bLeft);
+		} else {
+		  return -EFAULT;
+		}
+
+		if (uUsed < 0) {
+		  up(&s->sem);
+		  return -EFAULT;
+		}
+		b->offset += bUsed;
+		buffer += uUsed;
+		count -= uUsed;
+
+		if (b->offset < s->fragsize) {
+			up(&s->sem);
+			break;
+		}
+
+		/* 
+		 * Make this buffer available for DMA again.
+		 * We unlock this fragment's checkpoint descriptor and
+		 * kick DMA if it is idle.  Using checkpoint descriptors
+		 * allows for control operations without the need for 
+		 * stopping the DMA channel if it is already running.
+		 */
+		b->offset = 0;
+		b->dma_desc->ddadr &= ~DDADR_STOP;
+
+		/* move the index to the next fragment */
+		if (++s->usr_frag >= s->nbfrags)
+			s->usr_frag = 0;
+	}
+
+	if ((buffer - buffer0))
+		ret = buffer - buffer0;
+	return ret;
+}
+
+
+static int audio_sync(struct file *file)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *s = state->output_stream;
+	audio_buf_t *b;
+	pxa_dma_desc *final_desc;
+	u_long dcmd_save = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped)
+		return 0;
+
+	/*
+	 * Send current buffer if it contains data.  Be sure to send
+	 * a full sample count.
+	 */
+	final_desc = NULL;
+	b = &s->buffers[s->usr_frag];
+	if (b->offset &= ~3) {
+		final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE];
+		b->offset &= (MAX_DMA_SIZE-1);
+		dcmd_save = final_desc->dcmd;
+		final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; 
+		final_desc->ddadr |= DDADR_STOP;
+		b->offset = 0;
+		b->dma_desc->ddadr &= ~DDADR_STOP;
+
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(s->dma_ch) & DCSR_RUN)){
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#endif
+	}
+
+	/* Wait for DMA to complete. */
+	set_current_state(TASK_INTERRUPTIBLE);
+#if 0
+	/* 
+	 * The STOPSTATE IRQ never seem to occur if DCSR_STOPIRQEN is set
+	 * along wotj DCSR_RUN.  Silicon bug?
+	 */
+	add_wait_queue(&s->stop_wq, &wait);
+	DCSR(s->dma_ch) |= DCSR_STOPIRQEN;
+	schedule();
+#else 
+	add_wait_queue(&s->frag_wq, &wait);
+	while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) {
+		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+#endif
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->frag_wq, &wait);
+
+	corgi_intmode = 0;
+
+	/* Restore the descriptor chain. */
+	if (final_desc) {
+		final_desc->dcmd = dcmd_save;
+		final_desc->ddadr &= ~DDADR_STOP;
+		b->dma_desc->ddadr |= DDADR_STOP;
+	}
+	return 0;
+}
+
+
+static unsigned int audio_poll(struct file *file,
+			       struct poll_table_struct *wait)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *is = state->input_stream;
+	audio_stream_t *os = state->output_stream;
+	unsigned int mask = 0;
+
+	if (file->f_mode & FMODE_READ) {
+		/* Start audio input if not already active */
+		if (!is->buffers && audio_setup_buf(is))
+			return -ENOMEM;
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(is->dma_ch) & DCSR_STOPSTATE)||
+			!(DCSR(is->dma_ch) & DCSR_RUN)){
+			DDADR(is->dma_ch) = 
+				is->buffers[is->dma_frag].dma_desc->ddadr;
+			DCSR(is->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(is->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(is->dma_ch) = 
+				is->buffers[is->dma_frag].dma_desc->ddadr;
+			DCSR(is->dma_ch) = DCSR_RUN;
+		}
+#endif
+		poll_wait(file, &is->frag_wq, wait);
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		if (!os->buffers && audio_setup_buf(os))
+			return -ENOMEM;
+		poll_wait(file, &os->frag_wq, wait);
+	}
+
+	if (file->f_mode & FMODE_READ)
+		if (( is->mapped && is->bytecount > 0) ||
+		    (!is->mapped && atomic_read(&is->sem.count) > 0))
+			mask |= POLLIN | POLLRDNORM;
+
+	if (file->f_mode & FMODE_WRITE)
+		if (( os->mapped && os->bytecount > 0) ||
+		    (!os->mapped && atomic_read(&os->sem.count) > 0))
+			mask |= POLLOUT | POLLWRNORM;
+
+	return mask;
+}
+
+
+static int audio_ioctl( struct inode *inode, struct file *file,
+			uint cmd, ulong arg)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *os = state->output_stream;
+	audio_stream_t *is = state->input_stream;
+	long val;
+	long fmt;
+	int data;
+
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE)
+			return put_user(os->fragsize, (int *)arg);
+		else
+			return put_user(is->fragsize, (int *)arg);
+
+	case SNDCTL_DSP_GETCAPS:
+		val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;
+		if (is && os)
+			val |= DSP_CAP_DUPLEX;
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (get_user(val, (long *) arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			int ret = audio_set_fragments(is, val);
+			if (ret < 0)
+				return ret;
+			ret = put_user(ret, (int *)arg);
+			if (ret)
+				return ret;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			int ret = audio_set_fragments(os, val);
+			if (ret < 0)
+				return ret;
+			ret = put_user(ret, (int *)arg);
+			if (ret)
+				return ret;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SYNC:
+		return audio_sync(file);
+
+	case SNDCTL_DSP_SETDUPLEX:
+		return 0;
+
+	case SNDCTL_DSP_POST:
+		return 0;
+
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN)
+			val |= PCM_ENABLE_INPUT;
+		if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN)
+			val |= PCM_ENABLE_OUTPUT;
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_SETTRIGGER:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			if (val & PCM_ENABLE_INPUT) {
+				if (!is->buffers && audio_setup_buf(is))
+					return -ENOMEM;
+				if (!(DCSR(is->dma_ch) & DCSR_RUN)) {
+					audio_buf_t *b = &is->buffers[is->dma_frag];
+					DDADR(is->dma_ch) = b->dma_desc->ddadr;
+					DCSR(is->dma_ch) = DCSR_RUN;
+				}
+			} else {
+				DCSR(is->dma_ch) = 0;
+			}
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT) {
+				if (!os->buffers && audio_setup_buf(os))
+					return -ENOMEM;
+				if (!(DCSR(os->dma_ch) & DCSR_RUN)) {
+					audio_buf_t *b = &os->buffers[os->dma_frag];
+					DDADR(os->dma_ch) = b->dma_desc->ddadr;
+					DCSR(os->dma_ch) = DCSR_RUN;
+				}
+			} else {
+				DCSR(os->dma_ch) = 0;
+			}
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+	    {
+		audio_buf_info inf = { 0, };
+		audio_stream_t *s = os;
+		int j,k;
+
+		if ((s == os && !(file->f_mode & FMODE_WRITE)))
+			return -EINVAL;
+		if (!s->buffers && audio_setup_buf(s))
+			return -ENOMEM;
+
+		j = s->usr_frag;
+		k = s->dma_frag;
+		if ( atomic_read(&s->sem.count) > 0  ) {
+		  if ( j > k ) {
+		    inf.fragments = s->nbfrags - ( j - k );
+		  } else if ( j < k ) {
+		    inf.fragments = k - j;
+		  } else {
+		    inf.fragments = s->nbfrags;
+		  }
+		}
+		inf.bytes = s->fragsize * inf.fragments;
+
+		inf.fragsize = s->fragsize;
+		inf.fragstotal = s->nbfrags;
+		return copy_to_user((void *)arg, &inf, sizeof(inf));
+	    }
+
+	case SNDCTL_DSP_GETISPACE:
+	    {
+		audio_buf_info inf = { 0, };
+		audio_stream_t *s = is;
+		int j,k;
+
+		if ((s == is && !(file->f_mode & FMODE_READ)))
+			return -EINVAL;
+		if (!s->buffers && audio_setup_buf(s))
+			return -ENOMEM;
+
+		j = s->usr_frag;
+		k = s->dma_frag;
+
+		if ( atomic_read(&s->sem.count) <= 0  ) {
+		    inf.fragments = 0;
+		} else {
+		    inf.fragments = atomic_read(&s->sem.count);
+		}
+
+		inf.bytes = s->fragsize * inf.fragments;
+
+		inf.fragsize = s->fragsize;
+		inf.fragstotal = s->nbfrags;
+		return copy_to_user((void *)arg, &inf, sizeof(inf));
+	    }
+
+
+
+	case SNDCTL_DSP_GETOPTR:
+	case SNDCTL_DSP_GETIPTR:
+	    {
+		count_info inf = { 0, };
+		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
+		dma_addr_t ptr;
+		int bytecount, offset;
+		unsigned long flags;
+
+		if ((s == is && !(file->f_mode & FMODE_READ)) ||
+		    (s == os && !(file->f_mode & FMODE_WRITE)))
+			return -EINVAL;
+		local_irq_save(flags); 
+		if (DCSR(s->dma_ch) & DCSR_RUN) {
+			audio_buf_t *b;
+			ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch);
+			b = &s->buffers[s->dma_frag];
+			offset = ptr - b->dma_desc->dsadr;
+			if (offset >= s->fragsize)
+				offset = s->fragsize - 4;
+		} else {
+			offset = 0;
+		}
+		inf.ptr = s->dma_frag * s->fragsize + offset;
+		bytecount = s->bytecount + offset;
+		s->bytecount = -offset;
+		inf.blocks = s->fragcount;
+		s->fragcount = 0;
+		local_irq_restore(flags);
+		if (bytecount < 0)
+			bytecount = 0;
+		inf.bytes = bytecount;
+		return copy_to_user((void *)arg, &inf, sizeof(inf));
+	    }
+
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_RESET:
+		if (file->f_mode & FMODE_WRITE) 
+			audio_clear_buf(os);
+		if (file->f_mode & FMODE_READ)
+			audio_clear_buf(is);
+		return 0;
+
+	//
+	case SNDCTL_DSP_SPEED:
+	  audio_sync(file);
+	  IOCTL_IN(arg, data);
+	  return IOCTL_OUT(arg, (*sound.mach.setFreq)(data));
+	case SNDCTL_DSP_STEREO:
+	  audio_sync(file);
+	  IOCTL_IN(arg, data);
+	  return IOCTL_OUT(arg, (*sound.mach.setStereo)(data));
+	case SOUND_PCM_WRITE_CHANNELS:
+	  audio_sync(file);
+	  IOCTL_IN(arg, data);
+	  return IOCTL_OUT(arg, (*sound.mach.setStereo)(data-1)+1);
+	case SNDCTL_DSP_SETFMT:
+	  audio_sync(file);
+	  IOCTL_IN(arg, data);
+	  return IOCTL_OUT(arg, (*sound.mach.setFormat)(data));
+	case SNDCTL_DSP_GETFMTS:
+	  fmt = 0;
+	  if (sound.trans) {
+	    if (sound.trans->ct_ulaw)
+	      fmt |= AFMT_MU_LAW;
+	    if (sound.trans->ct_alaw)
+	      fmt |= AFMT_A_LAW;
+	    if (sound.trans->ct_s8)
+	      fmt |= AFMT_S8;
+	    if (sound.trans->ct_u8)
+	      fmt |= AFMT_U8;
+	    if (sound.trans->ct_s16be)
+	      fmt |= AFMT_S16_BE;
+	    if (sound.trans->ct_u16be)
+	      fmt |= AFMT_U16_BE;
+	    if (sound.trans->ct_s16le)
+	      fmt |= AFMT_S16_LE;
+	    if (sound.trans->ct_u16le)
+	      fmt |= AFMT_U16_LE;
+	  }
+	  return IOCTL_OUT(arg, fmt);
+	//
+
+	default:
+		return mixer_ioctl(inode, file, cmd, arg);
+	}
+
+	return 0;
+}
+
+
+static int audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	audio_state_t *state = file->private_data;
+	audio_stream_t *s;
+	unsigned long size, vma_addr;
+	int i, ret;
+
+	if (vma->vm_pgoff != 0)
+		return -EINVAL;
+
+	if (vma->vm_flags & VM_WRITE) {
+		if (!state->wr_ref)
+			return -EINVAL;;
+		s = state->output_stream;
+	} else if (vma->vm_flags & VM_READ) {
+		if (!state->rd_ref)
+			return -EINVAL;
+		s = state->input_stream;
+	} else return -EINVAL;
+
+	if (s->mapped)
+		return -EINVAL;
+	size = vma->vm_end - vma->vm_start;
+	if (size != s->fragsize * s->nbfrags)
+		return -EINVAL;
+	if (!s->buffers && audio_setup_buf(s))
+		return -ENOMEM;
+	vma_addr = vma->vm_start;
+	for (i = 0; i < s->nbfrags; i++) {
+		audio_buf_t *buf = &s->buffers[i];
+		if (!buf->master)
+			continue;
+		ret = remap_pfn_range(vma, vma_addr, buf->dma_desc->dsadr >> PAGE_SHIFT,
+				       buf->master, vma->vm_page_prot);
+		if (ret)
+			return ret;
+		vma_addr += buf->master;
+	}
+	for (i = 0; i < s->nbfrags; i++)
+		s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP;
+	s->mapped = 1;
+	return 0;
+}
+
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	audio_state_t *state = file->private_data;
+	int err;
+
+
+	down(&state->sem);
+
+	//  HP & sounder & mic off
+#if (defined AUDIO_ALWAYS_SP_ON) || (defined AUDIO_SP_DELAY_OFF)
+	reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_MIC_BIAS );
+#ifdef AUDIO_SP_DELAY_OFF
+	corgi_sp_delay_off();
+#endif
+#else
+	reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON | CORGI_SCP_MIC_BIAS );
+#endif
+
+
+	if (file->f_mode & FMODE_READ) {
+		audio_clear_buf(state->input_stream);
+		*state->input_stream->drcmr = 0;
+		pxa_free_dma(state->input_stream->dma_ch);
+		state->rd_ref = 0;
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		audio_sync(file);
+		audio_clear_buf(state->output_stream);
+		*state->output_stream->drcmr = 0;
+		pxa_free_dma(state->output_stream->dma_ch);
+		state->wr_ref = 0;
+	}
+
+	// Close wm8731
+	err = wm8731_close();
+	if ( err ) {
+	  PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close wm8731\n");
+	  return err;
+	}
+
+	// Close I2S
+	err = i2s_close( CORGI_I2S_ADDRESS );
+	if ( err ) {
+	  PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+	  return err;
+	}
+
+	up(&state->sem);
+	return 0;
+}
+
+
+static int audio_open(struct inode *inode, struct file *file )
+{
+	audio_state_t  *state = &pxa_audio_state;
+	audio_stream_t *is = state->input_stream;
+	audio_stream_t *os = state->output_stream;
+	SOUND_SETTINGS settings;
+	int err;
+	int now;
+
+	while(1) {
+	  if ( isPXAI2SReady ) break;
+	  schedule();
+	}
+
+	down(&state->sem);
+
+	/* access control */
+	err = -ENODEV;
+	if ((file->f_mode & FMODE_WRITE) && !os)
+		goto out;
+	if ((file->f_mode & FMODE_READ) && !is)
+		goto out;
+	err = -EBUSY;
+
+	if ( state->wr_ref || state->rd_ref )
+#ifdef BUZZER_FORCE_CLOSE
+	  {
+	    if( !buzzer_open ){
+	      goto out;
+	    }else{
+	      int now;
+
+	      // force close buzzer
+	      PXAI2S_DBGPRINT(DBG_LEVEL1, "force a buzzer stop!\n");
+	      buzzer_close = 1;
+	      if(DCSR(os->dma_ch) & DCSR_RUN) {
+		DCSR(os->dma_ch) &=
+		  (DCSR_RUN|DCSR_ENDINTR|DCSR_STARTINTR|DCSR_BUSERR);
+	      }
+	      now = jiffies;
+	      while(1) {
+		if ( !buzzer_open ) break;
+		schedule();
+		if ( jiffies > ( now + WAIT_BZ_RELEASE ) ) break;
+	      }
+	      buzzer_close = 0;
+	      if( buzzer_open ) goto out;
+	    }
+	  }
+#else
+		goto out;
+#endif
+
+	/* request DMA channels */
+	if (file->f_mode & FMODE_WRITE) {
+	  err = pxa_request_dma(os->name, DMA_PRIO_LOW, audio_dma_irq, os);
+	  if ( err < 0 )
+	    goto out;
+	  os->dma_ch = err;
+	}
+	if (file->f_mode & FMODE_READ) {
+	  err = pxa_request_dma(is->name, DMA_PRIO_LOW, audio_dma_irq, is);
+	  if (err < 0) {
+	    if (file->f_mode & FMODE_WRITE) {
+	      *os->drcmr = 0;
+	      pxa_free_dma(os->dma_ch);
+	    }
+	    goto out;
+	  }
+	  is->dma_ch = err;
+	}
+
+	file->private_data	= state;
+
+	if ((file->f_mode & FMODE_WRITE)) {
+	  state->wr_ref = 1;
+	  os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+	  os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+	  os->output = 1;
+	  os->mapped = 0;
+	  init_waitqueue_head(&os->frag_wq);
+	  init_waitqueue_head(&os->stop_wq);
+	  *os->drcmr = os->dma_ch | DRCMR_MAPVLD;
+
+	  settings.mode = SOUND_PLAY_MODE;
+	}
+	if (file->f_mode & FMODE_READ) {
+	  state->rd_ref = 1;
+	  is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+	  is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+	  is->output = 0;
+	  is->mapped = 0;
+	  init_waitqueue_head(&is->frag_wq);
+	  init_waitqueue_head(&is->stop_wq);
+	  *is->drcmr = is->dma_ch | DRCMR_MAPVLD;
+
+	  settings.mode = SOUND_REC_MODE;
+	}
+
+	if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+	  CorgiSetFreq(8000);
+	  CorgiSetStereo(0);
+	  CorgiSetFormat(AFMT_MU_LAW);
+	}
+
+	settings.output.left  = sound.volume_left;
+	settings.output.right = sound.volume_right;
+	settings.input.left   = sound.gain_left;
+	settings.input.right  = sound.gain_right;
+	settings.frequency    = sound.hw_freq;
+
+	// Open wm8731
+	err = wm8731_open(&settings);
+	if ( err ) {
+	  PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open wm8731\n");
+	  goto error;
+	}
+
+	// Open I2S
+	//err = i2s_open( CORGI_I2S_ADDRESS , CORGI_DEFAULT_FREQUENCY);
+	err = i2s_open( CORGI_I2S_ADDRESS , sound.hw_freq );
+	if ( err ) {
+	  wm8731_close();
+	  PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+	  goto error;
+	}
+
+#ifdef AUDIO_SP_DELAY_OFF
+	del_timer(&speaker_timers);
+#endif
+
+#if 0	// debug
+    reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  HP off
+    set_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  HP on
+    mdelay(100);
+    reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  HP off
+#endif
+
+#if 1
+        // play 50msec
+	now = jiffies;
+	while(1) {
+	  corgi_i2s_write(AUDIO_DATA);
+	  if ( jiffies > ( now + WAIT_PLAY1 ) ) break;
+	}
+#endif
+
+	if( settings.mode == SOUND_REC_MODE ){
+		if(file->f_mode & FMODE_WRITE){
+			// Read & Write means earphone mic mode
+			corgi_hp_mode( CORGI_HP_HEADSET );
+		}else{
+			// mic mode
+			corgi_hp_mode( CORGI_HP_MIC );
+		}
+	}else{
+		corgi_hp_mode(CORGI_HP_AUDIO);
+	}
+
+	err = nonseekable_open(inode, file);;
+out:
+	up(&state->sem);
+	return err;
+
+error:
+	up(&state->sem);
+	if ( ( file->f_mode & FMODE_WRITE ) && ( os->dma_ch >= 0 ) ) {
+	  *os->drcmr = 0;
+	  pxa_free_dma(os->dma_ch);
+	}
+	if ( ( file->f_mode & FMODE_READ ) && ( is->dma_ch >= 0 ) ) {
+	  *is->drcmr = 0;
+	  pxa_free_dma(is->dma_ch);
+	}
+	state->wr_ref = 0;
+	state->rd_ref = 0;
+	return err;
+}
+
+
+/*** Platform *************************************************************/
+static int CorgiSetFormat(int format)
+{
+  int size;
+
+
+  switch (format) {
+  case AFMT_QUERY:
+    return(sound.format);
+  case AFMT_MU_LAW:
+    size = 8;
+    ct_func = sound.trans->ct_ulaw;
+    break;
+  case AFMT_A_LAW:
+    size = 8;
+    ct_func = sound.trans->ct_alaw;
+    break;
+#if 0 // unsupport
+  case AFMT_S8:
+    size = 8;
+    ct_func = sound.trans->ct_s8;
+    break;
+  case AFMT_S16_BE:
+    size = 16;
+    ct_func = sound.trans->ct_s16be;
+    break;
+  case AFMT_U16_BE:
+    size = 16;
+    ct_func = sound.trans->ct_u16be;
+    break;
+  case AFMT_U16_LE:
+    size = 16;
+    ct_func = sound.trans->ct_u16le;
+    break;
+#endif
+  case AFMT_U8:
+    size = 8;
+    ct_func = sound.trans->ct_u8;
+    ct_read_func = sound.trans_read->ct_u8;
+    break;
+  case AFMT_S16_LE:
+    size = 16;
+    ct_func = sound.trans->ct_s16le;
+    ct_read_func = sound.trans_read->ct_s16le;
+    break;
+  default: /* :-) */
+    size = 16;
+    format = AFMT_S16_LE;
+
+  }
+
+  sound.format = format;
+  sound.size = size;
+
+  return format;
+}
+
+static void CorgiVolumeMuteTemp(void)
+{
+  // If sound driver is opened , so update volume.
+  if ( wm8731_busy() ) {
+    wm8731_set_output_volume(0,0);
+  }
+}
+
+static void CorgiUpdateVolume(void)
+{
+  // If sound driver is opened , so update volume.
+  if ( wm8731_busy() ) {
+    wm8731_set_output_volume(sound.volume_left, sound.volume_right);
+  }
+}
+
+static int CorgiSetVolume(int volume)
+{
+  sound.volume_left = volume & 0xff;
+  if ( sound.volume_left > 100 ) sound.volume_left = 100;
+
+  sound.volume_right = ( (volume & 0xff00) >> 8);
+  if ( sound.volume_right > 100 ) sound.volume_right = 100;
+
+  CorgiUpdateVolume();
+
+}
+
+static int CorgiGetVolume(void)
+{
+  return ( sound.volume_right << 8 | sound.volume_left );
+}
+
+static int CorgiSetStereo(int stereo)
+{
+  if (stereo < 0) {
+    return(sound.stereo);
+  }
+
+  stereo = !!stereo;    /* should be 0 or 1 now */
+  sound.stereo = stereo;
+  return(stereo);
+}
+
+static int CorgiSetFreq(int speed)
+{
+  if (speed < 0) {
+    return(sound.freq);
+  }
+  sound.freq = speed;
+  switch (sound.freq) {
+  case 8000:
+  case 44100:
+  case 48000:
+    sound.hw_freq = sound.freq;
+    break;
+  case 11025:
+  case 22050:
+    sound.hw_freq = 44100;
+    break;
+  case 12000:
+  case 16000:
+  case 32000:
+  case 24000:
+    sound.hw_freq = 48000;
+    break;
+  default:
+    sound.hw_freq = 44100;
+    break;
+  }
+
+  if ( wm8731_busy() ) {
+    int err;
+
+    wm8731_set_freq(sound.hw_freq);
+    err = i2s_close( CORGI_I2S_ADDRESS );
+    if ( err ) {
+      PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+    }
+    err = i2s_open( CORGI_I2S_ADDRESS , sound.hw_freq );
+    if ( err ) {
+      PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+    }
+  }
+
+  return(sound.freq);
+}
+
+static void CorgiUpdateGain(void)
+{
+  sound.gain       = input_gain[ ( ( 6 * sound.gain_left ) / 100 ) ].gain;
+  sound.gain_shift = input_gain[ ( ( 6 * sound.gain_left ) / 100 ) ].shift;
+
+  if ( wm8731_busy() ) {
+    wm8731_set_mic_gain_boost(sound.gain);
+  }
+
+}
+
+static int CorgiSetGain(int gain)
+{
+  sound.gain_left = gain & 0xff;
+  if ( sound.gain_left > 100 ) sound.gain_left = 100;
+
+  sound.gain_right = ( (gain & 0xff00) >> 8);
+  if ( sound.gain_right > 100 ) sound.gain_right = 100;
+
+  CorgiUpdateGain();
+
+  return 1;
+}
+
+static int CorgiGetGain(void)
+{
+  return ( sound.gain_right << 8 | sound.gain_left );
+}
+
+
+static void Corgi_hp_in_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+  if ( !isPXAI2SReady ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Currently audio driver is not ready\n");
+    return;
+  }
+
+  PXAI2S_DBGPRINT(DBG_LEVEL2, "Corgi_hp_interrupt\n");
+  schedule_work(&hp_proc);
+}
+
+
+static void corgi_hp_mode(int mode)
+{
+  int state;
+
+  if ( !isPXAI2SReady ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Currently audio driver is not ready\n");
+    return;
+  }
+
+#if 0
+  if (isChkHPstatus ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Currently hp thread is running.. so skip !\n");
+    return;
+  }
+#endif
+
+	if( corgi_HPstatus < 0 ){
+		corgi_HPstatus = GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT);
+	}
+	state = corgi_HPstatus;
+
+	if(( mode == CORGI_HP_AUDIO )||( mode == CORGI_HP_BUZZER )){
+		if ( state ) { 	// Insert HP
+			PXAI2S_DBGPRINT(DBG_LEVEL1, "Insert HP\n");
+			mode = CORGI_HP_HP;
+		} else {	// Not Insert HP
+			PXAI2S_DBGPRINT(DBG_LEVEL1, "Not Insert HP\n");
+			mode = CORGI_HP_SOUNDER;
+		}
+	}
+	switch( mode ){
+	case CORGI_HP_SOUNDER:
+		set_scoop_gpio( CORGI_SCP_APM_ON );					// Speaker On
+		reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  HP off
+		break;
+	case CORGI_HP_HP:
+		reset_scoop_gpio( CORGI_SCP_APM_ON );				// Speaker Off
+		set_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  HP on
+		break;
+	case CORGI_HP_BOTH:
+		set_scoop_gpio( CORGI_SCP_APM_ON | CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  All on
+		break;
+	case CORGI_HP_MIC:
+		set_scoop_gpio( CORGI_SCP_MIC_BIAS );	//  MIC bias on
+		reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON );
+		break;
+	case CORGI_HP_HEADSET:
+		if ( state ) { 	// Insert HP
+			set_scoop_gpio( CORGI_SCP_MIC_BIAS | CORGI_SCP_MUTE_R );	//  MIC bias on
+			reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_APM_ON );
+		} else {	// Not Insert HP
+			set_scoop_gpio( CORGI_SCP_MIC_BIAS | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON);
+			reset_scoop_gpio( CORGI_SCP_MUTE_L );
+		}
+		break;
+	case CORGI_HP_AUDIO:
+	case CORGI_HP_BUZZER:
+	default:
+		return;
+	}
+
+  CorgiUpdateVolume();
+}
+
+static void corgi_hp_thread(void *private_)
+{
+	int count,err;
+	int state;
+	audio_state_t  *audio_state = &pxa_audio_state;
+
+	isChkHPstatus = 1;
+
+
+#ifdef AUDIO_SP_DELAY_OFF
+		del_timer(&speaker_timers);
+#endif
+
+	if ( audio_state->wr_ref || audio_state->rd_ref ){
+  		// sound is playing
+		reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON | CORGI_SCP_MIC_BIAS );	//  HP, Speaker & Mic off
+			// volume zero
+		CorgiVolumeMuteTemp();
+	}
+
+	while(1) {
+
+		state = GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT);
+		count = 0;
+		err = 0;
+		while(1) {
+			schedule_timeout(5);
+
+			if ( state == ( GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT) ) ) count++;
+			else {
+  				err++;
+  				state = GPLR(CORGI_GPIO_AK_INT) & GPIO_bit(CORGI_GPIO_AK_INT);
+  				count = 0;
+			}
+
+			if ( count > 10 ) break;
+			if ( err > 50 ) break;
+
+   		}
+   		if ( count > 10 ) {
+			if ( state ) { 	// Insert HP
+	 			PXAI2S_DBGPRINT(DBG_LEVEL1, "Insert HP\n");
+	  			printk("Insert HP\n");
+	  			corgi_HPstatus = HPJACK_STATE_HEADPHONE;
+			} else {	// Not Insert HP
+				printk("Not Insert HP\n");
+	  			PXAI2S_DBGPRINT(DBG_LEVEL1, "Not Insert HP\n");
+	  			corgi_HPstatus = HPJACK_STATE_NONE;
+			}
+      	} else {
+      		printk("??? HP\n");
+	  		PXAI2S_DBGPRINT(DBG_LEVEL1, "??? HP\n");
+	  		corgi_HPstatus = HPJACK_STATE_NONE;
+      	}
+      	break;
+    }
+    // sound is not playing , so HP/SP be disabled.
+	if ( !audio_state->wr_ref && !audio_state->rd_ref ) {
+		isChkHPstatus = 0;
+		return;
+	}
+	
+	if( audio_state->rd_ref ){
+		// mic mode
+		corgi_hp_mode((audio_state->wr_ref)?
+		  CORGI_HP_HEADSET:CORGI_HP_MIC);
+	}else{
+		corgi_hp_mode((corgi_HPstatus == HPJACK_STATE_NONE)?
+		CORGI_HP_SOUNDER : CORGI_HP_HP);
+	}
+  	isChkHPstatus = 0;
+}
+
+
+static int corgi_init_thread(void *arg)
+{
+  SOUND_SETTINGS settings;
+  int err;
+  int now;
+  settings.mode = SOUND_PLAY_MODE;
+
+  strcpy(current->comm, "snd_init");
+
+
+  isPXAI2SReady = 0;
+
+  settings.output.left  = sound.volume_left;
+  settings.output.right = sound.volume_right;
+  settings.input.left   = sound.gain_left;
+  settings.input.right  = sound.gain_right;
+  settings.frequency    = sound.hw_freq;
+
+  // Open wm8731
+  err = wm8731_open(&settings);
+  if ( err ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open wm8731\n");
+  }
+
+  // Open I2S
+  err = i2s_open( CORGI_I2S_ADDRESS , CORGI_DEFAULT_FREQUENCY);
+  if ( err ) {
+    //wm8731_close();
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+  }
+
+  // play 2sec
+  now = jiffies;
+  while(1) {
+	corgi_i2s_write(AUDIO_DATA);
+	if ( jiffies > ( now + WAIT_INIT_PLAY ) ) break;
+  }
+
+  // Close wm8731
+  err = wm8731_close();
+  if ( err ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close wm8731\n");
+  }
+
+  // Close I2S
+  err = i2s_close( CORGI_I2S_ADDRESS );
+  if ( err ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+  }
+
+  isPXAI2SReady = 1;
+  
+  return 0;
+}
+
+static void CorgiInit(void)
+{
+
+  // MUTE
+  reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON | CORGI_SCP_MIC_BIAS );
+
+  if ( wm8731_init() ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Fail Init\n");
+  }
+
+  /* GPIO15:Both Edge */
+ 	set_irq_type(CORGI_IRQ_GPIO_AK_INT, IRQT_BOTHEDGE);	
+
+	/* Register interrupt handler. */
+	if (request_irq(CORGI_IRQ_GPIO_AK_INT, Corgi_hp_in_interrupt,
+			SA_INTERRUPT, "Audio Headphone", Corgi_hp_in_interrupt)) 
+				PXAI2S_DBGPRINT(DBG_ALWAYS, "Request_irq(%d) failed.\n", CORGI_IRQ_GPIO_AK_INT);
+
+  /* Make threads */
+  //kernel_thread(corgi_hp_thread,  NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+  kernel_thread(corgi_init_thread,  NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+
+}
+
+
+/*** Buzzer *******************************************************/
+#if ALARM_NO_MALLOC
+int audio_buzzer_intmode(unsigned short *buffer,int count,int speed)
+{
+  int idx,i;
+  unsigned long	snddata;
+  audio_state_t  *state = &pxa_audio_state;
+  audio_stream_t *os = state->output_stream;
+  audio_stream_t *s = os;
+
+  int_data_org = buffer;
+  corgi_intmode = (count * sound.hw_freq / speed)&(~3);
+  corgi_intmode_speed = speed;
+  corgi_intmode_cur = 0;
+  corgi_intmode_step = (speed << 8 ) / sound.hw_freq; // fixed point (x256)
+  corgi_intmode_direct = 1;
+
+    // pause during play or recording , so kick this place.
+    if ( ( ( DCSR(s->dma_ch) & DCSR_STOPSTATE ) && ( state->wr_ref ) ) ||
+	 ( ( !state->wr_ref ) && ( state->rd_ref ) ) )
+    {
+	  for(i=0;i<(corgi_intmode/4);i++) {
+		  idx = (corgi_intmode_cur>>8);
+		  snddata = (buffer[idx*2]|(buffer[idx*2+1]<<16));
+		  corgi_intmode_cur += corgi_intmode_step;
+		  corgi_i2s_write(snddata);
+	  }
+
+      corgi_intmode = 0;
+      int_data_org = NULL;
+	}
+  corgi_intmode_direct = 0;
+  return 1;
+}
+#else
+int audio_buzzer_intmode(unsigned short *buffer,int count,int speed)
+{
+  int samplingCount = count * sound.hw_freq / speed;
+  int idx,i ;
+  int cur=0,step = (speed << 8 ) / sound.hw_freq; // fixed point (x256)
+  unsigned short *dstct;
+
+  int_data = (unsigned short *)kmalloc(count * 6,GFP_KERNEL);
+  if ( !int_data ) return 0; 
+  int_data_org = int_data;
+
+  samplingCount &= ~0x3;
+
+  dstct = int_data;
+  for(i=0;i<(samplingCount/4);i++) {
+      idx = (cur>>8);
+      *dstct++ = buffer[idx*2];
+      *dstct++ = buffer[idx*2+1];
+      cur += step;
+  }
+
+  corgi_intmode = samplingCount;
+  corgi_intmode_speed = speed;
+  corgi_intmode_direct = 1;
+
+  {
+    audio_state_t  *state = &pxa_audio_state;
+    audio_stream_t *os = state->output_stream;
+    audio_stream_t *s = os;
+
+    // pause during play or recording , so kick this place.
+    if ( ( ( DCSR(s->dma_ch) & DCSR_STOPSTATE ) && ( state->wr_ref ) ) ||
+	 ( ( !state->wr_ref ) && ( state->rd_ref ) ) )
+    {
+      int i;
+      for(i=0;i<(corgi_intmode/4);i++) {
+	corgi_i2s_write(*(unsigned long *)int_data);
+	int_data++;
+	int_data++;
+      }
+      corgi_intmode = 0;
+      kfree(int_data_org);
+      int_data_org = NULL;
+    }
+  }
+
+  corgi_intmode_direct = 0;
+  return 1;
+}
+#endif
+
+#if ALARM_NO_MALLOC
+static void corgi_intmode_mix(unsigned char *dest,int bUsed)
+{
+  int i;
+  short *cdata = (short *)dest;
+  int cnt = min(corgi_intmode,bUsed);
+  int idx;
+
+  for(i=0;i<(cnt/4);i++) {
+	  idx = (corgi_intmode_cur>>8);
+	  *cdata++ = int_data_org[idx*2];
+	  *cdata++ = int_data_org[idx*2+1];
+	  corgi_intmode_cur += corgi_intmode_step;
+  }
+
+  corgi_intmode -= cnt;
+  if ( corgi_intmode <= 0 ) {
+	  corgi_intmode = 0;
+	  int_data_org = NULL;
+  }
+  return;
+}
+#else
+static void corgi_intmode_mix(unsigned char *dest,int bUsed)
+{
+  int i;
+  short *cdata = (short *)dest;
+  int cnt = min(corgi_intmode,bUsed);
+
+  for(i=0;i<(cnt/4);i++) {
+    *cdata = *int_data;
+    int_data++;
+    cdata++;
+    *cdata = *int_data;
+    int_data++;
+    cdata++;
+  }
+
+  corgi_intmode -= cnt;
+  if ( corgi_intmode <= 0 ) {
+    corgi_intmode = 0;
+    if ( int_data_org ) {
+      kfree(int_data_org);
+      int_data_org = NULL;
+    }
+  }
+}
+#endif
+
+int audio_buzzer_write(const char *buffer,int count)
+{
+  const char *buffer0 = buffer;
+  audio_state_t  *state = &pxa_audio_state;
+  audio_stream_t *s = state->output_stream;
+  int chunksize, ret = 0;
+
+
+#ifdef AUDIO_BUFFER_SETUP_NOCLEAR
+  if (!s->buffers && __audio_setup_buf(s,0))
+    return -ENOMEM;
+#else
+  if (!s->buffers && audio_setup_buf(s))
+    return -ENOMEM;
+#endif
+
+  while (count > 0) {
+    audio_buf_t *b = &s->buffers[s->usr_frag];
+
+#ifdef BUZZER_FORCE_CLOSE
+    if( buzzer_close ) {
+      break;
+    }
+#endif
+
+    chunksize = s->fragsize - b->offset;
+    if (chunksize > count)
+      chunksize = count;
+    memcpy(b->data + b->offset, buffer, chunksize);
+
+    b->offset += chunksize;
+    buffer += chunksize;
+    count -= chunksize;
+
+    if (b->offset < s->fragsize) {
+      up(&s->sem);
+      break;
+    }
+
+    b->offset = 0;
+    b->dma_desc->ddadr &= ~DDADR_STOP;
+#ifdef DMA_NO_INITIALIZED
+    if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+	!(DCSR(s->dma_ch) & DCSR_RUN)){
+      DDADR(s->dma_ch) = b->dma_desc->ddadr;
+      DCSR(s->dma_ch) = DCSR_RUN;
+    }
+#else
+    if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+      DDADR(s->dma_ch) = b->dma_desc->ddadr;
+      DCSR(s->dma_ch) = DCSR_RUN;
+    }
+#endif
+
+    /* move the index to the next fragment */
+    if (++s->usr_frag >= s->nbfrags)
+      s->usr_frag = 0;
+  }
+
+  if ((buffer - buffer0))
+    ret = buffer - buffer0;
+
+  return ret;
+}
+
+void audio_buzzer_sync(void)
+{
+  audio_state_t  *state = &pxa_audio_state;
+  audio_stream_t *s = state->output_stream;
+  audio_buf_t *b;
+  pxa_dma_desc *final_desc;
+  u_long dcmd_save = 0;
+  int err;
+  DECLARE_WAITQUEUE(wait, current);
+
+
+#ifdef BUZZER_FORCE_CLOSE
+  if( buzzer_close ) goto sync_end;
+#endif
+
+  //audio_sync(file);
+
+	/*
+	 * Send current buffer if it contains data.  Be sure to send
+	 * a full sample count.
+	 */
+	final_desc = NULL;
+	b = &s->buffers[s->usr_frag];
+	if (b->offset &= ~3) {
+		final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE];
+		b->offset &= (MAX_DMA_SIZE-1);
+		dcmd_save = final_desc->dcmd;
+		final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; 
+		final_desc->ddadr |= DDADR_STOP;
+		b->offset = 0;
+		b->dma_desc->ddadr &= ~DDADR_STOP;
+#ifdef DMA_NO_INITIALIZED
+		if ((DCSR(s->dma_ch) & DCSR_STOPSTATE)||
+		    !(DCSR(s->dma_ch) & DCSR_RUN)){
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#else
+		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
+			DDADR(s->dma_ch) = b->dma_desc->ddadr;
+			DCSR(s->dma_ch) = DCSR_RUN;
+		}
+#endif
+	}
+
+#ifdef BUZZER_FORCE_CLOSE
+ sync_end:;
+#endif
+
+  /* Wait for DMA to complete. */
+  set_current_state(TASK_INTERRUPTIBLE);
+
+  add_wait_queue(&s->frag_wq, &wait);
+  while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) {
+    schedule();
+    set_current_state(TASK_INTERRUPTIBLE);
+  }
+
+  set_current_state(TASK_RUNNING);
+  remove_wait_queue(&s->frag_wq, &wait);
+}
+
+int audio_buzzer_release(void)
+{
+  audio_state_t  *state = &pxa_audio_state;
+  audio_stream_t *s = state->output_stream;
+  int err, ret = 0;
+  DECLARE_WAITQUEUE(wait, current);
+
+
+  //audio_sync(file);
+  /* Wait for DMA to complete. */
+  set_current_state(TASK_INTERRUPTIBLE);
+
+  add_wait_queue(&s->frag_wq, &wait);
+  while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) {
+    schedule();
+    set_current_state(TASK_INTERRUPTIBLE);
+  }
+
+  set_current_state(TASK_RUNNING);
+  remove_wait_queue(&s->frag_wq, &wait);
+
+#if (defined AUDIO_ALWAYS_SP_ON) || (defined AUDIO_SP_DELAY_OFF)
+  reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//  HP & Speaker off
+#ifdef AUDIO_SP_DELAY_OFF
+  corgi_sp_delay_off();
+#endif
+#else
+  reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_APM_ON );	//  HP & Speaker off
+#endif
+
+  audio_clear_buf(state->output_stream);
+  *state->output_stream->drcmr = 0;
+  pxa_free_dma(state->output_stream->dma_ch);
+
+#if ALARM_NO_MALLOC
+	// wait playing int sound.
+#ifdef BUZZER_FORCE_CLOSE
+	while(corgi_intmode_direct && !buzzer_close)
+	  schedule();
+#else
+	while(corgi_intmode_direct)
+	  schedule();
+#endif
+
+	corgi_intmode = 0;
+    int_data_org = NULL;
+#else
+  if ( int_data_org ) {
+    kfree(int_data_org);
+    int_data_org = NULL;
+  }
+#endif
+
+  // Close wm8731
+  err = wm8731_close();
+  if ( err ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close wm8731\n");
+	ret = err;
+  }
+
+  // Close I2S
+  err = i2s_close( CORGI_I2S_ADDRESS );
+  if ( err ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+	ret = err;
+  }
+
+  state->wr_ref = 0;
+#ifdef BUZZER_FORCE_CLOSE
+  buzzer_open = 0;
+#endif
+
+  return ret;
+}
+
+int audio_buzzer_open(int speed)
+{
+  audio_state_t  *state = &pxa_audio_state;
+  audio_stream_t *os = state->output_stream;
+  SOUND_SETTINGS settings;
+  int err;
+  int now;
+
+  while(1) {
+    if ( isPXAI2SReady ) break;
+    schedule();
+  }
+
+  err = -EBUSY;
+  if ( state->wr_ref || state->rd_ref )
+    goto out;
+
+  state->wr_ref = 1;
+
+#ifdef BUZZER_FORCE_CLOSE
+  buzzer_open = 1;
+#endif
+
+  /* request DMA channels */
+  err = pxa_request_dma(os->name, DMA_PRIO_LOW, audio_dma_irq, os);
+  if ( err < 0 )
+    goto error;
+  os->dma_ch = err;
+
+  os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
+  os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
+  os->output = 1;
+  os->mapped = 0;
+  init_waitqueue_head(&os->frag_wq);
+  init_waitqueue_head(&os->stop_wq);
+  *os->drcmr = os->dma_ch | DRCMR_MAPVLD;
+
+  settings.mode = SOUND_PLAY_MODE;
+  settings.output.left  = sound.volume_left;
+  settings.output.right = sound.volume_right;
+  settings.input.left   = sound.gain_left;
+  settings.input.right  = sound.gain_right;
+  settings.frequency    = speed;
+
+  // Open wm8731
+  err = wm8731_open(&settings);
+  if ( err ) {
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open wm8731\n");
+    goto error;
+  }
+
+  sound.hw_freq = speed;
+  // Open I2S
+  err = i2s_open( CORGI_I2S_ADDRESS , sound.hw_freq );
+  if ( err ) {
+    wm8731_close();
+    PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+    goto error;
+  }
+
+#ifdef AUDIO_SP_DELAY_OFF
+	del_timer(&speaker_timers);
+#endif
+
+#if 0
+  // play 50msec
+  now = jiffies;
+  while(1) {
+    corgi_i2s_write(AUDIO_DATA);
+    if ( jiffies > ( now + WAIT_PLAY1 ) ) break;
+  }
+#endif
+
+  corgi_hp_mode(CORGI_HP_BUZZER);
+
+  err = 0;
+#ifdef BUZZER_FORCE_CLOSE
+  if( buzzer_close ){
+    err = -EBUSY;
+    goto error;
+  }
+#endif
+out:
+  return err;
+
+error:
+  *os->drcmr = 0;
+  pxa_free_dma(os->dma_ch);
+  state->wr_ref = 0;
+  return err;
+}
+
+
+/*****************************************************************/
+/*
+ * /dev/sndstat
+ *  Audio Stat stuff
+ *
+ */
+static int state_open(struct inode *inode, struct file *file)
+{
+  char *buffer = pxa_i2s_state.buf;
+  int len = 0;
+
+  if (pxa_i2s_state.busy) {
+    return -EBUSY;
+  }
+
+  //MOD_INC_USE_COUNT;
+  pxa_i2s_state.ptr = 0;
+  pxa_i2s_state.busy = 1;
+
+  len += sprintf(buffer+len, "  CORGI I2S sound driver:\n");
+
+  len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.format);
+  switch (sound.format) {
+  case AFMT_MU_LAW:
+    len += sprintf(buffer+len, " (mu-law)");
+    break;
+  case AFMT_A_LAW:
+    len += sprintf(buffer+len, " (A-law)");
+    break;
+  case AFMT_U8:
+    len += sprintf(buffer+len, " (unsigned 8 bit)");
+    break;
+  case AFMT_S8:
+    len += sprintf(buffer+len, " (signed 8 bit)");
+    break;
+  case AFMT_S16_BE:
+    len += sprintf(buffer+len, " (signed 16 bit big)");
+    break;
+  case AFMT_U16_BE:
+    len += sprintf(buffer+len, " (unsigned 16 bit big)");
+    break;
+  case AFMT_S16_LE:
+    len += sprintf(buffer+len, " (signed 16 bit little)");
+    break;
+  case AFMT_U16_LE:
+    len += sprintf(buffer+len, " (unsigned 16 bit little)");
+    break;
+  }
+  len += sprintf(buffer+len, "\n");
+  len += sprintf(buffer+len, "\tsound.speed = %dHz \n",sound.freq);
+  len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+		       sound.stereo, sound.stereo ? "stereo" : "mono");
+  pxa_i2s_state.len = len;
+
+  return 0;
+}
+
+
+static int state_release(struct inode *inode, struct file *file)
+{
+  pxa_i2s_state.busy = 0;
+  //MOD_DEC_USE_COUNT;
+  return 0;
+}
+
+
+static ssize_t state_read(struct file *file, char *buf, size_t count,
+			  loff_t *ppos)
+{
+  int n = pxa_i2s_state.len - pxa_i2s_state.ptr;
+  if (n > count)
+    n = count;
+  if (n <= 0) {
+    return 0;
+  }
+  if (copy_to_user(buf, &pxa_i2s_state.buf[pxa_i2s_state.ptr], n)) {
+    return -EFAULT;
+  }
+  pxa_i2s_state.ptr += n;
+  return n;
+}
+
+static struct file_operations state_fops =
+{
+  llseek:	no_llseek,
+  read:		state_read,
+  open:		state_open,
+  release:	state_release,
+};
+
+static void __init state_init(void)
+{
+  // Regist /dev/sndstat
+  pxa_i2s_state.dev_state = register_sound_special(&state_fops, SND_DEV_STATUS);
+  if ( pxa_i2s_state.dev_state < 0 ) {
+    return;
+  }
+  pxa_i2s_state.busy = 0;
+}
+
+
+/*****************************************************************/
+/*
+ *  /dev/mixer
+ *  Audio Mixer stuff
+ *
+ */
+
+static int mixer_ioctl( struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+  int data;
+
+  switch (cmd) {
+  case SOUND_MIXER_READ_DEVMASK:
+    return IOCTL_OUT(arg, (SOUND_MASK_VOLUME|SOUND_MASK_MIC) );
+  case SOUND_MIXER_READ_RECMASK:
+    return IOCTL_OUT(arg, 0);
+  case SOUND_MIXER_READ_STEREODEVS:
+    return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+  case SOUND_MIXER_READ_CAPS:
+    return IOCTL_OUT(arg, 0);
+  case SOUND_MIXER_WRITE_VOLUME:
+    IOCTL_IN(arg, data);
+    (*sound.mach.setVolume)(data);
+  case SOUND_MIXER_READ_VOLUME:
+    return IOCTL_OUT(arg, (*sound.mach.getVolume)());
+  case SOUND_MIXER_READ_TREBLE:
+    return IOCTL_OUT(arg, 0);
+  case SOUND_MIXER_WRITE_TREBLE:
+    return IOCTL_OUT(arg, 0);
+  case SOUND_MIXER_READ_SPEAKER:
+    return IOCTL_OUT(arg, 0);
+  case SOUND_MIXER_WRITE_SPEAKER:
+    return IOCTL_OUT(arg, 0);
+
+  case SOUND_MIXER_WRITE_MIC:
+    IOCTL_IN(arg, data);
+    //printk("<mic data>:%x\n",data);
+    CorgiSetGain(data);
+  case SOUND_MIXER_READ_MIC:
+    return IOCTL_OUT(arg, CorgiGetGain());
+
+  }
+
+  return -EINVAL;
+
+}
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+  if ( 	pxa_i2s_codec.busy  ) {
+    return -EBUSY;
+  }
+
+  //MOD_INC_USE_COUNT;
+  pxa_i2s_codec.busy = 1;
+  return 0;
+}
+
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+  pxa_i2s_codec.busy = 0;
+  //MOD_DEC_USE_COUNT;
+  return 0;
+}
+
+
+static struct file_operations corgi_mixer_fops = {
+        ioctl:		mixer_ioctl,
+	llseek:		no_llseek,
+	open:    	mixer_open,
+	release: 	mixer_release,
+	owner:		THIS_MODULE
+};
+
+static void __init mixer_init(void)
+{
+  // Regist /dev/mixer.
+  pxa_i2s_codec.dev_mixer = register_sound_mixer(&corgi_mixer_fops, -1);
+  if ( pxa_i2s_codec.dev_mixer < 0 ) {
+    return;
+  }
+  pxa_i2s_codec.busy = 0;
+}
+
+/*****************************************************************/
+/*
+ *  /dev/dsp
+ *  Audio stuff
+ */
+
+static struct file_operations corgi_audio_fops =
+{
+  llseek:	no_llseek,
+  write:	audio_write,
+  read:		audio_read,
+  poll:		audio_poll,
+  ioctl:	audio_ioctl,
+  open:		audio_open,
+  release:	audio_release,
+  mmap:		audio_mmap,
+};
+
+static void __init sq_init(void)
+{
+  // Regist /dev/dsp.
+  pxa_audio_state.dev_dsp = register_sound_dsp(&corgi_audio_fops, -1);
+  if ( pxa_audio_state.dev_dsp < 0 ) {
+    return;
+  }
+
+  pxa_audio_state.wr_ref = 0;
+  pxa_audio_state.rd_ref = 0;
+
+  // Set Default Settings
+  sound.format = AFMT_S16_LE;
+  sound.stereo = 1;
+  sound.freq   = 44100;
+  sound.hw_freq = 44100;
+  sound.size   = 16;
+  sound.trans  = &transCorgi;
+  sound.trans_read  = &transReadCorgi;
+
+  sound.volume_left = 80;
+  sound.volume_right = 80;
+
+  sound.gain_left = 40;
+  sound.gain_right = 40;
+
+
+  // Change Format
+  (*sound.mach.setFormat)(sound.format);
+
+}
+
+
+
+
+/*** Power Management ****************************************************/
+#ifdef CONFIG_PM
+static int CorgiPMCallBack(struct pm_dev *pm_dev,pm_request_t req, void *data)
+{
+	switch (req) {
+	case PM_SUSPEND:
+	  {
+	    int err;
+
+	    if ( pxa_audio_state.rd_ref || pxa_audio_state.wr_ref ) {
+	      wm8731_suspend();
+	      err = i2s_close( CORGI_I2S_ADDRESS );
+	      if ( err ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not close i2s\n");
+	      }
+	    }
+
+	    if ( pxa_audio_state.rd_ref != 0 ) {
+	      audio_clear_buf(pxa_audio_state.input_stream);
+	      *pxa_audio_state.input_stream->drcmr = 0;
+	      pxa_free_dma(pxa_audio_state.input_stream->dma_ch);
+	    }
+
+	    if ( pxa_audio_state.wr_ref != 0 ) {
+	      audio_clear_buf(pxa_audio_state.output_stream);
+	      *pxa_audio_state.output_stream->drcmr = 0;
+	      pxa_free_dma(pxa_audio_state.output_stream->dma_ch);
+	    }
+
+	  }
+//	  corgi_HPstatus = HPJACK_STATE_UNDETECT;
+#ifdef AUDIO_SP_DELAY_OFF
+	  corgi_sounder_timer(0);
+#endif
+
+	  break;
+
+	case PM_RESUME:
+	  {
+	    int err;
+
+	    /* request DMA channels */
+	    if ( pxa_audio_state.wr_ref != 0 ) {
+	      init_waitqueue_head(&pxa_audio_state.output_stream->frag_wq);
+	      init_waitqueue_head(&pxa_audio_state.output_stream->stop_wq);
+	      *pxa_audio_state.output_stream->drcmr = pxa_audio_state.output_stream->dma_ch | DRCMR_MAPVLD;
+	      err = pxa_request_dma(pxa_audio_state.output_stream->name, DMA_PRIO_LOW,
+				    audio_dma_irq, pxa_audio_state.output_stream);
+
+	      if ( err < 0 ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not get DMA\n");
+	      }
+	      pxa_audio_state.output_stream->dma_ch = err;
+	    }
+
+	    if ( pxa_audio_state.rd_ref != 0 ) {
+	      init_waitqueue_head(&pxa_audio_state.input_stream->frag_wq);
+	      init_waitqueue_head(&pxa_audio_state.input_stream->stop_wq);
+	      *pxa_audio_state.input_stream->drcmr = pxa_audio_state.input_stream->dma_ch | DRCMR_MAPVLD;
+
+	      err = pxa_request_dma(pxa_audio_state.input_stream->name, DMA_PRIO_LOW,
+				    audio_dma_irq, pxa_audio_state.input_stream);
+	      if ( err < 0 ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not get DMA\n");
+	      }
+	      pxa_audio_state.input_stream->dma_ch = err;
+	    }
+
+	    if ( pxa_audio_state.rd_ref || pxa_audio_state.wr_ref ) {
+	      wm8731_resume();
+	      err = i2s_open( CORGI_I2S_ADDRESS , sound.hw_freq );
+	      if ( err ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Can not open i2s\n");
+	      }
+	    }
+	    if ( pxa_audio_state.rd_ref || pxa_audio_state.wr_ref ) {
+	      schedule_work(&hp_proc);
+	    }
+	  break;
+	  }
+	}
+	return 0;
+}
+#endif
+
+
+/*** Config & Setup *********************************************************/
+static int __init pxa_i2s_init(void)
+{
+	sound.mach = machCorgi;
+
+	printk("Corgi audio driver initialize\n");
+
+	(*sound.mach.init)();
+
+	/* Set default settings. */
+	sq_init();
+
+	/* Set up /dev/sndstat. */
+	state_init();
+
+	/* Set up /dev/mixer. */
+	mixer_init();
+
+
+#ifdef CONFIG_PM
+	pxa_sound_pm_dev = pm_register(PM_SYS_DEV, 0, CorgiPMCallBack);
+#endif
+
+	return 0;
+}
+
+static void __exit pxa_i2s_exit(void)
+{
+  // FIXME : release buffer
+
+  if ( pxa_audio_state.dev_dsp >= 0 ) 
+    unregister_sound_dsp(pxa_audio_state.dev_dsp);
+  if ( pxa_i2s_codec.dev_mixer >= 0 ) 
+    unregister_sound_mixer(pxa_i2s_codec.dev_mixer);
+  if ( pxa_i2s_state.dev_state >= 0 )
+    unregister_sound_special(pxa_i2s_state.dev_state);
+
+}
+
+module_init(pxa_i2s_init);
+module_exit(pxa_i2s_exit);
+
+
Index: linux-2.6.11-rc2/sound/oss/poodle_i2sc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/poodle_i2sc.h	2005-01-28 15:42:49.348279256 +0000
@@ -0,0 +1,41 @@
+/*
+ * linux/drivers/sound/poodle_i2sc.h
+ *
+ * I2C & I2S control header file
+ *
+ *      
+ * Copyright (C) 2002  SHARP
+ *
+ * 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.
+ *
+ * Change Log
+ *
+ */
+#ifndef _POODLE_I2SC_H_
+#define _POODLE_I2SC_H_
+
+#define TRUE  1
+#define FALSE 0
+
+int i2c_open(unsigned char);
+int i2c_close(unsigned char);
+
+int i2s_open(unsigned char,unsigned int);
+int i2s_close(unsigned char);
+
+int i2c_byte_write(unsigned char,unsigned char,unsigned char);
+
+int i2c_init(void);
+void i2c_suspend(void);
+void i2c_resume(void);
+
+
+#endif
Index: linux-2.6.11-rc2/sound/oss/poodle_wm8731.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/poodle_wm8731.h	2005-01-28 15:42:49.348279256 +0000
@@ -0,0 +1,154 @@
+/*
+ * linux/drivers/sound/poodle_wm8731.h
+ *
+ * Sound Driver for WM8731 codec device header file
+ *
+ *      
+ * Copyright (C) 2002  SHARP
+ *
+ * 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.
+ *
+ * Change Log
+ *
+ */
+#ifndef _WM8731_H_
+#define _WM8731_H_
+
+
+#define WM8731_REG_NUM  9
+
+#define TRUE  1
+#define FALSE 0
+
+#define WM8731_DEV_ADR0 0x1a                // CSB = Low
+#define WM8731_DEV_ADR1 0x1b                // CSB = High
+#define WM8731_DEVICE   WM8731_DEV_ADR1
+
+// Register address
+#define WM8731_LeftLineIn_ADR		0x00
+#define WM8731_RightLineIn_ADR		0x01
+#define WM8731_LeftHdpOut_ADR		0x02
+#define WM8731_RightHdpOut_ADR		0x03
+#define WM8731_AnalogAudioPath_ADR	0x04
+#define WM8731_DigitalAudioPath_ADR	0x05
+#define WM8731_PowDownCtl_ADR		0x06
+#define WM8731_DigitalIfFormat_ADR	0x07
+#define WM8731_SamplingCtl_ADR		0x08
+#define WM8731_ActiveCtl_ADR		0x09
+#define WM8731_ResetReg_ADR		0x0f
+
+
+// Volume ctrl registers ( Left Line in / Right Line in / Left HP out / Right HP out )
+//  (0000000),  (0000001),  (0000010),  (0000011)
+#define INPUT_MUTE_ON			( 1 << 7 )
+#define INPUT_MUTE_OFF			( 0 )
+#define ZERO_CROSS_UPDATE		( 1 << 7 )        
+#define SIMUL_UPDATE			( 1 << 8 )
+
+// Initial value
+#define INIT_HP_VOL			(121)	// Initial Volume 0dB
+#define INIT_LINE_VOL			(23)	// Initial Volume 0dB
+#define MAX_HP_VOL			(127)
+#define MIN_HP_VOL			(0)
+#define MAX_LINE_VOL			(31)
+#define MIN_LINE_VOL			(0)
+#define INITIAL_PORT_DIR		(0x2705)
+#define HP_VOL_MASK			(0x7f)
+#define LINE_VOL_MASK			(0x1f)
+
+// Analog Audio path ctrl register (0000100)
+#define SIDETONE_ENABLE			(1<<5)
+#define SIDETONE_DISABLE		( 0 )
+#define ST_ATTN_6dB			( (0) << 6 )
+#define ST_ATTN_9dB			( (1) << 6 )
+#define ST_ATTN_12dB			( (2) << 6 )
+#define ST_ATTN_15dB			( (3) << 6 )
+#define DAC_OFF				( 0 )
+#define DAC_SELECT			( 1 << 4 )
+#define BYPASS_ENABLE			( 1 << 3 )
+#define BYPASS_DISABLE			( 0 )
+#define INPUT_MIC			( 1 << 2 )
+#define INPUT_LINE			( 0 << 2 )
+#define MIC_MUTE_ON			( 1 << 1 )
+#define MIC_MUTE_OFF			( 0 )
+#define MIC_BOOST_ON			( 1 )
+#define MIC_BOOST_OFF			( 0 )
+
+// Digital Audio path ctrl register  (0000101)
+#define DPC_DAC_MUTE_ON			( 1U << 3 )
+#define DPC_DAC_MUTE_OFF		( 0U )
+#define DPC_DAC_MUTE_MASK		(~ ( 1U << 3 ) )
+#define DEEMPHASIS_MODE(x)		( (( x ) & 3U ) << 1 )
+#define DPC_DEEMPHASIS_MASK		(~ ( 3U << 1 ) )
+#define DPC_ADC_HPF_ENABLE		( 1U )
+#define DPC_ADC_HPF_DISABLE		( 0U )
+#define DPC_INIT			( 0U )
+
+// Power Down control register  (0000110)
+#define PD_ALL				( 1U << 7 )
+#define PD_CLK				( 1U << 6 )
+#define PD_OSC				( 1U << 5 )
+#define PD_OUT				( 1U << 4 )
+#define PD_DAC				( 1U << 3 )
+#define PD_ADC				( 1U << 2 )
+#define PD_MIC				( 1U << 1 )
+#define PD_LIN				( 1U << 0 )
+
+#define PD_DEC_ACTIVE			( PD_OSC | PD_ADC | PD_MIC | PD_LIN )
+#define PD_ENC_ACTIVE			( PD_OSC | PD_DAC | PD_MIC )
+#define PD_SHTDWN			( PD_ALL )
+
+// Digital Audio Interface Format register  (0000111)
+#define SLAVE				( 0 )
+#define MASTER				( 1U << 6 )
+#define I2S_MODE			( 2U )
+#define LEFT_JUSTIFIED			( 1U )
+#define RIGHT_JUSTIFIED			( 0U )
+#define IWL_16BIT			( 0 )
+#define IWL_20BIT			( 1U << 2 )
+#define IWL_24BIT			( 2U << 2 )
+#define IWL_32BIT			( 3U << 2 )
+#define LRSWAP_DISABLE			( 0U )
+#define LRSWAP_ENABLE			( 1U << 5 )
+#define LRP_RIGHT_HIGH			( 0U )
+#define LRP_RIGHT_LOW			( 1U )
+
+// Sampling ctrl register defines  (0001000)
+#define SRC_CLKOUT_DIV			( 1 << 7 )
+#define SRC_CLKIN_DIV			( 1 << 6 )
+#define SRC_BOTH_44KHZ			( 8 << 2 )
+#define SRC_BOTH_48KHZ			( 0 << 2 )
+#define SRC_BOTH_8KHZ			( 3 << 2 )
+#define SRC_OSR_256FS			( 0 )		// 12.288MHz/48kHz,11.2896MHz/44.1kHz
+#define SRC_OSR_384FS			( 1 << 1 )	// 18.432MHz/48kHz,16.9344MHz/44.1kHz
+#define SRC_OSR_250FS			( 0 )		// 12MHz/48 kHz
+#define SRC_OSR_272FS			( 1 << 1 )	// 12MHz/44.1kHz
+#define SRC_USB_MODE			( 1 )
+#define SRC_NORMAL_MODE			( 0 )
+#define DIGITAL_IF_ACTIVE		( 1 )		// digital interface active
+#define DIGITAL_IF_INACTIVE		( 0 )
+
+int wm8731_busy(void);
+int wm8731_init(void);
+int wm8731_open(SOUND_SETTINGS *);
+int wm8731_close(void);
+void wm8731_set_volume(int,int);
+void wm8731_input_volume(int,int);
+int wm8731_suspend(void);
+int wm8731_set_output_volume(int,int);
+int wm8731_set_mic_gain_boost(int);
+int wm8731_resume(void);
+int wm8731_set_freq(int freq);
+
+
+
+
+#endif
Index: linux-2.6.11-rc2/sound/oss/poodle_audio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.11-rc2/sound/oss/poodle_audio.h	2005-01-28 15:42:49.349279104 +0000
@@ -0,0 +1,55 @@
+/*
+ * linux/drivers/sound/poodle_audio.h
+ *
+ * Sound Driver for WM8731 codec device header file
+ *
+ *      
+ * Copyright (C) 2002  SHARP
+ *
+ * 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.
+ *
+ * Change Log
+ *
+ */
+
+#ifndef _SOUNDDRV_H_
+#define _SOUNDDRV_H_
+
+typedef struct GAIN_SETTINGS {
+  int left;
+  int right;
+} GAIN_SETTINGS;
+
+typedef struct SOUND_SETTINGS {
+  unsigned short mode;
+  GAIN_SETTINGS output;
+  GAIN_SETTINGS input;
+  int frequency;
+} SOUND_SETTINGS;
+
+// mode
+#define SOUND_PLAY_MODE		(0x0001)
+#define SOUND_REC_MODE		(0x0002)
+#define SOUND_MODE_MASK		(0x0003)
+
+
+// volume
+enum {
+	VOLUME_IGNORE = -2,
+	VOLUME_MUTE = -1
+};
+#define MAX_VOLUME		MAX_HP_VOL
+#define MIN_VOLUME		MIN_HP_VOL
+#define MAX_INPUT_VOLUME	MAX_LINE_VOL
+#define MIN_INPUT_VOLUME	MIN_LINE_VOL
+
+
+#endif

