/** * @brief This function downloads firmware image to the card. * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ int sd_download_firmware_w_helper(bt_private * priv) { struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card; const struct firmware *fw_firmware = NULL; u8 *firmware = NULL; int firmwarelen; u8 base0; u8 base1; int ret = BT_STATUS_SUCCESS; int offset; void *tmpfwbuf = NULL; int tmpfwbufsz; u8 *fwbuf; u16 len; int txlen = 0; int tx_blocks = 0; int i = 0; int tries = 0; #ifdef FW_DOWNLOAD_SPEED u32 tv1, tv2; #endif char *cur_fw_name = NULL; ENTER(); if (fw_name == NULL) /* Check revision ID */ switch (priv->adapter->chip_rev) { case SD8787_W0: case SD8787_W1: cur_fw_name = SD8787_W1_FW_NAME; break; case SD8787_A0_A1: cur_fw_name = SD8787_AX_FW_NAME; break; default: cur_fw_name = DEFAULT_FW_NAME; break; } else cur_fw_name = fw_name; if ((ret = request_firmware(&fw_firmware, cur_fw_name, priv->hotplug_device)) < 0) { PRINTM(FATAL, "request_firmware() failed, error code = %#x\n", ret); goto done; } if (fw_firmware) { firmware = (u8 *) fw_firmware->data; firmwarelen = fw_firmware->size; } else { PRINTM(MSG, "No firmware image found! Terminating download\n"); ret = BT_STATUS_FAILURE; goto done; } PRINTM(INFO, "Downloading FW image (%d bytes)\n", firmwarelen); #ifdef FW_DOWNLOAD_SPEED tv1 = get_utimeofday(); #endif #ifdef PXA3XX_DMA_ALIGN tmpfwbufsz = ALIGN_SZ(BT_UPLD_SIZE, PXA3XX_DMA_ALIGNMENT); #else /* PXA3XX_DMA_ALIGN */ tmpfwbufsz = BT_UPLD_SIZE; #endif tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL); if (!tmpfwbuf) { PRINTM(ERROR, "Unable to allocate buffer for firmware. Terminating download\n"); ret = BT_STATUS_FAILURE; goto done; } memset(tmpfwbuf, 0, tmpfwbufsz); #ifdef PXA3XX_DMA_ALIGN /* Ensure 8-byte aligned firmware buffer */ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, PXA3XX_DMA_ALIGNMENT); #else /* PXA3XX_DMA_ALIGN */ fwbuf = (u8 *) tmpfwbuf; #endif /* Perform firmware data transfer */ offset = 0; do { /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */ ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY); if (ret < 0) { PRINTM(FATAL, "FW download with helper poll status timeout @ %d\n", offset); goto done; } /* More data? */ if (offset >= firmwarelen) break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE0 register read failed:" " base0=0x%04X(%d). Terminating download\n", base0, base0); ret = BT_STATUS_FAILURE; goto done; } base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE1 register read failed:" " base1=0x%04X(%d). Terminating download\n", base1, base1); ret = BT_STATUS_FAILURE; goto done; } len = (((u16) base1) << 8) | base0; if (len != 0) break; udelay(10); } if (len == 0) break; else if (len > BT_UPLD_SIZE) { PRINTM(FATAL, "FW download failure @ %d, invalid length %d\n", offset, len); ret = BT_STATUS_FAILURE; goto done; } txlen = len; if (len & BIT(0)) { i++; if (i > MAX_WRITE_IOMEM_RETRY) { PRINTM(FATAL, "FW download failure @ %d, over max retry count\n", offset); ret = BT_STATUS_FAILURE; goto done; } PRINTM(ERROR, "FW CRC error indicated by the helper:" " len = 0x%04X, txlen = %d\n", len, txlen); len &= ~BIT(0); /* Setting this to 0 to resend from same offset */ txlen = 0; } else { i = 0; /* Set blocksize to transfer - checking for last block */ if (firmwarelen - offset < txlen) txlen = firmwarelen - offset; PRINTM(INFO, "."); tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL; /* Copy payload to buffer */ memcpy(fwbuf, &firmware[offset], txlen); } /* Send data */ ret = sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf, tx_blocks * SD_BLOCK_SIZE_FW_DL); if (ret < 0) { PRINTM(ERROR, "FW download, write iomem (%d) failed @ %d\n", i, offset); sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret); if (ret) PRINTM(ERROR, "write ioreg failed (CFG)\n"); } offset += txlen; } while (TRUE); PRINTM(INFO, "\nFW download over, size %d bytes\n", offset); ret = BT_STATUS_SUCCESS; done: #ifdef FW_DOWNLOAD_SPEED tv2 = get_utimeofday(); PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000, (tv1 % 1000000) / 1000, tv1 % 1000); PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); tv2 -= tv1; PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); #endif if (tmpfwbuf) kfree(tmpfwbuf); if (fw_firmware) release_firmware(fw_firmware); LEAVE(); return ret; }
static void smssdio_work_thread(struct work_struct *arg) { int ret, isr; struct smscore_buffer_t *cb; struct SmsMsgHdr_S *hdr; size_t size; struct smssdio_device *smsdev = container_of(arg, struct smssdio_device, work_thread); struct sdio_func *sdfunc = smsdev->func; /* * The interrupt register has no defined meaning. It is just * a way of turning of the level triggered interrupt. */ sdio_claim_host(smsdev->func); isr = sdio_readb(smsdev->func, SMSSDIO_INT, &ret); if (ret) { sms_err("Got error reading interrupt status=%d, isr=%d\n", ret, isr); isr = sdio_readb(smsdev->func, SMSSDIO_INT, &ret); if (ret) { sms_err("Second read also failed, try to recover\n"); sdio_release_host(smsdev->func); sdfunc = kmemdup(smsdev->func, sizeof(struct sdio_func), GFP_KERNEL); if (!sdfunc) { sms_err("Out of memory!!!"); return; } sdfunc->num = 0; sdio_claim_host(sdfunc); sdio_writeb(sdfunc, 2, SMSSDIO_CCCR, &ret); sms_err("Read ISR status (write returned) %d\n", ret); isr = sdio_readb(smsdev->func, SMSSDIO_INT, &ret); sms_err("Read returned ret=%d, isr=%d\n", ret, isr); sdio_writeb(sdfunc, 0, SMSSDIO_CCCR, &ret); sdio_release_host(sdfunc); kfree(sdfunc); sms_err("Recovered, but this transaction is lost."); return; } sms_err("Second read succeed status=%d, isr=%d (continue)\n", ret, isr); } if (smsdev->split_cb == NULL) { cb = smscore_getbuffer(smsdev->coredev); if (!cb) { sms_err("Unable to allocate data buffer!\n"); sdio_release_host(smsdev->func); return; } ret = sdio_memcpy_fromio(smsdev->func, cb->p, SMSSDIO_DATA, SMSSDIO_BLOCK_SIZE); if (ret) { sms_warn("Error %d reading initial block, " "continue with sequence.\n", ret); } hdr = cb->p; if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { smsdev->split_cb = cb; sdio_release_host(smsdev->func); return; } if (hdr->msgLength > smsdev->func->cur_blksize) size = hdr->msgLength - smsdev->func->cur_blksize; else size = 0; } else { cb = smsdev->split_cb; hdr = cb->p; size = hdr->msgLength - sizeof(struct SmsMsgHdr_S); smsdev->split_cb = NULL; } if (size) { void *buffer; buffer = cb->p + (hdr->msgLength - size); size = ALIGN(size, SMSSDIO_BLOCK_SIZE); BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE); /* * First attempt to transfer all of it in one go... */ ret = sdio_memcpy_fromio(smsdev->func, buffer, SMSSDIO_DATA, size); if (ret && ret != -EINVAL) { smscore_putbuffer(smsdev->coredev, cb); sms_err("Error %d reading data from card!\n", ret); sdio_release_host(smsdev->func); return; } /* * ..then fall back to one block at a time if that is * not possible... * * (we have to do this manually because of the * problem with the "increase address" bit) */ if (ret == -EINVAL) { while (size) { ret = sdio_memcpy_fromio(smsdev->func, buffer, SMSSDIO_DATA, smsdev->func->cur_blksize); if (ret) { smscore_putbuffer(smsdev->coredev, cb); sms_err("Error %d reading " "data from card!\n", ret); sdio_release_host(smsdev->func); return; } buffer += smsdev->func->cur_blksize; if (size > smsdev->func->cur_blksize) size -= smsdev->func->cur_blksize; else size = 0; } } } sdio_release_host(smsdev->func); cb->size = hdr->msgLength; cb->offset = 0; smscore_onresponse(smsdev->coredev, cb); }
/** * @brief Transfer firmware to card * * @param priv A Pointer to bt_private structure * @return BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no. */ static int sd_init_fw_dpc(bt_private * priv) { struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card; u8 *firmware = NULL; int firmwarelen; u8 base0; u8 base1; int ret = BT_STATUS_SUCCESS; int offset; void *tmpfwbuf = NULL; int tmpfwbufsz; u8 *fwbuf; u16 len; int txlen = 0; int tx_blocks = 0; int i = 0; int tries = 0; #ifdef FW_DOWNLOAD_SPEED u32 tv1, tv2; #endif u8 crc_buffer = 0; ENTER(); firmware = (u8 *) priv->firmware->data; firmwarelen = priv->firmware->size; PRINTM(INFO, "BT: Downloading FW image (%d bytes)\n", firmwarelen); #ifdef FW_DOWNLOAD_SPEED tv1 = get_utimeofday(); #endif tmpfwbufsz = ALIGN_SZ(BT_UPLD_SIZE, DMA_ALIGNMENT); tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL); if (!tmpfwbuf) { PRINTM(ERROR, "BT: Unable to allocate buffer for firmware. Terminating download\n"); ret = BT_STATUS_FAILURE; goto done; } memset(tmpfwbuf, 0, tmpfwbufsz); /* Ensure 8-byte aligned firmware buffer */ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, DMA_ALIGNMENT); if (!(priv->fw_crc_check)) { /* CRC check not required, use custom header first */ firmware = fw_crc_header; firmwarelen = FW_CRC_HEADER; crc_buffer = 1; } /* Perform firmware data transfer */ offset = 0; do { /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY bits */ ret = sd_poll_card_status(priv, CARD_IO_READY | DN_LD_CARD_RDY); if (ret < 0) { PRINTM(FATAL, "BT: FW download with helper poll status timeout @ %d\n", offset); goto done; } if (!crc_buffer) /* More data? */ if (offset >= firmwarelen) break; for (tries = 0; tries < MAX_POLL_TRIES; tries++) { base0 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A0_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE0 register read failed:" " base0=0x%04X(%d). Terminating download\n", base0, base0); ret = BT_STATUS_FAILURE; goto done; } base1 = sdio_readb(card->func, SQ_READ_BASE_ADDRESS_A1_REG, &ret); if (ret) { PRINTM(WARN, "Dev BASE1 register read failed:" " base1=0x%04X(%d). Terminating download\n", base1, base1); ret = BT_STATUS_FAILURE; goto done; } len = (((u16) base1) << 8) | base0; if (len != 0) break; udelay(10); } if (len == 0) break; else if (len > BT_UPLD_SIZE) { PRINTM(FATAL, "BT: FW download failure @ %d, invalid length %d\n", offset, len); ret = BT_STATUS_FAILURE; goto done; } txlen = len; if (len & BIT(0)) { i++; if (i > MAX_WRITE_IOMEM_RETRY) { PRINTM(FATAL, "BT: FW download failure @ %d, over max retry count\n", offset); ret = BT_STATUS_FAILURE; goto done; } PRINTM(ERROR, "BT: FW CRC error indicated by the helper:" " len = 0x%04X, txlen = %d\n", len, txlen); len &= ~BIT(0); PRINTM(ERROR, "BT: retry: %d, offset %d\n", i, offset); DBG_HEXDUMP(ERROR, "BT: FW block:", fwbuf, len); /* Setting this to 0 to resend from same offset */ txlen = 0; } else { i = 0; /* Set blocksize to transfer - checking for last block */ if (firmwarelen - offset < txlen) txlen = firmwarelen - offset; PRINTM(INFO, "."); tx_blocks = (txlen + SD_BLOCK_SIZE_FW_DL - 1) / SD_BLOCK_SIZE_FW_DL; /* Copy payload to buffer */ memcpy(fwbuf, &firmware[offset], txlen); } /* Send data */ ret = sdio_writesb(card->func, priv->bt_dev.ioport, fwbuf, tx_blocks * SD_BLOCK_SIZE_FW_DL); if (ret < 0) { PRINTM(ERROR, "BT: FW download, write iomem (%d) failed @ %d\n", i, offset); sdio_writeb(card->func, 0x04, CONFIGURATION_REG, &ret); if (ret) PRINTM(ERROR, "write ioreg failed (CFG)\n"); } offset += txlen; if (crc_buffer) { if (offset >= FW_CRC_HEADER) { /* Custom header download complete, restore original FW */ offset = 0; firmware = (u8 *) priv->firmware->data; firmwarelen = priv->firmware->size; crc_buffer = 0; } } } while (TRUE); PRINTM(INFO, "\nBT: FW download over, size %d bytes\n", offset); ret = BT_STATUS_SUCCESS; done: #ifdef FW_DOWNLOAD_SPEED tv2 = get_utimeofday(); PRINTM(INFO, "FW: %ld.%03ld.%03ld ", tv1 / 1000000, (tv1 % 1000000) / 1000, tv1 % 1000); PRINTM(INFO, " -> %ld.%03ld.%03ld ", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); tv2 -= tv1; PRINTM(INFO, " == %ld.%03ld.%03ld\n", tv2 / 1000000, (tv2 % 1000000) / 1000, tv2 % 1000); #endif if (tmpfwbuf) kfree(tmpfwbuf); LEAVE(); return ret; }
static void iwmct_irq(struct sdio_func *func) { struct iwmct_priv *priv; int val, ret; int iosize; int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR; struct iwmct_work_struct *read_req; priv = sdio_get_drvdata(func); LOG_TRACE(priv, IRQ, "enter iwmct_irq\n"); /* read the function's status register */ val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret); LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); if (!val) { LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n"); goto exit_clear_intr; } /* * read 2 bytes of the transaction size * IMPORTANT: sdio transaction size has to be read before clearing * sdio interrupt!!! */ val = sdio_readb(priv->func, addr++, &ret); iosize = val; val = sdio_readb(priv->func, addr++, &ret); iosize += val << 8; LOG_INFO(priv, IRQ, "READ size %d\n", iosize); if (iosize == 0) { LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize); goto exit_clear_intr; } /* allocate a work structure to pass iosize to the worker */ read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL); if (!read_req) { LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n"); goto exit_clear_intr; } INIT_LIST_HEAD(&read_req->list); read_req->iosize = iosize; list_add_tail(&priv->read_req_list, &read_req->list); /* clear the function's interrupt request bit (write 1 to clear) */ sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); queue_work(priv->wq, &priv->isr_worker); LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); return; exit_clear_intr: /* clear the function's interrupt request bit (write 1 to clear) */ sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); }
static void iwm_sdio_isr(struct sdio_func *func) { struct iwm_priv *iwm; struct iwm_sdio_priv *hw; struct iwm_rx_info *rx_info; struct sk_buff *skb; unsigned long buf_size, read_size; int ret; u8 val; hw = sdio_get_drvdata(func); iwm = hw_to_iwm(hw); buf_size = hw->blk_size; /* We're checking the status */ val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret); if (val == 0 || ret < 0) { IWM_ERR(iwm, "Wrong INTR_STATUS\n"); return; } /* See if we have free buffers */ if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) { IWM_ERR(iwm, "No buffer for more Rx frames\n"); return; } /* We first read the transaction size */ read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret); read_size = read_size << 8; if (ret < 0) { IWM_ERR(iwm, "Couldn't read the xfer size\n"); return; } /* We need to clear the INT register */ sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret); if (ret < 0) { IWM_ERR(iwm, "Couldn't clear the INT register\n"); return; } while (buf_size < read_size) buf_size <<= 1; skb = dev_alloc_skb(buf_size); if (!skb) { IWM_ERR(iwm, "Couldn't alloc RX skb\n"); return; } rx_info = skb_to_rx_info(skb); rx_info->rx_size = read_size; rx_info->rx_buf_size = buf_size; /* Now we can read the actual buffer */ ret = sdio_memcpy_fromio(func, skb_put(skb, read_size), IWM_SDIO_DATA_ADDR, read_size); /* The skb is put on a driver's specific Rx SKB list */ skb_queue_tail(&iwm->rx_list, skb); /* We can now schedule the actual worker */ queue_work(hw->isr_wq, &hw->isr_worker); }
/** * @brief This function registers the device. * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ int sbi_register_dev(bt_private * priv) { int ret = BT_STATUS_SUCCESS; u8 reg; u8 chiprev; struct sdio_mmc_card *card = priv->bt_dev.card; struct sdio_func *func; ENTER(); if (!card || !card->func) { PRINTM(ERROR, "BT: Error: card or function is NULL!\n"); goto failed; } func = card->func; priv->hotplug_device = &func->dev; if (fw_name == NULL) fw_name = DEFAULT_FW_NAME; /* Initialize the private structure */ strncpy(priv->bt_dev.name, "bt_sdio0", sizeof(priv->bt_dev.name)); priv->bt_dev.ioport = 0; priv->bt_dev.fn = func->num; sdio_claim_host(func); ret = sdio_claim_irq(func, sd_interrupt); if (ret) { PRINTM(FATAL, "BT: sdio_claim_irq failed: ret=%d\n", ret); goto release_host; } ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE); if (ret) { PRINTM(FATAL, "BT: %s: cannot set SDIO block size\n", __FUNCTION__); goto release_irq; } /* read Revision Register to get the chip revision number */ chiprev = sdio_readb(func, CARD_REVISION_REG, &ret); if (ret) { PRINTM(FATAL, "BT: cannot read CARD_REVISION_REG\n"); goto release_irq; } priv->adapter->chip_rev = chiprev; PRINTM(INFO, "revision=%#x\n", chiprev); /* * Read the HOST_INTSTATUS_REG for ACK the first interrupt got * from the bootloader. If we don't do this we get a interrupt * as soon as we register the irq. */ reg = sdio_readb(func, HOST_INTSTATUS_REG, &ret); if (ret < 0) goto release_irq; /* Read the IO port */ reg = sdio_readb(func, IO_PORT_0_REG, &ret); if (ret < 0) goto release_irq; else priv->bt_dev.ioport |= reg; reg = sdio_readb(func, IO_PORT_1_REG, &ret); if (ret < 0) goto release_irq; else priv->bt_dev.ioport |= (reg << 8); reg = sdio_readb(func, IO_PORT_2_REG, &ret); if (ret < 0) goto release_irq; else priv->bt_dev.ioport |= (reg << 16); PRINTM(INFO, "BT: SDIO FUNC%d IO port: 0x%x\n", priv->bt_dev.fn, priv->bt_dev.ioport); #define SDIO_INT_MASK 0x3F /* Set Host interrupt reset to read to clear */ reg = sdio_readb(func, HOST_INT_RSR_REG, &ret); if (ret < 0) goto release_irq; sdio_writeb(func, reg | SDIO_INT_MASK, HOST_INT_RSR_REG, &ret); if (ret < 0) goto release_irq; /* Set auto re-enable */ reg = sdio_readb(func, CARD_MISC_CFG_REG, &ret); if (ret < 0) goto release_irq; sdio_writeb(func, reg | AUTO_RE_ENABLE_INT, CARD_MISC_CFG_REG, &ret); if (ret < 0) goto release_irq; sdio_set_drvdata(func, card); sdio_release_host(func); LEAVE(); return BT_STATUS_SUCCESS; release_irq: sdio_release_irq(func); release_host: sdio_release_host(func); failed: LEAVE(); return BT_STATUS_FAILURE; }
int sqn_wakeup_fw(struct sdio_func *func) { int rv = 0; int ver = 0; int counter = 0; int retry_cnt = 3; u32 wakeup_delay = 0; unsigned long timeout = msecs_to_jiffies(800); unsigned long irq_flags = 0; struct sqn_private *priv = ((struct sqn_sdio_card *)sdio_get_drvdata(func))->priv; struct sqn_sdio_card *card = priv->card; u8 need_to_unlock_wakelock = 0; sqn_pr_enter(); sqn_pr_info("waking up the card...\n"); if (!wake_lock_active(&card->wakelock_tx)) { if (mmc_wimax_get_sdio_wakelock_log()) { printk(KERN_INFO "[WIMAX] lock wl_tx2,"); PRINTRTC; } wake_lock(&card->wakelock_tx); need_to_unlock_wakelock = 1; } retry: if (priv->removed) goto out; sdio_claim_host(func); #define SDIO_CCCR_CCCR_SDIO_VERSION_VALUE 0x11 wakeup_delay = 2; counter = 5; do { sqn_pr_dbg("CMD52 #%d, delay %d msec\n", counter, wakeup_delay); ver = sdio_readb(func, SDIO_CCCR_CCCR_SDIO_VERSION, &rv); // To avoid FW sutck in PLLOFF, SDIO isn't able to wake up it. mdelay(wakeup_delay); --counter; } while((rv || ver != SDIO_CCCR_CCCR_SDIO_VERSION_VALUE) && counter > 0); if (rv) { sqn_pr_err("error when reading SDIO_VERSION\n"); if (mmc_wimax_get_wimax_FW_freeze_WK_TX()) { sqn_pr_info("[ste]set is_card_sleeps 0 to avoid TX polling\n"); card->is_card_sleeps = 0; } sdio_release_host(func); goto out; } else sqn_pr_dbg("SDIO_VERSION has been read successfully\n"); sqn_pr_dbg("send wake-up signal to card\n"); sdio_writeb(func, 1, SQN_SOC_SIGS_LSBS, &rv); if (rv) sqn_pr_err("error when writing to SQN_SOC_SIGS_LSBS: %d\n", rv); sdio_release_host(func); sqn_pr_info("wait for completion (timeout %d msec)...\n" , jiffies_to_msecs(timeout)); rv = wait_event_interruptible_timeout(g_card_sleep_waitq , 0 == card->is_card_sleeps || priv->removed, timeout); if (priv->removed) goto out; if (-ERESTARTSYS == rv) { sqn_pr_warn("got a signal from kernel %d\n", rv); } else if (0 == rv) { rv = -1; sqn_pr_err("can't wake up the card - timeout elapsed\n"); if (retry_cnt-- > 0 && card->is_card_sleeps) { sqn_pr_info("retry wake up\n"); goto retry; } sqn_pr_info("giving up to wake up the card\n"); spin_lock_irqsave(&priv->drv_lock, irq_flags); card->is_card_sleeps = 0; spin_unlock_irqrestore(&priv->drv_lock, irq_flags); } else { rv = 0; sqn_pr_info("card is waked up successfully\n"); } out: if (need_to_unlock_wakelock && wake_lock_active(&card->wakelock_tx)) { if (mmc_wimax_get_sdio_wakelock_log()) { printk(KERN_INFO "[WIMAX] release wake_lock_tx in %s,", __func__); PRINTRTC; } wake_unlock(&card->wakelock_tx); /* TX */ } sqn_pr_leave(); return rv; }
static void iwm_sdio_isr(struct sdio_func *func) { struct iwm_priv *iwm; struct iwm_sdio_priv *hw; struct iwm_rx_info *rx_info; struct sk_buff *skb; unsigned long buf_size, read_size; int ret; u8 val; hw = sdio_get_drvdata(func); iwm = hw_to_iwm(hw); buf_size = hw->blk_size; val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret); if (val == 0 || ret < 0) { IWM_ERR(iwm, "Wrong INTR_STATUS\n"); return; } if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) { IWM_ERR(iwm, "No buffer for more Rx frames\n"); return; } read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret); read_size = read_size << 8; if (ret < 0) { IWM_ERR(iwm, "Couldn't read the xfer size\n"); return; } sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret); if (ret < 0) { IWM_ERR(iwm, "Couldn't clear the INT register\n"); return; } while (buf_size < read_size) buf_size <<= 1; skb = dev_alloc_skb(buf_size); if (!skb) { IWM_ERR(iwm, "Couldn't alloc RX skb\n"); return; } rx_info = skb_to_rx_info(skb); rx_info->rx_size = read_size; rx_info->rx_buf_size = buf_size; ret = sdio_memcpy_fromio(func, skb_put(skb, read_size), IWM_SDIO_DATA_ADDR, read_size); skb_queue_tail(&iwm->rx_list, skb); queue_work(hw->isr_wq, &hw->isr_worker); }
unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr, int *err_ret) { return sdio_readb(func, addr, err_ret); }
static void smssdio_interrupt(struct sdio_func *func) { int ret, isr; struct smssdio_device *smsdev; struct smscore_buffer_t *cb; struct SmsMsgHdr_ST *hdr; size_t size; smsdev = sdio_get_drvdata(func); /* * The interrupt register has no defined meaning. It is just * a way of turning of the level triggered interrupt. */ isr = sdio_readb(func, SMSSDIO_INT, &ret); if (ret) { sms_err("Unable to read interrupt register!\n"); return; } if (smsdev->split_cb == NULL) { cb = smscore_getbuffer(smsdev->coredev); if (!cb) { sms_err("Unable to allocate data buffer!\n"); return; } ret = sdio_memcpy_fromio(smsdev->func, cb->p, SMSSDIO_DATA, SMSSDIO_BLOCK_SIZE); if (ret) { sms_err("Error %d reading initial block!\n", ret); return; } hdr = cb->p; if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { smsdev->split_cb = cb; return; } if (hdr->msgLength > smsdev->func->cur_blksize) size = hdr->msgLength - smsdev->func->cur_blksize; else size = 0; } else { cb = smsdev->split_cb; hdr = cb->p; size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); smsdev->split_cb = NULL; } if (size) { void *buffer; buffer = cb->p + (hdr->msgLength - size); size = ALIGN(size, SMSSDIO_BLOCK_SIZE); BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE); /* * First attempt to transfer all of it in one go... */ ret = sdio_memcpy_fromio(smsdev->func, buffer, SMSSDIO_DATA, size); if (ret && ret != -EINVAL) { smscore_putbuffer(smsdev->coredev, cb); sms_err("Error %d reading data from card!\n", ret); return; } /* * ..then fall back to one block at a time if that is * not possible... * * (we have to do this manually because of the * problem with the "increase address" bit) */ if (ret == -EINVAL) { while (size) { ret = sdio_memcpy_fromio(smsdev->func, buffer, SMSSDIO_DATA, smsdev->func->cur_blksize); if (ret) { smscore_putbuffer(smsdev->coredev, cb); sms_err("Error %d reading " "data from card!\n", ret); return; } buffer += smsdev->func->cur_blksize; if (size > smsdev->func->cur_blksize) size -= smsdev->func->cur_blksize; else size = 0; } } } cb->size = hdr->msgLength; cb->offset = 0; smscore_onresponse(smsdev->coredev, cb); }
/** * @brief This function registers the device. * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ int sbi_register_dev(bt_private *priv) { int ret = BT_STATUS_SUCCESS; u8 reg; u8 chiprev; struct sdio_mmc_card *card = priv->bt_dev.card; struct sdio_func *func; u8 host_intstatus_reg = HOST_INTSTATUS_REG; u8 card_revision_reg = CARD_REVISION_REG; u8 io_port_0_reg = IO_PORT_0_REG; u8 io_port_1_reg = IO_PORT_1_REG; u8 io_port_2_reg = IO_PORT_2_REG; ENTER(); if (!card || !card->func) { PRINTM(ERROR, "BT: Error: card or function is NULL!\n"); goto failed; } func = card->func; priv->hotplug_device = &func->dev; /* Initialize the private structure */ strncpy(priv->bt_dev.name, "bt_sdio0", sizeof(priv->bt_dev.name)); priv->bt_dev.ioport = 0; priv->bt_dev.fn = func->num; sdio_claim_host(func); ret = sdio_claim_irq(func, sd_interrupt); if (ret) { PRINTM(FATAL, ": sdio_claim_irq failed: ret=%d\n", ret); goto release_host; } ret = sdio_set_block_size(card->func, SD_BLOCK_SIZE); if (ret) { PRINTM(FATAL, ": %s: cannot set SDIO block size\n", __func__); goto release_irq; } /* read Revision Register to get the chip revision number */ chiprev = sdio_readb(func, card_revision_reg, &ret); if (ret) { PRINTM(FATAL, ": cannot read CARD_REVISION_REG\n"); goto release_irq; } priv->adapter->chip_rev = chiprev; PRINTM(INFO, "revision=%#x\n", chiprev); /* * Read the HOST_INTSTATUS_REG for ACK the first interrupt got * from the bootloader. If we don't do this we get a interrupt * as soon as we register the irq. */ reg = sdio_readb(func, host_intstatus_reg, &ret); if (ret < 0) goto release_irq; /* Read the IO port */ reg = sdio_readb(func, io_port_0_reg, &ret); if (ret < 0) goto release_irq; else priv->bt_dev.ioport |= reg; reg = sdio_readb(func, io_port_1_reg, &ret); if (ret < 0) goto release_irq; else priv->bt_dev.ioport |= (reg << 8); reg = sdio_readb(func, io_port_2_reg, &ret); if (ret < 0) goto release_irq; else priv->bt_dev.ioport |= (reg << 16); PRINTM(INFO, ": SDIO FUNC%d IO port: 0x%x\n", priv->bt_dev.fn, priv->bt_dev.ioport); sdio_set_drvdata(func, card); sdio_release_host(func); LEAVE(); return BT_STATUS_SUCCESS; release_irq: sdio_release_irq(func); release_host: sdio_release_host(func); failed: LEAVE(); return BT_STATUS_FAILURE; }
static void rtw_dev_remove(struct sdio_func *func) { PADAPTER padapter; struct net_device *pnetdev; #ifdef CONFIG_IOCTL_CFG80211 struct wireless_dev *wdev; #endif _func_enter_; RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n")); padapter = ((struct dvobj_priv*)sdio_get_drvdata(func))->padapter; #ifdef CONFIG_IOCTL_CFG80211 wdev = padapter->rtw_wdev; #endif #if defined(CONFIG_HAS_EARLYSUSPEND ) || defined(CONFIG_ANDROID_POWER) rtw_unregister_early_suspend(&padapter->pwrctrlpriv); #endif if (padapter->bSurpriseRemoved == _FALSE) { // test surprise remove int err; sdio_claim_host(func); sdio_readb(func, 0, &err); sdio_release_host(func); if (err == -ENOMEDIUM) { padapter->bSurpriseRemoved = _TRUE; DBG_871X(KERN_NOTICE "%s: device had been removed!\n", __func__); } } #ifdef CONFIG_HOSTAPD_MLME hostapd_mode_unload(padapter); #endif LeaveAllPowerSaveMode(padapter); pnetdev = (struct net_device*)padapter->pnetdev; if (pnetdev) { unregister_netdev(pnetdev); //will call netdev_close() RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("rtw_dev_remove: unregister netdev\n")); #ifdef CONFIG_PROC_DEBUG rtw_proc_remove_one(pnetdev); #endif } else { RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("rtw_dev_remove: NO padapter->pnetdev!\n")); } rtw_cancel_all_timer(padapter); rtw_dev_unload(padapter); // interface deinit sdio_deinit(padapter); RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("rtw_dev_remove: deinit intf complete!\n")); rtw_free_drv_sw(padapter); #ifdef CONFIG_IOCTL_CFG80211 rtw_wdev_free(wdev); #endif RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n")); _func_exit_; }
static struct buffer_descriptor *rx_packet(struct net_adapter *adapter) { int ret = 0; int read_idx; struct buffer_descriptor *bufdsc; s32 t_len; s32 t_index; s32 t_size; u8 *t_buff; read_idx = sdio_readb(adapter->func, SDIO_C2H_RP_REG, &ret); bufdsc = kmalloc(sizeof(*bufdsc), GFP_KERNEL); if (unlikely(!bufdsc)) { pr_err("%s bufdsc alloc fail", __func__); return NULL; } if (unlikely(ret)) { pr_err("%s sdio_readb error", __func__); schedule_work(&adapter->wimax_reset); goto err; } #if 0 /*check modem buffer overflow*/ if (read_idx == sdio_readb(adapter->func, SDIO_C2H_WP_REG, &ret)) { read_idx = -1; goto err; } #endif #ifdef CMC7xx_MULTIPACKET_SUPPORT if (adapter->download_complete) t_len = sdio_readl(adapter->func, (SDIO_RX_BANK_ADDR + (read_idx * SDIO_RXBANK_SIZE)), &ret); else #endif t_len = sdio_readl(adapter->func, (SDIO_RX_BANK_ADDR + (read_idx * SDIO_BANK_SIZE)), &ret); if (unlikely(ret)) { pr_err("%s sdio_readl error", __func__); schedule_work(&adapter->wimax_reset); goto err; } #ifdef CMC7xx_MULTIPACKET_SUPPORT if (adapter->download_complete) { if (unlikely(t_len > (SDIO_RXBANK_SIZE - CMC732_PACKET_LENGTH_SIZE))) { pr_err("%s length out of bound", __func__); t_len = SDIO_RXBANK_SIZE - CMC732_PACKET_LENGTH_SIZE; } sdio_writeb(adapter->func, (read_idx + 1) % SDIO_RXBANK_COUNT, SDIO_C2H_RP_REG, NULL); } else #endif { if (unlikely(t_len > (SDIO_BANK_SIZE - CMC732_PACKET_LENGTH_SIZE))) { pr_err("%s length out of bound", __func__); t_len = SDIO_BANK_SIZE - CMC732_PACKET_LENGTH_SIZE; } sdio_writeb(adapter->func, (read_idx + 1) % 16, SDIO_C2H_RP_REG, NULL); } bufdsc->buffer = kmalloc(t_len, GFP_KERNEL); if (unlikely(!bufdsc->buffer)) { pr_err("%s bufdsc->buffer alloc fail", __func__); goto err; } bufdsc->length = (s32)t_len; t_buff = (u8 *)bufdsc->buffer; #ifdef RX_SINGLE_BLOCK_MODE #ifdef CMC7xx_MULTIPACKET_SUPPORT if (adapter->download_complete) t_index = (SDIO_RX_BANK_ADDR + (SDIO_RXBANK_SIZE * read_idx) + 4); else #endif t_index = (SDIO_RX_BANK_ADDR + (SDIO_BANK_SIZE * read_idx) + 4); while (likely(t_len)) { t_size = (t_len > CMC_BLOCK_SIZE) ? (CMC_BLOCK_SIZE) : t_len; ret = sdio_memcpy_fromio(adapter->func, (void *)t_buff, t_index, t_size); if (unlikely(ret)) { pr_err("%s sdio_memcpy_fromio fail\n", __func__); schedule_work(&adapter->wimax_reset); goto err_2; } t_len -= t_size; t_buff += t_size; t_index += t_size; } #else ret = sdio_memcpy_fromio(adapter->func, (void *)t_buff, t_index, t_len); if (unlikely(ret)) { pr_err("%s sdio_memcpy_fromio fail", __func__); schedule_work(&adapter->wimax_reset); goto err_2; } #endif return bufdsc; err_2: kfree(bufdsc->buffer); err: kfree(bufdsc); adapter->netstats.rx_dropped++; return NULL; }
int wlan_prog_helper(const uint8_t * firmware, int size) { int ret; uint8_t status; uint8_t *chunk_buffer; uint32_t chunk_size; uint64_t startTime; bufferPrintf("wlan: programming firmware helper...\r\n"); chunk_buffer = (uint8_t*) memalign(64, 4); if (!chunk_buffer) { ret = -1; goto release_fw; } ret = sdio_set_block_size(1, 32); if (ret) goto release; while (size) { startTime = timer_get_system_microtime(); while (TRUE) { status = sdio_readb(1, IF_SDIO_STATUS, &ret); if (ret) goto release; if ((status & IF_SDIO_IO_RDY) && (status & IF_SDIO_DL_RDY)) break; if(has_elapsed(startTime, 1000 * 1000)) { ret = -1; goto release; } udelay(1000); } if(size > 60) chunk_size = 60; else chunk_size = size; *((uint32_t*)chunk_buffer) = chunk_size; memcpy(chunk_buffer + 4, firmware, chunk_size); //bufferPrintf("wlan: sending %d bytes chunk\r\n", chunk_size); ret = sdio_writesb(1, ioport, chunk_buffer, 64); if (ret) goto release; firmware += chunk_size; size -= chunk_size; } /* an empty block marks the end of the transfer */ memset(chunk_buffer, 0, 4); ret = sdio_writesb(1, ioport, chunk_buffer, 64); if (ret) goto release; bufferPrintf("wlan: waiting for helper to boot\r\n"); /* wait for the helper to boot by looking at the size register */ startTime = timer_get_system_microtime(); while (TRUE) { uint16_t req_size; req_size = sdio_readb(1, IF_SDIO_RD_BASE, &ret); if (ret) goto release; req_size |= sdio_readb(1, IF_SDIO_RD_BASE + 1, &ret) << 8; if (ret) goto release; if (req_size != 0) break; if(has_elapsed(startTime, 1000 * 1000)) { ret = -1; goto release; } udelay(10000); } ret = 0; bufferPrintf("wlan: helper has booted!\r\n"); release: free(chunk_buffer); release_fw: if (ret) bufferPrintf("wlan: failed to load helper firmware\r\n"); return ret; }
int wlan_prog_real(const uint8_t* firmware, size_t size) { int ret; uint8_t status; uint8_t *chunk_buffer; uint32_t chunk_size; size_t req_size; uint64_t startTime; bufferPrintf("wlan: programming firmware...\r\n"); chunk_buffer = (uint8_t*) memalign(512, 4); if (!chunk_buffer) { ret = -1; goto release_fw; } ret = sdio_set_block_size(1, 32); if (ret) goto release; while (size) { startTime = timer_get_system_microtime(); while (1) { status = sdio_readb(1, IF_SDIO_STATUS, &ret); if (ret) goto release; if ((status & IF_SDIO_IO_RDY) && (status & IF_SDIO_DL_RDY)) break; if(has_elapsed(startTime, 1000 * 1000)) { ret = -1; goto release; } udelay(1000); } req_size = sdio_readb(1, IF_SDIO_RD_BASE, &ret); if (ret) goto release; req_size |= sdio_readb(1, IF_SDIO_RD_BASE + 1, &ret) << 8; if (ret) goto release; //bufferPrintf("wlan: firmware helper wants %d bytes\r\n", (int)req_size); if (req_size == 0) { bufferPrintf("wlan: firmware helper gave up early\r\n"); ret = -1; goto release; } if (req_size & 0x01) { bufferPrintf("wlan: firmware helper signalled error\r\n"); ret = -1; goto release; } if (req_size > size) req_size = size; while (req_size) { if(req_size > 512) chunk_size = 512; else chunk_size = req_size; memcpy(chunk_buffer, firmware, chunk_size); //bufferPrintf("wlan: sending %d bytes (%d bytes) chunk\r\n", // chunk_size, (chunk_size + 31) / 32 * 32); int to_send; to_send = chunk_size / 32; to_send *= 32; if(to_send < chunk_size) to_send += 32; ret = sdio_writesb(1, ioport, chunk_buffer, to_send); if (ret) goto release; firmware += chunk_size; size -= chunk_size; req_size -= chunk_size; } } ret = 0; bufferPrintf("wlan: waiting for firmware to boot\r\n"); /* wait for the firmware to boot */ startTime = timer_get_system_microtime(); while (TRUE) { uint16_t scratch; scratch = wlan_read_scratch(&ret); if (ret) goto release; if (scratch == IF_SDIO_FIRMWARE_OK) break; if(has_elapsed(startTime, 1000 * 1000)) { ret = -1; goto release; } udelay(10000); } ret = 0; bufferPrintf("wlan: firmware booted!\r\n"); release: free(chunk_buffer); release_fw: if (ret) bufferPrintf("wlan: failed to load firmware\r\n"); return ret; }