Exemplo n.º 1
0
static int ProcessCreditCounterReadBuffer(u8 *pBuffer, int Length)
{
    int     credits = 0;
    
    /* theory of how this works:
     * We read the credit decrement register multiple times on a byte-wide basis. 
     * The number of times (32) aligns the I/O operation to be a multiple of 4 bytes and provides a 
     * reasonable chance to acquire "all" pending credits in a single I/O operation. 
     * 
     * Once we obtain the filled buffer, we can walk through it looking for credit decrement transitions.
     * Each non-zero byte represents a single credit decrement (which is a credit given back to the host)
     * For example if the target provides 3 credits and added 4 more during the 32-byte read operation the following
     * pattern "could" appear:
     * 
     *    0x3 0x2 0x1 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1 0x0 0x1 0x0 0x1 0x0 ......rest zeros
     *    <--------->                     <----------------------------->
     *         \_ credits aleady there              \_ target adding 4 more credits
     * 
     *    The total available credits would be 7, since there are 7 non-zero bytes in the buffer.
     * 
     * */
    
    if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
        DebugDumpBytes(pBuffer, Length, "GMBOX Credit read buffer");
    } 
        
    while (Length) {
        if (*pBuffer != 0) {
            credits++;    
        }
        Length--;
        pBuffer++;   
    }  
    
    return credits;
}
Exemplo n.º 2
0
static A_STATUS HTCProcessTrailer(HTC_TARGET     *target,
                                  A_UINT8        *pBuffer,
                                  int             Length,
                                  HTC_ENDPOINT_ID FromEndpoint)
{
    HTC_RECORD_HDR          *pRecord;
    A_UINT8                 htc_rec_id;
    A_UINT8                 htc_rec_len;
    A_UINT8                 *pRecordBuf;
    A_UINT8                 *pOrigBuffer;
    int                     origLength;
    A_STATUS                status;

    AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));

    if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
        AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
    }

    pOrigBuffer = pBuffer;
    origLength = Length;
    status = A_OK;

    while (Length > 0) {

        if (Length < sizeof(HTC_RECORD_HDR)) {
            status = A_EPROTO;
            break;
        }
            /* these are byte aligned structs */
        pRecord = (HTC_RECORD_HDR *)pBuffer;
        Length -= sizeof(HTC_RECORD_HDR);
        pBuffer += sizeof(HTC_RECORD_HDR);

        htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH);
        htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID);

        if (htc_rec_len > Length) {
                /* no room left in buffer for record */
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
                (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
                        htc_rec_len, htc_rec_id, Length));
            status = A_EPROTO;
            break;
        }
            /* start of record follows the header */
        pRecordBuf = pBuffer;

        switch (htc_rec_id) {
            case HTC_RECORD_CREDITS:
                AR_DEBUG_ASSERT(htc_rec_len >= sizeof(HTC_CREDIT_REPORT));
                HTCProcessCreditRpt(target,
                                    (HTC_CREDIT_REPORT *)pRecordBuf,
                                    htc_rec_len / (sizeof(HTC_CREDIT_REPORT)),
                                    FromEndpoint);
                break;
            default:
                AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
                        htc_rec_id, htc_rec_len));
                break;
        }

        if (A_FAILED(status)) {
            break;
        }

            /* advance buffer past this record for next time around */
        pBuffer += htc_rec_len; 
        Length -= htc_rec_len;
    }

    if (A_FAILED(status)) {
        DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
    return status;

}
/* process pending interrupts synchronously */
static int ProcessPendingIRQs(AR6K_DEVICE *pDev, bool *pDone, bool *pASyncProcessing)
{
    int    status = 0;
    u8 host_int_status = 0;
    u32 lookAhead = 0;

    AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+ProcessPendingIRQs: (dev: 0x%lX)\n", (unsigned long)pDev));

    /*** NOTE: the HIF implementation guarantees that the context of this call allows
     *         us to perform SYNCHRONOUS I/O, that is we can block, sleep or call any API that
     *         can block or switch thread/task ontexts.
     *         This is a fully schedulable context.
     * */
    do {

            if (pDev->IrqEnableRegisters.int_status_enable == 0) {
                /* interrupt enables have been cleared, do not try to process any pending interrupts that
                 * may result in more bus transactions.  The target may be unresponsive at this
                 * point. */
                 break;
            }

            if (pDev->GetPendingEventsFunc != NULL) {
                HIF_PENDING_EVENTS_INFO events;

#ifdef THREAD_X
            events.Polling= 0;
#endif
                /* the HIF layer uses a special mechanism to get events
                 * get this synchronously  */
            status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
                                                &events,
                                                NULL);

            if (status) {
                break;
            }

            if (events.Events & HIF_RECV_MSG_AVAIL) {
                lookAhead = events.LookAhead;
                if (0 == lookAhead) {
                    AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs1 lookAhead is zero! \n"));
                }
            }

            if (!(events.Events & HIF_OTHER_EVENTS) ||
                !(pDev->IrqEnableRegisters.int_status_enable & OTHER_INTS_ENABLED)) {
                    /* no need to read the register table, no other interesting interrupts.
                     * Some interfaces (like SPI) can shadow interrupt sources without
                     * requiring the host to do a full table read */
                break;
            }

            /* otherwise fall through and read the register table */
        }

        /*
         * Read the first 28 bytes of the HTC register table. This will yield us
         * the value of different int status registers and the lookahead
         * registers.
         *    length = sizeof(int_status) + sizeof(cpu_int_status) +
         *             sizeof(error_int_status) + sizeof(counter_int_status) +
         *             sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
         *             sizeof(hole) +  sizeof(rx_lookahead) +
         *             sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
         *             sizeof(error_status_enable) +
         *             sizeof(counter_int_status_enable);
         *
        */
#ifdef CONFIG_MMC_SDHCI_S3C
            pDev->IrqProcRegisters.host_int_status = 0;
            pDev->IrqProcRegisters.rx_lookahead_valid = 0;
            pDev->IrqProcRegisters.host_int_status2 = 0;
            pDev->IrqProcRegisters.rx_lookahead[0] = 0;
            pDev->IrqProcRegisters.rx_lookahead[1] = 0xaaa5555;
#endif /* CONFIG_MMC_SDHCI_S3C */
        status = HIFReadWrite(pDev->HIFDevice,
                              HOST_INT_STATUS_ADDRESS,
                              (u8 *)&pDev->IrqProcRegisters,
                              AR6K_IRQ_PROC_REGS_SIZE,
                              HIF_RD_SYNC_BYTE_INC,
                              NULL);

        if (status) {
            break;
        }

#ifdef ATH_DEBUG_MODULE
        if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
            DevDumpRegisters(pDev,
                             &pDev->IrqProcRegisters,
                             &pDev->IrqEnableRegisters);
        }
