diff -urN a/ar6000/hif/hif2.c b/ar6000/hif/hif2.c
--- a/ar6000/hif/hif2.c	2009-03-25 00:23:38.000000000 +0300
+++ b/ar6000/hif/hif2.c	2009-03-29 23:29:02.000000000 +0400
@@ -25,14 +25,26 @@
 #include <linux/sched.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+
+/*
+ * turn on GTA02 platform depened code.
+ * if you make driver for another, comment it.
+ */
+#define _GTA02_
+
+#ifdef _GTA02_
 #include <asm/gpio.h>
 #include <mach/gta02-pm-wlan.h>
+#include <mach/regs-gpio.h>
+#endif /* end _GTA02_ */
 
 #include "athdefs.h"
 #include "a_types.h"
 #include "hif.h"
 
+extern A_UINT32 onebitmode;
 
 /*
  * KNOWN BUGS:
@@ -86,6 +98,13 @@
 	struct sdio_func *func;
 
 	/*
+	 * SDIO irq process handle, for prevent claim/relese in irq call.
+	 * we must try not permit send any, not IRQ process necessary data,
+	 * while IRQ not completed.
+	 */
+	struct task_struct *irq_task;
+
+	/*
 	 * @@@ our sweet little bit of bogosity - the mechanism that lets us
 	 * use the SDIO stack from softirqs. This really wants to use skbs.
 	 */
@@ -109,14 +128,10 @@
 struct hif_request {
 	struct list_head list;
 	struct sdio_func *func;
-	int (*read)(struct sdio_func *func,
-	    void *dst, unsigned int addr, int count);
-	int (*write)(struct sdio_func *func,
-	    unsigned int addr, void *src, int count);
 	void *buf;
-	unsigned long addr;
-	int len;
-	A_STATUS (*completion)(void *context, A_STATUS status);
+	u32  addr;
+	u32  len;
+	u32  flags;
 	void *context;
 };
 
@@ -132,35 +147,95 @@
 /* ----- Request processing ------------------------------------------------ */
 
 
-#include <mach/regs-gpio.h>
-
 
