コード例 #1
0
/** 
 *  @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;
}
コード例 #2
0
/** 
 *  @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;
}
コード例 #3
0
ファイル: wlan_main.c プロジェクト: LucidOne/Rovio
/** 
 *  @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;
}