
From: Ralf Baechle <ralf@linux-mips.org>

Update for the AMD Alchemy SOCs, platforms based on those and drivers specific
to the SOC and platforms.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/mips/Kconfig                           |   25 
 25-akpm/arch/mips/au1000/common/au1xxx_irqmap.c     |    1 
 25-akpm/arch/mips/au1000/common/cputable.c          |    2 
 25-akpm/arch/mips/au1000/common/dbdma.c             |    8 
 25-akpm/arch/mips/au1000/common/dma.c               |    5 
 25-akpm/arch/mips/au1000/common/irq.c               |    2 
 25-akpm/arch/mips/au1000/common/pci.c               |    9 
 25-akpm/arch/mips/au1000/common/platform.c          |    1 
 25-akpm/arch/mips/au1000/common/power.c             |    2 
 25-akpm/arch/mips/au1000/common/sleeper.S           |    1 
 25-akpm/arch/mips/au1000/common/time.c              |    9 
 25-akpm/arch/mips/au1000/csb250/board_setup.c       |   11 
 25-akpm/arch/mips/au1000/db1x00/mirage_ts.c         |    6 
 25-akpm/arch/mips/au1000/hydrogen3/board_setup.c    |    4 
 25-akpm/arch/mips/au1000/mtx-1/board_setup.c        |   12 
 25-akpm/arch/mips/au1000/mtx-1/init.c               |   23 
 25-akpm/arch/mips/au1000/mtx-1/irqmap.c             |   12 
 25-akpm/arch/mips/au1000/pb1000/board_setup.c       |   12 
 25-akpm/arch/mips/au1000/pb1000/irqmap.c            |    2 
 25-akpm/arch/mips/au1000/pb1100/board_setup.c       |    8 
 25-akpm/arch/mips/au1000/pb1500/board_setup.c       |    8 
 25-akpm/arch/mips/au1000/pb1550/board_setup.c       |    1 
 25-akpm/arch/mips/configs/db1000_defconfig          |   40 
 25-akpm/arch/mips/configs/db1100_defconfig          |   40 
 25-akpm/arch/mips/configs/db1500_defconfig          |   45 
 25-akpm/arch/mips/configs/db1550_defconfig          |   42 
 25-akpm/arch/mips/configs/pb1100_defconfig          |   43 
 25-akpm/arch/mips/configs/pb1500_defconfig          |   41 
 25-akpm/arch/mips/configs/pb1550_defconfig          |   41 
 25-akpm/arch/mips/pci/fixup-au1000.c                |   13 
 25-akpm/drivers/pcmcia/Kconfig                      |    4 
 25-akpm/drivers/pcmcia/Makefile                     |   11 
 25-akpm/drivers/pcmcia/au1000_db1x00.c              |  288 ++
 25-akpm/drivers/pcmcia/au1000_generic.c             |  942 +++-----
 25-akpm/drivers/pcmcia/au1000_generic.h             |  150 +
 25-akpm/drivers/pcmcia/au1000_pb1x00.c              |   43 
 25-akpm/drivers/pcmcia/au1000_xxs1500.c             |  191 +
 25-akpm/drivers/usb/host/ohci-au1xxx.c              |  362 +++
 25-akpm/drivers/usb/host/ohci-hcd.c                 |    5 
 25-akpm/drivers/video/Kconfig                       |   36 
 25-akpm/drivers/video/Makefile                      |    1 
 25-akpm/drivers/video/au1100fb.c                    |  676 ++++++
 25-akpm/drivers/video/au1100fb.h                    |  381 +++
 25-akpm/include/asm-mips/mach-au1x00/au1000.h       |    2 
 25-akpm/include/asm-mips/mach-au1x00/au1xxx_dbdma.h |    2 
 25-akpm/include/asm-mips/mach-au1x00/au1xxx_psc.h   |  349 +++
 25-akpm/include/asm-mips/mach-db1x00/db1x00.h       |    3 
 25-akpm/include/asm-mips/mach-pb1x00/pb1550.h       |   12 
 25-akpm/include/linux/ac97_codec.h                  |   33 
 25-akpm/sound/Kconfig                               |    2 
 25-akpm/sound/Makefile                              |    2 
 25-akpm/sound/mips/Kconfig                          |   15 
 25-akpm/sound/mips/Makefile                         |    8 
 25-akpm/sound/mips/au1x00.c                         |  686 ++++++
 25-akpm/sound/oss/Kconfig                           |    8 
 25-akpm/sound/oss/Makefile                          |    2 
 25-akpm/sound/oss/ac97_codec.c                      |    1 
 25-akpm/sound/oss/au1000.c                          |  205 -
 25-akpm/sound/oss/au1550_ac97.c                     | 2119 ++++++++++++++++++++
 59 files changed, 6166 insertions(+), 842 deletions(-)

diff -puN arch/mips/au1000/common/au1xxx_irqmap.c~mips-amd-alchemy-update arch/mips/au1000/common/au1xxx_irqmap.c
--- 25/arch/mips/au1000/common/au1xxx_irqmap.c~mips-amd-alchemy-update	2005-01-29 11:26:00.174721360 -0800
+++ 25-akpm/arch/mips/au1000/common/au1xxx_irqmap.c	2005-01-29 11:26:00.248710112 -0800
@@ -25,6 +25,7 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/irq.h>
diff -puN arch/mips/au1000/common/cputable.c~mips-amd-alchemy-update arch/mips/au1000/common/cputable.c
--- 25/arch/mips/au1000/common/cputable.c~mips-amd-alchemy-update	2005-01-29 11:26:00.176721056 -0800
+++ 25-akpm/arch/mips/au1000/common/cputable.c	2005-01-29 11:26:00.248710112 -0800
@@ -11,8 +11,6 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/threads.h>
diff -puN arch/mips/au1000/common/dbdma.c~mips-amd-alchemy-update arch/mips/au1000/common/dbdma.c
--- 25/arch/mips/au1000/common/dbdma.c~mips-amd-alchemy-update	2005-01-29 11:26:00.177720904 -0800
+++ 25-akpm/arch/mips/au1000/common/dbdma.c	2005-01-29 11:26:00.249709960 -0800
@@ -29,7 +29,7 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
-
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -55,7 +55,7 @@
  * functions.  The drivers allocate the data buffers and assign them
  * to the descriptors.
  */
-static spinlock_t au1xxx_dbdma_spin_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
 
 /* I couldn't find a macro that did this......
 */
@@ -370,7 +370,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int 
 	 * and if we try that first we are likely to not waste larger
 	 * slabs of memory.
 	 */
-	desc_base = kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
+	desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
 	if (desc_base == 0)
 		return 0;
 
@@ -381,7 +381,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int 
 		kfree((const void *)desc_base);
 		i = entries * sizeof(au1x_ddma_desc_t);
 		i += (sizeof(au1x_ddma_desc_t) - 1);
-		if ((desc_base = kmalloc(i, GFP_KERNEL)) == 0)
+		if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0)
 			return 0;
 
 		desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
diff -puN arch/mips/au1000/common/dma.c~mips-amd-alchemy-update arch/mips/au1000/common/dma.c
--- 25/arch/mips/au1000/common/dma.c~mips-amd-alchemy-update	2005-01-29 11:26:00.179720600 -0800
+++ 25-akpm/arch/mips/au1000/common/dma.c	2005-01-29 11:26:00.249709960 -0800
@@ -7,6 +7,7 @@
  * Copyright 2000 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
  *         	stevel@mvista.com or source@mvista.com
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -29,7 +30,7 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
-
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -61,7 +62,7 @@
  */
 
 
-spinlock_t au1000_dma_spin_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(au1000_dma_spin_lock);
 
 struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = {
       {.dev_id = -1,},
diff -puN arch/mips/au1000/common/irq.c~mips-amd-alchemy-update arch/mips/au1000/common/irq.c
--- 25/arch/mips/au1000/common/irq.c~mips-amd-alchemy-update	2005-01-29 11:26:00.180720448 -0800
+++ 25-akpm/arch/mips/au1000/common/irq.c	2005-01-29 11:26:00.250709808 -0800
@@ -86,7 +86,7 @@ void	(*board_init_irq)(void);
 extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
 #endif
 
-static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(irq_lock);
 
 
 static unsigned int startup_irq(unsigned int irq_nr)
diff -puN arch/mips/au1000/common/pci.c~mips-amd-alchemy-update arch/mips/au1000/common/pci.c
--- 25/arch/mips/au1000/common/pci.c~mips-amd-alchemy-update	2005-01-29 11:26:00.182720144 -0800
+++ 25-akpm/arch/mips/au1000/common/pci.c	2005-01-29 11:26:00.250709808 -0800
@@ -78,10 +78,13 @@ static int __init au1x_pci_setup(void)
 
 #ifdef CONFIG_DMA_NONCOHERENT
 	/* 
-	 *  Set the NC bit in controller for pre-AC silicon
+         *  Set the NC bit in controller for Au1500 pre-AC silicon
 	 */
-	au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG);
-	printk("Non-coherent PCI accesses enabled\n");
+	u32 prid = read_c0_prid();
+	if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
+	       au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG);
+	       printk("Non-coherent PCI accesses enabled\n");
+	}
 #endif
 
 	set_io_port_base(virt_io_addr);
diff -puN arch/mips/au1000/common/platform.c~mips-amd-alchemy-update arch/mips/au1000/common/platform.c
--- 25/arch/mips/au1000/common/platform.c~mips-amd-alchemy-update	2005-01-29 11:26:00.183719992 -0800
+++ 25-akpm/arch/mips/au1000/common/platform.c	2005-01-29 11:26:00.251709656 -0800
@@ -7,7 +7,6 @@
  * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
-#include <linux/config.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff -puN arch/mips/au1000/common/power.c~mips-amd-alchemy-update arch/mips/au1000/common/power.c
--- 25/arch/mips/au1000/common/power.c~mips-amd-alchemy-update	2005-01-29 11:26:00.185719688 -0800
+++ 25-akpm/arch/mips/au1000/common/power.c	2005-01-29 11:26:00.251709656 -0800
@@ -66,7 +66,7 @@ extern void local_enable_irq(unsigned in
 #define	ACPI_SLEEP 21
 
 
-static spinlock_t pm_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pm_lock);
 
 /* We need to save/restore a bunch of core registers that are
  * either volatile or reset to some state across a processor sleep.
diff -puN arch/mips/au1000/common/sleeper.S~mips-amd-alchemy-update arch/mips/au1000/common/sleeper.S
--- 25/arch/mips/au1000/common/sleeper.S~mips-amd-alchemy-update	2005-01-29 11:26:00.186719536 -0800
+++ 25-akpm/arch/mips/au1000/common/sleeper.S	2005-01-29 11:26:00.252709504 -0800
@@ -9,7 +9,6 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
-#include <linux/config.h>
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
diff -puN arch/mips/au1000/common/time.c~mips-amd-alchemy-update arch/mips/au1000/common/time.c
--- 25/arch/mips/au1000/common/time.c~mips-amd-alchemy-update	2005-01-29 11:26:00.187719384 -0800
+++ 25-akpm/arch/mips/au1000/common/time.c	2005-01-29 11:26:00.252709504 -0800
@@ -69,7 +69,7 @@ extern void startup_match20_interrupt(vo
 static unsigned long last_pc0, last_match20;
 #endif
 
-static spinlock_t time_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(time_lock);
 
 static inline void ack_r4ktimer(unsigned long newval)
 {
@@ -304,8 +304,7 @@ unsigned long cal_r4koff(void)
 
 /* This is for machines which generate the exact clock. */
 #define USECS_PER_JIFFY (1000000/HZ)
-#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff)
-
+#define USECS_PER_JIFFY_FRAC (0x100000000LL*1000000/HZ&0xffffffff)
 
 static unsigned long
 div64_32(unsigned long v1, unsigned long v2, unsigned long v3)
@@ -407,10 +406,6 @@ void au1xxx_timer_setup(struct irqaction
 	r4k_cur = (read_c0_count() + r4k_offset);
 	write_c0_compare(r4k_cur);
 
-	/* no RTC on the pb1000 */
-	xtime.tv_sec = 0;
-	//xtime.tv_usec = 0;
-
 #ifdef CONFIG_PM
 	/*
 	 * setup counter 0, since it keeps ticking after a
diff -puN arch/mips/au1000/csb250/board_setup.c~mips-amd-alchemy-update arch/mips/au1000/csb250/board_setup.c
--- 25/arch/mips/au1000/csb250/board_setup.c~mips-amd-alchemy-update	2005-01-29 11:26:00.189719080 -0800
+++ 25-akpm/arch/mips/au1000/csb250/board_setup.c	2005-01-29 11:26:00.253709352 -0800
@@ -45,16 +45,6 @@
 #include <asm/au1000.h>
 #include <asm/csb250.h>
 
-#ifdef CONFIG_USB_OHCI
-// Enable the workaround for the OHCI DoneHead
-// register corruption problem.
-#define CONFIG_AU1000_OHCI_FIX
-#endif
-
-#ifdef CONFIG_RTC
-extern struct rtc_ops csb250_rtc_ops;
-#endif
-
 extern int (*board_pci_idsel)(unsigned int devsel, int assert);
 int	csb250_pci_idsel(unsigned int devsel, int assert);
 
@@ -203,7 +193,6 @@ void __init board_setup(void)
 	au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
 
 #ifdef CONFIG_RTC
-	rtc_ops = &csb250_rtc_ops;
 	// Enable the RTC if not already enabled
 	if (!(au_readl(0xac000028) & 0x20)) {
 		printk("enabling clock ...\n");
diff -puN arch/mips/au1000/db1x00/mirage_ts.c~mips-amd-alchemy-update arch/mips/au1000/db1x00/mirage_ts.c
--- 25/arch/mips/au1000/db1x00/mirage_ts.c~mips-amd-alchemy-update	2005-01-29 11:26:00.190718928 -0800
+++ 25-akpm/arch/mips/au1000/db1x00/mirage_ts.c	2005-01-29 11:26:00.254709200 -0800
@@ -42,6 +42,7 @@
 #include <linux/proc_fs.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/wait.h>
 
 #include <asm/segment.h>
 #include <asm/irq.h>
@@ -147,10 +148,7 @@ static int ts_thread(void *id)
 	ts = wm97xx_ts_get_handle(0);
 
 	/* proceed only after everybody is ready */
-	while ( ! wm97xx_ts_ready(ts) ) {
-		/* give a little time for initializations to complete */
-		interruptible_sleep_on_timeout(&pendown_wait, HZ / 4);
-	}
+	wait_event_timeout(pendown_wait, wm97xx_ts_ready(ts), HZ/4);
 
 	/* board-specific calibration */
 	wm97xx_ts_set_cal(ts,
diff -puN arch/mips/au1000/hydrogen3/board_setup.c~mips-amd-alchemy-update arch/mips/au1000/hydrogen3/board_setup.c
--- 25/arch/mips/au1000/hydrogen3/board_setup.c~mips-amd-alchemy-update	2005-01-29 11:26:00.191718776 -0800
+++ 25-akpm/arch/mips/au1000/hydrogen3/board_setup.c	2005-01-29 11:26:00.255709048 -0800
@@ -45,8 +45,6 @@
 #include <asm/pgtable.h>
 #include <asm/au1000.h>
 
-extern struct rtc_ops no_rtc_ops;
-
 void board_reset (void)
 {
 }
@@ -55,8 +53,6 @@ void __init board_setup(void)
 {
 	u32 pin_func;
 
-	rtc_ops = &no_rtc_ops;
-
 #ifdef CONFIG_AU1X00_USB_DEVICE
 	// 2nd USB port is USB device
 	pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
diff -puN arch/mips/au1000/mtx-1/board_setup.c~mips-amd-alchemy-update arch/mips/au1000/mtx-1/board_setup.c
--- 25/arch/mips/au1000/mtx-1/board_setup.c~mips-amd-alchemy-update	2005-01-29 11:26:00.193718472 -0800
+++ 25-akpm/arch/mips/au1000/mtx-1/board_setup.c	2005-01-29 11:26:00.256708896 -0800
@@ -34,24 +34,24 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/console.h>
-#include <linux/mc146818rtc.h>
 #include <linux/delay.h>
 
 #include <asm/cpu.h>
 #include <asm/bootinfo.h>
 #include <asm/irq.h>
-#include <asm/keyboard.h>
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
 #include <asm/pgtable.h>
-#include <asm/au1000.h>
+#include <asm/mach-au1x00/au1000.h>
 
-extern struct rtc_ops no_rtc_ops;
+void board_reset (void)
+{
+	/* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+	au_writel(0x00000000, 0xAE00001C);
+}
 
 void __init board_setup(void)
 {
-	rtc_ops = &no_rtc_ops;
-
 #if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
 #ifdef CONFIG_AU1X00_USB_DEVICE
 	// 2nd USB port is USB device
diff -puN arch/mips/au1000/mtx-1/init.c~mips-amd-alchemy-update arch/mips/au1000/mtx-1/init.c
--- 25/arch/mips/au1000/mtx-1/init.c~mips-amd-alchemy-update	2005-01-29 11:26:00.194718320 -0800
+++ 25-akpm/arch/mips/au1000/mtx-1/init.c	2005-01-29 11:26:00.256708896 -0800
@@ -28,17 +28,15 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
-
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/bootmem.h>
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
 
 int prom_argc;
 char **prom_argv, **prom_envp;
@@ -50,25 +48,24 @@ const char *get_system_type(void)
 	return "MTX-1";
 }
 
-int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
+void __init prom_init(void)
 {
 	unsigned char *memsize_str;
 	unsigned long memsize;
 
-	prom_argc = argc;
-	prom_argv = argv;
-	prom_envp = envp;
+	prom_argc = fw_arg0;
+	prom_argv = (char **) fw_arg1;
+	prom_envp = (char **) fw_arg2;
 
 	mips_machgroup = MACH_GROUP_ALCHEMY;
 	mips_machtype = MACH_MTX1;	/* set the platform # */
+
 	prom_init_cmdline();
 
 	memsize_str = prom_getenv("memsize");
-	if (!memsize_str) {
+	if (!memsize_str)
 		memsize = 0x04000000;
-	} else {
+	else
 		memsize = simple_strtol(memsize_str, NULL, 0);
-	}
 	add_memory_region(0, memsize, BOOT_MEM_RAM);
-	return 0;
 }
diff -puN arch/mips/au1000/mtx-1/irqmap.c~mips-amd-alchemy-update arch/mips/au1000/mtx-1/irqmap.c
--- 25/arch/mips/au1000/mtx-1/irqmap.c~mips-amd-alchemy-update	2005-01-29 11:26:00.195718168 -0800
+++ 25-akpm/arch/mips/au1000/mtx-1/irqmap.c	2005-01-29 11:26:00.257708744 -0800
@@ -45,12 +45,14 @@
 #include <asm/io.h>
 #include <asm/mipsregs.h>
 #include <asm/system.h>
-#include <asm/au1000.h>
+#include <asm/mach-au1x00/au1000.h>
 
-/* Need to define this.
-*/
 au1xxx_irq_map_t au1xxx_irq_map[] = {
-	{ 0. 0. 0}
+       { AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0},
+       { AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 },
+       { AU1500_GPIO_202, INTC_INT_LOW_LEVEL, 0 },
+       { AU1500_GPIO_203, INTC_INT_LOW_LEVEL, 0 },
+       { AU1500_GPIO_205, INTC_INT_LOW_LEVEL, 0 },
 };
 
-int au1xxx_nr_irqs = 0;
+int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
diff -puN arch/mips/au1000/pb1000/board_setup.c~mips-amd-alchemy-update arch/mips/au1000/pb1000/board_setup.c
--- 25/arch/mips/au1000/pb1000/board_setup.c~mips-amd-alchemy-update	2005-01-29 11:26:00.196718016 -0800
+++ 25-akpm/arch/mips/au1000/pb1000/board_setup.c	2005-01-29 11:26:00.258708592 -0800
@@ -37,16 +37,8 @@
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
 #include <asm/pgtable.h>
-#include <asm/au1000.h>
-#include <asm/pb1000.h>
-
-#ifdef CONFIG_USB_OHCI
-// Enable the workaround for the OHCI DoneHead
-// register corruption problem.
-#define CONFIG_AU1000_OHCI_FIX
-        ^^^^^^^^^^^^^^^^^^^^^^
-    !!! I shall not define symbols starting with CONFIG_ !!!
-#endif
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-pb1x00/pb1000.h>
 
 void board_reset (void)
 {
diff -puN arch/mips/au1000/pb1000/irqmap.c~mips-amd-alchemy-update arch/mips/au1000/pb1000/irqmap.c
--- 25/arch/mips/au1000/pb1000/irqmap.c~mips-amd-alchemy-update	2005-01-29 11:26:00.198717712 -0800
+++ 25-akpm/arch/mips/au1000/pb1000/irqmap.c	2005-01-29 11:26:00.258708592 -0800
@@ -45,7 +45,7 @@
 #include <asm/io.h>
 #include <asm/mipsregs.h>
 #include <asm/system.h>
-#include <asm/au1000.h>
+#include <asm/mach-au1x00/au1000.h>
 
 au1xxx_irq_map_t au1xxx_irq_map[] = {
 	{ AU1000_GPIO_15, INTC_INT_LOW_LEVEL, 0 },
diff -puN arch/mips/au1000/pb1100/board_setup.c~mips-amd-alchemy-update arch/mips/au1000/pb1100/board_setup.c
--- 25/arch/mips/au1000/pb1100/board_setup.c~mips-amd-alchemy-update	2005-01-29 11:26:00.199717560 -0800
+++ 25-akpm/arch/mips/au1000/pb1100/board_setup.c	2005-01-29 11:26:00.259708440 -0800
@@ -40,14 +40,6 @@
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-pb1x00/pb1100.h>
 
-#ifdef CONFIG_USB_OHCI
-// Enable the workaround for the OHCI DoneHead
-// register corruption problem.
-#define CONFIG_AU1000_OHCI_FIX
-        ^^^^^^^^^^^^^^^^^^^^^^
-    !!! I shall not define symbols starting with CONFIG_ !!!
-#endif
-
 void board_reset (void)
 {
     /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
diff -puN arch/mips/au1000/pb1500/board_setup.c~mips-amd-alchemy-update arch/mips/au1000/pb1500/board_setup.c
--- 25/arch/mips/au1000/pb1500/board_setup.c~mips-amd-alchemy-update	2005-01-29 11:26:00.200717408 -0800
+++ 25-akpm/arch/mips/au1000/pb1500/board_setup.c	2005-01-29 11:26:00.259708440 -0800
@@ -40,14 +40,6 @@
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-pb1x00/pb1500.h>
 
-#ifdef CONFIG_USB_OHCI
-// Enable the workaround for the OHCI DoneHead
-// register corruption problem.
-#define CONFIG_AU1000_OHCI_FIX
-        ^^^^^^^^^^^^^^^^^^^^^^
-    !!! I shall not define symbols starting with CONFIG_ !!!
-#endif
-
 void board_reset (void)
 {
     /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
diff -puN arch/mips/au1000/pb1550/board_setup.c~mips-amd-alchemy-update arch/mips/au1000/pb1550/board_setup.c
--- 25/arch/mips/au1000/pb1550/board_setup.c~mips-amd-alchemy-update	2005-01-29 11:26:00.202717104 -0800
+++ 25-akpm/arch/mips/au1000/pb1550/board_setup.c	2005-01-29 11:26:00.260708288 -0800
@@ -27,7 +27,6 @@
  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
diff -puN arch/mips/configs/db1000_defconfig~mips-amd-alchemy-update arch/mips/configs/db1000_defconfig
--- 25/arch/mips/configs/db1000_defconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.203716952 -0800
+++ 25-akpm/arch/mips/configs/db1000_defconfig	2005-01-29 11:26:00.282704944 -0800
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Sun Nov 21 14:11:56 2004
+# Linux kernel version: 2.6.11-rc2
+# Wed Jan 26 02:49:01 2005
 #
 CONFIG_MIPS=y
 # CONFIG_MIPS64 is not set
@@ -101,11 +101,11 @@ CONFIG_MIPS_DB1000=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_FB is not set
 
 #
 # CPU selection
@@ -132,7 +132,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
 CONFIG_64BIT_PHYS_ADDR=y
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
@@ -151,7 +150,6 @@ CONFIG_MMU=y
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 
 #
@@ -200,10 +198,12 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 CONFIG_CDROM_PKTCDVD=m
@@ -217,6 +217,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -293,8 +294,6 @@ CONFIG_IP_NF_CONNTRACK_MARK=y
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -426,6 +425,7 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_LIBPS2 is not set
 CONFIG_SERIO_RAW=m
 
 #
@@ -479,7 +479,6 @@ CONFIG_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -515,12 +514,14 @@ CONFIG_SYNCLINK_CS=m
 #
 # Graphics support
 #
+# CONFIG_FB is not set
 
 #
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -534,11 +535,25 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -686,6 +701,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
@@ -728,6 +748,10 @@ CONFIG_CRYPTO_CRC32C=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff -puN arch/mips/configs/db1100_defconfig~mips-amd-alchemy-update arch/mips/configs/db1100_defconfig
--- 25/arch/mips/configs/db1100_defconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.204716800 -0800
+++ 25-akpm/arch/mips/configs/db1100_defconfig	2005-01-29 11:26:00.280705248 -0800
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Sun Nov 21 14:11:56 2004
+# Linux kernel version: 2.6.11-rc2
+# Wed Jan 26 02:49:01 2005
 #
 CONFIG_MIPS=y
 # CONFIG_MIPS64 is not set
@@ -101,11 +101,11 @@ CONFIG_MIPS_DB1100=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_FB is not set
 
 #
 # CPU selection
@@ -132,7 +132,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
@@ -149,7 +148,6 @@ CONFIG_MMU=y
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 
 #
@@ -198,10 +196,12 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 CONFIG_CDROM_PKTCDVD=m
@@ -215,6 +215,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -291,8 +292,6 @@ CONFIG_IP_NF_CONNTRACK_MARK=y
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -424,6 +423,7 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
+CONFIG_SERIO_LIBPS2=m
 CONFIG_SERIO_RAW=m
 
 #
@@ -474,7 +474,6 @@ CONFIG_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -510,12 +509,14 @@ CONFIG_SYNCLINK_CS=m
 #
 # Graphics support
 #
+# CONFIG_FB is not set
 
 #
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -529,11 +530,25 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -681,6 +696,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
@@ -723,6 +743,10 @@ CONFIG_CRYPTO_CRC32C=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff -puN arch/mips/configs/db1500_defconfig~mips-amd-alchemy-update arch/mips/configs/db1500_defconfig
--- 25/arch/mips/configs/db1500_defconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.206716496 -0800
+++ 25-akpm/arch/mips/configs/db1500_defconfig	2005-01-29 11:26:00.283704792 -0800
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Sun Nov 21 14:11:56 2004
+# Linux kernel version: 2.6.11-rc2
+# Wed Jan 26 02:49:01 2005
 #
 CONFIG_MIPS=y
 # CONFIG_MIPS64 is not set
@@ -101,12 +101,12 @@ CONFIG_MIPS_DB1500=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_COHERENT=y
 CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_FB is not set
 
 #
 # CPU selection
@@ -133,7 +133,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
 CONFIG_64BIT_PHYS_ADDR=y
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
@@ -154,7 +153,6 @@ CONFIG_MMU=y
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 CONFIG_CARDBUS=y
 
@@ -234,6 +232,7 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
 
 #
 # Mapping drivers for chip access
@@ -252,6 +251,7 @@ CONFIG_MTD_DB1X00_USER=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -282,12 +282,14 @@ CONFIG_MTD_DB1X00_USER=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 CONFIG_CDROM_PKTCDVD=m
@@ -301,6 +303,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -402,8 +405,6 @@ CONFIG_IP_NF_CONNTRACK_MARK=y
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -557,6 +558,7 @@ CONFIG_SERIO=y
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_LIBPS2 is not set
 CONFIG_SERIO_RAW=m
 
 #
@@ -609,7 +611,6 @@ CONFIG_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -645,6 +646,8 @@ CONFIG_SYNCLINK_CS=m
 #
 # Graphics support
 #
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -705,6 +708,7 @@ CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB_EHCI_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
 
 #
 # USB Device Class drivers
@@ -714,6 +718,10 @@ CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_MIDI is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
 # CONFIG_USB_STORAGE is not set
 
 #
@@ -769,7 +777,6 @@ CONFIG_USB_HIDINPUT=y
 #
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
-# CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
@@ -778,6 +785,7 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_CYTHERM is not set
 # CONFIG_USB_PHIDGETKIT is not set
 # CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
 
 #
 # USB ATM/DSL drivers
@@ -789,6 +797,16 @@ CONFIG_USB_HIDINPUT=y
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -938,6 +956,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
@@ -980,6 +1003,10 @@ CONFIG_CRYPTO_CRC32C=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff -puN arch/mips/configs/db1550_defconfig~mips-amd-alchemy-update arch/mips/configs/db1550_defconfig
--- 25/arch/mips/configs/db1550_defconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.207716344 -0800
+++ 25-akpm/arch/mips/configs/db1550_defconfig	2005-01-29 11:26:00.285704488 -0800
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Sun Nov 21 14:11:57 2004
+# Linux kernel version: 2.6.11-rc2
+# Wed Jan 26 02:49:02 2005
 #
 CONFIG_MIPS=y
 # CONFIG_MIPS64 is not set
@@ -101,12 +101,12 @@ CONFIG_MIPS_DB1550=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_COHERENT=y
 CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_FB is not set
 
 #
 # CPU selection
@@ -133,7 +133,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
 CONFIG_64BIT_PHYS_ADDR=y
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
@@ -154,7 +153,6 @@ CONFIG_MMU=y
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 CONFIG_CARDBUS=y
 
@@ -252,6 +250,7 @@ CONFIG_MTD_DB1550_USER=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -268,6 +267,7 @@ CONFIG_MTD_NAND=m
 CONFIG_MTD_NAND_IDS=m
 CONFIG_MTD_NAND_AU1550=m
 # CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
 
 #
 # Parallel port support
@@ -286,11 +286,13 @@ CONFIG_MTD_NAND_AU1550=m
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 CONFIG_CDROM_PKTCDVD=m
@@ -304,6 +306,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -433,8 +436,6 @@ CONFIG_IP_NF_CONNTRACK_MARK=y
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -596,6 +597,7 @@ CONFIG_SERIO=y
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_LIBPS2 is not set
 CONFIG_SERIO_RAW=m
 
 #
@@ -649,7 +651,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -685,6 +686,8 @@ CONFIG_SYNCLINK_CS=m
 #
 # Graphics support
 #
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -699,11 +702,25 @@ CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -853,6 +870,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
@@ -895,6 +917,10 @@ CONFIG_CRYPTO_CRC32C=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff -puN arch/mips/configs/pb1100_defconfig~mips-amd-alchemy-update arch/mips/configs/pb1100_defconfig
--- 25/arch/mips/configs/pb1100_defconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.209716040 -0800
+++ 25-akpm/arch/mips/configs/pb1100_defconfig	2005-01-29 11:26:00.262707984 -0800
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Sun Nov 21 14:12:05 2004
+# Linux kernel version: 2.6.11-rc2
+# Wed Jan 26 02:49:08 2005
 #
 CONFIG_MIPS=y
 # CONFIG_MIPS64 is not set
@@ -101,13 +101,13 @@ CONFIG_MIPS_PB1100=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_NONCOHERENT=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_SWAP_IO_SPACE=y
-# CONFIG_AU1000_USB_DEVICE is not set
+# CONFIG_AU1X00_USB_DEVICE is not set
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_FB is not set
 
 #
 # CPU selection
@@ -134,7 +134,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
 # CONFIG_64BIT_PHYS_ADDR is not set
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
@@ -153,7 +152,6 @@ CONFIG_MMU=y
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 
 #
@@ -245,6 +243,7 @@ CONFIG_MTD_PB1500_USER=y
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -271,10 +270,12 @@ CONFIG_MTD_PB1500_USER=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 CONFIG_CDROM_PKTCDVD=m
@@ -288,6 +289,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -364,8 +366,6 @@ CONFIG_IP_NF_CONNTRACK_MARK=y
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -489,6 +489,7 @@ CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_LIBPS2 is not set
 CONFIG_SERIO_RAW=m
 
 #
@@ -539,7 +540,6 @@ CONFIG_RTC=y
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -575,12 +575,14 @@ CONFIG_SYNCLINK_CS=m
 #
 # Graphics support
 #
+# CONFIG_FB is not set
 
 #
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -594,11 +596,25 @@ CONFIG_DUMMY_CONSOLE=y
 # CONFIG_USB_ARCH_HAS_OHCI is not set
 
 #
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -748,6 +764,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
@@ -790,6 +811,10 @@ CONFIG_CRYPTO_CRC32C=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff -puN arch/mips/configs/pb1500_defconfig~mips-amd-alchemy-update arch/mips/configs/pb1500_defconfig
--- 25/arch/mips/configs/pb1500_defconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.210715888 -0800
+++ 25-akpm/arch/mips/configs/pb1500_defconfig	2005-01-29 11:26:00.318699472 -0800
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Sun Nov 21 14:12:05 2004
+# Linux kernel version: 2.6.11-rc2
+# Wed Jan 26 02:49:09 2005
 #
 CONFIG_MIPS=y
 # CONFIG_MIPS64 is not set
@@ -101,12 +101,12 @@ CONFIG_MIPS_PB1500=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_COHERENT=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 # CONFIG_AU1X00_USB_DEVICE is not set
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_FB is not set
 
 #
 # CPU selection
@@ -133,7 +133,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
 CONFIG_64BIT_PHYS_ADDR=y
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
@@ -154,7 +153,6 @@ CONFIG_MMU=y
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 CONFIG_CARDBUS=y
 
@@ -166,6 +164,7 @@ CONFIG_PD6729=m
 # CONFIG_I82092 is not set
 # CONFIG_TCIC is not set
 # CONFIG_PCMCIA_AU1X00 is not set
+CONFIG_PCCARD_NONSTATIC=m
 
 #
 # PCI Hotplug Support
@@ -212,11 +211,13 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 CONFIG_CDROM_PKTCDVD=m
@@ -230,6 +231,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -359,8 +361,6 @@ CONFIG_IP_NF_CONNTRACK_MARK=y
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -522,6 +522,7 @@ CONFIG_SERIO=y
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_LIBPS2 is not set
 CONFIG_SERIO_RAW=m
 
 #
@@ -575,7 +576,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -611,6 +611,8 @@ CONFIG_SYNCLINK_CS=m
 #
 # Graphics support
 #
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -625,11 +627,25 @@ CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -777,6 +793,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
@@ -819,6 +840,10 @@ CONFIG_CRYPTO_MICHAEL_MIC=y
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff -puN arch/mips/configs/pb1550_defconfig~mips-amd-alchemy-update arch/mips/configs/pb1550_defconfig
--- 25/arch/mips/configs/pb1550_defconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.211715736 -0800
+++ 25-akpm/arch/mips/configs/pb1550_defconfig	2005-01-29 11:26:00.317699624 -0800
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc2
-# Sun Nov 21 14:12:05 2004
+# Linux kernel version: 2.6.11-rc2
+# Wed Jan 26 02:49:09 2005
 #
 CONFIG_MIPS=y
 # CONFIG_MIPS64 is not set
@@ -101,12 +101,12 @@ CONFIG_MIPS_PB1550=y
 # CONFIG_SNI_RM200_PCI is not set
 # CONFIG_TOSHIBA_RBTX4927 is not set
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_DMA_COHERENT=y
 CONFIG_MIPS_DISABLE_OBSOLETE_IDE=y
 CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_FB is not set
 
 #
 # CPU selection
@@ -133,7 +133,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
 CONFIG_CPU_HAS_PREFETCH=y
-# CONFIG_VTAG_ICACHE is not set
 CONFIG_64BIT_PHYS_ADDR=y
 # CONFIG_CPU_ADVANCED is not set
 CONFIG_CPU_HAS_LLSC=y
@@ -154,7 +153,6 @@ CONFIG_MMU=y
 #
 CONFIG_PCCARD=m
 # CONFIG_PCMCIA_DEBUG is not set
-# CONFIG_PCMCIA_OBSOLETE is not set
 CONFIG_PCMCIA=m
 CONFIG_CARDBUS=y
 
@@ -166,6 +164,7 @@ CONFIG_PD6729=m
 # CONFIG_I82092 is not set
 # CONFIG_TCIC is not set
 # CONFIG_PCMCIA_AU1X00 is not set
+CONFIG_PCCARD_NONSTATIC=m
 
 #
 # PCI Hotplug Support
@@ -212,11 +211,13 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_SX8 is not set
 # CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_INITRAMFS_SOURCE=""
 # CONFIG_LBD is not set
 CONFIG_CDROM_PKTCDVD=m
@@ -230,6 +231,7 @@ CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
 CONFIG_IOSCHED_CFQ=y
+CONFIG_ATA_OVER_ETH=m
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -359,8 +361,6 @@ CONFIG_IP_NF_CONNTRACK_MARK=y
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 CONFIG_XFRM=y
 CONFIG_XFRM_USER=m
 
@@ -514,6 +514,7 @@ CONFIG_SERIO=y
 CONFIG_SERIO_SERPORT=y
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_LIBPS2 is not set
 CONFIG_SERIO_RAW=m
 
 #
@@ -567,7 +568,6 @@ CONFIG_LEGACY_PTY_COUNT=256
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 
 #
@@ -603,6 +603,8 @@ CONFIG_SYNCLINK_CS=m
 #
 # Graphics support
 #
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -617,11 +619,25 @@ CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 
 #
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
 
 #
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -769,6 +785,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
 # CONFIG_NLS_UTF8 is not set
 
 #
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
@@ -811,6 +832,10 @@ CONFIG_CRYPTO_CRC32C=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
 CONFIG_CRC_CCITT=m
diff -puN arch/mips/Kconfig~mips-amd-alchemy-update arch/mips/Kconfig
--- 25/arch/mips/Kconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.213715432 -0800
+++ 25-akpm/arch/mips/Kconfig	2005-01-29 11:26:00.320699168 -0800
@@ -513,31 +513,31 @@ config SOC_AU1X00
 choice
 	prompt "Au1X00 SOC Type"
 	depends on SOC_AU1X00
-        help
-           Say Y here to enable support for one of three AMD/Alchemy
-           SOCs. For additional documentation see www.amd.com.
+	help
+	  Say Y here to enable support for one of three AMD/Alchemy
+	  SOCs. For additional documentation see www.amd.com.
 
 config SOC_AU1000
-        bool "SOC_AU1000"
+	bool "SOC_AU1000"
 config SOC_AU1100
-        bool "SOC_AU1100"
+	bool "SOC_AU1100"
 config SOC_AU1500
-        bool "SOC_AU1500"
+	bool "SOC_AU1500"
 config SOC_AU1550
-        bool "SOC_AU1550"
+	bool "SOC_AU1550"
 
 endchoice
 
 choice
-        prompt "AMD/Alchemy Au1x00 board support"
-        depends on SOC_AU1X00
+	prompt "AMD/Alchemy Au1x00 board support"
+	depends on SOC_AU1X00
 	help
 	  These are evaluation boards built by AMD/Alchemy to
 	  showcase their Au1X00 Internet Edge Processors. The SOC design
 	  is based on the MIPS32 architecture running at 266/400/500MHz
-          with many integrated peripherals. Further information can be
-          found at their website, <http://www.amd.com/>. Say Y here if you
-          wish to build a kernel for this platform.
+	  with many integrated peripherals. Further information can be
+	  found at their website, <http://www.amd.com/>. Say Y here if you
+	  wish to build a kernel for this platform.
 
 config MIPS_PB1000
 	bool "PB1000 board"
@@ -609,6 +609,7 @@ config MIPS_XXS1500
 config MIPS_MTX1
 	bool "4G Systems MTX-1 board"
 	depends on SOC_AU1500
+	select HW_HAS_PCI
 	select DMA_NONCOHERENT
 
 endchoice
diff -puN arch/mips/pci/fixup-au1000.c~mips-amd-alchemy-update arch/mips/pci/fixup-au1000.c
--- 25/arch/mips/pci/fixup-au1000.c~mips-amd-alchemy-update	2005-01-29 11:26:00.214715280 -0800
+++ 25-akpm/arch/mips/pci/fixup-au1000.c	2005-01-29 11:26:00.315699928 -0800
@@ -98,6 +98,19 @@ static char irq_tab_alchemy[][5] __initd
 };
 #endif
 
+#ifdef CONFIG_MIPS_MTX1
+static char irq_tab_alchemy[][5] __initdata = {
+ [0] = { -1, INTA, INTB, INTX, INTX},   /* IDSEL 00 - AdapterA-Slot0 (top)    */
+ [1] = { -1, INTB, INTA, INTX, INTX},   /* IDSEL 01 - AdapterA-Slot1 (bottom) */
+ [2] = { -1, INTC, INTD, INTX, INTX},   /* IDSEL 02 - AdapterB-Slot0 (top)    */
+ [3] = { -1, INTD, INTC, INTX, INTX},   /* IDSEL 03 - AdapterB-Slot1 (bottom) */
+ [4] = { -1, INTA, INTB, INTX, INTX},   /* IDSEL 04 - AdapterC-Slot0 (top)    */
+ [5] = { -1, INTB, INTA, INTX, INTX},   /* IDSEL 05 - AdapterC-Slot1 (bottom) */
+ [6] = { -1, INTC, INTD, INTX, INTX},   /* IDSEL 06 - AdapterD-Slot0 (top)    */
+ [7] = { -1, INTD, INTC, INTX, INTX},   /* IDSEL 07 - AdapterD-Slot1 (bottom) */
+};
+#endif
+
 int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
 	return irq_tab_alchemy[slot][pin];
diff -puN /dev/null drivers/pcmcia/au1000_db1x00.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/pcmcia/au1000_db1x00.c	2005-01-29 11:26:00.263707832 -0800
@@ -0,0 +1,288 @@
+/*
+ *
+ * Alchemy Semi Db1x00 boards specific pcmcia routines.
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ * Copyright 2004 Pete Popov, updated the driver to 2.6.
+ * Followed the sa11xx API and largely copied many of the hardware
+ * independent functions.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/signal.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/db1x00.h>
+
+#include "au1000_generic.h"
+
+#if 0
+#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
+#else
+#define debug(x,args...)
+#endif
+
+static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
+
+struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS];
+extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int);
+
+static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt)
+{
+#ifdef CONFIG_MIPS_DB1550
+	skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3;
+#else
+	skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2;
+#endif
+	return 0;
+}
+
+static void db1x00_pcmcia_shutdown(struct au1000_pcmcia_socket *skt)
+{
+	bcsr->pcmcia = 0; /* turn off power */
+	au_sync_delay(2);
+}
+
+static void
+db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state *state)
+{
+	u32 inserted;
+	unsigned char vs;
+
+	state->ready = 0;
+	state->vs_Xv = 0;
+	state->vs_3v = 0;
+	state->detect = 0;
+
+	switch (skt->nr) {
+	case 0:
+		vs = bcsr->status & 0x3;
+		inserted = !(bcsr->status & (1<<4));
+		break;
+	case 1:
+		vs = (bcsr->status & 0xC)>>2;
+		inserted = !(bcsr->status & (1<<5));
+		break;
+	default:/* should never happen */
+		return;
+	}
+
+	if (inserted)
+		debug("db1x00 socket %d: inserted %d, vs %d pcmcia %x\n",
+				skt->nr, inserted, vs, bcsr->pcmcia);
+
+	if (inserted) {
+		switch (vs) {
+			case 0:
+			case 2:
+				state->vs_3v=1;
+				break;
+			case 3: /* 5V */
+				break;
+			default:
+				/* return without setting 'detect' */
+				printk(KERN_ERR "db1x00 bad VS (%d)\n",
+						vs);
+		}
+		state->detect = 1;
+		state->ready = 1;
+	}
+	else {
+		/* if the card was previously inserted and then ejected,
+		 * we should turn off power to it
+		 */
+		if ((skt->nr == 0) && (bcsr->pcmcia & BCSR_PCMCIA_PC0RST)) {
+			bcsr->pcmcia &= ~(BCSR_PCMCIA_PC0RST |
+					BCSR_PCMCIA_PC0DRVEN |
+					BCSR_PCMCIA_PC0VPP |
+					BCSR_PCMCIA_PC0VCC);
+			au_sync_delay(10);
+		}
+		else if ((skt->nr == 1) && bcsr->pcmcia & BCSR_PCMCIA_PC1RST) {
+			bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST |
+					BCSR_PCMCIA_PC1DRVEN |
+					BCSR_PCMCIA_PC1VPP |
+					BCSR_PCMCIA_PC1VCC);
+			au_sync_delay(10);
+		}
+	}
+
+	state->bvd1=1;
+	state->bvd2=1;
+	state->wrprot=0;
+}
+
+static int
+db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_state_t *state)
+{
+	u16 pwr;
+	int sock = skt->nr;
+
+	debug("config_skt %d Vcc %dV Vpp %dV, reset %d\n",
+			sock, state->Vcc, state->Vpp,
+			state->flags & SS_RESET);
+
+	/* pcmcia reg was set to zero at init time. Be careful when
+	 * initializing a socket not to wipe out the settings of the
+	 * other socket.
+	 */
+	pwr = bcsr->pcmcia;
+	pwr &= ~(0xf << sock*8); /* clear voltage settings */
+
+	state->Vpp = 0;
+	switch(state->Vcc){
+		case 0:  /* Vcc 0 */
+			pwr |= SET_VCC_VPP(0,0,sock);
+			break;
+		case 50: /* Vcc 5V */
+			switch(state->Vpp) {
+				case 0:
+					pwr |= SET_VCC_VPP(2,0,sock);
+					break;
+				case 50:
+					pwr |= SET_VCC_VPP(2,1,sock);
+					break;
+				case 12:
+					pwr |= SET_VCC_VPP(2,2,sock);
+					break;
+				case 33:
+				default:
+					pwr |= SET_VCC_VPP(0,0,sock);
+					printk("%s: bad Vcc/Vpp (%d:%d)\n",
+							__FUNCTION__,
+							state->Vcc,
+							state->Vpp);
+					break;
+			}
+			break;
+		case 33: /* Vcc 3.3V */
+			switch(state->Vpp) {
+				case 0:
+					pwr |= SET_VCC_VPP(1,0,sock);
+					break;
+				case 12:
+					pwr |= SET_VCC_VPP(1,2,sock);
+					break;
+				case 33:
+					pwr |= SET_VCC_VPP(1,1,sock);
+					break;
+				case 50:
+				default:
+					pwr |= SET_VCC_VPP(0,0,sock);
+					printk("%s: bad Vcc/Vpp (%d:%d)\n",
+							__FUNCTION__,
+							state->Vcc,
+							state->Vpp);
+					break;
+			}
+			break;
+		default: /* what's this ? */
+			pwr |= SET_VCC_VPP(0,0,sock);
+			printk(KERN_ERR "%s: bad Vcc %d\n",
+					__FUNCTION__, state->Vcc);
+			break;
+	}
+
+	bcsr->pcmcia = pwr;
+	au_sync_delay(300);
+
+	if (sock == 0) {
+		if (!(state->flags & SS_RESET)) {
+			pwr |= BCSR_PCMCIA_PC0DRVEN;
+			bcsr->pcmcia = pwr;
+			au_sync_delay(300);
+			pwr |= BCSR_PCMCIA_PC0RST;
+			bcsr->pcmcia = pwr;
+			au_sync_delay(100);
+		}
+		else {
+			pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
+			bcsr->pcmcia = pwr;
+			au_sync_delay(100);
+		}
+	}
+	else {
+		if (!(state->flags & SS_RESET)) {
+			pwr |= BCSR_PCMCIA_PC1DRVEN;
+			bcsr->pcmcia = pwr;
+			au_sync_delay(300);
+			pwr |= BCSR_PCMCIA_PC1RST;
+			bcsr->pcmcia = pwr;
+			au_sync_delay(100);
+		}
+		else {
+			pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
+			bcsr->pcmcia = pwr;
+			au_sync_delay(100);
+		}
+	}
+	return 0;
+}
+
+/*
+ * Enable card status IRQs on (re-)initialisation.  This can
+ * be called at initialisation, power management event, or
+ * pcmcia event.
+ */
+void db1x00_socket_init(struct au1000_pcmcia_socket *skt)
+{
+	/* nothing to do for now */
+}
+
+/*
+ * Disable card status IRQs and PCMCIA bus on suspend.
+ */
+void db1x00_socket_suspend(struct au1000_pcmcia_socket *skt)
+{
+	/* nothing to do for now */
+}
+
+struct pcmcia_low_level db1x00_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+
+	.hw_init 		= db1x00_pcmcia_hw_init,
+	.hw_shutdown		= db1x00_pcmcia_shutdown,
+
+	.socket_state		= db1x00_pcmcia_socket_state,
+	.configure_socket	= db1x00_pcmcia_configure_socket,
+
+	.socket_init		= db1x00_socket_init,
+	.socket_suspend		= db1x00_socket_suspend
+};
+
+int __init au1x_board_init(struct device *dev)
+{
+	int ret = -ENODEV;
+	bcsr->pcmcia = 0; /* turn off power, if it's not already off */
+	au_sync_delay(2);
+	ret = au1x00_pcmcia_socket_probe(dev, &db1x00_pcmcia_ops, 0, 2);
+	return ret;
+}
diff -puN drivers/pcmcia/au1000_generic.c~mips-amd-alchemy-update drivers/pcmcia/au1000_generic.c
--- 25/drivers/pcmcia/au1000_generic.c~mips-amd-alchemy-update	2005-01-29 11:26:00.216714976 -0800
+++ 25-akpm/drivers/pcmcia/au1000_generic.c	2005-01-29 11:26:00.270706768 -0800
@@ -2,9 +2,13 @@
  *
  * Alchemy Semi Au1000 pcmcia driver
  *
- * Copyright 2001 MontaVista Software Inc.
+ * Copyright 2001-2003 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
- *         	ppopov@mvista.com or source@mvista.com
+ *         	ppopov@embeddedalley.com or source@mvista.com
+ *
+ * Copyright 2004 Pete Popov, Embedded Alley Solutions, Inc.
+ * Updated the driver to 2.6. Followed the sa11xx API and largely
+ * copied many of the hardware independent functions.
  *
  * ########################################################################
  *
@@ -25,450 +29,255 @@
  *
  * 
  */
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/config.h>
-#include <linux/delay.h>
+#include <linux/cpufreq.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
-#include <linux/tqueue.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/ss.h>
-#include <pcmcia/bulkmem.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/bus_ops.h>
-#include "cs_internal.h"
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
-#include <asm/au1000.h>
-#include <asm/au1000_pcmcia.h>
-
-#ifdef DEBUG
-static int pc_debug;
-
-module_param(pc_debug, int, 0644);
-
-#define debug(lvl,fmt) do {			\
-	if (pc_debug > (lvl))			\
-		printk(KERN_DEBUG fmt);		\
-} while (0)
-#else
-#define debug(lvl,fmt) do { } while (0)
-#endif
+#include <asm/mach-au1x00/au1000.h>
+#include "au1000_generic.h"
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pete Popov, MontaVista Software <ppopov@mvista.com>");
+MODULE_AUTHOR("Pete Popov <ppopov@embeddedalley.com>");
 MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller");
 
