/*
 * bt_send_frame - send data frames
*/
static int bt_send_frame(struct sk_buff *skb)
{
    struct hci_dev             *hdev = (struct hci_dev *)skb->dev;
    HCI_TRANSPORT_PACKET_TYPE  type;
    AR6K_HCI_BRIDGE_INFO       *pHcidevInfo;
    HTC_PACKET                 *pPacket;
    A_STATUS                   status = A_OK;
    struct sk_buff             *txSkb = NULL;
    
    if (!hdev) {
        AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HCI Bridge: bt_send_frame - no device\n"));
        return -ENODEV;
    }
      
    if (!test_bit(HCI_RUNNING, &hdev->flags)) {
        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_send_frame - not open\n"));
        return -EBUSY;
    }
  
    pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)hdev->driver_data;   
    A_ASSERT(pHcidevInfo != NULL);
      
    AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("+bt_send_frame type: %d \n",bt_cb(skb)->pkt_type));
    type = HCI_COMMAND_TYPE;
    
    switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
            type = HCI_COMMAND_TYPE;
            hdev->stat.cmd_tx++;
            break;
 
        case HCI_ACLDATA_PKT:
            type = HCI_ACL_TYPE;
            hdev->stat.acl_tx++;
            break;

        case HCI_SCODATA_PKT:
            /* we don't support SCO over the bridge */
            kfree_skb(skb);
            return 0;
        default:
            A_ASSERT(FALSE);
            kfree_skb(skb);
            return 0;
    } 

    if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) {
        AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(">>> Send HCI %s packet len: %d\n",
                        (type == HCI_COMMAND_TYPE) ? "COMMAND" : "ACL",
                        skb->len));
        if (type == HCI_COMMAND_TYPE) {
            A_UINT16 opcode = HCI_GET_OP_CODE(skb->data);
            AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("    HCI Command: OGF:0x%X OCF:0x%X \r\n", 
                  opcode >> 10, opcode & 0x3FF));
        }
        AR_DEBUG_PRINTBUF(skb->data,skb->len,"BT HCI SEND Packet Dump");
    }
/****************************************************
 * Invoked from bluetooth stack via hdev->send()
 * to send the packet out via ar6k to PAL firmware.
 *
 * For HCI command packet wmi_send_hci_cmd() is invoked.
 * wmi_send_hci_cmd adds WMI_CMD_HDR and sends the packet
 * to PAL firmware.
 *
 * For HCI ACL data packet wmi_data_hdr_add is invoked 
 * to add WMI_DATA_HDR to the packet.  ar6000_acl_data_tx 
 * is then invoked to send the packet to PAL firmware.
 ******************************************************/
static int btpal_send_frame(struct sk_buff *skb)
{
	struct hci_dev *hdev = (struct hci_dev *)skb->dev;
	HCI_TRANSPORT_PACKET_TYPE type;
	ar6k_hci_pal_info_t *pHciPalInfo;
	int status = 0;
	struct sk_buff *txSkb = NULL;
	AR_SOFTC_T *ar;

	if (!hdev) {
		PRIN_LOG("HCI PAL: btpal_send_frame - no device\n");
		return -ENODEV;
	}

	if (!test_bit(HCI_RUNNING, &hdev->flags)) {
		PRIN_LOG("HCI PAL: btpal_send_frame - not open\n");
		return -EBUSY;
	}

	pHciPalInfo = (ar6k_hci_pal_info_t *)hdev->driver_data;   
	A_ASSERT(pHciPalInfo != NULL);
	ar = pHciPalInfo->ar;

	PRIN_LOG("+btpal_send_frame type: %d \n",bt_cb(skb)->pkt_type);
	type = HCI_COMMAND_TYPE;

	switch (bt_cb(skb)->pkt_type) {
		case HCI_COMMAND_PKT:
			type = HCI_COMMAND_TYPE;
			hdev->stat.cmd_tx++;
			break;

		case HCI_ACLDATA_PKT:
			type = HCI_ACL_TYPE;
			hdev->stat.acl_tx++;
			break;

		case HCI_SCODATA_PKT:
			/* we don't support SCO over the pal */
			kfree_skb(skb);
			return 0;
		default:
			A_ASSERT(false);
			kfree_skb(skb);
			return 0;
	} 

	if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) {
		A_PRINTF(">>> Send HCI %s packet len: %d\n",
				(type == HCI_COMMAND_TYPE) ? "COMMAND" : "ACL",
				skb->len);
		if (type == HCI_COMMAND_TYPE) {
			PRIN_LOG("    HCI Command: OGF:0x%X OCF:0x%X \r\n", 
					HCI_GET_OP_CODE(skb-data) >> 10, HCI_GET_OP_CODE(skb-data) & 0x3FF);
		}
		AR_DEBUG_PRINTBUF(skb->data,skb->len,"BT HCI SEND Packet Dump");
	}
