static void DoRecvCompletion(HTC_ENDPOINT *pEndpoint, HTC_PACKET_QUEUE *pQueueToIndicate) { do { if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { /* nothing to indicate */ break; } if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d, recv multiple callback (%d pkts) \n", pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate))); /* a recv multiple handler is being used, pass the queue to the handler */ pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint->EpCallBacks.pContext, pQueueToIndicate); INIT_HTC_PACKET_QUEUE(pQueueToIndicate); } else { HTC_PACKET *pPacket; /* using legacy EpRecv */ while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate); AR_DEBUG_PRINTF(ATH_DEBUG_RECV, (" HTC calling ep %d recv callback on packet %p \n", pEndpoint->Id, pPacket)); pEndpoint->EpCallBacks.EpRecv(pEndpoint->EpCallBacks.pContext, pPacket); } } } while (FALSE); }
static void ResetEndpointStates(HTC_TARGET *target) { HTC_ENDPOINT *pEndpoint; int i; for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { pEndpoint = &target->EndPoint[i]; pEndpoint->ServiceID = 0; pEndpoint->MaxMsgLength = 0; pEndpoint->MaxTxQueueDepth = 0; pEndpoint->Id = i; INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue); INIT_HTC_PACKET_QUEUE(&pEndpoint->TxLookupQueue); INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBufferHoldQueue); pEndpoint->target = target; //pEndpoint->TxCreditFlowEnabled = (A_BOOL)htc_credit_flow; pEndpoint->TxCreditFlowEnabled = (A_BOOL)1; adf_os_atomic_init(&pEndpoint->TxProcessCount); } }
static void RefillRecvBuffers(struct ar6k_hci_bridge_info *pHcidevInfo, HCI_TRANSPORT_PACKET_TYPE Type, int NumBuffers) { int length, i; void *osBuf = NULL; struct htc_packet_queue queue; struct htc_packet *pPacket; INIT_HTC_PACKET_QUEUE(&queue); if (Type == HCI_ACL_TYPE) { if (pHcidevInfo->HciNormalMode) { length = HCI_MAX_FRAME_SIZE; } else { length = MAX_ACL_RECV_LENGTH; } } else { length = MAX_EVT_RECV_LENGTH; } /* add on transport head and tail room */ length += pHcidevInfo->HCIProps.HeadRoom + pHcidevInfo->HCIProps.TailRoom; /* round up to the required I/O padding */ length = BLOCK_ROUND_UP_PWR2(length,pHcidevInfo->HCIProps.IOBlockPad); for (i = 0; i < NumBuffers; i++) { if (pHcidevInfo->HciNormalMode) { osBuf = bt_alloc_buffer(pHcidevInfo,length); } else { osBuf = A_NETBUF_ALLOC(length); } if (NULL == osBuf) { break; } pPacket = AllocHTCStruct(pHcidevInfo); if (NULL == pPacket) { FreeBtOsBuf(pHcidevInfo,osBuf); AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n")); break; } SET_HTC_PACKET_INFO_RX_REFILL(pPacket,osBuf,A_NETBUF_DATA(osBuf),length,Type); /* add to queue */ HTC_PACKET_ENQUEUE(&queue,pPacket); } if (i > 0) { HCI_TransportAddReceivePkts(pHcidevInfo->pHCIDev, &queue); } }
static void ResetEndpointStates(HTC_TARGET *target) { HTC_ENDPOINT *pEndpoint; int i; for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { pEndpoint = &target->EndPoint[i]; A_MEMZERO(&pEndpoint->CreditDist, sizeof(pEndpoint->CreditDist)); pEndpoint->ServiceID = 0; pEndpoint->CurrentTxQueueDepth = 0; pEndpoint->MaxMsgLength = 0; pEndpoint->MaxTxQueueDepth = 0; #ifdef HTC_EP_STAT_PROFILING A_MEMZERO(&pEndpoint->EndPointStats,sizeof(pEndpoint->EndPointStats)); #endif INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers); INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue); } /* reset distribution list */ target->EpCreditDistributionListHead = NULL; }
A_STATUS DevSetup(AR6K_DEVICE *pDev) { A_UINT32 blocksizes[AR6K_MAILBOXES]; A_STATUS status = A_OK; int i; HTC_CALLBACKS htcCallbacks; do { DL_LIST_INIT(&pDev->ScatterReqHead); /* initialize our free list of IO packets */ INIT_HTC_PACKET_QUEUE(&pDev->RegisterIOList); A_MUTEX_INIT(&pDev->Lock); A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS)); /* the device layer handles these */ htcCallbacks.rwCompletionHandler = DevRWCompletionHandler; htcCallbacks.dsrHandler = DevDsrHandler; htcCallbacks.context = pDev; status = HIFAttachHTC(pDev->HIFDevice, &htcCallbacks); if (A_FAILED(status)) { break; } pDev->HifAttached = TRUE; /* get the addresses for all 4 mailboxes */ status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR, &pDev->MailBoxInfo, sizeof(pDev->MailBoxInfo)); if (status != A_OK) { A_ASSERT(FALSE); break; } /* carve up register I/O packets (these are for ASYNC register I/O ) */ for (i = 0; i < AR6K_MAX_REG_IO_BUFFERS; i++) { HTC_PACKET *pIOPacket; pIOPacket = &pDev->RegIOBuffers[i].HtcPacket; SET_HTC_PACKET_INFO_RX_REFILL(pIOPacket, pDev, pDev->RegIOBuffers[i].Buffer, AR6K_REG_IO_BUFFER_SIZE, 0); /* don't care */ AR6KFreeIOPacket(pDev,pIOPacket); } /* get the block sizes */ status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, blocksizes, sizeof(blocksizes)); if (status != A_OK) { A_ASSERT(FALSE); break; } /* note: we actually get the block size of a mailbox other than 0, for SDIO the block * size on mailbox 0 is artificially set to 1. So we use the block size that is set * for the other 3 mailboxes */ pDev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE]; /* must be a power of 2 */ A_ASSERT((pDev->BlockSize & (pDev->BlockSize - 1)) == 0); /* assemble mask, used for padding to a block */ pDev->BlockMask = pDev->BlockSize - 1; AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("BlockSize: %d, MailboxAddress:0x%X \n", pDev->BlockSize, pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX])); pDev->GetPendingEventsFunc = NULL; /* see if the HIF layer implements the get pending events function */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_PENDING_EVENTS_FUNC, &pDev->GetPendingEventsFunc, sizeof(pDev->GetPendingEventsFunc)); /* assume we can process HIF interrupt events asynchronously */ pDev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC; /* see if the HIF layer overrides this assumption */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_IRQ_PROC_MODE, &pDev->HifIRQProcessingMode, sizeof(pDev->HifIRQProcessingMode)); switch (pDev->HifIRQProcessingMode) { case HIF_DEVICE_IRQ_SYNC_ONLY: AR_DEBUG_PRINTF(ATH_DEBUG_WARN,("HIF Interrupt processing is SYNC ONLY\n")); /* see if HIF layer wants HTC to yield */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_IRQ_YIELD_PARAMS, &pDev->HifIRQYieldParams, sizeof(pDev->HifIRQYieldParams)); if (pDev->HifIRQYieldParams.RecvPacketYieldCount > 0) { AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HIF requests that DSR yield per %d RECV packets \n", pDev->HifIRQYieldParams.RecvPacketYieldCount)); pDev->DSRCanYield = TRUE; } break; case HIF_DEVICE_IRQ_ASYNC_SYNC: AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is ASYNC and SYNC\n")); break; default: A_ASSERT(FALSE); } pDev->HifMaskUmaskRecvEvent = NULL; /* see if the HIF layer implements the mask/unmask recv events function */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC, &pDev->HifMaskUmaskRecvEvent, sizeof(pDev->HifMaskUmaskRecvEvent)); AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF special overrides : 0x%lX , 0x%lX\n", (unsigned long)pDev->GetPendingEventsFunc, (unsigned long)pDev->HifMaskUmaskRecvEvent)); status = DevDisableInterrupts(pDev); if (A_FAILED(status)) { break; } status = DevSetupGMbox(pDev); } while (FALSE); if (A_FAILED(status)) { if (pDev->HifAttached) { HIFDetachHTC(pDev->HIFDevice); pDev->HifAttached = FALSE; } } return status; }
/* registered target arrival callback from the HIF layer */ HTC_HANDLE HTCCreate(void *hHIF, HTC_INIT_INFO *pInfo, adf_os_device_t osdev) { MSG_BASED_HIF_CALLBACKS htcCallbacks; HTC_ENDPOINT *pEndpoint=NULL; HTC_TARGET *target = NULL; int i; AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("+HTCCreate .. HIF :%p \n",hHIF)); A_REGISTER_MODULE_DEBUG_INFO(htc); if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HTC : Unable to allocate memory\n")); return NULL; } A_MEMZERO(target, sizeof(HTC_TARGET)); adf_os_spinlock_init(&target->HTCLock); adf_os_spinlock_init(&target->HTCRxLock); adf_os_spinlock_init(&target->HTCTxLock); do { A_MEMCPY(&target->HTCInitInfo,pInfo,sizeof(HTC_INIT_INFO)); target->host_handle = pInfo->pContext; target->osdev = osdev; ResetEndpointStates(target); INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) { HTC_PACKET *pPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET)); if (pPacket != NULL) { A_MEMZERO(pPacket,sizeof(HTC_PACKET)); FreeHTCPacketContainer(target,pPacket); } } #ifdef TODO_FIXME for (i = 0; i < NUM_CONTROL_TX_BUFFERS; i++) { pPacket = BuildHTCTxCtrlPacket(); if (NULL == pPacket) { break; } HTCFreeControlTxPacket(target,pPacket); } #endif /* setup HIF layer callbacks */ A_MEMZERO(&htcCallbacks, sizeof(MSG_BASED_HIF_CALLBACKS)); htcCallbacks.Context = target; htcCallbacks.rxCompletionHandler = HTCRxCompletionHandler; htcCallbacks.txCompletionHandler = HTCTxCompletionHandler; htcCallbacks.txResourceAvailHandler = HTCTxResourceAvailHandler; htcCallbacks.fwEventHandler = HTCFwEventHandler; target->hif_dev = hHIF; /* Get HIF default pipe for HTC message exchange */ pEndpoint = &target->EndPoint[ENDPOINT_0]; HIFPostInit(hHIF, target, &htcCallbacks); HIFGetDefaultPipe(hHIF, &pEndpoint->UL_PipeID, &pEndpoint->DL_PipeID); } while (FALSE); HTCRecvInit(target); AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("-HTCCreate (0x%p) \n", target)); return (HTC_HANDLE)target; }
/* registered target arrival callback from the HIF layer */ HTC_HANDLE HTCCreate(void *hif_handle, HTC_INIT_INFO *pInfo) { HTC_TARGET *target = NULL; A_STATUS status = A_OK; int i; A_UINT32 ctrl_bufsz; A_UINT32 blocksizes[HTC_MAILBOX_NUM_MAX]; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Enter\n")); printk("HTCCreate !!\n"); do { /* allocate target memory */ if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); status = A_ERROR; break; } A_MEMZERO(target, sizeof(HTC_TARGET)); A_MUTEX_INIT(&target->HTCLock); A_MUTEX_INIT(&target->HTCRxLock); A_MUTEX_INIT(&target->HTCTxLock); INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList); /* give device layer the hif device handle */ target->Device.HIFDevice = hif_handle; /* give the device layer our context (for event processing) * the device layer will register it's own context with HIF * so we need to set this so we can fetch it in the target remove handler */ target->Device.HTCContext = target; /* set device layer target failure callback */ target->Device.TargetFailureCallback = HTCReportFailure; /* set device layer recv message pending callback */ target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler; target->EpWaitingForBuffers = ENDPOINT_MAX; A_MEMCPY(&target->HTCInitInfo,pInfo,sizeof(HTC_INIT_INFO)); /* setup device layer */ status = DevSetup(&target->Device); if (A_FAILED(status)) { break; } /* get the block sizes */ status = HIFConfigureDevice(hif_handle, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, blocksizes, sizeof(blocksizes)); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get block size info from HIF layer...\n")); break; } /* Set the control buffer size based on the block size */ if (blocksizes[1] > HTC_MAX_CONTROL_MESSAGE_LENGTH) { ctrl_bufsz = blocksizes[1] + HTC_HDR_LENGTH; } else { ctrl_bufsz = HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH; } for (i = 0;i < NUM_CONTROL_BUFFERS;i++) { target->HTCControlBuffers[i].Buffer = A_MALLOC(ctrl_bufsz); if (target->HTCControlBuffers[i].Buffer == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); status = A_ERROR; break; } } if (A_FAILED(status)) { break; } /* carve up buffers/packets for control messages */ for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) { HTC_PACKET *pControlPacket; pControlPacket = &target->HTCControlBuffers[i].HtcPacket; SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket, target, target->HTCControlBuffers[i].Buffer, ctrl_bufsz, ENDPOINT_0); HTC_FREE_CONTROL_RX(target,pControlPacket); } for (;i < NUM_CONTROL_BUFFERS;i++) { HTC_PACKET *pControlPacket; pControlPacket = &target->HTCControlBuffers[i].HtcPacket; INIT_HTC_PACKET_INFO(pControlPacket, target->HTCControlBuffers[i].Buffer, ctrl_bufsz); HTC_FREE_CONTROL_TX(target,pControlPacket); } } while (FALSE); if (A_FAILED(status)) { if (target != NULL) { HTCCleanup(target); target = NULL; } } AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Exit\n")); return target; }
A_STATUS ar6000_setup_hci(AR_SOFTC_T *ar) #endif { HCI_TRANSPORT_CONFIG_INFO config; A_STATUS status = A_OK; int i; HTC_PACKET *pPacket; AR6K_HCI_BRIDGE_INFO *pHcidevInfo; do { pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)A_MALLOC(sizeof(AR6K_HCI_BRIDGE_INFO)); if (NULL == pHcidevInfo) { status = A_NO_MEMORY; break; } A_MEMZERO(pHcidevInfo, sizeof(AR6K_HCI_BRIDGE_INFO)); #ifdef EXPORT_HCI_BRIDGE_INTERFACE g_pHcidevInfo = pHcidevInfo; pHcidevInfo->HCITransHdl = *(HCI_TRANSPORT_MISC_HANDLES *)ar; #else ar->hcidev_info = pHcidevInfo; pHcidevInfo->ar = ar; #endif spin_lock_init(&pHcidevInfo->BridgeLock); INIT_HTC_PACKET_QUEUE(&pHcidevInfo->HTCPacketStructHead); ar->exitCallback = AR3KConfigureExit; status = bt_setup_hci(pHcidevInfo); if (A_FAILED(status)) { break; } if (pHcidevInfo->HciNormalMode) { AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: running in normal mode... \n")); } else { AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: running in test mode... \n")); } pHcidevInfo->pHTCStructAlloc = (A_UINT8 *)A_MALLOC((sizeof(HTC_PACKET)) * NUM_HTC_PACKET_STRUCTS); if (NULL == pHcidevInfo->pHTCStructAlloc) { status = A_NO_MEMORY; break; } pPacket = (HTC_PACKET *)pHcidevInfo->pHTCStructAlloc; for (i = 0; i < NUM_HTC_PACKET_STRUCTS; i++,pPacket++) { FreeHTCStruct(pHcidevInfo,pPacket); } A_MEMZERO(&config,sizeof(HCI_TRANSPORT_CONFIG_INFO)); config.ACLRecvBufferWaterMark = MAX_ACL_RECV_BUFS / 2; config.EventRecvBufferWaterMark = MAX_EVT_RECV_BUFS / 2; config.MaxSendQueueDepth = MAX_HCI_WRITE_QUEUE_DEPTH; config.pContext = pHcidevInfo; config.TransportFailure = ar6000_hci_transport_failure; config.TransportReady = ar6000_hci_transport_ready; config.TransportRemoved = ar6000_hci_transport_removed; config.pHCISendComplete = ar6000_hci_send_complete; config.pHCIPktRecv = ar6000_hci_pkt_recv; config.pHCIPktRecvRefill = ar6000_hci_pkt_refill; config.pHCISendFull = ar6000_hci_pkt_send_full; #ifdef EXPORT_HCI_BRIDGE_INTERFACE pHcidevInfo->pHCIDev = HCI_TransportAttach(pHcidevInfo->HCITransHdl.htcHandle, &config); #else pHcidevInfo->pHCIDev = HCI_TransportAttach(ar->arHtcTarget, &config); #endif if (NULL == pHcidevInfo->pHCIDev) { status = A_ERROR; } } while (FALSE); if (A_FAILED(status)) { if (pHcidevInfo != NULL) { if (NULL == pHcidevInfo->pHCIDev) { /* GMBOX may not be present in older chips */ /* just return success */ status = A_OK; } } ar6000_cleanup_hci(ar); } return status; }
/* registered target arrival callback from the HIF layer */ HTC_HANDLE htc_create(void *ol_sc, HTC_INIT_INFO *pInfo, cdf_device_t osdev) { struct hif_msg_callbacks htcCallbacks; HTC_ENDPOINT *pEndpoint = NULL; HTC_TARGET *target = NULL; int i; if (ol_sc == NULL) { HTC_ERROR("%s: ol_sc = NULL", __func__); return NULL; } HTC_TRACE("+htc_create .. HIF :%p", ol_sc); A_REGISTER_MODULE_DEBUG_INFO(htc); target = (HTC_TARGET *) cdf_mem_malloc(sizeof(HTC_TARGET)); if (target == NULL) { HTC_ERROR("%s: Unable to allocate memory", __func__); return NULL; } A_MEMZERO(target, sizeof(HTC_TARGET)); cdf_spinlock_init(&target->HTCLock); cdf_spinlock_init(&target->HTCRxLock); cdf_spinlock_init(&target->HTCTxLock); cdf_spinlock_init(&target->HTCCreditLock); do { A_MEMCPY(&target->HTCInitInfo, pInfo, sizeof(HTC_INIT_INFO)); target->host_handle = pInfo->pContext; target->osdev = osdev; reset_endpoint_states(target); INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) { HTC_PACKET *pPacket = (HTC_PACKET *) cdf_mem_malloc(sizeof(HTC_PACKET)); if (pPacket != NULL) { A_MEMZERO(pPacket, sizeof(HTC_PACKET)); free_htc_packet_container(target, pPacket); } } #ifdef TODO_FIXME for (i = 0; i < NUM_CONTROL_TX_BUFFERS; i++) { pPacket = build_htc_tx_ctrl_packet(); if (NULL == pPacket) { break; } htc_free_control_tx_packet(target, pPacket); } #endif /* setup HIF layer callbacks */ cdf_mem_zero(&htcCallbacks, sizeof(struct hif_msg_callbacks)); htcCallbacks.Context = target; htcCallbacks.rxCompletionHandler = htc_rx_completion_handler; htcCallbacks.txCompletionHandler = htc_tx_completion_handler; htcCallbacks.txResourceAvailHandler = htc_tx_resource_avail_handler; htcCallbacks.fwEventHandler = htc_fw_event_handler; target->hif_dev = ol_sc; /* Get HIF default pipe for HTC message exchange */ pEndpoint = &target->EndPoint[ENDPOINT_0]; hif_post_init(target->hif_dev, target, &htcCallbacks); hif_get_default_pipe(target->hif_dev, &pEndpoint->UL_PipeID, &pEndpoint->DL_PipeID); } while (false); htc_recv_init(target); HTC_TRACE("-htc_create: (0x%p)", target); return (HTC_HANDLE) target; }
A_STATUS HTCConnectService(HTC_HANDLE HTCHandle, HTC_SERVICE_CONNECT_REQ *pConnectReq, HTC_SERVICE_CONNECT_RESP *pConnectResp) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); A_STATUS status = A_OK; HTC_PACKET *pRecvPacket = NULL; HTC_PACKET *pSendPacket = NULL; HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg; HTC_CONNECT_SERVICE_MSG *pConnectMsg; HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX; HTC_ENDPOINT *pEndpoint; int maxMsgSize = 0; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCConnectService, target:0x%X SvcID:0x%X \n", (A_UINT32)target, pConnectReq->ServiceID)); do { AR_DEBUG_ASSERT(pConnectReq->ServiceID != 0); if (HTC_CTRL_RSVD_SVC == pConnectReq->ServiceID) { /* special case for pseudo control service */ assignedEndpoint = ENDPOINT_0; maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH; } else { /* allocate a packet to send to the target */ pSendPacket = HTC_ALLOC_CONTROL_TX(target); if (NULL == pSendPacket) { AR_DEBUG_ASSERT(FALSE); status = A_NO_MEMORY; break; } /* assemble connect service message */ pConnectMsg = (HTC_CONNECT_SERVICE_MSG *)pSendPacket->pBuffer; AR_DEBUG_ASSERT(pConnectMsg != NULL); A_MEMZERO(pConnectMsg,sizeof(HTC_CONNECT_SERVICE_MSG)); pConnectMsg->MessageID = HTC_MSG_CONNECT_SERVICE_ID; pConnectMsg->ServiceID = pConnectReq->ServiceID; pConnectMsg->ConnectionFlags = pConnectReq->ConnectionFlags; /* check caller if it wants to transfer meta data */ if ((pConnectReq->pMetaData != NULL) && (pConnectReq->MetaDataLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) { /* copy meta data into message buffer (after header ) */ A_MEMCPY((A_UINT8 *)pConnectMsg + sizeof(HTC_CONNECT_SERVICE_MSG), pConnectReq->pMetaData, pConnectReq->MetaDataLength); pConnectMsg->ServiceMetaLength = pConnectReq->MetaDataLength; } SET_HTC_PACKET_INFO_TX(pSendPacket, NULL, (A_UINT8 *)pConnectMsg, sizeof(HTC_CONNECT_SERVICE_MSG) + pConnectMsg->ServiceMetaLength, ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); /* we want synchronous operation */ pSendPacket->Completion = NULL; status = HTCIssueSend(target,pSendPacket,0); if (A_FAILED(status)) { break; } /* wait for response */ status = HTCWaitforControlMessage(target, &pRecvPacket); if (A_FAILED(status)) { break; } /* we controlled the buffer creation so it has to be properly aligned */ pResponseMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *)pRecvPacket->pBuffer; if ((pResponseMsg->MessageID != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) || (pRecvPacket->ActualLength < sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) { /* this message is not valid */ AR_DEBUG_ASSERT(FALSE); status = A_EPROTO; break; } pConnectResp->ConnectRespCode = pResponseMsg->Status; /* check response status */ if (pResponseMsg->Status != HTC_SERVICE_SUCCESS) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target failed service 0x%X connect request (status:%d)\n", pResponseMsg->ServiceID, pResponseMsg->Status)); status = A_EPROTO; break; } assignedEndpoint = (HTC_ENDPOINT_ID) pResponseMsg->EndpointID; maxMsgSize = pResponseMsg->MaxMsgSize; if ((pConnectResp->pMetaData != NULL) && (pResponseMsg->ServiceMetaLength > 0) && (pResponseMsg->ServiceMetaLength <= HTC_SERVICE_META_DATA_MAX_LENGTH)) { /* caller supplied a buffer and the target responded with data */ int copyLength = min((int)pConnectResp->BufferLength, (int)pResponseMsg->ServiceMetaLength); /* copy the meta data */ A_MEMCPY(pConnectResp->pMetaData, ((A_UINT8 *)pResponseMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG), copyLength); pConnectResp->ActualLength = copyLength; } } /* the rest of these are parameter checks so set the error status */ status = A_EPROTO; if (assignedEndpoint >= ENDPOINT_MAX) { AR_DEBUG_ASSERT(FALSE); break; } if (0 == maxMsgSize) { AR_DEBUG_ASSERT(FALSE); break; } pEndpoint = &target->EndPoint[assignedEndpoint]; if (pEndpoint->ServiceID != 0) { /* endpoint already in use! */ AR_DEBUG_ASSERT(FALSE); break; } /* return assigned endpoint to caller */ pConnectResp->Endpoint = assignedEndpoint; pConnectResp->MaxMsgLength = maxMsgSize; /* setup the endpoint */ pEndpoint->ServiceID = pConnectReq->ServiceID; /* this marks the endpoint in use */ pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth; pEndpoint->MaxMsgLength = maxMsgSize; /* copy all the callbacks */ pEndpoint->EpCallBacks = pConnectReq->EpCallbacks; INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBuffers); INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue); /* set the credit distribution info for this endpoint, this information is * passed back to the credit distribution callback function */ pEndpoint->CreditDist.ServiceID = pConnectReq->ServiceID; pEndpoint->CreditDist.pHTCReserved = pEndpoint; pEndpoint->CreditDist.Endpoint = assignedEndpoint; pEndpoint->CreditDist.TxCreditSize = target->TargetCreditSize; pEndpoint->CreditDist.TxCreditsPerMaxMsg = maxMsgSize / target->TargetCreditSize; if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) { pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1; } status = A_OK; } while (FALSE); if (pSendPacket != NULL) { HTC_FREE_CONTROL_TX(target,pSendPacket); } if (pRecvPacket != NULL) { HTC_FREE_CONTROL_RX(target,pRecvPacket); } AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCConnectService \n")); return status; }