-static A_STATUS process_request(struct hif_request *req)
+static A_STATUS \
+process_request(struct sdio_func *func, A_UCHAR *buff, A_UINT32 addr,
+                A_UINT32 len, A_UINT32 flags)
 {
-	int ret;
-	A_STATUS status;
+	u32 blksz, blocks, arg;
+	struct hif_device *hif;
+	struct mmc_card *card;
+	struct mmc_host *host;
+	struct {
+		struct mmc_request mrq;
+		struct mmc_command cmd;
+		struct mmc_data data;
+		struct scatterlist sg;
+	} req;
 
-	dev_dbg(&req->func->dev, "process_request(req %p)\n", req);
-	sdio_claim_host(req->func);
-	if (req->read) {
-		while (!s3c2410_gpio_getpin(S3C2410_GPE7)) {
-			printk(KERN_INFO "READ WHILE BUSY !\n");
-			yield();
-		}
-		ret = req->read(req->func, req->buf, req->addr, req->len);
+	/*
+	 * Next code based on: 'mmc_io_rw_extended' (mmc/core/sdio_ops.c),
+	 * but have shorten path and send small blocks not in byte mode.
+	 */
+
+	memset(&req, 0, sizeof(req));
+
+	req.mrq.cmd  = &req.cmd;
+	req.mrq.data = &req.data;
+
+	req.cmd.opcode = SD_IO_RW_EXTENDED;
+
+	arg  = (flags & HIF_WRITE) ? 0x80000000 : 0x00000000;
+	arg |= (func->num << 28);
+	arg |= (flags & HIF_INCREMENTAL_ADDRESS) ? 0x04000000 : 0x00000000;
+ 	arg |= (addr << 9);
+
+	if (flags & HIF_BYTE_BASIS) {
+		/* byte mode */
+		blksz  = len;
+		blocks = 1;
+		arg   |= blksz;
 	} else {
-		while (!s3c2410_gpio_getpin(S3C2410_GPE7)) {
-			printk(KERN_INFO "WRITE WHILE BUSY !\n");
-			yield();
+		/* block mode */
+		blksz  = HIF_MBOX_BLOCK_SIZE;
+		blocks = len / HIF_MBOX_BLOCK_SIZE;
+		arg   |= blocks | 0x08000000;
+	}
+
+	req.cmd.arg = arg;
+	req.cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+	req.data.blksz  = blksz;
+	req.data.blocks = blocks;
+	req.data.flags  = (flags & HIF_WRITE) ? MMC_DATA_WRITE : MMC_DATA_READ;
+	req.data.sg     = &req.sg;
+	req.data.sg_len = 1;
+
+	sg_init_one(&req.sg, buff, blksz * blocks);
+
+	card = func->card;
+	host = card->host;
+
+	mmc_set_data_timeout(&req.data, card);
+
+	hif = sdio_get_drvdata(func);
+
+	/* prevent claim in irq */
+	if (hif->irq_task != current)
+		sdio_claim_host(func);
+
+#ifdef _GTA02_
+	while (!s3c2410_gpio_getpin(S3C2410_GPE7)) {
+		printk(KERN_INFO "READ/WRITE WHILE BUSY !\n");
+		yield();
+#endif /* end _GTA02_ */
+
+	mmc_wait_for_req(host, &req.mrq);
+
+	/* prevent relese in irq */
+	if (hif->irq_task != current)
+		sdio_release_host(func);
+
+	if ((req.cmd.error) || (req.data.error))
+		return A_ERROR;
+
+	if (!(mmc_host_is_spi(host))) {
+		if (req.cmd.resp[0] & (R5_ERROR|R5_FUNCTION_NUMBER|R5_OUT_OF_RANGE)) {
+			return A_ERROR;
 		}
-		ret = req->write(req->func, req->addr, req->buf, req->len);
 	}
-	sdio_release_host(req->func);
-	status = ret ? A_ERROR : A_OK;
-	if (req->completion)
-		req->completion(req->context, status);
-	kfree(req);
-	return status;
+
+	return A_OK;
 }
 
 
@@ -241,7 +316,18 @@
 		}
 		finish_wait(&hif->wait, &wait);
 
-		(void) process_request(req);
+		{
+			A_STATUS status;
+			void *context;
+
+			status = process_request(req->func, req->buf, req->addr, 
+			                         req->len, req->flags);
+			context = req->context;
+
+			kfree(req);
+
+			htcCallbacks.rwCompletionHandler(context, status);
+		}
 	}
 	return 0;
 }
@@ -270,38 +356,25 @@
 		address += HIF_MBOX_WIDTH-length;
 	}
 
-	req = kzalloc(sizeof(*req), GFP_ATOMIC);
-	if (!req) {
-		if (request & HIF_ASYNCHRONOUS)
-			htcCallbacks.rwCompletionHandler(context, A_ERROR);
-		return A_ERROR;
+	if (!(request & HIF_ASYNCHRONOUS)) {
+		return process_request(hif->func, buffer, address, length, request);
 	}
 
-	req->func = hif->func;
-	req->addr = address;
-	req->buf = buffer;
-	req->len = length;
-
-	if (request & HIF_READ) {
-		if (request & HIF_FIXED_ADDRESS)
-			req->read = sdio_readsb;
-		else
-			req->read = sdio_memcpy_fromio;
-	} else {
-		if (request & HIF_FIXED_ADDRESS)
-			req->write = sdio_writesb;
-		else
-			req->write = sdio_memcpy_toio;
-	}
+	if ((req = kzalloc(sizeof(*req), GFP_ATOMIC))) {
+		req->func    = hif->func;
+		req->buf     = buffer;
+		req->addr    = address;
+		req->len     = length;
+		req->flags   = request;
+		req->context = context;
 
-	if (!(request & HIF_ASYNCHRONOUS))
-		return process_request(req);
+		enqueue_request(hif, req);
 
-	req->completion = htcCallbacks.rwCompletionHandler;
-	req->context = context;
-	enqueue_request(hif, req);
+		return A_OK;
+	}
 
-	return A_OK;
+	htcCallbacks.rwCompletionHandler(context, A_ERROR);
+	return A_ERROR;
 }
 
 
@@ -359,9 +432,11 @@
 	 *
 	 * Solution 2) is probably the best for now. Will try it later.
 	 */
-	sdio_release_host(func);
+
+	hif->irq_task = current;
 	ar6000_do_irq(func);
-	sdio_claim_host(func);
+	hif->irq_task = NULL;
+
 	in_interrupt = 0;
 }
 
