Bläddra i källkod

update SDIO protocol

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1979 bbd45198-f89e-11dd-88c7-29a3b14d5316
luohui2320@gmail.com 13 år sedan
förälder
incheckning
dea9c19e5e

+ 13 - 2
bsp/at91sam9260/at91_mci.c

@@ -681,10 +681,10 @@ static void at91_mci_irq(int irq)
 		}
 
 		/*if (int_status & AT91_MCI_SDIOIRQA)
-			rt_mmcsd_signal_sdio_irq(host->mmc);
+			rt_mmcsd_signal_sdio_irq(host->mmc);*/
 
 		if (int_status & AT91_MCI_SDIOIRQB)
-			rt_mmcsd_signal_sdio_irq(host->mmc);*/
+			sdio_irq_wakeup(at_mci->host);
 
 		if (int_status & AT91_MCI_TXRDY)
 			mci_dbg("Ready to transmit\n");
@@ -778,10 +778,17 @@ static void at91_mci_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cf
 }
 
 
+static void at91_mci_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
+{
+	at91_mci_write(enable ? AT91_MCI_IER : AT91_MCI_IDR, AT91_MCI_SDIOIRQB);
+}
+
+
 static const struct rt_mmcsd_host_ops ops = {
 	at91_mci_request,
 	at91_mci_set_iocfg,
         RT_NULL,
+	at91_mci_enable_sdio_irq,
 };
 
 void at91_mci_detect(int irq)
@@ -834,6 +841,10 @@ rt_int32_t at91_mci_init(void)
 	host->freq_max = 25000000;
 	host->valid_ocr = VDD_32_33 | VDD_33_34;
 	host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE;
+	host->max_seg_size = 65535;
+	host->max_dma_segs = 2;
+	host->max_blk_size = 512;
+	host->max_blk_count = 4096;
 
 	at_mci->host = host;
 

+ 1 - 0
components/drivers/sdio/SConscript

@@ -6,6 +6,7 @@ src = Split("""
 block_dev.c
 mmcsd_core.c
 sd.c
+sdio.c
 """)
 
 # The set of source files associated with this SConscript file.

+ 3 - 3
components/drivers/sdio/block_dev.c

@@ -114,7 +114,7 @@ static rt_err_t rt_mmcsd_req_blk(struct rt_mmcsd_card *card, rt_uint32_t sector,
 	req.data = &data;
 	
 	cmd.arg = sector;
-	if (!(card->card_type & CARD_TYPE_SDHC)) 
+	if (!(card->flags & CARD_FLAG_SDHC)) 
 	{
 		cmd.arg <<= 9;
 	}
@@ -307,7 +307,7 @@ static rt_int32_t mmcsd_set_blksize(struct rt_mmcsd_card *card)
 	int err;
 
 	/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
-	if (card->card_type & CARD_TYPE_SDHC)
+	if (card->flags & CARD_FLAG_SDHC)
 		return 0;
 
 	mmcsd_host_lock(card->host);
@@ -412,7 +412,7 @@ rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card)
 
 					blk_dev->geometry.bytes_per_sector = 1<<9;
 					blk_dev->geometry.block_size = card->card_blksize;
-					if (card->card_type | CARD_TYPE_SDHC) 
+					if (card->flags & CARD_FLAG_SDHC) 
 					{
 						blk_dev->geometry.sector_count = (card->csd.c_size + 1) * 1024;
 					}

+ 44 - 8
components/drivers/sdio/mmcsd_card.h

@@ -16,6 +16,7 @@
 #define __MMCSD_CARD_H__
 
 #include "mmcsd_host.h"
+#include "sdio.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -61,6 +62,28 @@ struct rt_sd_scr {
 	rt_uint8_t		sd_bus_widths;
 };
 
