/** * @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; }
/** * @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; }
/** * @brief This function hanldes the major job in WLAN driver. * it handles the event generated by firmware, rx data received * from firmware and tx data sent from kernel. * * @param data A pointer to wlan_thread structure * @return WLAN_STATUS_SUCCESS */ static void wlan_service_main_thread(cyg_addrword_t data) { struct eth_drv_sc *sc = (struct eth_drv_sc *)data; wlan_private *priv = (wlan_private *)sc->driver_private; w99702_priv_t * priv702 = priv->priv; wlan_thread *thread = &priv->MainThread; wlan_adapter *Adapter = priv->adapter; //wait_queue_t wait; cyg_uint8 ireg = 0; int volatile save_irq; int x; int ret; //OS_INTERRUPT_SAVE_AREA; ENTER(); wlan_activate_thread(thread); thread_stop_ptr[0] = NULL; //init_waitqueue_entry(&wait, current); for (;;) { #if 0 diag_printf("main-thread 111: IntCounter=%d " "CurCmd=%p CmdPending=%s Connect=%d " "dnld_sent=%d\n", Adapter->IntCounter, Adapter->CurCmd, list_empty(&Adapter->CmdPendingQ) ? "N" : "Y", Adapter->MediaConnectStatus, /*Adapter->CurrentTxSkb,*/ priv->wlan_dev.dnld_sent); #endif //add_wait_queue(&thread->waitQ, &wait); //OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE); TX_DISABLE; if ((Adapter->WakeupTries) || (Adapter->PSState == PS_STATE_SLEEP && !Adapter->bWakeupDevRequired) || (!Adapter->IntCounter && (priv->wlan_dev.dnld_sent || !Adapter->wmm.enabled || Adapter->TxLockFlag /*|| !os_queue_is_active(priv)*/ || wmm_lists_empty(priv)) && (priv->wlan_dev.dnld_sent || Adapter->TxLockFlag || !Adapter->TxSkbNum) && (priv->wlan_dev.dnld_sent || Adapter->CurCmd || list_empty(&Adapter->CmdPendingQ)) ) ) { #if 0 diag_printf( "main-thread sleeping... Conn=%d IntC=%d PS_Mode=%d PS_State=%d\n", Adapter->MediaConnectStatus, Adapter->IntCounter, Adapter->PSMode, Adapter->PSState); #endif #ifdef _MAINSTONE MST_LEDDAT1 = get_utimeofday(); #endif TX_RESTORE; //schedule(); /* Lock control thread to avoid re-entry when waiting event. ??? */ //cyg_mutex_lock(&thread->waitQ_mutex); //diag_printf("main_thread wait\n"); /* Waitint until any event input */ x = cyg_flag_wait( &thread->waitQ_flag_q, -1, CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR ); //diag_printf("main_thread wakeup %d\n", Adapter->IntCounter); /* ----------if keypad pressed then print message----------------- */ //if ( 2 & x ) } else { TX_RESTORE; } #if 0 diag_printf( "main-thread 222 (waking up): IntCounter=%d " "dnld_sent=%d\n", Adapter->IntCounter, /*Adapter->CurrentTxSkb,*/ priv->wlan_dev.dnld_sent); //OS_SET_THREAD_STATE(TASK_RUNNING); //remove_wait_queue(&thread->waitQ, &wait); diag_printf("main-thread 333: IntCounter=%d "//CurrentTxSkb=%p "dnld_sent=%d g_NeedWakeupMainThread = %d\n", Adapter->IntCounter, /*Adapter->CurrentTxSkb,*/ priv->wlan_dev.dnld_sent, g_WakeupMainThreadStatus); #endif if (thread_should_stop() || Adapter->SurpriseRemoved) { diag_printf( "main-thread: break from main thread: SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved); break; } //OS_INT_DISABLE(save_irq); if(Adapter->IntCounter) { Adapter->IntCounter = 0; if ((ret = sbi_get_int_status(sc, &ireg)) < 0) { diag_printf("main-thread: reading HOST_INT_STATUS_REG failed\n"); //OS_INT_RESTORE(save_irq); continue; } OS_INT_DISABLE(save_irq); Adapter->HisRegCpy |= ireg; OS_INT_RESTORE(save_irq); } //else if (Adapter->bWakeupDevRequired && ((Adapter->PSState == PS_STATE_SLEEP))) else if (Adapter->bWakeupDevRequired && Adapter->HS_Activated) //JONO { //OS_INT_RESTORE(save_irq); Adapter->WakeupTries++; /* we borrow deep_sleep wakeup code for time being */ if (sbi_exit_deep_sleep(priv)) diag_printf("main-thread: wakeup dev failed\n"); continue; } //else OS_INT_RESTORE(save_irq); #if 0 diag_printf("main-thread 444: IntCounter=%d "// CurrentTxSkb=%p "dnld_sent=%d TxSkbNum=%d\n", Adapter->IntCounter, /*Adapter->CurrentTxSkb,*/ priv->wlan_dev.dnld_sent, Adapter->TxSkbNum); diag_printf("Adapter->HisRegCpy = %x, %d, %d, %d\n", Adapter->HisRegCpy, priv->wlan_dev.dnld_sent, Adapter->TxLockFlag, priv->open); #endif /* Command response? */ if (Adapter->HisRegCpy & HIS_CmdUpLdRdy) { //diag_printf("main-thread: Cmd response ready.\n"); OS_INT_DISABLE(save_irq); Adapter->HisRegCpy &= ~HIS_CmdUpLdRdy; OS_INT_RESTORE(save_irq); wlan_process_rx_command(priv); } /* Any received data? */ #if 1 if (Adapter->HisRegCpy & HIS_RxUpLdRdy) { //diag_printf("main-thread: Rx Packet ready.\n"); OS_INT_DISABLE(save_irq); Adapter->HisRegCpy &= ~HIS_RxUpLdRdy; OS_INT_RESTORE(save_irq); //wlan_send_rxskbQ(priv); if((priv702->rx_head != priv702->rx_tail) || !priv702->rx_head->mode) eth_drv_dsr(0, 0, (cyg_addrword_t)sc); } else OS_INT_RESTORE(save_irq); #endif /* Any Card Event */ if (Adapter->HisRegCpy & HIS_CardEvent) { //diag_printf("main-thread: Card Event Activity.\n"); OS_INT_DISABLE(save_irq); Adapter->HisRegCpy &= ~HIS_CardEvent; OS_INT_RESTORE(save_irq); if (sbi_read_event_cause(priv)) { diag_printf("main-thread: sbi_read_event_cause failed.\n"); continue; } wlan_process_event(priv); } /* Check if we need to confirm Sleep Request received previously */ if (Adapter->PSState == PS_STATE_PRE_SLEEP) { if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) { if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { diag_printf( "main_thread: PRE_SLEEP--IntCounter=%d "// CurrentTxSkb=%p "dnld_sent=%d CurCmd=%p, confirm now\n", Adapter->IntCounter, /*Adapter->CurrentTxSkb,*/ priv->wlan_dev.dnld_sent, Adapter->CurCmd); PSConfirmSleep(priv, (cyg_uint16) Adapter->PSMode); } else { /* workaround for firmware sending deauth/linkloss event immediately after sleep request, remove this after firmware fixes it */ Adapter->PSState = PS_STATE_AWAKE; diag_printf( "main-thread: ignore PS_SleepConfirm in non-connected state\n"); } } } /* The PS state is changed during processing of Sleep Request event above */ if ((priv->adapter->PSState == PS_STATE_SLEEP) || (priv->adapter->PSState == PS_STATE_PRE_SLEEP) ) { diag_printf("999 The PS state is changed during processing ... %d\n", priv->adapter->PSState); continue; //JONO } if (Adapter->HS_Activated && Adapter->bWakeupDevRequired) { //JONO diag_printf( "main-thread: cannot send command or date, HS_Activated=%d\n", Adapter->HS_Activated); //JONO continue; } /* Execute the next command */ if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) { ExecuteNextCommand(priv); } if (Adapter->wmm.enabled) { if (!wmm_lists_empty(priv) && (priv->open == TRUE)/* && os_queue_is_active(priv)*/) { if ((Adapter->PSState == PS_STATE_FULL_POWER) || (Adapter->sleep_period.period == 0) || (Adapter->TxLockFlag == FALSE)) //wmm_process_tx(priv); handle_send(sc); } } else { if (!priv->wlan_dev.dnld_sent && (Adapter->TxLockFlag == false) &&(priv->open == TRUE) /*&& !list_empty((struct list_head *) &priv->adapter->TxSkbQ)*/) { //wlan_process_txqueue(priv); //diag_printf("send01\n"); handle_send(sc); //diag_printf("send02\n"); } } } wlan_deactivate_thread(thread); LEAVE(); return ;//WLAN_STATUS_SUCCESS; }