@@ -454,8 +529,13 @@
 			mbs_cfg[i] = HIF_MBOX_START_ADDR(i);
 		break;
 	case HIF_DEVICE_GET_IRQ_PROC_MODE:
-		*ipm_cfg = HIF_DEVICE_IRQ_SYNC_ONLY;
-//		*ipm_cfg = HIF_DEVICE_IRQ_ASYNC_SYNC;
+		/*
+		 * WARN:
+		 * HIF_DEVICE_IRQ_ASYNC_SYNC in BUG list, but I not have it problem.
+		 * Need additional testing on different boards.
+		 */
+//		*ipm_cfg = HIF_DEVICE_IRQ_SYNC_ONLY;
+		*ipm_cfg = HIF_DEVICE_IRQ_ASYNC_SYNC;
 		break;
 	default:
 		return A_ERROR;
@@ -464,6 +544,55 @@
 }
 
 
+/*
+ * sdio_f0_writeb function allow write only to address range 0xF0...0xFF.
+ * this function is a copy of 'mmc_io_rw_direct' (mmc/core/sdio_ops.c)
+ * for leave out this restriction.
+ */
+static int sdio_rw_direct(struct mmc_card *card, int write, unsigned fn,
+	unsigned addr, u8 in, u8* out)
+{
+	struct mmc_command cmd;
+	int err;
+
+	BUG_ON(!card);
+	BUG_ON(fn > 7);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_IO_RW_DIRECT;
+	cmd.arg = write ? 0x80000000 : 0x00000000;
+	cmd.arg |= fn << 28;
+	cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
+	cmd.arg |= addr << 9;
+	cmd.arg |= in;
+	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err)
+		return err;
+
+	if (mmc_host_is_spi(card->host)) {
+		/* host driver already reported errors */
+	} else {
+		if (cmd.resp[0] & R5_ERROR)
+			return -EIO;
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+			return -EINVAL;
+		if (cmd.resp[0] & R5_OUT_OF_RANGE)
+			return -ERANGE;
+	}
+
+	if (out) {
+		if (mmc_host_is_spi(card->host))
+			*out = (cmd.resp[0] >> 8) & 0xFF;
+		else
+			*out = cmd.resp[0] & 0xFF;
+	}
+
+	return 0;
+}
+
 /* ----- Device probe and removal (Linux side) ----------------------------- */
 
 
@@ -476,6 +605,40 @@
 	dev_dbg(dev, "ar6000_do_activate\n");
 
 	sdio_claim_host(func);