-#define MAP_SIZE 0x1000000
-
-/* This structure maintains housekeeping state for each socket, such
- * as the last known values of the card detect pins, or the Card Services
- * callback value associated with the socket:
- */
-static struct au1000_pcmcia_socket *pcmcia_socket;
-static int socket_count;
-
-
-/* Returned by the low-level PCMCIA interface: */
-static struct pcmcia_low_level *pcmcia_low_level;
-
-/* Event poll timer structure */
-static struct timer_list poll_timer;
-
-
-/* Prototypes for routines which are used internally: */
-
-static int  au1000_pcmcia_driver_init(void);
-static void au1000_pcmcia_driver_shutdown(void);
-static void au1000_pcmcia_task_handler(void *data);
-static void au1000_pcmcia_poll_event(unsigned long data);
-static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs);
-static struct tq_struct au1000_pcmcia_task;
-
-#ifdef CONFIG_PROC_FS
-static int au1000_pcmcia_proc_status(char *buf, char **start, 
-		off_t pos, int count, int *eof, void *data);
+#if 0
+#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
+#else
+#define debug(x,args...)
 #endif
 
+#define MAP_SIZE 0x100000
+extern struct au1000_pcmcia_socket au1000_pcmcia_socket[];
+#define PCMCIA_SOCKET(x)	(au1000_pcmcia_socket + (x))
+#define to_au1000_socket(x)	container_of(x, struct au1000_pcmcia_socket, socket)
 
-/* Prototypes for operations which are exported to the
- * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
+/* Some boards like to support CF cards as IDE root devices, so they
+ * grab pcmcia sockets directly.
  */
+u32 *pcmcia_base_vaddrs[2];
+extern const unsigned long mips_io_port_base;
 
-static int au1000_pcmcia_init(u32 sock);
-static int au1000_pcmcia_suspend(u32 sock);
-static int au1000_pcmcia_register_callback(u32 sock, 
-		void (*handler)(void *, u32), void *info);
-static int au1000_pcmcia_inquire_socket(u32 sock, socket_cap_t *cap);
-static int au1000_pcmcia_get_status(u32 sock, u_int *value);
-static int au1000_pcmcia_get_socket(u32 sock, socket_state_t *state);
-static int au1000_pcmcia_set_socket(u32 sock, socket_state_t *state);
-static int au1000_pcmcia_get_io_map(u32 sock, struct pccard_io_map *io);
-static int au1000_pcmcia_set_io_map(u32 sock, struct pccard_io_map *io);
-static int au1000_pcmcia_get_mem_map(u32 sock, struct pccard_mem_map *mem);
-static int au1000_pcmcia_set_mem_map(u32 sock, struct pccard_mem_map *mem);
-#ifdef CONFIG_PROC_FS
-static void au1000_pcmcia_proc_setup(u32 sock, struct proc_dir_entry *base);
-#endif
+DECLARE_MUTEX(pcmcia_sockets_lock);
 
