static ssize_t mt6620_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) { size_t newSize; ssize_t ret; if(size > MAX_RW_SIZE) return -EINVAL; #if (TX_PATH_BLKSZ_WORKAROUND == 1) if(size > mt6620_t.func->blk_sz) { unsigned blksz = mt6620_t.func->blk_sz; newSize = (size + (blksz - 1)) / blksz * blksz; } else newSize = size; #else newSize = size; #endif if(copy_from_user(mt6620_t.buf, buf, size)) return -EFAULT; if(newSize > size) // pad with zero memset(&mt6620_t.buf[size], 0, sizeof(char) * newSize - size); if(down_interruptible(&mt6620_sem)) { return -ERESTARTSYS; } ret = mtk_wcn_hif_sdio_write_buf(mt6620_t.cltCtx, mt6620_t.addr, (PUINT32)(mt6620_t.buf), newSize); if(ret == 0) { ret = size; } else { printk(KERN_INFO "%s(): io error code = %d\n", __func__, (int)ret); ret = -EIO; } up(&mt6620_sem); return ret; }
/*----------------------------------------------------------------------------*/ BOOL kalDevPortWrite(IN P_GLUE_INFO_T prGlueInfo, IN UINT_16 u2Port, IN UINT_32 u4Len, IN PUINT_8 pucBuf, IN UINT_32 u4ValidInBufSize) { P_GL_HIF_INFO_T prHifInfo = NULL; PUINT_8 pucSrc = 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"++kalDevPortWrite++ buf:0x%p, port:0x%x, length:%d\n", pucBuf, u2Port, u2Len); */ #endif ASSERT(prGlueInfo); prHifInfo = &prGlueInfo->rHifInfo; ASSERT(pucBuf); pucSrc = pucBuf; ASSERT(u4Len <= u4ValidInBufSize); #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) { /* block mode */ ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, prSdioFunc->cur_blksize * bNum); #ifdef CONFIG_X86 /* ENE workaround */ { int tmp; sdio_writel(prSdioFunc, 0x0, SDIO_X86_WORKAROUND_WRITE_MCR, &tmp); } #endif } else { /* byte mode */ ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, 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) { /* block mode */ ret = mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucSrc, ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz) * bNum); } else { /* byte mode */ ret = mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucSrc, count); } #endif if (ret) { kalSendAeeWarning(HIF_SDIO_ERR_TITLE_STR, HIF_SDIO_ERR_DESC_STR "sdio_writesb() reports error: %x", ret); DBGLOG(HAL, ERROR, ("sdio_writesb() reports error: %x", ret)); } return (ret) ? FALSE : TRUE; } /* end of kalDevPortWrite() */
static void if_sdio_host_to_card_worker(struct work_struct *work) { struct if_sdio_card *card = NULL; struct rda5890_private *priv = NULL; struct if_sdio_packet *packet = NULL; int ret; unsigned long flags; u16 size; u32 retries = 500; u8 size_l, size_h, write_status = 0; #define SDIO_HOST_WRITE_BATCH_SIZE 512 u16 bytes_left, offset, batch; card = container_of(work, struct if_sdio_card, packet_worker); priv = card->priv; //mask_all_sdio_irq(priv->cltCtx); #ifdef WIFI_POWER_MANAGER if(is_sdio_init_complete()) { if(atomic_read(&card->sleep_work_is_active)) { cancel_delayed_work(&card->sleep_work); #ifdef WIFI_UNLOCK_SYSTEM rda5990_wakeUnlock(); #endif atomic_set(&card->sleep_work_is_active, 0); } } #endif while (1) { retries = 500; spin_lock_irqsave(&card->lock, flags); packet = card->packets; if (packet) card->packets = packet->next; spin_unlock_irqrestore(&card->lock, flags); if (!packet) break; #ifdef WIFI_POWER_MANAGER if (atomic_read(&priv->sleep_flag)) { /* Deivce maybe sleep, wakeup it. */ RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM, "Wakeup\n"); ret = if_sdio_wakeup_card(card); if (ret) { RDA5890_ERRP("wakeup card fail\n"); goto out; } } #endif while(retries && is_sdio_patch_complete()) //check write flow ctrl { ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, &write_status); if(ret) { RDA5890_ERRP("read IF_SDIO_FUN1_INT_PEND failed\n"); goto release; } if((write_status & IF_SDIO_INT_RXCMPL) == 0) { //RDA5890_ERRP("**** sdio is busy retry next time \n "); retries --; schedule(); } else { ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_RXCMPL); if(ret) { RDA5890_ERRP("write IF_SDIO_FUN1_INT_PEND failed\n"); goto release; } break; } } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_host_to_card_worker, send one packet, size = %d\n", packet->nb); /* write length */ size = packet->nb/4; size_l = (u8)(size & 0xff); size_h = (u8)((size >> 8) & 0x7f); size_h |= 0x80; ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_L, size_l); if (ret) { RDA5890_ERRP("write PKTLEN_L reg fail\n"); goto release; } ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_H, size_h); if (ret) { RDA5890_ERRP("write PKTLEN_H reg fail\n"); goto release; } /* write data */ bytes_left = packet->nb; offset = 0; while(bytes_left) { batch = (bytes_left < SDIO_HOST_WRITE_BATCH_SIZE)? bytes_left:SDIO_HOST_WRITE_BATCH_SIZE; ret = mtk_wcn_hif_sdio_write_buf(priv->cltCtx, IF_SDIO_FUN1_FIFO_WR, packet->buffer + offset, batch); if (ret) { RDA5890_ERRP("sdio_writesb fail, ret = %d\n", ret); goto release; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "write batch %d, offset = %d\n", batch, offset); offset += batch; bytes_left -= batch; } RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG, "if_sdio_host_to_card_worker, send one packet done\n"); release: kfree(packet); packet = NULL; } out: if(is_sdio_init_complete()) //init complete should start sleep_work { #ifdef WIFI_UNLOCK_SYSTEM rda5990_wakeLock(); #endif #ifdef WIFI_POWER_MANAGER #ifdef WIFI_TEST_MODE if(rda_5990_wifi_in_test_mode()) return; #endif //end WIFI_TEST_MODE atomic_set(&card->sleep_work_is_active, 1); queue_delayed_work(priv->work_thread, &card->sleep_work, rda5890_assoc_in_progress ? 30 * HZ : HZ/5); // 100ms //queue_delayed_work(priv->work_thread, &card->sleep_work, HZ/5); // 100ms #endif } }