static A_STATUS RecvHCIEvent(AR3K_CONFIG_INFO *pConfig, A_UINT8 *pBuffer, int *pLength) { A_STATUS status = A_OK; HTC_PACKET *pRecvPacket = NULL; do { pRecvPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET)); if (NULL == pRecvPacket) { status = A_NO_MEMORY; AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n")); break; } A_MEMZERO(pRecvPacket,sizeof(HTC_PACKET)); SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket,NULL,pBuffer,*pLength,HCI_EVENT_TYPE); status = HCI_TransportRecvHCIEventSync(pConfig->pHCIDev, pRecvPacket, HCI_EVENT_RESP_TIMEOUTMS); if (A_FAILED(status)) { break; } *pLength = pRecvPacket->ActualLength; } while (FALSE); if (pRecvPacket != NULL) { A_FREE(pRecvPacket); } return status; }
LOCAL void _HTC_Ready(htc_handle_t htcHandle) { adf_nbuf_t pBuffer; HTC_READY_MSG *pReady; a_uint8_t *addr; HTC_CONTEXT *pHTC = (HTC_CONTEXT *)htcHandle; pBuffer = HTCAllocMsgBuffer(pHTC); /* an optimization... the header length is chosen to * be aligned on a 16 bit bounday, the fields in the message are designed to * be aligned */ addr = adf_nbuf_put_tail(pBuffer, sizeof(HTC_READY_MSG)); pReady = (HTC_READY_MSG *)addr; A_MEMZERO(pReady,sizeof(HTC_READY_MSG)); pReady->MessageID = adf_os_htons(HTC_MSG_READY_ID); pReady->CreditSize = adf_os_htons((A_UINT16)pHTC->RecvBufferSize); pReady->CreditCount = adf_os_htons((A_UINT16)pHTC->TotalCredits); pReady->MaxEndpoints = ENDPOINT_MAX; /* send out the message */ HTC_SendMsg(pHTC, ENDPOINT0, pBuffer); /* now we need to wait for service connection requests */ }
A_STATUS htc_start(HTC_HANDLE HTCHandle) { cdf_nbuf_t netbuf; A_STATUS status = A_OK; HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); HTC_SETUP_COMPLETE_EX_MSG *pSetupComp; HTC_PACKET *pSendPacket; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Enter\n")); do { htc_config_target_hif_pipe(target); /* allocate a buffer to send */ pSendPacket = htc_alloc_control_tx_packet(target); if (NULL == pSendPacket) { AR_DEBUG_ASSERT(false); cdf_print("%s: allocControlTxPacket failed\n", __func__); status = A_NO_MEMORY; break; } netbuf = (cdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket); /* assemble setup complete message */ cdf_nbuf_put_tail(netbuf, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); pSetupComp = (HTC_SETUP_COMPLETE_EX_MSG *) cdf_nbuf_data(netbuf); A_MEMZERO(pSetupComp, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); HTC_SET_FIELD(pSetupComp, HTC_SETUP_COMPLETE_EX_MSG, MESSAGEID, HTC_MSG_SETUP_COMPLETE_EX_ID); if (!htc_credit_flow) { AR_DEBUG_PRINTF(ATH_DEBUG_INIT, ("HTC will not use TX credit flow control\n")); pSetupComp->SetupFlags |= HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW; } else { AR_DEBUG_PRINTF(ATH_DEBUG_INIT, ("HTC using TX credit flow control\n")); } #ifdef HIF_SDIO #if ENABLE_BUNDLE_RX if (HTC_ENABLE_BUNDLE(target)) pSetupComp->SetupFlags |= HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV; #endif /* ENABLE_BUNDLE_RX */ #endif /* HIF_SDIO */ SET_HTC_PACKET_INFO_TX(pSendPacket, NULL, (A_UINT8 *) pSetupComp, sizeof(HTC_SETUP_COMPLETE_EX_MSG), ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); status = htc_send_pkt((HTC_HANDLE) target, pSendPacket); if (A_FAILED(status)) { break; } } while (false); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Exit\n")); return status; }
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; unsigned 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; HTC_PREPARE_SEND_PKT(pSendPacket,0,0,0); status = HTCIssueSend(target,pSendPacket); 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]; pEndpoint->Id = 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; /* 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; if (pConnectReq->MaxSendMsgSize != 0) { /* override TxCreditsPerMaxMsg calculation, this optimizes the credit-low indications * since the host will actually issue smaller messages in the Send path */ if (pConnectReq->MaxSendMsgSize > maxMsgSize) { /* can't be larger than the maximum the target can support */ AR_DEBUG_ASSERT(FALSE); break; } pEndpoint->CreditDist.TxCreditsPerMaxMsg = pConnectReq->MaxSendMsgSize / target->TargetCreditSize; } else { pEndpoint->CreditDist.TxCreditsPerMaxMsg = maxMsgSize / target->TargetCreditSize; } if (0 == pEndpoint->CreditDist.TxCreditsPerMaxMsg) { pEndpoint->CreditDist.TxCreditsPerMaxMsg = 1; } /* save local connection flags */ pEndpoint->LocalConnectionFlags = pConnectReq->LocalConnectionFlags; 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; }
static int hifDeviceInserted(struct sdio_func *func, const struct sdio_device_id *id) { int ret; HIF_DEVICE * device; int count; struct task_struct* startup_task_struct; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: hifDeviceInserted, Function: 0x%X, Vendor ID: 0x%X, Device ID: 0x%X, block size: 0x%X/0x%X\n", func->num, func->vendor, func->device, func->max_blksize, func->cur_blksize)); addHifDevice(func); device = getHifDevice(func); spin_lock_init(&device->lock); spin_lock_init(&device->asynclock); DL_LIST_INIT(&device->ScatterReqHead); if (!nohifscattersupport) { /* try to allow scatter operation on all instances, * unless globally overridden */ device->scatter_enabled = TRUE; } /* enable the SDIO function */ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: claim\n")); sdio_claim_host(func); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: enable\n")); if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) >= MANUFACTURER_ID_AR6003_BASE) { /* enable 4-bit ASYNC interrupt on AR6003 or later devices */ ret = Func0_CMD52WriteByte(func->card, CCCR_SDIO_IRQ_MODE_REG, SDIO_IRQ_MODE_ASYNC_4BIT_IRQ); if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("AR6000: failed to enable 4-bit ASYNC IRQ mode %d \n",ret)); sdio_release_host(func); return ret; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: 4-bit ASYNC IRQ mode enabled\n")); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) /* give us some time to enable, in ms */ func->enable_timeout = 100; #endif ret = sdio_enable_func(func); if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to enable AR6K: 0x%X\n", __FUNCTION__, ret)); sdio_release_host(func); return ret; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: set block size 0x%X\n", HIF_MBOX_BLOCK_SIZE)); ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); sdio_release_host(func); if (ret) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable to set block size 0x%x AR6K: 0x%X\n", __FUNCTION__, HIF_MBOX_BLOCK_SIZE, ret)); return ret; } /* Initialize the bus requests to be used later */ A_MEMZERO(device->busRequest, sizeof(device->busRequest)); for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) { sema_init(&device->busRequest[count].sem_req, 0); hifFreeBusRequest(device, &device->busRequest[count]); } /* create async I/O thread */ device->async_shutdown = 0; device->async_task = kthread_create(async_task, (void *)device, "AR6K Async"); if (IS_ERR(device->async_task)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create async task\n", __FUNCTION__)); return A_ERROR; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start async task\n")); sema_init(&device->sem_async, 0); wake_up_process(device->async_task ); /* create startup thread */ startup_task_struct = kthread_create(startup_task, (void *)device, "AR6K startup"); if (IS_ERR(startup_task_struct)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), to create startup task\n", __FUNCTION__)); return A_ERROR; } AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: start startup task\n")); wake_up_process(startup_task_struct); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: return %d\n", ret)); return ret; }
/* Internal functions */ static void * WlanEventThread(void *arg) { int left, ret, sd; struct timeval tv; socklen_t fromlen; struct nlmsghdr *h; fd_set readfds, tempfds; char buf[WLAN_EVENT_SIZE_MAX]; struct sockaddr_nl from, local; ABF_WLAN_INFO *pAbfWlanInfo = (ABF_WLAN_INFO *)arg; ATHBT_FILTER_INFO *pInfo = pAbfWlanInfo->pInfo; ATH_BT_FILTER_INSTANCE *pInstance = pInfo->pInstance; A_STATUS status; A_INFO("Starting the WLAN Event Handler task\n"); A_INFO("Checking WLAN adapter on startup .. \n"); if (!pInstance->pWlanAdapterName) { Abf_WlanCheckSettings(pAbfWlanInfo->IfName, NULL); if (pAbfWlanInfo->IfName[0]) { pAbfWlanInfo->IfIndex = if_nametoindex(pAbfWlanInfo->IfName); } } status = AcquireWlanAdapter(pAbfWlanInfo); if (A_FAILED(status)) { A_INFO("No WLAN adapter on startup (OKAY) \n"); }else { /* Communicate this to the Filter task */ HandleAdapterEvent(pInfo, ATH_ADAPTER_ARRIVED); A_INFO("WLAN Adapter Added\n"); } do { sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sd < 0) { A_ERR("[%s] socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE): %d\n", __FUNCTION__, sd); break; } A_MEMZERO(&local, sizeof(struct sockaddr_nl)); local.nl_family = AF_NETLINK; local.nl_groups = RTMGRP_LINK; if ((ret = bind(sd, (struct sockaddr *) &local, sizeof(local))) < 0) { A_ERR("[%s] bind(netlink): %d\n", __FUNCTION__, ret); close(sd); break; } FD_ZERO(&readfds); FD_SET(sd, &readfds); while (pAbfWlanInfo->Loop) { A_MEMCPY(&tempfds, &readfds, sizeof(fd_set)); tv.tv_sec = 1; tv.tv_usec = 0; ret = select(sd+1, &tempfds, NULL, NULL, &tv); if ((ret < 0) && (errno != EINTR)) { A_ERR("[%s] select failed: %d\n", __FUNCTION__, ret); break; } else if ((ret > 0) && (FD_ISSET(sd, &tempfds))) { fromlen = sizeof(from); do { left = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *) &from, &fromlen); } while (left == -1 && errno == EINTR); if (left < 0) { A_ERR("[%s] recvfrom(netlink)\n", __FUNCTION__); continue; // break; } h = (struct nlmsghdr *) buf; while (left >= sizeof(*h)) { int len, plen; len = h->nlmsg_len; plen = len - sizeof(*h); if (len > left || plen < 0) { A_ERR("[%s] malformed netlink message\n", __FUNCTION__); continue; } //A_DEBUG("RTM Message Type: %s\n", // ((h->nlmsg_type == RTM_NEWLINK) ? // "RTM_NEWLINK" : ((h->nlmsg_type == RTM_DELLINK) ? // "RTM_DELLINK" : "RTM_OTHER"))); switch (h->nlmsg_type) { case RTM_NEWLINK: NewLinkEvent(pInstance, h, plen); break; case RTM_DELLINK: DelLinkEvent(pInstance, h, plen); break; default: break; } len = NLMSG_ALIGN(len); left -= len; h = (struct nlmsghdr *) ((char *) h + len); } } } close(sd); } while (FALSE); /* Clean up the resources allocated in this task */ A_INFO("Terminating the WLAN Event Handler task\n"); A_MUTEX_LOCK(&pAbfWlanInfo->hWaitEventLock); pAbfWlanInfo->Loop = FALSE; A_COND_SIGNAL(&pAbfWlanInfo->hWaitEvent); A_MUTEX_UNLOCK(&pAbfWlanInfo->hWaitEventLock); return NULL; }
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; }
int android_ioctl_siwpriv(struct net_device *dev, struct iw_request_info *__info, struct iw_point *data, char *__extra) { char cmd[384]; /* assume that android command will not excess 384 */ char buf[512]; int len = sizeof(cmd)-1; AR_SOFTC_DEV_T *arPriv = (AR_SOFTC_DEV_T *)ar6k_priv(dev); AR_SOFTC_STA_T *arSta = &arPriv->arSta; if (!data->pointer) { return -EOPNOTSUPP; } if (data->length < len) { len = data->length; } if (copy_from_user(cmd, data->pointer, len)) { return -EIO; } cmd[len] = 0; if (strcasecmp(cmd, "RSSI")==0 || strcasecmp(cmd, "RSSI-APPROX") == 0) { int rssi = -200; struct iw_statistics *iwStats; struct iw_statistics* (*get_iwstats)(struct net_device *); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) get_iwstats = dev->get_wireless_stats; #else get_iwstats = dev->wireless_handlers->get_wireless_stats; #endif if (get_iwstats && arPriv->arConnected) { iwStats = get_iwstats(dev); if (iwStats) { rssi = iwStats->qual.qual; if (rssi == 255) rssi = -200; else rssi += (161 - 256); } } len = snprintf(buf, data->length, "SSID rssi %d\n", rssi) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (strcasecmp(cmd, "LINKSPEED")==0) { /* We skip to use SIOCGIWRATE since Android always asked LINKSPEED just after RSSI*/ unsigned int speed_mbps; if (arPriv->arConnected) { speed_mbps = arPriv->arTargetStats.tx_unicast_rate / 1000; } else { speed_mbps = 1; } len = snprintf(buf, data->length, "LinkSpeed %u\n", speed_mbps) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (memcmp(cmd, "CSCAN S\x01\x00\x00S\x00", 12)==0) { int iocmd = SIOCSIWSCAN - SIOCSIWCOMMIT; const iw_handler setScan = dev->wireless_handlers->standard[iocmd]; A_INT32 home_dwell=0, pas_dwell=0, act_dwell=0; A_UCHAR ssid[IW_ESSID_MAX_SIZE+1] = { 0 }; A_INT32 ssid_len = 0, ie_len; A_UINT8 index = 1; /* reserve index 0 for wext */ A_INT32 ch = 0; A_CHAR nprobe, scantype; struct iw_freq chList[IW_MAX_FREQUENCIES]; A_UCHAR *scanBuf = (A_UCHAR*)(cmd + 12); A_UCHAR *scanEnd = (A_UCHAR*)(cmd + len); A_BOOL broadcastSsid = FALSE; while ( scanBuf < scanEnd ) { A_UCHAR *sp = scanBuf; switch (*scanBuf) { case 'S': /* SSID section */ if (ssid_len > 0 && index < MAX_PROBED_SSID_INDEX) { /* setup the last parsed ssid, reserve index 0 for wext */ if (wmi_probedSsid_cmd(arPriv->arWmi, index, SPECIFIC_SSID_FLAG, ssid_len, ssid) == A_OK) { ++index; if (arSta->scanSpecificSsid<index) { arSta->scanSpecificSsid = index; } } } ie_len = ((scanBuf + 1) < scanEnd) ? ((A_INT32)*(scanBuf+1) + 1) : 0; if ((scanBuf+ie_len) < scanEnd ) { ssid_len = *(scanBuf+1); if (ssid_len == 0) { broadcastSsid = TRUE; } else { A_MEMCPY(ssid, scanBuf+2, ssid_len); ssid[ssid_len] = '\0'; } } scanBuf += 1 + ie_len; break; case 'C': /* Channel section */ if (scanBuf+1 < scanEnd) { int value = *(scanBuf+1); if (value == 0) { ch = 0; /* scan for all channels */ } else if (ch < IW_MAX_FREQUENCIES) { if (value>1000) { chList[ch].e = 1; chList[ch].m = value * 100000; } else { chList[ch].e = 0; chList[ch].m = value; } ++ch; } } scanBuf += 2; break; case 'P': /* Passive dwell section */ if (scanBuf+2 < scanEnd) { pas_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8); } scanBuf += 3; break; case 'H': /* Home dwell section */ if (scanBuf+2 < scanEnd) { home_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8); } scanBuf += 3; break; case 'N': /* Number of probe section */ if (scanBuf+1 < scanEnd) { nprobe = *(scanBuf+1); } scanBuf += 2; break; case 'A': /* Active dwell section */ if (scanBuf+2 < scanEnd) { act_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8); } scanBuf += 3; break; case 'T': /* Scan active type section */ if (scanBuf+1 < scanEnd) { scantype = *(scanBuf+1); } scanBuf += 2; break; default: break; } if (sp == scanBuf) { return -1; /* parsing error */ } } if (ssid_len>0) { A_UINT8 idx; /* Clean up the last specific scan items */ for (idx=index; idx<arSta->scanSpecificSsid; ++idx) { wmi_probedSsid_cmd(arPriv->arWmi, idx, DISABLE_SSID_FLAG, 0, NULL); } arSta->scanSpecificSsid = index; /* * There is no way to know when we need to send broadcast probe in current Android wpa_supplicant_6 * combo scan implemenation. Always force to sent it here uniti future Android version will set * the broadcast flags for combo scan. */ #if 0 if (broadcastSsid) #endif { /* setup the last index as broadcast SSID for combo scan */ ++arSta->scanSpecificSsid; wmi_probedSsid_cmd(arPriv->arWmi, index, ANY_SSID_FLAG, 0, NULL); } } if (pas_dwell>0) { /* TODO: Should we change our passive dwell? There may be some impact for bt-coex */ } if (home_dwell>0) { /* TODO: Should we adjust home_dwell? How to pass it to wext handler? */ } if (setScan) { union iwreq_data miwr; struct iw_request_info minfo; struct iw_scan_req scanreq, *pScanReq = NULL; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); A_MEMZERO(&scanreq, sizeof(scanreq)); if (ssid_len > 0) { pScanReq = &scanreq; memcpy(scanreq.essid, ssid, ssid_len); scanreq.essid_len = ssid_len; miwr.data.flags |= IW_SCAN_THIS_ESSID; } if (ch > 0) { pScanReq = &scanreq; scanreq.num_channels = ch; memcpy(scanreq.channel_list, chList, ch * sizeof(chList[0])); miwr.data.flags |= IW_SCAN_THIS_FREQ; } if (pScanReq) { miwr.data.pointer = (__force void __user *)&scanreq; miwr.data.length = sizeof(scanreq); } minfo.cmd = SIOCSIWSCAN; return setScan(dev, &minfo, &miwr, (char*)pScanReq); } return -1; } else if (strcasecmp(cmd, "MACADDR")==0) { /* reply comes back in the form "Macaddr = XX:XX:XX:XX:XX:XX" where XX */ A_UCHAR *mac = dev->dev_addr; len = snprintf(buf, data->length, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } else if (strcasecmp(cmd, "SCAN-ACTIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "SCAN-PASSIVE")==0) { return 0; /* unsupport function. Suppress the error */ } else if (strcasecmp(cmd, "START")==0 || strcasecmp(cmd, "STOP")==0) { struct ifreq ifr; char userBuf[16]; int ex_arg = (strcasecmp(cmd, "START")==0) ? WLAN_ENABLED : WLAN_DISABLED; int ret; A_MEMZERO(userBuf, sizeof(userBuf)); ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_SET_WLAN_STATE; ((int *)userBuf)[1] = ex_arg; ret = android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf); if (ret==0) { /* Send wireless event which need by android supplicant */ union iwreq_data wrqu; A_MEMZERO(&wrqu, sizeof(wrqu)); wrqu.data.length = strlen(cmd); wireless_send_event(dev, IWEVCUSTOM, &wrqu, cmd); } return ret; } else if (strncasecmp(cmd, "POWERMODE ", 10)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode) == 1) { int iocmd = SIOCSIWPOWER - SIOCSIWCOMMIT; iw_handler setPower = dev->wireless_handlers->standard[iocmd]; if (setPower) { union iwreq_data miwr; struct iw_request_info minfo; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); minfo.cmd = SIOCSIWPOWER; if (mode == 0 /* auto */) miwr.power.disabled = 0; else if (mode == 1 /* active */) miwr.power.disabled = 1; else return -1; return setPower(dev, &minfo, &miwr, NULL); } } return -1; } else if (strcasecmp(cmd, "GETPOWER")==0) { struct ifreq ifr; int userBuf[2]; A_MEMZERO(userBuf, sizeof(userBuf)); ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_GET_POWER_MODE; if (android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf)>=0) { WMI_POWER_MODE_CMD *getPowerMode = (WMI_POWER_MODE_CMD *)userBuf; len = snprintf(buf, data->length, "powermode = %u\n", (getPowerMode->powerMode==MAX_PERF_POWER) ? 1/*active*/ : 0/*auto*/) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } return -1; } else if (strncasecmp(cmd, "SETSUSPENDOPT ", 14)==0) { int enable; if (sscanf(cmd, "%*s %d", &enable)==1) { /* * We set our suspend mode by wlan_config.h now. * Should we follow Android command?? TODO */ return 0; } return -1; } else if (strcasecmp(cmd, "SCAN-CHANNELS")==0) { // reply comes back in the form "Scan-Channels = X" where X is the number of channels int iocmd = SIOCGIWRANGE - SIOCSIWCOMMIT; iw_handler getRange = dev->wireless_handlers->standard[iocmd]; if (getRange) { union iwreq_data miwr; struct iw_request_info minfo; struct iw_range range; A_MEMZERO(&minfo, sizeof(minfo)); A_MEMZERO(&miwr, sizeof(miwr)); A_MEMZERO(&range, sizeof(range)); minfo.cmd = SIOCGIWRANGE; miwr.data.pointer = (__force void __user *) ⦥ miwr.data.length = sizeof(range); getRange(dev, &minfo, &miwr, (char*)&range); } if (arSta->arNumChannels!=-1) { len = snprintf(buf, data->length, "Scan-Channels = %d\n", arSta->arNumChannels) + 1; return (copy_to_user(data->pointer, buf, len)==0) ? len : -1; } return -1; } else if (strncasecmp(cmd, "SCAN-CHANNELS ", 14)==0 || strncasecmp(cmd, "COUNTRY ", 8)==0) { /* * Set the available channels with WMI_SET_CHANNELPARAMS cmd * However, the channels will be limited by the eeprom regulator domain * Try to use a regulator domain which will not limited the channels range. */ int i; int chan = 0; A_UINT16 *clist; struct ifreq ifr; char ioBuf[256]; WMI_CHANNEL_PARAMS_CMD *chParamCmd = (WMI_CHANNEL_PARAMS_CMD *)ioBuf; if (strncasecmp(cmd, "COUNTRY ", 8)==0) { char *country = cmd + 8; if (strcasecmp(country, "US")==0) { chan = 11; } else if (strcasecmp(country, "JP")==0) { chan = 14; } else if (strcasecmp(country, "EU")==0) { chan = 13; } } else if (sscanf(cmd, "%*s %d", &chan) != 1) { return -1; } if ( (chan != 11) && (chan != 13) && (chan != 14)) { return -1; } if (arPriv->arNextMode == AP_NETWORK) { return -1; } A_MEMZERO(&ifr, sizeof(ifr)); A_MEMZERO(ioBuf, sizeof(ioBuf)); chParamCmd->phyMode = WMI_11G_MODE; clist = chParamCmd->channelList; chParamCmd->numChannels = chan; chParamCmd->scanParam = 1; for (i = 0; i < chan; i++) { clist[i] = wlan_ieee2freq(i + 1); } return android_do_ioctl_direct(dev, AR6000_IOCTL_WMI_SET_CHANNELPARAMS, &ifr, ioBuf); } else if (strncasecmp(cmd, "BTCOEXMODE ", 11)==0) { int mode; if (sscanf(cmd, "%*s %d", &mode)==1) { /* * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected * It enable the BT-COEX after dhcp process is finished * We ignore since we have our way to do bt-coex during dhcp obtaining. */ switch (mode) { case 1: /* Disable*/ break; case 0: /* Enable */ /* fall through */ case 2: /* Sense*/ /* fall through */ default: break; } return 0; /* ignore it */ } return -1; } else if (strcasecmp(cmd, "BTCOEXSCAN-START")==0) { /* Android enable or disable Bluetooth coexistence scan mode. When this mode is on, * some of the low-level scan parameters used by the driver are changed to * reduce interference with A2DP streaming. */ return 0; /* ignore it since we have btfilter */ } else if (strcasecmp(cmd, "BTCOEXSCAN-STOP")==0) { return 0; /* ignore it since we have btfilter */ } else if (strncasecmp(cmd, "RXFILTER-ADD ", 13)==0) { return 0; /* ignore it */ } else if (strncasecmp(cmd, "RXFILTER-REMOVE ", 16)==0) { return 0; /* ignoret it */ } else if (strcasecmp(cmd, "RXFILTER-START")==0 || strcasecmp(cmd, "RXFILTER-STOP")==0) { unsigned int flags = dev->flags; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) int mc_count = dev->mc_count; #else int mc_count = netdev_mc_count(dev); #endif if (strcasecmp(cmd, "RXFILTER-START")==0) { if (mc_count > 0 || (flags & IFF_MULTICAST) ) { flags &= ~IFF_MULTICAST; } } else { flags |= IFF_MULTICAST; } if (flags != dev->flags) { dev_change_flags(dev, flags); } return 0; } return -EOPNOTSUPP; }
int DevGMboxSetTargetInterrupt(struct ar6k_device *pDev, int Signal, int AckTimeoutMS) { int status = 0; int i; u8 buffer[4]; A_MEMZERO(buffer, sizeof(buffer)); do { if (Signal >= MBOX_SIG_HCI_BRIDGE_MAX) { status = A_EINVAL; break; } /* set the last buffer to do the actual signal trigger */ buffer[3] = (1 << Signal); status = HIFReadWrite(pDev->HIFDevice, INT_WLAN_ADDRESS, buffer, sizeof(buffer), HIF_WR_SYNC_BYTE_FIX, /* hit the register 4 times to align the I/O */ NULL); if (status) { break; } } while (false); if (!status) { /* now read back the register to see if the bit cleared */ while (AckTimeoutMS) { status = HIFReadWrite(pDev->HIFDevice, INT_WLAN_ADDRESS, buffer, sizeof(buffer), HIF_RD_SYNC_BYTE_FIX, NULL); if (status) { break; } for (i = 0; i < sizeof(buffer); i++) { if (buffer[i] & (1 << Signal)) { /* bit is still set */ break; } } if (i >= sizeof(buffer)) { /* done */ break; } AckTimeoutMS--; A_MDELAY(1); } if (0 == AckTimeoutMS) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("DevGMboxSetTargetInterrupt : Ack Timed-out (sig:%d) \n",Signal)); status = A_ERROR; } } return status; }
int DevGMboxReadCreditCounter(struct ar6k_device *pDev, bool AsyncMode, int *pCredits) { int status = 0; struct htc_packet *pIOPacket = NULL; AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+DevGMboxReadCreditCounter (%s) \n", AsyncMode ? "ASYNC" : "SYNC")); do { pIOPacket = AR6KAllocIOPacket(pDev); if (NULL == pIOPacket) { status = A_NO_MEMORY; A_ASSERT(false); break; } A_MEMZERO(pIOPacket->pBuffer,AR6K_REG_IO_BUFFER_SIZE); if (AsyncMode) { /* stick in our completion routine when the I/O operation completes */ pIOPacket->Completion = DevGMboxReadCreditsAsyncHandler; pIOPacket->pContext = pDev; /* read registers asynchronously */ HIFReadWrite(pDev->HIFDevice, AR6K_GMBOX_CREDIT_DEC_ADDRESS, pIOPacket->pBuffer, AR6K_REG_IO_BUFFER_SIZE, /* hit the register multiple times */ HIF_RD_ASYNC_BYTE_FIX, pIOPacket); pIOPacket = NULL; break; } pIOPacket->Completion = NULL; /* if we get here we are doing it synchronously */ status = HIFReadWrite(pDev->HIFDevice, AR6K_GMBOX_CREDIT_DEC_ADDRESS, pIOPacket->pBuffer, AR6K_REG_IO_BUFFER_SIZE, HIF_RD_SYNC_BYTE_FIX, NULL); } while (false); if (status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" DevGMboxReadCreditCounter failed! status:%d \n", status)); } if (pIOPacket != NULL) { if (!status) { /* sync mode processing */ *pCredits = ProcessCreditCounterReadBuffer(pIOPacket->pBuffer, AR6K_REG_IO_BUFFER_SIZE); } AR6KFreeIOPacket(pDev,pIOPacket); } AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-DevGMboxReadCreditCounter (%s) (%d) \n", AsyncMode ? "ASYNC" : "SYNC", status)); 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; }
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; }
static A_STATUS ar6000_hci_transport_ready(HCI_TRANSPORT_HANDLE HCIHandle, HCI_TRANSPORT_PROPERTIES *pProps, void *pContext) { AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; A_STATUS status; AR_SOFTC_DEV_T *arDev = pHcidevInfo->ar->arDev[0]; pHcidevInfo->pHCIDev = HCIHandle; A_MEMCPY(&pHcidevInfo->HCIProps,pProps,sizeof(*pProps)); AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE,("HCI ready (hci:0x%lX, headroom:%d, tailroom:%d blockpad:%d) \n", (unsigned long)HCIHandle, pHcidevInfo->HCIProps.HeadRoom, pHcidevInfo->HCIProps.TailRoom, pHcidevInfo->HCIProps.IOBlockPad)); #ifdef EXPORT_HCI_BRIDGE_INTERFACE A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice)->hard_header_len); #else A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= arDev->arNetDev->hard_header_len); #endif /* provide buffers */ RefillRecvBuffers(pHcidevInfo, HCI_ACL_TYPE, MAX_ACL_RECV_BUFS); RefillRecvBuffers(pHcidevInfo, HCI_EVENT_TYPE, MAX_EVT_RECV_BUFS); do { /* start transport */ status = HCI_TransportStart(pHcidevInfo->pHCIDev); if (A_FAILED(status)) { break; } if (!pHcidevInfo->HciNormalMode) { /* in test mode, no need to go any further */ break; } /* The delay is required when AR6K is driving the BT reset line */ /* where time is needed after the BT chip is out of reset (HCI_TransportStart) */ /* and before the first HCI command is issued (AR3KConfigure) */ /* FIXME */ /* The delay should be configurable and be only applied when AR6K driving the BT */ /* reset line. This could be done by some module parameter or based on some HW config */ /* info. For now apply 100ms delay blindly */ A_MDELAY(100); A_MEMZERO(&ar3kconfig,sizeof(ar3kconfig)); ar3kconfig.pHCIDev = pHcidevInfo->pHCIDev; ar3kconfig.pHCIProps = &pHcidevInfo->HCIProps; #ifdef EXPORT_HCI_BRIDGE_INTERFACE ar3kconfig.pHIFDevice = (HIF_DEVICE *)(pHcidevInfo->HCITransHdl.hifDevice); #else ar3kconfig.pHIFDevice = pHcidevInfo->ar->arHifDevice; #endif ar3kconfig.pBtStackHCIDev = pHcidevInfo->pBtStackHCIDev; if (ar3khcibaud != 0) { /* user wants ar3k baud rate change */ ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR3K_BAUD; ar3kconfig.Flags |= AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY; ar3kconfig.AR3KBaudRate = ar3khcibaud; } if ((hciuartscale != 0) || (hciuartstep != 0)) { /* user wants to tune HCI bridge UART scale/step values */ ar3kconfig.AR6KScale = (A_UINT16)hciuartscale; ar3kconfig.AR6KStep = (A_UINT16)hciuartstep; ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP; } /* configure the AR3K device */ memcpy(ar3kconfig.bdaddr,arDev->bdaddr,6); status = AR3KConfigure(&ar3kconfig); if (A_FAILED(status)) { extern unsigned int setuphci; AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: Fail to configure AR3K. No device? Cleanup HCI\n")); pHcidevInfo->ar->exitCallback = NULL; ar6000_cleanup_hci(pHcidevInfo->ar); setuphci = 0; pHcidevInfo->ar->arBTSharing = 0; break; } /* Make sure both AR6K and AR3K have power management enabled */ if (ar3kconfig.PwrMgmtEnabled) { A_UINT32 address, hci_uart_pwr_mgmt_params; /* Fetch the address of the hi_hci_uart_pwr_mgmt_params instance in the host interest area */ address = TARG_VTOP(pHcidevInfo->ar->arTargetType, HOST_INTEREST_ITEM_ADDRESS(pHcidevInfo->ar->arTargetType, hi_hci_uart_pwr_mgmt_params)); status = ar6000_ReadRegDiag(pHcidevInfo->ar->arHifDevice, &address, &hci_uart_pwr_mgmt_params); hci_uart_pwr_mgmt_params &= 0xFFFF; /* wakeup timeout is [31:16] */ hci_uart_pwr_mgmt_params |= (ar3kconfig.WakeupTimeout << 16); status |= ar6000_WriteRegDiag(pHcidevInfo->ar->arHifDevice, &address, &hci_uart_pwr_mgmt_params); if (A_OK != status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to write hci_uart_pwr_mgmt_params!\n")); } /* Fetch the address of the hi_hci_uart_pwr_mgmt_params_ext instance in the host interest area */ address = TARG_VTOP(pHcidevInfo->ar->arTargetType, HOST_INTEREST_ITEM_ADDRESS(pHcidevInfo->ar->arTargetType, hi_hci_uart_pwr_mgmt_params_ext)); status = ar6000_WriteRegDiag(pHcidevInfo->ar->arHifDevice, &address, &ar3kconfig.IdleTimeout); if (A_OK != status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to write hci_uart_pwr_mgmt_params_ext!\n")); } status = HCI_TransportEnablePowerMgmt(pHcidevInfo->pHCIDev, TRUE); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to enable TLPM for AR6K! \n")); } } status = bt_register_hci(pHcidevInfo); } while (FALSE); return status; }
NDIS_STATUS busDriverInit (NDIS_HANDLE miniportHandle, NDIS_HANDLE wrapperConfigurationContext, A_UINT32 sysIntr, BUS_DRIVER_HANDLE *busDriverHandle) { PNDIS_RESOURCE_LIST pNdisResourceList; PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDesc; NDIS_PHYSICAL_ADDRESS physicalAddress; A_UINT32 bufferSize; A_UINT32 dwResourceCount; NDIS_STATUS status=NDIS_STATUS_FAILURE; A_UINT32 addressSpace; *busDriverHandle = NULL; HIF_DEBUG_PRINTF(ATH_LOG_TRC, "ar6000CFBusInit: Enter \n"); cfDevice = A_MALLOC(sizeof(CF_DEVICE)); if (cfDevice == NULL) { HIF_DEBUG_PRINTF(ATH_LOG_ERR, "ar6000CFBusInit: Allocate Memory for CF_DEVICE failed\n"); return status; } A_MEMZERO(cfDevice,sizeof(CF_DEVICE)); cfDevice->miniportHandle = miniportHandle; cfDevice->wrapperConfigurationContext=wrapperConfigurationContext; pNdisResourceList = NULL; bufferSize = 0; // First call is just to determine buffer size NdisMQueryAdapterResources( &status, wrapperConfigurationContext, pNdisResourceList, &bufferSize); pNdisResourceList = A_MALLOC(bufferSize); if (pNdisResourceList == NULL) { HIF_DEBUG_PRINTF(ATH_LOG_ERR, "ar6000CFBusInit: AllocateMemory for NDIS_RESOURCE_LIST failed\n"); A_FREE(cfDevice); return NDIS_STATUS_FAILURE; } NdisMQueryAdapterResources( &status, wrapperConfigurationContext, pNdisResourceList, &bufferSize); if (status != NDIS_STATUS_SUCCESS) { HIF_DEBUG_PRINTF(ATH_LOG_ERR, "ar6000CFBusInit: NdisMQueryAdapterResources failed \n"); A_FREE(pNdisResourceList); A_FREE(cfDevice); return status; } /* Search for I/O address and IRQ in assigned resources. */ dwResourceCount = pNdisResourceList->Count; pResourceDesc = &(pNdisResourceList->PartialDescriptors[0]); while (dwResourceCount--) { switch(pResourceDesc->Type) { case CmResourceTypeInterrupt: cfDevice->interruptNumber = pResourceDesc->u.Interrupt.Vector; HIF_DEBUG_PRINTF(ATH_LOG_INF, "ar6000CFBusInit: Interrupt Number = %u\n", cfDevice->interruptNumber); break; case CmResourceTypeMemory: cfDevice->memLen = pResourceDesc->u.Memory.Length; cfDevice->deviceMemBase = pResourceDesc->u.Memory.Start.LowPart; HIF_DEBUG_PRINTF(ATH_LOG_INF, "ar6000CFBusInit: Physical Address = %x Length = %x\n", cfDevice->deviceMemBase,cfDevice->memLen); break; default: HIF_DEBUG_PRINTF(ATH_LOG_ERR, "ar6000CFBusInit: Unexpected assigned resource type %u\n", pResourceDesc->Type); break; } pResourceDesc++; } A_FREE(pNdisResourceList); cfDevice->sysIntr = sysIntr; HIF_DEBUG_PRINTF(ATH_LOG_INF, "ar6000CFBusInit: sysIntr = %u\n", cfDevice->sysIntr); NdisSetPhysicalAddressLow(physicalAddress, cfDevice->deviceMemBase); NdisSetPhysicalAddressHigh(physicalAddress, 0); cfDevice->ndisMapped = 1; status = NdisMMapIoSpace((PVOID *)&cfDevice->mappedMemBase, cfDevice->miniportHandle, physicalAddress, cfDevice->memLen); if (status != NDIS_STATUS_SUCCESS) { HIF_DEBUG_PRINTF(ATH_LOG_ERR, "ar6000CFBusInit: NdisMmapIoSpace failed.. Trying MmMapIoSpace \n"); /* NdisMmapIoSpace fails sometimes in WINCE, type MmMapIoSpace */ cfDevice->mappedMemBase = (A_UINT32) MmMapIoSpace(physicalAddress, cfDevice->memLen, FALSE); if (!cfDevice->mappedMemBase) { HIF_DEBUG_PRINTF(ATH_LOG_ERR, "ar6000CFBusInit: MmMapIoSpace failed \n"); A_FREE(cfDevice); return NDIS_STATUS_FAILURE; } cfDevice->ndisMapped = 0; } addressSpace = 0; #ifdef SHARED_INTERRUPTS #if (UNDER_CE==600) giisrMappedAddress = (PVOID)cfDevice->mappedMemBase; #else if (!TransBusAddrToStatic(PCIBus, 0, physicalAddress, cfDevice->memLen, &addressSpace, &giisrMappedAddress)) { HIF_DEBUG_PRINTF(ATH_LOG_ERR, "ar6000CFBusInit : TransBusAddrToStatic failed \n"); A_FREE(cfDevice); return NDIS_STATUS_FAILURE; } #endif //UNDER_CE #endif //SHARED_INTERRUPTS *busDriverHandle = (BUS_DRIVER_HANDLE)cfDevice; HIF_DEBUG_PRINTF(ATH_LOG_TRC, "ar6000CFBusInit: Exit \n"); return NDIS_STATUS_SUCCESS; }
int ar6000_htc_raw_open(AR_SOFTC_T *ar) { A_STATUS status; int streamID, endPt, count2; raw_htc_buffer *buffer; HTC_SERVICE_ID servicepriority; AR_RAW_HTC_T *arRaw = ar->arRawHtc; if (!arRaw) { arRaw = ar->arRawHtc = A_MALLOC(sizeof(AR_RAW_HTC_T)); if (arRaw) { A_MEMZERO(arRaw, sizeof(AR_RAW_HTC_T)); } } A_ASSERT(ar->arHtcTarget != NULL); if (!arRaw) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Faile to allocate memory for HTC RAW interface\n")); return -ENOMEM; } /* wait for target */ status = HTCWaitTarget(ar->arHtcTarget); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTCWaitTarget failed (%d)\n", status)); return -ENODEV; } for (endPt = 0; endPt < ENDPOINT_MAX; endPt++) { arRaw->arEp2RawMapping[endPt] = HTC_RAW_STREAM_NOT_MAPPED; } for (streamID = HTC_RAW_STREAM_0; streamID < HTC_RAW_STREAM_NUM_MAX; streamID++) { /* Initialize the data structures */ init_MUTEX(&arRaw->raw_htc_read_sem[streamID]); init_MUTEX(&arRaw->raw_htc_write_sem[streamID]); init_waitqueue_head(&arRaw->raw_htc_read_queue[streamID]); init_waitqueue_head(&arRaw->raw_htc_write_queue[streamID]); /* try to connect to the raw service */ status = ar6000_connect_raw_service(ar,streamID); if (A_FAILED(status)) { break; } if (arRawStream2EndpointID(ar,streamID) == 0) { break; } for (count2 = 0; count2 < RAW_HTC_READ_BUFFERS_NUM; count2 ++) { /* Initialize the receive buffers */ buffer = &arRaw->raw_htc_write_buffer[streamID][count2]; memset(buffer, 0, sizeof(raw_htc_buffer)); buffer = &arRaw->raw_htc_read_buffer[streamID][count2]; memset(buffer, 0, sizeof(raw_htc_buffer)); SET_HTC_PACKET_INFO_RX_REFILL(&buffer->HTCPacket, buffer, buffer->data, HTC_RAW_BUFFER_SIZE, arRawStream2EndpointID(ar,streamID)); /* Queue buffers to HTC for receive */ if ((status = HTCAddReceivePkt(ar->arHtcTarget, &buffer->HTCPacket)) != A_OK) { BMIInit(); return -EIO; } } for (count2 = 0; count2 < RAW_HTC_WRITE_BUFFERS_NUM; count2 ++) { /* Initialize the receive buffers */ buffer = &arRaw->raw_htc_write_buffer[streamID][count2]; memset(buffer, 0, sizeof(raw_htc_buffer)); } arRaw->read_buffer_available[streamID] = FALSE; arRaw->write_buffer_available[streamID] = TRUE; } if (A_FAILED(status)) { return -EIO; } AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("HTC RAW, number of streams the target supports: %d \n", streamID)); servicepriority = HTC_RAW_STREAMS_SVC; /* only 1 */ /* set callbacks and priority list */ HTCSetCreditDistribution(ar->arHtcTarget, ar, NULL, /* use default */ NULL, /* use default */ &servicepriority, 1); /* Start the HTC component */ if ((status = HTCStart(ar->arHtcTarget)) != A_OK) { BMIInit(); return -EIO; } (ar)->arRawIfInit = TRUE; return 0; }
static int ar6000_hci_transport_ready(HCI_TRANSPORT_HANDLE HCIHandle, struct hci_transport_properties *pProps, void *pContext) { struct ar6k_hci_bridge_info *pHcidevInfo = (struct ar6k_hci_bridge_info *)pContext; int status; u32 address, hci_uart_pwr_mgmt_params; // struct ar3k_config_info ar3kconfig; pHcidevInfo->pHCIDev = HCIHandle; memcpy(&pHcidevInfo->HCIProps,pProps,sizeof(*pProps)); AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE,("HCI ready (hci:0x%lX, headroom:%d, tailroom:%d blockpad:%d) \n", (unsigned long)HCIHandle, pHcidevInfo->HCIProps.HeadRoom, pHcidevInfo->HCIProps.TailRoom, pHcidevInfo->HCIProps.IOBlockPad)); #ifdef EXPORT_HCI_BRIDGE_INTERFACE A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice)->hard_header_len); #else A_ASSERT((pProps->HeadRoom + pProps->TailRoom) <= pHcidevInfo->ar->arNetDev->hard_header_len); #endif /* provide buffers */ RefillRecvBuffers(pHcidevInfo, HCI_ACL_TYPE, MAX_ACL_RECV_BUFS); RefillRecvBuffers(pHcidevInfo, HCI_EVENT_TYPE, MAX_EVT_RECV_BUFS); do { /* start transport */ status = HCI_TransportStart(pHcidevInfo->pHCIDev); if (status) { break; } if (!pHcidevInfo->HciNormalMode) { /* in test mode, no need to go any further */ break; } // The delay is required when AR6K is driving the BT reset line // where time is needed after the BT chip is out of reset (HCI_TransportStart) // and before the first HCI command is issued (AR3KConfigure) // FIXME // The delay should be configurable and be only applied when AR6K driving the BT // reset line. This could be done by some module parameter or based on some HW config // info. For now apply 100ms delay blindly A_MDELAY(100); A_MEMZERO(&ar3kconfig,sizeof(ar3kconfig)); ar3kconfig.pHCIDev = pHcidevInfo->pHCIDev; ar3kconfig.pHCIProps = &pHcidevInfo->HCIProps; #ifdef EXPORT_HCI_BRIDGE_INTERFACE ar3kconfig.pHIFDevice = (struct hif_device *)(pHcidevInfo->HCITransHdl.hifDevice); #else ar3kconfig.pHIFDevice = pHcidevInfo->ar->arHifDevice; #endif ar3kconfig.pBtStackHCIDev = pHcidevInfo->pBtStackHCIDev; if (ar3khcibaud != 0) { /* user wants ar3k baud rate change */ ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR3K_BAUD; ar3kconfig.Flags |= AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY; ar3kconfig.AR3KBaudRate = ar3khcibaud; } if ((hciuartscale != 0) || (hciuartstep != 0)) { /* user wants to tune HCI bridge UART scale/step values */ ar3kconfig.AR6KScale = (u16)hciuartscale; ar3kconfig.AR6KStep = (u16)hciuartstep; ar3kconfig.Flags |= AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP; } /* Fetch the address of the hi_hci_uart_pwr_mgmt_params instance in the host interest area */ address = TARG_VTOP(pHcidevInfo->ar->arTargetType, HOST_INTEREST_ITEM_ADDRESS(pHcidevInfo->ar, hi_hci_uart_pwr_mgmt_params)); status = ar6000_ReadRegDiag(pHcidevInfo->ar->arHifDevice, &address, &hci_uart_pwr_mgmt_params); if (0 == status) { ar3kconfig.PwrMgmtEnabled = (hci_uart_pwr_mgmt_params & 0x1); ar3kconfig.IdleTimeout = (hci_uart_pwr_mgmt_params & 0xFFFF0000) >> 16; ar3kconfig.WakeupTimeout = (hci_uart_pwr_mgmt_params & 0xFF00) >> 8; } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to read hci_uart_pwr_mgmt_params! \n")); } /* configure the AR3K device */ memcpy(ar3kconfig.bdaddr,pHcidevInfo->ar->bdaddr,6); status = AR3KConfigure(&ar3kconfig); if (status) { break; } /* Make sure both AR6K and AR3K have power management enabled */ if (ar3kconfig.PwrMgmtEnabled) { status = HCI_TransportEnablePowerMgmt(pHcidevInfo->pHCIDev, true); if (status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to enable TLPM for AR6K! \n")); } } status = bt_register_hci(pHcidevInfo); } while (false);
static void ar6000_htc_raw_read_cb(void *Context, HTC_PACKET *pPacket) { AR_SOFTC_T *ar = (AR_SOFTC_T *)Context; raw_htc_buffer *busy; HTC_RAW_STREAM_ID streamID; AR_RAW_HTC_T *arRaw = ar->arRawHtc; busy = (raw_htc_buffer *)pPacket->pPktContext; A_ASSERT(busy != NULL); if (pPacket->Status == A_ECANCELED) { /* * HTC provides A_ECANCELED status when it doesn't want to be refilled * (probably due to a shutdown) */ return; } streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint); A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED); if(streamID == HTC_RAW_STREAM_NOT_MAPPED) { return; /* in case panic_on_assert==0 */ } #ifdef CF if (down_trylock(&arRaw->raw_htc_read_sem[streamID])) { #else if (down_interruptible(&arRaw->raw_htc_read_sem[streamID])) { #endif /* CF */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to down the semaphore\n")); } A_ASSERT((pPacket->Status != A_OK) || (pPacket->pBuffer == (busy->data + HTC_HEADER_LEN))); busy->length = pPacket->ActualLength + HTC_HEADER_LEN; busy->currPtr = HTC_HEADER_LEN; arRaw->read_buffer_available[streamID] = TRUE; //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("raw read cb: 0x%X 0x%X \n", busy->currPtr,busy->length); up(&arRaw->raw_htc_read_sem[streamID]); /* Signal the waiting process */ AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Waking up the StreamID(%d) read process\n", streamID)); wake_up_interruptible(&arRaw->raw_htc_read_queue[streamID]); } static void ar6000_htc_raw_write_cb(void *Context, HTC_PACKET *pPacket) { AR_SOFTC_T *ar = (AR_SOFTC_T *)Context; raw_htc_buffer *free; HTC_RAW_STREAM_ID streamID; AR_RAW_HTC_T *arRaw = ar->arRawHtc; free = (raw_htc_buffer *)pPacket->pPktContext; A_ASSERT(free != NULL); if (pPacket->Status == A_ECANCELED) { /* * HTC provides A_ECANCELED status when it doesn't want to be refilled * (probably due to a shutdown) */ return; } streamID = arEndpoint2RawStreamID(ar,pPacket->Endpoint); A_ASSERT(streamID != HTC_RAW_STREAM_NOT_MAPPED); if(streamID == HTC_RAW_STREAM_NOT_MAPPED) { return; /* in case panic_on_assert==0 */ } #ifdef CF if (down_trylock(&arRaw->raw_htc_write_sem[streamID])) { #else if (down_interruptible(&arRaw->raw_htc_write_sem[streamID])) { #endif AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Unable to down the semaphore\n")); } A_ASSERT(pPacket->pBuffer == (free->data + HTC_HEADER_LEN)); free->length = 0; arRaw->write_buffer_available[streamID] = TRUE; up(&arRaw->raw_htc_write_sem[streamID]); /* Signal the waiting process */ AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("Waking up the StreamID(%d) write process\n", streamID)); wake_up_interruptible(&arRaw->raw_htc_write_queue[streamID]); } /* connect to a service */ static A_STATUS ar6000_connect_raw_service(AR_SOFTC_T *ar, HTC_RAW_STREAM_ID StreamID) { A_STATUS status; HTC_SERVICE_CONNECT_RESP response; A_UINT8 streamNo; HTC_SERVICE_CONNECT_REQ connect; do { A_MEMZERO(&connect,sizeof(connect)); /* pass the stream ID as meta data to the RAW streams service */ streamNo = (A_UINT8)StreamID; connect.pMetaData = &streamNo; connect.MetaDataLength = sizeof(A_UINT8); /* these fields are the same for all endpoints */ connect.EpCallbacks.pContext = ar; connect.EpCallbacks.EpTxComplete = ar6000_htc_raw_write_cb; connect.EpCallbacks.EpRecv = ar6000_htc_raw_read_cb; /* simple interface, we don't need these optional callbacks */ connect.EpCallbacks.EpRecvRefill = NULL; connect.EpCallbacks.EpSendFull = NULL; connect.MaxSendQueueDepth = RAW_HTC_WRITE_BUFFERS_NUM; /* connect to the raw streams service, we may be able to get 1 or more * connections, depending on WHAT is running on the target */ connect.ServiceID = HTC_RAW_STREAMS_SVC; A_MEMZERO(&response,sizeof(response)); /* try to connect to the raw stream, it is okay if this fails with * status HTC_SERVICE_NO_MORE_EP */ status = HTCConnectService(ar->arHtcTarget, &connect, &response); if (A_FAILED(status)) { if (response.ConnectRespCode == HTC_SERVICE_NO_MORE_EP) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HTC RAW , No more streams allowed \n")); status = A_OK; } break; } /* set endpoint mapping for the RAW HTC streams */ arSetRawStream2EndpointIDMap(ar,StreamID,response.Endpoint); AR_DEBUG_PRINTF(ATH_DEBUG_HTC_RAW,("HTC RAW : stream ID: %d, endpoint: %d\n", StreamID, arRawStream2EndpointID(ar,StreamID))); } while (FALSE); return status; }
/* wait for the target to arrive (sends HTC Ready message) * this operation is fully synchronous and the message is polled for */ A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle) { HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); A_STATUS status; HTC_PACKET *pPacket = NULL; HTC_READY_MSG *pRdyMsg; HTC_SERVICE_CONNECT_REQ connect; HTC_SERVICE_CONNECT_RESP resp; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%X) \n", (A_UINT32)target)); do { #ifdef MBOXHW_UNIT_TEST status = DoMboxHWTest(&target->Device); if (status != A_OK) { break; } #endif /* we should be getting 1 control message that the target is ready */ status = HTCWaitforControlMessage(target, &pPacket); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Target Not Available!!\n")); break; } /* we controlled the buffer creation so it has to be properly aligned */ pRdyMsg = (HTC_READY_MSG *)pPacket->pBuffer; if ((pRdyMsg->MessageID != HTC_MSG_READY_ID) || (pPacket->ActualLength < sizeof(HTC_READY_MSG))) { /* this message is not valid */ AR_DEBUG_ASSERT(FALSE); status = A_EPROTO; break; } if (pRdyMsg->CreditCount == 0 || pRdyMsg->CreditSize == 0) { /* this message is not valid */ AR_DEBUG_ASSERT(FALSE); status = A_EPROTO; break; } target->TargetCredits = pRdyMsg->CreditCount; target->TargetCreditSize = pRdyMsg->CreditSize; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, (" Target Ready: credits: %d credit size: %d\n", target->TargetCredits, target->TargetCreditSize)); printk(" Target Ready: credits: %d credit size: %d\n",target->TargetCredits, target->TargetCreditSize); /* setup our pseudo HTC control endpoint connection */ A_MEMZERO(&connect,sizeof(connect)); A_MEMZERO(&resp,sizeof(resp)); connect.EpCallbacks.pContext = target; connect.EpCallbacks.EpTxComplete = HTCControlTxComplete; connect.EpCallbacks.EpRecv = HTCControlRecv; connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */ connect.EpCallbacks.EpSendFull = NULL; /* not nedded */ connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS; connect.ServiceID = HTC_CTRL_RSVD_SVC; /* connect fake service */ status = HTCConnectService((HTC_HANDLE)target, &connect, &resp); if (!A_FAILED(status)) { break; } } while (FALSE); if (pPacket != NULL) { HTC_FREE_CONTROL_RX(target,pPacket); } AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit\n")); return status; }
/* setup of HIF scatter resources */ A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_INFO *pInfo) { A_STATUS status = A_ERROR; int i; HIF_SCATTER_REQ_PRIV *pReqPriv; BUS_REQUEST *busrequest; do { /* check if host supports scatter requests and it meets our requirements */ if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n", device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ)); status = A_ENOTSUP; break; } AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("HIF-SCATTER Enabled: max scatter req : %d entries: %d \n", MAX_SCATTER_REQUESTS, MAX_SCATTER_ENTRIES_PER_REQ)); for (i = 0; i < MAX_SCATTER_REQUESTS; i++) { /* allocate the private request blob */ pReqPriv = (HIF_SCATTER_REQ_PRIV *)A_MALLOC(sizeof(HIF_SCATTER_REQ_PRIV)); if (NULL == pReqPriv) { break; } A_MEMZERO(pReqPriv, sizeof(HIF_SCATTER_REQ_PRIV)); /* save the device instance*/ pReqPriv->device = device; /* allocate the scatter request */ pReqPriv->pHifScatterReq = (HIF_SCATTER_REQ *)A_MALLOC(sizeof(HIF_SCATTER_REQ) + (MAX_SCATTER_ENTRIES_PER_REQ - 1) * (sizeof(HIF_SCATTER_ITEM))); if (NULL == pReqPriv->pHifScatterReq) { A_FREE(pReqPriv); break; } /* just zero the main part of the scatter request */ A_MEMZERO(pReqPriv->pHifScatterReq, sizeof(HIF_SCATTER_REQ)); /* back pointer to the private struct */ pReqPriv->pHifScatterReq->HIFPrivate[0] = pReqPriv; /* allocate a bus request for this scatter request */ busrequest = hifAllocateBusRequest(device); if (NULL == busrequest) { A_FREE(pReqPriv->pHifScatterReq); A_FREE(pReqPriv); break; } /* assign the scatter request to this bus request */ busrequest->pScatterReq = pReqPriv; /* point back to the request */ pReqPriv->busrequest = busrequest; /* add it to the scatter pool */ FreeScatterReq(device,pReqPriv->pHifScatterReq); } if (i != MAX_SCATTER_REQUESTS) { status = A_NO_MEMORY; AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : failed to alloc scatter resources !\n")); break; } /* set scatter function pointers */ pInfo->pAllocateReqFunc = AllocScatterReq; pInfo->pFreeReqFunc = FreeScatterReq; pInfo->pReadWriteScatterFunc = HifReadWriteScatter; pInfo->MaxScatterEntries = MAX_SCATTER_ENTRIES_PER_REQ; pInfo->MaxTransferSizePerScatterReq = MAX_SCATTER_REQ_TRANSFER_SIZE; status = A_OK; } while (FALSE); if (A_FAILED(status)) { CleanupHIFScatterResources(device); } return status; }
/* 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 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; }
void HTCStop(HTC_TARGET *target) { A_UINT32 count; A_STATUS status; A_UINT32 address; HIF_REQUEST request; A_UINT32 window_data; HTC_ENDPOINT *endPoint; HTC_REG_REQUEST_LIST *regList; HTC_REG_REQUEST_ELEMENT *element; HTC_DATA_REQUEST_QUEUE *sendQueue; HTC_DATA_REQUEST_QUEUE *recvQueue; HTC_DEBUG_PRINTF(ATH_LOG_TRC, "HTCStop: Enter"); /* Disable all the dragon interrupts */ target->table.int_status_enable = 0; target->table.cpu_int_status_enable = 0; target->table.error_status_enable = 0; target->table.counter_int_status_enable = 0; HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS); address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, &target->table.int_status_enable, 4, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); /* Disable the host controller interrupts */ HIFMaskInterrupt(target->device); /* Flush all the queues and return the buffers to their owner */ for (count = ENDPOINT1; count <= ENDPOINT4; count ++) { endPoint = &target->endPoint[count]; /* Decrement the number of credits consumed */ if (endPoint->txCreditsConsumed) { HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(TX_CREDIT_COUNTER_DECREMENT_REG, count); #ifdef ONLY_16BIT status = HIFReadWrite(target->device, address, (A_UCHAR *)endPoint->txCreditsAvailable, endPoint->txCreditsConsumed * 2, &request, NULL); #else status = HIFReadWrite(target->device, address, endPoint->txCreditsAvailable, endPoint->txCreditsConsumed, &request, NULL); #endif AR_DEBUG_ASSERT(status == A_OK); } SET_TX_CREDITS_AVAILABLE(endPoint, 0); SET_TX_CREDITS_CONSUMED(endPoint, 0); #ifdef DEBUG txcreditsavailable[count] = GET_TX_CREDITS_AVAILABLE(endPoint); txcreditsconsumed[count] = GET_TX_CREDITS_CONSUMED(endPoint); #endif endPoint->txCreditsIntrEnable = FALSE; endPoint->rxLengthPending = 0; endPoint->enabled = FALSE; /* Flush the Pending Receive Queue */ HTC_DEBUG_PRINTF(ATH_LOG_INF, "Flushing the recv queue & returning the buffers\n"); recvQueue = &endPoint->recvQueue; flushMboxQueue(endPoint, recvQueue, HTC_BUFFER_RECEIVED); /* Flush the Pending Send Queue */ HTC_DEBUG_PRINTF(ATH_LOG_INF, "Flushing the send queue & returning the buffers\n"); sendQueue = &endPoint->sendQueue; flushMboxQueue(endPoint, sendQueue, HTC_BUFFER_SENT); } /* Clear the tx counters */ memset(tx_attempt, 0, sizeof(tx_attempt)); memset(tx_post, 0, sizeof(tx_post)); memset(tx_complete, 0, sizeof(tx_complete)); /* Attempting a force reset of the target */ window_data = RESET_CONTROL_COLD_RST_MASK; HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS); address = getRegAddr(WINDOW_DATA_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, (A_UCHAR *)&window_data, 4, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); _WRITE_WINDOW_ADDR(target, WINDOW_WRITE_ADDR_REG, RESET_CONTROL_ADDRESS); /* * Read back the RESET CAUSE register to ensure that the cold reset * went through. */ A_MDELAY(2000); /* 2 Second delay to allow dragon to settle down */ _WRITE_WINDOW_ADDR(target, WINDOW_READ_ADDR_REG, RESET_CAUSE_ADDRESS); window_data = 0; HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS); address = getRegAddr(WINDOW_DATA_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, (A_UCHAR *)&window_data, 4, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); HTC_DEBUG_PRINTF(ATH_LOG_INF, "window data: %d\n", window_data); window_data &= RESET_CAUSE_LAST_MASK; if (window_data != 2) { HTC_DEBUG_PRINTF(ATH_LOG_ERR, "Unable to cold reset the target\n"); } /* * Ensure that all the pending asynchronous register read/writes have * been finished. */ regList = &target->regList; for (count = 0; count < HTC_REG_REQUEST_LIST_SIZE; count ++) { element = ®List->element[count]; AR_DEBUG_ASSERT(IS_ELEMENT_FREE(element)); } /* Initialize the shadow copy of the target register table */ A_MEMZERO(&target->table, sizeof(HTC_REGISTER_TABLE)); target->ready = FALSE; HTC_DEBUG_PRINTF(ATH_LOG_TRC, "HTCStop: Exit"); }
/* called in response to the arrival of a service connection message */ LOCAL void HTCProcessConnectMsg(HTC_CONTEXT *pHTC, HTC_CONNECT_SERVICE_MSG *pMsg) { HTC_SERVICE *pService = pHTC->pServiceList; A_UINT8 connectStatus = HTC_SERVICE_NOT_FOUND; adf_nbuf_t pBuffer; HTC_CONNECT_SERVICE_RESPONSE_MSG *pRspMsg; int metaDataOutLen = 0; A_UINT16 serviceId = adf_os_ntohs(pMsg->ServiceID); pBuffer = HTCAllocMsgBuffer(pHTC); /* note : this will be aligned */ pRspMsg = (HTC_CONNECT_SERVICE_RESPONSE_MSG *) adf_nbuf_put_tail(pBuffer, sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG)); A_MEMZERO(pRspMsg,sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG)); pRspMsg->MessageID = adf_os_htons(HTC_MSG_CONNECT_SERVICE_RESPONSE_ID); /* reflect the service ID for this connect attempt */ pRspMsg->ServiceID = adf_os_htons(serviceId); while (pService) { if (pHTC->CurrentEpIndex >= ENDPOINT_MAX) { /* no more endpoints */ connectStatus = HTC_SERVICE_NO_RESOURCES; break; } if (serviceId == pService->ServiceID) { /* we found a match */ A_UINT8 *pMetaDataIN = NULL; A_UINT8 *pMetaDataOut; /* outgoing meta data resides in the space after the response message */ pMetaDataOut = ((A_UINT8 *)pRspMsg) + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG); if (pMsg->ServiceMetaLength != 0) { /* the meta data follows the connect service message */ pMetaDataIN = ((A_UINT8 *)pMsg) + sizeof(HTC_CONNECT_SERVICE_MSG); } /* call the connect callback with the endpoint to use and pointers to meta data */ connectStatus = pService->ProcessConnect(pService, pHTC->CurrentEpIndex, pMetaDataIN, pMsg->ServiceMetaLength, pMetaDataOut, &metaDataOutLen); /* check if the service accepted this connection request */ if (HTC_SERVICE_SUCCESS == connectStatus) { /* set the length of the response meta data going back to the host */ pRspMsg->ServiceMetaLength = (A_UINT8)metaDataOutLen; /* set the endpoint ID the host will now communicate over */ pRspMsg->EndpointID = pHTC->CurrentEpIndex; /* return the maximum message size for this service */ pRspMsg->MaxMsgSize = adf_os_htons((A_UINT16)pService->MaxSvcMsgSize); /* assign this endpoint to this service, this will be used in routing messages */ pHTC->Endpoints[pHTC->CurrentEpIndex].pService = pService; /* set connection flags */ pHTC->Endpoints[pHTC->CurrentEpIndex].ConnectionFlags = pMsg->ConnectionFlags; pHTC->Endpoints[pHTC->CurrentEpIndex].DownLinkPipeID = pMsg->DownLinkPipeID; pHTC->Endpoints[pHTC->CurrentEpIndex].UpLinkPipeID = pMsg->UpLinkPipeID; /* mark that we are now connected */ pService->ServiceFlags |= HTC_SERVICE_FLAGS_CONNECTED; /* bump up our index, this EP is now in use */ pHTC->CurrentEpIndex++; } break; } pService = pService->pNext; } pRspMsg->Status = connectStatus; /* send out the response message */ HTC_SendMsg(pHTC, ENDPOINT0, pBuffer); }
/* 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; }
void Abf_WlanCheckSettings(A_CHAR *wifname, A_UINT32 *btfiltFlags) { int sd; A_CHAR ifname[IFNAMSIZ]; #ifdef ANDROID char ifprop[PROPERTY_VALUE_MAX]; if (wifname[0] == '\0' && property_get("wifi.interface", ifprop, NULL)) { strcpy(wifname, ifprop); } #endif { A_BOOL found = FALSE; A_CHAR linebuf[1024]; FILE *f = fopen("/proc/net/wireless", "r"); if (f) { while(fgets(linebuf, sizeof(linebuf)-1, f)) { if (strchr(linebuf, ':')) { char *dest = ifname; char *p = linebuf; while(*p && isspace(*p)) ++p; while (*p && *p != ':') *dest++ = *p++; *dest = '\0'; if (strcmp(wifname, ifname)==0) { found = TRUE; break; } } } if (!found && ifname[0]!='\0') { strcpy(wifname, ifname); } fclose(f); } } A_DEBUG("%s : wlan: %s\n", __FUNCTION__, wifname); if (wifname[0] == '\0' || !btfiltFlags) { return; } if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { A_ERR("[%s] Error creating socket: %d\n", __FUNCTION__, sd); return; } do { A_UINT32 flags = *btfiltFlags; struct ifreq ifr; struct ar6000_version revinfo; A_MEMZERO(&revinfo, sizeof(revinfo)); strncpy(ifr.ifr_name, wifname, sizeof(ifr.ifr_name)); ifr.ifr_data = (void *)&revinfo; if (ioctl(sd, AR6000_IOCTL_WMI_GETREV, &ifr) < 0) { break; } if ( (revinfo.target_ver & 0xf0000000)==0x30000000) { *btfiltFlags |= ABF_WIFI_CHIP_IS_VENUS; } else { *btfiltFlags &= ~ABF_WIFI_CHIP_IS_VENUS; } if (*btfiltFlags != flags) { A_DEBUG("Change btfilt flags from %u to %u isVenus %d\n", flags, *btfiltFlags, (*btfiltFlags & ABF_WIFI_CHIP_IS_VENUS) ? "yes" : "no"); } } while (0); close(sd); }
A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle) { A_STATUS status = A_OK; HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); HTC_READY_EX_MSG *pReadyMsg; HTC_SERVICE_CONNECT_REQ connect; HTC_SERVICE_CONNECT_RESP resp; HTC_READY_MSG *rdy_msg; A_UINT16 htc_rdy_msg_id; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Enter (target:0x%p) \n", HTCHandle)); AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("+HWT\n")); do { status = HIFStart(target->hif_dev); if (A_FAILED(status)) { break; } status = HTCWaitRecvCtrlMessage(target); if (A_FAILED(status)) { break; } if (target->CtrlResponseLength < (sizeof(HTC_READY_EX_MSG))) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid HTC Ready Msg Len:%d! \n",target->CtrlResponseLength)); status = A_ECOMM; break; } pReadyMsg = (HTC_READY_EX_MSG *)target->CtrlResponseBuffer; rdy_msg = &pReadyMsg->Version2_0_Info; htc_rdy_msg_id = HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, MESSAGEID); if (htc_rdy_msg_id != HTC_MSG_READY_ID) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid HTC Ready Msg : 0x%X ! \n",htc_rdy_msg_id)); status = A_ECOMM; break; } target->TotalTransmitCredits = HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITCOUNT); target->TargetCreditSize = (int)HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITSIZE); AR_DEBUG_PRINTF(ATH_DEBUG_INIT, ("Target Ready! : transmit resources : %d size:%d\n", target->TotalTransmitCredits, target->TargetCreditSize)); if ((0 == target->TotalTransmitCredits) || (0 == target->TargetCreditSize)) { status = A_ECOMM; break; } /* done processing */ target->CtrlResponseProcessing = FALSE; HTCSetupTargetBufferAssignments(target); /* setup our pseudo HTC control endpoint connection */ A_MEMZERO(&connect,sizeof(connect)); A_MEMZERO(&resp,sizeof(resp)); connect.EpCallbacks.pContext = target; connect.EpCallbacks.EpTxComplete = HTCControlTxComplete; connect.EpCallbacks.EpRecv = HTCControlRxComplete; connect.MaxSendQueueDepth = NUM_CONTROL_TX_BUFFERS; connect.ServiceID = HTC_CTRL_RSVD_SVC; /* connect fake service */ status = HTCConnectService((HTC_HANDLE)target, &connect, &resp); } while (FALSE); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCWaitTarget - Exit (%d)\n",status)); AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("-HWT\n")); return status; }
void HIFDetachHTC(HIF_DEVICE *device) { A_MEMZERO(&device->htcCallbacks,sizeof(device->htcCallbacks)); }
int main(int argc, char *argv[]) { int ret; char *config_file = NULL; int opt = 0, daemonize = 1, debug = 0, console_output=0; progname = argv[0]; A_STATUS status; struct sigaction sa; ATHBT_FILTER_INFO *pInfo; A_UINT32 btfiltFlags = 0; A_MEMZERO(&g_AthBtFilterInstance, sizeof(ATH_BT_FILTER_INSTANCE)); /* * Keep an option to specify the wireless extension. By default, * assume it to be equal to WIRELESS_EXT TODO */ /* Get user specified options */ while ((opt = getopt(argc, argv, "bsvandczxf:w:")) != EOF) { switch (opt) { case 'n': daemonize = 0; break; case 'd': debug = 1; break; case 'f': if (optarg) { config_file = strdup(optarg); } break; case 'c': console_output = 1; break; case 'a': btfiltFlags |= ABF_ENABLE_AFH_CHANNEL_CLASSIFICATION; break; case 'z': btfiltFlags |= ABF_USE_HCI_FILTER_FOR_HEADSET_PROFILE; break; case 'v': btfiltFlags |= ABF_WIFI_CHIP_IS_VENUS ; A_DEBUG("wifi chip is venus\n"); break; case 'x': btfiltFlags |= ABF_BT_CHIP_IS_ATHEROS ; A_DEBUG("bt chip is atheros\n"); break; case 's': btfiltFlags |= ABF_FE_ANT_IS_SA ; A_DEBUG("Front End Antenna Configuration is single antenna \n"); break; case 'w': memset(wifname, '\0', IFNAMSIZ); strcpy(wifname, optarg); g_AthBtFilterInstance.pWlanAdapterName = (A_CHAR *)&wifname; break; case 'b': btfiltFlags |= ABF_USE_ONLY_DBUS_FILTERING; break; default: usage(); exit(1); } } /* Launch the daemon if desired */ if (daemonize && daemon(0, console_output ? 1 : 0)) { printf("Can't daemonize: %s\n", strerror(errno)); exit(1); } /* Initialize the debug infrastructure */ A_DBG_INIT("ATHBT", "Ath BT Filter Daemon"); if (debug) { if (console_output) { A_DBG_SET_OUTPUT_TO_CONSOLE(); } // setlogmask(LOG_INFO | LOG_DEBUG | LOG_ERR); A_INFO("Enabling Debug Information\n"); A_SET_DEBUG(1); } if (config_file) { A_DEBUG("Config file: %s\n", config_file); if (!(gConfigFile = fopen(config_file, "r"))) { A_ERR("[%s] fopen failed\n", __FUNCTION__); } } A_MEMZERO(&sa, sizeof(struct sigaction)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = Abf_SigTerm; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); Abf_HciLibInit(&btfiltFlags); /* Initialize the Filter core */ do { Abf_WlanCheckSettings(wifname, &btfiltFlags); ret = AthBtFilter_Attach(&g_AthBtFilterInstance, btfiltFlags ); if (ret) { A_ERR("Filter initialization failed\n"); break; } /* Initialize the WLAN notification mechanism */ status = Abf_WlanStackNotificationInit(&g_AthBtFilterInstance, btfiltFlags ); if (A_FAILED(status)) { AthBtFilter_Detach(&g_AthBtFilterInstance); A_ERR("WLAN stack notification init failed\n"); break; } /* Initialize the BT notification mechanism */ status = Abf_BtStackNotificationInit(&g_AthBtFilterInstance,btfiltFlags); if (A_FAILED(status)) { Abf_WlanStackNotificationDeInit(&g_AthBtFilterInstance); AthBtFilter_Detach(&g_AthBtFilterInstance); A_ERR("BT stack notification init failed\n"); break; } /* Check for errors on the return value TODO */ pInfo = g_AthBtFilterInstance.pContext; GpInfo = pInfo; A_DEBUG("Service running, waiting for termination .... \n"); /* wait for termination signal */ while (!terminated) { sleep(1); } } while(FALSE); /* Initiate the shutdown sequence */ if(GpInfo != NULL) { AthBtFilter_State_Off(GpInfo); } Abf_ShutDown(); Abf_HciLibDeInit(); /* Shutdown */ if (gConfigFile) { fclose(gConfigFile); } if (config_file) { A_FREE(config_file); } A_DEBUG("Service terminated \n"); A_MEMZERO(&g_AthBtFilterInstance, sizeof(ATH_BT_FILTER_INSTANCE)); A_DBG_DEINIT(); return 0; }
A_STATUS HTCSendSetupComplete(HTC_TARGET *target) { HTC_PACKET *pSendPacket = NULL; A_STATUS status; do { /* allocate a packet to send to the target */ pSendPacket = HTC_ALLOC_CONTROL_TX(target); if (NULL == pSendPacket) { status = A_NO_MEMORY; break; } if (target->HTCTargetVersion >= HTC_VERSION_2P1) { HTC_SETUP_COMPLETE_EX_MSG *pSetupCompleteEx; A_UINT32 setupFlags = 0; pSetupCompleteEx = (HTC_SETUP_COMPLETE_EX_MSG *)pSendPacket->pBuffer; A_MEMZERO(pSetupCompleteEx, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); pSetupCompleteEx->MessageID = HTC_MSG_SETUP_COMPLETE_EX_ID; if (target->MaxMsgPerBundle > 0) { /* host can do HTC bundling, indicate this to the target */ setupFlags |= HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV; pSetupCompleteEx->MaxMsgsPerBundledRecv = target->MaxMsgPerBundle; } A_MEMCPY(&pSetupCompleteEx->SetupFlags, &setupFlags, sizeof(pSetupCompleteEx->SetupFlags)); SET_HTC_PACKET_INFO_TX(pSendPacket, NULL, (A_UINT8 *)pSetupCompleteEx, sizeof(HTC_SETUP_COMPLETE_EX_MSG), ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); } else { HTC_SETUP_COMPLETE_MSG *pSetupComplete; /* assemble setup complete message */ pSetupComplete = (HTC_SETUP_COMPLETE_MSG *)pSendPacket->pBuffer; A_MEMZERO(pSetupComplete, sizeof(HTC_SETUP_COMPLETE_MSG)); pSetupComplete->MessageID = HTC_MSG_SETUP_COMPLETE_ID; SET_HTC_PACKET_INFO_TX(pSendPacket, NULL, (A_UINT8 *)pSetupComplete, sizeof(HTC_SETUP_COMPLETE_MSG), ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); } /* we want synchronous operation */ pSendPacket->Completion = NULL; HTC_PREPARE_SEND_PKT(pSendPacket,0,0,0); /* send the message */ status = HTCIssueSend(target,pSendPacket); } while (FALSE); if (pSendPacket != NULL) { HTC_FREE_CONTROL_TX(target,pSendPacket); } return status; }
A_STATUS htc_wait_target(HTC_HANDLE HTCHandle) { A_STATUS status = A_OK; HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); HTC_READY_EX_MSG *pReadyMsg; HTC_SERVICE_CONNECT_REQ connect; HTC_SERVICE_CONNECT_RESP resp; HTC_READY_MSG *rdy_msg; A_UINT16 htc_rdy_msg_id; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_wait_target - Enter (target:0x%p) \n", HTCHandle)); AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("+HWT\n")); do { status = hif_start(target->hif_dev); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("hif_start failed\n")); break; } status = htc_wait_recv_ctrl_message(target); if (A_FAILED(status)) { break; } if (target->CtrlResponseLength < (sizeof(HTC_READY_EX_MSG))) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid HTC Ready Msg Len:%d! \n", target->CtrlResponseLength)); status = A_ECOMM; break; } pReadyMsg = (HTC_READY_EX_MSG *) target->CtrlResponseBuffer; rdy_msg = &pReadyMsg->Version2_0_Info; htc_rdy_msg_id = HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, MESSAGEID); if (htc_rdy_msg_id != HTC_MSG_READY_ID) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid HTC Ready Msg : 0x%X ! \n", htc_rdy_msg_id)); status = A_ECOMM; break; } target->TotalTransmitCredits = HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITCOUNT); target->TargetCreditSize = (int)HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITSIZE); target->MaxMsgsPerHTCBundle = (A_UINT8) pReadyMsg->MaxMsgsPerHTCBundle; /* for old fw this value is set to 0. But the minimum value should be 1, * i.e., no bundling */ if (target->MaxMsgsPerHTCBundle < 1) target->MaxMsgsPerHTCBundle = 1; AR_DEBUG_PRINTF(ATH_DEBUG_INIT, ("Target Ready! : transmit resources : %d size:%d, MaxMsgsPerHTCBundle = %d\n", target->TotalTransmitCredits, target->TargetCreditSize, target->MaxMsgsPerHTCBundle)); if ((0 == target->TotalTransmitCredits) || (0 == target->TargetCreditSize)) { status = A_ECOMM; break; } /* done processing */ target->CtrlResponseProcessing = false; htc_setup_target_buffer_assignments(target); /* setup our pseudo HTC control endpoint connection */ A_MEMZERO(&connect, sizeof(connect)); A_MEMZERO(&resp, sizeof(resp)); connect.EpCallbacks.pContext = target; connect.EpCallbacks.EpTxComplete = htc_control_tx_complete; connect.EpCallbacks.EpRecv = htc_control_rx_complete; connect.MaxSendQueueDepth = NUM_CONTROL_TX_BUFFERS; connect.ServiceID = HTC_CTRL_RSVD_SVC; /* connect fake service */ status = htc_connect_service((HTC_HANDLE) target, &connect, &resp); } while (false); AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_wait_target - Exit (%d)\n", status)); AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("-HWT\n")); return status; }