#endif

            /* Update only those registers that are enabled */
        host_int_status = pDev->IrqProcRegisters.host_int_status &
                          pDev->IrqEnableRegisters.int_status_enable;

        if (NULL == pDev->GetPendingEventsFunc) {
                /* only look at mailbox status if the HIF layer did not provide this function,
                 * on some HIF interfaces reading the RX lookahead is not valid to do */
            if (host_int_status & (1 << HTC_MAILBOX)) {
                    /* mask out pending mailbox value, we use "lookAhead" as the real flag for
                     * mailbox processing below */
                host_int_status &= ~(1 << HTC_MAILBOX);
                if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX)) {
                        /* mailbox has a message and the look ahead is valid */
                    lookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
                    if (0 == lookAhead) {
                        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs2, lookAhead is zero! \n"));
                    }
                }
            }
        } else {
                /* not valid to check if the HIF has another mechanism for reading mailbox pending status*/
            host_int_status &= ~(1 << HTC_MAILBOX);
        }

        if (pDev->GMboxEnabled) {
                /*call GMBOX layer to process any interrupts of interest */
            status = DevCheckGMboxInterrupts(pDev);
        }

    } while (false);


    do {

            /* did the interrupt status fetches succeed? */
        if (status) {
            break;
        }

        if ((0 == host_int_status) && (0 == lookAhead)) {
                /* nothing to process, the caller can use this to break out of a loop */
            *pDone = true;
            break;
        }

        if (lookAhead != 0) {
            int fetched = 0;

            AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Pending mailbox message, LookAhead: 0x%X\n",lookAhead));
                /* Mailbox Interrupt, the HTC layer may issue async requests to empty the
                 * mailbox...
                 * When emptying the recv mailbox we use the async handler above called from the
                 * completion routine of the callers read request. This can improve performance
                 * by reducing context switching when we rapidly pull packets */
            status = pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, 1, pASyncProcessing, &fetched);
            if (status) {
                break;
            }

            if (!fetched) {
                    /* HTC could not pull any messages out due to lack of resources */
                    /* force DSR handler to ack the interrupt */
                *pASyncProcessing = false;
                pDev->RecheckIRQStatusCnt = 0;
            }
        }

            /* now handle the rest of them */
        AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
                            (" Valid interrupt source(s) for OTHER interrupts: 0x%x\n",
                            host_int_status));

        if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
                /* CPU Interrupt */
            status = DevServiceCPUInterrupt(pDev);
            if (status){
                break;
            }
        }

        if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
                /* Error Interrupt */
            status = DevServiceErrorInterrupt(pDev);
            if (status){
                break;
            }
        }

        if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
                /* Counter Interrupt */
            status = DevServiceCounterInterrupt(pDev);
            if (status){
                break;
            }
        }

    } while (false);

        /* an optimization to bypass reading the IRQ status registers unecessarily which can re-wake
         * the target, if upper layers determine that we are in a low-throughput mode, we can
         * rely on taking another interrupt rather than re-checking the status registers which can
         * re-wake the target.
         *
         * NOTE : for host interfaces that use the special GetPendingEventsFunc, this optimization cannot
         * be used due to possible side-effects.  For example, SPI requires the host to drain all
         * messages from the mailbox before exiting the ISR routine. */
    if (!(*pASyncProcessing) && (pDev->RecheckIRQStatusCnt == 0) && (pDev->GetPendingEventsFunc == NULL)) {
        AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Bypassing IRQ Status re-check, forcing done \n"));
        *pDone = true;
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-ProcessPendingIRQs: (done:%d, async:%d) status=%d \n",
                *pDone, *pASyncProcessing, status));

    return status;
}
Exemplo n.º 4
0
/* Start HTC, enable interrupts and let the target know host has finished setup */
A_STATUS HTCStart(HTC_HANDLE HTCHandle)
{
    HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
    HTC_PACKET *pPacket;
    A_STATUS   status;

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Enter\n"));
	printk("HTCStart Enter\n");

        /* make sure interrupts are disabled at the chip level,
         * this function can be called again from a reboot of the target without shutting down HTC */
    DevDisableInterrupts(&target->Device);
        /* make sure state is cleared again */
    target->HTCStateFlags = 0;
        
        /* now that we are starting, push control receive buffers into the
         * HTC control endpoint */

    while (1) {
        pPacket = HTC_ALLOC_CONTROL_RX(target);
        if (NULL == pPacket) {
            break;
        }
        HTCAddReceivePkt((HTC_HANDLE)target,pPacket);
    }

    do {

        AR_DEBUG_ASSERT(target->InitCredits != NULL);
        AR_DEBUG_ASSERT(target->EpCreditDistributionListHead != NULL);
        AR_DEBUG_ASSERT(target->EpCreditDistributionListHead->pNext != NULL);

            /* call init credits callback to do the distribution ,
             * NOTE: the first entry in the distribution list is ENDPOINT_0, so
             * we pass the start of the list after this one. */
        target->InitCredits(target->pCredDistContext,
                            target->EpCreditDistributionListHead->pNext,
                            target->TargetCredits);

        if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
            DumpCreditDistStates(target);
        }

            /* the caller is done connecting to services, so we can indicate to the
            * target that the setup phase is complete */
        status = HTCSendSetupComplete(target);
        if (A_FAILED(status)) {
            break;
        }

        /* unmask interrupts */
        status = DevUnmaskInterrupts(&target->Device);
        if (A_FAILED(status)) {
            HTCStop(target);
        }

    } while (FALSE);

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCStart Exit\n"));
	printk("HTCStart Exit\n");
    return status;
}
Exemplo n.º 5
0
/* process pending interrupts synchronously */
static A_STATUS ProcessPendingIRQs(AR6K_DEVICE *pDev, A_BOOL *pDone, A_BOOL *pASyncProcessing)
{
    A_STATUS    status = A_OK;
    A_UINT8     host_int_status = 0;
    A_UINT32    lookAhead = 0;

    AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+ProcessPendingIRQs: (dev: 0x%X)\n", (A_UINT32)pDev));

    /*** NOTE: the HIF implementation guarantees that the context of this call allows
     *         us to perform SYNCHRONOUS I/O, that is we can block, sleep or call any API that
     *         can block or switch thread/task ontexts.
     *         This is a fully schedulable context.
     * */
    do {

        if (pDev->IrqEnableRegisters.int_status_enable == 0) {
            /* interrupt enables have been cleared, do not try to process any pending interrupts that
             * may result in more bus transactions.  The target may be unresponsive at this
             * point. */
             break;    
        }
        
        if (pDev->GetPendingEventsFunc != NULL) {
            HIF_PENDING_EVENTS_INFO events;

                /* the HIF layer uses a special mechanism to get events
                 * get this synchronously  */
            status = pDev->GetPendingEventsFunc(pDev->HIFDevice,
                                                &events,
                                                NULL);

            if (A_FAILED(status)) {
                break;
            }

            if (events.Events & HIF_RECV_MSG_AVAIL) {
                lookAhead = events.LookAhead;
                if (0 == lookAhead) {
                    AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs1 lookAhead is zero! \n"));
                }
            }

            if (!(events.Events & HIF_OTHER_EVENTS) ||
                !(pDev->IrqEnableRegisters.int_status_enable & OTHER_INTS_ENABLED)) {
                    /* no need to read the register table, no other interesting interrupts.
                     * Some interfaces (like SPI) can shadow interrupt sources without
                     * requiring the host to do a full table read */
                break;
            }

            /* otherwise fall through and read the register table */
        }

        /*
         * Read the first 28 bytes of the HTC register table. This will yield us
         * the value of different int status registers and the lookahead
         * registers.
         *    length = sizeof(int_status) + sizeof(cpu_int_status) +
         *             sizeof(error_int_status) + sizeof(counter_int_status) +
         *             sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
         *             sizeof(hole) +  sizeof(rx_lookahead) +
         *             sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
         *             sizeof(error_status_enable) +
         *             sizeof(counter_int_status_enable);
         *
        */
        status = HIFReadWrite(pDev->HIFDevice,
                              HOST_INT_STATUS_ADDRESS,
                              (A_UINT8 *)&pDev->IrqProcRegisters,
                              AR6K_IRQ_PROC_REGS_SIZE,
                              HIF_RD_SYNC_BYTE_INC,
                              NULL);

        if (A_FAILED(status)) {
            break;
        }

        if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) {
            DevDumpRegisters(&pDev->IrqProcRegisters,
                             &pDev->IrqEnableRegisters);
        }

            /* Update only those registers that are enabled */
        host_int_status = pDev->IrqProcRegisters.host_int_status &
                          pDev->IrqEnableRegisters.int_status_enable;

        if (NULL == pDev->GetPendingEventsFunc) {
                /* only look at mailbox status if the HIF layer did not provide this function,
                 * on some HIF interfaces reading the RX lookahead is not valid to do */
            if (host_int_status & (1 << HTC_MAILBOX)) {
                    /* mask out pending mailbox value, we use "lookAhead" as the real flag for
                     * mailbox processing below */
                host_int_status &= ~(1 << HTC_MAILBOX);
                if (pDev->IrqProcRegisters.rx_lookahead_valid & (1 << HTC_MAILBOX)) {
                        /* mailbox has a message and the look ahead is valid */
                    lookAhead = pDev->IrqProcRegisters.rx_lookahead[HTC_MAILBOX];
                    if (0 == lookAhead) {
                        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ProcessPendingIRQs2, lookAhead is zero! \n"));
                    }
                }
            }
        } else {
                /* not valid to check if the HIF has another mechanism for reading mailbox pending status*/
            host_int_status &= ~(1 << HTC_MAILBOX);
        }

    } while (FALSE);


    do {

            /* did the interrupt status fetches succeed? */
        if (A_FAILED(status)) {
            break;
        }

        if ((0 == host_int_status) && (0 == lookAhead)) {
                /* nothing to process, the caller can use this to break out of a loop */
            *pDone = TRUE;
            break;
        }

        if (lookAhead != 0) {
            AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Pending mailbox message, LookAhead: 0x%X\n",lookAhead));
                /* Mailbox Interrupt, the HTC layer may issue async requests to empty the
                 * mailbox...
                 * When emptying the recv mailbox we use the async handler above called from the
                 * completion routine of the callers read request. This can improve performance
                 * by reducing context switching when we rapidly pull packets */
            status = pDev->MessagePendingCallback(pDev->HTCContext, lookAhead, pASyncProcessing);
            if (A_FAILED(status)) {
                break;
            }
        }

            /* now handle the rest of them */
        AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,
                            (" Valid interrupt source(s) for OTHER interrupts: 0x%x\n",
                            host_int_status));

        if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
                /* CPU Interrupt */
            status = DevServiceCPUInterrupt(pDev);
            if (A_FAILED(status)){
                break;
            }
        }

        if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
                /* Error Interrupt */
            status = DevServiceErrorInterrupt(pDev);
            if (A_FAILED(status)){
                break;
            }
        }

        if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
                /* Counter Interrupt */
            status = DevServiceCounterInterrupt(pDev);
            if (A_FAILED(status)){
                break;
            }
        }

    } while (FALSE);

    AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-ProcessPendingIRQs: (done:%d, async:%d) status=%d \n",
                *pDone, *pASyncProcessing, status));

    return status;
}
static void ar6000_hci_pkt_recv(void *pContext, HTC_PACKET *pPacket)
{
    AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext;
    struct sk_buff       *skb;
    AR_SOFTC_DEV_T *arDev = pHcidevInfo->ar->arDev[0];
    
    A_ASSERT(pHcidevInfo != NULL);
    skb = (struct sk_buff *)pPacket->pPktContext;
    A_ASSERT(skb != NULL);
          
    do {
        
        if (A_FAILED(pPacket->Status)) {
            break;
        }
  
        AR_DEBUG_PRINTF(ATH_DEBUG_HCI_RECV, 
                        ("HCI Bridge, packet received type : %d len:%d \n",
                        HCI_GET_PACKET_TYPE(pPacket),pPacket->ActualLength));
    
            /* set the actual buffer position in the os buffer, HTC recv buffers posted to HCI are set
             * to fill the front of the buffer */
        A_NETBUF_PUT(skb,pPacket->ActualLength + pHcidevInfo->HCIProps.HeadRoom);
        A_NETBUF_PULL(skb,pHcidevInfo->HCIProps.HeadRoom);
        
        if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("<<< Recv HCI %s packet len:%d \n",
                        (HCI_GET_PACKET_TYPE(pPacket) == HCI_EVENT_TYPE) ? "EVENT" : "ACL",
                        skb->len));
            AR_DEBUG_PRINTBUF(skb->data, skb->len,"BT HCI RECV Packet Dump");
        }
        
        if (pHcidevInfo->HciNormalMode) {
                /* indicate the packet */         
            if (bt_indicate_recv(pHcidevInfo,HCI_GET_PACKET_TYPE(pPacket),skb)) {
                    /* bt stack accepted the packet */
                skb = NULL;
            }  
            break;
        }
        
            /* for testing, indicate packet to the network stack */ 