+
+	if (onebitmode)
+	{
+		struct mmc_card *card;
+		struct mmc_host *host;
+		u8 ctrl;
+
+		/*
+		 * Init SDIO 1-wire mode.
+		 */
+		card = func->card;
+		host = card->host;
+
+		ret = sdio_rw_direct (card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
+		if (ret) {
+			dev_err(dev, "sdio_f0_readb (SDIO_CCCR_IF) returns %d\n",
+			        ret);
+			goto out_claimed;
+		}
+
+		ctrl &= ~(SDIO_BUS_WIDTH_4BIT|SDIO_BUS_WIDTH_1BIT);
+		ctrl |= SDIO_BUS_WIDTH_1BIT;
+
+		ret = sdio_rw_direct (card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
+		if (ret) {
+			dev_err(dev, "sdio_f0_writeb (SDIO_CCCR_IF) returns %d\n",
+			        ret);
+			goto out_claimed;
+		}
+
+		host->ios.bus_width = MMC_BUS_WIDTH_1;
+		host->ops->set_ios(host, &host->ios);
+	}
+
 	sdio_enable_func(func);
 
 	INIT_LIST_HEAD(&hif->queue);
@@ -531,6 +694,7 @@
 
 out_enabled:
 	sdio_disable_func(func);
+out_claimed:
 	sdio_release_host(func);
 
 	return ret;
@@ -568,6 +732,40 @@
 	sdio_claim_host(func);
 	sdio_release_irq(func);
 	sdio_disable_func(func);
+
+	if (onebitmode)
+	{
+		struct mmc_card *card;
+		struct mmc_host *host;
+		u8 ctrl;
+
+		/*
+		 * Release SDIO 1-wire mode,
+		 * or init back to SDIO 4-wire.
+		 */
+		card = func->card;
+		host = card->host;
+
+		ret = sdio_rw_direct (card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
+		if (ret) {
+			dev_err(dev, "sdio_f0_readb (SDIO_CCCR_IF) returns %d\n",
+			        ret);
+			ctrl = 0;
+		}
+
+		ctrl &= ~(SDIO_BUS_WIDTH_4BIT|SDIO_BUS_WIDTH_1BIT);
+		ctrl |= SDIO_BUS_WIDTH_4BIT;
+
+		ret = sdio_rw_direct (card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
+		if (ret) {
+			dev_err(dev, "sdio_f0_writeb (SDIO_CCCR_IF) returns %d\n",
+			        ret);
+		}
+
+		host->ios.bus_width = MMC_BUS_WIDTH_1;
+		host->ops->set_ios(host, &host->ios);
+	}
+
 	sdio_release_host(func);
 }
 
@@ -599,6 +797,7 @@
 }
 
 
+#ifdef _GTA02_
 static int ar6000_rfkill_cb(void *data, int on)
 {
 	struct hif_device *hif = data;
@@ -611,6 +810,7 @@
 	ar6000_deactivate(hif);
 	return 0;
 }
+#endif /* end _GTA02_ */
 
 
 static int sdio_ar6000_probe(struct sdio_func *func,
@@ -632,14 +832,20 @@
 	mutex_init(&hif->activate_lock);
 	hif->active = 0;
 
+#ifdef _GTA02_
 	if (gta02_wlan_query_rfkill_lock())
 		ret = ar6000_activate(hif);
 	if (!ret) {
 		gta02_wlan_set_rfkill_cb(ar6000_rfkill_cb, hif);
-		return 0;
+		goto _free;
 	}
 	gta02_wlan_query_rfkill_unlock();
+#else /* not _GTA02_ */
+	if (!(ret = ar6000_activate(hif)))
+		goto _free;
+#endif /* end _GTA02_ */
 	sdio_set_drvdata(func, NULL);
+_free:
 	kfree(hif);
 	return ret;
 }
@@ -651,7 +857,9 @@
 	HIF_DEVICE *hif = sdio_get_drvdata(func);
 
 	dev_dbg(dev, "sdio_ar6000_remove\n");
+#ifdef _GTA02_
 	gta02_wlan_clear_rfkill_cb();
+#endif /* end _GTA02_ */
 	ar6000_deactivate(hif);
 	sdio_set_drvdata(func, NULL);
 	kfree(hif);
@@ -660,18 +868,25 @@
 
 /* ----- Device registration/unregistration (called by HIF) ---------------- */
 
+/*
+ * define vendor/device IDs. Prefferd keep it in this file,
+ * while it is not will added to official linux kernel.
+ */
+#define SDIO_VENDOR_ID_ATHEROS          0x271
+#define SDIO_DEVICE_ID_ATHEROS_AR6001   0x100
+#define SDIO_DEVICE_ID_ATHEROS_AR6002   0x200
 
 #define ATHEROS_SDIO_DEVICE(id, offset) \
     SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_##id | (offset))
 
 static const struct sdio_device_id sdio_ar6000_ids[] = {
-	{ ATHEROS_SDIO_DEVICE(AR6000, 0)	},
-	{ ATHEROS_SDIO_DEVICE(AR6000, 0x1)	},
-	{ ATHEROS_SDIO_DEVICE(AR6000, 0x8)	},
-	{ ATHEROS_SDIO_DEVICE(AR6000, 0x9)	},
-	{ ATHEROS_SDIO_DEVICE(AR6000, 0xa)	},
-	{ ATHEROS_SDIO_DEVICE(AR6000, 0xb)	},
-	{ /* end: all zeroes */			},
+	{ ATHEROS_SDIO_DEVICE(AR6002, 0x0)	},
+	{ ATHEROS_SDIO_DEVICE(AR6002, 0x1)	},
+	{ ATHEROS_SDIO_DEVICE(AR6001, 0x8)	},
+	{ ATHEROS_SDIO_DEVICE(AR6001, 0x9)	},
+	{ ATHEROS_SDIO_DEVICE(AR6001, 0xa)	},
+	{ ATHEROS_SDIO_DEVICE(AR6001, 0xb)	},
+	{ /* end: all zeroes */			    },
 };
 
 MODULE_DEVICE_TABLE(sdio, sdio_ar6000_ids);
