static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, size_t len, bool fixed) { int ret; struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); struct sdio_func *func = dev_to_sdio_func(glue->dev); sdio_claim_host(func); if (unlikely(dump)) { printk(KERN_DEBUG "wlcore_sdio: READ from 0x%04x\n", addr); print_hex_dump(KERN_DEBUG, "wlcore_sdio: READ ", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false); } if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) { ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n", addr, ((u8 *)buf)[0]); } else { if (fixed) ret = sdio_readsb(func, buf, addr, len); else ret = sdio_memcpy_fromio(func, buf, addr, len); dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n", addr, len); } sdio_release_host(func); if (WARN_ON(ret)) dev_err(child->parent, "sdio read failed (%d)\n", ret); return ret; }
static int msdc_ettagent_read(struct msdc_host *host, unsigned int u4Addr, unsigned int u4Func, void *pBuffer, unsigned int u4Len, unsigned int u4Cmd) { int ret = 0; u8 *value = (u8 *) pBuffer; struct sdio_func *sdioFunc; if((pBuffer==NULL) || (host==NULL)) { printk("[%s] pBuffer = %p, host = %p\n", __func__, pBuffer, host); return -1; } if( ((u4Cmd == 53) && (u4Len < 4)) || ((u4Cmd == 52) && (u4Len > 1)) ) { printk("[%s] u4Cmd = %d, u4Len = %d\n", __func__, u4Cmd, u4Len); return -1; } sdioFunc = host->mmc->card->sdio_func[u4Func - 1]; //sdio_claim_host(sdioFunc); if(u4Cmd == 53) ret = sdio_readsb(sdioFunc, pBuffer, u4Addr, u4Len); else if(u4Cmd == 52) *value = sdio_readb(sdioFunc, u4Addr, &ret); else { printk("[%s] Doesn't support u4Cmd = %d\n", __func__, u4Cmd); ret = -1; } //sdio_release_host(sdioFunc); // printk("Isaac: host->error = %d\n", host->error); return ret; }
static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, size_t len, bool fixed) { int ret; struct sdio_func *func = wl_to_func(wl); if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", addr, ((u8 *)buf)[0]); } else { if (fixed) ret = sdio_readsb(func, buf, addr, len); else ret = sdio_memcpy_fromio(func, buf, addr, len); wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes", addr, len); wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); } if (ret) wl1271_error("sdio read failed (%d)", ret); }
/* * This function reads multiple data from SDIO card memory. */ static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer, u32 len, u32 port, u8 claim) { struct sdio_mmc_card *card = adapter->card; int ret = -1; u8 blk_mode = (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1; u32 blk_cnt = (blk_mode == BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len; u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK); if (claim) sdio_claim_host(card->func); if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size)) ret = 0; if (claim) sdio_release_host(card->func); return ret; }
static A_STATUS __HIFReadWrite(HIF_DEVICE *device, A_UINT32 address, A_UCHAR *buffer, A_UINT32 length, A_UINT32 request, void *context) { A_UINT8 opcode; A_STATUS status = A_OK; int ret; A_UINT8 *tbuffer; A_BOOL bounced = FALSE; AR_DEBUG_ASSERT(device != NULL); AR_DEBUG_ASSERT(device->func != NULL); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: 0x%p, buffer:0x%p (addr:0x%X)\n", device, buffer, address)); do { if (request & HIF_EXTENDED_IO) { //AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Command type: CMD53\n")); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: Invalid command type: 0x%08x\n", request)); status = A_EINVAL; break; } if (request & HIF_BLOCK_BASIS) { /* round to whole block length size */ length = (length / HIF_MBOX_BLOCK_SIZE) * HIF_MBOX_BLOCK_SIZE; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Block mode (BlockLen: %d)\n", length)); } else if (request & HIF_BYTE_BASIS) { AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Byte mode (BlockLen: %d)\n", length)); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: Invalid data mode: 0x%08x\n", request)); status = A_EINVAL; break; } #if 0 /* useful for checking register accesses */ if (length & 0x3) { A_PRINTF(KERN_ALERT"AR6000: HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n", request & HIF_WRITE ? "write":"read", address, length); } #endif if (request & HIF_WRITE) { if ((address >= HIF_MBOX_START_ADDR(0)) && (address <= HIF_MBOX_END_ADDR(3))) { AR_DEBUG_ASSERT(length <= HIF_MBOX_WIDTH); /* * Mailbox write. Adjust the address so that the last byte * falls on the EOM address. */ address += (HIF_MBOX_WIDTH - length); } } if (request & HIF_FIXED_ADDRESS) { opcode = CMD53_FIXED_ADDRESS; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Fixed 0x%X\n", address)); } else if (request & HIF_INCREMENTAL_ADDRESS) { opcode = CMD53_INCR_ADDRESS; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Address mode: Incremental 0x%X\n", address)); } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: Invalid address mode: 0x%08x\n", request)); status = A_EINVAL; break; } if (request & HIF_WRITE) { #if HIF_USE_DMA_BOUNCE_BUFFER if (BUFFER_NEEDS_BOUNCE(buffer)) { AR_DEBUG_ASSERT(device->dma_buffer != NULL); tbuffer = device->dma_buffer; /* copy the write data to the dma buffer */ AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE); memcpy(tbuffer, buffer, length); bounced = TRUE; } else { tbuffer = buffer; } #else tbuffer = buffer; #endif if (opcode == CMD53_FIXED_ADDRESS) { ret = sdio_writesb(device->func, address, tbuffer, length); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writesb ret=%d address: 0x%X, len: %d, 0x%X\n", ret, address, length, *(int *)tbuffer)); } else { ret = sdio_memcpy_toio(device->func, address, tbuffer, length); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: writeio ret=%d address: 0x%X, len: %d, 0x%X\n", ret, address, length, *(int *)tbuffer)); } } else if (request & HIF_READ) { #if HIF_USE_DMA_BOUNCE_BUFFER if (BUFFER_NEEDS_BOUNCE(buffer)) { AR_DEBUG_ASSERT(device->dma_buffer != NULL); AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE); tbuffer = device->dma_buffer; bounced = TRUE; } else { tbuffer = buffer; } #else tbuffer = buffer; #endif if (opcode == CMD53_FIXED_ADDRESS) { ret = sdio_readsb(device->func, tbuffer, address, length); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readsb ret=%d address: 0x%X, len: %d, 0x%X\n", ret, address, length, *(int *)tbuffer)); } else { ret = sdio_memcpy_fromio(device->func, tbuffer, address, length); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: readio ret=%d address: 0x%X, len: %d, 0x%X\n", ret, address, length, *(int *)tbuffer)); } #if HIF_USE_DMA_BOUNCE_BUFFER if (bounced) { /* copy the read data from the dma buffer */ memcpy(buffer, tbuffer, length); } #endif } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: Invalid direction: 0x%08x\n", request)); status = A_EINVAL; break; } if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: SDIO bus operation failed! MMC stack returned : %d \n", ret)); status = A_ERROR; } } while (FALSE); return status; }
/** * @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; }
int bcmsdio_cmd53(unsigned int offset, int rw, int func, int blk_mode, int opcode, int buflen, char *buff) { struct sdio_func *function = func_data[BCM_SDIO_FN1]->func; int ret = -1; int count = 0; if (function == NULL) { BCM_DEBUG_PRINT(ERROR_LEVEL, KERN_ALERT " ***Error: %s %d ***\n", __func__, __LINE__); return -ENON_INTF_ERR; } sdio_claim_host(function); if(func_data[BCM_SDIO_FN1]->bremoved) { ret = -ENON_INTF_ERR; BCM_DEBUG_PRINT(ERROR_LEVEL, KERN_ALERT "Error :%s,%d removed flag var is non-zero :%d \n", __func__, __LINE__,func_data[BCM_SDIO_FN1]->bremoved); goto rel_host; } /* NOTE: blk_mode is not used here. If buflen exceeds corresponding * block size then SDIO stack will internally convert the request to * block req * */ if(buflen%4) { int i; /* Some SDIO controllers don't like CMD53 for * request len not-multiple of 4. */ ret = 0; for(i=0; i<buflen; i++) { buff[i] = bcmsdio_cmd52_nolock(buff[i], offset, rw, func,&ret); if(ret) { BCM_DEBUG_PRINT(debuglevel, "FAILED IN INDEX: %d for CMD52 %d rw: %x addr: %x\n", i, ret, rw, offset); goto rel_host; } else { if(opcode) offset++; } } } else { while( count < SDIO_CMD_RETRIES ) { if(func != BCM_SDIO_FN0) { if (rw) { if (opcode) ret = sdio_memcpy_toio(function, offset, buff, buflen); else ret = sdio_writesb(function, offset, buff, buflen); } else { if (opcode) ret = sdio_memcpy_fromio(function, buff, offset, buflen); else ret = sdio_readsb(function, buff, offset, buflen); } } else { ret = bcm_sdio_cmd53(function,rw,offset,opcode,buff,buflen,BCM_SDIO_FN0_BLK_SIZE); } if(!ret) break; count++; } if(count) BCM_DEBUG_PRINT(debuglevel, "Count is higher than 0 for cmd53: %x\n", count); if(ret) BCM_DEBUG_PRINT(debuglevel, "FAILED IN CMD53 %d rw: %x addr: %x count: %x\n", ret, rw, offset, count); } //BCM_DEBUG_PRINT(debuglevel, KERN_ALERT "cmd53-fn-%d-%d: addr:x%x w:x%x sz:x%x ret:x%x\n", func, function->num, offset, rw, buflen, ret); rel_host: sdio_release_host(function); return ret; }
/*----------------------------------------------------------------------------*/ BOOL kalDevPortRead(IN P_GLUE_INFO_T prGlueInfo, IN UINT_16 u2Port, IN UINT_32 u4Len, OUT PUINT_8 pucBuf, IN UINT_32 u4ValidOutBufSize) { P_GL_HIF_INFO_T prHifInfo = NULL; PUINT_8 pucDst = NULL; int count = u4Len; int ret = 0; int bNum = 0; #if (MTK_WCN_HIF_SDIO == 0) struct sdio_func *prSdioFunc = NULL; #endif #if DBG /* printk(KERN_INFO DRV_NAME"++kalDevPortRead++ buf:0x%p, port:0x%x, length:%d\n", pucBuf, u2Port, u4Len); */ #endif ASSERT(prGlueInfo); prHifInfo = &prGlueInfo->rHifInfo; ASSERT(pucBuf); pucDst = pucBuf; ASSERT(u4Len <= u4ValidOutBufSize); #if (MTK_WCN_HIF_SDIO == 0) prSdioFunc = prHifInfo->func; ASSERT(prSdioFunc->cur_blksize > 0); if (!in_interrupt) { sdio_claim_host(prSdioFunc); } /* Split buffer into multiple single block to workaround hifsys */ while (count >= prSdioFunc->cur_blksize) { count -= prSdioFunc->cur_blksize; bNum++; } if (count > 0 && bNum > 0) { bNum++; } if (bNum > 0) { ret = sdio_readsb(prSdioFunc, pucDst, u2Port, prSdioFunc->cur_blksize * bNum); #ifdef CONFIG_X86 /* ENE workaround */ { int tmp; sdio_writel(prSdioFunc, 0x0, SDIO_X86_WORKAROUND_WRITE_MCR, &tmp); } #endif } else { ret = sdio_readsb(prSdioFunc, pucDst, u2Port, count); } if (!in_interrupt) { sdio_release_host(prSdioFunc); } #else /* Split buffer into multiple single block to workaround hifsys */ while (count >= (prGlueInfo->rHifInfo).prFuncInfo->blk_sz) { count -= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz); bNum++; } if (count > 0 && bNum > 0) { bNum++; } if (bNum > 0) { ret = mtk_wcn_hif_sdio_read_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucDst, ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz) * bNum); } else { ret = mtk_wcn_hif_sdio_read_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucDst, count); } #endif if (ret) { kalSendAeeWarning(HIF_SDIO_ERR_TITLE_STR, HIF_SDIO_ERR_DESC_STR "sdio_readsb() reports error: %x", ret); DBGLOG(HAL, ERROR, ("sdio_readsb() reports error: %x", ret)); } return (ret) ? FALSE : TRUE; } /* end of kalDevPortRead() */
static int brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, uint write, uint func, uint addr, struct sk_buff *pkt) { bool fifo = (fix_inc == SDIOH_DATA_FIX); u32 SGCount = 0; int err_ret = 0; struct sk_buff *pnext; brcmf_dbg(TRACE, "Enter\n"); brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait); if (brcmf_pm_resume_error(sdiodev)) return -EIO; /* Claim host controller */ sdio_claim_host(sdiodev->func[func]); for (pnext = pkt; pnext; pnext = pnext->next) { uint pkt_len = pnext->len; pkt_len += 3; pkt_len &= 0xFFFFFFFC; if ((write) && (!fifo)) { err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, ((u8 *) (pnext->data)), pkt_len); } else if (write) { err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, ((u8 *) (pnext->data)), pkt_len); } else if (fifo) { err_ret = sdio_readsb(sdiodev->func[func], ((u8 *) (pnext->data)), addr, pkt_len); } else { err_ret = sdio_memcpy_fromio(sdiodev->func[func], ((u8 *) (pnext->data)), addr, pkt_len); } if (err_ret) { brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", write ? "TX" : "RX", pnext, SGCount, addr, pkt_len, err_ret); } else { brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", write ? "TX" : "RX", pnext, SGCount, addr, pkt_len); } if (!fifo) addr += pkt_len; SGCount++; } /* Release host controller */ sdio_release_host(sdiodev->func[func]); brcmf_dbg(TRACE, "Exit\n"); return err_ret; }
static int write_data(struct sdio_func *func, u32 addr, void *data , u32 size, u32 access_size) { int rv = 0; struct sqn_sdio_card *sqn_card = sdio_get_drvdata(func); sqn_pr_enter(); sdio_claim_host(func); if (is_good_ahb_address(addr, sqn_card->version) && 0 == (size % 4) && 4 == access_size) { /* write data using AHB */ u8 *data_cp = 0; #ifdef DEBUG u8 *read_data = 0; #endif sqn_pr_dbg("write data using AHB\n"); sdio_writel(func, addr, SQN_SDIO_ADA_ADDR, &rv); if (rv) { sqn_pr_dbg("can't set SQN_SDIO_ADA_ADDR register\n"); goto out; } sqn_pr_dbg("after SQN_SDIO_ADA_ADDR\n"); data_cp = kmalloc(size, GFP_KERNEL | GFP_DMA); memcpy(data_cp, data, size); rv = sdio_writesb(func, SQN_SDIO_ADA_RDWR, data_cp, size); if (rv) { sqn_pr_dbg("can't write to SQN_SDIO_ADA_RDWR register\n"); goto out; } kfree(data_cp); /* * Workaround when sdio_writesb doesn't work because DMA * alignment */ /* int i = 0; for (; i < size/4; ++i) { sdio_writel(func, *((u32*)data + i), SQN_SDIO_ADA_RDWR, &rv); if (rv) { sqn_pr_dbg("can't write to SQN_SDIO_ADA_RDWR register\n"); goto out; } } */ sqn_pr_dbg("after SQN_SDIO_ADA_RDWR\n"); /* ******** only for debugging ******** */ /* validate written data */ /* #ifdef DEBUG */ #if 0 sqn_pr_dbg("reading data using AHB\n"); sdio_writel(func, addr, SQN_SDIO_ADA_ADDR, &rv); if (rv) { sqn_pr_dbg("can't set SQN_SDIO_ADA_ADDR register\n"); goto out; } sqn_pr_dbg("after SQN_SDIO_ADA_ADDR\n"); read_data = kmalloc(size, GFP_KERNEL); rv = sdio_readsb(func, read_data, SQN_SDIO_ADA_RDWR, size); if (rv) { sqn_pr_dbg("can't read from SQN_SDIO_ADA_RDWR register\n"); kfree(read_data); goto out; } if (memcmp(data, read_data, size)) sqn_pr_dbg("WARNING: written data are __not__ equal\n"); else sqn_pr_dbg("OK: written data are equal\n"); kfree(read_data); #endif /* DEBUG */ /* ******** only for debugging ******** */ } else if (4 == access_size && size >= 4) { /* write data using CMD53 */ sqn_pr_dbg("write data using CMD53\n"); rv = sdio_memcpy_toio(func, addr, data , size); } else { /* write data using CMD52 */ /* not implemented yet, so we use CMD53 */ /* rv = sdio_memcpy_toio(func, addr, data , size); */ int i = 0; sqn_pr_dbg("write data using CMD52\n"); for (i = 0; i < size; ++i) { sdio_writeb(func, *((u8*)data + i), addr + i, &rv); if (rv) { sqn_pr_dbg("can't write 1 byte to %xh addr using CMD52\n" , addr + i); goto out; } } } out: sdio_release_host(func); sqn_pr_leave(); return rv; }
/** * @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; }
int sif_io_sync(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, u32 flag) { int err = 0; u8 * ibuf = NULL; bool need_ibuf = false; struct esp_sdio_ctrl *sctrl = NULL; struct sdio_func *func = NULL; if (epub == NULL || buf == NULL) { ESSERT(0); err = -EINVAL; goto _exit; } sctrl = (struct esp_sdio_ctrl *)epub->sif; func = sctrl->func; if (func == NULL) { ESSERT(0); err = -EINVAL; goto _exit; } if (bad_buf(buf)) { esp_dbg(ESP_DBG_TRACE, "%s dst 0x%08x, len %d badbuf\n", __func__, addr, len); need_ibuf = true; ibuf = sctrl->dma_buffer; } else { ibuf = buf; } if (flag & SIF_BLOCK_BASIS) { /* round up for block data transcation */ } if (flag & SIF_TO_DEVICE) { esp_dbg(ESP_DBG_TRACE, "%s to addr 0x%08x, len %d \n", __func__, addr, len); if (need_ibuf) memcpy(ibuf, buf, len); sdio_claim_host(func); if (flag & SIF_FIXED_ADDR) err = sdio_writesb(func, addr, ibuf, len); else if (flag & SIF_INC_ADDR) { err = sdio_memcpy_toio(func, addr, ibuf, len); } sif_platform_check_r1_ready(epub); sdio_release_host(func); } else if (flag & SIF_FROM_DEVICE) { esp_dbg(ESP_DBG_TRACE, "%s from addr 0x%08x, len %d \n", __func__, addr, len); sdio_claim_host(func); if (flag & SIF_FIXED_ADDR) err = sdio_readsb(func, ibuf, addr, len); else if (flag & SIF_INC_ADDR) { err = sdio_memcpy_fromio(func, ibuf, addr, len); } sdio_release_host(func); if (!err && need_ibuf) memcpy(buf, ibuf, len); } _exit: return err; }