#ifdef EXPORT_HCI_BRIDGE_INTERFACE
        skb->dev = (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice);        
        if ((((struct net_device *)pHcidevInfo->HCITransHdl.netDevice)->flags & IFF_UP) == IFF_UP) {
            skb->protocol = eth_type_trans(skb, (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice));
#else
        skb->dev = arDev->arNetDev;        
        if ((arDev->arNetDev->flags & IFF_UP) == IFF_UP) {
            skb->protocol = eth_type_trans(skb, arDev->arNetDev);
#endif
            netif_rx(skb);
            skb = NULL;
        } 
        
    } while (FALSE);
    
    FreeHTCStruct(pHcidevInfo,pPacket);
    
    if (skb != NULL) {
            /* packet was not accepted, free it */
        FreeBtOsBuf(pHcidevInfo,skb);       
    }
    
}

static void  ar6000_hci_pkt_refill(void *pContext, HCI_TRANSPORT_PACKET_TYPE Type, int BuffersAvailable)
{
    AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext;
    int                  refillCount;

    if (Type == HCI_ACL_TYPE) {
        refillCount =  MAX_ACL_RECV_BUFS - BuffersAvailable;   
    } else {
        refillCount =  MAX_EVT_RECV_BUFS - BuffersAvailable;     
    }
    
    if (refillCount > 0) {
        RefillRecvBuffers(pHcidevInfo,Type,refillCount);
    }
    
}
Exemplo n.º 7
0
static INLINE A_STATUS HTCProcessTrailer(HTC_TARGET *target,
                                         A_UINT8    *pBuffer,
                                         int         Length,
                                         A_UINT32   *pNextLookAhead,
                                         HTC_ENDPOINT_ID FromEndpoint)
{
    HTC_RECORD_HDR          *pRecord;
    A_UINT8                 *pRecordBuf;
    HTC_LOOKAHEAD_REPORT    *pLookAhead;
    A_UINT8                 *pOrigBuffer;
    int                     origLength;
    A_STATUS                status;

    AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessTrailer (length:%d) \n", Length));

    if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
        AR_DEBUG_PRINTBUF(pBuffer,Length,"Recv Trailer");
    }

    pOrigBuffer = pBuffer;
    origLength = Length;
    status = A_OK;

    while (Length > 0) {

        if (Length < sizeof(HTC_RECORD_HDR)) {
            status = A_EPROTO;
            break;
        }
            /* these are byte aligned structs */
        pRecord = (HTC_RECORD_HDR *)pBuffer;
        Length -= sizeof(HTC_RECORD_HDR);
        pBuffer += sizeof(HTC_RECORD_HDR);

        if (pRecord->Length > Length) {
                /* no room left in buffer for record */
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
                (" invalid record length: %d (id:%d) buffer has: %d bytes left \n",
                        pRecord->Length, pRecord->RecordID, Length));
            status = A_EPROTO;
            break;
        }
            /* start of record follows the header */
        pRecordBuf = pBuffer;

        switch (pRecord->RecordID) {
            case HTC_RECORD_CREDITS:
                AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_CREDIT_REPORT));
                HTCProcessCreditRpt(target,
                                    (HTC_CREDIT_REPORT *)pRecordBuf,
                                    pRecord->Length / (sizeof(HTC_CREDIT_REPORT)),
                                    FromEndpoint);
                break;
            case HTC_RECORD_LOOKAHEAD:
                AR_DEBUG_ASSERT(pRecord->Length >= sizeof(HTC_LOOKAHEAD_REPORT));
                pLookAhead = (HTC_LOOKAHEAD_REPORT *)pRecordBuf;
                if ((pLookAhead->PreValid == ((~pLookAhead->PostValid) & 0xFF)) &&
                    (pNextLookAhead != NULL)) {

                    AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
                                (" LookAhead Report Found (pre valid:0x%X, post valid:0x%X) \n",
                                pLookAhead->PreValid,
                                pLookAhead->PostValid));

                        /* look ahead bytes are valid, copy them over */
                    ((A_UINT8 *)pNextLookAhead)[0] = pLookAhead->LookAhead[0];
                    ((A_UINT8 *)pNextLookAhead)[1] = pLookAhead->LookAhead[1];
                    ((A_UINT8 *)pNextLookAhead)[2] = pLookAhead->LookAhead[2];
                    ((A_UINT8 *)pNextLookAhead)[3] = pLookAhead->LookAhead[3];

                    if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
                        DebugDumpBytes((A_UINT8 *)pNextLookAhead,4,"Next Look Ahead");
                    }
                }
                break;
            default:
                AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" unhandled record: id:%d length:%d \n",
                        pRecord->RecordID, pRecord->Length));
                break;
        }

        if (A_FAILED(status)) {
            break;
        }

            /* advance buffer past this record for next time around */
        pBuffer += pRecord->Length;
        Length -= pRecord->Length;
    }

    if (A_FAILED(status)) {
        DebugDumpBytes(pOrigBuffer,origLength,"BAD Recv Trailer");
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessTrailer \n"));
    return status;

}
Exemplo n.º 8
0
/* process a received message (i.e. strip off header, process any trailer data)
 * note : locks must be released when this function is called */
