Index: linux/sound/oss/Makefile
===================================================================
--- linux.orig/sound/oss/Makefile	2005-01-22 01:47:32.000000000 +0000
+++ linux/sound/oss/Makefile	2005-01-28 18:06:34.000000000 +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/sound/oss/Kconfig
===================================================================
--- linux.orig/sound/oss/Kconfig	2005-01-22 01:48:48.000000000 +0000
+++ linux/sound/oss/Kconfig	2005-01-28 18:06:34.000000000 +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/sound/oss/pxa-audio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/sound/oss/pxa-audio.h	2005-01-28 18:06:34.000000000 +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/sound/oss/poodle_i2sc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/sound/oss/poodle_i2sc.c	2005-01-28 18:23:18.000000000 +0000
@@ -0,0 +1,316 @@
+/*
+ * 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 "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/sound/oss/poodle_wm8731.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/sound/oss/poodle_wm8731.c	2005-01-28 18:26:36.000000000 +0000
@@ -0,0 +1,679 @@
+/*
+ * 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 "poodle_audio.h"
+#include "poodle_wm8731.h"
+#include "poodle_i2sc.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] = {
+  ( INPUT_MUTE_ON | INIT_LINE_VOL ),
+  ( INPUT_MUTE_ON | INIT_LINE_VOL ),
+  ( INIT_HP_VOL ),
+  ( INIT_HP_VOL ),
+  ( 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] = {
+  ( INIT_LINE_VOL ),
+  ( INIT_LINE_VOL ),
+  ( INIT_HP_VOL ),
+  ( INIT_HP_VOL ),
+  ( 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/sound/oss/pxa-i2s_corgi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/sound/oss/pxa-i2s_corgi.c	2005-01-29 11:51:44.199317896 +0000
@@ -0,0 +1,2991 @@
+/*
+ * 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/device.h>
+#include <linux/interrupt.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 DMA_NO_INITIALIZED		1
+//#undef DMA_NO_INITIALIZED
+#define ALARM_NO_MALLOC		1
+#define BUZZER_FORCE_CLOSE		1
+
+/* 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 **********************************************************/
+
+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 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 void 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 AUDIO_BUFFER_SETUP_NOCLEAR
+static int __audio_setup_buf(audio_stream_t * s, int is_clr);
+#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 {
+	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 = {
+	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 }
+};
+
+
+// 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)
+	reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | CORGI_SCP_MIC_BIAS );
+#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;
+	}
+
+
+		// play 50msec
+	now = jiffies;
+	while(1) {
+		corgi_i2s_write(AUDIO_DATA);
+		if (jiffies > ( now + WAIT_PLAY1 ) ) break;
+	}
+
+	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 void 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 irqreturn_t Corgi_hp_in_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+{
+	PXAI2S_DBGPRINT(DBG_LEVEL2, "Corgi_hp_interrupt\n");
+	schedule_work(&hp_proc);
+	return IRQ_HANDLED;
+}
+
+
+static void corgi_hp_mode(int mode)
+{
+	int state;
+
+	if (!isPXAI2SReady ) {
+		PXAI2S_DBGPRINT(DBG_ALWAYS, "Currently audio driver is not ready\n");
+		return;
+	}
+
+	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;
+
+
+
+	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;
+	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)
+	reset_scoop_gpio( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R );	//	HP & Speaker off
+#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;
+
+	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;
+	}
+
+	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 corgi_snd_suspend(struct device *dev, uint32_t state, uint32_t level)
+{
+	if (level == SUSPEND_POWER_DOWN) {
+		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;
+	}
+	return 0;
+}
+
+
+static int corgi_snd_resume(struct device *dev, uint32_t level)
+{
+	if (level == RESUME_POWER_ON) 
+	{
+			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);
+			}
+
+	}
+	return 0;
+}
+#else
+#define corgi_snd_suspend		NULL
+#define corgi_snd_resume		NULL
+#endif
+
+
+/*** Config & Setup *********************************************************/
+static int __init corgi_snd_probe(struct device *dev) 
+{
+	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();
+
+
+	return 0;
+}
+
+static int corgi_snd_remove(struct device *dev) 
+{
+		// 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);
+		
+	return 0;
+}
+
+static struct device_driver corgi_snd_driver = {
+	.name		= "corgi-sound",
+	.bus		= &platform_bus_type,
+	.probe		= corgi_snd_probe,
+	.remove		= corgi_snd_remove,
+	.suspend	= corgi_snd_suspend,
+	.resume		= corgi_snd_resume,
+};
+
+static int __devinit corgi_snd_init(void)
+{
+	return driver_register(&corgi_snd_driver);
+}
+
+static void __exit corgi_snd_exit(void)
+{
+ 	driver_unregister(&corgi_snd_driver);
+}
+
+module_init(corgi_snd_init);
+module_exit(corgi_snd_exit);
+
+//MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Corgi Sound Driver");
+MODULE_LICENSE("GPLv2");
\ No newline at end of file
Index: linux/sound/oss/poodle_i2sc.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/sound/oss/poodle_i2sc.h	2005-01-28 18:06:34.000000000 +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/sound/oss/poodle_wm8731.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/sound/oss/poodle_wm8731.h	2005-01-28 18:06:34.000000000 +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/sound/oss/poodle_audio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux/sound/oss/poodle_audio.h	2005-01-28 18:06:34.000000000 +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

