/* callback when a control message arrives on this endpoint */ void HTCControlRecv(void *Context, HTC_PACKET *pPacket) { AR_DEBUG_ASSERT(pPacket->Endpoint == ENDPOINT_0); if (pPacket->Status == A_ECANCELED) { /* this is a flush operation, return the control packet back to the pool */ HTC_FREE_CONTROL_RX((HTC_TARGET*)Context,pPacket); return; } /* the only control messages we are expecting are NULL messages (credit resports) */ if (pPacket->ActualLength > 0) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCControlRecv, got message with length:%d \n", pPacket->ActualLength + (A_UINT32)HTC_HDR_LENGTH)); #ifdef ATH_DEBUG_MODULE /* dump header and message */ DebugDumpBytes(pPacket->pBuffer - HTC_HDR_LENGTH, pPacket->ActualLength + HTC_HDR_LENGTH, "Unexpected ENDPOINT 0 Message"); #endif } HTC_RECYCLE_RX_PKT((HTC_TARGET*)Context,pPacket,&((HTC_TARGET*)Context)->EndPoint[0]); }
/**************************************************** * 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; A_STATUS status = A_OK; struct sk_buff *txSkb = NULL; AR_SOFTC_DEV_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(loghci) { A_PRINTF(">>> Send HCI %s packet len: %d\n", (type == HCI_COMMAND_TYPE) ? "COMMAND" : "ACL", skb->len); if (type == HCI_COMMAND_TYPE) { A_PRINTF("HCI Command: OGF:0x%X OCF:0x%X \r\n", (HCI_GET_OP_CODE(skb->data)) >> 10, (HCI_GET_OP_CODE(skb->data)) & 0x3FF); } DebugDumpBytes(skb->data,skb->len,"BT HCI SEND Packet Dump"); }
static A_STATUS wmi_cmd_send(A_UINT8 *pBuffer, int Length, WMI_COMMAND_ID cmdId) { WMI_CMD_HDR *cHdr; A_ASSERT(pBuffer != NULL); pBuffer -= sizeof(WMI_CMD_HDR); /* caller always provides headroom */ Length += sizeof(WMI_CMD_HDR); cHdr = (WMI_CMD_HDR *)pBuffer; cHdr->commandId = cmdId; AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI Send Command : 0x%X (%d) len:%d \n",cmdId,cmdId, Length)); if (g_WMIloggingReq) { DebugDumpBytes(pBuffer, Length, "WMI Send Buffer Dump"); } return HTCSendMsg(g_HTCHandle, g_WMIControlEp, pBuffer, Length); }
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; }
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; }
A_STATUS HTCRxCompletionHandler( void *Context, adf_nbuf_t netbuf, a_uint8_t pipeID) { A_STATUS status = A_OK; HTC_FRAME_HDR *HtcHdr; HTC_TARGET *target = (HTC_TARGET *)Context; a_uint8_t *netdata; a_uint32_t netlen; HTC_ENDPOINT *pEndpoint; HTC_PACKET *pPacket; A_UINT16 payloadLen; a_uint32_t trailerlen = 0; A_UINT8 htc_ep_id; #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); if (target->IsRxSgInprogress) { target->CurRxSgTotalLen += adf_nbuf_len(netbuf); adf_nbuf_queue_add(&target->RxSgQueue, netbuf); if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) { netbuf = RxSgToSingleNetbuf(target); if (netbuf == NULL) { UNLOCK_HTC_RX(target); goto _out; } } else { netbuf = NULL; UNLOCK_HTC_RX(target); goto _out; } } UNLOCK_HTC_RX(target); #endif netdata = adf_nbuf_data(netbuf); netlen = adf_nbuf_len(netbuf); HtcHdr = (HTC_FRAME_HDR *)netdata; do { htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID); pEndpoint = &target->EndPoint[htc_ep_id]; if (htc_ep_id >= ENDPOINT_MAX) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx: invalid EndpointID=%d\n",htc_ep_id)); DebugDumpBytes((A_UINT8 *)HtcHdr,sizeof(HTC_FRAME_HDR),"BAD HTC Header"); status = A_ERROR; break; } /* * If this endpoint that received a message from the target has * a to-target HIF pipe whose send completions are polled rather * than interrupt-driven, this is a good point to ask HIF to check * whether it has any completed sends to handle. */ if (pEndpoint->ul_is_polled) { HTCSendCompleteCheck(pEndpoint, 1); } payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN); if (netlen < (payloadLen + HTC_HDR_LENGTH)) { #ifdef RX_SG_SUPPORT LOCK_HTC_RX(target); target->IsRxSgInprogress = TRUE; adf_nbuf_queue_init(&target->RxSgQueue); adf_nbuf_queue_add(&target->RxSgQueue, netbuf); target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH); target->CurRxSgTotalLen += netlen; UNLOCK_HTC_RX(target); netbuf = NULL; break; #else AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx: insufficient length, got:%d expected =%d\n", netlen, payloadLen + HTC_HDR_LENGTH)); DebugDumpBytes((A_UINT8 *)HtcHdr,sizeof(HTC_FRAME_HDR),"BAD RX packet length"); status = A_ERROR; break; #endif } #ifdef HTC_EP_STAT_PROFILING LOCK_HTC_RX(target); INC_HTC_EP_STAT(pEndpoint,RxReceived,1); UNLOCK_HTC_RX(target); #endif //if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { { A_UINT8 temp; /* get flags to check for trailer */ temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS); if (temp & HTC_FLAGS_RECV_TRAILER) { /* extract the trailer length */ temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, CONTROLBYTES0); 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; } trailerlen = temp; /* process trailer data that follows HDR + application payload */ status = HTCProcessTrailer(target, ((A_UINT8 *)HtcHdr + HTC_HDR_LENGTH + payloadLen - temp), temp, htc_ep_id); if (A_FAILED(status)) { break; } } } if (((int)payloadLen - (int)trailerlen) <= 0) { /* zero length packet with trailer data, just drop these */ break; } if (htc_ep_id == ENDPOINT_0) { A_UINT16 message_id; HTC_UNKNOWN_MSG *htc_msg; /* remove HTC header */ adf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); netdata = adf_nbuf_data(netbuf); netlen = adf_nbuf_len(netbuf); htc_msg = (HTC_UNKNOWN_MSG*)netdata; message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, MESSAGEID); switch (message_id) { default: /* handle HTC control message */ if (target->CtrlResponseProcessing) { /* this is a fatal error, target should not be sending unsolicited messages * on the endpoint 0 */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC Rx Ctrl still processing\n")); status = A_ERROR; break; } LOCK_HTC_RX(target); target->CtrlResponseLength = min((int)netlen,HTC_MAX_CONTROL_MESSAGE_LENGTH); A_MEMCPY(target->CtrlResponseBuffer,netdata,target->CtrlResponseLength); UNLOCK_HTC_RX(target); adf_os_mutex_release(target->osdev, &target->CtrlResponseValid); break; case HTC_MSG_SEND_SUSPEND_COMPLETE: target->HTCInitInfo.TargetSendSuspendComplete(target->HTCInitInfo.pContext); break; } adf_nbuf_free(netbuf); netbuf = NULL; break; } /* the current message based HIF architecture allocates net bufs for recv packets * since this layer bridges that HIF to upper layers , which expects HTC packets, * we form the packets here * TODO_FIXME */ pPacket = AllocateHTCPacketContainer(target); if (NULL == pPacket) { status = A_NO_RESOURCE; break; } pPacket->Status = A_OK; pPacket->Endpoint = htc_ep_id; pPacket->pPktContext = netbuf; pPacket->pBuffer = adf_nbuf_data(netbuf) + HTC_HDR_LENGTH; pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen; /* TODO : this is a hack because the driver layer will set the actual length * of the skb again which will just double the length */ //A_NETBUF_TRIM(netbuf,netlen); adf_nbuf_trim_tail(netbuf, netlen); RecvPacketCompletion(target,pEndpoint,pPacket); /* recover the packet container */ FreeHTCPacketContainer(target,pPacket); netbuf = NULL; } while(FALSE); #ifdef RX_SG_SUPPORT _out: #endif if (netbuf != NULL) { adf_nbuf_free(netbuf); } return status; }
A_STATUS wmi_control_rx(A_UINT8 *pBuffer, int Length) { WMI_CMD_HDR *cmd; A_UINT16 id; A_UINT8 *datap; A_UINT32 len; A_STATUS status = A_OK; A_CHAR *pWmiDumpStr = "WMI message payload"; if (Length < sizeof(WMI_CMD_HDR)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("WMI: invalid length: %d \n",Length)); return A_ERROR; } cmd = (WMI_CMD_HDR *)pBuffer; id = cmd->commandId; datap = pBuffer + sizeof(WMI_CMD_HDR); len = Length - sizeof(WMI_CMD_HDR); AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("---- WMI recv, MsgNo %d, Event ID: 0x%X (%d) ---------------------------\n", cmdRecvNum, id , id)); cmdRecvNum++; switch (id) { case (WMI_READY_EVENTID): { WMI_READY_EVENT *ev = (WMI_READY_EVENT *)datap; AR_DEBUG_PRINTF(ATH_DEBUG_WMI,("WMI_READY_EVENTID\n")); if (len < sizeof(WMI_READY_EVENT)) { return A_EINVAL; } A_MEMCPY(g_MACAddress, ev->macaddr, ATH_MAC_LEN); ar6000_ready_event(ev->macaddr, ev->phyCapability); } break; case (WMI_CONNECT_EVENTID): { WMI_CONNECT_EVENT *ev; AR_DEBUG_PRINTF(ATH_DEBUG_WMI,("WMI_CONNECT_EVENTID \n")); if (len < sizeof(WMI_CONNECT_EVENT)) { return A_EINVAL; } ev = (WMI_CONNECT_EVENT *)datap; A_MEMCPY(g_bssid, ev->bssid, ATH_MAC_LEN); ar6000_connect_event(ev->channel, ev->bssid, ev->listenInterval, ev->beaconInterval, ev->networkType, ev->beaconIeLen, ev->assocReqLen, ev->assocRespLen, ev->assocInfo); } break; case (WMI_DISCONNECT_EVENTID): { WMI_DISCONNECT_EVENT *ev; if (len < sizeof(WMI_DISCONNECT_EVENT)) { return A_EINVAL; } ev = (WMI_DISCONNECT_EVENT *)datap; A_MEMZERO(g_bssid, ATH_MAC_LEN); ar6000_disconnect_event(ev->disconnectReason, ev->bssid, ev->assocRespLen, ev->assocInfo, ev->protocolReasonStatus); } break; case (WMI_REGDOMAIN_EVENTID): { WMI_REG_DOMAIN_EVENT *ev; AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI_REGDOMAIN_EVENTID\n")); if (len < sizeof(*ev)) { return A_EINVAL; } ev = (WMI_REG_DOMAIN_EVENT *)datap; ar6000_regDomain_event(ev->regDomain); } break; case (WMI_EXTENSION_EVENTID): { A_UINT16 extId = datap[0] | ((A_UINT16)datap[1]) << 8; datap += sizeof(WMIX_CMD_HDR); len -= sizeof(WMIX_CMD_HDR); AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI_EXTENSION_EVENTID - id: 0x%X (%d) length:%d \n",extId, extId, len)); pWmiDumpStr = "WMI Extended Message payload"; } break; case (WMI_REPORT_STATISTICS_EVENTID) : { WMI_TARGET_STATS *reply; AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("WMI_EXTENSION_EVENTID\n")); if (len < sizeof(*reply)) { return A_EINVAL; } reply = (WMI_TARGET_STATS *)datap; ar6000_targetStats_event(reply); } default: AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("UNHANDLED WMI EVENT : 0x%X (%d) \n",id,id)); break; } AR_DEBUG_PRINTF(ATH_DEBUG_WMI, ("------------------------------------------------------------------------------------\n")); if (g_WMIloggingReq) { DebugDumpBytes(datap, len, pWmiDumpStr); } return status; }
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; }
/* asynchronous completion handler for recv packet fetching, when the device layer * completes a read request, it will call this completion handler */ void HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket) { HTC_TARGET *target = (HTC_TARGET *)Context; HTC_ENDPOINT *pEndpoint; A_UINT32 nextLookAhead = 0; A_STATUS status; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCRecvCompleteHandler (status:%d, ep:%d) \n", pPacket->Status, pPacket->Endpoint)); AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX); pEndpoint = &target->EndPoint[pPacket->Endpoint]; pPacket->Completion = NULL; /* get completion status */ status = pPacket->Status; do { if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler: request failed (status:%d, ep:%d) \n", pPacket->Status, pPacket->Endpoint)); break; } /* process the header for any trailer data */ status = HTCProcessRecvHeader(target,pPacket,&nextLookAhead); if (A_FAILED(status)) { break; } /* was there a lookahead for the next packet? */ if (nextLookAhead != 0) { A_STATUS nextStatus; AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("HTCRecvCompleteHandler - next look ahead was non-zero : 0x%X \n", nextLookAhead)); /* we have another packet, get the next packet fetch started (pipelined) before * we call into the endpoint's callback, this will start another async request */ nextStatus = HTCRecvMessagePendingHandler(target,&nextLookAhead,NULL); if (A_EPROTO == nextStatus) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Next look ahead from recv header was INVALID\n")); DebugDumpBytes((A_UINT8 *)&nextLookAhead, 4, "BAD lookahead from lookahead report"); } } else { AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("HTCRecvCompleteHandler - rechecking for more messages...\n")); /* if we did not get anything on the look-ahead, * call device layer to asynchronously re-check for messages. If we can keep the async * processing going we get better performance. If there is a pending message we will keep processing * messages asynchronously which should pipeline things nicely */ DevCheckPendingRecvMsgsAsync(&target->Device); } HTC_RX_STAT_PROFILE(target,pEndpoint,nextLookAhead); DO_RCV_COMPLETION(target,pPacket,pEndpoint); } while (FALSE); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTCRecvCompleteHandler , message fetch failed (status = %d) \n", status)); /* recyle this packet */ HTC_RECYCLE_RX_PKT(target, pPacket, pEndpoint); } AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvCompleteHandler\n")); }
/* 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; }
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__)); }
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__)); }