static A_STATUS HTCProcessRecvHeader(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT32 *pNextLookAhead)
{
    A_UINT8   temp;
    A_UINT8   *pBuf;
    A_STATUS  status = A_OK;
    A_UINT16  payloadLen;
    A_UINT32  lookAhead;

    pBuf = pPacket->pBuffer;

    AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader \n"));

    if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
        AR_DEBUG_PRINTBUF(pBuf,pPacket->ActualLength,"HTC Recv PKT");
    }

    do {
        /* note, we cannot assume the alignment of pBuffer, so we use the safe macros to
         * retrieve 16 bit fields */
        payloadLen = A_GET_UINT16_FIELD(pBuf, HTC_FRAME_HDR, PayloadLen);

        ((A_UINT8 *)&lookAhead)[0] = pBuf[0];
        ((A_UINT8 *)&lookAhead)[1] = pBuf[1];
        ((A_UINT8 *)&lookAhead)[2] = pBuf[2];
        ((A_UINT8 *)&lookAhead)[3] = pBuf[3];

        if (lookAhead != pPacket->HTCReserved) {
            /* somehow the lookahead that gave us the full read length did not
             * reflect the actual header in the pending message */
             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
                    ("HTCProcessRecvHeader, lookahead mismatch! \n"));
             DebugDumpBytes((A_UINT8 *)&pPacket->HTCReserved,4,"Expected Message LookAhead");
             DebugDumpBytes(pBuf,sizeof(HTC_FRAME_HDR),"Current Frame Header");
#ifdef HTC_CAPTURE_LAST_FRAME
            DebugDumpBytes((A_UINT8 *)&target->LastFrameHdr,sizeof(HTC_FRAME_HDR),"Last Frame Header");
            if (target->LastTrailerLength != 0) {
                DebugDumpBytes(target->LastTrailer,
                               target->LastTrailerLength,
                               "Last trailer");
            }
#endif
            status = A_EPROTO;
            break;
        }

            /* get flags */
        temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, Flags);

        if (temp & HTC_FLAGS_RECV_TRAILER) {
            /* this packet has a trailer */

                /* extract the trailer length in control byte 0 */
            temp = A_GET_UINT8_FIELD(pBuf, HTC_FRAME_HDR, ControlBytes[0]);

            if ((temp < sizeof(HTC_RECORD_HDR)) || (temp > payloadLen)) {
                AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
                    ("HTCProcessRecvHeader, invalid header (payloadlength should be :%d, CB[0] is:%d) \n",
                        payloadLen, temp));
                status = A_EPROTO;
                break;
            }

                /* process trailer data that follows HDR + application payload */
            status = HTCProcessTrailer(target,
                                       (pBuf + HTC_HDR_LENGTH + payloadLen - temp),
                                       temp,
                                       pNextLookAhead,
                                       pPacket->Endpoint);

            if (A_FAILED(status)) {
                break;
            }

