/** 
 *  @brief This function reads data from the card.
 *  
 *  @param priv    	A pointer to bt_private structure
 *  @return 	   	BT_STATUS_SUCCESS or BT_STATUS_FAILURE
 */
static int
sd_card_to_host(bt_private * priv)
{
    int ret = BT_STATUS_SUCCESS;
    u16 buf_len = 0;
    int buf_block_len;
    int blksz;
    struct sk_buff *skb = NULL;
    u32 type;
    u8 *payload = NULL;
    struct hci_dev *hdev = priv->bt_dev.hcidev;
    struct sdio_mmc_card *card = priv->bt_dev.card;

    ENTER();

    if (!card || !card->func) {
        PRINTM(ERROR, "card or function is NULL!\n");
        ret = BT_STATUS_FAILURE;
        goto exit;
    }

    /* Read the length of data to be transferred */
    ret = sd_read_rx_len(priv, &buf_len);
    if (ret < 0) {
        PRINTM(ERROR, "card_to_host, read scratch reg failed\n");
        ret = BT_STATUS_FAILURE;
        goto exit;
    }

    /* Allocate buffer */
    blksz = SD_BLOCK_SIZE;
    buf_block_len = (buf_len + blksz - 1) / blksz;
    if (buf_len <= BT_HEADER_LEN || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
        PRINTM(ERROR, "card_to_host, invalid packet length: %d\n", buf_len);
        ret = BT_STATUS_FAILURE;
        goto exit;
    }
    skb =
        bt_skb_alloc(buf_block_len * blksz + PXA3XX_DMA_ALIGNMENT, GFP_ATOMIC);
    if (skb == NULL) {
        PRINTM(WARN, "No free skb\n");
        goto exit;
    }
    if ((u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1)) {
        skb_put(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
        skb_pull(skb, (u32) skb->data & (PXA3XX_DMA_ALIGNMENT - 1));
    }

    payload = skb->tail;
    ret = sdio_readsb(card->func, payload, priv->bt_dev.ioport,
                      buf_block_len * blksz);
    if (ret < 0) {
        PRINTM(ERROR, "card_to_host, read iomem failed: %d\n", ret);
        ret = BT_STATUS_FAILURE;
        goto exit;
    }
    DBG_HEXDUMP(DAT_D, "SDIO Blk Rd", payload, blksz * buf_block_len);
    /* This is SDIO specific header length: byte[2][1][0], type: byte[3]
       (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */
    buf_len = payload[0];
    buf_len |= (u16) payload[1] << 8;
    type = payload[3];
    PRINTM(DATA, "SDIO Blk Rd dev%d: len=%d type=%d\n", hdev->id, buf_len,
           type);
    switch (type) {
    case HCI_ACLDATA_PKT:
    case HCI_SCODATA_PKT:
    case HCI_EVENT_PKT:
        bt_cb(skb)->pkt_type = type;
        skb->dev = (void *) hdev;
        skb_put(skb, buf_len);
        skb_pull(skb, BT_HEADER_LEN);
        if (type == HCI_EVENT_PKT)
            check_evtpkt(priv, skb);
        hci_recv_frame(skb);
        hdev->stat.byte_rx += buf_len;
        break;
    case MRVL_VENDOR_PKT:
        bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
        skb->dev = (void *) hdev;
        skb_put(skb, buf_len);
        skb_pull(skb, BT_HEADER_LEN);
        if (BT_STATUS_SUCCESS != bt_process_event(priv, skb))
            hci_recv_frame(skb);
        hdev->stat.byte_rx += buf_len;
        break;
    default:
        /* Driver specified event and command resp should be handle here */
        PRINTM(INFO, "Unknow PKT type:%d\n", type);
        kfree_skb(skb);
        skb = NULL;
        break;
    }
  exit:
    if (ret) {
        hdev->stat.err_rx++;
        if (skb)
            kfree_skb(skb);
    }

    LEAVE();
    return ret;
}
/**
 *  @brief This function reads data from the card.
 *
 *  @param priv     A pointer to bt_private structure
 *  @return         BT_STATUS_SUCCESS or BT_STATUS_FAILURE
 */
static int
sd_card_to_host(bt_private *priv)
{
	int ret = BT_STATUS_SUCCESS;
	u16 buf_len = 0;
	int buf_block_len;
	int blksz;
	struct sk_buff *skb = NULL;
	u32 type;
	u8 *payload = NULL;
	struct mbt_dev *mbt_dev = NULL;
	struct m_dev *mdev_bt = &(priv->bt_dev.m_dev[BT_SEQ]);
	struct m_dev *mdev_fm = &(priv->bt_dev.m_dev[FM_SEQ]);
	struct m_dev *mdev_nfc = &(priv->bt_dev.m_dev[NFC_SEQ]);
	struct nfc_dev *nfc_dev =
		(struct nfc_dev *)priv->bt_dev.m_dev[NFC_SEQ].dev_pointer;
	struct fm_dev *fm_dev =
		(struct fm_dev *)priv->bt_dev.m_dev[FM_SEQ].dev_pointer;
	struct m_dev *mdev_debug = &(priv->bt_dev.m_dev[DEBUG_SEQ]);
	struct debug_dev *debug_dev =
		(struct debug_dev *)priv->bt_dev.m_dev[DEBUG_SEQ].dev_pointer;
	struct sdio_mmc_card *card = priv->bt_dev.card;

	ENTER();
	if (priv->bt_dev.m_dev[BT_SEQ].spec_type != BLUEZ_SPEC)
		mbt_dev = (struct mbt_dev *)priv->bt_dev.m_dev[BT_SEQ].dev_pointer;
	if (!card || !card->func) {
		PRINTM(ERROR, "BT: card or function is NULL!\n");
		ret = BT_STATUS_FAILURE;
		goto exit;
	}

	/* Read the length of data to be transferred */
	ret = sd_read_rx_len(priv, &buf_len);
	if (ret < 0) {
		PRINTM(ERROR, "BT: card_to_host, read scratch reg failed\n");
		ret = BT_STATUS_FAILURE;
		goto exit;
	}

	/* Allocate buffer */
	blksz = SD_BLOCK_SIZE;
	buf_block_len = (buf_len + blksz - 1) / blksz;
	if (buf_len <= BT_HEADER_LEN ||
	    (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
		PRINTM(ERROR, "BT: card_to_host, invalid packet length: %d\n",
		       buf_len);
		ret = BT_STATUS_FAILURE;
		goto exit;
	}
	skb = bt_skb_alloc(buf_block_len * blksz + DMA_ALIGNMENT, GFP_ATOMIC);
	if (skb == NULL) {
		PRINTM(WARN, "BT: No free skb\n");
		goto exit;
	}
	if ((t_ptr)skb->data & (DMA_ALIGNMENT - 1)) {
		skb_put(skb,
			DMA_ALIGNMENT -
			((t_ptr)skb->data & (DMA_ALIGNMENT - 1)));
		skb_pull(skb,
			 DMA_ALIGNMENT -
			 ((t_ptr)skb->data & (DMA_ALIGNMENT - 1)));
	}

	payload = skb->data;
	ret = sdio_readsb(card->func, payload, priv->bt_dev.ioport,
			  buf_block_len * blksz);
	if (ret < 0) {
		PRINTM(ERROR, "BT: card_to_host, read iomem failed: %d\n", ret);
		kfree_skb(skb);
		skb = NULL;
		ret = BT_STATUS_FAILURE;
		goto exit;
	}
	/* This is SDIO specific header length: byte[2][1][0], * type: byte[3]
	   (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */
	buf_len = payload[0];
	buf_len |= (u16) payload[1] << 8;
	type = payload[3];
	PRINTM(DATA, "BT: SDIO Blk Rd %s: len=%d type=%d\n", mbt_dev->name,
	       buf_len, type);
	if (buf_len > buf_block_len * blksz) {
		PRINTM(ERROR,
		       "BT: Drop invalid rx pkt, len in hdr=%d, cmd53 length=%d\n",
		       buf_len, buf_block_len * blksz);
		ret = BT_STATUS_FAILURE;
		kfree_skb(skb);
		skb = NULL;
		goto exit;
	}
	DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Rd", payload, buf_len);
	switch (type) {
	case HCI_ACLDATA_PKT:
		bt_cb(skb)->pkt_type = type;
		skb_put(skb, buf_len);
		skb_pull(skb, BT_HEADER_LEN);
		if (mbt_dev) {
			skb->dev = (void *)mdev_bt;
			mdev_recv_frame(skb);
			mdev_bt->stat.byte_rx += buf_len;
		}
		break;
	case HCI_SCODATA_PKT:
		bt_cb(skb)->pkt_type = type;
		skb_put(skb, buf_len);
		skb_pull(skb, BT_HEADER_LEN);
		if (mbt_dev) {
			skb->dev = (void *)mdev_bt;
			mdev_recv_frame(skb);
			mdev_bt->stat.byte_rx += buf_len;
		}
		break;
	case HCI_EVENT_PKT:
		/** add EVT Demux */
		bt_cb(skb)->pkt_type = type;
		skb_put(skb, buf_len);
		skb_pull(skb, BT_HEADER_LEN);
		if (BT_STATUS_SUCCESS == check_evtpkt(priv, skb))
			break;
		switch (skb->data[0]) {
		case 0x0E:
			/** cmd complete */
			if (priv->debug_device_pending) {
				if (priv->debug_ocf_ogf[0] == skb->data[3] &&
				    priv->debug_ocf_ogf[1] == skb->data[4]) {
					priv->debug_device_pending = 0;
					priv->debug_ocf_ogf[0] = 0;
					priv->debug_ocf_ogf[1] = 0;
					/** debug cmd complete */
					if (debug_dev) {
						skb->dev = (void *)mdev_debug;
						mdev_recv_frame(skb);
						mdev_debug->stat.byte_rx +=
							buf_len;
					}
					break;
				}
			}
			if (skb->data[3] == 0x80 && skb->data[4] == 0xFE) {
				/** FM cmd complete */
				if (fm_dev) {
					skb->dev = (void *)mdev_fm;
					mdev_recv_frame(skb);
					mdev_fm->stat.byte_rx += buf_len;
				}
			} else if (skb->data[3] == 0x81 && skb->data[4] == 0xFE) {
				/** NFC cmd complete */
				if (nfc_dev) {
					skb->dev = (void *)mdev_nfc;
					mdev_recv_frame(skb);
					mdev_nfc->stat.byte_rx += buf_len;
				}
			} else {
				if (mbt_dev) {
					skb->dev = (void *)mdev_bt;
					mdev_recv_frame(skb);
					mdev_bt->stat.byte_rx += buf_len;
				}
			}
			break;
		case 0x0F:
			/** cmd status */
			if (skb->data[4] == 0x80 && skb->data[5] == 0xFE) {
				/** FM cmd ststus */
				if (fm_dev) {
					skb->dev = (void *)mdev_fm;
					mdev_recv_frame(skb);
					mdev_fm->stat.byte_rx += buf_len;
				}
			} else if (skb->data[4] == 0x81 && skb->data[5] == 0xFE) {
				/** NFC cmd ststus */
				if (nfc_dev) {
					skb->dev = (void *)mdev_nfc;
					mdev_recv_frame(skb);
					mdev_nfc->stat.byte_rx += buf_len;
				}
			} else {
				/** BT cmd status */
				if (mbt_dev) {
					skb->dev = (void *)mdev_bt;
					mdev_recv_frame(skb);
					mdev_bt->stat.byte_rx += buf_len;
				}
			}
			break;
		case 0xFF:
			/** Vendor specific pkt */
			if (skb->data[2] == 0xC0) {
				/** NFC EVT */
				if (nfc_dev) {
					skb->dev = (void *)mdev_nfc;
					mdev_recv_frame(skb);
					mdev_nfc->stat.byte_rx += buf_len;
				}
			} else if (skb->data[2] >= 0x80 && skb->data[2] <= 0xAF) {
				/** FM EVT */
				if (fm_dev) {
					skb->dev = (void *)mdev_fm;
					mdev_recv_frame(skb);
					mdev_fm->stat.byte_rx += buf_len;
				}
			} else {
				/** BT EVT */
				if (mbt_dev) {
					skb->dev = (void *)mdev_bt;
					mdev_recv_frame(skb);
					mdev_bt->stat.byte_rx += buf_len;
				}
			}
			break;
		default:
			/** BT EVT */
			if (mbt_dev) {
				skb->dev = (void *)mdev_bt;
				mdev_recv_frame(skb);
				mdev_bt->stat.byte_rx += buf_len;
			}
			break;
		}
		break;
	case MRVL_VENDOR_PKT:
		/* Just think here need to back compatible FM */
		bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
		skb_put(skb, buf_len);
		skb_pull(skb, BT_HEADER_LEN);
		if (mbt_dev) {
			if (BT_STATUS_SUCCESS != bt_process_event(priv, skb)) {
				skb->dev = (void *)mdev_bt;
				mdev_recv_frame(skb);
				mdev_bt->stat.byte_rx += buf_len;
			}
		}

		break;
	default:
		/* Driver specified event and command resp should be handle
		   here */
		PRINTM(INFO, "BT: Unknown PKT type:%d\n", type);
		kfree_skb(skb);
		skb = NULL;
		break;
	}
exit:
	if (ret) {
		if (mbt_dev)
			mdev_bt->stat.err_rx++;
		PRINTM(ERROR, "error when recv pkt!\n");
	}

	LEAVE();
	return ret;
}