-static struct pccard_operations au1000_pcmcia_operations = {
-	au1000_pcmcia_init,
-	au1000_pcmcia_suspend,
-	au1000_pcmcia_register_callback,
-	au1000_pcmcia_inquire_socket,
-	au1000_pcmcia_get_status,
-	au1000_pcmcia_get_socket,
-	au1000_pcmcia_set_socket,
-	au1000_pcmcia_get_io_map,
-	au1000_pcmcia_set_io_map,
-	au1000_pcmcia_get_mem_map,
-	au1000_pcmcia_set_mem_map,
-#ifdef CONFIG_PROC_FS
-	au1000_pcmcia_proc_setup
-#endif
+static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = {
+	au1x_board_init,
 };
 
-static DEFINE_SPINLOCK(pcmcia_lock);
-
-static int __init au1000_pcmcia_driver_init(void)
+static int
+au1x00_pcmcia_skt_state(struct au1000_pcmcia_socket *skt)
 {
-	struct pcmcia_init pcmcia_init;
 	struct pcmcia_state state;
-	unsigned int i;
+	unsigned int stat;
 
-	printk("\nAu1x00 PCMCIA\n");
+	memset(&state, 0, sizeof(struct pcmcia_state));
 
-#ifndef CONFIG_64BIT_PHYS_ADDR
-	printk(KERN_ERR "Au1x00 PCMCIA 36 bit IO support not enabled\n");
-	return -1;
-#endif
-
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)
-	pcmcia_low_level=&pb1x00_pcmcia_ops;
-#else
-#error Unsupported AU1000 board.
-#endif
+	skt->ops->socket_state(skt, &state);
 
-	pcmcia_init.handler=au1000_pcmcia_interrupt;
-	if((socket_count=pcmcia_low_level->init(&pcmcia_init))<0) {
-		printk(KERN_ERR "Unable to initialize PCMCIA service.\n");
-		return -EIO;
-	}
+	stat = state.detect  ? SS_DETECT : 0;
+	stat |= state.ready  ? SS_READY  : 0;
+	stat |= state.wrprot ? SS_WRPROT : 0;
+	stat |= state.vs_3v  ? SS_3VCARD : 0;
+	stat |= state.vs_Xv  ? SS_XVCARD : 0;
+	stat |= skt->cs_state.Vcc ? SS_POWERON : 0;
 
-	/* NOTE: the chip select must already be setup */
-
-	pcmcia_socket = 
-		kmalloc(sizeof(struct au1000_pcmcia_socket) * socket_count, 
-				GFP_KERNEL);
-	if (!pcmcia_socket) {
-		printk(KERN_ERR "Card Services can't get memory \n");
-		return -1;
+	if (skt->cs_state.flags & SS_IOCARD)
+		stat |= state.bvd1 ? SS_STSCHG : 0;
+	else {
+		if (state.bvd1 == 0)
+			stat |= SS_BATDEAD;
+		else if (state.bvd2 == 0)
+			stat |= SS_BATWARN;
 	}
-	memset(pcmcia_socket, 0,
-			sizeof(struct au1000_pcmcia_socket) * socket_count);
-			
-	/* 
-	 * Assuming max of 2 sockets, which the Au1000 supports.
-	 * WARNING: the Pb1000 has two sockets, and both work, but you
-	 * can't use them both at the same time due to glue logic conflicts.
-	 */
-	for(i=0; i < socket_count; i++) {
+	return stat;
+}
 
-		if(pcmcia_low_level->socket_state(i, &state)<0){
-			printk(KERN_ERR "Unable to get PCMCIA status\n");
-			return -EIO;
-		}
-		pcmcia_socket[i].k_state=state;
-		pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
-		
-		if (i == 0) {
-			pcmcia_socket[i].virt_io = 
-				(u32)ioremap((kio_addr_t)0xF00000000, 0x1000);
-			pcmcia_socket[i].phys_attr = (memaddr_t)0xF40000000;
-			pcmcia_socket[i].phys_mem = (memaddr_t)0xF80000000;
-		}
-		else  {
-			pcmcia_socket[i].virt_io = 
-				(u32)ioremap((kio_addr_t)0xF08000000, 0x1000);
-			pcmcia_socket[i].phys_attr = (memaddr_t)0xF48000000;
-			pcmcia_socket[i].phys_mem = (memaddr_t)0xF88000000;
-		}
-	}
+/*
+ * au100_pcmcia_config_skt
+ *
+ * Convert PCMCIA socket state to our socket configure structure.
+ */
+static int
+au1x00_pcmcia_config_skt(struct au1000_pcmcia_socket *skt, socket_state_t *state)
+{
+	int ret;
 
-	/* Only advertise as many sockets as we can detect: */
-	if(register_ss_entry(socket_count, &au1000_pcmcia_operations)<0){
-		printk(KERN_ERR "Unable to register socket service routine\n");
-		return -ENXIO;
+	ret = skt->ops->configure_socket(skt, state);
+	if (ret == 0) {
+		skt->cs_state = *state;
 	}
 
-	/* Start the event poll timer.  
-	 * It will reschedule by itself afterwards. 
-	 */
-	au1000_pcmcia_poll_event(0);
+	if (ret < 0)
+		debug("unable to configure socket %d\n", skt->nr);
 
-	debug(1, "au1000: initialization complete\n");
-	return 0;
-
-}  /* au1000_pcmcia_driver_init() */
-
-module_init(au1000_pcmcia_driver_init);
-
-static void __exit au1000_pcmcia_driver_shutdown(void)
-{
-	int i;
-
-	del_timer_sync(&poll_timer);
-	unregister_ss_entry(&au1000_pcmcia_operations);
-	pcmcia_low_level->shutdown();
-	flush_scheduled_tasks();
-	for(i=0; i < socket_count; i++) {
-		if (pcmcia_socket[i].virt_io) 
-			iounmap((void *)pcmcia_socket[i].virt_io);
-	}
-	debug(1, "au1000: shutdown complete\n");
+	return ret;
 }
 
-module_exit(au1000_pcmcia_driver_shutdown);
+/* au1x00_pcmcia_sock_init()
+ *
+ * (Re-)Initialise the socket, turning on status interrupts
+ * and PCMCIA bus.  This must wait for power to stabilise
+ * so that the card status signals report correctly.
+ *
+ * Returns: 0
+ */
+static int au1x00_pcmcia_sock_init(struct pcmcia_socket *sock)
+{
+	struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
 
-static int au1000_pcmcia_init(unsigned int sock) { return 0; }
+	debug("initializing socket %u\n", skt->nr);
 
-static int au1000_pcmcia_suspend(unsigned int sock)
-{
+	skt->ops->socket_init(skt);
 	return 0;
 }
 
-
-static inline unsigned 
-au1000_pcmcia_events(struct pcmcia_state *state, 
-		struct pcmcia_state *prev_state, 
-		unsigned int mask, unsigned int flags)
+/*
+ * au1x00_pcmcia_suspend()
+ *
+ * Remove power on the socket, disable IRQs from the card.
+ * Turn off status interrupts, and disable the PCMCIA bus.
+ *
+ * Returns: 0
+ */
+static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock)
 {
-	unsigned int events=0;
+	struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
+	int ret;
 
-	if(state->detect!=prev_state->detect){
-		debug(2, "%s(): card detect value %u\n", 
-				__FUNCTION__, state->detect);
-		events |= mask&SS_DETECT;
-	}
+	debug("suspending socket %u\n", skt->nr);
 
+	ret = au1x00_pcmcia_config_skt(skt, &dead_socket);
+	if (ret == 0)
+		skt->ops->socket_suspend(skt);
 
-	if(state->ready!=prev_state->ready){
-		debug(2, "%s(): card ready value %u\n", 
-				__FUNCTION__, state->ready);
-		events |= mask&((flags&SS_IOCARD)?0:SS_READY);
-	}
-
-	*prev_state=*state;
-	return events;
-
-}  /* au1000_pcmcia_events() */
+	return ret;
+}
 
+static DEFINE_SPINLOCK(status_lock);
 
-/* 
- * Au1000_pcmcia_task_handler()
- * Processes socket events.
+/*
+ * au1x00_check_status()
  */
-static void au1000_pcmcia_task_handler(void *data) 
+static void au1x00_check_status(struct au1000_pcmcia_socket *skt)
 {
-	struct pcmcia_state state;
-	int i, events, irq_status;
-
-	for(i=0; i<socket_count; i++)  {
-		if((irq_status = pcmcia_low_level->socket_state(i, &state))<0)
-			printk(KERN_ERR "low-level PCMCIA error\n");
-
-		events = au1000_pcmcia_events(&state, 
-				&pcmcia_socket[i].k_state, 
-				pcmcia_socket[i].cs_state.csc_mask, 
-				pcmcia_socket[i].cs_state.flags);
-		if(pcmcia_socket[i].handler!=NULL) {
-			pcmcia_socket[i].handler(pcmcia_socket[i].handler_info,
-					events);
-		}
-	}
-
-}  /* au1000_pcmcia_task_handler() */
-
-static struct tq_struct au1000_pcmcia_task = {
-	routine: au1000_pcmcia_task_handler
-};
+	unsigned int events;
 
+	debug("entering PCMCIA monitoring thread\n");
 
-static void au1000_pcmcia_poll_event(unsigned long dummy)
-{
-	poll_timer.function = au1000_pcmcia_poll_event;
-	poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD;
-	add_timer(&poll_timer);
-	schedule_task(&au1000_pcmcia_task);
+	do {
+		unsigned int status;
+		unsigned long flags;
+
+		status = au1x00_pcmcia_skt_state(skt);
+
+		spin_lock_irqsave(&status_lock, flags);
+		events = (status ^ skt->status) & skt->cs_state.csc_mask;
+		skt->status = status;
+		spin_unlock_irqrestore(&status_lock, flags);
+
+		debug("events: %s%s%s%s%s%s\n",
+			events == 0         ? "<NONE>"   : "",
+			events & SS_DETECT  ? "DETECT "  : "",
+			events & SS_READY   ? "READY "   : "",
+			events & SS_BATDEAD ? "BATDEAD " : "",
+			events & SS_BATWARN ? "BATWARN " : "",
+			events & SS_STSCHG  ? "STSCHG "  : "");
+
+		if (events)
+			pcmcia_parse_events(&skt->socket, events);
+	} while (events);
 }
 
-
 /* 
- * au1000_pcmcia_interrupt()
- * The actual interrupt work is performed by au1000_pcmcia_task(), 
- * because the Card Services event handling code performs scheduling 
- * operations which cannot be executed from within an interrupt context.
+ * au1x00_pcmcia_poll_event()
+ * Let's poll for events in addition to IRQs since IRQ only is unreliable...
  */
-static void 
-au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+static void au1x00_pcmcia_poll_event(unsigned long dummy)
 {
-	schedule_task(&au1000_pcmcia_task);
-}
+	struct au1000_pcmcia_socket *skt = (struct au1000_pcmcia_socket *)dummy;
+	debug("polling for events\n");
 
+	mod_timer(&skt->poll_timer, jiffies + AU1000_PCMCIA_POLL_PERIOD);
 
-static int 
-au1000_pcmcia_register_callback(unsigned int sock, 
-		void (*handler)(void *, unsigned int), void *info)
-{
-	if(handler==NULL){
-		pcmcia_socket[sock].handler=NULL;
-		MOD_DEC_USE_COUNT;
-	} else {
-		MOD_INC_USE_COUNT;
-		pcmcia_socket[sock].handler=handler;
-		pcmcia_socket[sock].handler_info=info;
-	}
-	return 0;
+	au1x00_check_status(skt);
 }
 
-
-/* au1000_pcmcia_inquire_socket()
- *
- * From the sa1100 socket driver : 
- *
- * Implements the inquire_socket() operation for the in-kernel PCMCIA
- * service (formerly SS_InquireSocket in Card Services).  We set 
- * SS_CAP_STATIC_MAP, which disables the memory resource database check. 
- * (Mapped memory is set up within the socket driver itself.)
+/* au1x00_pcmcia_get_status()
  *
- * In conjunction with the STATIC_MAP capability is a new field,
- * `io_offset', recommended by David Hinds. Rather than go through
- * the SetIOMap interface (which is not quite suited for communicating
- * window locations up from the socket driver), we just pass up 
- * an offset which is applied to client-requested base I/O addresses
- * in alloc_io_space().
+ * From the sa11xx_core.c:
+ * Implements the get_status() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetStatus in Card Services). Essentially just
+ * fills in bits in `status' according to internal driver state or
+ * the value of the voltage detect chipselect register.
+ *
+ * As a debugging note, during card startup, the PCMCIA core issues
+ * three set_socket() commands in a row the first with RESET deasserted,
+ * the second with RESET asserted, and the last with RESET deasserted
+ * again. Following the third set_socket(), a get_status() command will
+ * be issued. The kernel is looking for the SS_READY flag (see
+ * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
  *
- * Returns: 0 on success, -1 if no pin has been configured for `sock'
+ * Returns: 0
  */
-static int au1000_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
+static int
+au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status)
 {
-	struct pcmcia_irq_info irq_info;
-
-	if(sock > socket_count){
-		printk(KERN_ERR "au1000: socket %u not configured\n", sock);
-		return -1;
-	}
-
-	/* from the sa1100_generic driver: */
-
-	/* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
-	*   force_low argument to validate_mem() in rsrc_mgr.c -- since in
-	*   general, the mapped * addresses of the PCMCIA memory regions
-	*   will not be within 0xffff, setting force_low would be
-	*   undesirable.
-	*
-	* SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
-	*   resource database; we instead pass up physical address ranges
-	*   and allow other parts of Card Services to deal with remapping.
-	*
-	* SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
-	*   not 32-bit CardBus devices.
-	*/
-	cap->features=(SS_CAP_PAGE_REGS  | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
-
-	irq_info.sock=sock;
-	irq_info.irq=-1;
-
-	if(pcmcia_low_level->get_irq_info(&irq_info)<0){
-		printk(KERN_ERR "Error obtaining IRQ info socket %u\n", sock);
-		return -1;
-	}
+	struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
 
-	cap->irq_mask=0;
-	cap->map_size=MAP_SIZE;
-	cap->pci_irq=irq_info.irq;
-	cap->io_offset=pcmcia_socket[sock].virt_io;
+	skt->status = au1x00_pcmcia_skt_state(skt);
+	*status = skt->status;
 
 	return 0;
+}
 
-}  /* au1000_pcmcia_inquire_socket() */
-
-
-static int 
-au1000_pcmcia_get_status(unsigned int sock, unsigned int *status)
+/* au1x00_pcmcia_get_socket()
+ * Implements the get_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_GetSocket in Card Services). Not a very
+ * exciting routine.
+ *
+ * Returns: 0
+ */
+static int
+au1x00_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state)
 {
-	struct pcmcia_state state;
-
-
-	if((pcmcia_low_level->socket_state(sock, &state))<0){
-		printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
-		return -1;
-	}
-
-	pcmcia_socket[sock].k_state = state;
+  struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
 
-	*status = state.detect?SS_DETECT:0;
-
-	*status |= state.ready?SS_READY:0;
-
-	*status |= pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
-
-	if(pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
-		*status |= state.bvd1?SS_STSCHG:0;
-	else {
-		if(state.bvd1==0)
-			*status |= SS_BATDEAD;
-		else if(state.bvd2 == 0)
-			*status |= SS_BATWARN;
-	}
-
-	*status|=state.vs_3v?SS_3VCARD:0;
-
-	*status|=state.vs_Xv?SS_XVCARD:0;
-
-	debug(2, "\tstatus: %s%s%s%s%s%s%s%s\n",
-	(*status&SS_DETECT)?"DETECT ":"",
-	(*status&SS_READY)?"READY ":"", 
-	(*status&SS_BATDEAD)?"BATDEAD ":"",
-	(*status&SS_BATWARN)?"BATWARN ":"",
-	(*status&SS_POWERON)?"POWERON ":"",
-	(*status&SS_STSCHG)?"STSCHG ":"",
-	(*status&SS_3VCARD)?"3VCARD ":"",
-	(*status&SS_XVCARD)?"XVCARD ":"");
-
-	return 0;
-
-}  /* au1000_pcmcia_get_status() */
-
-
-static int 
-au1000_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
-{
-	*state = pcmcia_socket[sock].cs_state;
-	return 0;
+  debug("for sock %u\n", skt->nr);
+  *state = skt->cs_state;
+  return 0;
 }
 
-
-static int 
-au1000_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
+/* au1x00_pcmcia_set_socket()
+ * Implements the set_socket() operation for the in-kernel PCMCIA
+ * service (formerly SS_SetSocket in Card Services). We more or
+ * less punt all of this work and let the kernel handle the details
+ * of power configuration, reset, &c. We also record the value of
+ * `state' in order to regurgitate it to the PCMCIA core later.
+ *
+ * Returns: 0
+ */
+static int
+au1x00_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
 {
-	struct pcmcia_configure configure;
+  struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
+
+  debug("for sock %u\n", skt->nr);
 
-	debug(2, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
-	"\tVcc %d  Vpp %d  irq %d\n",
+  debug("\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n",
 	(state->csc_mask==0)?"<NONE>":"",
 	(state->csc_mask&SS_DETECT)?"DETECT ":"",
 	(state->csc_mask&SS_READY)?"READY ":"",
@@ -480,217 +289,294 @@ au1000_pcmcia_set_socket(unsigned int so
 	(state->flags&SS_IOCARD)?"IOCARD ":"",
 	(state->flags&SS_RESET)?"RESET ":"",
 	(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
-	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"");
+  debug("\tVcc %d  Vpp %d  irq %d\n",
 	state->Vcc, state->Vpp, state->io_irq);
 
-	configure.sock=sock;
-	configure.vcc=state->Vcc;
-	configure.vpp=state->Vpp;
-	configure.output=(state->flags&SS_OUTPUT_ENA)?1:0;
-	configure.speaker=(state->flags&SS_SPKR_ENA)?1:0;
-	configure.reset=(state->flags&SS_RESET)?1:0;
-
-	if(pcmcia_low_level->configure_socket(&configure)<0){
-		printk(KERN_ERR "Unable to configure socket %u\n", sock);
-		return -1;
-	}
-
-	pcmcia_socket[sock].cs_state = *state;
-	return 0;
-
-}  /* au1000_pcmcia_set_socket() */
-
-
-static int 
-au1000_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
-{
-	debug(1, "au1000_pcmcia_get_io_map: sock %d\n", sock);
-	if(map->map>=MAX_IO_WIN){
-		printk(KERN_ERR "%s(): map (%d) out of range\n", 
-				__FUNCTION__, map->map);
-		return -1;
-	}
-	*map=pcmcia_socket[sock].io_map[map->map];
-	return 0;
+  return au1x00_pcmcia_config_skt(skt, state);
 }
 
-
 int 
-au1000_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
+au1x00_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map)
 {
+	struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
 	unsigned int speed;
-	unsigned long start;
 
 	if(map->map>=MAX_IO_WIN){
-		printk(KERN_ERR "%s(): map (%d) out of range\n", 
-				__FUNCTION__, map->map);
+		debug("map (%d) out of range\n", map->map);
 		return -1;
 	}
 
 	if(map->flags&MAP_ACTIVE){
 		speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED;
-		pcmcia_socket[sock].speed_io=speed;
+		skt->spd_io[map->map] = speed;
 	}
 
-	start=map->start;
-
-	if(map->stop==1) {
-		map->stop=PAGE_SIZE-1;
-	}
-
-	map->start=pcmcia_socket[sock].virt_io;
-	map->stop=map->start+(map->stop-start);
-	pcmcia_socket[sock].io_map[map->map]=*map;
-	debug(3, "set_io_map %d start %x stop %x\n", 
-			map->map, map->start, map->stop);
+	map->start=(ioaddr_t)(u32)skt->virt_io;
+	map->stop=map->start+MAP_SIZE;
 	return 0;
 
-}  /* au1000_pcmcia_set_io_map() */
+}  /* au1x00_pcmcia_set_io_map() */
 
 
 static int 
-au1000_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
+au1x00_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
 {
+	struct au1000_pcmcia_socket *skt = to_au1000_socket(sock);
+	unsigned short speed = map->speed;
 
-	if(map->map>=MAX_WIN) {
-		printk(KERN_ERR "%s(): map (%d) out of range\n", 
-				__FUNCTION__, map->map);
+	if(map->map>=MAX_WIN){
+		debug("map (%d) out of range\n", map->map);
 		return -1;
 	}
-	*map=pcmcia_socket[sock].mem_map[map->map];
+
+	if (map->flags & MAP_ATTRIB) {
+		skt->spd_attr[map->map] = speed;
+		skt->spd_mem[map->map] = 0;
+	} else {
+		skt->spd_attr[map->map] = 0;
+		skt->spd_mem[map->map] = speed;
+	}
+
+	if (map->flags & MAP_ATTRIB) {
+		map->static_start = skt->phys_attr + map->card_start;
+	}
+	else {
+		map->static_start = skt->phys_mem + map->card_start;
+	}
+
+	debug("set_mem_map %d start %08lx card_start %08x\n",
+			map->map, map->static_start, map->card_start);
 	return 0;
-}
 
+}  /* au1x00_pcmcia_set_mem_map() */
 
-static int 
-au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
+static struct pccard_operations au1x00_pcmcia_operations = {
+	.init			= au1x00_pcmcia_sock_init,
+	.suspend		= au1x00_pcmcia_suspend,
+	.get_status		= au1x00_pcmcia_get_status,
+	.get_socket		= au1x00_pcmcia_get_socket,
+	.set_socket		= au1x00_pcmcia_set_socket,
+	.set_io_map		= au1x00_pcmcia_set_io_map,
+	.set_mem_map		= au1x00_pcmcia_set_mem_map,
+};
+
+static const char *skt_names[] = {
+	"PCMCIA socket 0",
+	"PCMCIA socket 1",
+};
+
+struct skt_dev_info {
+	int nskt;
+};
+
+int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr)
 {
-	unsigned int speed;
-	u_long flags;
+	struct skt_dev_info *sinfo;
+	int ret, i;
 
-	if(map->map>=MAX_WIN){
-		printk(KERN_ERR "%s(): map (%d) out of range\n", 
-				__FUNCTION__, map->map);
-		return -1;
+	sinfo = kmalloc(sizeof(struct skt_dev_info), GFP_KERNEL);
+	if (!sinfo) {
+		ret = -ENOMEM;
+		goto out;
 	}
 
-	if(map->flags&MAP_ACTIVE){
-		speed=(map->speed>0)?map->speed:AU1000_PCMCIA_MEM_SPEED;
+	memset(sinfo, 0, sizeof(struct skt_dev_info));
+	sinfo->nskt = nr;
 
-		/* TBD */
-		if(map->flags&MAP_ATTRIB){
-			pcmcia_socket[sock].speed_attr=speed;
-		} 
-		else {
-			pcmcia_socket[sock].speed_mem=speed;
+	/*
+	 * Initialise the per-socket structure.
+	 */
+	for (i = 0; i < nr; i++) {
+		struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+		memset(skt, 0, sizeof(*skt));
+
+		skt->socket.ops = &au1x00_pcmcia_operations;
+		skt->socket.owner = ops->owner;
+		skt->socket.dev.dev = dev;
+
+		init_timer(&skt->poll_timer);
+		skt->poll_timer.function = au1x00_pcmcia_poll_event;
+		skt->poll_timer.data = (unsigned long)skt;
+		skt->poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD;
+
+		skt->nr		= first + i;
+		skt->irq	= 255;
+		skt->dev	= dev;
+		skt->ops	= ops;
+
+		skt->res_skt.name	= skt_names[skt->nr];
+		skt->res_io.name	= "io";
+		skt->res_io.flags	= IORESOURCE_MEM | IORESOURCE_BUSY;
+		skt->res_mem.name	= "memory";
+		skt->res_mem.flags	= IORESOURCE_MEM;
+		skt->res_attr.name	= "attribute";
+		skt->res_attr.flags	= IORESOURCE_MEM;
+
+		/*
+		 * PCMCIA client drivers use the inb/outb macros to access the
+		 * IO registers. Since mips_io_port_base is added to the
+		 * access address of the mips implementation of inb/outb,
+		 * we need to subtract it here because we want to access the
+		 * I/O or MEM address directly, without going through this
+		 * "mips_io_port_base" mechanism.
+		 */
+		if (i == 0) {
+			skt->virt_io = (void *)
+				(ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) -
+				(u32)mips_io_port_base);
+			skt->phys_attr = AU1X_SOCK0_PSEUDO_PHYS_ATTR;
+			skt->phys_mem = AU1X_SOCK0_PSEUDO_PHYS_MEM;
 		}
-	}
+#ifndef CONFIG_MIPS_XXS1500
+		else  {
+			skt->virt_io = (void *)
+				(ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) -
+				(u32)mips_io_port_base);
+			skt->phys_attr = AU1X_SOCK1_PSEUDO_PHYS_ATTR;
+			skt->phys_mem = AU1X_SOCK1_PSEUDO_PHYS_MEM;
+		}
+#endif
+		pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io;
+		ret = ops->hw_init(skt);
 
-	spin_lock_irqsave(&pcmcia_lock, flags);
-	if (map->flags & MAP_ATTRIB) {
-		map->static_start = pcmcia_socket[sock].phys_attr + 
-			map->card_start;
-	}
-	else {
-		map->static_start = pcmcia_socket[sock].phys_mem + 
-			map->card_start;
+		skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD;
+		skt->socket.irq_mask = 0;
+		skt->socket.map_size = MAP_SIZE;
+		skt->socket.pci_irq = skt->irq;
+		skt->socket.io_offset = (unsigned long)skt->virt_io;
+
+		skt->status = au1x00_pcmcia_skt_state(skt);
+
+		ret = pcmcia_register_socket(&skt->socket);
+		if (ret)
+			goto out_err;
+
+		WARN_ON(skt->socket.sock != i);
+
+		add_timer(&skt->poll_timer);
 	}
 
-	pcmcia_socket[sock].mem_map[map->map]=*map;
-	spin_unlock_irqrestore(&pcmcia_lock, flags);
-	debug(3, "set_mem_map %d start %x card_start %x\n", 
-			map->map, map->static_start,
-			map->card_start);
+	dev_set_drvdata(dev, sinfo);
 	return 0;
 
-}  /* au1000_pcmcia_set_mem_map() */
+	do {
+		struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+
+		del_timer_sync(&skt->poll_timer);
+		pcmcia_unregister_socket(&skt->socket);
+out_err:
+		flush_scheduled_work();
+		ops->hw_shutdown(skt);
+
+		i--;
+	} while (i > 0);
+	kfree(sinfo);
+out:
+	return ret;
+}
+
+int au1x00_drv_pcmcia_remove(struct device *dev)
+{
+	struct skt_dev_info *sinfo = dev_get_drvdata(dev);
+	int i;
+
+	down(&pcmcia_sockets_lock);
+	dev_set_drvdata(dev, NULL);
 
+	for (i = 0; i < sinfo->nskt; i++) {
+		struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
+
+		del_timer_sync(&skt->poll_timer);
+		pcmcia_unregister_socket(&skt->socket);
+		flush_scheduled_work();
+		skt->ops->hw_shutdown(skt);
+		au1x00_pcmcia_config_skt(skt, &dead_socket);
+		iounmap(skt->virt_io);
+		skt->virt_io = NULL;
+	}
+
+	kfree(sinfo);
+	up(&pcmcia_sockets_lock);
+	return 0;
+}
 
-#if defined(CONFIG_PROC_FS)
 
-static void 
-au1000_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+/*
+ * PCMCIA "Driver" API
+ */
+
+static int au1x00_drv_pcmcia_probe(struct device *dev)
 {
-	struct proc_dir_entry *entry;
+	int i, ret = -ENODEV;
 
-	if((entry=create_proc_entry("status", 0, base))==NULL){
-		printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
-		return;
+	down(&pcmcia_sockets_lock);
+	for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) {
+		ret = au1x00_pcmcia_hw_init[i](dev);
+		if (ret == 0)
+			break;
 	}
+	up(&pcmcia_sockets_lock);
+	return ret;
+}
 
-	entry->read_proc=au1000_pcmcia_proc_status;
-	entry->data=(void *)sock;
+
+static int au1x00_drv_pcmcia_suspend(struct device *dev, u32 state, u32 level)
+{
+	int ret = 0;
+	if (level == SUSPEND_SAVE_STATE)
+		ret = pcmcia_socket_dev_suspend(dev, state);
+	return ret;
 }
 
+static int au1x00_drv_pcmcia_resume(struct device *dev, u32 level)
+{
+	int ret = 0;
+	if (level == RESUME_RESTORE_STATE)
+		ret = pcmcia_socket_dev_resume(dev);
+	return ret;
+}
+
+
+static struct device_driver au1x00_pcmcia_driver = {
+	.probe		= au1x00_drv_pcmcia_probe,
+	.remove		= au1x00_drv_pcmcia_remove,
+	.name		= "au1x00-pcmcia",
+	.bus		= &platform_bus_type,
+	.suspend	= au1x00_drv_pcmcia_suspend,
+	.resume		= au1x00_drv_pcmcia_resume
+};
+
+static struct platform_device au1x00_device = {
+	.name = "au1x00-pcmcia",
+	.id = 0,
+};
 
-/* au1000_pcmcia_proc_status()
- * Implements the /proc/bus/pccard/??/status file.
+/* au1x00_pcmcia_init()
  *
- * Returns: the number of characters added to the buffer
+ * This routine performs low-level PCMCIA initialization and then
+ * registers this socket driver with Card Services.
+ *
+ * Returns: 0 on success, -ve error code on failure
  */
-static int 
-au1000_pcmcia_proc_status(char *buf, char **start, off_t pos, 
-		int count, int *eof, void *data)
+static int __init au1x00_pcmcia_init(void)
 {
-	char *p=buf;
-	unsigned int sock=(unsigned int)data;
-
-	p+=sprintf(p, "k_flags  : %s%s%s%s%s%s%s\n", 
-	     pcmcia_socket[sock].k_state.detect?"detect ":"",
-	     pcmcia_socket[sock].k_state.ready?"ready ":"",
-	     pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
-	     pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
-	     pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
-	     pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
-	     pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
-
-	p+=sprintf(p, "status   : %s%s%s%s%s%s%s%s%s\n",
-	     pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
-	     pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
-	     pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
-	     pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     (pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
-	      pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
-	     ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
-	     ((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
-	      (pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
-	     pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
-	     pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
-
-	p+=sprintf(p, "mask     : %s%s%s%s%s\n",
-	     pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
-	     "SS_DETECT ":"",
-	     pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
-	     "SS_READY ":"",
-	     pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
-	     "SS_BATDEAD ":"",
-	     pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
-	     "SS_BATWARN ":"",
-	     pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
-	     "SS_STSCHG ":"");
-
-	p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
-	     pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
-	     "SS_PWR_AUTO ":"",
-	     pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
-	     "SS_IOCARD ":"",
-	     pcmcia_socket[sock].cs_state.flags&SS_RESET?\
-	     "SS_RESET ":"",
-	     pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
-	     "SS_SPKR_ENA ":"",
-	     pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
-	     "SS_OUTPUT_ENA ":"");
-
-	p+=sprintf(p, "Vcc      : %d\n", pcmcia_socket[sock].cs_state.Vcc);
-	p+=sprintf(p, "Vpp      : %d\n", pcmcia_socket[sock].cs_state.Vpp);
-	p+=sprintf(p, "irq      : %d\n", pcmcia_socket[sock].cs_state.io_irq);
-	p+=sprintf(p, "I/O      : %u\n", pcmcia_socket[sock].speed_io);
-	p+=sprintf(p, "attribute: %u\n", pcmcia_socket[sock].speed_attr);
-	p+=sprintf(p, "common   : %u\n", pcmcia_socket[sock].speed_mem);
-	return p-buf;
+	int error = 0;
+	if ((error = driver_register(&au1x00_pcmcia_driver)))
+		return error;
+	platform_device_register(&au1x00_device);
+	return error;
 }
 
+/* au1x00_pcmcia_exit()
+ * Invokes the low-level kernel service to free IRQs associated with this
+ * socket controller and reset GPIO edge detection.
+ */
+static void __exit au1x00_pcmcia_exit(void)
+{
+	driver_unregister(&au1x00_pcmcia_driver);
+	platform_device_unregister(&au1x00_device);
+}
 
-#endif  /* defined(CONFIG_PROC_FS) */
+module_init(au1x00_pcmcia_init);
+module_exit(au1x00_pcmcia_exit);
diff -puN /dev/null drivers/pcmcia/au1000_generic.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/pcmcia/au1000_generic.h	2005-01-29 11:26:00.271706616 -0800
@@ -0,0 +1,150 @@
+/*
+ * Alchemy Semi Au1000 pcmcia driver include file
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+#ifndef __ASM_AU1000_PCMCIA_H
+#define __ASM_AU1000_PCMCIA_H
+
+/* include the world */
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+#define AU1000_PCMCIA_POLL_PERIOD    (2*HZ)
+#define AU1000_PCMCIA_IO_SPEED       (255)
+#define AU1000_PCMCIA_MEM_SPEED      (300)
+
+#define AU1X_SOCK0_IO        0xF00000000
+#define AU1X_SOCK0_PHYS_ATTR 0xF40000000
+#define AU1X_SOCK0_PHYS_MEM  0xF80000000
+/* pseudo 32 bit phys addresses, which get fixed up to the
+ * real 36 bit address in fixup_bigphys_addr() */
+#define AU1X_SOCK0_PSEUDO_PHYS_ATTR 0xF4000000
+#define AU1X_SOCK0_PSEUDO_PHYS_MEM  0xF8000000
+
+/* pcmcia socket 1 needs external glue logic so the memory map
+ * differs from board to board.
+ */
+#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550)
+#define AU1X_SOCK1_IO        0xF08000000
+#define AU1X_SOCK1_PHYS_ATTR 0xF48000000
+#define AU1X_SOCK1_PHYS_MEM  0xF88000000
+#define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000
+#define AU1X_SOCK1_PSEUDO_PHYS_MEM  0xF8800000
+#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550)
+#define AU1X_SOCK1_IO        0xF04000000
+#define AU1X_SOCK1_PHYS_ATTR 0xF44000000
+#define AU1X_SOCK1_PHYS_MEM  0xF84000000
+#define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000
+#define AU1X_SOCK1_PSEUDO_PHYS_MEM  0xF8400000
+#endif
+
+struct pcmcia_state {
+  unsigned detect: 1,
+            ready: 1,
+           wrprot: 1,
+	     bvd1: 1,
+	     bvd2: 1,
+            vs_3v: 1,
+            vs_Xv: 1;
+};
+
+struct pcmcia_configure {
+  unsigned sock: 8,
+            vcc: 8,
+            vpp: 8,
+         output: 1,
+        speaker: 1,
+          reset: 1;
+};
+
+struct pcmcia_irqs {
+	int sock;
+	int irq;
+	const char *str;
+};
+
+
+struct au1000_pcmcia_socket {
+	struct pcmcia_socket socket;
+
+	/*
+	 * Info from low level handler
+	 */
+	struct device		*dev;
+	unsigned int		nr;
+	unsigned int		irq;
+
+	/*
+	 * Core PCMCIA state
+	 */
+	struct pcmcia_low_level *ops;
+
+	unsigned int 		status;
+	socket_state_t		cs_state;
+
+	unsigned short		spd_io[MAX_IO_WIN];
+	unsigned short		spd_mem[MAX_WIN];
+	unsigned short		spd_attr[MAX_WIN];
+
+	struct resource		res_skt;
+	struct resource		res_io;
+	struct resource		res_mem;
+	struct resource		res_attr;
+
+	void *                 	virt_io;
+	ioaddr_t              	phys_io;
+	unsigned int           	phys_attr;
+	unsigned int           	phys_mem;
+	unsigned short        	speed_io, speed_attr, speed_mem;
+
+	unsigned int		irq_state;
+
+	struct timer_list	poll_timer;
+};
+
+struct pcmcia_low_level {
+	struct module *owner;
+
+	int (*hw_init)(struct au1000_pcmcia_socket *);
+	void (*hw_shutdown)(struct au1000_pcmcia_socket *);
+
+	void (*socket_state)(struct au1000_pcmcia_socket *, struct pcmcia_state *);
+	int (*configure_socket)(struct au1000_pcmcia_socket *, struct socket_state_t *);
+
+	/*
+	 * Enable card status IRQs on (re-)initialisation.  This can
+	 * be called at initialisation, power management event, or
+	 * pcmcia event.
+	 */
+	void (*socket_init)(struct au1000_pcmcia_socket *);
+
+	/*
+	 * Disable card status IRQs and PCMCIA bus on suspend.
+	 */
+	void (*socket_suspend)(struct au1000_pcmcia_socket *);
+};
+
+extern int au1x_board_init(struct device *dev);
+
+#endif /* __ASM_AU1000_PCMCIA_H */
diff -puN drivers/pcmcia/au1000_pb1x00.c~mips-amd-alchemy-update drivers/pcmcia/au1000_pb1x00.c
--- 25/drivers/pcmcia/au1000_pb1x00.c~mips-amd-alchemy-update	2005-01-29 11:26:00.217714824 -0800
+++ 25-akpm/drivers/pcmcia/au1000_pb1x00.c	2005-01-29 11:26:00.273706312 -0800
@@ -30,6 +30,7 @@
 #include <linux/timer.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
+#include <linux/version.h>
 #include <linux/types.h>
 
 #include <pcmcia/version.h>
@@ -55,7 +56,7 @@
 #define PCMCIA_IRQ AU1000_GPIO_15
 #elif defined (CONFIG_MIPS_PB1500)
 #include <asm/pb1500.h>
-#define PCMCIA_IRQ AU1000_GPIO_11   /* fixme */
+#define PCMCIA_IRQ AU1500_GPIO_203
 #elif defined (CONFIG_MIPS_PB1100)
 #include <asm/pb1100.h>
 #define PCMCIA_IRQ AU1000_GPIO_11
@@ -82,9 +83,9 @@ static int pb1x00_pcmcia_init(struct pcm
 #else /* fixme -- take care of the Pb1500 at some point */
 
 	u16 pcr;
-	pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf; /* turn off power */
-	pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
-	au_writew(pcr, PB1100_MEM_PCMCIA);
+	pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
+	pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
+	au_writew(pcr, PCMCIA_BOARD_REG);
 	au_sync_delay(500);
 	return PCMCIA_NUM_SOCKS;
 #endif
@@ -102,9 +103,9 @@ static int pb1x00_pcmcia_shutdown(void)
 	return 0;
 #else
 	u16 pcr;
-	pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf; /* turn off power */
-	pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
-	au_writew(pcr, PB1100_MEM_PCMCIA);
+	pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
+	pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
+	au_writew(pcr, PCMCIA_BOARD_REG);
 	au_sync_delay(2);
 	return 0;
 #endif
@@ -123,9 +124,14 @@ pb1x00_pcmcia_socket_state(unsigned sock
 	vs0 = (vs0 >> 4) & 0x3;
 	vs1 = (vs1 >> 12) & 0x3;
 #else
-	vs0 = (au_readw(PB1100_BOARD_STATUS) >> 4) & 0x3;
+	vs0 = (au_readw(BOARD_STATUS_REG) >> 4) & 0x3;
+#ifdef CONFIG_MIPS_PB1500
+	inserted0 = !((au_readl(GPIO2_PINSTATE) >> 1) & 0x1); /* gpio 201 */
+#else /* Pb1100 */
 	inserted0 = !((au_readl(SYS_PINSTATERD) >> 9) & 0x1); /* gpio 9 */
 #endif
+	inserted1 = 0;
+#endif
 
 	state->ready = 0;
 	state->vs_Xv = 0;
@@ -145,7 +151,7 @@ pb1x00_pcmcia_socket_state(unsigned sock
 					/* return without setting 'detect' */
 					printk(KERN_ERR "pb1x00 bad VS (%d)\n",
 							vs0);
-					return;
+					return 0;
 			}
 			state->detect = 1;
 		}
@@ -163,7 +169,7 @@ pb1x00_pcmcia_socket_state(unsigned sock
 					/* return without setting 'detect' */
 					printk(KERN_ERR "pb1x00 bad VS (%d)\n",
 							vs1);
-					return;
+					return 0;
 			}
 			state->detect = 1;
 		}
@@ -324,7 +330,7 @@ pb1x00_pcmcia_configure_socket(const str
 
 #else
 
-	pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf;
+	pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf;
 
 	debug("Vcc %dV Vpp %dV, pcr %x, reset %d\n", 
 			configure->vcc, configure->vpp, pcr, configure->reset);
@@ -383,26 +389,27 @@ pb1x00_pcmcia_configure_socket(const str
 			break;
 	}
 
-	au_writew(pcr, PB1100_MEM_PCMCIA);
+	au_writew(pcr, PCMCIA_BOARD_REG);
 	au_sync_delay(300);
 
 	if (!configure->reset) {
-		pcr |= PB1100_PC_DRV_EN;
-		au_writew(pcr, PB1100_MEM_PCMCIA);
+		pcr |= PC_DRV_EN;
+		au_writew(pcr, PCMCIA_BOARD_REG);
 		au_sync_delay(100);
-		pcr |= PB1100_PC_DEASSERT_RST;
-		au_writew(pcr, PB1100_MEM_PCMCIA);
+		pcr |= PC_DEASSERT_RST;
+		au_writew(pcr, PCMCIA_BOARD_REG);
 		au_sync_delay(100);
 	}
 	else {
-		pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
-		au_writew(pcr, PB1100_MEM_PCMCIA);
+		pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
+		au_writew(pcr, PCMCIA_BOARD_REG);
 		au_sync_delay(100);
 	}
 #endif
 	return 0;
 }
 
+
 struct pcmcia_low_level pb1x00_pcmcia_ops = { 
 	pb1x00_pcmcia_init,
 	pb1x00_pcmcia_shutdown,
diff -puN /dev/null drivers/pcmcia/au1000_xxs1500.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/pcmcia/au1000_xxs1500.c	2005-01-29 11:26:00.275706008 -0800
@@ -0,0 +1,191 @@
+/*
+ *
+ * MyCable board specific pcmcia routines.
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: Pete Popov, MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/tqueue.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/version.h>
+#include <linux/types.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/bus_ops.h>
+#include "cs_internal.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <asm/au1000.h>
+#include <asm/au1000_pcmcia.h>
+#include <asm/xxs1500.h>
+
+#if 0
+#define DEBUG(x,args...)	printk(__FUNCTION__ ": " x,##args)
+#else
+#define DEBUG(x,args...)
+#endif
+
+static int xxs1500_pcmcia_init(struct pcmcia_init *init)
+{
+	return PCMCIA_NUM_SOCKS;
+}
+
+static int xxs1500_pcmcia_shutdown(void)
+{
+	/* turn off power */
+	au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
+			GPIO2_OUTPUT);
+	au_sync_delay(100);
+
+	/* assert reset */
+	au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
+			GPIO2_OUTPUT);
+	au_sync_delay(100);
+	return 0;
+}
+
+
+static int
+xxs1500_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
+{
+	u32 inserted; u32 vs;
+	unsigned long gpio, gpio2;
+
+	if(sock > PCMCIA_MAX_SOCK) return -1;
+
+	gpio = au_readl(SYS_PINSTATERD);
+	gpio2 = au_readl(GPIO2_PINSTATE);
+
+	vs = gpio2 & ((1<<8) | (1<<9));
+	inserted = (!(gpio & 0x1) && !(gpio & 0x2));
+
+	state->ready = 0;
+	state->vs_Xv = 0;
+	state->vs_3v = 0;
+	state->detect = 0;
+
+	if (inserted) {
+		switch (vs) {
+			case 0:
+			case 1:
+			case 2:
+				state->vs_3v=1;
+				break;
+			case 3: /* 5V */
+			default:
+				/* return without setting 'detect' */
+				printk(KERN_ERR "au1x00_cs: unsupported VS\n",
+						vs);
+				return;
+		}
+		state->detect = 1;
+	}
+
+	if (state->detect) {
+		state->ready = 1;
+	}
+
+	state->bvd1= gpio2 & (1<<10);
+	state->bvd2 = gpio2 & (1<<11);
+	state->wrprot=0;
+	return 1;
+}
+
+
+static int xxs1500_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+
+	if(info->sock > PCMCIA_MAX_SOCK) return -1;
+	info->irq = PCMCIA_IRQ;
+	return 0;
+}
+
+
+static int
+xxs1500_pcmcia_configure_socket(const struct pcmcia_configure *configure)
+{
+
+	if(configure->sock > PCMCIA_MAX_SOCK) return -1;
+
+	DEBUG("Vcc %dV Vpp %dV, reset %d\n",
+			configure->vcc, configure->vpp, configure->reset);
+
+	switch(configure->vcc){
+		case 33: /* Vcc 3.3V */
+			/* turn on power */
+			DEBUG("turn on power\n");
+			au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30),
+					GPIO2_OUTPUT);
+			au_sync_delay(100);
+			break;
+		case 50: /* Vcc 5V */
+		default: /* what's this ? */
+			printk(KERN_ERR "au1x00_cs: unsupported VCC\n");
+		case 0:  /* Vcc 0 */
+			/* turn off power */
+			au_sync_delay(100);
+			au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
+					GPIO2_OUTPUT);
+			break;
+	}
+
+	if (!configure->reset) {
+		DEBUG("deassert reset\n");
+		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<4))|(1<<20),
+				GPIO2_OUTPUT);
+		au_sync_delay(100);
+		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<5))|(1<<21),
+				GPIO2_OUTPUT);
+	}
+	else {
+		DEBUG("assert reset\n");
+		au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
+				GPIO2_OUTPUT);
+	}
+	au_sync_delay(100);
+	return 0;
+}
+
+struct pcmcia_low_level xxs1500_pcmcia_ops = {
+	xxs1500_pcmcia_init,
+	xxs1500_pcmcia_shutdown,
+	xxs1500_pcmcia_socket_state,
+	xxs1500_pcmcia_get_irq_info,
+	xxs1500_pcmcia_configure_socket
+};
diff -puN drivers/pcmcia/Kconfig~mips-amd-alchemy-update drivers/pcmcia/Kconfig
--- 25/drivers/pcmcia/Kconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.219714520 -0800
+++ 25-akpm/drivers/pcmcia/Kconfig	2005-01-29 11:26:00.275706008 -0800
@@ -134,6 +134,10 @@ config HD64465_PCMCIA
 	tristate "HD64465 host bridge support"
 	depends on HD64465 && PCMCIA
 
+config PCMCIA_AU1X00
+	tristate "Au1x00 pcmcia support"
+	depends on SOC_AU1X00 && PCMCIA
+
 config PCMCIA_SA1100
 	tristate "SA1100 support"
 	depends on ARM && ARCH_SA1100 && PCMCIA