+struct rt_sdio_cccr {
+	rt_uint8_t		sdio_version;
+	rt_uint8_t		sd_version;
+	rt_uint8_t		multi_block:1,
+				low_speed:1,
+				wide_bus:1,
+				high_power:1,
+				high_speed:1,
+				disable_cd:1;
+};
+
+struct rt_sdio_cis {
+	rt_uint16_t		manufacturer;
+	rt_uint16_t		product;
+	rt_uint16_t		func0_blk_size;
+	rt_uint32_t		max_tran_speed;
+};
+
+#define SDIO_MAX_FUNCTIONS		7
+
+
+
 struct rt_mmcsd_card {
 	struct rt_mmcsd_host *host;
 	rt_uint32_t	rca;		/* card addr */
@@ -73,16 +96,29 @@ struct rt_mmcsd_card {
 	rt_uint32_t	max_data_rate;	/* max data transfer rate */
 	rt_uint32_t	card_capacity;	/* card capacity, unit:KB */
 	rt_uint32_t	card_blksize;	/* card block size */
-	rt_uint32_t	card_type;
-#define CARD_TYPE_MMC		(1 << 0)	/* MMC card */
-#define CARD_TYPE_SD		(1 << 1)	/* SD card */
-#define CARD_TYPE_SDIO		(1 << 2)	/* SDIO card */
-#define CARD_TYPE_SDHC		(1 << 3)	/* SDHC card */
+	rt_uint16_t	card_type;
+#define CARD_TYPE_MMC                   0 /* MMC card */
+#define CARD_TYPE_SD                    1 /* SD card */
+#define CARD_TYPE_SDIO                  2 /* SDIO card */
+#define CARD_TYPE_SDIO_COMBO            3 /* SD combo (IO+mem) card */
+
+	rt_uint16_t flags;
+#define CARD_FLAG_HIGHSPEED  (1 << 0)   /* SDIO bus speed 50MHz */
+#define CARD_FLAG_SDHC       (1 << 1)   /* SDHC card */
+#define CARD_FLAG_SDXC       (1 << 2)   /* SDXC card */
+
 	struct rt_sd_scr	scr;
 	struct rt_mmcsd_csd	csd;
-	rt_uint32_t	hs_max_data_rate;	/* max data transfer rate in high speed mode */
-	rt_uint32_t	flags;
-#define CARD_MODE_HIGHSPEED	(1 << 0)
+	rt_uint32_t     hs_max_data_rate;  /* max data transfer rate in high speed mode */
+
+	rt_uint8_t      sdio_function_num;	/* totol number of SDIO functions */
+	struct rt_sdio_cccr    cccr;  /* common card info */
+	struct rt_sdio_cis     cis;  /* common tuple info */
+	struct rt_sdio_function *sdio_func0;
+	struct rt_sdio_function	*sdio_function[SDIO_MAX_FUNCTIONS]; /* SDIO functions (devices) */
+
+	//struct rt_sdio_function_tuple    *tuples;  /* tuples */
+
 };
 
 #ifdef __cplusplus

+ 33 - 0
components/drivers/sdio/mmcsd_cmd.h

@@ -93,6 +93,39 @@ extern "C" {
 #define SCR_SPEC_VER_1		1	/* Implements system specification 1.10 */
 #define SCR_SPEC_VER_2		2	/* Implements system specification 2.00 */
 
+
+/* SDIO commands                                          type  argument     response */
+#define SD_IO_SEND_OP_COND          5 /* bcr  [23:0] OCR         R4  */
+#define SD_IO_RW_DIRECT            52 /* ac   [31:0] See below   R5  */
+#define SD_IO_RW_EXTENDED          53 /* adtc [31:0] See below   R5  */
+
+
+/* CMD52 arguments */
+#define SDIO_ARG_CMD52_READ             (0<<31)
+#define SDIO_ARG_CMD52_WRITE            (1u<<31)
+#define SDIO_ARG_CMD52_FUNC_SHIFT       28
+#define SDIO_ARG_CMD52_FUNC_MASK        0x7
+#define SDIO_ARG_CMD52_RAW_FLAG         (1u<<27)
+#define SDIO_ARG_CMD52_REG_SHIFT        9
+#define SDIO_ARG_CMD52_REG_MASK         0x1ffff
+#define SDIO_ARG_CMD52_DATA_SHIFT       0
+#define SDIO_ARG_CMD52_DATA_MASK        0xff
+#define SDIO_R5_DATA(resp)            ((resp)[0] & 0xff)
+
+/* CMD53 arguments */
+#define SDIO_ARG_CMD53_READ             (0<<31)
+#define SDIO_ARG_CMD53_WRITE            (1u<<31)
+#define SDIO_ARG_CMD53_FUNC_SHIFT       28
+#define SDIO_ARG_CMD53_FUNC_MASK        0x7
+#define SDIO_ARG_CMD53_BLOCK_MODE       (1u<<27)
+#define SDIO_ARG_CMD53_INCREMENT        (1u<<26)
+#define SDIO_ARG_CMD53_REG_SHIFT        9
+#define SDIO_ARG_CMD53_REG_MASK         0x1ffff
+#define SDIO_ARG_CMD53_LENGTH_SHIFT     0
+#define SDIO_ARG_CMD53_LENGTH_MASK      0x1ff
+#define SDIO_ARG_CMD53_LENGTH_MAX       511
+
+
 #ifdef __cplusplus
 }
 #endif

+ 32 - 19
components/drivers/sdio/mmcsd_core.c

@@ -413,7 +413,7 @@ void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_ca
 {
 	rt_uint32_t mult;
 
-	if (card->card_type & CARD_TYPE_SDIO) 
+	if (card->card_type == CARD_TYPE_SDIO) 
 	{
 		data->timeout_ns = 1000000000;	/* SDIO card 1s */
 		data->timeout_clks = 0;
@@ -423,7 +423,7 @@ void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_ca
 	/*
 	 * SD cards use a 100 multiplier rather than 10
 	 */
-	mult = (card->card_type & CARD_TYPE_SD) ? 100 : 10;
+	mult = (card->card_type == CARD_TYPE_SD) ? 100 : 10;
 
 	/*
 	 * Scale up the multiplier (and therefore the timeout) by
@@ -438,7 +438,7 @@ void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_ca
 	/*
 	 * SD cards also have an upper limit on the timeout.
 	 */
-	if (card->card_type & CARD_TYPE_SD) 
+	if (card->card_type == CARD_TYPE_SD) 
 	{
 		rt_uint32_t timeout_us, limit_us;
 
@@ -458,7 +458,7 @@ void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_ca
 		/*
 		 * SDHC cards always use these fixed values.
 		 */
-		if (timeout_us > limit_us || card->card_type & CARD_TYPE_SDHC) 
+		if (timeout_us > limit_us || card->flags & CARD_FLAG_SDHC) 
 		{
 			data->timeout_ns = limit_us * 1000;	/* SDHC card fixed 250ms */
 			data->timeout_clks = 0;
@@ -576,24 +576,35 @@ void mmcsd_detect(void *param)
 	{
 		if (rt_mb_recv(&mmcsd_detect_mb, (rt_uint32_t*)&host, RT_WAITING_FOREVER) == RT_EOK)
 		{
-			mmcsd_host_lock(host);
-			mmcsd_power_up(host);
-			mmcsd_go_idle(host);
-
-			mmcsd_send_if_cond(host, host->valid_ocr);
-
-			/*
-			 * detect SD card
-			 */
-			err = mmcsd_send_app_op_cond(host, 0, &ocr);
-			if (!err) 
+			if (host->card == RT_NULL)
 			{
-				if (init_sd(host, ocr))
-					mmcsd_power_off(host);
+				mmcsd_host_lock(host);
+				mmcsd_power_up(host);
+				mmcsd_go_idle(host);
+
+				mmcsd_send_if_cond(host, host->valid_ocr);
+
+				err = sdio_io_send_op_cond(host, 0, &ocr);
+				if (!err) {
+					if (init_sdio(host, ocr))
+						mmcsd_power_off(host);
+					mmcsd_host_unlock(host);
+					continue;
+				}
+
+				/*
+				 * detect SD card
+				 */
+				err = mmcsd_send_app_op_cond(host, 0, &ocr);
+				if (!err) 
+				{
+					if (init_sd(host, ocr))
+						mmcsd_power_off(host);
+					mmcsd_host_unlock(host);
+					continue;
+				}
 				mmcsd_host_unlock(host);
-				continue;
 			}
-			mmcsd_host_unlock(host);
 		}
 	}
 }
@@ -641,4 +652,6 @@ void rt_mmcsd_core_init(void)
 	{
 		rt_thread_startup(&mmcsd_detect_thread);
 	}
+
+	rt_sdio_init();
 }

+ 12 - 0
components/drivers/sdio/mmcsd_core.h

@@ -66,6 +66,7 @@ struct rt_mmcsd_cmd {
 #define RESP_R4		(5 << 0)
 #define RESP_R6		(6 << 0)
 #define RESP_R7		(7 << 0)
+#define RESP_R5		(8 << 0)	/*SDIO command response type*/
 /*command types 
  *bits:4~5
  */
@@ -155,6 +156,17 @@ struct rt_mmcsd_req {
 
 #define CARD_BUSY	0x80000000	/* Card Power up status bit */
 
+/* R5 response bits */
+#define R5_COM_CRC_ERROR	(1 << 15)
+#define R5_ILLEGAL_COMMAND	(1 << 14)
+#define R5_ERROR			(1 << 11)
+#define R5_FUNCTION_NUMBER	(1 << 9)
+#define R5_OUT_OF_RANGE		(1 << 8)
+#define R5_STATUS(x)		(x & 0xCB00)
+#define R5_IO_CURRENT_STATE(x)	((x & 0x3000) >> 12)
+
+
+
 /**
  * fls - find last (most-significant) bit set
  * @x: the word to search

+ 13 - 0
components/drivers/sdio/mmcsd_host.h

@@ -59,6 +59,7 @@ struct rt_mmcsd_host_ops {
 	void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
 	void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
 	rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
+	void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
 };
 
 struct rt_mmcsd_host {
@@ -91,10 +92,22 @@ struct rt_mmcsd_host {
 #define MMCSD_MUTBLKWRITE	(1 << 2)
 #define MMCSD_HOST_IS_SPI	(1 << 3)
 #define controller_is_spi(host)	(host->flags & MMCSD_HOST_IS_SPI)
+#define MMCSD_SUP_SDIO_IRQ	(1 << 4)	/* support signal pending SDIO IRQs */
+#define MMCSD_SUP_HIGHSPEED	(1 << 5)	/* support high speed */
+
+	rt_uint32_t	max_seg_size;	/* maximum size of one dma segment */
+	rt_uint32_t	max_dma_segs;	/* maximum number of dma segments in one request */
+	rt_uint32_t	max_blk_size;   /* maximum block size */
+	rt_uint32_t	max_blk_count;  /* maximum block count */
+
 	rt_uint32_t   spi_use_crc;
 	struct rt_semaphore  bus_lock;
 	struct rt_semaphore  sem_ack;
 
+	rt_uint32_t       sdio_irq_num;
+	struct rt_semaphore    *sdio_irq_sem;
+	struct rt_thread     *sdio_irq_thread;
+
 	void *private_data;
 };
 

+ 4 - 4
components/drivers/sdio/sd.c

@@ -102,7 +102,7 @@ static rt_int32_t mmcsd_parse_csd(struct rt_mmcsd_card *card)
 	#endif
 		break;
 	case 1:
-		card->card_type |= CARD_TYPE_SDHC;
+		card->flags |= CARD_FLAG_SDHC;
 
 		/*This field is fixed to 0Eh, which indicates 1 ms. 
 		  The host should not use TAAC, NSAC, and R2W_FACTOR
@@ -187,7 +187,7 @@ static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
 	}
 
 	
-	if (!(card->card_type & CARD_TYPE_SD))
+	if (card->card_type != CARD_TYPE_SD)
 		goto err;
 	if (card->scr.sd_version < SCR_SPEC_VER_1)
 		goto err;
@@ -255,7 +255,7 @@ static rt_int32_t mmcsd_switch(struct rt_mmcsd_card *card)
 		goto err;
 	}
 
-	card->flags |= CARD_MODE_HIGHSPEED;
+	card->flags |= CARD_FLAG_HIGHSPEED;
 
 err:
 	rt_free_align(buf);
@@ -629,7 +629,7 @@ static rt_int32_t mmcsd_sd_init_card(struct rt_mmcsd_host *host, rt_uint32_t ocr
 	/* set bus speed */
 	max_data_rate = (unsigned int)-1;
 
-	if (card->flags & CARD_MODE_HIGHSPEED) 
+	if (card->flags & CARD_FLAG_HIGHSPEED) 
 	{
 		if (max_data_rate > card->hs_max_data_rate)
 			max_data_rate = card->hs_max_data_rate;

+ 1273 - 0
components/drivers/sdio/sdio.c

@@ -0,0 +1,1273 @@
+/*
+ * File      : sdio.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author		Notes
+ * 2012-01-13     weety		first version
+ */
+
+#include "mmcsd_core.h"
+#include "mmcsd_cmd.h"
+#include "list.h"
+
+#ifndef RT_SDIO_STACK_SIZE
+#define RT_SDIO_STACK_SIZE 512
+#endif
+#ifndef RT_SDIO_THREAD_PREORITY
+#define RT_SDIO_THREAD_PREORITY  0x40
+#endif
+
+static rt_list_t sdio_cards;
+static rt_list_t sdio_drivers;
+
+struct sdio_card {
+	struct rt_mmcsd_card *card;
+	rt_list_t  list;
+};
+
+struct sdio_driver {
+	struct rt_sdio_driver *drv;
+	rt_list_t  list;
+};
+
+#define MIN(a, b) (a < b ? a : b)
+
+static const rt_uint8_t speed_value[16] =
+	{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
+
+static const rt_uint32_t speed_unit[8] =
+	{ 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
+
+rt_int32_t sdio_io_send_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t 
+*cmd5_resp)
+{
+	struct rt_mmcsd_cmd cmd;
+	rt_int32_t i, err = 0;
+
+	RT_ASSERT(host != RT_NULL);
+
+	rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
+
+	cmd.cmd_code = SD_IO_SEND_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = RESP_SPI_R4 | RESP_R4 | CMD_BCR;
+
+	for (i = 100; i; i--) 
+	{
+		err = mmcsd_send_cmd(host, &cmd, 0);
+		if (err)
+			break;
+
+		/* if we're just probing, do a single pass */
+		if (ocr == 0)
+			break;
+
+		/* otherwise wait until reset completes */
+		if (controller_is_spi(host)) 
+		{
+			/*
+			 * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
+			 * an initialized card under SPI, but some cards
+			 * (Marvell's) only behave when looking at this
+			 * one.
+			 */
+			if (cmd.resp[1] & CARD_BUSY)
+				break;
+		} 
+		else 
+		{
+			if (cmd.resp[0] & CARD_BUSY)
+				break;
+		}
+
+		err = -RT_ETIMEOUT;
+
+		mmcsd_delay_ms(10);
+	}
+
+	if (cmd5_resp)
+		*cmd5_resp = cmd.resp[controller_is_spi(host) ? 1 : 0];
+
+	return err;
+}
+
+
+rt_int32_t sdio_io_rw_direct(struct rt_mmcsd_card *card, rt_int32_t rw, rt_uint32_t fn,
+	rt_uint32_t reg_addr, rt_uint8_t *pdata, rt_uint8_t raw)
+{
+	struct rt_mmcsd_cmd cmd;
+	rt_int32_t err;
+
+	RT_ASSERT(card != RT_NULL);
+	RT_ASSERT(fn <= SDIO_MAX_FUNCTIONS);
+
+	if (reg_addr & ~SDIO_ARG_CMD53_REG_MASK)
+		return -RT_ERROR;
+
+	rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
+
+	cmd.cmd_code = SD_IO_RW_DIRECT;
+	cmd.arg = rw ? SDIO_ARG_CMD52_WRITE : SDIO_ARG_CMD52_READ;
+	cmd.arg |= fn << SDIO_ARG_CMD52_FUNC_SHIFT;
+	cmd.arg |= raw ? SDIO_ARG_CMD52_RAW_FLAG : 0x00000000;
+	cmd.arg |= reg_addr << SDIO_ARG_CMD52_REG_SHIFT;
+	cmd.arg |= *pdata;
+	cmd.flags = RESP_SPI_R5 | RESP_R5 | CMD_AC;
+
+	err = mmcsd_send_cmd(card->host, &cmd, 0);
+	if (err)
+		return err;
+
+	if (!controller_is_spi(card->host)) 
+	{
+		if (cmd.resp[0] & R5_ERROR)
+			return -RT_EIO;
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+			return -RT_ERROR;
+		if (cmd.resp[0] & R5_OUT_OF_RANGE)
+			return -RT_ERROR;
+	}
+
+	if (!rw || raw) 
+	{
+		if (controller_is_spi(card->host))
+			*pdata = (cmd.resp[0] >> 8) & 0xFF;
+		else
+			*pdata = cmd.resp[0] & 0xFF;
+	}
+
+	return 0;
+}
+
+rt_int32_t sdio_io_rw_extended(struct rt_mmcsd_card *card, rt_int32_t rw, rt_uint32_t fn,
+	rt_uint32_t addr, rt_int32_t op_code, rt_uint8_t *buf, rt_uint32_t blocks, rt_uint32_t blksize)
+{
+	struct rt_mmcsd_req req;
+	struct rt_mmcsd_cmd cmd;
+	struct rt_mmcsd_data data;
+
+	RT_ASSERT(card != RT_NULL);
+	RT_ASSERT(fn <= SDIO_MAX_FUNCTIONS);
+	RT_ASSERT(blocks != 1 || blksize <= 512);
+	RT_ASSERT(blocks != 0);
+	RT_ASSERT(blksize != 0);
+
+	if (addr & ~SDIO_ARG_CMD53_REG_MASK)
+		return -RT_ERROR;
+
+	rt_memset(&req, 0, sizeof(struct rt_mmcsd_req));
+	rt_memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
+	rt_memset(&data, 0, sizeof(struct rt_mmcsd_data));
+
+	req.cmd = &cmd;
+	req.data = &data;
+
+	cmd.cmd_code = SD_IO_RW_EXTENDED;
+	cmd.arg = rw ? SDIO_ARG_CMD53_WRITE : SDIO_ARG_CMD53_READ;
+	cmd.arg |= fn << SDIO_ARG_CMD53_FUNC_SHIFT;
+	cmd.arg |= op_code ? SDIO_ARG_CMD53_INCREMENT : 0x00000000;
+	cmd.arg |= addr << SDIO_ARG_CMD53_REG_SHIFT;
+	if (blocks == 1 && blksize <= 512)
+		cmd.arg |= (blksize == 512) ? 0 : blksize;      /* byte mode */
+	else
+		cmd.arg |= SDIO_ARG_CMD53_BLOCK_MODE | blocks;  /* block mode */
+	cmd.flags = RESP_SPI_R5 | RESP_R5 | CMD_ADTC;
+
+	data.blksize = blksize;
+	data.blks = blocks;
+	data.flags = rw ? DATA_DIR_WRITE : DATA_DIR_READ;
+	data.buf = (rt_uint32_t *)buf;
+
+	mmcsd_set_data_timeout(&data, card);
+
+	mmcsd_send_request(card->host, &req);
+
+	if (cmd.err)
+		return cmd.err;
+	if (data.err)
+		return data.err;
+
+	if (!controller_is_spi(card->host)) 
+	{
+		if (cmd.resp[0] & R5_ERROR)
+			return -RT_EIO;
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+			return -RT_ERROR;
+		if (cmd.resp[0] & R5_OUT_OF_RANGE)
+			return -RT_ERROR;
+	}
+
+	return 0;
+}
+
+rt_inline rt_uint32_t sdio_max_block_size(struct rt_sdio_function *func)
+{
+	rt_uint32_t size = MIN(func->card->host->max_seg_size,
+			    func->card->host->max_blk_size);
+	size = MIN(size, func->max_blk_size);
+	return MIN(size, 512u); /* maximum size for byte mode */
+}
+
+static rt_int32_t sdio_io_rw_extended_block(struct rt_sdio_function *func, rt_int32_t rw,
+	rt_uint32_t addr, rt_int32_t op_code, rt_uint8_t *buf, rt_uint32_t len)
+{
+	rt_int32_t  ret;
+	rt_uint32_t left_size;
+	rt_uint32_t max_blks, blks;
+	
+	left_size = len;
+
+	/* Do the bulk of the transfer using block mode (if supported). */
+	if (func->card->cccr.multi_block && (len > sdio_max_block_size(func))) {
+		max_blks = MIN(func->card->host->max_blk_count,
+			func->card->host->max_seg_size / func->cur_blk_size);
+		max_blks = MIN(max_blks, 511u);
+
+		while (left_size > func->cur_blk_size) {
+
+			blks = left_size / func->cur_blk_size;
+			if (blks > max_blks)
+				blks = max_blks;
+			len = blks * func->cur_blk_size;
+
+			ret = sdio_io_rw_extended(func->card, rw, func->num, 
+				  addr, op_code, buf, blks, func->cur_blk_size);
+			if (ret)
+				return ret;
+
+			left_size -= len;
+			buf += len;
+			if (op_code)
+				addr += len;
+		}
+	}
+
+	while (left_size > 0) {
+		len = MIN(left_size, sdio_max_block_size(func));
+
+		ret = sdio_io_rw_extended(func->card, rw, func->num, 
+				  addr, op_code, buf, 1, len);
+		if (ret)
+			return ret;
+
+		left_size -= len;
+		buf += len;
+		if (op_code)
+			addr += len;
+	}
+
+	return 0;
+}
+
+
+rt_uint8_t sdio_io_readb(struct rt_sdio_function *func, 
+			 rt_uint32_t reg, rt_int32_t *err)
+{
+	rt_uint8_t data;
+	rt_int32_t ret;
+
+ 	ret = sdio_io_rw_direct(func->card, 0, func->num, reg, &data, 0);
+
+	if (err)
+	{
+		*err = ret;
+	}
+
+	return data;
+}
+
+rt_int32_t sdio_io_writeb(struct rt_sdio_function *func, 
+			  rt_uint32_t reg, rt_uint8_t data)
+{
+ 	return sdio_io_rw_direct(func->card, 1, func->num, reg, &data, 0);
+}
+
+rt_uint16_t sdio_io_readw(struct rt_sdio_function *func, rt_uint32_t addr, rt_int32_t *err)
+{
+	rt_int32_t ret;
+	rt_uint32_t dmabuf;
+
+	if (err)
+		*err = 0;
+
+	ret = sdio_io_rw_extended_block(func, 0, addr, 1, (rt_uint8_t *)&dmabuf, 2);
+	if (ret) 
+	{
+		if (err)
+			*err = ret;
+	}
+
+	return (rt_uint16_t)dmabuf;
+}
+
+rt_int32_t sdio_io_writew(struct rt_sdio_function *func, rt_uint16_t data, rt_uint32_t addr)
+{
+	rt_uint32_t dmabuf = data;
+
+	return sdio_io_rw_extended_block(func, 1, addr, 1, (rt_uint8_t *)&dmabuf, 2);
+}
+
+rt_int32_t sdio_io_read_multi_fifo_1(struct rt_sdio_function *func, 
+				     rt_uint32_t addr, rt_uint8_t *buf, rt_uint32_t len)
+{
+	return sdio_io_rw_extended_block(func, 0, addr, 0, buf, len);
+}
+
+rt_int32_t sdio_io_write_multi_fifo_1(struct rt_sdio_function *func, 
+				      rt_uint32_t addr, rt_uint8_t *buf, rt_uint32_t len)
+{
+	return sdio_io_rw_extended_block(func, 1, addr, 0, buf, len);
+}
+
+
+
+static rt_int32_t sdio_read_cccr(struct rt_mmcsd_card *card)
+{
+	rt_int32_t ret;
+	rt_int32_t cccr_version;
+	rt_uint8_t data;
+
+	rt_memset(&card->cccr, 0, sizeof(struct rt_sdio_cccr));
+
+	data = sdio_io_readb(card->sdio_func0, SDIO_REG_CCCR_CCCR_REV, &ret);
+	if (ret)
+		goto out;
+
+	cccr_version = data & 0x0f;
+
+	if (cccr_version > SDIO_CCCR_REV_1_20) 
+	{
+		rt_kprintf("unrecognised CCCR structure version %d\n", cccr_version);
+		return -RT_ERROR;
+	}
+
+	card->cccr.sdio_version = (data & 0xf0) >> 4;
+
+	data = sdio_io_readb(card->sdio_func0, SDIO_REG_CCCR_CARD_CAPS, &ret);
+	if (ret)
+		goto out;
+
+	if (data & SDIO_CCCR_CAP_SMB)
+		card->cccr.multi_block = 1;
+	if (data & SDIO_CCCR_CAP_LSC)
+		card->cccr.low_speed = 1;
+	if (data & SDIO_CCCR_CAP_4BLS)
+		card->cccr.wide_bus = 1;
+
+	if (cccr_version >= SDIO_CCCR_REV_1_10) 
+	{
+		data = sdio_io_readb(card->sdio_func0, SDIO_REG_CCCR_POWER_CTRL, &ret);
+		if (ret)
+			goto out;
+
+		if (data & SDIO_POWER_SMPC)
+			card->cccr.high_power = 1;
+	}
+
+	if (cccr_version >= SDIO_CCCR_REV_1_20) 
+	{
+		data = sdio_io_readb(card->sdio_func0, SDIO_REG_CCCR_SPEED, &ret);
+		if (ret)
+			goto out;
+
+		if (data & SDIO_SPEED_SHS)
+			card->cccr.high_speed = 1;
+	}
+
+out:
+	return ret;
+}
+
+static rt_int32_t cistpl_funce_func0(struct rt_mmcsd_card *card,
+			       const rt_uint8_t *buf, rt_uint32_t size)
+{
+	if (size < 0x04 || buf[0] != 0)
+		return -RT_ERROR;
+
+	/* TPLFE_FN0_BLK_SIZE */
+	card->cis.func0_blk_size = buf[1] | (buf[2] << 8);
+
+	/* TPLFE_MAX_TRAN_SPEED */
+	card->cis.max_tran_speed = speed_value[(buf[3] >> 3) & 15] *
+			    speed_unit[buf[3] & 7];
+
+	return 0;
+}
+
+static rt_int32_t cistpl_funce_func(struct rt_sdio_function *func,
+			     const rt_uint8_t *buf, rt_uint32_t size)
+{
+	rt_uint32_t version;
+	rt_uint32_t min_size;
+
+	version = func->card->cccr.sdio_version;
+	min_size = (version == SDIO_SDIO_REV_1_00) ? 28 : 42;
+
+	if (size < min_size || buf[0] != 1)
+		return -RT_ERROR;
+
+	/* TPLFE_MAX_BLK_SIZE */
+	func->max_blk_size = buf[12] | (buf[13] << 8);
+
+	/* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
+	if (version > SDIO_SDIO_REV_1_00)
+		func->enable_timeout_val = (buf[28] | (buf[29] << 8)) * 10;
+	else
+		func->enable_timeout_val = 1000; /* 1000ms */
+
+	return 0;
+}
+
+static rt_int32_t sdio_read_cis(struct rt_sdio_function *func)
+{
+	rt_int32_t ret;
+	struct rt_sdio_function_tuple *curr, **prev;
+	rt_uint32_t i, cisptr = 0;
+	rt_uint8_t data;
+	rt_uint8_t tpl_code, tpl_link;
+
+	struct rt_mmcsd_card *card = func->card;
+	struct rt_sdio_function *func0 = card->sdio_func0;
+
+	RT_ASSERT(func0 != RT_NULL);
+
+	for (i = 0; i < 3; i++)
+	{
+		data = sdio_io_readb(func, 
+			SDIO_REG_FBR_BASE(func->num) + SDIO_REG_FBR_CIS + i, &ret);
+		if (ret)
+			return ret;
+		cisptr |= data << (i * 8);
+	}
+
+	prev = &func->tuples;
+
+	do {
+		tpl_code = sdio_io_readb(func0, cisptr++, &ret);
+		if (ret)
+			break;
+		tpl_link = sdio_io_readb(func0, cisptr++, &ret);
+		if (ret)
+			break;
+
+		if ((tpl_code == CISTPL_END) || (tpl_link == 0xff))
+			break;
+
+		if (tpl_code == CISTPL_NULL)
+			continue;
+
+
+		curr = rt_malloc(sizeof(struct rt_sdio_function_tuple) + tpl_link);
+		if (!curr)
+			return -RT_ENOMEM;
+		curr->data = (rt_uint8_t *)curr + sizeof(struct rt_sdio_function_tuple);
+
+		for (i = 0; i < tpl_link; i++) 
+		{
+			curr->data[i] = sdio_io_readb(func0, cisptr + i, &ret);
+			if (ret)
+				break;
+		}
+		if (ret) 
+		{
+			rt_free(curr);
+			break;
+		}
+
+		switch (tpl_code)
+		{
+		case CISTPL_MANFID:
+			if (tpl_link < 4)
+			{
+				rt_kprintf("bad CISTPL_MANFID length\n");
+				break;
+			}
+			if (func->num != 0)
+			{
+				func->manufacturer = curr->data[0];
+				func->manufacturer = curr->data[1] << 8;
+				func->product = curr->data[2];
+				func->product = curr->data[3] << 8;
+			}
+			else
+			{
+				card->cis.manufacturer = curr->data[0];
+				card->cis.manufacturer = curr->data[1] << 8;
+				card->cis.product = curr->data[2];
+				card->cis.product = curr->data[3] << 8;
+			}
+			break;
+		case CISTPL_FUNCE:
+			if (func->num != 0)
+				ret = cistpl_funce_func(func, curr->data, tpl_link);
+			else
+				ret = cistpl_funce_func0(card, curr->data, tpl_link);
+
+			if (ret)
+			{
+				rt_kprintf("bad CISTPL_FUNCE size %u "
+				       "type %u\n", tpl_link, curr->data[0]);
+			}
+
+			break;
+		case CISTPL_VERS_1:
+			if (tpl_link < 2)
+			{
+				rt_kprintf("CISTPL_VERS_1 too short\n");
+			}
+			break;
+		default: 
+			/* this tuple is unknown to the core */
+			curr->next = RT_NULL;
+			curr->code = tpl_code;
+			curr->size = tpl_link;
+			*prev = curr;
+			prev = &curr->next;
+			rt_kprintf( "CIS tuple code %#x, length %d\n",
+			    tpl_code, tpl_link);
+			break;
+		}
+
+		cisptr += tpl_link;
+	} while (1);
+
+	/*
+	 * Link in all unknown tuples found in the common CIS so that
+	 * drivers don't have to go digging in two places.
+	 */
+	if (func->num != 0)
+		*prev = func0->tuples;
+
+	return ret;
+}
+
+
+void sdio_free_cis(struct rt_sdio_function *func)
+{
+	struct rt_sdio_function_tuple *tuple, *tmp;
+	struct rt_mmcsd_card *card = func->card;
+
+	tuple = func->tuples;
+
+	while (tuple && ((tuple != card->sdio_func0->tuples) || (!func->num))) 
+	{
+		tmp = tuple;
+		tuple = tuple->next;
+		rt_free(tmp);
+	}
+
+	func->tuples = RT_NULL;
+}
+
+
+
+static rt_int32_t sdio_read_fbr(struct rt_sdio_function *func)
+{
+	rt_int32_t ret;
+	rt_uint8_t data;
+
+	data = sdio_io_readb(func, 
+		SDIO_REG_FBR_BASE(func->num) + SDIO_REG_FBR_STD_FUNC_IF, &ret);
+	if (ret)
+		goto err;
+
+	data &= 0x0f;
+
+	if (data == 0x0f) 
+	{
+		data = sdio_io_readb(func, 
+			SDIO_REG_FBR_BASE(func->num) + SDIO_REG_FBR_STD_IF_EXT, &ret);
+		if (ret)
+			goto err;
+	}
+
+	func->func_code = data;
+
+err:
+	return ret;
+}
+
+
+static rt_int32_t sdio_initialize_function(struct rt_mmcsd_card *card, rt_uint32_t func_num)
+{
+	rt_int32_t ret;
+	struct rt_sdio_function *func;
+
+	RT_ASSERT(func_num <= SDIO_MAX_FUNCTIONS);
+
+	func = rt_malloc(sizeof(struct rt_sdio_function));
+	if (!func)
+	{
+		rt_kprintf("malloc rt_sdio_function failed\n");
+		ret = -RT_ENOMEM;
+		goto err;
+	}
+	rt_memset(func, 0, sizeof(struct rt_sdio_function));
+
+	func->num = func_num;
+
+	ret = sdio_read_fbr(func);
+	if (ret)
+		goto err1;
+
+	ret = sdio_read_cis(func);
+	if (ret)
+		goto err1;
+
+	card->sdio_function[func_num - 1] = func;
+
+	return 0;
+
+err1:
+	sdio_free_cis(func);
+	rt_free(func);
+	card->sdio_function[func_num - 1] = RT_NULL;
+err:
+	return ret;
+}
+
+
+static rt_int32_t sdio_set_highspeed(struct rt_mmcsd_card *card)
+{
+	rt_int32_t ret;
+	rt_uint8_t speed;
+
+	if (!(card->host->flags & MMCSD_SUP_HIGHSPEED))
+		return 0;
+
+	if (!card->cccr.high_speed)
+		return 0;
+
+	speed = sdio_io_readb(card->sdio_func0, SDIO_REG_CCCR_SPEED, &ret);
+	if (ret)
+		return ret;
+
+	speed |= SDIO_SPEED_EHS;
+
+	ret = sdio_io_writeb(card->sdio_func0, SDIO_REG_CCCR_SPEED, speed);
+	if (ret)
+		return ret;
+
+	card->flags |= CARD_FLAG_HIGHSPEED;
+
+	return 0;
+}
+
+static rt_int32_t sdio_set_bus_wide(struct rt_mmcsd_card *card)
+{
+	rt_int32_t ret;
+	rt_uint8_t busif;
+
+	if (!(card->host->flags & MMCSD_BUSWIDTH_4))
+		return 0;
+
+	if (card->cccr.low_speed && !card->cccr.wide_bus)
+		return 0;
+
+	busif = sdio_io_readb(card->sdio_func0, SDIO_REG_CCCR_BUS_IF, &ret);
+	if (ret)
+		return ret;
+
+	busif |= SDIO_BUS_WIDTH_4BIT;
+
+	ret = sdio_io_writeb(card->sdio_func0, SDIO_REG_CCCR_BUS_IF, busif);
+	if (ret)
+		return ret;
+
+	mmcsd_set_bus_width(card->host, MMCSD_BUS_WIDTH_4);
+
+	return 0;
+}
+
+
+static rt_int32_t sdio_register_card(struct rt_mmcsd_card *card)
+{
+	struct sdio_card *sc;
+
+	sc = rt_malloc(sizeof(struct sdio_card));
+	if (sc == RT_NULL)
+	{
+		rt_kprintf("malloc sdio card failed\n");
+		return -RT_ENOMEM;
+	}
+	list_insert_after(&sdio_cards, &sc->list);
+
+	return 0;
+}
+
+
+static rt_int32_t sdio_init_card(struct rt_mmcsd_host *host, rt_uint32_t ocr)
+{
+	rt_int32_t err = 0;
+	rt_int32_t i, function_num;
+	rt_uint32_t  cmd5_resp;
+	struct rt_mmcsd_card *card;
+
+	err = sdio_io_send_op_cond(host, ocr, &cmd5_resp);
+	if (err)
+		goto err;
+
+	if (controller_is_spi(host)) 
+	{
+		err = mmcsd_spi_use_crc(host, host->spi_use_crc);
+		if (err)
+			goto err;
+	}
+
+	function_num = (cmd5_resp & 0x70000000) >> 28;
+
+	card = rt_malloc(sizeof(struct rt_mmcsd_card));
+	if (!card) 
+	{
+		rt_kprintf("malloc card failed\n");
+		err = -RT_ENOMEM;
+		goto err;
+	}
+	rt_memset(card, 0, sizeof(struct rt_mmcsd_card));
+
+	card->card_type = CARD_TYPE_SDIO;
+	card->sdio_function_num = function_num;
+	card->host = host;
+	host->card = card;
+
+	card->sdio_func0 = rt_malloc(sizeof(struct rt_sdio_function));
+	if (!card->sdio_func0)
+	{
+		rt_kprintf("malloc sdio_func0 failed\n");
+		err = -RT_ENOMEM;
+		goto err1;
+	}
+	rt_memset(card->sdio_func0, 0, sizeof(struct rt_sdio_function));
+	card->sdio_func0->card = card;
+	card->sdio_func0->num = 0;
+
+	if (!controller_is_spi(host)) 
+	{
+		err = mmcsd_get_card_addr(host, &card->rca);
+		if (err)
+			goto err2;
+
+		mmcsd_set_bus_mode(host, MMCSD_BUSMODE_PUSHPULL);
+	}
+
+	if (!controller_is_spi(host)) 
+	{
+		err = mmcsd_select_card(card);
+		if (err)
+			goto err2;
+	}
+
+	err = sdio_read_cccr(card);
+	if (err)
+		goto err2;
+
+	err = sdio_read_cis(card->sdio_func0);
+	if (err)
+		goto err2;
+
+	err = sdio_set_highspeed(card);
+	if (err)
+		goto err2;
+
+	if (card->flags & CARD_FLAG_HIGHSPEED) 
+	{
+		mmcsd_set_clock(host, 50000000);
+	} 
+	else 
+	{
+		mmcsd_set_clock(host, card->cis.max_tran_speed);
+	}
+
+	err = sdio_set_bus_wide(card);
+	if (err)
+		goto err2;
+
+	for (i = 0; i < function_num; i++) 
+	{
+		err = sdio_initialize_function(card, i + 1);
+		if (err)
+			goto err3;
+	}
+
+
+	/* register sdio card */
+	err = sdio_register_card(card);
+	if (err)
+	{
+		goto err3;
+	}
+
+	return 0;
+
+err3:
+	if (host->card)
+	{
+		for (i = 0; i < host->card->sdio_function_num; i++)
+		{
+			if (host->card->sdio_function[i])
+			{
+				sdio_free_cis(host->card->sdio_function[i]);
+				rt_free(host->card->sdio_function[i]);
+				host->card->sdio_function[i] = RT_NULL;
+				rt_free(host->card);
+				host->card = RT_NULL;
+
+			}
+		}
+	}
+err2:
+	if (host->card && host->card->sdio_func0)
+	{
+		sdio_free_cis(host->card->sdio_func0);
+		rt_free(host->card->sdio_func0);
+		host->card->sdio_func0 = RT_NULL;
+	}
+err1:
+	if (host->card)
+	{
+		rt_free(host->card);
+	}
+err:
+ 	rt_kprintf("error %d while initialising SDIO card\n", err);
+	
+	return err;
+}
+
+
+
+rt_int32_t init_sdio(struct rt_mmcsd_host *host, rt_uint32_t ocr)
+{
+	rt_int32_t err;
+	rt_uint32_t  current_ocr;
+
+	RT_ASSERT(host != RT_NULL);
+
+	if (ocr & 0x7F) 
+	{
+		rt_kprintf("Card ocr below the defined voltage rang.\n");
+		ocr &= ~0x7F;
+	}
+
+	if (ocr & VDD_165_195) 
+	{
+		rt_kprintf("Can't support the low voltage SDIO card.\n");
+		ocr &= ~VDD_165_195;
+	}
+
+	current_ocr = mmcsd_select_voltage(host, ocr);
+
+	if (!current_ocr) 
+	{
+		err = -RT_ERROR;
+		goto err;
+	}
+
+	err = sdio_init_card(host, current_ocr);
+	if (err)
+		goto remove_card;
+
+	return 0;
+
+remove_card:
+	rt_free(host->card);
+	host->card = RT_NULL;
+err:
+
+	rt_kprintf("init SDIO card failed\n");
+
+	return err;
+
+	
+
+}
+
+
+static void sdio_irq_thread(void *param)
+{
+	rt_int32_t i, ret;
+	rt_uint8_t pending;
+	struct rt_mmcsd_card *card;
+	struct rt_mmcsd_host *host = (struct rt_mmcsd_host *)param;
+	RT_ASSERT(host != RT_NULL);
+	card = host->card;
+	RT_ASSERT(card != RT_NULL);
+
+	while (1) 
+	{
+		if (rt_sem_take(host->sdio_irq_sem, RT_WAITING_FOREVER) == RT_EOK)
+		{
+			mmcsd_host_lock(host);
+			pending = sdio_io_readb(host->card->sdio_func0, 
+						SDIO_REG_CCCR_INT_PEND, &ret);
+			if (ret) 
+			{
+				mmcsd_dbg("error %d reading SDIO_REG_CCCR_INT_PEND\n", ret);
+				goto out;
+			}
+
+			for (i = 1; i <= 7; i++) 
+			{
+				if (pending & (1 << i)) 
+				{
+					struct rt_sdio_function *func = card->sdio_function[i - 1];
+					if (!func) 
+					{
+						mmcsd_dbg("pending IRQ for "
+							"non-existant function %d\n", func->num);
+						goto out;
+					} 
+					else if (func->irq_handler) 
+					{
+						func->irq_handler(func);
+					} 
+					else 
+					{
+						mmcsd_dbg("pending IRQ with no register handler\n");
+						goto out;
+					}
+				}
+			}
+
+		out:
+			mmcsd_host_unlock(host);
+			if (host->flags & MMCSD_SUP_SDIO_IRQ)
+				host->ops->enable_sdio_irq(host, 1);
+			continue;
+		}
+	}
+}
+
+static rt_int32_t sdio_irq_thread_create(struct rt_mmcsd_card *card)
+{
+	struct rt_mmcsd_host *host = card->host;
+
+	/* init semaphore and create sdio irq processing thread */
+	if (!host->sdio_irq_num)
+	{
+		host->sdio_irq_num++;
+		host->sdio_irq_sem = rt_sem_create("sdio_irq", 0, RT_IPC_FLAG_FIFO);
+		RT_ASSERT(host->sdio_irq_sem != RT_NULL);
+
+		host->sdio_irq_thread = rt_thread_create("sdio_irq", sdio_irq_thread, host, 
+							 RT_SDIO_STACK_SIZE, RT_SDIO_THREAD_PREORITY, 20);
+		if (host->sdio_irq_thread != RT_NULL) 
+		{
+			rt_thread_startup(host->sdio_irq_thread);
+		}
+	}
+
+	return 0;
+}
+
+static rt_int32_t sdio_irq_thread_delete(struct rt_mmcsd_card *card)
+{
+	struct rt_mmcsd_host *host = card->host;
+
+	RT_ASSERT(host->sdio_irq_num > 0);
+
+	host->sdio_irq_num--;
+	if (!host->sdio_irq_num) 
+	{
+		if (host->flags & MMCSD_SUP_SDIO_IRQ)
+				host->ops->enable_sdio_irq(host, 0);
+		rt_sem_delete(host->sdio_irq_sem);
+		host->sdio_irq_sem = RT_NULL;
+		rt_thread_delete(host->sdio_irq_thread);
+		host->sdio_irq_thread = RT_NULL;
+	}
+
+	return 0;
+}
+
+
+rt_int32_t sdio_attach_irq(struct rt_sdio_function *func, rt_sdio_irq_handler_t *handler)
+{
+	rt_int32_t ret;
+	rt_uint8_t reg;
+
+	RT_ASSERT(func != RT_NULL);
+	RT_ASSERT(func->card != RT_NULL);
+
+	mmcsd_dbg("SDIO: enabling IRQ for function %d\n", func->num);
+
+	if (func->irq_handler) 
+	{
+		mmcsd_dbg("SDIO: IRQ for already in use.\n");
+		return -RT_EBUSY;
+	}
+
+	reg = sdio_io_readb(func, SDIO_REG_CCCR_INT_EN, &ret);
+	if (ret)
+		return ret;
+
+	reg |= 1 << func->num;
+
+	reg |= 1; /* Master interrupt enable */
+
+	ret = sdio_io_writeb(func, SDIO_REG_CCCR_INT_EN, reg);
+	if (ret)
+		return ret;
+
+	func->irq_handler = handler;
+
+	ret = sdio_irq_thread_create(func->card);
+	if (ret)
+		func->irq_handler = RT_NULL;
+
+	return ret;
+}
+
+rt_int32_t sdio_detach_irq(struct rt_sdio_function *func)
+{
+	rt_int32_t ret;
+	rt_uint8_t reg;
+
+	RT_ASSERT(func != RT_NULL);
+	RT_ASSERT(func->card != RT_NULL);
+
+	mmcsd_dbg("SDIO: disabling IRQ for function %d\n", func->num);
+
+	if (func->irq_handler) 
+	{
+		func->irq_handler = RT_NULL;
+		sdio_irq_thread_delete(func->card);
+	}
+
+	reg = sdio_io_readb(func, SDIO_REG_CCCR_INT_EN, &ret);
+	if (ret)
+		return ret;
+
+	reg &= ~(1 << func->num);
+
+	/* Disable master interrupt with the last function interrupt */
+	if (!(reg & 0xFE))
+		reg = 0;
+
+	ret = sdio_io_writeb(func, SDIO_REG_CCCR_INT_EN, reg);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void sdio_irq_wakeup(struct rt_mmcsd_host *host)
+{
+	host->ops->enable_sdio_irq(host, 0);
+	rt_sem_release(host->sdio_irq_sem);
+}
+
+
+rt_int32_t sdio_enable_func(struct rt_sdio_function *func)
+{
+	rt_int32_t ret;
+	rt_uint8_t reg;
+	rt_uint32_t timeout;
+
+	RT_ASSERT(func != RT_NULL);
+	RT_ASSERT(func->card != RT_NULL);
+
+	mmcsd_dbg("SDIO: enabling function %d\n", func->num);
+
+	reg = sdio_io_readb(func, SDIO_REG_CCCR_IO_EN, &ret);
+	if (ret)
+		goto err;
+
+	reg |= 1 << func->num;
+
+	ret = sdio_io_writeb(func, SDIO_REG_CCCR_IO_EN, reg);
+	if (ret)
+		goto err;
+
+	timeout = rt_tick_get() + func->enable_timeout_val * 1000 / RT_TICK_PER_SECOND;
+
+	while (1) 
+	{
+		reg = sdio_io_readb(func, SDIO_REG_CCCR_IO_RDY, &ret);
+		if (ret)
+			goto err;
+		if (reg & (1 << func->num))
+			break;
+		ret = -RT_ETIMEOUT;
+		if (rt_tick_get() > timeout)
+			goto err;
+	}
+
+	mmcsd_dbg("SDIO: enabled function successfull\n");
+
+	return 0;
+
+err:
+	mmcsd_dbg("SDIO: failed to enable function %d\n", func->num);
+	return ret;
+}
+
+
+rt_int32_t sdio_disable_func(struct rt_sdio_function *func)
+{
+	rt_int32_t ret;
+	rt_uint8_t reg;
+
+	RT_ASSERT(func != RT_NULL);
+	RT_ASSERT(func->card != RT_NULL);
+
+	mmcsd_dbg("SDIO: disabling function %d\n", func->num);
+
+	reg =  sdio_io_readb(func, SDIO_REG_CCCR_IO_EN, &ret);
+	if (ret)
+		goto err;
+
+	reg &= ~(1 << func->num);
+
+	ret = sdio_io_writeb(func, SDIO_REG_CCCR_IO_EN, reg);
+	if (ret)
+		goto err;
+
+	mmcsd_dbg("SDIO: disabled function successfull\n");
+
+	return 0;
+
+err:
+	mmcsd_dbg("SDIO: failed to disable function %d\n", func->num);
+	return -RT_EIO;
+}
+
+rt_int32_t sdio_set_block_size(struct rt_sdio_function *func, rt_uint32_t blksize)
+{
+	rt_int32_t ret;
+
+	if (blksize > func->card->host->max_blk_size)
+		return -RT_ERROR;
+
+	if (blksize == 0) 
+	{
+		blksize = MIN(func->max_blk_size, func->card->host->max_blk_size);
+		blksize = MIN(blksize, 512u);
+	}
+
+	ret = sdio_io_writeb(func, SDIO_REG_FBR_BASE(func->num) + SDIO_REG_FBR_BLKSIZE, 
+			     blksize & 0xff);
+	if (ret)
+		return ret;
+	ret = sdio_io_writeb(func, SDIO_REG_FBR_BASE(func->num) + SDIO_REG_FBR_BLKSIZE + 1, 
+			     (blksize >> 8) & 0xff);
+	if (ret)
+		return ret;
+	func->cur_blk_size = blksize;
+
+	return 0;
+}
+
+
+rt_inline rt_int32_t sdio_match_function(struct rt_sdio_function *func,
+	const struct rt_sdio_device_id *id)
+{
+	if (id->func_code != SDIO_ANY_FUNC_ID && id->func_code != func->func_code)
+		return 0;
+	if (id->manufacturer != SDIO_ANY_MAN_ID && id->manufacturer != func->manufacturer)
+		return 0;
+	if (id->product != SDIO_ANY_PROD_ID && id->product != func->product)
+		return 0;
+
+	return 1;
+}
+
+static struct rt_sdio_function *sdio_match_driver(struct rt_sdio_device_id *id)
+{
+	rt_uint32_t fn;
+	rt_list_t *l;
+	struct sdio_card *sc;
+	struct rt_mmcsd_card *card;
+
+	for (l = (&sdio_cards)->next; l != &sdio_cards; l = l->next)
+	{
+		sc = (struct sdio_card *)list_entry(l, struct sdio_card, list);
+		card = sc->card;
+		for (fn = 0; fn < card->sdio_function_num; fn++)
+		{
+			if (sdio_match_function(card->sdio_function[fn], id))
+			{
+				return card->sdio_function[fn];
+			}
+		}
+	}
+
+	return RT_NULL;
+}
+
+rt_int32_t sdio_register_driver(struct rt_sdio_driver *driver)
+{
+	struct sdio_driver *sd;
+	struct rt_sdio_function *func;
+
+	sd = rt_malloc(sizeof(struct sdio_driver));
+	if (sd == RT_NULL)
+	{
+		rt_kprintf("malloc sdio driver failed\n");
+		return -RT_ENOMEM;
+	}
+
+	list_insert_after(&sdio_drivers, &sd->list);
+
+	if (!list_isempty(&sdio_cards))
+	{
+		func = sdio_match_driver(driver->id);
+		if (func != RT_NULL)
+		{
+			driver->probe(func);
+		}
+	}
+
+	return 0;
+}
+
+rt_int32_t sdio_unregister_driver(struct rt_sdio_driver *driver)
+{
+	rt_list_t *l;
+	struct sdio_driver *sd = RT_NULL;
+	struct rt_sdio_function *func;
+
+
+	list_insert_after(&sdio_drivers, &sd->list);
+
+	for (l = (&sdio_drivers)->next; l != &sdio_drivers; l = l->next)
+	{
+		sd = (struct sdio_driver *)list_entry(l, struct sdio_driver, list);
+		if (sd->drv != driver)
+		{
+			sd = RT_NULL;
+		}
+	}
+
+	if (sd == RT_NULL)
+	{
+		rt_kprintf("SDIO driver %s not register\n", driver->name);
+		return -RT_ERROR;
+	}
+
+	if (!list_isempty(&sdio_cards))
+	{
+		func = sdio_match_driver(driver->id);
+		if (func != RT_NULL)
+		{
+			driver->remove(func);
+			list_remove(&sd->list);
+			rt_free(sd);
+		}
+	}
+
+	return 0;
+}
+
+
+void rt_sdio_init(void)
+{
+	list_init(&sdio_cards);
+	list_init(&sdio_drivers);
+}
+

+ 227 - 0
components/drivers/sdio/sdio.h

@@ -0,0 +1,227 @@
+/*
+ * File      : sdio.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author		Notes
+ * 2012-01-15     weety		first version
+ */
+
+
+#ifndef __SDIO_H__
+#define __SDIO_H__
+
+
+#include <rtthread.h>
+#include "mmcsd_host.h"
+#include "mmcsd_card.h"
+#include "sdio_func_ids.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rt_sdio_function;
+
+typedef void (rt_sdio_irq_handler_t)(struct rt_sdio_function *);
+
+/*
+ * SDIO function CIS tuple (unknown to the core)
+ */
+struct rt_sdio_function_tuple {
+	struct rt_sdio_function_tuple *next;
+	rt_uint8_t code;
+	rt_uint8_t size;
+	rt_uint8_t *data;
+};
+
+/*
+ * SDIO function devices
+ */
+struct rt_sdio_function {
+	struct rt_mmcsd_card		*card;		/* the card this device belongs to */
+	rt_sdio_irq_handler_t	*irq_handler;	/* IRQ callback */
+	rt_uint8_t		num;		/* function number */
+
+	rt_uint8_t		func_code;   /*  Standard SDIO Function interface code  */
+	rt_uint16_t		manufacturer;		/* manufacturer id */
+	rt_uint16_t		product;		/* product id */
+
+	rt_uint32_t		max_blk_size;	/* maximum block size */
+	rt_uint32_t		cur_blk_size;	/* current block size */
+
+	rt_uint32_t		enable_timeout_val; /* max enable timeout in msec */
+
+	struct rt_sdio_function_tuple *tuples;
+};
+
+/*
+ * Card Common Control Registers (CCCR)
+ */
+
+#define SDIO_REG_CCCR_CCCR_REV		0x00
+
+#define  SDIO_CCCR_REV_1_00	0	/* CCCR/FBR Version 1.00 */
+#define  SDIO_CCCR_REV_1_10	1	/* CCCR/FBR Version 1.10 */
+#define  SDIO_CCCR_REV_1_20	2	/* CCCR/FBR Version 1.20 */
+
+#define  SDIO_SDIO_REV_1_00	0	/* SDIO Spec Version 1.00 */
+#define  SDIO_SDIO_REV_1_10	1	/* SDIO Spec Version 1.10 */
+#define  SDIO_SDIO_REV_1_20	2	/* SDIO Spec Version 1.20 */
+#define  SDIO_SDIO_REV_2_00	3	/* SDIO Spec Version 2.00 */
+
+#define SDIO_REG_CCCR_SD_REV		0x01
+
+#define  SDIO_SD_REV_1_01	0	/* SD Physical Spec Version 1.01 */
+#define  SDIO_SD_REV_1_10	1	/* SD Physical Spec Version 1.10 */
+#define  SDIO_SD_REV_2_00	2	/* SD Physical Spec Version 2.00 */
+
+#define SDIO_REG_CCCR_IO_EN		0x02
+#define SDIO_REG_CCCR_IO_RDY		0x03
+
+#define SDIO_REG_CCCR_INT_EN		0x04	/* Function/Master Interrupt Enable */
+#define SDIO_REG_CCCR_INT_PEND		0x05	/* Function Interrupt Pending */
+
+#define SDIO_REG_CCCR_IO_ABORT		0x06	/* function abort/card reset */
+
+#define SDIO_REG_CCCR_BUS_IF		0x07	/* bus interface controls */
+
+#define  SDIO_BUS_WIDTH_1BIT	0x00
+#define  SDIO_BUS_WIDTH_4BIT	0x02
+#define  SDIO_BUS_ECSI		0x20	/* Enable continuous SPI interrupt */
+#define  SDIO_BUS_SCSI		0x40	/* Support continuous SPI interrupt */
+
+#define  SDIO_BUS_ASYNC_INT	0x20
+
+#define  SDIO_BUS_CD_DISABLE     0x80	/* disable pull-up on DAT3 (pin 1) */
+
+#define SDIO_REG_CCCR_CARD_CAPS		0x08
+
+#define  SDIO_CCCR_CAP_SDC	0x01	/* can do CMD52 while data transfer */
+#define  SDIO_CCCR_CAP_SMB	0x02	/* can do multi-block xfers (CMD53) */
+#define  SDIO_CCCR_CAP_SRW	0x04	/* supports read-wait protocol */
+#define  SDIO_CCCR_CAP_SBS	0x08	/* supports suspend/resume */
+#define  SDIO_CCCR_CAP_S4MI	0x10	/* interrupt during 4-bit CMD53 */
+#define  SDIO_CCCR_CAP_E4MI	0x20	/* enable ints during 4-bit CMD53 */
+#define  SDIO_CCCR_CAP_LSC	0x40	/* low speed card */
+#define  SDIO_CCCR_CAP_4BLS	0x80	/* 4 bit low speed card */
+
+#define SDIO_REG_CCCR_CIS_PTR		0x09	/* common CIS pointer (3 bytes) */
+
+/* Following 4 regs are valid only if SBS is set */
+#define SDIO_REG_CCCR_BUS_SUSPEND	0x0c
+#define SDIO_REG_CCCR_FUNC_SEL		0x0d
+#define SDIO_REG_CCCR_EXEC_FLAG		0x0e
+#define SDIO_REG_CCCR_READY_FLAG	0x0f
+
+#define SDIO_REG_CCCR_FN0_BLKSIZE	0x10 /* 2bytes, 0x10~0x11 */
+
+#define SDIO_REG_CCCR_POWER_CTRL		0x12
+
+#define  SDIO_POWER_SMPC	0x01	/* Supports Master Power Control */
+#define  SDIO_POWER_EMPC	0x02	/* Enable Master Power Control */
+
+#define SDIO_REG_CCCR_SPEED		0x13
+
+#define  SDIO_SPEED_SHS		0x01	/* Supports High-Speed mode */
+#define  SDIO_SPEED_EHS		0x02	/* Enable High-Speed mode */
+
+/*
+ * Function Basic Registers (FBR)
+ */
+
+#define SDIO_REG_FBR_BASE(f)	((f) * 0x100) /* base of function f's FBRs */
+
+#define SDIO_REG_FBR_STD_FUNC_IF		0x00
+
+#define  SDIO_FBR_SUPPORTS_CSA	0x40	/* supports Code Storage Area */
+#define  SDIO_FBR_ENABLE_CSA	0x80	/* enable Code Storage Area */
+
+#define SDIO_REG_FBR_STD_IF_EXT	0x01
+
+#define SDIO_REG_FBR_POWER		0x02
+
+#define  SDIO_FBR_POWER_SPS	0x01	/* Supports Power Selection */
+#define  SDIO_FBR_POWER_EPS	0x02	/* Enable (low) Power Selection */
+
+#define SDIO_REG_FBR_CIS		0x09	/* CIS pointer (3 bytes) */
+
+
+#define SDIO_REG_FBR_CSA		0x0C	/* CSA pointer (3 bytes) */
+
+#define SDIO_REG_FBR_CSA_DATA	0x0F
+
+#define SDIO_REG_FBR_BLKSIZE	0x10	/* block size (2 bytes) */
+
+
+/* SDIO CIS Tuple code */
+#define CISTPL_NULL      0x00
+#define CISTPL_CHECKSUM  0x10
+#define CISTPL_VERS_1    0x15
+#define CISTPL_ALTSTR    0x16
+#define CISTPL_MANFID    0x20
+#define CISTPL_FUNCID    0x21
+#define CISTPL_FUNCE     0x22
+#define CISTPL_SDIO_STD  0x91
+#define CISTPL_SDIO_EXT  0x92
+#define CISTPL_END       0xff
+
+/* SDIO device id */
+#define SDIO_ANY_FUNC_ID    0xff
+#define SDIO_ANY_MAN_ID     0xffff
+#define SDIO_ANY_PROD_ID    0xffff
+
+struct rt_sdio_device_id {
+	rt_uint8_t   func_code;
+	rt_uint16_t  manufacturer;
+	rt_uint16_t  product;
+};
+
+struct rt_sdio_driver {
+	char *name;
+	rt_int32_t (*probe)(struct rt_sdio_function *func);
+	rt_int32_t (*remove)(struct rt_sdio_function *func);
+	struct rt_sdio_device_id *id;
+};
+
+
+
+rt_int32_t sdio_io_send_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t 
+*cmd5_resp);
+rt_int32_t sdio_io_rw_direct(struct rt_mmcsd_card *card, rt_int32_t rw, rt_uint32_t fn,
+	rt_uint32_t reg_addr, rt_uint8_t *pdata, rt_uint8_t raw);
+rt_int32_t sdio_io_rw_extended(struct rt_mmcsd_card *card, rt_int32_t rw, rt_uint32_t fn,
+	rt_uint32_t addr, rt_int32_t op_code, rt_uint8_t *buf, rt_uint32_t blocks, rt_uint32_t blksize);
+rt_uint8_t sdio_io_readb(struct rt_sdio_function *func, 
+			 rt_uint32_t reg, rt_int32_t *err);
+rt_int32_t sdio_io_writeb(struct rt_sdio_function *func, 
+			  rt_uint32_t reg, rt_uint8_t data);
+rt_uint16_t sdio_io_readw(struct rt_sdio_function *func, rt_uint32_t addr, rt_int32_t *err);
+rt_int32_t sdio_io_writew(struct rt_sdio_function *func, rt_uint16_t data, rt_uint32_t addr);
+rt_int32_t sdio_io_read_multi_fifo_1(struct rt_sdio_function *func, 
+				     rt_uint32_t addr, rt_uint8_t *buf, rt_uint32_t len);
+rt_int32_t sdio_io_write_multi_fifo_1(struct rt_sdio_function *func, 
+				      rt_uint32_t addr, rt_uint8_t *buf, rt_uint32_t len);
+rt_int32_t init_sdio(struct rt_mmcsd_host *host, rt_uint32_t ocr);
+rt_int32_t sdio_attach_irq(struct rt_sdio_function *func, rt_sdio_irq_handler_t *handler);
+rt_int32_t sdio_detach_irq(struct rt_sdio_function *func);
+void sdio_irq_wakeup(struct rt_mmcsd_host *host);
+rt_int32_t sdio_enable_func(struct rt_sdio_function *func);
+rt_int32_t sdio_disable_func(struct rt_sdio_function *func);
+rt_int32_t sdio_set_block_size(struct rt_sdio_function *func, rt_uint32_t blksize);
+rt_int32_t sdio_register_driver(struct rt_sdio_driver *driver);
+rt_int32_t sdio_unregister_driver(struct rt_sdio_driver *driver);
+void rt_sdio_init(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

+ 44 - 0
components/drivers/sdio/sdio_func_ids.h

@@ -0,0 +1,44 @@
+/*
+ * File      : sdio_func_ids.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author		Notes
+ * 2012-02-26     weety		first version
+ */
+ 
+#ifndef __SDIO_FUNC_IDS_H__
+#define __SDIO_FUNC_IDS_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Standard SDIO Function Interfaces */
+
+#define SDIO_FUNC_CODE_NONE        0x00	/* Not a SDIO standard interface */
+#define SDIO_FUNC_CODE_UART        0x01	/* SDIO Standard UART */
+#define SDIO_FUNC_CODE_BT_A        0x02	/* SDIO Type-A for Bluetooth standard interface */
+#define SDIO_FUNC_CODE_BT_B        0x03	/* SDIO Type-B for Bluetooth standard interface */
+#define SDIO_FUNC_CODE_GPS         0x04	/* SDIO GPS standard interface */
+#define SDIO_FUNC_CODE_CAMERA      0x05	/* SDIO Camera standard interface */
+#define SDIO_FUNC_CODE_PHS         0x06	/* SDIO PHS standard interface */
+#define SDIO_FUNC_CODE_WLAN        0x07	/* SDIO WLAN interface */
+#define SDIO_FUNC_CODE_ATA         0x08	/* Embedded SDIO-ATA standard interface */
+
+/* manufacturer id, product io */
+
+#define SDIO_MANUFACTURER_ID_MARVELL			0x02df
+#define SDIO_PRODUCT_ID_MARVELL_LIBERTAS		0x9103
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif