diff -urN linux.old/drivers/block/Kconfig linux.dev/drivers/block/Kconfig
--- linux.old/drivers/block/Kconfig	2006-06-08 20:20:52.000000000 +0200
+++ linux.dev/drivers/block/Kconfig	2006-06-08 22:14:58.000000000 +0200
@@ -453,4 +453,12 @@
 	This driver provides Support for ATA over Ethernet block
 	devices like the Coraid EtherDrive (R) Storage Blade.
 
+config BLK_DEV_CF_MIPS
+	bool "CF slot of RB532 board"
+	depends on MIKROTIK_RB500
+	default y
+	help
+	  The Routerboard 532 has a CF slot on it. Enable the special block
+	  device driver for it.
+
 endmenu
diff -urN linux.old/drivers/block/rb500/ata.c linux.dev/drivers/block/rb500/ata.c
--- linux.old/drivers/block/rb500/ata.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.dev/drivers/block/rb500/ata.c	2006-06-09 01:58:40.000000000 +0200
@@ -0,0 +1,474 @@
+#include <linux/kernel.h>	/* printk() */
+#include <linux/module.h>	/* module to be loadable */
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>	/* request_mem_region() */
+#include <asm/unaligned.h>		/* ioremap() */
+#include <asm/io.h>		/* ioremap() */
+#include <asm/rc32434/rb.h>
+
+#include "ata.h"
+
+#define REQUEST_MEM_REGION 0
+#define DEBUG 1
+
+#if DEBUG
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define SECS	1000000		/* unit for wait_not_busy() is 1us */
+
+unsigned cf_head = 0;
+unsigned cf_cyl = 0;
+unsigned cf_spt = 0;
+unsigned cf_sectors = 0;
+static unsigned cf_block_size = 1;
+static void *baddr = 0;
+
+#define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET))
+
+
+static void cf_do_tasklet(unsigned long dev_l);
+
+
+static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev)
+{
+	writeb(val, dev->baddr + ATA_REG_OFFSET + reg);
+}
+
+static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev)
+{
+	return readb(dev->baddr + ATA_REG_OFFSET + reg);
+}
+
+static inline int get_gpio_bit(gpio_func ofs, struct cf_mips_dev *dev)
+{
+	return (gpio_get(ofs) >> dev->pin) & 1;
+}
+
+static inline void set_gpio_bit(int bit, gpio_func ofs, struct cf_mips_dev *dev)
+{
+	gpio_set(ofs, (1 << dev->pin), ((bit & 1) << dev->pin));
+}
+
+static inline int cfrdy(struct cf_mips_dev *dev)
+{
+	return get_gpio_bit(DATA, dev);
+}
+
+static inline void prepare_cf_irq(struct cf_mips_dev *dev)
+{
+	set_gpio_bit(1, ILEVEL, dev);	/* interrupt on cf ready (not busy) */
+	set_gpio_bit(0, ISTAT, dev); 	/* clear interrupt status */
+}
+
+static inline int cf_present(struct cf_mips_dev* dev)
+{
+	/* TODO: read and configure CIS into memory mapped mode
+	 * TODO:   parse CISTPL_CONFIG on CF+ cards to get base address (0x200)
+	 * TODO:   maybe adjust power saving setting for Hitachi Microdrive
+	 */
+	int i;
+
+	/* setup CFRDY GPIO as input */
+	set_gpio_bit(0, FUNC, dev);
+	set_gpio_bit(0, CFG, dev);
+
+	for (i = 0; i < 0x10; ++i) {
+		if (rareg(i,dev) != 0xff)
+			return 1;
+	}
+	return 0;
+}
+
+static inline int is_busy(struct cf_mips_dev *dev)
+{
+	return !cfrdy(dev);
+}
+
+static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev)
+{
+	int us_passed = 0;
+	if (wait_for_busy && !is_busy(dev)) {
+		/* busy must appear within 400ns,
+		 * but it may dissapear before we see it
+		 *  => must not wait for busy in a loop
+		 */
+		ndelay(400);
+	}
+
+	do {
+		if (us_passed)
+			udelay(1);	/* never reached in async mode */
+		if (!is_busy(dev)) {
+			if (us_passed > 1 * SECS) {
+				printk(KERN_WARNING "cf-mips:   not busy ok (after %dus)"
+				       ", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev));
+			}
+			return CF_TRANS_OK;
+		}
+		if (us_passed == 1 * SECS) {
+			printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us);
+		}
+		if (dev->async_mode) {
+			dev->to_timer.expires = jiffies + (to_us * HZ / SECS);
+			dev->irq_enable_time = jiffies;
+			prepare_cf_irq(dev);
+			if (is_busy(dev)) {
+				add_timer(&dev->to_timer);
+				enable_irq(dev->irq);
+				return CF_TRANS_IN_PROGRESS;
+			}
+			continue;
+		}
+		++us_passed;
+	} while (us_passed < to_us);
+
+	printk(KERN_ERR "cf-mips:  wait not busy timeout (%dus)"
+	       ", status 0x%02x, state %d\n",
+	       to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
+	return CF_TRANS_FAILED;
+}
+
+static irqreturn_t cf_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* While tasklet has not disabled irq, irq will be retried all the time
+	 * because of ILEVEL matching GPIO pin status => deadlock.
+	 * To avoid this, we change ILEVEL to 0.
+	 */
+	struct cf_mips_dev *dev=dev_id;
+	
+	set_gpio_bit(0, ILEVEL, dev);
+	set_gpio_bit(0, ISTAT, dev);
+	
+	del_timer(&dev->to_timer);
+	tasklet_schedule(&dev->tasklet);
+	return IRQ_HANDLED;
+}
+
+static int do_reset(struct cf_mips_dev *dev)
+{
+	printk(KERN_INFO "cf-mips: resetting..\n");
+
+	wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev);
+	udelay(1);		/* FIXME: how long should we wait here? */
+	wareg(0, ATA_REG_DC,dev);
+
+	return wait_not_busy(30 * SECS, 1,dev);
+}
+
+static int set_multiple(struct cf_mips_dev *dev)
+{
+	if (dev->block_size <= 1)
+		return CF_TRANS_OK;
+
+	wareg(dev->block_size, ATA_REG_SC,dev);
+	wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
+	wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
+
+	return wait_not_busy(10 * SECS, 1,dev);
+}
+
+static int set_cmd(struct cf_mips_dev *dev)
+{
+	//DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd);
+	// sector_count should be <=24 bits..
+	BUG_ON(dev->tsect_start>=0x10000000);
+	// This way, it addresses 2^24 * 512 = 128G
+
+	if (dev->tsector_count) {
+		wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev);
+		wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev);
+		wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev);
+		wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev);
+	}
+	wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA,
+	      ATA_REG_DH,dev);	/* select drive on all commands */
+	wareg(dev->tcmd, ATA_REG_CMD,dev);
+	return wait_not_busy(10 * SECS, 1,dev);
+}
+
+static int do_trans(struct cf_mips_dev *dev)
+{
+	int res;
+	unsigned st;
+	int transfered;
+	
+	//printk("do_trans: %d sectors left\n",dev->tsectors_left);
+	while (dev->tsectors_left) {
+		transfered = 0;
+
+		st = rareg(ATA_REG_ST,dev);
+		if (!(st & ATA_REG_ST_DRQ)) {
+			printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st);
+			if (st & ATA_REG_ST_ERR) {
+				int errId = rareg(ATA_REG_ERR,dev);
+				printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
+				       (dev->tread ? "read" : "write"), st, errId);
+			}
+			return CF_TRANS_FAILED;
+		}
+		do { /* Fill/read the buffer one block */
+			u32 *qbuf, *qend;
+			qbuf = (u32 *)dev->tbuf;
+			qend = qbuf + CF_SECT_SIZE / sizeof(u32);
+			if (dev->tread) {
+			    while (qbuf!=qend)
+				put_unaligned(*DBUF32,qbuf++);
+				//*(qbuf++) = *DBUF32;
+			}
+			else {
+			    while(qbuf!=qend)
+				*DBUF32 = get_unaligned(qbuf++);
+			}
+
+			dev->tsectors_left--;
+			dev->tbuf += CF_SECT_SIZE;
+			dev->tbuf_size -= CF_SECT_SIZE;
+			transfered++;
+		} while (transfered != dev->block_size && dev->tsectors_left > 0);
+
+		res = wait_not_busy(10 * SECS, 1,dev);
+		if (res != CF_TRANS_OK)
+			return res;
+	};
+
+	st = rareg(ATA_REG_ST,dev);
+	if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) {
+		if (st & ATA_REG_ST_DRQ) {
+			printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s"
+			       ", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st);
+		} else if (st & ATA_REG_ST_DWF) {
+			printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st);
+		} else {
+			int errId = rareg(ATA_REG_ERR,dev);
+			printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
+			       (dev->tread ? "read" : "write"), st, errId);
+		}
+		return CF_TRANS_FAILED;
+	}
+	return CF_TRANS_OK;
+}
+
+static int cf_do_state(struct cf_mips_dev *dev)
+{
+	int res;
+	switch (dev->tstate) {	/* fall through everywhere */
+	case TS_IDLE:
+		dev->tstate = TS_READY;
+		if (is_busy(dev)) {
+			dev->tstate = TS_AFTER_RESET;
+			res = do_reset(dev);
+			if (res != CF_TRANS_OK)
+				break;
+		}
+	case TS_AFTER_RESET:
+		if (dev->tstate == TS_AFTER_RESET) {
+			dev->tstate = TS_READY;
+			res = set_multiple(dev);
+			if (res != CF_TRANS_OK)
+				break;
+		}
+	case TS_READY:
+		dev->tstate = TS_CMD;
+		res = set_cmd(dev);
+		if (res != CF_TRANS_OK)
+			break;;
+	case TS_CMD:
+		dev->tstate = TS_TRANS;
+	case TS_TRANS:
+		res = do_trans(dev);
+		break;
+	default:
+		printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate);
+		return CF_TRANS_FAILED;
+	}
+	if (res != CF_TRANS_IN_PROGRESS)
+		dev->tstate = TS_IDLE;
+	return res;
+}
+
+static void cf_do_tasklet(unsigned long dev_l)
+{
+	struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
+	int res;
+
+	disable_irq(dev->irq);
+
+	if (dev->tstate == TS_IDLE)
+		return;		/* can happen when irq is first registered */
+
+#if 0
+	DEBUGP(KERN_WARNING "cf-mips:   not busy ok (tasklet)  status 0x%02x\n",
+	       (unsigned) rareg(ATA_REG_ST,dev));
+#endif
+
+	res = cf_do_state(dev);
+	if (res == CF_TRANS_IN_PROGRESS)
+		return;
+	cf_async_trans_done(dev,res);
+}
+
+static void cf_async_timeout(unsigned long dev_l)
+{
+	struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
+	disable_irq(dev->irq);
+	/* Perhaps send abort to the device? */
+	printk(KERN_ERR "cf-mips:  wait not busy timeout (%lus)"
+	       ", status 0x%02x, state %d\n",
+	       jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
+	dev->tstate = TS_IDLE;
+	cf_async_trans_done(dev,CF_TRANS_FAILED);
+}
+
+int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect, 
+	char* buffer, int is_write)
+{
+	BUG_ON(dev->tstate!=TS_IDLE);
+	if (nsect > ATA_MAX_SECT_PER_CMD) {
+		printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect);
+		return CF_TRANS_FAILED;
+	}
+	if (sector + nsect > dev->sectors) {
+		printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector);
+		return CF_TRANS_FAILED;
+	}
+	dev->tbuf = buffer;
+	dev->tbuf_size = nsect*512;
+	dev->tsect_start = sector;
+	dev->tsector_count = nsect;
+	dev->tsectors_left = dev->tsector_count;
+	dev->tread = (is_write)?0:1;
+	
+	dev->tcmd = (dev->block_size == 1 ?
+		(is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) :
+		(is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE));
+
+	return cf_do_state(dev);
+}
+
+static int do_identify(struct cf_mips_dev *dev)
+{
+	u16 sbuf[CF_SECT_SIZE >> 1];
+ 	int res;
+	char tstr[17]; //serial
+	BUG_ON(dev->tstate!=TS_IDLE);
+	dev->tbuf = (char *) sbuf;
+	dev->tbuf_size = CF_SECT_SIZE;
+	dev->tsect_start = 0;
+	dev->tsector_count = 0;
+	dev->tsectors_left = 1;
+	dev->tread = 1;
+	dev->tcmd = ATA_CMD_IDENTIFY_DRIVE;
+
+	DEBUGP(KERN_INFO "cf-mips: identify drive..\n");
+	res = cf_do_state(dev);
+	if (res == CF_TRANS_IN_PROGRESS) {
+		printk(KERN_ERR "cf-mips: BUG: async identify cmd\n");
+		return CF_TRANS_FAILED;
+	}
+	if (res != CF_TRANS_OK)
+		return 0;
+
+	dev->head = sbuf[3];
+	dev->cyl = sbuf[1];
+	dev->spt = sbuf[6];
+	dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8];
+	dev->dtype=sbuf[0];
+	memcpy(tstr,&sbuf[12],16);
+	tstr[16]=0;
+	printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n",
+	       (sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head,
+	       dev->spt, dev->sectors, dev->sectors >> 11,tstr);
+	return 1;
+}
+
+static void init_multiple(struct cf_mips_dev * dev)
+{
+	int res;
+	DEBUGP(KERN_INFO "cf-mips: detecting block size\n");
+
+	dev->block_size = 128;	/* max block size = 128 sectors (64KB) */
+	do {
+		wareg(dev->block_size, ATA_REG_SC,dev);
+		wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
+		wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
+
+		res = wait_not_busy(10 * SECS, 1,dev);
+		if (res != CF_TRANS_OK) {
+			printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n");
+			dev->block_size = 1;
+			return;
+		}
+		if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0)
+			break;
+		dev->block_size /= 2;
+	} while (dev->block_size > 1);
+
+	printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size);
+}
+
+int cf_init(struct cf_mips_dev *dev)
+{
+	tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev);
+	dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE);
+	if (!dev->baddr) {
+		printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n",
+		       (unsigned long) dev->base, CFDEV_BUF_SIZE);
+		return -EBUSY;
+	}
+
+	if (!cf_present(dev)) {
+		printk(KERN_WARNING "cf-mips: cf card not present\n");
+		iounmap(dev->baddr);
+		return -ENODEV;
+	}
+
+	if (do_reset(dev) != CF_TRANS_OK) {
+		printk(KERN_ERR "cf-mips: cf reset failed\n");
+		iounmap(dev->baddr);
+		return -EBUSY;
+	}
+
+	if (!do_identify(dev)) {
+		printk(KERN_ERR "cf-mips: cf identify failed\n");
+		iounmap(dev->baddr);
+		return -EBUSY;
+	}
+
+/*	set_apm_level(ATA_APM_WITH_STANDBY); */
+	init_multiple(dev);
+
+	init_timer(&dev->to_timer);
+	dev->to_timer.function = cf_async_timeout;
+	dev->to_timer.data = (unsigned long)dev;
+
+	prepare_cf_irq(dev);
+	if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) {
+		printk(KERN_ERR "cf-mips: failed to get irq\n");
+		iounmap(dev->baddr);
+		return -EBUSY;
+	}
+	/* Disable below would be odd, because request will enable, and the tasklet
+	  will disable it itself */
+	//disable_irq(dev->irq);
+	
+	dev->async_mode = 1;
+
+	return 0;
+}
+
+void cf_cleanup(struct cf_mips_dev *dev)
+{
+	iounmap(dev->baddr);
+	free_irq(dev->irq, NULL);
+#if REQUEST_MEM_REGION
+	release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE);
+#endif
+}
+
+
+/*eof*/
diff -urN linux.old/drivers/block/rb500/ata.h linux.dev/drivers/block/rb500/ata.h
--- linux.old/drivers/block/rb500/ata.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.dev/drivers/block/rb500/ata.h	2006-06-09 00:15:23.000000000 +0200
@@ -0,0 +1,132 @@
+#ifndef __CFMIPS_ATA_H__
+#define __CFMIPS_ATA_H__
+
+#include <linux/interrupt.h>
+
+#define CFG_DC_DEV1	(void*)0xb8010010
+#define   CFG_DC_DEVBASE	0x0
+#define   CFG_DC_DEVMASK	0x4
+#define   CFG_DC_DEVC		0x8
+#define   CFG_DC_DEVTC		0xC
+
+#define CFDEV_BUF_SIZE	0x1000
+#define ATA_CIS_OFFSET	0x200
+#define ATA_REG_OFFSET	0x800
+#define ATA_DBUF_OFFSET	0xC00
+
+#define ATA_REG_FEAT	0x1
+#define ATA_REG_SC	0x2
+#define ATA_REG_SN	0x3
+#define ATA_REG_CL	0x4
+#define ATA_REG_CH	0x5
+#define ATA_REG_DH	0x6
+#define   ATA_REG_DH_BASE	0xa0
+#define   ATA_REG_DH_LBA	0x40
+#define   ATA_REG_DH_DRV	0x10
+#define ATA_REG_CMD	0x7
+#define ATA_REG_ST	0x7
+#define   ATA_REG_ST_BUSY	0x80
+#define   ATA_REG_ST_RDY	0x40
+#define   ATA_REG_ST_DWF	0x20
+#define   ATA_REG_ST_DSC	0x10
+#define   ATA_REG_ST_DRQ	0x08
+#define   ATA_REG_ST_CORR	0x04
+#define   ATA_REG_ST_ERR	0x01
+#define ATA_REG_ERR	0xd
+#define ATA_REG_DC	0xe
+#define   ATA_REG_DC_IEN	0x02
+#define   ATA_REG_DC_SRST	0x04
+
+#define ATA_CMD_READ_SECTORS	0x20
+#define ATA_CMD_WRITE_SECTORS	0x30
+#define ATA_CMD_EXEC_DRIVE_DIAG	0x90
+#define ATA_CMD_READ_MULTIPLE	0xC4
+#define ATA_CMD_WRITE_MULTIPLE	0xC5
+#define ATA_CMD_SET_MULTIPLE	0xC6
+#define ATA_CMD_IDENTIFY_DRIVE	0xEC
+#define ATA_CMD_SET_FEATURES	0xEF
+
+#define ATA_FEATURE_ENABLE_APM	0x05
+#define ATA_FEATURE_DISABLE_APM	0x85
+#define ATA_APM_DISABLED	0x00
+#define ATA_APM_MIN_POWER	0x01
+#define ATA_APM_WITH_STANDBY	0x7f
+#define ATA_APM_WITHOUT_STANDBY	0x80
+#define ATA_APM_MAX_PERFORMANCE	0xfe
+
+#define CF_SECT_SIZE	0x200
+/* That is the ratio CF_SECT_SIZE/512 (the kernel sector size) */
+#define CF_KERNEL_MUL	1
+#define ATA_MAX_SECT_PER_CMD	0x100
+
+#define CF_TRANS_FAILED		0
+#define CF_TRANS_OK		1
+#define CF_TRANS_IN_PROGRESS	2
+
+
+enum trans_state {
+	TS_IDLE = 0,
+	TS_AFTER_RESET,
+	TS_READY,
+	TS_CMD,
+	TS_TRANS
+};
+
+// 
+// #if DEBUG
+// static unsigned long busy_time;
+// #endif
+
+/** Struct to hold the cfdev
+Actually, all the data here only has one instance. However, for 
+reasons of programming conformity, it is passed around as a pointer
+*/
+struct cf_mips_dev {
+	void *base; /* base address for I/O */
+	void *baddr; /* remapped address */
+
+	int pin; /* gpio pin */
+	int irq; /* gpio irq */
+	
+	unsigned head;
+	unsigned cyl;
+	unsigned spt;
+	unsigned sectors;
+	
+	unsigned short block_size;
+	unsigned dtype ; // ATA or CF
+	struct request_queue *queue;
+	struct gendisk  *gd;
+	
+	/* Transaction state */
+	enum trans_state tstate;
+	char *tbuf;
+	unsigned long tbuf_size;
+	sector_t tsect_start;
+	unsigned tsector_count;
+	unsigned tsectors_left;
+	int tread;
+	unsigned tcmd;
+	int async_mode;
+	unsigned long irq_enable_time;
+	
+	struct request *active_req; /* A request is being carried out. Is that different from tstate? */
+	int users;
+	struct timer_list to_timer;
+	struct tasklet_struct tasklet;
+
+	/** This lock ensures that the requests to this device are all done
+	atomically. Transfers can run in parallel, requests are all queued
+	one-by-one */
+	spinlock_t lock;
+};
+
+int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect, 
+	char* buffer, int is_write);
+int cf_init(struct cf_mips_dev* dev);
+void cf_cleanup(struct cf_mips_dev* dev);
+
+void cf_async_trans_done(struct cf_mips_dev* dev, int result);
+// void *cf_get_next_buf(unsigned long *buf_size);
+
+#endif
diff -urN linux.old/drivers/block/rb500/bdev.c linux.dev/drivers/block/rb500/bdev.c
--- linux.old/drivers/block/rb500/bdev.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.dev/drivers/block/rb500/bdev.c	2006-06-15 16:29:04.000000000 +0200
@@ -0,0 +1,340 @@
+/* CF-mips driver
+   This is a block driver for the direct (mmaped) interface to the CF-slot,
+   found in Routerboard.com's RB532 board
+   See SDK provided from routerboard.com.
+   
+   Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
+   Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
+
+   This work is redistributed under the terms of the GNU General Public License.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/hdreg.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <asm/rc32434/rb.h>
+
+#ifdef DEBUG
+#define DEBUGP printk
+#define DLEVEL 1
+#else
+#define DEBUGP(format, args...)
+#define DLEVEL 0
+#endif
+
+#define CF_MIPS_MAJOR 13
+#define MAJOR_NR	CF_MIPS_MAJOR
+#define CF_MAX_PART	16		/* max 15 partitions */
+
+#include "ata.h"
+
+//extern struct block_device_operations cf_bdops;
+
+// static struct hd_struct cf_parts[CF_MAX_PART];
+// static int cf_part_sizes[CF_MAX_PART];
+// static int cf_hsect_sizes[CF_MAX_PART];
+// static int cf_max_sectors[CF_MAX_PART];
+// static int cf_blksize_sizes[CF_MAX_PART];
+
+// static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+// volatile int cf_busy = 0;
+
+static struct request *active_req = NULL;
+
+static int cf_open (struct inode *, struct file *);
+static int cf_release (struct inode *, struct file *);
+static int cf_ioctl (struct inode *, struct file *, unsigned, unsigned long);
+
+static void cf_request(request_queue_t * q);
+static int cf_transfer(const struct request *req);
+
+/*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
+long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/
+// int (*direct_access) (struct block_device *, sector_t, unsigned long *);
+// int (*media_changed) (struct gendisk *);
+// int (*revalidate_disk) (struct gendisk *);
+
+static struct block_device_operations cf_bdops = {
+      .owner = THIS_MODULE,
+      .open = cf_open,
+      .release = cf_release,
+      .ioctl = cf_ioctl,
+      .media_changed = NULL,
+      .unlocked_ioctl = NULL,
+      .revalidate_disk = NULL,
+      .compat_ioctl = NULL,
+      .direct_access = NULL
+};
+
+
+int cf_mips_probe(struct platform_device *pdev)
+{
+	struct gendisk* cf_gendisk=NULL;
+	struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
+	struct cf_mips_dev *dev;
+	struct resource *r;
+	int reg_result;
+
+	reg_result = register_blkdev(MAJOR_NR, "cf-mips");
+	if (reg_result < 0) {
+		printk(KERN_WARNING "cf-mips: can't get major %d\n", MAJOR_NR);
+		return reg_result;
+	}
+
+	dev = (struct cf_mips_dev *)kmalloc(sizeof(struct cf_mips_dev),GFP_KERNEL);
+	if (!dev)
+		goto out_err;
+	memset(dev, 0, sizeof(struct cf_mips_dev));
+	cdev->dev = dev;
+	
+	dev->pin = cdev->gpio_pin;
+	dev->irq = platform_get_irq_byname(pdev, "cf_irq");
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cf_membase");
+	dev->base = (void *) r->start;
+	
+	if (cf_init(dev)) goto out_err;
+	printk("init done");
+	
+	spin_lock_init(&dev->lock);
+	dev->queue = blk_init_queue(cf_request,&dev->lock);
+	if (!dev->queue){
+		printk(KERN_ERR "cf-mips: no mem for queue\n");
+		goto out_err;
+	}
+	blk_queue_max_sectors(dev->queue,ATA_MAX_SECT_PER_CMD);
+
+	/* For memory devices, it is always better to avoid crossing segments
+	inside the same request. */
+/*	if (dev->dtype==0x848A){
+		printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1);
+		blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1);
+	}*/
+
+	dev->gd = alloc_disk(CF_MAX_PART);
+	cf_gendisk = dev->gd;
+	cdev->gd = dev->gd;
+	if (!cf_gendisk) goto out_err; /* Last of these goto's */
+	
+	cf_gendisk->major = MAJOR_NR;
+	cf_gendisk->first_minor = 0;
+	cf_gendisk->queue=dev->queue;
+	BUG_ON(cf_gendisk->minors != CF_MAX_PART);
+	strcpy(cf_gendisk->disk_name,"cfa");
+	strcpy(cf_gendisk->devfs_name,"cf/card0");
+	cf_gendisk->fops = &cf_bdops;
+	cf_gendisk->flags = 0 ; /* is not yet GENHD_FL_REMOVABLE */
+	cf_gendisk->private_data=dev;
+	
+	set_capacity(cf_gendisk,dev->sectors * CF_KERNEL_MUL);
+	
+	/* Let the disk go live */
+	add_disk(cf_gendisk);
+#if 0
+	result = cf_init();
+	
+	/* default cfg for all partitions */
+	memset(cf_parts, 0, sizeof (cf_parts[0]) * CF_MAX_PART);
+	memset(cf_part_sizes, 0, sizeof (cf_part_sizes[0]) * CF_MAX_PART);
+	for (i = 0; i < CF_MAX_PART; ++i) {
+		cf_hsect_sizes[i] = CF_SECT_SIZE;
+		cf_max_sectors[i] = ATA_MAX_SECT_PER_CMD;
+		cf_blksize_sizes[i] = BLOCK_SIZE;
+	}
+
+	/* setup info for whole disk (partition 0) */
+	cf_part_sizes[0] = cf_sectors / 2;
+	cf_parts[0].nr_sects = cf_sectors;
+
+	blk_size[MAJOR_NR] = cf_part_sizes;
+	blksize_size[MAJOR_NR] = cf_blksize_sizes;
+	max_sectors[MAJOR_NR] = cf_max_sectors;
+	hardsect_size[MAJOR_NR] = cf_hsect_sizes;
+	read_ahead[MAJOR_NR] = 8;	/* (4kB) */
+
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+
+	add_gendisk(&cf_gendisk);
+#endif
+// 	printk(KERN_INFO "cf-mips partition check: \n");
+// 	register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART,
+// 		      &cf_bdops, dev->sectors);
+	return 0;
+
+out_err:
+	if (dev->queue){
+		blk_cleanup_queue(dev->queue);
+	}
+	if (reg_result) {
+		unregister_blkdev(MAJOR_NR, "cf-mips");
+		return reg_result;
+	}
+	if (dev){
+		cf_cleanup(dev);
+		kfree(dev);
+	}
+	return 1;
+}
+
+static int
+cf_mips_remove(struct platform_device *pdev)
+{
+	struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
+	struct cf_mips_dev *dev = (struct cf_mips_dev *) cdev->dev;
+	
+	unregister_blkdev(MAJOR_NR, "cf-mips");
+	blk_cleanup_queue(dev->queue);
+
+	del_gendisk(dev->gd);
+	cf_cleanup(dev);
+	return 0;
+}
+
+
+static struct platform_driver cf_driver = {
+	.driver.name = "rb500-cf",
+	.probe = cf_mips_probe,
+	.remove = cf_mips_remove,
+};
+
+static int __init cf_mips_init(void)
+{
+	printk(KERN_INFO "cf-mips module loaded\n");
+	return platform_driver_register(&cf_driver);
+}
+
+static void cf_mips_cleanup(void)
+{
+	platform_driver_unregister(&cf_driver);
+	printk(KERN_INFO "cf-mips module removed\n");
+}
+
+module_init(cf_mips_init);
+module_exit(cf_mips_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR);
+
+
+static int cf_open(struct inode *inode, struct file *filp)
+{
+	struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data;
+	int minor = MINOR(inode->i_rdev);
+	
+	if (minor >= CF_MAX_PART)
+		return -ENODEV;
+	//DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor);
+	spin_lock(&dev->lock);
+	dev->users++;
+	spin_unlock(&dev->lock);
+	filp->private_data=dev;
+	
+	/* dirty workaround to set CFRDY GPIO as an input when some other
+	   program sets it as an output */
+	gpio_set(CFG, (1 << dev->pin), 0);
+	return 0;		/* success */
+}
+
+static int cf_release(struct inode *inode, struct file *filp)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data;
+	spin_lock(&dev->lock);
+	dev->users--;
+	spin_unlock(&dev->lock);
+	return 0;
+}
+
+static int cf_ioctl(struct inode *inode, struct file *filp,
+	 unsigned int cmd, unsigned long arg)
+{
+	unsigned minor = MINOR(inode->i_rdev);
+	struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data;
+
+	DEBUGP(KERN_INFO "cf_ioctl cmd %u\n", cmd);
+	switch (cmd) {
+	case BLKRRPART:	/* re-read partition table */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		printk(KERN_INFO "cf-mips partition check: \n");
+		register_disk(dev->gd);
+		return 0;
+
+	case HDIO_GETGEO:
+		{
+			struct hd_geometry geo;
+			geo.cylinders = dev->cyl;
+			geo.heads = dev->head;
+			geo.sectors = dev->spt;
+			geo.start = (*dev->gd->part)[minor].start_sect;
+			if (copy_to_user((void *) arg, &geo, sizeof (geo)))
+				return -EFAULT;
+		}
+		return 0;
+	}
+
+	return -EINVAL;		/* unknown command */
+}
+
+static void cf_request(request_queue_t * q)
+{
+	struct cf_mips_dev* dev;
+	
+	struct request * req;
+	int status;
+
+	/* We could have q->queuedata = dev , but haven't yet. */
+	if (active_req)
+		return;
+
+	while ((req=elv_next_request(q))!=NULL){
+		dev=req->rq_disk->private_data;
+		status=cf_transfer(req);
+		if (status==CF_TRANS_IN_PROGRESS){
+			active_req=req;
+			return;
+		}
+		end_request(req,status);
+	}
+}
+
+static int cf_transfer(const struct request *req)
+{
+	struct cf_mips_dev* dev=req->rq_disk->private_data;
+
+	if (!blk_fs_request(req)){	
+		if (printk_ratelimit())
+			printk(KERN_WARNING "cf-mips: skipping non-fs request 0x%x\n",req->cmd[0]);
+		return CF_TRANS_FAILED;
+	}
+	
+	return cf_do_transfer(dev,req->sector,req->current_nr_sectors,req->buffer,rq_data_dir(req));
+}
+
+void cf_async_trans_done(struct cf_mips_dev * dev,int result)
+{
+	struct request *req;
+	
+	spin_lock(&dev->lock);
+	req=active_req;
+	active_req=NULL;
+	end_request(req,result);
+	spin_unlock(&dev->lock);
+
+	spin_lock(&dev->lock);
+	cf_request(dev->queue);
+	spin_unlock(&dev->lock);
+}
+
diff -urN linux.old/drivers/block/rb500/Makefile linux.dev/drivers/block/rb500/Makefile
--- linux.old/drivers/block/rb500/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux.dev/drivers/block/rb500/Makefile	2006-06-08 22:14:58.000000000 +0200
@@ -0,0 +1,3 @@
+## Makefile for the RB532 CF port
+
+obj-y		+= bdev.o ata.o
diff -urN linux.old/drivers/Makefile linux.dev/drivers/Makefile
--- linux.old/drivers/Makefile	2006-06-08 20:20:52.000000000 +0200
+++ linux.dev/drivers/Makefile	2006-06-08 22:14:58.000000000 +0200
@@ -73,3 +73,4 @@
 obj-y				+= firmware/
 obj-$(CONFIG_CRYPTO)		+= crypto/
 obj-$(CONFIG_SUPERH)		+= sh/
+obj-$(CONFIG_BLK_DEV_CF_MIPS)	+= block/rb500/
\ No newline at end of file