diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/sound/psionw_sound.c linux-2.4.19-rmk2/drivers/sound/psionw_sound.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/sound/psionw_sound.c linux-2.4.19-rmk2/drivers/sound/psionw_sound.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/sound/psionw_sound.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/sound/psionw_sound.c	2002-10-02 22:07:30.000000000 -0700
@@ -0,0 +1,360 @@
+/*
+    Driver for PsionW Sound output
+
+    (c) 2002 Simon Howard
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* TODO:
+ *
+ *  - Microphone support
+ *  - /dev/mixer support
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/hardware/psionw.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/psionw-power.h>
+
+#include "ulaw.h"
+
+/* these ought to be in the hardware headers: */
+
+#define CODOUTEN (1 << 0)
+#define CODINEN  (1 << 1)
+
+#define SAMPLE_RATE 8000 /* this cant be changed */
+
+static int users;
+static struct semaphore users_lock;
+
+extern void enable_irq(unsigned int irq);
+extern void disable_irq(unsigned int irq);
+
+static int audio_dev;
+
+/* buffer size */
+
+#define BUFSIZE 128
+
+/* lock for access to writebuf. the interrupt handler does not check
+ * for this but interrupts are also disabled while we access writebuf
+ * in write
+ */
+
+static struct semaphore writebuf_lock;
+
+/* freelist for buffering data */
+
+static unsigned char writebuf[BUFSIZE];
+static int writebuf_head, writebuf_tail, writebuf_size;
+
+/* interrupt routine */
+
+void psionw_sound_isr(unsigned int irq)
+{
+	int i, count;
+
+	/* write some more data to the speaker */
+
+	count = writebuf_size < 8 ? writebuf_size : 8;
+
+	for (i=0; i<count; ++i) {
+		psionw_writeb(dsp_ulaw[writebuf[writebuf_head]], CODR);
+		writebuf_head = (writebuf_head + 1) % BUFSIZE;
+	}
+
+	for (; i<8; ++i) {
+		psionw_writeb(0, CODR);
+	}
+
+	writebuf_size -= count;
+
+	/* if we had nothing left, stop interrupts until we 
+	 * get more (set in the write function)
+	 */
+
+	if (count == 0) 
+		disable_irq(IRQ_CSINT);
+
+	/* clear interrupt */
+
+	psionw_writel(1, COEOI);
+
+}
+
+static ssize_t psionw_sound_read(struct file *file, char *buffer, 
+				 size_t count, loff_t *ppos)
+{
+	/* insert microphone code here */
+	return count;
+}
+
+static ssize_t psionw_sound_write(struct file *file, const char *buffer, 
+				  size_t count, loff_t *ppos)
+{
+	int i, n, ret = 0;
+
+	while (count > 0) {
+
+		/* check we can fit anything into the buffer */
+
+		if (writebuf_size >= BUFSIZE) {
+			if (file->f_flags & O_NONBLOCK)
+				break;
+
+			set_current_state(TASK_INTERRUPTIBLE);
+                        schedule_timeout(1);
+			continue;
+		}
+
+		down(&writebuf_lock);
+
+		/* disable irq while we do this */
+	
+		disable_irq(IRQ_CSINT);
+	
+		/* fit in as much as we can to the write buffer */
+	
+		if (count > BUFSIZE - writebuf_size)
+			n = BUFSIZE - writebuf_size;
+		else
+			n = count;
+	
+		/* this is complicated stuff to add to the buffer in blocks
+		 * rather than byte-by-byte, for speed
+		 * we dont want to disable the sound IRQ for too long or we
+		 * get nasty breaks in the sound
+		 */
+	
+		if (writebuf_tail >= writebuf_head) {
+	
+			/* fill in as much as possible at the end */
+	
+			i = BUFSIZE - writebuf_tail;
+	
+			if (i >= n) {
+	
+				/* we can fit them all at the end */
+	
+				memcpy(writebuf + writebuf_tail, buffer, n);
+			} else {
+	
+				/* first part at the end of buffer */
+	
+				memcpy(writebuf + writebuf_tail, buffer, i);
+	
+				/* second part at the beginning */
+	
+				memcpy(writebuf, buffer+i, n-i);
+			}
+		} else {
+	
+			/* just fit in as much as we can */
+	
+			memcpy(writebuf + writebuf_tail, buffer, n);
+		}
+	
+		writebuf_tail = (writebuf_tail + n) % BUFSIZE;
+		writebuf_size += n;
+
+		count -= n;
+		buffer += n;
+		ret += n;
+
+		/* enable irq again */
+
+		enable_irq(IRQ_CSINT);
+
+		up(&writebuf_lock);
+	}
+
+	if (file->f_flags & O_NONBLOCK && ret == 0)
+		return -EAGAIN;
+
+	return ret;
+}
+
+static int psionw_sound_ioctl(struct inode *inode, struct file *file, 
+	 		      unsigned int cmd, unsigned long arg)
+{
+	int val;
+
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		return 0;
+
+	case SNDCTL_DSP_SYNC:
+		/* we cant really do this, but we'll pretend
+		 * we can, to keep programs that use it happy
+		 */
+		return 0;
+
+	case SNDCTL_DSP_SPEED:  /* set sample rate */
+		/* we cant change it */
+
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		if (val >= 0)
+			return put_user(SAMPLE_RATE, (int *)arg);
+		else
+			return -EFAULT;
+
+	case SNDCTL_DSP_STEREO: /* set stereo or mono */
+
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		/* we are stuck in mono mode */
+
+		if (val)
+			printk("psionw_sound: attempt to put in stereo mode (unsupported)\n");
+	
+		return 0;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		return put_user(8, (int *)arg);  /* 8 byte block size (?) */
+
+	case SNDCTL_DSP_GETFMTS:
+		return put_user(AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT:
+		return put_user(AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_CHANNELS: 	/* set channels */
+		return put_user(1, (int *) arg);
+
+		
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+
+	}
+
+	return -EINVAL;
+}
+
+static int psionw_sound_open(struct inode *inode, struct file *file)
+{
+	down(&users_lock);
+
+	if (users > 0) {
+		up(&users_lock);
+		return -EBUSY;
+	}
+
+	++users;
+
+	/* empty list */
+
+	writebuf_head = writebuf_tail = writebuf_size = 0;
+
+	/* enable codec */
+
+	psionw_writeb(psionw_readb(PDDR) | PDDR_AMPEN | PDDR_CDE, PDDR);
+	psionw_writel(psionw_readl(CONFG) | CODINEN | CODOUTEN, CONFG);
+
+	/* enable sound irq */
+
+	irq_desc[IRQ_CSINT].mask_ack = psionw_sound_isr;
+
+	enable_irq(IRQ_CSINT);
+
+	up(&users_lock);
+
+	return 0; 
+}
+
+static int psionw_sound_release(struct inode *inode, struct file *file)
+{
+	down(&users_lock);
+
+	--users;
+
+	/* disable codec */
+
+	psionw_writeb(psionw_readb(PDDR) & ~(PDDR_AMPEN|PDDR_CDE), PDDR);
+	psionw_writel(psionw_readl(CONFG) & ~(CODINEN|CODOUTEN), CONFG);
+
+	/* disable sound irq */
+
+	disable_irq(IRQ_CSINT);
+
+	up(&users_lock);
+
+	return 0;
+}
+
+static int psionw_sound_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static struct file_operations sound_ops = {
+        owner:          THIS_MODULE,
+	llseek: 	no_llseek,
+	read: 		psionw_sound_read,
+        write:          psionw_sound_write,
+        ioctl:          psionw_sound_ioctl,
+	mmap:		psionw_sound_mmap,
+        open:           psionw_sound_open,
+        release:        psionw_sound_release,
+};
+
+int __init init_psionw_sound(void)
+{
+	audio_dev = register_sound_dsp(&sound_ops, -1);
+
+	if (audio_dev < 0) {
+		printk(KERN_ERR "psionw_sound: cannot register sound device\n");
+		return -ENODEV;
+	}
+
+	init_MUTEX(&writebuf_lock);
+	init_MUTEX(&users_lock);
+
+	printk("psionw_sound: initialised sound output\n");
+
+	return 0;
+}
+
+void __exit cleanup_psionw_sound(void)
+{
+	unregister_sound_dsp(audio_dev);
+}
+
+
+MODULE_DESCRIPTION("psionw sound output driver");
+MODULE_AUTHOR("Simon Howard");
+MODULE_LICENSE("GPL");
+
+module_init(init_psionw_sound);
+module_exit(cleanup_psionw_sound);
+