diff -puN drivers/pcmcia/Makefile~mips-amd-alchemy-update drivers/pcmcia/Makefile
--- 25/drivers/pcmcia/Makefile~mips-amd-alchemy-update	2005-01-29 11:26:00.220714368 -0800
+++ 25-akpm/drivers/pcmcia/Makefile	2005-01-29 11:26:00.276705856 -0800
@@ -30,10 +30,21 @@ obj-$(CONFIG_PCMCIA_SA1111)			+= sa11xx_
 obj-$(CONFIG_PCMCIA_PXA2XX)                     += pxa2xx_core.o pxa2xx_cs.o
 obj-$(CONFIG_M32R_PCC)				+= m32r_pcc.o
 obj-$(CONFIG_M32R_CFC)				+= m32r_cfc.o
+obj-$(CONFIG_PCMCIA_AU1X00)			+= au1x00_ss.o
 
 sa11xx_core-y					+= soc_common.o sa11xx_base.o
 pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
 
+au1x00_ss-y					+= au1000_generic.o
+au1x00_ss-$(CONFIG_MIPS_PB1000)			+= au1000_pb1x00.o
+au1x00_ss-$(CONFIG_MIPS_PB1100)			+= au1000_pb1x00.o
+au1x00_ss-$(CONFIG_MIPS_PB1500)			+= au1000_pb1x00.o
+au1x00_ss-$(CONFIG_MIPS_DB1000)			+= au1000_db1x00.o
+au1x00_ss-$(CONFIG_MIPS_DB1100)			+= au1000_db1x00.o
+au1x00_ss-$(CONFIG_MIPS_DB1500)			+= au1000_db1x00.o
+au1x00_ss-$(CONFIG_MIPS_DB1550)			+= au1000_db1x00.o
+au1x00_ss-$(CONFIG_MIPS_XXS1500)               += au1000_xxs1500.o
+
 sa1111_cs-y					+= sa1111_generic.o
 sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1100_neponset.o
 sa1111_cs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o
diff -puN /dev/null drivers/usb/host/ohci-au1xxx.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/usb/host/ohci-au1xxx.c	2005-01-29 11:26:00.279705400 -0800
@@ -0,0 +1,362 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for AMD Alchemy Au1xxx
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ * Modified for AMD Alchemy Au1xxx
+ *  by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/mach-au1x00/au1000.h>
+
+#define USBH_ENABLE_BE (1<<0)
+#define USBH_ENABLE_C  (1<<1)
+#define USBH_ENABLE_E  (1<<2)
+#define USBH_ENABLE_CE (1<<3)
+#define USBH_ENABLE_RD (1<<4)
+
+#ifdef __LITTLE_ENDIAN
+#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
+#elif __BIG_ENDIAN
+#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | USBH_ENABLE_BE)
+#else
+#error not byte order defined
+#endif
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void au1xxx_start_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+		": starting Au1xxx OHCI USB Controller\n");
+
+	/* enable host controller */
+	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
+	udelay(1000);
+
+	/* wait for reset complete (read register twice; see au1500 errata) */
+	while (au_readl(USB_HOST_CONFIG),
+		!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
+		udelay(1000);
+
+	printk(KERN_DEBUG __FILE__
+	": Clock to USB host has been enabled \n");
+}
+
+static void au1xxx_stop_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+	       ": stopping Au1xxx OHCI USB Controller\n");
+
+	/* Disable clock */
+	au_writel(readl((void *)USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+static irqreturn_t usb_hcd_au1xxx_hcim_irq (int irq, void *__hcd,
+					     struct pt_regs * r)
+{
+	struct usb_hcd *hcd = __hcd;
+
+	return usb_hcd_irq(irq, hcd, r);
+}
+
+/*-------------------------------------------------------------------------*/
+
+void usb_hcd_au1xxx_remove (struct usb_hcd *, struct platform_device *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
+			  struct usb_hcd **hcd_out,
+			  struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd = 0;
+
+	unsigned int *addr = NULL;
+
+	if (!request_mem_region(dev->resource[0].start,
+				dev->resource[0].end
+				- dev->resource[0].start + 1, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		return -EBUSY;
+	}
+
+	au1xxx_start_hc(dev);
+
+	addr = ioremap(dev->resource[0].start,
+		       dev->resource[0].end
+		       - dev->resource[0].start + 1);
+	if (!addr) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err1;
+	}
+
+	if(dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+		retval = -ENOMEM;
+		goto err1;
+	}
+
+	hcd = usb_create_hcd(driver);
+	if (hcd == NULL) {
+		pr_debug ("usb_create_hcd failed");
+		retval = -ENOMEM;
+		goto err1;
+	}
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	hcd->irq = dev->resource[1].start;
+	hcd->regs = addr;
+	hcd->self.controller = &dev->dev;
+
+	retval = hcd_buffer_create (hcd);
+	if (retval != 0) {
+		pr_debug ("pool alloc fail");
+		goto err2;
+	}
+
+	retval = request_irq (hcd->irq, usb_hcd_au1xxx_hcim_irq, SA_INTERRUPT,
+			      hcd->driver->description, hcd);
+	if (retval != 0) {
+		pr_debug("request_irq failed");
+		retval = -EBUSY;
+		goto err3;
+	}
+
+	pr_debug ("%s (Au1xxx) at 0x%p, irq %d",
+	     hcd->driver->description, hcd->regs, hcd->irq);
+
+	hcd->self.bus_name = "au1xxx";
+
+	usb_register_bus (&hcd->self);
+
+	if ((retval = driver->start (hcd)) < 0)
+	{
+		usb_hcd_au1xxx_remove(hcd, dev);
+		printk("bad driver->start\n");
+		return retval;
+	}
+
+	*hcd_out = hcd;
+	return 0;
+
+ err3:
+	hcd_buffer_destroy (hcd);
+ err2:
+	usb_put_hcd(hcd);
+ err1:
+	au1xxx_stop_hc(dev);
+	release_mem_region(dev->resource[0].start,
+				dev->resource[0].end
+			   - dev->resource[0].start + 1);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_au1xxx_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+	pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
+
+	if (in_interrupt ())
+		BUG ();
+
+	hcd->state = USB_STATE_QUIESCING;
+
+	pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
+	usb_disconnect (&hcd->self.root_hub);
+
+	hcd->driver->stop (hcd);
+	hcd->state = USB_STATE_HALT;
+
+	free_irq (hcd->irq, hcd);
+	hcd_buffer_destroy (hcd);
+
+	usb_deregister_bus (&hcd->self);
+
+	au1xxx_stop_hc(dev);
+	release_mem_region(dev->resource[0].start,
+			   dev->resource[0].end
+			   - dev->resource[0].start + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_au1xxx_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	ohci_dbg (ohci, "ohci_au1xxx_start, ohci:%p", ohci);
+
+	if ((ret = ohci_init (ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run (ohci)) < 0) {
+		err ("can't start %s", hcd->self.bus_name);
+		ohci_stop (hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_au1xxx_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"Au1xxx OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_au1xxx_start,
+#ifdef	CONFIG_PM
+	/* suspend:		ohci_au1xxx_suspend,  -- tbd */
+	/* resume:		ohci_au1xxx_resume,   -- tbd */
+#endif /*CONFIG_PM*/
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_au1xxx_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = NULL;
+	int ret;
+
+	pr_debug ("In ohci_hcd_au1xxx_drv_probe");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, &hcd, pdev);
+
+	if (ret == 0)
+		dev_set_drvdata(dev, hcd);
+
+	return ret;
+}
+
+static int ohci_hcd_au1xxx_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_au1xxx_remove(hcd, pdev);
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+	/*TBD*/
+/*static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+static int ohci_hcd_au1xxx_drv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+*/
+
+static struct device_driver ohci_hcd_au1xxx_driver = {
+	.name		= "au1xxx-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_au1xxx_drv_probe,
+	.remove		= ohci_hcd_au1xxx_drv_remove,
+	/*.suspend	= ohci_hcd_au1xxx_drv_suspend, */
+	/*.resume	= ohci_hcd_au1xxx_drv_resume, */
+};
+
+static int __init ohci_hcd_au1xxx_init (void)
+{
+	pr_debug (DRIVER_INFO " (Au1xxx)");
+	pr_debug ("block sizes: ed %d td %d\n",
+		sizeof (struct ed), sizeof (struct td));
+
+	return driver_register(&ohci_hcd_au1xxx_driver);
+}
+
+static void __exit ohci_hcd_au1xxx_cleanup (void)
+{
+	driver_unregister(&ohci_hcd_au1xxx_driver);
+}
+
+module_init (ohci_hcd_au1xxx_init);
+module_exit (ohci_hcd_au1xxx_cleanup);
diff -puN drivers/usb/host/ohci-hcd.c~mips-amd-alchemy-update drivers/usb/host/ohci-hcd.c
--- 25/drivers/usb/host/ohci-hcd.c~mips-amd-alchemy-update	2005-01-29 11:26:00.222714064 -0800
+++ 25-akpm/drivers/usb/host/ohci-hcd.c	2005-01-29 11:26:00.277705704 -0800
@@ -897,11 +897,16 @@ MODULE_LICENSE ("GPL");
 #include "ohci-pxa27x.c"
 #endif
 
+#ifdef CONFIG_SOC_AU1X00
+#include "ohci-au1xxx.c"
+#endif
+
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_ARCH_OMAP) \
       || defined (CONFIG_ARCH_LH7A404) \
       || defined (CONFIG_PXA27x) \
+      || defined (CONFIG_SOC_AU1X00) \
 	)
 #error "missing bus glue for ohci-hcd"
 #endif
diff -puN /dev/null drivers/video/au1100fb.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/video/au1100fb.c	2005-01-29 11:26:00.291703576 -0800
@@ -0,0 +1,676 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1100 LCD Driver.
+ *
+ * Copyright 2002 MontaVista Software
+ * Author: MontaVista Software, Inc.
+ *		ppopov@mvista.com or source@mvista.com
+ *
+ * Copyright 2002 Alchemy Semiconductor
+ * Author: Alchemy Semiconductor
+ *
+ * Based on:
+ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
+ *  Created 28 Dec 1997 by Geert Uytterhoeven
+ *
+ *  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  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/au1000.h>
+#include <asm/pb1100.h>
+#include "au1100fb.h"
+
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include <video/fbcon-cfb2.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+
+/*
+ * Sanity check. If this is a new Au1100 based board, search for
+ * the PB1100 ifdefs to make sure you modify the code accordingly.
+ */
+#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_HYDROGEN3)
+#else
+error Unknown Au1100 board
+#endif
+
+#define CMAPSIZE 16
+
+static int my_lcd_index; /* default is zero */
+struct known_lcd_panels *p_lcd;
+AU1100_LCD *p_lcd_reg = (AU1100_LCD *)AU1100_LCD_ADDR;
+
+struct au1100fb_info {
+	struct fb_info_gen gen;
+	unsigned long fb_virt_start;
+	unsigned long fb_size;
+	unsigned long fb_phys;
+	int mmaped;
+	int nohwcursor;
+
+	struct { unsigned red, green, blue, pad; } palette[256];
+
+#if defined(FBCON_HAS_CFB16)
+	u16 fbcon_cmap16[16];
+#endif
+};
+
+
+struct au1100fb_par {
+        struct fb_var_screeninfo var;
+
+	int line_length;  // in bytes
+	int cmap_len;     // color-map length
+};
+
+
+static struct au1100fb_info fb_info;
+static struct au1100fb_par current_par;
+static struct display disp;
+
+int au1100fb_init(void);
+void au1100fb_setup(char *options, int *ints);
+static int au1100fb_mmap(struct fb_info *fb, struct file *file,
+		struct vm_area_struct *vma);
+static int au1100_blank(int blank_mode, struct fb_info_gen *info);
+static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info);
+
+void au1100_nocursor(struct display *p, int mode, int xx, int yy){};
+
+static struct fb_ops au1100fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	fbgen_get_fix,
+	fb_get_var:	fbgen_get_var,
+	fb_set_var:	fbgen_set_var,
+	fb_get_cmap:	fbgen_get_cmap,
+	fb_set_cmap:	fbgen_set_cmap,
+	fb_pan_display: fbgen_pan_display,
+        fb_ioctl:       au1100fb_ioctl,
+	fb_mmap:        au1100fb_mmap,
+};
+
+static void au1100_detect(void)
+{
+	/*
+	 *  This function should detect the current video mode settings
+	 *  and store it as the default video mode
+	 */
+
+	/*
+	 * Yeh, well, we're not going to change any settings so we're
+	 * always stuck with the default ...
+	 */
+
+}
+
+static int au1100_encode_fix(struct fb_fix_screeninfo *fix,
+		const void *_par, struct fb_info_gen *_info)
+{
+        struct au1100fb_info *info = (struct au1100fb_info *) _info;
+        struct au1100fb_par *par = (struct au1100fb_par *) _par;
+	struct fb_var_screeninfo *var = &par->var;
+
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+	fix->smem_start = info->fb_phys;
+	fix->smem_len = info->fb_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+        fix->visual = (var->bits_per_pixel == 8) ?
+	       	FB_VISUAL_PSEUDOCOLOR	: FB_VISUAL_TRUECOLOR;
+	fix->ywrapstep = 0;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->line_length = current_par.line_length;
+	return 0;
+}
+
+static void set_color_bitfields(struct fb_var_screeninfo *var)
+{
+	switch (var->bits_per_pixel) {
+	case 8:
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 16:	/* RGB 565 */
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	}
+
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+}
+
+static int au1100_decode_var(const struct fb_var_screeninfo *var,
+		void *_par, struct fb_info_gen *_info)
+{
+
+	struct au1100fb_par *par = (struct au1100fb_par *)_par;
+
+	/*
+	 * Don't allow setting any of these yet: xres and yres don't
+	 * make sense for LCD panels.
+	 */
+	if (var->xres != p_lcd->xres ||
+	    var->yres != p_lcd->yres ||
+	    var->xres != p_lcd->xres ||
+	    var->yres != p_lcd->yres) {
+		return -EINVAL;
+	}
+	if(var->bits_per_pixel != p_lcd->bpp) {
+		return -EINVAL;
+	}
+
+	memset(par, 0, sizeof(struct au1100fb_par));
+	par->var = *var;
+
+	/* FIXME */
+	switch (var->bits_per_pixel) {
+		case 8:
+			par->var.bits_per_pixel = 8;
+			break;
+		case 16:
+			par->var.bits_per_pixel = 16;
+			break;
+		default:
+			printk("color depth %d bpp not supported\n",
+					var->bits_per_pixel);
+			return -EINVAL;
+
+	}
+	set_color_bitfields(&par->var);
+	par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16;
+	return 0;
+}
+
+static int au1100_encode_var(struct fb_var_screeninfo *var,
+		const void *par, struct fb_info_gen *_info)
+{
+
+	*var = ((struct au1100fb_par *)par)->var;
+	return 0;
+}
+
+static void
+au1100_get_par(void *_par, struct fb_info_gen *_info)
+{
+	*(struct au1100fb_par *)_par = current_par;
+}
+
+static void au1100_set_par(const void *par, struct fb_info_gen *info)
+{
+	/* nothing to do: we don't change any settings */
+}
+
+static int au1100_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			 unsigned *blue, unsigned *transp,
+			 struct fb_info *info)
+{
+
+	struct au1100fb_info* i = (struct au1100fb_info*)info;
+
+	if (regno > 255)
+		return 1;
+
+	*red    = i->palette[regno].red;
+	*green  = i->palette[regno].green;
+	*blue   = i->palette[regno].blue;
+	*transp = 0;
+
+	return 0;
+}
+
+static int au1100_setcolreg(unsigned regno, unsigned red, unsigned green,
+			 unsigned blue, unsigned transp,
+			 struct fb_info *info)
+{
+	struct au1100fb_info* i = (struct au1100fb_info *)info;
+	u32 rgbcol;
+
+	if (regno > 255)
+		return 1;
+
+	i->palette[regno].red    = red;
+	i->palette[regno].green  = green;
+	i->palette[regno].blue   = blue;
+
+	switch(p_lcd->bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		red >>= 10;
+		green >>= 10;
+		blue >>= 10;
+		p_lcd_reg->lcd_pallettebase[regno] = (blue&0x1f) |
+			((green&0x3f)<<5) | ((red&0x1f)<<11);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		i->fbcon_cmap16[regno] =
+			((red & 0xf800) >> 0) |
+			((green & 0xfc00) >> 5) |
+			((blue & 0xf800) >> 11);
+		break;
+#endif
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+
+static int  au1100_blank(int blank_mode, struct fb_info_gen *_info)
+{
+
+	switch (blank_mode) {
+	case VESA_NO_BLANKING:
+		/* turn on panel */
+		//printk("turn on panel\n");
+#ifdef CONFIG_MIPS_PB1100
+		p_lcd_reg->lcd_control |= LCD_CONTROL_GO;
+		au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight,
+			PB1100_G_CONTROL);
+#endif
+#ifdef CONFIG_MIPS_HYDROGEN3
+		/*  Turn controller & power supply on,  GPIO213 */
+		au_writel(0x20002000, 0xB1700008);
+		au_writel(0x00040000, 0xB1900108);
+		au_writel(0x01000100, 0xB1700008);
+#endif
+		au_sync();
+		break;
+
+	case VESA_VSYNC_SUSPEND:
+	case VESA_HSYNC_SUSPEND:
+	case VESA_POWERDOWN:
+		/* turn off panel */
+		//printk("turn off panel\n");
+#ifdef CONFIG_MIPS_PB1100
+		au_writew(au_readw(PB1100_G_CONTROL) & ~p_lcd->mode_backlight,
+			PB1100_G_CONTROL);
+		p_lcd_reg->lcd_control &= ~LCD_CONTROL_GO;
+#endif
+		au_sync();
+		break;
+	default:
+		break;
+
+	}
+	return 0;
+}
+
+static void au1100_set_disp(const void *unused, struct display *disp,
+			 struct fb_info_gen *info)
+{
+	disp->screen_base = (char *)fb_info.fb_virt_start;
+
+	switch (disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		disp->dispsw = &fbcon_cfb8;
+		if (fb_info.nohwcursor)
+			fbcon_cfb8.cursor = au1100_nocursor;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		disp->dispsw = &fbcon_cfb16;
+		disp->dispsw_data = fb_info.fbcon_cmap16;
+		if (fb_info.nohwcursor)
+			fbcon_cfb16.cursor = au1100_nocursor;
+		break;
+#endif
+	default:
+		disp->dispsw = &fbcon_dummy;
+		disp->dispsw_data = NULL;
+		break;
+	}
+}
+
+static int
+au1100fb_mmap(struct fb_info *_fb,
+	     struct file *file,
+	     struct vm_area_struct *vma)
+{
+	unsigned int len;
+	unsigned long start=0, off;
+	struct au1100fb_info *fb = (struct au1100fb_info *)_fb;
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
+		return -EINVAL;
+	}
+
+	start = fb_info.fb_phys & PAGE_MASK;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + fb_info.fb_size);
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	if ((vma->vm_end - vma->vm_start + off) > len) {
+		return -EINVAL;
+	}
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+	//pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT;
+	pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
+
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO;
+
+	if (io_remap_page_range(vma->vm_start, off,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot)) {
+		return -EAGAIN;
+	}
+
+	fb->mmaped = 1;
+	return 0;
+}
+
+int au1100_pan_display(const struct fb_var_screeninfo *var,
+		       struct fb_info_gen *info)
+{
+	return 0;
+}
+
+static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+			  u_long arg, int con, struct fb_info *info)
+{
+	/* nothing to do yet */
+	return -EINVAL;
+}
+
+static struct fbgen_hwswitch au1100_switch = {
+	au1100_detect,
+	au1100_encode_fix,
+	au1100_decode_var,
+	au1100_encode_var,
+	au1100_get_par,
+	au1100_set_par,
+	au1100_getcolreg,
+	au1100_setcolreg,
+	au1100_pan_display,
+	au1100_blank,
+	au1100_set_disp
+};
+
+
+int au1100_setmode(void)
+{
+	int words;
+
+	/* FIXME Need to accomodate for swivel mode and 12bpp, <8bpp*/
+	switch (p_lcd->mode_control & LCD_CONTROL_SM)
+	{
+		case LCD_CONTROL_SM_0:
+		case LCD_CONTROL_SM_180:
+		words = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 32;
+			break;
+		case LCD_CONTROL_SM_90:
+		case LCD_CONTROL_SM_270:
+			/* is this correct? */
+		words = (p_lcd->xres * p_lcd->bpp) / 8;
+			break;
+		default:
+			printk("mode_control reg not initialized\n");
+			return -EINVAL;
+	}
+
+	/*
+	 * Setup LCD controller
+	 */
+
+	p_lcd_reg->lcd_control = p_lcd->mode_control;
+	p_lcd_reg->lcd_intstatus = 0;
+	p_lcd_reg->lcd_intenable = 0;
+	p_lcd_reg->lcd_horztiming = p_lcd->mode_horztiming;
+	p_lcd_reg->lcd_verttiming = p_lcd->mode_verttiming;
+	p_lcd_reg->lcd_clkcontrol = p_lcd->mode_clkcontrol;
+	p_lcd_reg->lcd_words = words - 1;
+	p_lcd_reg->lcd_dmaaddr0 = fb_info.fb_phys;
+
+	/* turn on panel */
+#ifdef CONFIG_MIPS_PB1100
+	au_writew(au_readw(PB1100_G_CONTROL) | p_lcd->mode_backlight,
+			PB1100_G_CONTROL);
+#endif
+#ifdef CONFIG_MIPS_HYDROGEN3
+	/*  Turn controller & power supply on,  GPIO213 */
+	au_writel(0x20002000, 0xB1700008);
+	au_writel(0x00040000, 0xB1900108);
+	au_writel(0x01000100, 0xB1700008);
+#endif
+
+	p_lcd_reg->lcd_control |= LCD_CONTROL_GO;
+
+	return 0;
+}
+
+
+int __init au1100fb_init(void)
+{
+	uint32 sys_clksrc;
+	unsigned long page;
+
+	/*
+	* Get the panel information/display mode and update the registry
+	*/
+	p_lcd = &panels[my_lcd_index];
+
+	switch (p_lcd->mode_control & LCD_CONTROL_SM)
+	{
+		case LCD_CONTROL_SM_0:
+		case LCD_CONTROL_SM_180:
+		p_lcd->xres =
+			(p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1;
+		p_lcd->yres =
+			(p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1;
+			break;
+		case LCD_CONTROL_SM_90:
+		case LCD_CONTROL_SM_270:
+		p_lcd->yres =
+			(p_lcd->mode_horztiming & LCD_HORZTIMING_PPL) + 1;
+		p_lcd->xres =
+			(p_lcd->mode_verttiming & LCD_VERTTIMING_LPP) + 1;
+			break;
+	}
+
+	/*
+	 * Panel dimensions x bpp must be divisible by 32
+	 */
+	if (((p_lcd->yres * p_lcd->bpp) % 32) != 0)
+		printk("VERT %% 32\n");
+	if (((p_lcd->xres * p_lcd->bpp) % 32) != 0)
+		printk("HORZ %% 32\n");
+
+	/*
+	 * Allocate LCD framebuffer from system memory
+	 */
+	fb_info.fb_size = (p_lcd->xres * p_lcd->yres * p_lcd->bpp) / 8;
+
+	current_par.var.xres = p_lcd->xres;
+	current_par.var.xres_virtual = p_lcd->xres;
+	current_par.var.yres = p_lcd->yres;
+	current_par.var.yres_virtual = p_lcd->yres;
+	current_par.var.bits_per_pixel = p_lcd->bpp;
+
+	/* FIX!!! only works for 8/16 bpp */
+	current_par.line_length = p_lcd->xres * p_lcd->bpp / 8; /* in bytes */
+	fb_info.fb_virt_start = (unsigned long )
+		__get_free_pages(GFP_ATOMIC | GFP_DMA,
+				get_order(fb_info.fb_size + 0x1000));
+	if (!fb_info.fb_virt_start) {
+		printk("Unable to allocate fb memory\n");
+		return -ENOMEM;
+	}
+	fb_info.fb_phys = virt_to_bus((void *)fb_info.fb_virt_start);
+
+	/*
+	 * Set page reserved so that mmap will work. This is necessary
+	 * since we'll be remapping normal memory.
+	 */
+	for (page = fb_info.fb_virt_start;
+	     page < PAGE_ALIGN(fb_info.fb_virt_start + fb_info.fb_size);
+	     page += PAGE_SIZE) {
+		SetPageReserved(virt_to_page(page));
+	}
+
+	memset((void *)fb_info.fb_virt_start, 0, fb_info.fb_size);
+
+	/* set freqctrl now to allow more time to stabilize */
+	/* zero-out out LCD bits */
+	sys_clksrc = au_readl(SYS_CLKSRC) & ~0x000003e0;
+	sys_clksrc |= p_lcd->mode_toyclksrc;
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	/* FIXME add check to make sure auxpll is what is expected! */
+	au1100_setmode();
+
+	fb_info.gen.parsize = sizeof(struct au1100fb_par);
+	fb_info.gen.fbhw = &au1100_switch;
+
+	strcpy(fb_info.gen.info.modename, "Au1100 LCD");
+	fb_info.gen.info.changevar = NULL;
+	fb_info.gen.info.node = -1;
+
+	fb_info.gen.info.fbops = &au1100fb_ops;
+	fb_info.gen.info.disp = &disp;
+	fb_info.gen.info.switch_con = &fbgen_switch;
+	fb_info.gen.info.updatevar = &fbgen_update_var;
+	fb_info.gen.info.blank = &fbgen_blank;
+	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+
+	/* This should give a reasonable default video mode */
+	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+	fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+	fbgen_set_disp(-1, &fb_info.gen);
+	fbgen_install_cmap(0, &fb_info.gen);
+	if (register_framebuffer(&fb_info.gen.info) < 0)
+		return -EINVAL;
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+			GET_FB_IDX(fb_info.gen.info.node),
+			fb_info.gen.info.modename);
+
+	return 0;
+}
+
+
+void au1100fb_cleanup(struct fb_info *info)
+{
+	unregister_framebuffer(info);
+}
+
+
+void au1100fb_setup(char *options, int *ints)
+{
+	char* this_opt;
+	int i;
+	int num_panels = sizeof(panels)/sizeof(struct known_lcd_panels);
+
+
+	if (!options || !*options)
+		return;
+
+	for(this_opt=strtok(options, ","); this_opt;
+	    this_opt=strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "panel:", 6)) {
+#if defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1100)
+			/* Read Pb1100 Switch S10 ? */
+			if (!strncmp(this_opt+6, "s10", 3))
+			{
+				int panel;
+				panel = *(volatile int *)0xAE000008; /* BCSR SWITCHES */
+				panel >>= 8;
+				panel &= 0x0F;
+				if (panel >= num_panels) panel = 0;
+				my_lcd_index = panel;
+			}
+			else
+#endif
+			/* Get the panel name, everything else if fixed */
+			for (i=0; i<num_panels; i++) {
+				if (!strncmp(this_opt+6, panels[i].panel_name,
+							strlen(this_opt))) {
+					my_lcd_index = i;
+					break;
+				}
+			}
+		}
+		else if (!strncmp(this_opt, "nohwcursor", 10)) {
+			printk("nohwcursor\n");
+			fb_info.nohwcursor = 1;
+		}
+	}
+
+	printk("au1100fb: Panel %d %s\n", my_lcd_index,
+		panels[my_lcd_index].panel_name);
+}
+
+
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+int init_module(void)
+{
+	return au1100fb_init();
+}
+
+void cleanup_module(void)
+{
+	au1100fb_cleanup(void);
+}
+
+MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
+MODULE_DESCRIPTION("Au1100 LCD framebuffer device driver");
+#endif /* MODULE */
diff -puN /dev/null drivers/video/au1100fb.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/video/au1100fb.h	2005-01-29 11:26:00.287704184 -0800
@@ -0,0 +1,381 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Hardware definitions for the Au1100 LCD controller
+ *
+ * Copyright 2002 MontaVista Software
+ * Copyright 2002 Alchemy Semiconductor
+ * Author:	Alchemy Semiconductor, MontaVista Software
+ *
+ *  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  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#ifndef _AU1100LCD_H
+#define _AU1100LCD_H
+
+/********************************************************************/
+#define uint32 unsigned long
+typedef volatile struct
+{
+	uint32	lcd_control;
+	uint32	lcd_intstatus;
+	uint32	lcd_intenable;
+	uint32	lcd_horztiming;
+	uint32	lcd_verttiming;
+	uint32	lcd_clkcontrol;
+	uint32	lcd_dmaaddr0;
+	uint32	lcd_dmaaddr1;
+	uint32	lcd_words;
+	uint32	lcd_pwmdiv;
+	uint32	lcd_pwmhi;
+	uint32	reserved[(0x0400-0x002C)/4];
+	uint32	lcd_pallettebase[256];
+
+} AU1100_LCD;
+
+/********************************************************************/
+
+#define AU1100_LCD_ADDR		0xB5000000
+
+/*
+ * Register bit definitions
+ */
+
+/* lcd_control */
+#define LCD_CONTROL_SBPPF		(7<<18)
+#define LCD_CONTROL_SBPPF_655	(0<<18)
+#define LCD_CONTROL_SBPPF_565	(1<<18)
+#define LCD_CONTROL_SBPPF_556	(2<<18)
+#define LCD_CONTROL_SBPPF_1555	(3<<18)
+#define LCD_CONTROL_SBPPF_5551	(4<<18)
+#define LCD_CONTROL_WP			(1<<17)
+#define LCD_CONTROL_WD			(1<<16)
+#define LCD_CONTROL_C			(1<<15)
+#define LCD_CONTROL_SM			(3<<13)
+#define LCD_CONTROL_SM_0		(0<<13)
+#define LCD_CONTROL_SM_90		(1<<13)
+#define LCD_CONTROL_SM_180		(2<<13)
+#define LCD_CONTROL_SM_270		(3<<13)
+#define LCD_CONTROL_DB			(1<<12)
+#define LCD_CONTROL_CCO			(1<<11)
+#define LCD_CONTROL_DP			(1<<10)
+#define LCD_CONTROL_PO			(3<<8)
+#define LCD_CONTROL_PO_00		(0<<8)
+#define LCD_CONTROL_PO_01		(1<<8)
+#define LCD_CONTROL_PO_10		(2<<8)
+#define LCD_CONTROL_PO_11		(3<<8)
+#define LCD_CONTROL_MPI			(1<<7)
+#define LCD_CONTROL_PT			(1<<6)
+#define LCD_CONTROL_PC			(1<<5)
+#define LCD_CONTROL_BPP			(7<<1)
+#define LCD_CONTROL_BPP_1		(0<<1)
+#define LCD_CONTROL_BPP_2		(1<<1)
+#define LCD_CONTROL_BPP_4		(2<<1)
+#define LCD_CONTROL_BPP_8		(3<<1)
+#define LCD_CONTROL_BPP_12		(4<<1)
+#define LCD_CONTROL_BPP_16		(5<<1)
+#define LCD_CONTROL_GO			(1<<0)
+
+/* lcd_intstatus, lcd_intenable */
+#define LCD_INT_SD				(1<<7)
+#define LCD_INT_OF				(1<<6)
+#define LCD_INT_UF				(1<<5)
+#define LCD_INT_SA				(1<<3)
+#define LCD_INT_SS				(1<<2)
+#define LCD_INT_S1				(1<<1)
+#define LCD_INT_S0				(1<<0)
+
+/* lcd_horztiming */
+#define LCD_HORZTIMING_HN2		(255<<24)
+#define LCD_HORZTIMING_HN2_N(N)	(((N)-1)<<24)
+#define LCD_HORZTIMING_HN1		(255<<16)
+#define LCD_HORZTIMING_HN1_N(N)	(((N)-1)<<16)
+#define LCD_HORZTIMING_HPW		(63<<10)
+#define LCD_HORZTIMING_HPW_N(N)	(((N)-1)<<10)
+#define LCD_HORZTIMING_PPL		(1023<<0)
+#define LCD_HORZTIMING_PPL_N(N)	(((N)-1)<<0)
+
+/* lcd_verttiming */
+#define LCD_VERTTIMING_VN2		(255<<24)
+#define LCD_VERTTIMING_VN2_N(N)	(((N)-1)<<24)
+#define LCD_VERTTIMING_VN1		(255<<16)
+#define LCD_VERTTIMING_VN1_N(N)	(((N)-1)<<16)
+#define LCD_VERTTIMING_VPW		(63<<10)
+#define LCD_VERTTIMING_VPW_N(N)	(((N)-1)<<10)
+#define LCD_VERTTIMING_LPP		(1023<<0)
+#define LCD_VERTTIMING_LPP_N(N)	(((N)-1)<<0)
+
+/* lcd_clkcontrol */
+#define LCD_CLKCONTROL_IB		(1<<18)
+#define LCD_CLKCONTROL_IC		(1<<17)
+#define LCD_CLKCONTROL_IH		(1<<16)
+#define LCD_CLKCONTROL_IV		(1<<15)
+#define LCD_CLKCONTROL_BF		(31<<10)
+#define LCD_CLKCONTROL_BF_N(N)	(((N)-1)<<10)
+#define LCD_CLKCONTROL_PCD		(1023<<0)
+#define LCD_CLKCONTROL_PCD_N(N)	((N)<<0)
+
+/* lcd_pwmdiv */
+#define LCD_PWMDIV_EN			(1<<12)
+#define LCD_PWMDIV_PWMDIV		(2047<<0)
+#define LCD_PWMDIV_PWMDIV_N(N)	(((N)-1)<<0)
+
+/* lcd_pwmhi */
+#define LCD_PWMHI_PWMHI1		(2047<<12)
+#define LCD_PWMHI_PWMHI1_N(N)	((N)<<12)
+#define LCD_PWMHI_PWMHI0		(2047<<0)
+#define LCD_PWMHI_PWMHI0_N(N)	((N)<<0)
+
+/* lcd_pallettebase - MONOCHROME */
+#define LCD_PALLETTE_MONO_MI		(15<<0)
+#define LCD_PALLETTE_MONO_MI_N(N)	((N)<<0)
+
+/* lcd_pallettebase - COLOR */
+#define LCD_PALLETTE_COLOR_BI		(15<<8)
+#define LCD_PALLETTE_COLOR_BI_N(N)	((N)<<8)
+#define LCD_PALLETTE_COLOR_GI		(15<<4)
+#define LCD_PALLETTE_COLOR_GI_N(N)	((N)<<4)
+#define LCD_PALLETTE_COLOR_RI		(15<<0)
+#define LCD_PALLETTE_COLOR_RI_N(N)	((N)<<0)
+
+/* lcd_palletebase - COLOR TFT PALLETIZED */
+#define LCD_PALLETTE_TFT_DC			(65535<<0)
+#define LCD_PALLETTE_TFT_DC_N(N)	((N)<<0)
+
+/********************************************************************/
+
+struct known_lcd_panels
+{
+	uint32 xres;
+	uint32 yres;
+	uint32 bpp;
+	unsigned char  panel_name[256];
+	uint32 mode_control;
+	uint32 mode_horztiming;
+	uint32 mode_verttiming;
+	uint32 mode_clkcontrol;
+	uint32 mode_pwmdiv;
+	uint32 mode_pwmhi;
+	uint32 mode_toyclksrc;
+	uint32 mode_backlight;
+
+};
+
+#if defined(__BIG_ENDIAN)
+#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_11
+#else
+#define LCD_DEFAULT_PIX_FORMAT LCD_CONTROL_PO_00
+#endif
+
+/*
+ * The fb driver assumes that AUX PLL is at 48MHz.  That can
+ * cover up to 800x600 resolution; if you need higher resolution,
+ * you should modify the driver as needed, not just this structure.
+ */
+struct known_lcd_panels panels[] =
+{
+	{ /* 0: Pb1100 LCDA: Sharp 320x240 TFT panel */
+		320, /* xres */
+		240, /* yres */
+		16,  /* bpp  */
+
+		"Sharp_320x240_16",
+		/* mode_control */
+		( LCD_CONTROL_SBPPF_565
+		/*LCD_CONTROL_WP*/
+		/*LCD_CONTROL_WD*/
+		| LCD_CONTROL_C
+		| LCD_CONTROL_SM_0
+		/*LCD_CONTROL_DB*/
+		/*LCD_CONTROL_CCO*/
+		/*LCD_CONTROL_DP*/
+		| LCD_DEFAULT_PIX_FORMAT
+		/*LCD_CONTROL_MPI*/
+		| LCD_CONTROL_PT
+		| LCD_CONTROL_PC
+		| LCD_CONTROL_BPP_16 ),
+
+		/* mode_horztiming */
+		( LCD_HORZTIMING_HN2_N(8)
+		| LCD_HORZTIMING_HN1_N(60)
+		| LCD_HORZTIMING_HPW_N(12)
+		| LCD_HORZTIMING_PPL_N(320) ),
+
+		/* mode_verttiming */
+		( LCD_VERTTIMING_VN2_N(5)
+		| LCD_VERTTIMING_VN1_N(17)
+		| LCD_VERTTIMING_VPW_N(1)
+		| LCD_VERTTIMING_LPP_N(240) ),
+
+		/* mode_clkcontrol */
+		( 0
+		/*LCD_CLKCONTROL_IB*/
+		/*LCD_CLKCONTROL_IC*/
+		/*LCD_CLKCONTROL_IH*/
+		/*LCD_CLKCONTROL_IV*/
+		| LCD_CLKCONTROL_PCD_N(1) ),
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (1<<5)),
+
+		/* mode_backlight */
+		6
+	},
+
+	{ /* 1: Pb1100 LCDC 640x480 TFT panel */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp  */
+
+		"Generic_640x480_16",
+
+		/* mode_control */
+		0x004806a | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x3434d67f,
+
+		/* mode_verttiming */
+		0x0e0e39df,
+
+		/* mode_clkcontrol */
+		( 0
+		/*LCD_CLKCONTROL_IB*/
+		/*LCD_CLKCONTROL_IC*/
+		/*LCD_CLKCONTROL_IH*/
+		/*LCD_CLKCONTROL_IV*/
+		| LCD_CLKCONTROL_PCD_N(1) ),
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 2: Pb1100 LCDB 640x480 PrimeView TFT panel */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp  */
+
+		"PrimeView_640x480_16",
+
+		/* mode_control */
+		0x0004886a | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x0e4bfe7f,
+
+		/* mode_verttiming */
+		0x210805df,
+
+		/* mode_clkcontrol */
+		0x00038001,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 3: Pb1100 800x600x16bpp NEON CRT */
+		800, /* xres */
+		600, /* yres */
+		16,  /* bpp */
+
+		"NEON_800x600_16",
+
+		/* mode_control */
+		0x0004886A | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x005AFF1F,
+
+		/* mode_verttiming */
+		0x16000E57,
+
+		/* mode_clkcontrol */
+		0x00020000,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+
+	{ /* 4: Pb1100 640x480x16bpp NEON CRT */
+		640, /* xres */
+		480, /* yres */
+		16,  /* bpp */
+
+		"NEON_640x480_16",
+
+		/* mode_control */
+		0x0004886A | LCD_DEFAULT_PIX_FORMAT,
+
+		/* mode_horztiming */
+		0x0052E27F,
+
+		/* mode_verttiming */
+		0x18000DDF,
+
+		/* mode_clkcontrol */
+		0x00020000,
+
+		/* mode_pwmdiv */
+		0,
+
+		/* mode_pwmhi */
+		0,
+
+		/* mode_toyclksrc */
+		((1<<7) | (1<<6) | (0<<5)),
+
+		/* mode_backlight */
+		7
+	},
+};
+#endif /* _AU1100LCD_H */
diff -puN drivers/video/Kconfig~mips-amd-alchemy-update drivers/video/Kconfig
--- 25/drivers/video/Kconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.224713760 -0800
+++ 25-akpm/drivers/video/Kconfig	2005-01-29 11:26:00.292703424 -0800
@@ -919,6 +919,42 @@ config FB_PM3
 	  similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000
 	  and maybe other boards.
 