#ifdef HTC_CAPTURE_LAST_FRAME
            A_MEMCPY(target->LastTrailer, (pBuf + HTC_HDR_LENGTH + payloadLen - temp), temp);
            target->LastTrailerLength = temp;
#endif
                /* trim length by trailer bytes */
            pPacket->ActualLength -= temp;
        }
#ifdef HTC_CAPTURE_LAST_FRAME
         else {
            target->LastTrailerLength = 0;
        }
#endif

            /* if we get to this point, the packet is good */
            /* remove header and adjust length */
        pPacket->pBuffer += HTC_HDR_LENGTH;
        pPacket->ActualLength -= HTC_HDR_LENGTH;

    } while (FALSE);

    if (A_FAILED(status)) {
            /* dump the whole packet */
        DebugDumpBytes(pBuf,pPacket->ActualLength,"BAD HTC Recv PKT");
    } else {
#ifdef HTC_CAPTURE_LAST_FRAME
        A_MEMCPY(&target->LastFrameHdr,pBuf,sizeof(HTC_FRAME_HDR));
#endif
        if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
            if (pPacket->ActualLength > 0) {
                AR_DEBUG_PRINTBUF(pPacket->pBuffer,pPacket->ActualLength,"HTC - Application Msg");
            }
        }
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCProcessRecvHeader \n"));
    return status;
}
Exemplo n.º 9
0
static void usb_hif_usb_recv_bundle_complete(struct urb *urb)
{
	HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context;
	A_STATUS status = A_OK;
	adf_nbuf_t buf = NULL;
	HIF_USB_PIPE *pipe = urb_context->pipe;
	A_UINT8 *netdata, *netdata_new;
	A_UINT32 netlen, netlen_new;
	HTC_FRAME_HDR *HtcHdr;
	A_UINT16 payloadLen;
	adf_nbuf_t new_skb = NULL;

	AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, (
			 "+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p\n",
			 __func__,
			 pipe->logical_pipe_num,
			 urb->status, urb->actual_length,
			 urb));

	/* this urb is not pending anymore */
	usb_hif_remove_pending_transfer(urb_context);

	do {

		if (urb->status != 0) {
			status = A_ECOMM;
			switch (urb->status) {
			case -ECONNRESET:
			case -ENOENT:
			case -ESHUTDOWN:
				/* NOTE: no need to spew these errors when
				 * device is removed
				 * or urb is killed due to driver shutdown
				 */
				status = A_ECANCELED;
				break;
			default:
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
						 "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n",
						 __func__,
						 pipe->logical_pipe_num,
						 pipe->ep_address,
						 urb->status));
				break;
			}
			break;
		}

		if (urb->actual_length == 0)
			break;

		buf = urb_context->buf;

		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
			A_UINT8 *data;
			A_UINT32 len;
			adf_nbuf_peek_header(buf, &data, &len);
			DebugDumpBytes(data, len, "hif recv data");
		}

		adf_nbuf_peek_header(buf, &netdata, &netlen);
		netlen = urb->actual_length;

		do {
#if defined(AR6004_1_0_ALIGN_WAR)
			A_UINT8 extra_pad;
			A_UINT16 act_frame_len;
#endif
			A_UINT16 frame_len;

			/* Hack into HTC header for bundle processing */
			HtcHdr = (HTC_FRAME_HDR *) netdata;
			if (HtcHdr->EndpointID >= ENDPOINT_MAX) {
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
					("athusb: Rx: invalid EndpointID=%d\n",
					HtcHdr->EndpointID));
				break;
			}

			payloadLen = HtcHdr->PayloadLen;
			payloadLen = A_LE2CPU16(payloadLen);