Beispiel #3
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;

}
Beispiel #4
0
A_STATUS SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig,
                                           A_UINT8          *pHCICommand,
                                           int              CmdLength,
                                           A_UINT8          **ppEventBuffer,
                                           A_UINT8          **ppBufferToFree)
{
    A_STATUS    status = A_OK;
    A_UINT8     *pBuffer = NULL;
    A_UINT8     *pTemp;
    int         length;
    A_BOOL      commandComplete = FALSE;
    A_UINT8     opCodeBytes[2];

    do {

        length = max(HCI_MAX_EVT_RECV_LENGTH,CmdLength);
        length += pConfig->pHCIProps->HeadRoom + pConfig->pHCIProps->TailRoom;
        length += pConfig->pHCIProps->IOBlockPad;

        pBuffer = (A_UINT8 *)A_MALLOC(length);
        if (NULL == pBuffer) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to allocate bt buffer \n"));
            status = A_NO_MEMORY;
            break;
        }

            /* get the opcodes to check the command complete event */
        opCodeBytes[0] = pHCICommand[HCI_CMD_OPCODE_BYTE_LOW_OFFSET];
        opCodeBytes[1] = pHCICommand[HCI_CMD_OPCODE_BYTE_HI_OFFSET];

            /* copy HCI command */
        A_MEMCPY(pBuffer + pConfig->pHCIProps->HeadRoom,pHCICommand,CmdLength);
            /* send command */
        status = SendHCICommand(pConfig,
                                pBuffer + pConfig->pHCIProps->HeadRoom,
                                CmdLength);
        if (A_FAILED(status)) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to send HCI Command (%d) \n", status));
            AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
            break;
        }

            /* reuse buffer to capture command complete event */
        A_MEMZERO(pBuffer,length);
        status = RecvHCIEvent(pConfig,pBuffer,&length);
        if (A_FAILED(status)) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI event recv failed \n"));
            AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
            break;
        }

        pTemp = pBuffer + pConfig->pHCIProps->HeadRoom;
        if (pTemp[0] == HCI_CMD_COMPLETE_EVENT_CODE) {
            if ((pTemp[HCI_EVENT_OPCODE_BYTE_LOW] == opCodeBytes[0]) &&
                (pTemp[HCI_EVENT_OPCODE_BYTE_HI] == opCodeBytes[1])) {
                commandComplete = TRUE;
            }
        }

        if (!commandComplete) {
            AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Unexpected HCI event : %d \n",pTemp[0]));
            AR_DEBUG_PRINTBUF(pTemp,pTemp[1],"Unexpected HCI event");
            status = A_ECOMM;
            break;
        }

        if (ppEventBuffer != NULL) {
                /* caller wants to look at the event */
            *ppEventBuffer = pTemp;
            if (ppBufferToFree == NULL) {
                status = A_EINVAL;
                break;
            }
                /* caller must free the buffer */
            *ppBufferToFree = pBuffer;
            pBuffer = NULL;
        }

    } while (FALSE);

    if (pBuffer != NULL) {
        A_FREE(pBuffer);
    }

    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);
    }
    
}
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;

}
/* 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;
}