+config FB_E1356
+	tristate "Epson SED1356 framebuffer support"
+	depends on FB && EXPERIMENTAL && PCI && MIPS
+
+config PB1000_CRT
+	bool "Use CRT on Pb1000 (J65)"
+	depends on MIPS_PB1000=y && FB_E1356
+
+config PB1000_NTSC
+	bool "Use Compsite NTSC on Pb1000 (J63)"
+	depends on MIPS_PB1000=y && FB_E1356
+
+config PB1000_TFT
+	bool "Use TFT Panel on Pb1000 (J64)"
+	depends on MIPS_PB1000=y && FB_E1356
+
+config PB1500_CRT
+	bool "Use CRT on Pb1500 " if MIPS_PB1500=y
+	depends on FB_E1356
+
+config PB1500_CRT
+	prompt "Use CRT on Pb1100 "
+	depends on FB_E1356 && MIPS_PB1100=y
+
+config PB1500_TFT
+	bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y
+	depends on FB_E1356
+
+config PB1500_TFT
+	prompt "Use TFT Panel on Pb1100 "
+	depends on FB_E1356 && MIPS_PB1100=y
+
+config FB_AU1100
+	bool "Au1100 LCD Driver"
+	depends on FB && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
+
 config FB_SBUS
 	bool "SBUS and UPA framebuffers"
 	depends on FB && (SPARC32 || SPARC64)
diff -puN drivers/video/Makefile~mips-amd-alchemy-update drivers/video/Makefile
--- 25/drivers/video/Makefile~mips-amd-alchemy-update	2005-01-29 11:26:00.225713608 -0800
+++ 25-akpm/drivers/video/Makefile	2005-01-29 11:26:00.291703576 -0800
@@ -96,6 +96,7 @@ obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.o
 obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_PXA)		  += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o
 obj-$(CONFIG_FB_W100)		   += w100fb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o
+obj-$(CONFIG_FB_AU1100)		  += au1100fb.o fbgen.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
diff -puN include/asm-mips/mach-au1x00/au1000.h~mips-amd-alchemy-update include/asm-mips/mach-au1x00/au1000.h
--- 25/include/asm-mips/mach-au1x00/au1000.h~mips-amd-alchemy-update	2005-01-29 11:26:00.227713304 -0800
+++ 25-akpm/include/asm-mips/mach-au1x00/au1000.h	2005-01-29 11:26:00.324698560 -0800
@@ -35,6 +35,8 @@
 #ifndef _AU1000_H_
 #define _AU1000_H_
 
+#include <linux/config.h>
+
 #ifndef _LANGUAGE_ASSEMBLY
 
 #include <linux/delay.h>
diff -puN include/asm-mips/mach-au1x00/au1xxx_dbdma.h~mips-amd-alchemy-update include/asm-mips/mach-au1x00/au1xxx_dbdma.h
--- 25/include/asm-mips/mach-au1x00/au1xxx_dbdma.h~mips-amd-alchemy-update	2005-01-29 11:26:00.228713152 -0800
+++ 25-akpm/include/asm-mips/mach-au1x00/au1xxx_dbdma.h	2005-01-29 11:26:00.321699016 -0800
@@ -34,6 +34,8 @@
 #ifndef _AU1000_DBDMA_H_
 #define _AU1000_DBDMA_H_
 
+#include <linux/config.h>
+
 #ifndef _LANGUAGE_ASSEMBLY
 
 /* The DMA base addresses.
diff -puN include/asm-mips/mach-au1x00/au1xxx_psc.h~mips-amd-alchemy-update include/asm-mips/mach-au1x00/au1xxx_psc.h
--- 25/include/asm-mips/mach-au1x00/au1xxx_psc.h~mips-amd-alchemy-update	2005-01-29 11:26:00.230712848 -0800
+++ 25-akpm/include/asm-mips/mach-au1x00/au1xxx_psc.h	2005-01-29 11:26:00.323698712 -0800
@@ -33,27 +33,14 @@
 #ifndef _AU1000_PSC_H_
 #define _AU1000_PSC_H_
 
-/* The PSC base addresses.
-*/
-#define PSC_BASE0		0xb1a00000
-#define PSC_BASE1		0xb1b00000
-#define PSC_BASE2		0xb0a00000
-#define PSC_BASE3		0xb0d00000
-
-/* These should be defined in a board specific file!
-*/
-#ifdef CONFIG_MIPS_PB1550
-#define SPI_PSC_BASE		PSC_BASE0
-#define AC97_PSC_BASE		PSC_BASE1
-#define SMBUS_PSC_BASE		PSC_BASE2
-#endif
-#ifdef CONFIG_MIPS_DB1550
-#define SPI_PSC_BASE		PSC_BASE0
-#define AC97_PSC_BASE		PSC_BASE1
-#define SMBUS_PSC_BASE		PSC_BASE2
+/* The PSC base addresses.  */
+#ifdef CONFIG_SOC_AU1550
+#define PSC0_BASE_ADDR		0xb1a00000
+#define PSC1_BASE_ADDR		0xb1b00000
+#define PSC2_BASE_ADDR		0xb0a00000
+#define PSC3_BASE_ADDR		0xb0d00000
 #endif
 
-
 /* The PSC select and control registers are common to
  * all protocols.
  */
@@ -208,4 +195,328 @@
 #define PSC_AC97RST_SNC		(1 << 0)
 
 
+/* PSC in I2S Mode.
+*/
+typedef struct	psc_i2s {
+	u32	psc_sel;
+	u32	psc_ctrl;
+	u32	psc_i2scfg;
+	u32	psc_i2smsk;
+	u32	psc_i2spcr;
+	u32	psc_i2sstat;
+	u32	psc_i2sevent;
+	u32	psc_i2stxrx;
+	u32	psc_i2sudf;
+} psc_i2s_t;
+
+/* I2S Config Register.
+*/
+#define PSC_I2SCFG_RT_MASK	(3 << 30)
+#define PSC_I2SCFG_RT_FIFO1	(0 << 30)
+#define PSC_I2SCFG_RT_FIFO2	(1 << 30)
+#define PSC_I2SCFG_RT_FIFO4	(2 << 30)
+#define PSC_I2SCFG_RT_FIFO8	(3 << 30)
+
+#define PSC_I2SCFG_TT_MASK	(3 << 28)
+#define PSC_I2SCFG_TT_FIFO1	(0 << 28)
+#define PSC_I2SCFG_TT_FIFO2	(1 << 28)
+#define PSC_I2SCFG_TT_FIFO4	(2 << 28)
+#define PSC_I2SCFG_TT_FIFO8	(3 << 28)
+
+#define PSC_I2SCFG_DD_DISABLE	(1 << 27)
+#define PSC_I2SCFG_DE_ENABLE	(1 << 26)
+#define PSC_I2SCFG_SET_WS(x)	(((((x) / 2) - 1) & 0x7f) << 16)
+#define PSC_I2SCFG_WI		(1 << 15)
+
+#define PSC_I2SCFG_DIV_MASK	(3 << 13)
+#define PSC_I2SCFG_DIV2		(0 << 13)
+#define PSC_I2SCFG_DIV4		(1 << 13)
+#define PSC_I2SCFG_DIV8		(2 << 13)
+#define PSC_I2SCFG_DIV16	(3 << 13)
+
+#define PSC_I2SCFG_BI		(1 << 12)
+#define PSC_I2SCFG_BUF		(1 << 11)
+#define PSC_I2SCFG_MLJ		(1 << 10)
+#define PSC_I2SCFG_XM		(1 << 9)
+
+/* The word length equation is simply LEN+1.
+ */
+#define PSC_I2SCFG_SET_LEN(x)	((((x) - 1) & 0x1f) << 4)
+#define PSC_I2SCFG_GET_LEN(x)	((((x) >> 4) & 0x1f) + 1)
+
+#define PSC_I2SCFG_LB		(1 << 2)
+#define PSC_I2SCFG_MLF		(1 << 1)
+#define PSC_I2SCFG_MS		(1 << 0)
+
+/* I2S Mask Register.
+*/
+#define PSC_I2SMSK_RR		(1 << 13)
+#define PSC_I2SMSK_RO		(1 << 12)
+#define PSC_I2SMSK_RU		(1 << 11)
+#define PSC_I2SMSK_TR		(1 << 10)
+#define PSC_I2SMSK_TO		(1 << 9)
+#define PSC_I2SMSK_TU		(1 << 8)
+#define PSC_I2SMSK_RD		(1 << 5)
+#define PSC_I2SMSK_TD		(1 << 4)
+#define PSC_I2SMSK_ALLMASK	(PSC_I2SMSK_RR | PSC_I2SMSK_RO | \
+				 PSC_I2SMSK_RU | PSC_I2SMSK_TR | \
+				 PSC_I2SMSK_TO | PSC_I2SMSK_TU | \
+				 PSC_I2SMSK_RD | PSC_I2SMSK_TD)
+
+/* I2S Protocol Control Register.
+*/
+#define PSC_I2SPCR_RC		(1 << 6)
+#define PSC_I2SPCR_RP		(1 << 5)
+#define PSC_I2SPCR_RS		(1 << 4)
+#define PSC_I2SPCR_TC		(1 << 2)
+#define PSC_I2SPCR_TP		(1 << 1)
+#define PSC_I2SPCR_TS		(1 << 0)
+
+/* I2S Status register (read only).
+*/
+#define PSC_I2SSTAT_RF		(1 << 13)
+#define PSC_I2SSTAT_RE		(1 << 12)
+#define PSC_I2SSTAT_RR		(1 << 11)
+#define PSC_I2SSTAT_TF		(1 << 10)
+#define PSC_I2SSTAT_TE		(1 << 9)
+#define PSC_I2SSTAT_TR		(1 << 8)
+#define PSC_I2SSTAT_RB		(1 << 5)
+#define PSC_I2SSTAT_TB		(1 << 4)
+#define PSC_I2SSTAT_DI		(1 << 2)
+#define PSC_I2SSTAT_DR		(1 << 1)
+#define PSC_I2SSTAT_SR		(1 << 0)
+
+/* I2S Event Register.
+*/
+#define PSC_I2SEVNT_RR		(1 << 13)
+#define PSC_I2SEVNT_RO		(1 << 12)
+#define PSC_I2SEVNT_RU		(1 << 11)
+#define PSC_I2SEVNT_TR		(1 << 10)
+#define PSC_I2SEVNT_TO		(1 << 9)
+#define PSC_I2SEVNT_TU		(1 << 8)
+#define PSC_I2SEVNT_RD		(1 << 5)
+#define PSC_I2SEVNT_TD		(1 << 4)
+
+/* PSC in SPI Mode.
+*/
+typedef struct	psc_spi {
+	u32	psc_sel;
+	u32	psc_ctrl;
+	u32	psc_spicfg;
+	u32	psc_spimsk;
+	u32	psc_spipcr;
+	u32	psc_spistat;
+	u32	psc_spievent;
+	u32	psc_spitxrx;
+} psc_spi_t;
+
+/* SPI Config Register.
+*/
+#define PSC_SPICFG_RT_MASK	(3 << 30)
+#define PSC_SPICFG_RT_FIFO1	(0 << 30)
+#define PSC_SPICFG_RT_FIFO2	(1 << 30)
+#define PSC_SPICFG_RT_FIFO4	(2 << 30)
+#define PSC_SPICFG_RT_FIFO8	(3 << 30)
+
+#define PSC_SPICFG_TT_MASK	(3 << 28)
+#define PSC_SPICFG_TT_FIFO1	(0 << 28)
+#define PSC_SPICFG_TT_FIFO2	(1 << 28)
+#define PSC_SPICFG_TT_FIFO4	(2 << 28)
+#define PSC_SPICFG_TT_FIFO8	(3 << 28)
+
+#define PSC_SPICFG_DD_DISABLE	(1 << 27)
+#define PSC_SPICFG_DE_ENABLE	(1 << 26)
+#define PSC_SPICFG_CLR_BAUD(x)	((x) & ~((0x3f) << 15))
+#define PSC_SPICFG_SET_BAUD(x)	(((x) & 0x3f) << 15)
+
+#define PSC_SPICFG_SET_DIV(x)	(((x) & 0x03) << 13)
+#define PSC_SPICFG_DIV2		0
+#define PSC_SPICFG_DIV4		1
+#define PSC_SPICFG_DIV8		2
+#define PSC_SPICFG_DIV16	3
+
+#define PSC_SPICFG_BI		(1 << 12)
+#define PSC_SPICFG_PSE		(1 << 11)
+#define PSC_SPICFG_CGE		(1 << 10)
+#define PSC_SPICFG_CDE		(1 << 9)
+
+#define PSC_SPICFG_CLR_LEN(x)	((x) & ~((0x1f) << 4))
+#define PSC_SPICFG_SET_LEN(x)	(((x-1) & 0x1f) << 4)
+
+#define PSC_SPICFG_LB		(1 << 3)
+#define PSC_SPICFG_MLF		(1 << 1)
+#define PSC_SPICFG_MO		(1 << 0)
+
+/* SPI Mask Register.
+*/
+#define PSC_SPIMSK_MM		(1 << 16)
+#define PSC_SPIMSK_RR		(1 << 13)
+#define PSC_SPIMSK_RO		(1 << 12)
+#define PSC_SPIMSK_RU		(1 << 11)
+#define PSC_SPIMSK_TR		(1 << 10)
+#define PSC_SPIMSK_TO		(1 << 9)
+#define PSC_SPIMSK_TU		(1 << 8)
+#define PSC_SPIMSK_SD		(1 << 5)
+#define PSC_SPIMSK_MD		(1 << 4)
+#define PSC_SPIMSK_ALLMASK	(PSC_SPIMSK_MM | PSC_SPIMSK_RR | \
+				 PSC_SPIMSK_RO | PSC_SPIMSK_TO | \
+				 PSC_SPIMSK_TU | PSC_SPIMSK_SD | \
+				 PSC_SPIMSK_MD)
+
+/* SPI Protocol Control Register.
+*/
+#define PSC_SPIPCR_RC		(1 << 6)
+#define PSC_SPIPCR_SP		(1 << 5)
+#define PSC_SPIPCR_SS		(1 << 4)
+#define PSC_SPIPCR_TC		(1 << 2)
+#define PSC_SPIPCR_MS		(1 << 0)
+
+/* SPI Status register (read only).
+*/
+#define PSC_SPISTAT_RF		(1 << 13)
+#define PSC_SPISTAT_RE		(1 << 12)
+#define PSC_SPISTAT_RR		(1 << 11)
+#define PSC_SPISTAT_TF		(1 << 10)
+#define PSC_SPISTAT_TE		(1 << 9)
+#define PSC_SPISTAT_TR		(1 << 8)
+#define PSC_SPISTAT_SB		(1 << 5)
+#define PSC_SPISTAT_MB		(1 << 4)
+#define PSC_SPISTAT_DI		(1 << 2)
+#define PSC_SPISTAT_DR		(1 << 1)
+#define PSC_SPISTAT_SR		(1 << 0)
+
+/* SPI Event Register.
+*/
+#define PSC_SPIEVNT_MM		(1 << 16)
+#define PSC_SPIEVNT_RR		(1 << 13)
+#define PSC_SPIEVNT_RO		(1 << 12)
+#define PSC_SPIEVNT_RU		(1 << 11)
+#define PSC_SPIEVNT_TR		(1 << 10)
+#define PSC_SPIEVNT_TO		(1 << 9)
+#define PSC_SPIEVNT_TU		(1 << 8)
+#define PSC_SPIEVNT_SD		(1 << 5)
+#define PSC_SPIEVNT_MD		(1 << 4)
+
+/* Transmit register control.
+*/
+#define PSC_SPITXRX_LC		(1 << 29)
+#define PSC_SPITXRX_SR		(1 << 28)
+
+/* PSC in SMBus (I2C) Mode.
+*/
+typedef struct	psc_smb {
+	u32	psc_sel;
+	u32	psc_ctrl;
+	u32	psc_smbcfg;
+	u32	psc_smbmsk;
+	u32	psc_smbpcr;
+	u32	psc_smbstat;
+	u32	psc_smbevnt;
+	u32	psc_smbtxrx;
+	u32	psc_smbtmr;
+} psc_smb_t;
+
+/* SMBus Config Register.
+*/
+#define PSC_SMBCFG_RT_MASK	(3 << 30)
+#define PSC_SMBCFG_RT_FIFO1	(0 << 30)
+#define PSC_SMBCFG_RT_FIFO2	(1 << 30)
+#define PSC_SMBCFG_RT_FIFO4	(2 << 30)
+#define PSC_SMBCFG_RT_FIFO8	(3 << 30)
+
+#define PSC_SMBCFG_TT_MASK	(3 << 28)
+#define PSC_SMBCFG_TT_FIFO1	(0 << 28)
+#define PSC_SMBCFG_TT_FIFO2	(1 << 28)
+#define PSC_SMBCFG_TT_FIFO4	(2 << 28)
+#define PSC_SMBCFG_TT_FIFO8	(3 << 28)
+
+#define PSC_SMBCFG_DD_DISABLE	(1 << 27)
+#define PSC_SMBCFG_DE_ENABLE	(1 << 26)
+
+#define PSC_SMBCFG_SET_DIV(x)	(((x) & 0x03) << 13)
+#define PSC_SMBCFG_DIV2		0
+#define PSC_SMBCFG_DIV4		1
+#define PSC_SMBCFG_DIV8		2
+#define PSC_SMBCFG_DIV16	3
+
+#define PSC_SMBCFG_GCE		(1 << 9)
+#define PSC_SMBCFG_SFM		(1 << 8)
+
+#define PSC_SMBCFG_SET_SLV(x)	(((x) & 0x7f) << 1)
+
+/* SMBus Mask Register.
+*/
+#define PSC_SMBMSK_DN		(1 << 30)
+#define PSC_SMBMSK_AN		(1 << 29)
+#define PSC_SMBMSK_AL		(1 << 28)
+#define PSC_SMBMSK_RR		(1 << 13)
+#define PSC_SMBMSK_RO		(1 << 12)
+#define PSC_SMBMSK_RU		(1 << 11)
+#define PSC_SMBMSK_TR		(1 << 10)
+#define PSC_SMBMSK_TO		(1 << 9)
+#define PSC_SMBMSK_TU		(1 << 8)
+#define PSC_SMBMSK_SD		(1 << 5)
+#define PSC_SMBMSK_MD		(1 << 4)
+#define PSC_SMBMSK_ALLMASK	(PSC_SMBMSK_DN | PSC_SMBMSK_AN | \
+				 PSC_SMBMSK_AL | PSC_SMBMSK_RR | \
+				 PSC_SMBMSK_RO | PSC_SMBMSK_TO | \
+				 PSC_SMBMSK_TU | PSC_SMBMSK_SD | \
+				 PSC_SMBMSK_MD)
+
+/* SMBus Protocol Control Register.
+*/
+#define PSC_SMBPCR_DC		(1 << 2)
+#define PSC_SMBPCR_MS		(1 << 0)
+
+/* SMBus Status register (read only).
+*/
+#define PSC_SMBSTAT_BB		(1 << 28)
+#define PSC_SMBSTAT_RF		(1 << 13)
+#define PSC_SMBSTAT_RE		(1 << 12)
+#define PSC_SMBSTAT_RR		(1 << 11)
+#define PSC_SMBSTAT_TF		(1 << 10)
+#define PSC_SMBSTAT_TE		(1 << 9)
+#define PSC_SMBSTAT_TR		(1 << 8)
+#define PSC_SMBSTAT_SB		(1 << 5)
+#define PSC_SMBSTAT_MB		(1 << 4)
+#define PSC_SMBSTAT_DI		(1 << 2)
+#define PSC_SMBSTAT_DR		(1 << 1)
+#define PSC_SMBSTAT_SR		(1 << 0)
+
+/* SMBus Event Register.
+*/
+#define PSC_SMBEVNT_DN		(1 << 30)
+#define PSC_SMBEVNT_AN		(1 << 29)
+#define PSC_SMBEVNT_AL		(1 << 28)
+#define PSC_SMBEVNT_RR		(1 << 13)
+#define PSC_SMBEVNT_RO		(1 << 12)
+#define PSC_SMBEVNT_RU		(1 << 11)
+#define PSC_SMBEVNT_TR		(1 << 10)
+#define PSC_SMBEVNT_TO		(1 << 9)
+#define PSC_SMBEVNT_TU		(1 << 8)
+#define PSC_SMBEVNT_SD		(1 << 5)
+#define PSC_SMBEVNT_MD		(1 << 4)
+#define PSC_SMBEVNT_ALLCLR	(PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | \
+				 PSC_SMBEVNT_AL | PSC_SMBEVNT_RR | \
+				 PSC_SMBEVNT_RO | PSC_SMBEVNT_TO | \
+				 PSC_SMBEVNT_TU | PSC_SMBEVNT_SD | \
+				 PSC_SMBEVNT_MD)
+
+/* Transmit register control.
+*/
+#define PSC_SMBTXRX_RSR		(1 << 30)
+#define PSC_SMBTXRX_STP		(1 << 29)
+#define PSC_SMBTXRX_DATAMASK	(0xff)
+
+/* SMBus protocol timers register.
+*/
+#define PSC_SMBTMR_SET_TH(x)	(((x) & 0x3) << 30)
+#define PSC_SMBTMR_SET_PS(x)	(((x) & 0x1f) << 25)
+#define PSC_SMBTMR_SET_PU(x)	(((x) & 0x1f) << 20)
+#define PSC_SMBTMR_SET_SH(x)	(((x) & 0x1f) << 15)
+#define PSC_SMBTMR_SET_SU(x)	(((x) & 0x1f) << 10)
+#define PSC_SMBTMR_SET_CL(x)	(((x) & 0x1f) << 5)
+#define PSC_SMBTMR_SET_CH(x)	(((x) & 0x1f) << 0)
+
+
 #endif /* _AU1000_PSC_H_ */
diff -puN include/asm-mips/mach-db1x00/db1x00.h~mips-amd-alchemy-update include/asm-mips/mach-db1x00/db1x00.h
--- 25/include/asm-mips/mach-db1x00/db1x00.h~mips-amd-alchemy-update	2005-01-29 11:26:00.231712696 -0800
+++ 25-akpm/include/asm-mips/mach-db1x00/db1x00.h	2005-01-29 11:26:00.324698560 -0800
@@ -4,6 +4,7 @@
  * Copyright 2001 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
  *         	ppopov@mvista.com or source@mvista.com
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
  *
  * ########################################################################
  *
@@ -27,6 +28,8 @@
 #ifndef __ASM_DB1X00_H
 #define __ASM_DB1X00_H
 
+#include <linux/config.h>
+
 #ifdef CONFIG_MIPS_DB1550
 #define BCSR_KSEG1_ADDR 0xAF000000
 #define NAND_PHYS_ADDR  0x20000000
diff -puN include/asm-mips/mach-pb1x00/pb1550.h~mips-amd-alchemy-update include/asm-mips/mach-pb1x00/pb1550.h
--- 25/include/asm-mips/mach-pb1x00/pb1550.h~mips-amd-alchemy-update	2005-01-29 11:26:00.233712392 -0800
+++ 25-akpm/include/asm-mips/mach-pb1x00/pb1550.h	2005-01-29 11:26:00.325698408 -0800
@@ -3,6 +3,7 @@
  * Board Registers defines.
  *
  * Copyright 2004 Embedded Edge LLC.
+ * Copyright 2005 Ralf Baechle (ralf@linux-mips.org)
  *
  * ########################################################################
  *
@@ -26,8 +27,19 @@
 #ifndef __ASM_PB1550_H
 #define __ASM_PB1550_H
 
+#include <linux/config.h>
 #include <linux/types.h>
 
+#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
+#define DBDMA_AC97_RX_CHAN DSCR_CMD0_PSC1_RX
+#define DBDMA_I2S_TX_CHAN DSCR_CMD0_PSC3_TX
+#define DBDMA_I2S_RX_CHAN DSCR_CMD0_PSC3_RX
+
+#define SPI_PSC_BASE        PSC0_BASE_ADDR
+#define AC97_PSC_BASE       PSC1_BASE_ADDR
+#define SMBUS_PSC_BASE      PSC2_BASE_ADDR
+#define I2S_PSC_BASE        PSC3_BASE_ADDR
+
 #define BCSR_PHYS_ADDR 0xAF000000
 
 typedef volatile struct
diff -puN include/linux/ac97_codec.h~mips-amd-alchemy-update include/linux/ac97_codec.h
--- 25/include/linux/ac97_codec.h~mips-amd-alchemy-update	2005-01-29 11:26:00.234712240 -0800
+++ 25-akpm/include/linux/ac97_codec.h	2005-01-29 11:26:00.313700232 -0800
@@ -176,6 +176,39 @@
 #define AC97_EXTSTAT_PRK          0x2000
 #define AC97_EXTSTAT_PRL          0x4000
 
+/* extended audio ID register bit defines */
+#define AC97_EXTID_VRA            0x0001
+#define AC97_EXTID_DRA            0x0002
+#define AC97_EXTID_SPDIF          0x0004
+#define AC97_EXTID_VRM            0x0008
+#define AC97_EXTID_DSA0           0x0010
+#define AC97_EXTID_DSA1           0x0020
+#define AC97_EXTID_CDAC           0x0040
+#define AC97_EXTID_SDAC           0x0080
+#define AC97_EXTID_LDAC           0x0100
+#define AC97_EXTID_AMAP           0x0200
+#define AC97_EXTID_REV0           0x0400
+#define AC97_EXTID_REV1           0x0800
+#define AC97_EXTID_ID0            0x4000
+#define AC97_EXTID_ID1            0x8000
+
+/* extended status register bit defines */
+#define AC97_EXTSTAT_VRA          0x0001
+#define AC97_EXTSTAT_DRA          0x0002
+#define AC97_EXTSTAT_SPDIF        0x0004
+#define AC97_EXTSTAT_VRM          0x0008
+#define AC97_EXTSTAT_SPSA0        0x0010
+#define AC97_EXTSTAT_SPSA1        0x0020
+#define AC97_EXTSTAT_CDAC         0x0040
+#define AC97_EXTSTAT_SDAC         0x0080
+#define AC97_EXTSTAT_LDAC         0x0100
+#define AC97_EXTSTAT_MADC         0x0200
+#define AC97_EXTSTAT_SPCV         0x0400
+#define AC97_EXTSTAT_PRI          0x0800
+#define AC97_EXTSTAT_PRJ          0x1000
+#define AC97_EXTSTAT_PRK          0x2000
+#define AC97_EXTSTAT_PRL          0x4000
+
 /* useful power states */
 #define AC97_PWR_D0               0x0000      /* everything on */
 #define AC97_PWR_D1              AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4
diff -puN sound/Kconfig~mips-amd-alchemy-update sound/Kconfig
--- 25/sound/Kconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.235712088 -0800
+++ 25-akpm/sound/Kconfig	2005-01-29 11:26:00.297702664 -0800
@@ -55,6 +55,8 @@ source "sound/ppc/Kconfig"
 
 source "sound/arm/Kconfig"
 
+source "sound/mips/Kconfig"
+
 # the following will depenend on the order of config.
 # here assuming USB is defined before ALSA
 source "sound/usb/Kconfig"