#if defined(AR6004_1_0_ALIGN_WAR)
			act_frame_len = (HTC_HDR_LENGTH + payloadLen);

			if (HtcHdr->EndpointID == 0 ||
				HtcHdr->EndpointID == 1) {
				/* assumption: target won't pad on HTC endpoint
				 * 0 & 1.
				 */
				extra_pad = 0;
			} else {
				extra_pad =
				    A_GET_UINT8_FIELD((A_UINT8 *) HtcHdr,
						      HTC_FRAME_HDR,
						      ControlBytes[1]);
			}
#endif

			if (payloadLen > HIF_USB_RX_BUFFER_SIZE) {
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
					("athusb: payloadLen too long %u\n",
					payloadLen));
				break;
			}
#if defined(AR6004_1_0_ALIGN_WAR)
			frame_len = (act_frame_len + extra_pad);
#else
			frame_len = (HTC_HDR_LENGTH + payloadLen);
#endif

			if (netlen >= frame_len) {
				/* allocate a new skb and copy */
#if defined(AR6004_1_0_ALIGN_WAR)
				new_skb =
				    adf_nbuf_alloc(NULL, act_frame_len, 0, 4,
						   FALSE);
				if (new_skb == NULL) {
					AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
							 "athusb: allocate skb (len=%u) failed\n",
							 act_frame_len));
					break;
				}

				adf_nbuf_peek_header(new_skb, &netdata_new,
						     &netlen_new);
				adf_os_mem_copy(netdata_new, netdata,
						act_frame_len);
				adf_nbuf_put_tail(new_skb, act_frame_len);