diff -puN sound/Makefile~mips-amd-alchemy-update sound/Makefile
--- 25/sound/Makefile~mips-amd-alchemy-update	2005-01-29 11:26:00.236711936 -0800
+++ 25-akpm/sound/Makefile	2005-01-29 11:26:00.297702664 -0800
@@ -4,7 +4,7 @@
 obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
 
 ifeq ($(CONFIG_SND),y)
   obj-y += last.o
diff -puN /dev/null sound/mips/au1x00.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/sound/mips/au1x00.c	2005-01-29 11:26:00.296702816 -0800
@@ -0,0 +1,686 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *  Driver for AMD Au1000 MIPS Processor, AC'97 Sound Port
+ *
+ * Copyright 2004 Cooper Street Innovations Inc.
+ * Author: Charles Eidsness	<charles@cooper-street.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ * History:
+ *
+ * 2004-09-09 Charles Eidsness	-- Original verion -- based on
+ * 				  sa11xx-uda1341.c ALSA driver and the
+ *				  au1000.c OSS driver.
+ * 2004-09-09 Matt Porter	-- Added support for ALSA 1.0.6
+ *
+ */
+
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1000_dma.h>
+
+MODULE_AUTHOR("Charles Eidsness <charles@cooper-street.com>");
+MODULE_DESCRIPTION("Au1000 AC'97 ALSA Driver");
+MODULE_LICENSE("GPL");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+MODULE_SUPPORTED_DEVICE("{{AMD,Au1000 AC'97}}");
+#else
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{AMD,Au1000 AC'97}}");
+#endif
+
+#define chip_t au1000_t
+
+#define PLAYBACK 0
+#define CAPTURE 1
+#define AC97_SLOT_3 0x01
+#define AC97_SLOT_4 0x02
+#define AC97_SLOT_6 0x08
+#define AC97_CMD_IRQ 31
+#define READ 0
+#define WRITE 1
+#define READ_WAIT 2
+#define RW_DONE 3
+
+DECLARE_WAIT_QUEUE_HEAD(ac97_command_wq);
+
+typedef struct au1000_period au1000_period_t;
+struct au1000_period
+{
+	u32 start;
+	u32 relative_end;	/*realtive to start of buffer*/
+	au1000_period_t * next;
+};
+
+/*Au1000 AC97 Port Control Reisters*/
+typedef struct au1000_ac97_reg au1000_ac97_reg_t;
+struct au1000_ac97_reg {
+	u32 volatile config;
+	u32 volatile status;
+	u32 volatile data;
+	u32 volatile cmd;
+	u32 volatile cntrl;
+};
+
+typedef struct audio_stream audio_stream_t;
+struct audio_stream {
+	snd_pcm_substream_t * substream;
+	int dma;
+	spinlock_t dma_lock;
+	au1000_period_t * buffer;
+	unsigned long period_size;
+};
+
+typedef struct snd_card_au1000 {
+	snd_card_t *card;
+	au1000_ac97_reg_t volatile *ac97_ioport;
+
+	struct resource *ac97_res_port;
+	spinlock_t ac97_lock;
+	ac97_t *ac97;
+
+	snd_pcm_t *pcm;
+	audio_stream_t *stream[2];	/* playback & capture */
+} au1000_t;
+
+static au1000_t *au1000 = NULL;
+
+/*--------------------------- Local Functions --------------------------------*/
+static void
+au1000_set_ac97_xmit_slots(long xmit_slots)
+{
+	u32 volatile ac97_config;
+
+	spin_lock(&au1000->ac97_lock);
+	ac97_config = au1000->ac97_ioport->config;
+	ac97_config = ac97_config & ~AC97C_XMIT_SLOTS_MASK;
+	ac97_config |= (xmit_slots << AC97C_XMIT_SLOTS_BIT);
+	au1000->ac97_ioport->config = ac97_config;
+	spin_unlock(&au1000->ac97_lock);
+}
+
+static void
+au1000_set_ac97_recv_slots(long recv_slots)
+{
+	u32 volatile ac97_config;
+
+	spin_lock(&au1000->ac97_lock);
+	ac97_config = au1000->ac97_ioport->config;
+	ac97_config = ac97_config & ~AC97C_RECV_SLOTS_MASK;
+	ac97_config |= (recv_slots << AC97C_RECV_SLOTS_BIT);
+	au1000->ac97_ioport->config = ac97_config;
+	spin_unlock(&au1000->ac97_lock);
+}
+
+
+static void
+au1000_dma_stop(audio_stream_t *stream)
+{
+	unsigned long   flags;
+	au1000_period_t * pointer;
+	au1000_period_t * pointer_next;
+
+	if (stream->buffer != NULL) {
+		spin_lock_irqsave(&stream->dma_lock, flags);
+		disable_dma(stream->dma);
+		spin_unlock_irqrestore(&stream->dma_lock, flags);
+
+		pointer = stream->buffer;
+		pointer_next = stream->buffer->next;
+
+		do {
+			kfree(pointer);
+			pointer = pointer_next;
+			pointer_next = pointer->next;
+		} while (pointer != stream->buffer);
+
+		stream->buffer = NULL;
+	}
+}
+
+static void
+au1000_dma_start(audio_stream_t *stream)
+{
+	snd_pcm_substream_t *substream = stream->substream;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	unsigned long flags, dma_start;
+	int i;
+	au1000_period_t * pointer;
+
+	if (stream->buffer == NULL) {
+		dma_start = virt_to_phys(runtime->dma_area);
+
+		stream->period_size = frames_to_bytes(runtime,
+			runtime->period_size);
+		stream->buffer = kmalloc(sizeof(au1000_period_t), GFP_KERNEL);
+		pointer = stream->buffer;
+		for (i = 0 ; i < runtime->periods ; i++) {
+			pointer->start = (u32)(dma_start +
+				(i * stream->period_size));
+			pointer->relative_end = (u32)
+				(((i+1) * stream->period_size) - 0x1);
+			if ( i < runtime->periods - 1) {
+				pointer->next = kmalloc(sizeof(au1000_period_t)
+					, GFP_KERNEL);
+				pointer = pointer->next;
+			}
+		}
+		pointer->next = stream->buffer;
+
+		spin_lock_irqsave(&stream->dma_lock, flags);
+		init_dma(stream->dma);
+		if (get_dma_active_buffer(stream->dma) == 0) {
+			clear_dma_done0(stream->dma);
+			set_dma_addr0(stream->dma, stream->buffer->start);
+			set_dma_count0(stream->dma, stream->period_size >> 1);
+			set_dma_addr1(stream->dma, stream->buffer->next->start);
+			set_dma_count1(stream->dma, stream->period_size >> 1);
+		} else {
+			clear_dma_done1(stream->dma);
+			set_dma_addr1(stream->dma, stream->buffer->start);
+			set_dma_count1(stream->dma, stream->period_size >> 1);
+			set_dma_addr0(stream->dma, stream->buffer->next->start);
+			set_dma_count0(stream->dma, stream->period_size >> 1);
+		}
+		enable_dma_buffers(stream->dma);
+		start_dma(stream->dma);
+		spin_unlock_irqrestore(&stream->dma_lock, flags);
+	}
+}
+
+static irqreturn_t
+au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	audio_stream_t *stream = (audio_stream_t *) dev_id;
+	snd_pcm_substream_t *substream = stream->substream;
+
+	spin_lock(&stream->dma_lock);
+	switch (get_dma_buffer_done(stream->dma)) {
+	case DMA_D0:
+		stream->buffer = stream->buffer->next;
+		clear_dma_done0(stream->dma);
+		set_dma_addr0(stream->dma, stream->buffer->next->start);
+		set_dma_count0(stream->dma, stream->period_size >> 1);
+		enable_dma_buffer0(stream->dma);
+		break;
+	case DMA_D1:
+		stream->buffer = stream->buffer->next;
+		clear_dma_done1(stream->dma);
+		set_dma_addr1(stream->dma, stream->buffer->next->start);
+		set_dma_count1(stream->dma, stream->period_size >> 1);
+		enable_dma_buffer1(stream->dma);
+		break;
+	case (DMA_D0 | DMA_D1):
+		spin_unlock(&stream->dma_lock);
+		printk(KERN_ERR "DMA %d missed interrupt.\n",stream->dma);
+		au1000_dma_stop(stream);
+		au1000_dma_start(stream);
+		spin_lock(&stream->dma_lock);
+		break;
+	case (~DMA_D0 & ~DMA_D1):
+		printk(KERN_ERR "DMA %d empty irq.\n",stream->dma);
+	}
+	spin_unlock(&stream->dma_lock);
+	snd_pcm_period_elapsed(substream);
+	return IRQ_HANDLED;
+}
+
+/*-------------------------- PCM Audio Streams -------------------------------*/
+
+static unsigned int rates[] = {8000, 11025, 16000, 22050};
+static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+	.count	=  sizeof(rates) / sizeof(rates[0]),
+	.list	= rates,
+	.mask	= 0,
+};
+
+static snd_pcm_hardware_t snd_au1000 =
+{
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED | \
+				SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050),
+	.rate_min		= 8000,
+	.rate_max		= 22050,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 128*1024,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 16*1024,
+	.periods_min		= 8,
+	.periods_max		= 255,
+	.fifo_size		= 16,
+};
+
+static int
+snd_au1000_playback_open(snd_pcm_substream_t * substream)
+{
+	au1000->stream[PLAYBACK]->substream = substream;
+	au1000->stream[PLAYBACK]->buffer = NULL;
+	substream->private_data = au1000->stream[PLAYBACK];
+	substream->runtime->hw = snd_au1000;
+	return (snd_pcm_hw_constraint_list(substream->runtime, 0,
+		SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
+}
+
+static int
+snd_au1000_capture_open(snd_pcm_substream_t * substream)
+{
+	au1000->stream[CAPTURE]->substream = substream;
+	au1000->stream[CAPTURE]->buffer = NULL;
+	substream->private_data = au1000->stream[CAPTURE];
+	substream->runtime->hw = snd_au1000;
+	return (snd_pcm_hw_constraint_list(substream->runtime, 0,
+		SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
+
+}
+
+static int
+snd_au1000_playback_close(snd_pcm_substream_t * substream)
+{
+	au1000->stream[PLAYBACK]->substream = NULL;
+	return 0;
+}
+
+static int
+snd_au1000_capture_close(snd_pcm_substream_t * substream)
+{
+	au1000->stream[CAPTURE]->substream = NULL;
+	return 0;
+}
+
+static int
+snd_au1000_hw_params(snd_pcm_substream_t * substream,
+					snd_pcm_hw_params_t * hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+static int
+snd_au1000_hw_free(snd_pcm_substream_t * substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int
+snd_au1000_playback_prepare(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	if (runtime->channels == 1 )
+		au1000_set_ac97_xmit_slots(AC97_SLOT_4);
+	else
+		au1000_set_ac97_xmit_slots(AC97_SLOT_3 | AC97_SLOT_4);
+	snd_ac97_set_rate(au1000->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
+	return 0;
+}
+
+static int
+snd_au1000_capture_prepare(snd_pcm_substream_t * substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	if (runtime->channels == 1 )
+		au1000_set_ac97_recv_slots(AC97_SLOT_4);
+	else
+		au1000_set_ac97_recv_slots(AC97_SLOT_3 | AC97_SLOT_4);
+	snd_ac97_set_rate(au1000->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
+	return 0;
+}
+
+static int
+snd_au1000_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+	audio_stream_t *stream = substream->private_data;
+	int err = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		au1000_dma_start(stream);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		au1000_dma_stop(stream);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+static snd_pcm_uframes_t
+snd_au1000_pointer(snd_pcm_substream_t * substream)
+{
+	audio_stream_t *stream = substream->private_data;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	unsigned long flags;
+	long location;
+
+	spin_lock_irqsave(&stream->dma_lock, flags);
+	location = get_dma_residue(stream->dma);
+	spin_unlock_irqrestore(&stream->dma_lock, flags);
+	location = stream->buffer->relative_end - location;
+	if (location == -1)
+		location = 0;
+	return bytes_to_frames(runtime,location);
+}
+
+static snd_pcm_ops_t snd_card_au1000_playback_ops = {
+	.open			= snd_au1000_playback_open,
+	.close			= snd_au1000_playback_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params	        = snd_au1000_hw_params,
+	.hw_free	        = snd_au1000_hw_free,
+	.prepare		= snd_au1000_playback_prepare,
+	.trigger		= snd_au1000_trigger,
+	.pointer		= snd_au1000_pointer,
+};
+
+static snd_pcm_ops_t snd_card_au1000_capture_ops = {
+	.open			= snd_au1000_capture_open,
+	.close			= snd_au1000_capture_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params	        = snd_au1000_hw_params,
+	.hw_free	        = snd_au1000_hw_free,
+	.prepare		= snd_au1000_capture_prepare,
+	.trigger		= snd_au1000_trigger,
+	.pointer		= snd_au1000_pointer,
+};
+
+static int __devinit
+snd_au1000_pcm_new(void)
+{
+	snd_pcm_t *pcm;
+	int err;
+	unsigned long flags;
+
+	if ((err = snd_pcm_new(au1000->card, "AU1000 AC97 PCM", 0, 1, 1, &pcm)) < 0)
+		return err;
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+		snd_dma_continuous_data(GFP_KERNEL), 128*1024, 128*1024);
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+		&snd_card_au1000_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+		&snd_card_au1000_capture_ops);
+
+	pcm->private_data = au1000;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "Au1000 AC97 PCM");
+
+	flags = claim_dma_lock();
+	if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX,
+			"AC97 TX", au1000_dma_interrupt, SA_INTERRUPT,
+			au1000->stream[PLAYBACK])) < 0) {
+		release_dma_lock(flags);
+		return -EBUSY;
+	}
+	if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX,
+			"AC97 RX", au1000_dma_interrupt, SA_INTERRUPT,
+			au1000->stream[CAPTURE])) < 0){
+		release_dma_lock(flags);
+		return -EBUSY;
+	}
+	/* enable DMA coherency in read/write DMA channels */
+	set_dma_mode(au1000->stream[PLAYBACK]->dma,
+		     get_dma_mode(au1000->stream[PLAYBACK]->dma) & ~DMA_NC);
+	set_dma_mode(au1000->stream[CAPTURE]->dma,
+		     get_dma_mode(au1000->stream[CAPTURE]->dma) & ~DMA_NC);
+	release_dma_lock(flags);
+	spin_lock_init(&au1000->stream[PLAYBACK]->dma_lock);
+	spin_lock_init(&au1000->stream[CAPTURE]->dma_lock);
+	au1000->pcm = pcm;
+	return 0;
+}
+
+
+/*-------------------------- AC97 CODEC Control ------------------------------*/
+
+static unsigned short
+snd_au1000_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+	u32 volatile cmd;
+	u16 volatile data;
+	int             i;
+	spin_lock(au1000->ac97_lock);
+/* would rather use the interupt than this polling but it works and I can't
+get the interupt driven case to work efficiently */
+	for (i = 0; i < 0x5000; i++)
+		if (!(au1000->ac97_ioport->status & AC97C_CP))
+			break;
+	if (i == 0x5000)
+		printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
+
+	cmd = (u32) reg & AC97C_INDEX_MASK;
+	cmd |= AC97C_READ;
+	au1000->ac97_ioport->cmd = cmd;
+
+	/* now wait for the data */
+	for (i = 0; i < 0x5000; i++)
+		if (!(au1000->ac97_ioport->status & AC97C_CP))
+			break;
+	if (i == 0x5000) {
+		printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
+		return 0;
+	}
+
+	data = au1000->ac97_ioport->cmd & 0xffff;
+	spin_unlock(au1000->ac97_lock);
+
+	return data;
+
+}
+
+
+static void
+snd_au1000_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+	u32 cmd;
+	int i;
+	spin_lock(au1000->ac97_lock);
+/* would rather use the interupt than this polling but it works and I can't
+get the interupt driven case to work efficiently */
+	for (i = 0; i < 0x5000; i++)
+		if (!(au1000->ac97_ioport->status & AC97C_CP))
+			break;
+	if (i == 0x5000)
+		printk(KERN_ERR "au1000 AC97: AC97 command write timeout\n");
+
+	cmd = (u32) reg & AC97C_INDEX_MASK;
+	cmd &= ~AC97C_READ;
+	cmd |= ((u32) val << AC97C_WD_BIT);
+	au1000->ac97_ioport->cmd = cmd;
+	spin_unlock(au1000->ac97_lock);
+}
+static void
+snd_au1000_ac97_free(ac97_t *ac97)
+{
+	au1000->ac97 = NULL;
+}
+
+static int __devinit
+snd_au1000_ac97_new(void)
+{
+	int err;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+	ac97_bus_t *pbus;
+	ac97_template_t ac97;
+ 	static ac97_bus_ops_t ops = {
+		.write = snd_au1000_ac97_write,
+		.read = snd_au1000_ac97_read,
+	};
+#else
+	ac97_bus_t bus, *pbus;
+	ac97_t ac97;
+#endif
+
+	if ((au1000->ac97_res_port = request_region(AC97C_CONFIG,
+	       		sizeof(au1000_ac97_reg_t), "Au1x00 AC97")) == NULL) {
+		snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n");
+		return -EBUSY;
+	}
+	au1000->ac97_ioport = (au1000_ac97_reg_t *) au1000->ac97_res_port->start;
+
+	spin_lock_init(&au1000->ac97_lock);
+
+	spin_lock(&au1000->ac97_lock);
+
+	/* configure pins for AC'97
+	TODO: move to board_setup.c */
+	au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
+
+	/* Initialise Au1000's AC'97 Control Block */
+	au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
+	udelay(10);
+	au1000->ac97_ioport->cntrl = AC97C_CE;
+	udelay(10);
+
+	/* Initialise External CODEC -- cold reset */
+	au1000->ac97_ioport->config = AC97C_RESET;
+	udelay(10);
+	au1000->ac97_ioport->config = 0x0;
+	mdelay(5);
+
+	spin_unlock(&au1000->ac97_lock);
+
+	/* Initialise AC97 middle-layer */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+	if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0)
+ 		return err;
+#else
+	memset(&bus, 0, sizeof(bus));
+	bus.write = snd_au1000_ac97_write;
+	bus.read = snd_au1000_ac97_read;
+	if ((err = snd_ac97_bus(au1000->card, &bus, &pbus)) < 0)
+		return err;
+#endif
+	memset(&ac97, 0, sizeof(ac97));
+	ac97.private_data = au1000;
+	ac97.private_free = snd_au1000_ac97_free;
+	if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0)
+		return err;
+	return 0;
+
+}
+
+/*------------------------------ Setup / Destroy ----------------------------*/
+
+void
+snd_au1000_free(snd_card_t *card)
+{
+
+	if (au1000->ac97_res_port) {
+		/* put internal AC97 block into reset */
+		au1000->ac97_ioport->cntrl = AC97C_RS;
+		au1000->ac97_ioport = NULL;
+		release_resource(au1000->ac97_res_port);
+		kfree_nocheck(au1000->ac97_res_port);
+	}
+
+	if (au1000->stream[PLAYBACK]->dma >= 0)
+		free_au1000_dma(au1000->stream[PLAYBACK]->dma);
+
+	if (au1000->stream[CAPTURE]->dma >= 0)
+		free_au1000_dma(au1000->stream[CAPTURE]->dma);
+
+	kfree(au1000->stream[PLAYBACK]);
+	au1000->stream[PLAYBACK] = NULL;
+	kfree(au1000->stream[CAPTURE]);
+	au1000->stream[CAPTURE] = NULL;
+	kfree(au1000);
+	au1000 = NULL;
+
+}
+
+static int __init
+au1000_init(void)
+{
+	int err;
+
+	au1000 = kmalloc(sizeof(au1000_t), GFP_KERNEL);
+	if (au1000 == NULL)
+		return -ENOMEM;
+	au1000->stream[PLAYBACK] = kmalloc(sizeof(audio_stream_t), GFP_KERNEL);
+	if (au1000->stream[PLAYBACK] == NULL)
+		return -ENOMEM;
+	au1000->stream[CAPTURE] = kmalloc(sizeof(audio_stream_t), GFP_KERNEL);
+	if (au1000->stream[CAPTURE] == NULL)
+		return -ENOMEM;
+	/* so that snd_au1000_free will work as intended */
+	au1000->stream[PLAYBACK]->dma = -1;
+	au1000->stream[CAPTURE]->dma = -1;
+ 	au1000->ac97_res_port = NULL;
+
+	au1000->card = snd_card_new(-1, "AC97", THIS_MODULE, sizeof(au1000_t));
+	if (au1000->card == NULL) {
+		snd_au1000_free(au1000->card);
+		return -ENOMEM;
+	}
+
+	au1000->card->private_data = (au1000_t *)au1000;
+	au1000->card->private_free = snd_au1000_free;
+
+	if ((err = snd_au1000_ac97_new()) < 0 ) {
+		snd_card_free(au1000->card);
+		return err;
+	}
+
+	if ((err = snd_au1000_pcm_new()) < 0) {
+		snd_card_free(au1000->card);
+		return err;
+	}
+
+	strcpy(au1000->card->driver, "AMD-Au1000-AC97");
+	strcpy(au1000->card->shortname, "Au1000-AC97");
+	sprintf(au1000->card->longname, "AMD Au1000--AC97 ALSA Driver");
+
+	if ((err = snd_card_register(au1000->card)) < 0) {
+		snd_card_free(au1000->card);
+		return err;
+	}
+
+	printk( KERN_INFO "ALSA AC97: Driver Initialized\n" );
+	return 0;
+}
+
+static void __exit au1000_exit(void)
+{
+	snd_card_free(au1000->card);
+}
+
+module_init(au1000_init);
+module_exit(au1000_exit);
+
diff -puN /dev/null sound/mips/Kconfig
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/sound/mips/Kconfig	2005-01-29 11:26:00.297702664 -0800
@@ -0,0 +1,15 @@
+# ALSA MIPS drivers
+
+menu "ALSA MIPS devices"
+	depends on SND!=n && MIPS
+
+config SND_AU1X00
+	tristate "Au1x00 AC97 Port Driver"
+	depends on (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SND
+	select SND_PCM
+	select SND_AC97_CODEC
+	help
+	  ALSA Sound driver for the Au1x00's AC97 port.
+
+endmenu
+
diff -puN /dev/null sound/mips/Makefile
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/sound/mips/Makefile	2005-01-29 11:26:00.297702664 -0800
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+#
+
+snd-au1x00-objs := au1x00.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o
diff -puN sound/oss/ac97_codec.c~mips-amd-alchemy-update sound/oss/ac97_codec.c
--- 25/sound/oss/ac97_codec.c~mips-amd-alchemy-update	2005-01-29 11:26:00.239711480 -0800
+++ 25-akpm/sound/oss/ac97_codec.c	2005-01-29 11:26:00.315699928 -0800
@@ -177,6 +177,7 @@ static const struct {
 	{0x83847608, "SigmaTel STAC9708",	&sigmatel_9708_ops},
 	{0x83847609, "SigmaTel STAC9721/23",	&sigmatel_9721_ops},
 	{0x83847644, "SigmaTel STAC9744/45",	&sigmatel_9744_ops},
+	{0x83847652, "SigmaTel STAC9752/53",	&default_ops},
 	{0x83847656, "SigmaTel STAC9756/57",	&sigmatel_9744_ops},
 	{0x83847666, "SigmaTel STAC9750T",	&sigmatel_9744_ops},
 	{0x83847684, "SigmaTel STAC9783/84?",	&null_ops},
diff -puN sound/oss/au1000.c~mips-amd-alchemy-update sound/oss/au1000.c
--- 25/sound/oss/au1000.c~mips-amd-alchemy-update	2005-01-29 11:26:00.240711328 -0800
+++ 25-akpm/sound/oss/au1000.c	2005-01-29 11:26:00.311700536 -0800
@@ -59,6 +59,7 @@
 #include <linux/slab.h>
 #include <linux/soundcard.h>
 #include <linux/init.h>
+#include <linux/page-flags.h>
 #include <linux/poll.h>
 #include <linux/pci.h>
 #include <linux/bitops.h>
@@ -66,21 +67,18 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
-#include <linux/wrapper.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/au1000.h>
-#include <asm/au1000_dma.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1000_dma.h>
 
 /* --------------------------------------------------------------------- */
 
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#define AU1000_DEBUG
+#undef AU1000_DEBUG
 #undef AU1000_VERBOSE_DEBUG
 
-#define USE_COHERENT_DMA
-
 #define AU1000_MODULE_NAME "Au1000 audio"
 #define PFX AU1000_MODULE_NAME
 
@@ -116,7 +114,7 @@ struct au1000_state {
 	struct proc_dir_entry *ac97_ps;
 #endif				/* AU1000_DEBUG */
 
-	struct ac97_codec *codec;
+	struct ac97_codec codec;
 	unsigned        codec_base_caps;// AC'97 reg 00h, "Reset Register"
 	unsigned        codec_ext_caps;	// AC'97 reg 28h, "Extended Audio ID"
 	int             no_vra;	// do not use VRA
@@ -191,35 +189,6 @@ static inline unsigned ld2(unsigned int 
 	return r;
 }
 
-
-#ifdef USE_COHERENT_DMA
-static inline void * dma_alloc(size_t size, dma_addr_t * dma_handle)
-{
-	void* ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA,
-					     get_order(size));
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_phys(ret);
-	}
-	return ret;
-}
-
-static inline void dma_free(size_t size, void* va, dma_addr_t dma_handle)
-{
-	free_pages((unsigned long)va, get_order(size));
-}
-#else
-static inline void * dma_alloc(size_t size, dma_addr_t * dma_handle)
-{
-	return pci_alloc_consistent(NULL, size, dma_handle);
-}
-
-static inline void dma_free(size_t size, void* va, dma_addr_t dma_handle)
-{
-	pci_free_consistent(NULL, size, va, dma_handle);
-}
-#endif
-
 /* --------------------------------------------------------------------- */
 
 static void au1000_delay(int msec)
@@ -356,17 +325,17 @@ static void set_adc_rate(struct au1000_s
 
 	adc->src_factor = 1;
 
-	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
+	ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
 
 	rate = rate > 48000 ? 48000 : rate;
 
 	// enable VRA
-	wrcodec(s->codec, AC97_EXTENDED_STATUS,
+	wrcodec(&s->codec, AC97_EXTENDED_STATUS,
 		ac97_extstat | AC97_EXTSTAT_VRA);
 	// now write the sample rate
-	wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
+	wrcodec(&s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
 	// read it back for actual supported rate
-	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
+	adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
 
 #ifdef AU1000_VERBOSE_DEBUG
 	dbg("%s: set to %d Hz", __FUNCTION__, adc_rate);
@@ -374,11 +343,11 @@ static void set_adc_rate(struct au1000_s
 
 	// some codec's don't allow unequal DAC and ADC rates, in which case
 	// writing one rate reg actually changes both.
-	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
+	dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
 	if (dac->num_channels > 2)
-		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
+		wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
 	if (dac->num_channels > 4)
-		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
+		wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
 
 	adc->sample_rate = adc_rate;
 	dac->sample_rate = dac_rate;
@@ -401,23 +370,23 @@ static void set_dac_rate(struct au1000_s
 
 	dac->src_factor = 1;
 
-	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
+	ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
 
 	rate = rate > 48000 ? 48000 : rate;
 
 	// enable VRA
-	wrcodec(s->codec, AC97_EXTENDED_STATUS,
+	wrcodec(&s->codec, AC97_EXTENDED_STATUS,
 		ac97_extstat | AC97_EXTSTAT_VRA);
 	// now write the sample rate
-	wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
+	wrcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
 	// I don't support different sample rates for multichannel,
 	// so make these channels the same.
 	if (dac->num_channels > 2)
-		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
+		wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
 	if (dac->num_channels > 4)
-		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
+		wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
 	// read it back for actual supported rate
-	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
+	dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
 
 #ifdef AU1000_VERBOSE_DEBUG
 	dbg("%s: set to %d Hz", __FUNCTION__, dac_rate);
@@ -425,7 +394,7 @@ static void set_dac_rate(struct au1000_s
 
 	// some codec's don't allow unequal DAC and ADC rates, in which case
 	// writing one rate reg actually changes both.
-	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
+	adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
 
 	dac->sample_rate = dac_rate;
 	adc->sample_rate = adc_rate;
@@ -603,8 +572,11 @@ extern inline void dealloc_dmabuf(struct
 		pend = virt_to_page(db->rawbuf +
 				    (PAGE_SIZE << db->buforder) - 1);
 		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			mem_map_unreserve(page);
-		dma_free(PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
+			ClearPageReserved(page);
+		dma_free_noncoherent(NULL,
+				PAGE_SIZE << db->buforder,
+				db->rawbuf,
+				db->dmaaddr);
 	}
 	db->rawbuf = db->nextIn = db->nextOut = NULL;
 	db->mapped = db->ready = 0;
@@ -622,8 +594,10 @@ static int prog_dmabuf(struct au1000_sta
 		db->ready = db->mapped = 0;
 		for (order = DMABUF_DEFAULTORDER;
 		     order >= DMABUF_MINORDER; order--)
-			if ((db->rawbuf = dma_alloc(PAGE_SIZE << order,
-						  &db->dmaaddr)))
+			if ((db->rawbuf = dma_alloc_noncoherent(NULL,
+						PAGE_SIZE << order,
+						&db->dmaaddr,
+						0)))
 				break;
 		if (!db->rawbuf)
 			return -ENOMEM;
@@ -633,7 +607,7 @@ static int prog_dmabuf(struct au1000_sta
 		pend = virt_to_page(db->rawbuf +
 				    (PAGE_SIZE << db->buforder) - 1);
 		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			mem_map_reserve(page);
+			SetPageReserved(page);
 	}
 
 	db->cnt_factor = 1;
@@ -708,7 +682,7 @@ extern inline int prog_dmabuf_dac(struct
 
 
 /* hold spinlock for the following */
-static void dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct au1000_state *s = (struct au1000_state *) dev_id;
 	struct dmabuf  *dac = &s->dma_dac;
@@ -723,7 +697,7 @@ static void dac_dma_interrupt(int irq, v
 
 	if ((buff_done = get_dma_buffer_done(dac->dmanr)) == 0) {
 		/* fastpath out, to ease interrupt sharing */
-		return;
+		return IRQ_HANDLED;
 	}
 
 	spin_lock(&s->lock);
@@ -786,10 +760,12 @@ static void dac_dma_interrupt(int irq, v
 		wake_up(&dac->wait);
 
 	spin_unlock(&s->lock);
+
+	return IRQ_HANDLED;
 }
 
 
-static void adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct au1000_state *s = (struct au1000_state *) dev_id;
 	struct dmabuf  *adc = &s->dma_adc;
@@ -804,7 +780,7 @@ static void adc_dma_interrupt(int irq, v
 
 	if ((buff_done = get_dma_buffer_done(adc->dmanr)) == 0) {
 		/* fastpath out, to ease interrupt sharing */
-		return;
+		return IRQ_HANDLED;
 	}
 
 	spin_lock(&s->lock);
@@ -816,7 +792,7 @@ static void adc_dma_interrupt(int irq, v
 			stop_adc(s);
 			adc->error++;
 			err("adc overrun");
-			return;
+			return IRQ_NONE;
 		}
 
 		adc->nextIn += adc->dma_fragsize;
@@ -853,7 +829,7 @@ static void adc_dma_interrupt(int irq, v
 			adc->error++;
 			err("adc overrun");
 			spin_unlock(&s->lock);
-			return;
+			return IRQ_NONE;
 		}
 
 		adc->nextIn += 2*adc->dma_fragsize;
@@ -873,6 +849,8 @@ static void adc_dma_interrupt(int irq, v
 		wake_up(&adc->wait);
 
 	spin_unlock(&s->lock);
+
+	return IRQ_HANDLED;
 }
 
 /* --------------------------------------------------------------------- */
@@ -904,7 +882,7 @@ static int au1000_ioctl_mixdev(struct in
 			       unsigned int cmd, unsigned long arg)
 {
 	struct au1000_state *s = (struct au1000_state *)file->private_data;
-	struct ac97_codec *codec = s->codec;
+	struct ac97_codec *codec = &s->codec;
 
 	return mixdev_ioctl(codec, cmd, arg);
 }
@@ -1338,8 +1316,7 @@ static int au1000_mmap(struct file *file
 		ret = -EINVAL;
 		goto out;
 	}
-	if (remap_pfn_range(vma->vm_start,
-			     virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
+	if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(db->rawbuf),
 			     size, vma->vm_page_prot)) {
 		ret = -EAGAIN;
 		goto out;
@@ -1500,9 +1477,9 @@ static int au1000_ioctl(struct inode *in
 			s->dma_dac.num_channels = val ? 2 : 1;
 			if (s->codec_ext_caps & AC97_EXT_DACS) {
 				// disable surround and center/lfe in AC'97
-				u16 ext_stat = rdcodec(s->codec,
+				u16 ext_stat = rdcodec(&s->codec,
 						       AC97_EXTENDED_STATUS);
-				wrcodec(s->codec, AC97_EXTENDED_STATUS,
+				wrcodec(&s->codec, AC97_EXTENDED_STATUS,
 					ext_stat | (AC97_EXTSTAT_PRI |
 						    AC97_EXTSTAT_PRJ |
 						    AC97_EXTSTAT_PRK));
@@ -1552,9 +1529,9 @@ static int au1000_ioctl(struct inode *in
 					// disable surround and center/lfe
 					// channels in AC'97
 					u16             ext_stat =
-						rdcodec(s->codec,
+						rdcodec(&s->codec,
 							AC97_EXTENDED_STATUS);
-					wrcodec(s->codec,
+					wrcodec(&s->codec,
 						AC97_EXTENDED_STATUS,
 						ext_stat | (AC97_EXTSTAT_PRI |
 							    AC97_EXTSTAT_PRJ |
@@ -1563,14 +1540,14 @@ static int au1000_ioctl(struct inode *in
 					// enable surround, center/lfe
 					// channels in AC'97
 					u16             ext_stat =
-						rdcodec(s->codec,
+						rdcodec(&s->codec,
 							AC97_EXTENDED_STATUS);
 					ext_stat &= ~AC97_EXTSTAT_PRJ;
 					if (val == 6)
 						ext_stat &=
 							~(AC97_EXTSTAT_PRI |
 							  AC97_EXTSTAT_PRK);
-					wrcodec(s->codec,
+					wrcodec(&s->codec,
 						AC97_EXTENDED_STATUS,
 						ext_stat);
 				}
@@ -1832,7 +1809,7 @@ static int au1000_ioctl(struct inode *in
 		return -EINVAL;
 	}
 
-	return mixdev_ioctl(s->codec, cmd, arg);
+	return mixdev_ioctl(&s->codec, cmd, arg);
 }
 
 
@@ -1983,7 +1960,7 @@ static int proc_au1000_dump(char *buf, c
 	len += sprintf(buf + len, "----------------------\n");
 	for (cnt = 0; cnt <= 0x7e; cnt += 2)
 		len += sprintf(buf + len, "reg %02x = %04x\n",
-			       cnt, rdcodec(s->codec, cnt));
+			       cnt, rdcodec(&s->codec, cnt));
 
 	if (fpos >= len) {
 		*start = buf;
@@ -2010,7 +1987,9 @@ static int __devinit au1000_probe(void)
 {
 	struct au1000_state *s = &au1000_state;
 	int             val;
+#ifdef AU1000_DEBUG
 	char            proc_str[80];
+#endif
 
 	memset(s, 0, sizeof(struct au1000_state));
 
@@ -2019,23 +1998,16 @@ static int __devinit au1000_probe(void)
 	init_waitqueue_head(&s->open_wait);
 	init_MUTEX(&s->open_sem);
 	spin_lock_init(&s->lock);
-	
-	s->codec = ac97_alloc_codec();
-	if(s->codec == NULL)
-	{
-		error("Out of memory");
-		return -1;
-	}
-	s->codec->private_data = s;
-	s->codec->id = 0;
-	s->codec->codec_read = rdcodec;
-	s->codec->codec_write = wrcodec;
-	s->codec->codec_wait = waitcodec;
+	s->codec.private_data = s;
+	s->codec.id = 0;
+	s->codec.codec_read = rdcodec;
+	s->codec.codec_write = wrcodec;
+	s->codec.codec_wait = waitcodec;
 
-	if (!request_region(virt_to_phys((void *) AC97C_CONFIG),
+	if (!request_mem_region(CPHYSADDR(AC97C_CONFIG),
 			    0x14, AU1000_MODULE_NAME)) {
 		err("AC'97 ports in use");
-		goto err_codec;
+		return -1;
 	}
 	// Allocate the DMA Channels
 	if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX,
@@ -2057,25 +2029,17 @@ static int __devinit au1000_probe(void)
 	     s->dma_dac.dmanr, get_dma_done_irq(s->dma_dac.dmanr),
 	     s->dma_adc.dmanr, get_dma_done_irq(s->dma_adc.dmanr));
 
-#ifdef USE_COHERENT_DMA
 	// enable DMA coherency in read/write DMA channels
 	set_dma_mode(s->dma_dac.dmanr,
 		     get_dma_mode(s->dma_dac.dmanr) & ~DMA_NC);
 	set_dma_mode(s->dma_adc.dmanr,
 		     get_dma_mode(s->dma_adc.dmanr) & ~DMA_NC);
-#else
-	// disable DMA coherency in read/write DMA channels
-	set_dma_mode(s->dma_dac.dmanr,
-		     get_dma_mode(s->dma_dac.dmanr) | DMA_NC);
-	set_dma_mode(s->dma_adc.dmanr,
-		     get_dma_mode(s->dma_adc.dmanr) | DMA_NC);
-#endif
 
 	/* register devices */
 
 	if ((s->dev_audio = register_sound_dsp(&au1000_audio_fops, -1)) < 0)
 		goto err_dev1;
-	if ((s->codec->dev_mixer =
+	if ((s->codec.dev_mixer =
 	     register_sound_mixer(&au1000_mixer_fops, -1)) < 0)
 		goto err_dev2;
 
@@ -2108,11 +2072,11 @@ static int __devinit au1000_probe(void)
 	au_writel(0, AC97C_CONFIG);
 
 	/* codec init */
-	if (!ac97_probe_codec(s->codec))
+	if (!ac97_probe_codec(&s->codec))
 		goto err_dev3;
 
-	s->codec_base_caps = rdcodec(s->codec, AC97_RESET);
-	s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID);
+	s->codec_base_caps = rdcodec(&s->codec, AC97_RESET);
+	s->codec_ext_caps = rdcodec(&s->codec, AC97_EXTENDED_ID);
 	info("AC'97 Base/Extended ID = %04x/%04x",
 	     s->codec_base_caps, s->codec_ext_caps);
 
@@ -2124,12 +2088,12 @@ static int __devinit au1000_probe(void)
 	 * ALTPCM). ac97_codec.c does not handle detection
 	 * of this channel correctly.
 	 */
-	s->codec->supported_mixers |= SOUND_MASK_ALTPCM;
+	s->codec.supported_mixers |= SOUND_MASK_ALTPCM;
 	/*
 	 * Now set AUX_OUT's default volume.
 	 */
 	val = 0x4343;
-	mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_ALTPCM,
+	mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_ALTPCM,
 		     (unsigned long) &val);
 	
 	if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
@@ -2137,8 +2101,8 @@ static int __devinit au1000_probe(void)
 		s->no_vra = 1;
 	} else if (!vra) {
 		// Boot option says disable VRA
-		u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
-		wrcodec(s->codec, AC97_EXTENDED_STATUS,
+		u16 ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
+		wrcodec(&s->codec, AC97_EXTENDED_STATUS,
 			ac97_extstat & ~AC97_EXTSTAT_VRA);
 		s->no_vra = 1;
 	}
@@ -2147,20 +2111,38 @@ static int __devinit au1000_probe(void)
 
 	/* set mic to be the recording source */
 	val = SOUND_MASK_MIC;
-	mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC,
+	mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC,
 		     (unsigned long) &val);
 
 #ifdef AU1000_DEBUG
 	sprintf(proc_str, "driver/%s/%d/ac97", AU1000_MODULE_NAME,
-		s->codec->id);
+		s->codec.id);
 	s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,
-					     ac97_read_proc, s->codec);
+					     ac97_read_proc, &s->codec);
+#endif
+
+#ifdef CONFIG_MIPS_XXS1500
+	/* deassert eapd */
+	wrcodec(&s->codec, AC97_POWER_CONTROL,
+			rdcodec(&s->codec, AC97_POWER_CONTROL) & ~0x8000);
+	/* mute a number of signals which seem to be causing problems
+	 * if not muted.
+	 */
+	wrcodec(&s->codec, AC97_PCBEEP_VOL, 0x8000);
+	wrcodec(&s->codec, AC97_PHONE_VOL, 0x8008);
+	wrcodec(&s->codec, AC97_MIC_VOL, 0x8008);
+	wrcodec(&s->codec, AC97_LINEIN_VOL, 0x8808);
+	wrcodec(&s->codec, AC97_CD_VOL, 0x8808);
+	wrcodec(&s->codec, AC97_VIDEO_VOL, 0x8808);
+	wrcodec(&s->codec, AC97_AUX_VOL, 0x8808);
+	wrcodec(&s->codec, AC97_PCMOUT_VOL, 0x0808);
+	wrcodec(&s->codec, AC97_GENERAL_PURPOSE, 0x2000);
 #endif
 
 	return 0;
 
  err_dev3:
-	unregister_sound_mixer(s->codec->dev_mixer);
+	unregister_sound_mixer(s->codec.dev_mixer);
  err_dev2:
 	unregister_sound_dsp(s->dev_audio);
  err_dev1:
@@ -2168,9 +2150,7 @@ static int __devinit au1000_probe(void)
  err_dma2:
 	free_au1000_dma(s->dma_dac.dmanr);
  err_dma1:
-	release_region(virt_to_phys((void *) AC97C_CONFIG), 0x14);
- err_codec:
- 	ac97_release_codec(s->codec);
+	release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
 	return -1;
 }
 
@@ -2187,10 +2167,9 @@ static void au1000_remove(void)
 	synchronize_irq();
 	free_au1000_dma(s->dma_adc.dmanr);
 	free_au1000_dma(s->dma_dac.dmanr);
-	release_region(virt_to_phys((void *) AC97C_CONFIG), 0x14);
+	release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
 	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->codec->dev_mixer);
-	ac97_release_codec(s->codec);
+	unregister_sound_mixer(s->codec.dev_mixer);
 }
 
 static int __init init_au1000(void)
@@ -2219,7 +2198,7 @@ static int __init au1000_setup(char *opt
 	if (!options || !*options)
 		return 0;
 
-	while (this_opt = strsep(&options, ",")) {
+	while ((this_opt = strsep(&options, ","))) {
 		if (!*this_opt)
 			continue;
 		if (!strncmp(this_opt, "vra", 3)) {
diff -puN /dev/null sound/oss/au1550_ac97.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/sound/oss/au1550_ac97.c	2005-01-29 11:26:00.307701144 -0800
@@ -0,0 +1,2119 @@
+/*
+ * au1550_ac97.c  --  Sound driver for Alchemy Au1550 MIPS Internet Edge
+ *                    Processor.
+ *
+ * Copyright 2004 Embedded Edge, LLC
+ *	dan@embeddededge.com
+ *
+ * Mostly copied from the au1000.c driver and some from the
+ * PowerMac dbdma driver.
+ * We assume the processor can do memory coherent DMA.
+ *
+ * Ported to 2.6 by Matt Porter <mporter@kernel.crashing.org>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/slab.h>
+#include <linux/soundcard.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/ac97_codec.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#undef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+/* misc stuff */
+#define POLL_COUNT   0x50000
+#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
+
+/* The number of DBDMA ring descriptors to allocate.  No sense making
+ * this too large....if you can't keep up with a few you aren't likely
+ * to be able to with lots of them, either.
+ */
+#define NUM_DBDMA_DESCRIPTORS 4
+
+#define err(format, arg...) printk(KERN_ERR format "\n" , ## arg)
+
+/* Boot options
+ * 0 = no VRA, 1 = use VRA if codec supports it
+ */
+static int      vra = 1;
+MODULE_PARM(vra, "i");
+MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
+
+static struct au1550_state {
+	/* soundcore stuff */
+	int             dev_audio;
+
+	struct ac97_codec *codec;
+	unsigned        codec_base_caps; /* AC'97 reg 00h, "Reset Register" */
+	unsigned        codec_ext_caps;  /* AC'97 reg 28h, "Extended Audio ID" */
+	int             no_vra;		/* do not use VRA */
+
+	spinlock_t      lock;
+	struct semaphore open_sem;
+	struct semaphore sem;
+	mode_t          open_mode;
+	wait_queue_head_t open_wait;
+
+	struct dmabuf {
+		u32		dmanr;
+		unsigned        sample_rate;
+		unsigned	src_factor;
+		unsigned        sample_size;
+		int             num_channels;
+		int		dma_bytes_per_sample;
+		int		user_bytes_per_sample;
+		int		cnt_factor;
+
+		void		*rawbuf;
+		unsigned        buforder;
+		unsigned	numfrag;
+		unsigned        fragshift;
+		void		*nextIn;
+		void		*nextOut;
+		int		count;
+		unsigned        total_bytes;
+		unsigned        error;
+		wait_queue_head_t wait;
+
+		/* redundant, but makes calculations easier */
+		unsigned	fragsize;
+		unsigned	dma_fragsize;
+		unsigned	dmasize;
+		unsigned	dma_qcount;
+
+		/* OSS stuff */
+		unsigned        mapped:1;
+		unsigned        ready:1;
+		unsigned        stopped:1;
+		unsigned        ossfragshift;
+		int             ossmaxfrags;
+		unsigned        subdivision;
+	} dma_dac, dma_adc;
+} au1550_state;
+
+static unsigned
+ld2(unsigned int x)
+{
+	unsigned        r = 0;
+
+	if (x >= 0x10000) {
+		x >>= 16;
+		r += 16;
+	}
+	if (x >= 0x100) {
+		x >>= 8;
+		r += 8;
+	}
+	if (x >= 0x10) {
+		x >>= 4;
+		r += 4;
+	}
+	if (x >= 4) {
+		x >>= 2;
+		r += 2;
+	}
+	if (x >= 2)
+		r++;
+	return r;
+}
+
+static void
+au1550_delay(int msec)
+{
+	unsigned long   tmo;
+	signed long     tmo2;
+
+	if (in_interrupt())
+		return;
+
+	tmo = jiffies + (msec * HZ) / 1000;
+	for (;;) {
+		tmo2 = tmo - jiffies;
+		if (tmo2 <= 0)
+			break;
+		schedule_timeout(tmo2);
+	}
+}
+
+static u16
+rdcodec(struct ac97_codec *codec, u8 addr)
+{
+	struct au1550_state *s = (struct au1550_state *)codec->private_data;
+	unsigned long   flags;
+	u32             cmd, val;
+	u16             data;
+	int             i;
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	for (i = 0; i < POLL_COUNT; i++) {
+		val = au_readl(PSC_AC97STAT);
+		au_sync();
+		if (!(val & PSC_AC97STAT_CP))
+			break;
+	}
+	if (i == POLL_COUNT)
+		err("rdcodec: codec cmd pending expired!");
+
+	cmd = (u32)PSC_AC97CDC_INDX(addr);
+	cmd |= PSC_AC97CDC_RD;	/* read command */
+	au_writel(cmd, PSC_AC97CDC);
+	au_sync();
+
+	/* now wait for the data
+	*/
+	for (i = 0; i < POLL_COUNT; i++) {
+		val = au_readl(PSC_AC97STAT);
+		au_sync();
+		if (!(val & PSC_AC97STAT_CP))
+			break;
+	}
+	if (i == POLL_COUNT) {
+		err("rdcodec: read poll expired!");
+		return 0;
+	}
+
+	/* wait for command done?
+	*/
+	for (i = 0; i < POLL_COUNT; i++) {
+		val = au_readl(PSC_AC97EVNT);
+		au_sync();
+		if (val & PSC_AC97EVNT_CD)
+			break;
+	}
+	if (i == POLL_COUNT) {
+		err("rdcodec: read cmdwait expired!");
+		return 0;
+	}
+
+	data = au_readl(PSC_AC97CDC) & 0xffff;
+	au_sync();
+
+	/* Clear command done event.
+	*/
+	au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
+	au_sync();
+
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	return data;
+}
+
+
+static void
+wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
+{
+	struct au1550_state *s = (struct au1550_state *)codec->private_data;
+	unsigned long   flags;
+	u32             cmd, val;
+	int             i;
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	for (i = 0; i < POLL_COUNT; i++) {
+		val = au_readl(PSC_AC97STAT);
+		au_sync();
+		if (!(val & PSC_AC97STAT_CP))
+			break;
+	}
+	if (i == POLL_COUNT)
+		err("wrcodec: codec cmd pending expired!");
+
+	cmd = (u32)PSC_AC97CDC_INDX(addr);
+	cmd |= (u32)data;
+	au_writel(cmd, PSC_AC97CDC);
+	au_sync();
+
+	for (i = 0; i < POLL_COUNT; i++) {
+		val = au_readl(PSC_AC97STAT);
+		au_sync();
+		if (!(val & PSC_AC97STAT_CP))
+			break;
+	}
+	if (i == POLL_COUNT)
+		err("wrcodec: codec cmd pending expired!");
+
+	for (i = 0; i < POLL_COUNT; i++) {
+		val = au_readl(PSC_AC97EVNT);
+		au_sync();
+		if (val & PSC_AC97EVNT_CD)
+			break;
+	}
+	if (i == POLL_COUNT)
+		err("wrcodec: read cmdwait expired!");
+
+	/* Clear command done event.
+	*/
+	au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT);
+	au_sync();
+
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void
+waitcodec(struct ac97_codec *codec)
+{
+	u16	temp;
+	u32	val;
+	int	i;
+
+	/* codec_wait is used to wait for a ready state after
+	 * an AC97C_RESET.
+	 */
+	au1550_delay(10);
+
+	/* first poll the CODEC_READY tag bit
+	*/
+	for (i = 0; i < POLL_COUNT; i++) {
+		val = au_readl(PSC_AC97STAT);
+		au_sync();
+		if (val & PSC_AC97STAT_CR)
+			break;
+	}
+	if (i == POLL_COUNT) {
+		err("waitcodec: CODEC_READY poll expired!");
+		return;
+	}
+
+	/* get AC'97 powerdown control/status register
+	*/
+	temp = rdcodec(codec, AC97_POWER_CONTROL);
+
+	/* If anything is powered down, power'em up
+	*/
+	if (temp & 0x7f00) {
+		/* Power on
+		*/
+		wrcodec(codec, AC97_POWER_CONTROL, 0);
+		au1550_delay(100);
+
+		/* Reread
+		*/
+		temp = rdcodec(codec, AC97_POWER_CONTROL);
+	}
+
+	/* Check if Codec REF,ANL,DAC,ADC ready
+	*/
+	if ((temp & 0x7f0f) != 0x000f)
+		err("codec reg 26 status (0x%x) not ready!!", temp);
+}
+
+/* stop the ADC before calling */
+static void
+set_adc_rate(struct au1550_state *s, unsigned rate)
+{
+	struct dmabuf  *adc = &s->dma_adc;
+	struct dmabuf  *dac = &s->dma_dac;
+	unsigned        adc_rate, dac_rate;
+	u16             ac97_extstat;
+
+	if (s->no_vra) {
+		/* calc SRC factor
+		*/
+		adc->src_factor = ((96000 / rate) + 1) >> 1;
+		adc->sample_rate = 48000 / adc->src_factor;
+		return;
+	}
+
+	adc->src_factor = 1;
+
+	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
+
+	rate = rate > 48000 ? 48000 : rate;
+
+	/* enable VRA
+	*/
+	wrcodec(s->codec, AC97_EXTENDED_STATUS,
+		ac97_extstat | AC97_EXTSTAT_VRA);
+
+	/* now write the sample rate
+	*/
+	wrcodec(s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
+
+	/* read it back for actual supported rate
+	*/
+	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
+
+	pr_debug("set_adc_rate: set to %d Hz\n", adc_rate);
+
+	/* some codec's don't allow unequal DAC and ADC rates, in which case
+	 * writing one rate reg actually changes both.
+	 */
+	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
+	if (dac->num_channels > 2)
+		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
+	if (dac->num_channels > 4)
+		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
+
+	adc->sample_rate = adc_rate;
+	dac->sample_rate = dac_rate;
+}
+
+/* stop the DAC before calling */
+static void
+set_dac_rate(struct au1550_state *s, unsigned rate)
+{
+	struct dmabuf  *dac = &s->dma_dac;
+	struct dmabuf  *adc = &s->dma_adc;
+	unsigned        adc_rate, dac_rate;
+	u16             ac97_extstat;
+
+	if (s->no_vra) {
+		/* calc SRC factor
+		*/
+		dac->src_factor = ((96000 / rate) + 1) >> 1;
+		dac->sample_rate = 48000 / dac->src_factor;
+		return;
+	}
+
+	dac->src_factor = 1;
+
+	ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
+
+	rate = rate > 48000 ? 48000 : rate;
+
+	/* enable VRA
+	*/
+	wrcodec(s->codec, AC97_EXTENDED_STATUS,
+		ac97_extstat | AC97_EXTSTAT_VRA);
+
+	/* now write the sample rate
+	*/
+	wrcodec(s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
+
+	/* I don't support different sample rates for multichannel,
+	 * so make these channels the same.
+	 */
+	if (dac->num_channels > 2)
+		wrcodec(s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
+	if (dac->num_channels > 4)
+		wrcodec(s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
+	/* read it back for actual supported rate
+	*/
+	dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE);
+
+	pr_debug("set_dac_rate: set to %d Hz\n", dac_rate);
+
+	/* some codec's don't allow unequal DAC and ADC rates, in which case
+	 * writing one rate reg actually changes both.
+	 */
+	adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE);
+
+	dac->sample_rate = dac_rate;
+	adc->sample_rate = adc_rate;
+}
+
+static void
+stop_dac(struct au1550_state *s)
+{
+	struct dmabuf  *db = &s->dma_dac;
+	u32		stat;
+	unsigned long   flags;
+
+	if (db->stopped)
+		return;
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	au_writel(PSC_AC97PCR_TP, PSC_AC97PCR);
+	au_sync();
+
+	/* Wait for Transmit Busy to show disabled.
+	*/
+	do {
+		stat = readl((void *)PSC_AC97STAT);
+		au_sync();
+	} while ((stat & PSC_AC97STAT_TB) != 0);
+
+	au1xxx_dbdma_reset(db->dmanr);
+
+	db->stopped = 1;
+
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void
+stop_adc(struct au1550_state *s)
+{
+	struct dmabuf  *db = &s->dma_adc;
+	unsigned long   flags;
+	u32		stat;
+
+	if (db->stopped)
+		return;
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	au_writel(PSC_AC97PCR_RP, PSC_AC97PCR);
+	au_sync();
+
+	/* Wait for Receive Busy to show disabled.
+	*/
+	do {
+		stat = readl((void *)PSC_AC97STAT);
+		au_sync();
+	} while ((stat & PSC_AC97STAT_RB) != 0);
+
+	au1xxx_dbdma_reset(db->dmanr);
+
+	db->stopped = 1;
+
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+
+static void
+set_xmit_slots(int num_channels)
+{
+	u32	ac97_config, stat;
+
+	ac97_config = au_readl(PSC_AC97CFG);
+	au_sync();
+	ac97_config &= ~(PSC_AC97CFG_TXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
+	au_writel(ac97_config, PSC_AC97CFG);
+	au_sync();
+
+	switch (num_channels) {
+	case 6:		/* stereo with surround and center/LFE,
+			 * slots 3,4,6,7,8,9
+			 */
+		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(6);
+		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(9);
+
+	case 4:		/* stereo with surround, slots 3,4,7,8 */
+		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(7);
+		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(8);
+
+	case 2:		/* stereo, slots 3,4 */
+	case 1:		/* mono */
+		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(3);
+		ac97_config |= PSC_AC97CFG_TXSLOT_ENA(4);
+	}
+
+	au_writel(ac97_config, PSC_AC97CFG);
+	au_sync();
+
+	ac97_config |= PSC_AC97CFG_DE_ENABLE;
+	au_writel(ac97_config, PSC_AC97CFG);
+	au_sync();
+
+	/* Wait for Device ready.
+	*/
+	do {
+		stat = readl((void *)PSC_AC97STAT);
+		au_sync();
+	} while ((stat & PSC_AC97STAT_DR) == 0);
+}
+
+static void
+set_recv_slots(int num_channels)
+{
+	u32	ac97_config, stat;
+
+	ac97_config = au_readl(PSC_AC97CFG);
+	au_sync();
+	ac97_config &= ~(PSC_AC97CFG_RXSLOT_MASK | PSC_AC97CFG_DE_ENABLE);
+	au_writel(ac97_config, PSC_AC97CFG);
+	au_sync();
+
+	/* Always enable slots 3 and 4 (stereo). Slot 6 is
+	 * optional Mic ADC, which we don't support yet.
+	 */
+	ac97_config |= PSC_AC97CFG_RXSLOT_ENA(3);
+	ac97_config |= PSC_AC97CFG_RXSLOT_ENA(4);
+
+	au_writel(ac97_config, PSC_AC97CFG);
+	au_sync();
+
+	ac97_config |= PSC_AC97CFG_DE_ENABLE;
+	au_writel(ac97_config, PSC_AC97CFG);
+	au_sync();
+
+	/* Wait for Device ready.
+	*/
+	do {
+		stat = readl((void *)PSC_AC97STAT);
+		au_sync();
+	} while ((stat & PSC_AC97STAT_DR) == 0);
+}
+
+static void
+start_dac(struct au1550_state *s)
+{
+	struct dmabuf  *db = &s->dma_dac;
+	unsigned long   flags;
+
+	if (!db->stopped)
+		return;
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	set_xmit_slots(db->num_channels);
+	au_writel(PSC_AC97PCR_TC, PSC_AC97PCR);
+	au_sync();
+	au_writel(PSC_AC97PCR_TS, PSC_AC97PCR);
+	au_sync();
+
+	au1xxx_dbdma_start(db->dmanr);
+
+	db->stopped = 0;
+
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void
+start_adc(struct au1550_state *s)
+{
+	struct dmabuf  *db = &s->dma_adc;
+	int	i;
+
+	if (!db->stopped)
+		return;
+
+	/* Put two buffers on the ring to get things started.
+	*/
+	for (i=0; i<2; i++) {
+		au1xxx_dbdma_put_dest(db->dmanr, db->nextIn, db->dma_fragsize);
+
+		db->nextIn += db->dma_fragsize;
+		if (db->nextIn >= db->rawbuf + db->dmasize)
+			db->nextIn -= db->dmasize;
+	}
+
+	set_recv_slots(db->num_channels);
+	au1xxx_dbdma_start(db->dmanr);
+	au_writel(PSC_AC97PCR_RC, PSC_AC97PCR);
+	au_sync();
+	au_writel(PSC_AC97PCR_RS, PSC_AC97PCR);
+	au_sync();
+
+	db->stopped = 0;
+}
+
+static int
+prog_dmabuf(struct au1550_state *s, struct dmabuf *db)
+{
+	unsigned user_bytes_per_sec;
+	unsigned        bufs;
+	unsigned        rate = db->sample_rate;
+
+	if (!db->rawbuf) {
+		db->ready = db->mapped = 0;
+		db->buforder = 5;	/* 32 * PAGE_SIZE */
+		db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL);
+		if (!db->rawbuf)
+			return -ENOMEM;
+	}
+
+	db->cnt_factor = 1;
+	if (db->sample_size == 8)
+		db->cnt_factor *= 2;
+	if (db->num_channels == 1)
+		db->cnt_factor *= 2;
+	db->cnt_factor *= db->src_factor;
+
+	db->count = 0;
+	db->dma_qcount = 0;
+	db->nextIn = db->nextOut = db->rawbuf;
+
+	db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
+	db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
+					2 : db->num_channels);
+
+	user_bytes_per_sec = rate * db->user_bytes_per_sample;
+	bufs = PAGE_SIZE << db->buforder;
+	if (db->ossfragshift) {
+		if ((1000 << db->ossfragshift) < user_bytes_per_sec)
+			db->fragshift = ld2(user_bytes_per_sec/1000);
+		else
+			db->fragshift = db->ossfragshift;
+	} else {
+		db->fragshift = ld2(user_bytes_per_sec / 100 /
+				    (db->subdivision ? db->subdivision : 1));
+		if (db->fragshift < 3)
+			db->fragshift = 3;
+	}
+
+	db->fragsize = 1 << db->fragshift;
+	db->dma_fragsize = db->fragsize * db->cnt_factor;
+	db->numfrag = bufs / db->dma_fragsize;
+
+	while (db->numfrag < 4 && db->fragshift > 3) {
+		db->fragshift--;
+		db->fragsize = 1 << db->fragshift;
+		db->dma_fragsize = db->fragsize * db->cnt_factor;
+		db->numfrag = bufs / db->dma_fragsize;
+	}
+
+	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+		db->numfrag = db->ossmaxfrags;
+
+	db->dmasize = db->dma_fragsize * db->numfrag;
+	memset(db->rawbuf, 0, bufs);
+
+	pr_debug("prog_dmabuf: rate=%d, samplesize=%d, channels=%d\n",
+	    rate, db->sample_size, db->num_channels);
+	pr_debug("prog_dmabuf: fragsize=%d, cnt_factor=%d, dma_fragsize=%d\n",
+	    db->fragsize, db->cnt_factor, db->dma_fragsize);
+	pr_debug("prog_dmabuf: numfrag=%d, dmasize=%d\n", db->numfrag, db->dmasize);
+
+	db->ready = 1;
+	return 0;
+}
+
+static int
+prog_dmabuf_adc(struct au1550_state *s)
+{
+	stop_adc(s);
+	return prog_dmabuf(s, &s->dma_adc);
+
+}
+
+static int
+prog_dmabuf_dac(struct au1550_state *s)
+{
+	stop_dac(s);
+	return prog_dmabuf(s, &s->dma_dac);
+}
+
+
+/* hold spinlock for the following */
+static void
+dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct au1550_state *s = (struct au1550_state *) dev_id;
+	struct dmabuf  *db = &s->dma_dac;
+	u32	ac97c_stat;
+
+	ac97c_stat = au_readl(PSC_AC97STAT);
+	if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
+		pr_debug("AC97C status = 0x%08x\n", ac97c_stat);
+	db->dma_qcount--;
+
+	if (db->count >= db->fragsize) {
+		if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
+							db->fragsize) == 0) {
+			err("qcount < 2 and no ring room!");
+		}
+		db->nextOut += db->fragsize;
+		if (db->nextOut >= db->rawbuf + db->dmasize)
+			db->nextOut -= db->dmasize;
+		db->count -= db->fragsize;
+		db->total_bytes += db->dma_fragsize;
+		db->dma_qcount++;
+	}
+
+	/* wake up anybody listening */
+	if (waitqueue_active(&db->wait))
+		wake_up(&db->wait);
+}
+
+
+static void
+adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct	au1550_state *s = (struct au1550_state *)dev_id;
+	struct	dmabuf  *dp = &s->dma_adc;
+	u32	obytes;
+	char	*obuf;
+
+	/* Pull the buffer from the dma queue.
+	*/
+	au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes);
+
+	if ((dp->count + obytes) > dp->dmasize) {
+		/* Overrun. Stop ADC and log the error
+		*/
+		stop_adc(s);
+		dp->error++;
+		err("adc overrun");
+		return;
+	}
+
+	/* Put a new empty buffer on the destination DMA.
+	*/
+	au1xxx_dbdma_put_dest(dp->dmanr, dp->nextIn, dp->dma_fragsize);
+
+	dp->nextIn += dp->dma_fragsize;
+	if (dp->nextIn >= dp->rawbuf + dp->dmasize)
+		dp->nextIn -= dp->dmasize;
+
+	dp->count += obytes;
+	dp->total_bytes += obytes;
+
+	/* wake up anybody listening
+	*/
+	if (waitqueue_active(&dp->wait))
+		wake_up(&dp->wait);
+
+}
+
+static loff_t
+au1550_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+
+static int
+au1550_open_mixdev(struct inode *inode, struct file *file)
+{
+	file->private_data = &au1550_state;
+	return 0;
+}
+
+static int
+au1550_release_mixdev(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int
+mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
+                        unsigned long arg)
+{
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static int
+au1550_ioctl_mixdev(struct inode *inode, struct file *file,
+			       unsigned int cmd, unsigned long arg)
+{
+	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct ac97_codec *codec = s->codec;
+
+	return mixdev_ioctl(codec, cmd, arg);
+}
+
+static /*const */ struct file_operations au1550_mixer_fops = {
+	owner:THIS_MODULE,
+	llseek:au1550_llseek,
+	ioctl:au1550_ioctl_mixdev,
+	open:au1550_open_mixdev,
+	release:au1550_release_mixdev,
+};
+
+static int
+drain_dac(struct au1550_state *s, int nonblock)
+{
+	unsigned long   flags;
+	int             count, tmo;
+
+	if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
+		return 0;
+
+	for (;;) {
+		spin_lock_irqsave(&s->lock, flags);
+		count = s->dma_dac.count;
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (count <= s->dma_dac.fragsize)
+			break;
+		if (signal_pending(current))
+			break;
+		if (nonblock)
+			return -EBUSY;
+		tmo = 1000 * count / (s->no_vra ?
+				      48000 : s->dma_dac.sample_rate);
+		tmo /= s->dma_dac.dma_bytes_per_sample;
+		au1550_delay(tmo);
+	}
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+	return 0;
+}
+
+static inline u8 S16_TO_U8(s16 ch)
+{
+	return (u8) (ch >> 8) + 0x80;
+}
+static inline s16 U8_TO_S16(u8 ch)
+{
+	return (s16) (ch - 0x80) << 8;
+}
+
+/*
+ * Translates user samples to dma buffer suitable for AC'97 DAC data:
+ *     If mono, copy left channel to right channel in dma buffer.
+ *     If 8 bit samples, cvt to 16-bit before writing to dma buffer.
+ *     If interpolating (no VRA), duplicate every audio frame src_factor times.
+ */
+static int
+translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,
+							       int dmacount)
+{
+	int             sample, i;
+	int             interp_bytes_per_sample;
+	int             num_samples;
+	int             mono = (db->num_channels == 1);
+	char            usersample[12];
+	s16             ch, dmasample[6];
+
+	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
+		/* no translation necessary, just copy
+		*/
+		if (copy_from_user(dmabuf, userbuf, dmacount))
+			return -EFAULT;
+		return dmacount;
+	}
+
+	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
+	num_samples = dmacount / interp_bytes_per_sample;
+
+	for (sample = 0; sample < num_samples; sample++) {
+		if (copy_from_user(usersample, userbuf,
+				   db->user_bytes_per_sample)) {
+			return -EFAULT;
+		}
+
+		for (i = 0; i < db->num_channels; i++) {
+			if (db->sample_size == 8)
+				ch = U8_TO_S16(usersample[i]);
+			else
+				ch = *((s16 *) (&usersample[i * 2]));
+			dmasample[i] = ch;
+			if (mono)
+				dmasample[i + 1] = ch;	/* right channel */
+		}
+
+		/* duplicate every audio frame src_factor times
+		*/
+		for (i = 0; i < db->src_factor; i++)
+			memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
+
+		userbuf += db->user_bytes_per_sample;
+		dmabuf += interp_bytes_per_sample;
+	}
+
+	return num_samples * interp_bytes_per_sample;
+}
+
+/*
+ * Translates AC'97 ADC samples to user buffer:
+ *     If mono, send only left channel to user buffer.
+ *     If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
+ *     If decimating (no VRA), skip over src_factor audio frames.
+ */
+static int
+translate_to_user(struct dmabuf *db, char* userbuf, char* dmabuf,
+							     int dmacount)
+{
+	int             sample, i;
+	int             interp_bytes_per_sample;
+	int             num_samples;
+	int             mono = (db->num_channels == 1);
+	char            usersample[12];
+
+	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
+		/* no translation necessary, just copy
+		*/
+		if (copy_to_user(userbuf, dmabuf, dmacount))
+			return -EFAULT;
+		return dmacount;
+	}
+
+	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
+	num_samples = dmacount / interp_bytes_per_sample;
+
+	for (sample = 0; sample < num_samples; sample++) {
+		for (i = 0; i < db->num_channels; i++) {
+			if (db->sample_size == 8)
+				usersample[i] =
+					S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
+			else
+				*((s16 *) (&usersample[i * 2])) =
+					*((s16 *) (&dmabuf[i * 2]));
+		}
+
+		if (copy_to_user(userbuf, usersample,
+				 db->user_bytes_per_sample)) {
+			return -EFAULT;
+		}
+
+		userbuf += db->user_bytes_per_sample;
+		dmabuf += interp_bytes_per_sample;
+	}
+
+	return num_samples * interp_bytes_per_sample;
+}
+
+/*
+ * Copy audio data to/from user buffer from/to dma buffer, taking care
+ * that we wrap when reading/writing the dma buffer. Returns actual byte
+ * count written to or read from the dma buffer.
+ */
+static int
+copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
+{
+	char           *bufptr = to_user ? db->nextOut : db->nextIn;
+	char           *bufend = db->rawbuf + db->dmasize;
+	int             cnt, ret;
+
+	if (bufptr + count > bufend) {
+		int             partial = (int) (bufend - bufptr);
+		if (to_user) {
+			if ((cnt = translate_to_user(db, userbuf,
+						     bufptr, partial)) < 0)
+				return cnt;
+			ret = cnt;
+			if ((cnt = translate_to_user(db, userbuf + partial,
+						     db->rawbuf,
+						     count - partial)) < 0)
+				return cnt;
+			ret += cnt;
+		} else {
+			if ((cnt = translate_from_user(db, bufptr, userbuf,
+						       partial)) < 0)
+				return cnt;
+			ret = cnt;
+			if ((cnt = translate_from_user(db, db->rawbuf,
+						       userbuf + partial,
+						       count - partial)) < 0)
+				return cnt;
+			ret += cnt;
+		}
+	} else {
+		if (to_user)
+			ret = translate_to_user(db, userbuf, bufptr, count);
+		else
+			ret = translate_from_user(db, bufptr, userbuf, count);
+	}
+
+	return ret;
+}
+
+
+static ssize_t
+au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct dmabuf  *db = &s->dma_adc;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t         ret;
+	unsigned long   flags;
+	int             cnt, usercnt, avail;
+
+	if (db->mapped)
+		return -ENXIO;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	ret = 0;
+
+	count *= db->cnt_factor;
+
+	down(&s->sem);
+	add_wait_queue(&db->wait, &wait);
+
+	while (count > 0) {
+		/* wait for samples in ADC dma buffer
+		*/
+		do {
+			if (db->stopped)
+				start_adc(s);
+			spin_lock_irqsave(&s->lock, flags);
+			avail = db->count;
+			if (avail <= 0)
+				__set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irqrestore(&s->lock, flags);
+			if (avail <= 0) {
+				if (file->f_flags & O_NONBLOCK) {
+					if (!ret)
+						ret = -EAGAIN;
+					goto out;
+				}
+				up(&s->sem);
+				schedule();
+				if (signal_pending(current)) {
+					if (!ret)
+						ret = -ERESTARTSYS;
+					goto out2;
+				}
+				down(&s->sem);
+			}
+		} while (avail <= 0);
+
+		/* copy from nextOut to user
+		*/
+		if ((cnt = copy_dmabuf_user(db, buffer,
+					    count > avail ?
+					    avail : count, 1)) < 0) {
+			if (!ret)
+				ret = -EFAULT;
+			goto out;
+		}
+
+		spin_lock_irqsave(&s->lock, flags);
+		db->count -= cnt;
+		db->nextOut += cnt;
+		if (db->nextOut >= db->rawbuf + db->dmasize)
+			db->nextOut -= db->dmasize;
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		count -= cnt;
+		usercnt = cnt / db->cnt_factor;
+		buffer += usercnt;
+		ret += usercnt;
+	}			/* while (count > 0) */
+
+out:
+	up(&s->sem);
+out2:
+	remove_wait_queue(&db->wait, &wait);
+	set_current_state(TASK_RUNNING);
+	return ret;
+}
+
+static ssize_t
+au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
+{
+	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct dmabuf  *db = &s->dma_dac;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t         ret = 0;
+	unsigned long   flags;
+	int             cnt, usercnt, avail;
+
+	pr_debug("write: count=%d\n", count);
+
+	if (db->mapped)
+		return -ENXIO;
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+
+	count *= db->cnt_factor;
+
+	down(&s->sem);
+	add_wait_queue(&db->wait, &wait);
+
+	while (count > 0) {
+		/* wait for space in playback buffer
+		*/
+		do {
+			spin_lock_irqsave(&s->lock, flags);
+			avail = (int) db->dmasize - db->count;
+			if (avail <= 0)
+				__set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock_irqrestore(&s->lock, flags);
+			if (avail <= 0) {
+				if (file->f_flags & O_NONBLOCK) {
+					if (!ret)
+						ret = -EAGAIN;
+					goto out;
+				}
+				up(&s->sem);
+				schedule();
+				if (signal_pending(current)) {
+					if (!ret)
+						ret = -ERESTARTSYS;
+					goto out2;
+				}
+				down(&s->sem);
+			}
+		} while (avail <= 0);
+
+		/* copy from user to nextIn
+		*/
+		if ((cnt = copy_dmabuf_user(db, (char *) buffer,
+					    count > avail ?
+					    avail : count, 0)) < 0) {
+			if (!ret)
+				ret = -EFAULT;
+			goto out;
+		}
+
+		spin_lock_irqsave(&s->lock, flags);
+		db->count += cnt;
+		db->nextIn += cnt;
+		if (db->nextIn >= db->rawbuf + db->dmasize)
+			db->nextIn -= db->dmasize;
+
+		/* If the data is available, we want to keep two buffers
+		 * on the dma queue.  If the queue count reaches zero,
+		 * we know the dma has stopped.
+		 */
+		while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
+			if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
+							db->fragsize) == 0) {
+				err("qcount < 2 and no ring room!");
+			}
+			db->nextOut += db->fragsize;
+			if (db->nextOut >= db->rawbuf + db->dmasize)
+				db->nextOut -= db->dmasize;
+			db->total_bytes += db->dma_fragsize;
+			if (db->dma_qcount == 0)
+				start_dac(s);
+			db->dma_qcount++;
+		}
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		count -= cnt;
+		usercnt = cnt / db->cnt_factor;
+		buffer += usercnt;
+		ret += usercnt;
+	}			/* while (count > 0) */
+
+out:
+	up(&s->sem);
+out2:
+	remove_wait_queue(&db->wait, &wait);
+	set_current_state(TASK_RUNNING);
+	return ret;
+}
+
+
+/* No kernel lock - we have our own spinlock */
+static unsigned int
+au1550_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	unsigned long   flags;
+	unsigned int    mask = 0;
+
+	if (file->f_mode & FMODE_WRITE) {
+		if (!s->dma_dac.ready)
+			return 0;
+		poll_wait(file, &s->dma_dac.wait, wait);
+	}
+	if (file->f_mode & FMODE_READ) {
+		if (!s->dma_adc.ready)
+			return 0;
+		poll_wait(file, &s->dma_adc.wait, wait);
+	}
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	if (file->f_mode & FMODE_READ) {
+		if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (s->dma_dac.mapped) {
+			if (s->dma_dac.count >=
+			    (signed)s->dma_dac.dma_fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((signed) s->dma_dac.dmasize >=
+			    s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+	return mask;
+}
+
+static int
+au1550_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	struct dmabuf  *db;
+	unsigned long   size;
+	int ret = 0;
+
+	lock_kernel();
+	down(&s->sem);
+	if (vma->vm_flags & VM_WRITE)
+		db = &s->dma_dac;
+	else if (vma->vm_flags & VM_READ)
+		db = &s->dma_adc;
+	else {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (vma->vm_pgoff != 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+	size = vma->vm_end - vma->vm_start;
+	if (size > (PAGE_SIZE << db->buforder)) {
+		ret = -EINVAL;
+		goto out;
+	}
+	if (remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page(db->rawbuf)),
+			     size, vma->vm_page_prot)) {
+		ret = -EAGAIN;
+		goto out;
+	}
+	vma->vm_flags &= ~VM_IO;
+	db->mapped = 1;
+out:
+	up(&s->sem);
+	unlock_kernel();
+	return ret;
+}
+
+#ifdef DEBUG
+static struct ioctl_str_t {
+	unsigned int    cmd;
+	const char     *str;
+} ioctl_str[] = {
+	{SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
+	{SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
+	{SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
+	{SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
+	{SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
+	{SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
+	{SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
+	{SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
+	{SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
+	{SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
+	{SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
+	{SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
+	{SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
+	{SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
+	{SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
+	{SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
+	{SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
+	{SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
+	{SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
+	{SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
+	{SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
+	{SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
+	{SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
+	{SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
+	{SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
+	{SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
+	{SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
+	{SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
+	{SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
+	{OSS_GETVERSION, "OSS_GETVERSION"},
+	{SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
+	{SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
+	{SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
+	{SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
+};
+#endif
+
+static int
+dma_count_done(struct dmabuf *db)
+{
+	if (db->stopped)
+		return 0;
+
+	return db->dma_fragsize - au1xxx_get_dma_residue(db->dmanr);
+}
+
+
+static int
+au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+							unsigned long arg)
+{
+	struct au1550_state *s = (struct au1550_state *)file->private_data;
+	unsigned long   flags;
+	audio_buf_info  abinfo;
+	count_info      cinfo;
+	int             count;
+	int             val, mapped, ret, diff;
+
+	mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+
+#ifdef DEBUG
+	for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
+		if (ioctl_str[count].cmd == cmd)
+			break;
+	}
+	if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))
+		pr_debug("ioctl %s, arg=0x%lxn", ioctl_str[count].str, arg);
+	else
+		pr_debug("ioctl 0x%x unknown, arg=0x%lx\n", cmd, arg);
+#endif
+
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *) arg);
+
+	case SNDCTL_DSP_SYNC:
+		if (file->f_mode & FMODE_WRITE)
+			return drain_dac(s, file->f_flags & O_NONBLOCK);
+		return 0;
+
+	case SNDCTL_DSP_SETDUPLEX:
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
+				DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(s);
+			synchronize_irq();
+			s->dma_dac.count = s->dma_dac.total_bytes = 0;
+			s->dma_dac.nextIn = s->dma_dac.nextOut =
+				s->dma_dac.rawbuf;
+		}
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(s);
+			synchronize_irq();
+			s->dma_adc.count = s->dma_adc.total_bytes = 0;
+			s->dma_adc.nextIn = s->dma_adc.nextOut =
+				s->dma_adc.rawbuf;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SPEED:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val >= 0) {
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(s);
+				set_adc_rate(s, val);
+			}
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(s);
+				set_dac_rate(s, val);
+			}
+			if (s->open_mode & FMODE_READ)
+				if ((ret = prog_dmabuf_adc(s)))
+					return ret;
+			if (s->open_mode & FMODE_WRITE)
+				if ((ret = prog_dmabuf_dac(s)))
+					return ret;
+		}
+		return put_user((file->f_mode & FMODE_READ) ?
+				s->dma_adc.sample_rate :
+				s->dma_dac.sample_rate,
+				(int *)arg);
+
+	case SNDCTL_DSP_STEREO:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(s);
+			s->dma_adc.num_channels = val ? 2 : 1;
+			if ((ret = prog_dmabuf_adc(s)))
+				return ret;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(s);
+			s->dma_dac.num_channels = val ? 2 : 1;
+			if (s->codec_ext_caps & AC97_EXT_DACS) {
+				/* disable surround and center/lfe in AC'97
+				*/
+				u16 ext_stat = rdcodec(s->codec,
+						       AC97_EXTENDED_STATUS);
+				wrcodec(s->codec, AC97_EXTENDED_STATUS,
+					ext_stat | (AC97_EXTSTAT_PRI |
+						    AC97_EXTSTAT_PRJ |
+						    AC97_EXTSTAT_PRK));
+			}
+			if ((ret = prog_dmabuf_dac(s)))
+				return ret;
+		}
+		return 0;
+
+	case SNDCTL_DSP_CHANNELS:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val != 0) {
+			if (file->f_mode & FMODE_READ) {
+				if (val < 0 || val > 2)
+					return -EINVAL;
+				stop_adc(s);
+				s->dma_adc.num_channels = val;
+				if ((ret = prog_dmabuf_adc(s)))
+					return ret;
+			}
+			if (file->f_mode & FMODE_WRITE) {
+				switch (val) {
+				case 1:
+				case 2:
+					break;
+				case 3:
+				case 5:
+					return -EINVAL;
+				case 4:
+					if (!(s->codec_ext_caps &
+					      AC97_EXTID_SDAC))
+						return -EINVAL;
+					break;
+				case 6:
+					if ((s->codec_ext_caps &
+					     AC97_EXT_DACS) != AC97_EXT_DACS)
+						return -EINVAL;
+					break;
+				default:
+					return -EINVAL;
+				}
+
+				stop_dac(s);
+				if (val <= 2 &&
+				    (s->codec_ext_caps & AC97_EXT_DACS)) {
+					/* disable surround and center/lfe
+					 * channels in AC'97
+					 */
+					u16             ext_stat =
+						rdcodec(s->codec,
+							AC97_EXTENDED_STATUS);
+					wrcodec(s->codec,
+						AC97_EXTENDED_STATUS,
+						ext_stat | (AC97_EXTSTAT_PRI |
+							    AC97_EXTSTAT_PRJ |
+							    AC97_EXTSTAT_PRK));
+				} else if (val >= 4) {
+					/* enable surround, center/lfe
+					 * channels in AC'97
+					 */
+					u16             ext_stat =
+						rdcodec(s->codec,
+							AC97_EXTENDED_STATUS);
+					ext_stat &= ~AC97_EXTSTAT_PRJ;
+					if (val == 6)
+						ext_stat &=
+							~(AC97_EXTSTAT_PRI |
+							  AC97_EXTSTAT_PRK);
+					wrcodec(s->codec,
+						AC97_EXTENDED_STATUS,
+						ext_stat);
+				}
+
+				s->dma_dac.num_channels = val;
+				if ((ret = prog_dmabuf_dac(s)))
+					return ret;
+			}
+		}
+		return put_user(val, (int *) arg);
+
+	case SNDCTL_DSP_GETFMTS:	/* Returns a mask */
+		return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
+
+	case SNDCTL_DSP_SETFMT:	/* Selects ONE fmt */
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val != AFMT_QUERY) {
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(s);
+				if (val == AFMT_S16_LE)
+					s->dma_adc.sample_size = 16;
+				else {
+					val = AFMT_U8;
+					s->dma_adc.sample_size = 8;
+				}
+				if ((ret = prog_dmabuf_adc(s)))
+					return ret;
+			}
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(s);
+				if (val == AFMT_S16_LE)
+					s->dma_dac.sample_size = 16;
+				else {
+					val = AFMT_U8;
+					s->dma_dac.sample_size = 8;
+				}
+				if ((ret = prog_dmabuf_dac(s)))
+					return ret;
+			}
+		} else {
+			if (file->f_mode & FMODE_READ)
+				val = (s->dma_adc.sample_size == 16) ?
+					AFMT_S16_LE : AFMT_U8;
+			else
+				val = (s->dma_dac.sample_size == 16) ?
+					AFMT_S16_LE : AFMT_U8;
+		}
+		return put_user(val, (int *) arg);
+
+	case SNDCTL_DSP_POST:
+		return 0;
+
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		spin_lock_irqsave(&s->lock, flags);
+		if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
+			val |= PCM_ENABLE_INPUT;
+		if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
+			val |= PCM_ENABLE_OUTPUT;
+		spin_unlock_irqrestore(&s->lock, flags);
+		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)
+				start_adc(s);
+			else
+				stop_adc(s);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT)
+				start_dac(s);
+			else
+				stop_dac(s);
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		abinfo.fragsize = s->dma_dac.fragsize;
+		spin_lock_irqsave(&s->lock, flags);
+		count = s->dma_dac.count;
+		count -= dma_count_done(&s->dma_dac);
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (count < 0)
+			count = 0;
+		abinfo.bytes = (s->dma_dac.dmasize - count) /
+			s->dma_dac.cnt_factor;
+		abinfo.fragstotal = s->dma_dac.numfrag;
+		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+		pr_debug("ioctl SNDCTL_DSP_GETOSPACE: bytes=%d, fragments=%d\n", abinfo.bytes, abinfo.fragments);
+		return copy_to_user((void *) arg, &abinfo,
+				    sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		abinfo.fragsize = s->dma_adc.fragsize;
+		spin_lock_irqsave(&s->lock, flags);
+		count = s->dma_adc.count;
+		count += dma_count_done(&s->dma_adc);
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (count < 0)
+			count = 0;
+		abinfo.bytes = count / s->dma_adc.cnt_factor;
+		abinfo.fragstotal = s->dma_adc.numfrag;
+		abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+		return copy_to_user((void *) arg, &abinfo,
+				    sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		count = s->dma_dac.count;
+		count -= dma_count_done(&s->dma_dac);
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (count < 0)
+			count = 0;
+		count /= s->dma_dac.cnt_factor;
+		return put_user(count, (int *) arg);
+
+	case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		cinfo.bytes = s->dma_adc.total_bytes;
+		count = s->dma_adc.count;
+		if (!s->dma_adc.stopped) {
+			diff = dma_count_done(&s->dma_adc);
+			count += diff;
+			cinfo.bytes += diff;
+			cinfo.ptr =  virt_to_phys(s->dma_adc.nextIn) + diff -
+				virt_to_phys(s->dma_adc.rawbuf);
+		} else
+			cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
+				virt_to_phys(s->dma_adc.rawbuf);
+		if (s->dma_adc.mapped)
+			s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (count < 0)
+			count = 0;
+		cinfo.blocks = count >> s->dma_adc.fragshift;
+		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+
+	case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		spin_lock_irqsave(&s->lock, flags);
+		cinfo.bytes = s->dma_dac.total_bytes;
+		count = s->dma_dac.count;
+		if (!s->dma_dac.stopped) {
+			diff = dma_count_done(&s->dma_dac);
+			count -= diff;
+			cinfo.bytes += diff;
+			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
+				virt_to_phys(s->dma_dac.rawbuf);
+		} else
+			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
+				virt_to_phys(s->dma_dac.rawbuf);
+		if (s->dma_dac.mapped)
+			s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
+		spin_unlock_irqrestore(&s->lock, flags);
+		if (count < 0)
+			count = 0;
+		cinfo.blocks = count >> s->dma_dac.fragshift;
+		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE)
+			return put_user(s->dma_dac.fragsize, (int *) arg);
+		else
+			return put_user(s->dma_adc.fragsize, (int *) arg);
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(s);
+			s->dma_adc.ossfragshift = val & 0xffff;
+			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+			if (s->dma_adc.ossfragshift < 4)
+				s->dma_adc.ossfragshift = 4;
+			if (s->dma_adc.ossfragshift > 15)
+				s->dma_adc.ossfragshift = 15;
+			if (s->dma_adc.ossmaxfrags < 4)
+				s->dma_adc.ossmaxfrags = 4;
+			if ((ret = prog_dmabuf_adc(s)))
+				return ret;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(s);
+			s->dma_dac.ossfragshift = val & 0xffff;
+			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+			if (s->dma_dac.ossfragshift < 4)
+				s->dma_dac.ossfragshift = 4;
+			if (s->dma_dac.ossfragshift > 15)
+				s->dma_dac.ossfragshift = 15;
+			if (s->dma_dac.ossmaxfrags < 4)
+				s->dma_dac.ossmaxfrags = 4;
+			if ((ret = prog_dmabuf_dac(s)))
+				return ret;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+			return -EINVAL;
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(s);
+			s->dma_adc.subdivision = val;
+			if ((ret = prog_dmabuf_adc(s)))
+				return ret;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(s);
+			s->dma_dac.subdivision = val;
+			if ((ret = prog_dmabuf_dac(s)))
+				return ret;
+		}
+		return 0;
+
+	case SOUND_PCM_READ_RATE:
+		return put_user((file->f_mode & FMODE_READ) ?
+				s->dma_adc.sample_rate :
+				s->dma_dac.sample_rate,
+				(int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+		if (file->f_mode & FMODE_READ)
+			return put_user(s->dma_adc.num_channels, (int *)arg);
+		else
+			return put_user(s->dma_dac.num_channels, (int *)arg);
+
+	case SOUND_PCM_READ_BITS:
+		if (file->f_mode & FMODE_READ)
+			return put_user(s->dma_adc.sample_size, (int *)arg);
+		else
+			return put_user(s->dma_dac.sample_size, (int *)arg);
+
+	case SOUND_PCM_WRITE_FILTER:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_READ_FILTER:
+		return -EINVAL;
+	}
+
+	return mixdev_ioctl(s->codec, cmd, arg);
+}
+
+
+static int
+au1550_open(struct inode *inode, struct file *file)
+{
+	int             minor = MINOR(inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);
+	struct au1550_state *s = &au1550_state;
+	int             ret;
+
+#ifdef DEBUG
+	if (file->f_flags & O_NONBLOCK)
+		pr_debug("open: non-blocking\n");
+	else
+		pr_debug("open: blocking\n");
+#endif
+
+	file->private_data = s;
+	/* wait for device to become free */
+	down(&s->open_sem);
+	while (s->open_mode & file->f_mode) {
+		if (file->f_flags & O_NONBLOCK) {
+			up(&s->open_sem);
+			return -EBUSY;
+		}
+		add_wait_queue(&s->open_wait, &wait);
+		__set_current_state(TASK_INTERRUPTIBLE);
+		up(&s->open_sem);
+		schedule();
+		remove_wait_queue(&s->open_wait, &wait);
+		set_current_state(TASK_RUNNING);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+		down(&s->open_sem);
+	}
+
+	stop_dac(s);
+	stop_adc(s);
+
+	if (file->f_mode & FMODE_READ) {
+		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
+			s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
+		s->dma_adc.num_channels = 1;
+		s->dma_adc.sample_size = 8;
+		set_adc_rate(s, 8000);
+		if ((minor & 0xf) == SND_DEV_DSP16)
+			s->dma_adc.sample_size = 16;
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
+			s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
+		s->dma_dac.num_channels = 1;
+		s->dma_dac.sample_size = 8;
+		set_dac_rate(s, 8000);
+		if ((minor & 0xf) == SND_DEV_DSP16)
+			s->dma_dac.sample_size = 16;
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		if ((ret = prog_dmabuf_adc(s)))
+			return ret;
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if ((ret = prog_dmabuf_dac(s)))
+			return ret;
+	}
+
+	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	up(&s->open_sem);
+	init_MUTEX(&s->sem);
+	return 0;
+}
+
+static int
+au1550_release(struct inode *inode, struct file *file)
+{
+	struct au1550_state *s = (struct au1550_state *)file->private_data;
+
+	lock_kernel();
+
+	if (file->f_mode & FMODE_WRITE) {
+		unlock_kernel();
+		drain_dac(s, file->f_flags & O_NONBLOCK);
+		lock_kernel();
+	}
+
+	down(&s->open_sem);
+	if (file->f_mode & FMODE_WRITE) {
+		stop_dac(s);
+		kfree(s->dma_dac.rawbuf);
+		s->dma_dac.rawbuf = NULL;
+	}
+	if (file->f_mode & FMODE_READ) {
+		stop_adc(s);
+		kfree(s->dma_adc.rawbuf);
+		s->dma_adc.rawbuf = NULL;
+	}
+	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
+	up(&s->open_sem);
+	wake_up(&s->open_wait);
+	unlock_kernel();
+	return 0;
+}
+
+static /*const */ struct file_operations au1550_audio_fops = {
+	owner:		THIS_MODULE,
+	llseek:		au1550_llseek,
+	read:		au1550_read,
+	write:		au1550_write,
+	poll:		au1550_poll,
+	ioctl:		au1550_ioctl,
+	mmap:		au1550_mmap,
+	open:		au1550_open,
+	release:	au1550_release,
+};
+
+MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
+MODULE_DESCRIPTION("Au1550 AC97 Audio Driver");
+
+static int __devinit
+au1550_probe(void)
+{
+	struct au1550_state *s = &au1550_state;
+	int             val;
+
+	memset(s, 0, sizeof(struct au1550_state));
+
+	init_waitqueue_head(&s->dma_adc.wait);
+	init_waitqueue_head(&s->dma_dac.wait);
+	init_waitqueue_head(&s->open_wait);
+	init_MUTEX(&s->open_sem);
+	spin_lock_init(&s->lock);
+
+	s->codec = ac97_alloc_codec();
+	if(s->codec == NULL) {
+		err("Out of memory");
+		return -1;
+	}
+	s->codec->private_data = s;
+	s->codec->id = 0;
+	s->codec->codec_read = rdcodec;
+	s->codec->codec_write = wrcodec;
+	s->codec->codec_wait = waitcodec;
+
+	if (!request_mem_region(CPHYSADDR(AC97_PSC_SEL),
+			    0x30, "Au1550 AC97")) {
+		err("AC'97 ports in use");
+	}
+
+	/* Allocate the DMA Channels
+	*/
+	if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN,
+	    DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) {
+		err("Can't get DAC DMA");
+		goto err_dma1;
+	}
+	au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16);
+	if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr,
+					NUM_DBDMA_DESCRIPTORS) == 0) {
+		err("Can't get DAC DMA descriptors");
+		goto err_dma1;
+	}
+
+	if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN,
+	    DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) {
+		err("Can't get ADC DMA");
+		goto err_dma2;
+	}
+	au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16);
+	if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr,
+					NUM_DBDMA_DESCRIPTORS) == 0) {
+		err("Can't get ADC DMA descriptors");
+		goto err_dma2;
+	}
+
+	pr_info("DAC: DMA%d, ADC: DMA%d", DBDMA_AC97_TX_CHAN, DBDMA_AC97_RX_CHAN);
+
+	/* register devices */
+
+	if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)
+		goto err_dev1;
+	if ((s->codec->dev_mixer =
+	     register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
+		goto err_dev2;
+
+	/* The GPIO for the appropriate PSC was configured by the
+	 * board specific start up.
+	 *
+	 * configure PSC for AC'97
+	 */
+	au_writel(0, AC97_PSC_CTRL);	/* Disable PSC */
+	au_sync();
+	au_writel((PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE), AC97_PSC_SEL);
+	au_sync();
+
+	/* cold reset the AC'97
+	*/
+	au_writel(PSC_AC97RST_RST, PSC_AC97RST);
+	au_sync();
+	au1550_delay(10);
+	au_writel(0, PSC_AC97RST);
+	au_sync();
+
+	/* need to delay around 500msec(bleech) to give
+	   some CODECs enough time to wakeup */
+	au1550_delay(500);
+
+	/* warm reset the AC'97 to start the bitclk
+	*/
+	au_writel(PSC_AC97RST_SNC, PSC_AC97RST);
+	au_sync();
+	udelay(100);
+	au_writel(0, PSC_AC97RST);
+	au_sync();
+
+	/* Enable PSC
+	*/
+	au_writel(PSC_CTRL_ENABLE, AC97_PSC_CTRL);
+	au_sync();
+
+	/* Wait for PSC ready.
+	*/
+	do {
+		val = readl((void *)PSC_AC97STAT);
+		au_sync();
+	} while ((val & PSC_AC97STAT_SR) == 0);
+
+	/* Configure AC97 controller.
+	 * Deep FIFO, 16-bit sample, DMA, make sure DMA matches fifo size.
+	 */
+	val = PSC_AC97CFG_SET_LEN(16);
+	val |= PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8;
+
+	/* Enable device so we can at least
+	 * talk over the AC-link.
+	 */
+	au_writel(val, PSC_AC97CFG);
+	au_writel(PSC_AC97MSK_ALLMASK, PSC_AC97MSK);
+	au_sync();
+	val |= PSC_AC97CFG_DE_ENABLE;
+	au_writel(val, PSC_AC97CFG);
+	au_sync();
+
+	/* Wait for Device ready.
+	*/
+	do {
+		val = readl((void *)PSC_AC97STAT);
+		au_sync();
+	} while ((val & PSC_AC97STAT_DR) == 0);
+
+	/* codec init */
+	if (!ac97_probe_codec(s->codec))
+		goto err_dev3;
+
+	s->codec_base_caps = rdcodec(s->codec, AC97_RESET);
+	s->codec_ext_caps = rdcodec(s->codec, AC97_EXTENDED_ID);
+	pr_info("AC'97 Base/Extended ID = %04x/%04x",
+	     s->codec_base_caps, s->codec_ext_caps);
+
+	if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
+		/* codec does not support VRA
+		*/
+		s->no_vra = 1;
+	} else if (!vra) {
+		/* Boot option says disable VRA
+		*/
+		u16 ac97_extstat = rdcodec(s->codec, AC97_EXTENDED_STATUS);
+		wrcodec(s->codec, AC97_EXTENDED_STATUS,
+			ac97_extstat & ~AC97_EXTSTAT_VRA);
+		s->no_vra = 1;
+	}
+	if (s->no_vra)
+		pr_info("no VRA, interpolating and decimating");
+
+	/* set mic to be the recording source */
+	val = SOUND_MASK_MIC;
+	mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC,
+		     (unsigned long) &val);
+
+	return 0;
+
+ err_dev3:
+	unregister_sound_mixer(s->codec->dev_mixer);
+ err_dev2:
+	unregister_sound_dsp(s->dev_audio);
+ err_dev1:
+	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
+ err_dma2:
+	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
+ err_dma1:
+	release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
+
+	ac97_release_codec(s->codec);
+	return -1;
+}
+
+static void __devinit
+au1550_remove(void)
+{
+	struct au1550_state *s = &au1550_state;
+
+	if (!s)
+		return;
+	synchronize_irq();
+	au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
+	au1xxx_dbdma_chan_free(s->dma_dac.dmanr);
+	release_mem_region(CPHYSADDR(AC97_PSC_SEL), 0x30);
+	unregister_sound_dsp(s->dev_audio);
+	unregister_sound_mixer(s->codec->dev_mixer);
+	ac97_release_codec(s->codec);
+}
+
+static int __init
+init_au1550(void)
+{
+	return au1550_probe();
+}
+
+static void __exit
+cleanup_au1550(void)
+{
+	au1550_remove();
+}
+
+module_init(init_au1550);
+module_exit(cleanup_au1550);
+
+#ifndef MODULE
+
+static int __init
+au1550_setup(char *options)
+{
+	char           *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ","))) {
+		if (!*this_opt)
+			continue;
+		if (!strncmp(this_opt, "vra", 3)) {
+			vra = 1;
+		}
+	}
+
+	return 1;
+}
+
+__setup("au1550_audio=", au1550_setup);
+
+#endif /* MODULE */
diff -puN sound/oss/Kconfig~mips-amd-alchemy-update sound/oss/Kconfig
--- 25/sound/oss/Kconfig~mips-amd-alchemy-update	2005-01-29 11:26:00.242711024 -0800
+++ 25-akpm/sound/oss/Kconfig	2005-01-29 11:26:00.314700080 -0800
@@ -212,6 +212,14 @@ config SOUND_VRC5477
 	  integrated, multi-function controller chip for MIPS CPUs.  Works
 	  with the AC97 codec.
 
+config SOUND_AU1000
+	tristate "Au1000 Sound"
+	depends on SOUND_PRIME!=n && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SOUND
+
+config SOUND_AU1550_AC97
+	tristate "Au1550 AC97 Sound"
+	depends on SOUND_PRIME!=n && SOC_AU1550 && SOUND
+
 config SOUND_TRIDENT
 	tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
 	depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT
diff -puN sound/oss/Makefile~mips-amd-alchemy-update sound/oss/Makefile
--- 25/sound/oss/Makefile~mips-amd-alchemy-update	2005-01-29 11:26:00.243710872 -0800
+++ 25-akpm/sound/oss/Makefile	2005-01-29 11:26:00.312700384 -0800
@@ -64,6 +64,8 @@ endif
 obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
 obj-$(CONFIG_SOUND_ES1371)	+= es1371.o ac97_codec.o
 obj-$(CONFIG_SOUND_VRC5477)	+= nec_vrc5477.o ac97_codec.o
+obj-$(CONFIG_SOUND_AU1000)	+= au1000.o ac97_codec.o
+obj-$(CONFIG_SOUND_AU1550_AC97)	+= au1550_ac97.o ac97_codec.o
 obj-$(CONFIG_SOUND_ESSSOLO1)	+= esssolo1.o
 obj-$(CONFIG_SOUND_FUSION)	+= cs46xx.o ac97_codec.o
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
_