#else
				new_skb =
				    adf_nbuf_alloc(NULL, frame_len, 0, 4,
						   FALSE);
				if (new_skb == NULL) {
					AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
							 "athusb: allocate skb (len=%u) failed\n",
							 frame_len));
					break;
				}

				adf_nbuf_peek_header(new_skb, &netdata_new,
						     &netlen_new);
				adf_os_mem_copy(netdata_new, netdata,
						frame_len);
				adf_nbuf_put_tail(new_skb, frame_len);
#endif
				skb_queue_tail(&pipe->io_comp_queue, new_skb);
				new_skb = NULL;

				netdata += frame_len;
				netlen -= frame_len;
			} else {
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
					 "athusb: subframe length %d not fitted into bundle packet length %d\n"
					 , netlen, frame_len));
				break;
			}

		} while (netlen);

		schedule_work(&pipe->io_complete_work);

	} while (FALSE);

	if (urb_context->buf == NULL) {
		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
				("athusb: buffer in urb_context is NULL\n"));
	}

	/* reset urb_context->buf ==> seems not necessary */
	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);

	if (A_SUCCESS(status)) {
		if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
			/* our free urbs are piling up, post more transfers */
			usb_hif_post_recv_bundle_transfers(pipe, 0
			/* pass zero for not allocating urb-buffer again */
			    );
		}
	}

	AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-%s\n", __func__));
}
Exemplo n.º 10
0
static void usb_hif_usb_recv_complete(struct urb *urb)
{
	HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context;
	A_STATUS status = A_OK;
	adf_nbuf_t buf = NULL;
	HIF_USB_PIPE *pipe = urb_context->pipe;

	AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, (
			 "+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p\n",
			 __func__,
			 pipe->logical_pipe_num,
			 urb->status, urb->actual_length,
			 urb));

	/* this urb is not pending anymore */
	usb_hif_remove_pending_transfer(urb_context);

	do {

		if (urb->status != 0) {
			status = A_ECOMM;
			switch (urb->status) {
#ifdef RX_SG_SUPPORT
			case -EOVERFLOW:
				urb->actual_length = HIF_USB_RX_BUFFER_SIZE;
				status = A_OK;
				break;
#endif
			case -ECONNRESET:
			case -ENOENT:
			case -ESHUTDOWN:
				/* NOTE: no need to spew these errors when
				 * device is removed
				 * or urb is killed due to driver shutdown
				 */
				status = A_ECANCELED;
				break;
			default:
				AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (
						 "%s recv pipe: %d (ep:0x%2.2X), failed:%d\n",
						 __func__,
						 pipe->logical_pipe_num,
						 pipe->ep_address,
						 urb->status));
				break;
			}
			break;
		}

		if (urb->actual_length == 0)
			break;

		buf = urb_context->buf;
		/* we are going to pass it up */
		urb_context->buf = NULL;
		adf_nbuf_put_tail(buf, urb->actual_length);
		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
			A_UINT8 *data;
			A_UINT32 len;
			adf_nbuf_peek_header(buf, &data, &len);
			DebugDumpBytes(data, len, "hif recv data");
		}

		/* note: queue implements a lock */
		skb_queue_tail(&pipe->io_comp_queue, buf);
		schedule_work(&pipe->io_complete_work);

	} while (FALSE);

	usb_hif_cleanup_recv_urb(urb_context);

	if (A_SUCCESS(status)) {
		if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
			/* our free urbs are piling up, post more transfers */
			usb_hif_post_recv_transfers(pipe,
						    HIF_USB_RX_BUFFER_SIZE);
		}
	}

	AR_DEBUG_PRINTF(USB_HIF_DEBUG_BULK_IN, ("-%s\n", __func__));
}