Index: chromeos/drivers/ath6kl/os/linux/hci_bridge.c |
diff --git a/chromeos/drivers/ath6kl/os/linux/hci_bridge.c b/chromeos/drivers/ath6kl/os/linux/hci_bridge.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..32489336975d4e1794ded18ba7fa0fc6e650d34e |
--- /dev/null |
+++ b/chromeos/drivers/ath6kl/os/linux/hci_bridge.c |
@@ -0,0 +1,1117 @@ |
+//------------------------------------------------------------------------------ |
+// <copyright file="hci_bridge.c" company="Atheros"> |
+// Copyright (c) 2009 Atheros Corporation. All rights reserved. |
+// |
+// This program is free software; you can redistribute it and/or modify |
+// it under the terms of the GNU General Public License version 2 as |
+// published by the Free Software Foundation; |
+// |
+// Software distributed under the License is distributed on an "AS |
+// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
+// implied. See the License for the specific language governing |
+// rights and limitations under the License. |
+// |
+// |
+//------------------------------------------------------------------------------ |
+//============================================================================== |
+// HCI bridge implementation |
+// |
+// Author(s): ="Atheros" |
+//============================================================================== |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+#include <linux/etherdevice.h> |
+#include <a_config.h> |
+#include <athdefs.h> |
+#include "a_types.h" |
+#include "a_osapi.h" |
+#include "htc_api.h" |
+#include "wmi.h" |
+#include "a_drv.h" |
+#include "hif.h" |
+#include "common_drv.h" |
+#include "a_debug.h" |
+#define ATH_DEBUG_HCI_BRIDGE ATH_DEBUG_MAKE_MODULE_MASK(6) |
+#define ATH_DEBUG_HCI_RECV ATH_DEBUG_MAKE_MODULE_MASK(7) |
+#define ATH_DEBUG_HCI_SEND ATH_DEBUG_MAKE_MODULE_MASK(8) |
+#define ATH_DEBUG_HCI_DUMP ATH_DEBUG_MAKE_MODULE_MASK(9) |
+#else |
+#include "ar6000_drv.h" |
+#endif /* EXPORT_HCI_BRIDGE_INTERFACE */ |
+ |
+#ifdef ATH_AR6K_ENABLE_GMBOX |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+#include "export_hci_transport.h" |
+#else |
+#include "hci_transport_api.h" |
+#endif |
+#include "epping_test.h" |
+#include "gmboxif.h" |
+#include "ar3kconfig.h" |
+#include <net/bluetooth/bluetooth.h> |
+#include <net/bluetooth/hci_core.h> |
+ |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) |
+ /* only build on newer kernels which have BT configured */ |
+#if defined(CONFIG_BT_MODULE) || defined(CONFIG_BT) |
+#define CONFIG_BLUEZ_HCI_BRIDGE |
+#endif |
+#endif |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+unsigned int ar3khcibaud = 0; |
+unsigned int hciuartscale = 0; |
+unsigned int hciuartstep = 0; |
+ |
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) |
+module_param(ar3khcibaud, int, 0644); |
+module_param(hciuartscale, int, 0644); |
+module_param(hciuartstep, int, 0644); |
+#else |
+ |
+#define __user |
+/* for linux 2.4 and lower */ |
+MODULE_PARM(ar3khcibaud, "i"); |
+MODULE_PARM(hciuartscale, "i"); |
+MODULE_PARM(hciuartstep, "i"); |
+#endif |
+#else |
+extern unsigned int ar3khcibaud; |
+extern unsigned int hciuartscale; |
+extern unsigned int hciuartstep; |
+#endif /* EXPORT_HCI_BRIDGE_INTERFACE */ |
+ |
+typedef struct { |
+ void *pHCIDev; /* HCI bridge device */ |
+ HCI_TRANSPORT_PROPERTIES HCIProps; /* HCI bridge props */ |
+ struct hci_dev *pBtStackHCIDev; /* BT Stack HCI dev */ |
+ A_BOOL HciNormalMode; /* Actual HCI mode enabled (non-TEST)*/ |
+ A_BOOL HciRegistered; /* HCI device registered with stack */ |
+ HTC_PACKET_QUEUE HTCPacketStructHead; |
+ A_UINT8 *pHTCStructAlloc; |
+ spinlock_t BridgeLock; |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+ HCI_TRANSPORT_MISC_HANDLES HCITransHdl; |
+#else |
+ AR_SOFTC_T *ar; |
+#endif /* EXPORT_HCI_BRIDGE_INTERFACE */ |
+} AR6K_HCI_BRIDGE_INFO; |
+ |
+#define MAX_ACL_RECV_BUFS 16 |
+#define MAX_EVT_RECV_BUFS 8 |
+#define MAX_HCI_WRITE_QUEUE_DEPTH 32 |
+#define MAX_ACL_RECV_LENGTH 1200 |
+#define MAX_EVT_RECV_LENGTH 257 |
+#define TX_PACKET_RSV_OFFSET 32 |
+#define NUM_HTC_PACKET_STRUCTS ((MAX_ACL_RECV_BUFS + MAX_EVT_RECV_BUFS + MAX_HCI_WRITE_QUEUE_DEPTH) * 2) |
+ |
+#define HCI_GET_OP_CODE(p) (((A_UINT16)((p)[1])) << 8) | ((A_UINT16)((p)[0])) |
+ |
+extern unsigned int setupbtdev; |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+AR6K_HCI_BRIDGE_INFO *g_pHcidevInfo; |
+#endif |
+ |
+static A_STATUS bt_setup_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo); |
+static void bt_cleanup_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo); |
+static A_STATUS bt_register_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo); |
+static A_BOOL bt_indicate_recv(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, |
+ HCI_TRANSPORT_PACKET_TYPE Type, |
+ struct sk_buff *skb); |
+static struct sk_buff *bt_alloc_buffer(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, int Length); |
+static void bt_free_buffer(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, struct sk_buff *skb); |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+A_STATUS ar6000_setup_hci(void *ar); |
+void ar6000_cleanup_hci(void *ar); |
+A_STATUS hci_test_send(void *ar, struct sk_buff *skb); |
+#else |
+A_STATUS ar6000_setup_hci(AR_SOFTC_T *ar); |
+void ar6000_cleanup_hci(AR_SOFTC_T *ar); |
+/* HCI bridge testing */ |
+A_STATUS hci_test_send(AR_SOFTC_T *ar, struct sk_buff *skb); |
+#endif /* EXPORT_HCI_BRIDGE_INTERFACE */ |
+ |
+#define LOCK_BRIDGE(dev) spin_lock_bh(&(dev)->BridgeLock) |
+#define UNLOCK_BRIDGE(dev) spin_unlock_bh(&(dev)->BridgeLock) |
+ |
+static inline void FreeBtOsBuf(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, void *osbuf) |
+{ |
+ if (pHcidevInfo->HciNormalMode) { |
+ bt_free_buffer(pHcidevInfo, (struct sk_buff *)osbuf); |
+ } else { |
+ /* in test mode, these are just ordinary netbuf allocations */ |
+ A_NETBUF_FREE(osbuf); |
+ } |
+} |
+ |
+static void FreeHTCStruct(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, HTC_PACKET *pPacket) |
+{ |
+ LOCK_BRIDGE(pHcidevInfo); |
+ HTC_PACKET_ENQUEUE(&pHcidevInfo->HTCPacketStructHead,pPacket); |
+ UNLOCK_BRIDGE(pHcidevInfo); |
+} |
+ |
+static HTC_PACKET * AllocHTCStruct(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) |
+{ |
+ HTC_PACKET *pPacket = NULL; |
+ LOCK_BRIDGE(pHcidevInfo); |
+ pPacket = HTC_PACKET_DEQUEUE(&pHcidevInfo->HTCPacketStructHead); |
+ UNLOCK_BRIDGE(pHcidevInfo); |
+ return pPacket; |
+} |
+ |
+#define BLOCK_ROUND_UP_PWR2(x, align) (((int) (x) + ((align)-1)) & ~((align)-1)) |
+ |
+static void RefillRecvBuffers(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, |
+ HCI_TRANSPORT_PACKET_TYPE Type, |
+ int NumBuffers) |
+{ |
+ int length, i; |
+ void *osBuf = NULL; |
+ HTC_PACKET_QUEUE queue; |
+ 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 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; |
+ AR3K_CONFIG_INFO ar3kconfig; |
+ |
+ pHcidevInfo->pHCIDev = HCIHandle; |
+ |
+ A_MEMCPY(&pHcidevInfo->HCIProps,pProps,sizeof(*pProps)); |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE,("HCI ready (hci:0x%X, headroom:%d, tailroom:%d blockpad:%d) \n", |
+ (A_UINT32)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 (A_FAILED(status)) { |
+ break; |
+ } |
+ |
+ if (!pHcidevInfo->HciNormalMode) { |
+ /* in test mode, no need to go any further */ |
+ break; |
+ } |
+ |
+ 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 */ |
+ status = AR3KConfigure(&ar3kconfig); |
+ if (A_FAILED(status)) { |
+ break; |
+ } |
+ |
+ status = bt_register_hci(pHcidevInfo); |
+ |
+ } while (FALSE); |
+ |
+ return status; |
+} |
+ |
+static void ar6000_hci_transport_failure(void *pContext, A_STATUS Status) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: transport failure! \n")); |
+ |
+ if (pHcidevInfo->HciNormalMode) { |
+ /* TODO .. */ |
+ } |
+} |
+ |
+static void ar6000_hci_transport_removed(void *pContext) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: transport removed. \n")); |
+ |
+ A_ASSERT(pHcidevInfo->pHCIDev != NULL); |
+ |
+ HCI_TransportDetach(pHcidevInfo->pHCIDev); |
+ bt_cleanup_hci(pHcidevInfo); |
+ pHcidevInfo->pHCIDev = NULL; |
+} |
+ |
+static void ar6000_hci_send_complete(void *pContext, HTC_PACKET *pPacket) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; |
+ void *osbuf = pPacket->pPktContext; |
+ A_ASSERT(osbuf != NULL); |
+ A_ASSERT(pHcidevInfo != NULL); |
+ |
+ if (A_FAILED(pPacket->Status)) { |
+ if ((pPacket->Status != A_ECANCELED) && (pPacket->Status != A_NO_RESOURCE)) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: Send Packet Failed: %d \n",pPacket->Status)); |
+ } |
+ } |
+ |
+ FreeHTCStruct(pHcidevInfo,pPacket); |
+ FreeBtOsBuf(pHcidevInfo,osbuf); |
+ |
+} |
+ |
+static void ar6000_hci_pkt_recv(void *pContext, HTC_PACKET *pPacket) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; |
+ struct sk_buff *skb; |
+ |
+ A_ASSERT(pHcidevInfo != NULL); |
+ skb = (struct sk_buff *)pPacket->pPktContext; |
+ A_ASSERT(skb != NULL); |
+ |
+ do { |
+ |
+ if (A_FAILED(pPacket->Status)) { |
+ break; |
+ } |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_RECV, |
+ ("HCI Bridge, packet received type : %d len:%d \n", |
+ HCI_GET_PACKET_TYPE(pPacket),pPacket->ActualLength)); |
+ |
+ /* set the actual buffer position in the os buffer, HTC recv buffers posted to HCI are set |
+ * to fill the front of the buffer */ |
+ A_NETBUF_PUT(skb,pPacket->ActualLength + pHcidevInfo->HCIProps.HeadRoom); |
+ A_NETBUF_PULL(skb,pHcidevInfo->HCIProps.HeadRoom); |
+ |
+ if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ANY,("<<< Recv HCI %s packet len:%d \n", |
+ (HCI_GET_PACKET_TYPE(pPacket) == HCI_EVENT_TYPE) ? "EVENT" : "ACL", |
+ skb->len)); |
+ AR_DEBUG_PRINTBUF(skb->data, skb->len,"BT HCI RECV Packet Dump"); |
+ } |
+ |
+ if (pHcidevInfo->HciNormalMode) { |
+ /* indicate the packet */ |
+ if (bt_indicate_recv(pHcidevInfo,HCI_GET_PACKET_TYPE(pPacket),skb)) { |
+ /* bt stack accepted the packet */ |
+ skb = NULL; |
+ } |
+ break; |
+ } |
+ |
+ /* for testing, indicate packet to the network stack */ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+ skb->dev = (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice); |
+ if ((((struct net_device *)pHcidevInfo->HCITransHdl.netDevice)->flags & IFF_UP) == IFF_UP) { |
+ skb->protocol = eth_type_trans(skb, (struct net_device *)(pHcidevInfo->HCITransHdl.netDevice)); |
+#else |
+ skb->dev = pHcidevInfo->ar->arNetDev; |
+ if ((pHcidevInfo->ar->arNetDev->flags & IFF_UP) == IFF_UP) { |
+ skb->protocol = eth_type_trans(skb, pHcidevInfo->ar->arNetDev); |
+#endif |
+ netif_rx(skb); |
+ skb = NULL; |
+ } |
+ |
+ } while (FALSE); |
+ |
+ FreeHTCStruct(pHcidevInfo,pPacket); |
+ |
+ if (skb != NULL) { |
+ /* packet was not accepted, free it */ |
+ FreeBtOsBuf(pHcidevInfo,skb); |
+ } |
+ |
+} |
+ |
+static void ar6000_hci_pkt_refill(void *pContext, HCI_TRANSPORT_PACKET_TYPE Type, int BuffersAvailable) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; |
+ int refillCount; |
+ |
+ if (Type == HCI_ACL_TYPE) { |
+ refillCount = MAX_ACL_RECV_BUFS - BuffersAvailable; |
+ } else { |
+ refillCount = MAX_EVT_RECV_BUFS - BuffersAvailable; |
+ } |
+ |
+ if (refillCount > 0) { |
+ RefillRecvBuffers(pHcidevInfo,Type,refillCount); |
+ } |
+ |
+} |
+ |
+static HCI_SEND_FULL_ACTION ar6000_hci_pkt_send_full(void *pContext, HTC_PACKET *pPacket) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)pContext; |
+ HCI_SEND_FULL_ACTION action = HCI_SEND_FULL_KEEP; |
+ |
+ if (!pHcidevInfo->HciNormalMode) { |
+ /* for epping testing, check packet tag, some epping packets are |
+ * special and cannot be dropped */ |
+ if (HTC_GET_TAG_FROM_PKT(pPacket) == AR6K_DATA_PKT_TAG) { |
+ action = HCI_SEND_FULL_DROP; |
+ } |
+ } |
+ |
+ return action; |
+} |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+A_STATUS ar6000_setup_hci(void *ar) |
+#else |
+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; |
+} |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+void ar6000_cleanup_hci(void *ar) |
+#else |
+void ar6000_cleanup_hci(AR_SOFTC_T *ar) |
+#endif |
+{ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = g_pHcidevInfo; |
+#else |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)ar->hcidev_info; |
+#endif |
+ |
+ if (pHcidevInfo != NULL) { |
+ bt_cleanup_hci(pHcidevInfo); |
+ |
+ if (pHcidevInfo->pHCIDev != NULL) { |
+ HCI_TransportStop(pHcidevInfo->pHCIDev); |
+ HCI_TransportDetach(pHcidevInfo->pHCIDev); |
+ pHcidevInfo->pHCIDev = NULL; |
+ } |
+ |
+ if (pHcidevInfo->pHTCStructAlloc != NULL) { |
+ A_FREE(pHcidevInfo->pHTCStructAlloc); |
+ pHcidevInfo->pHTCStructAlloc = NULL; |
+ } |
+ |
+ A_FREE(pHcidevInfo); |
+#ifndef EXPORT_HCI_BRIDGE_INTERFACE |
+ ar->hcidev_info = NULL; |
+#endif |
+ } |
+ |
+ |
+} |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+A_STATUS hci_test_send(void *ar, struct sk_buff *skb) |
+#else |
+A_STATUS hci_test_send(AR_SOFTC_T *ar, struct sk_buff *skb) |
+#endif |
+{ |
+ int status = A_OK; |
+ int length; |
+ EPPING_HEADER *pHeader; |
+ HTC_PACKET *pPacket; |
+ HTC_TX_TAG htc_tag = AR6K_DATA_PKT_TAG; |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = g_pHcidevInfo; |
+#else |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)ar->hcidev_info; |
+#endif |
+ |
+ do { |
+ |
+ if (NULL == pHcidevInfo) { |
+ status = A_ERROR; |
+ break; |
+ } |
+ |
+ if (NULL == pHcidevInfo->pHCIDev) { |
+ status = A_ERROR; |
+ break; |
+ } |
+ |
+ if (pHcidevInfo->HciNormalMode) { |
+ /* this interface cannot run when normal WMI is running */ |
+ status = A_ERROR; |
+ break; |
+ } |
+ |
+ pHeader = (EPPING_HEADER *)A_NETBUF_DATA(skb); |
+ |
+ if (!IS_EPPING_PACKET(pHeader)) { |
+ status = A_EINVAL; |
+ break; |
+ } |
+ |
+ if (IS_EPING_PACKET_NO_DROP(pHeader)) { |
+ htc_tag = AR6K_CONTROL_PKT_TAG; |
+ } |
+ |
+ length = sizeof(EPPING_HEADER) + pHeader->DataLength; |
+ |
+ pPacket = AllocHTCStruct(pHcidevInfo); |
+ if (NULL == pPacket) { |
+ status = A_NO_MEMORY; |
+ break; |
+ } |
+ |
+ SET_HTC_PACKET_INFO_TX(pPacket, |
+ skb, |
+ A_NETBUF_DATA(skb), |
+ length, |
+ HCI_ACL_TYPE, /* send every thing out as ACL */ |
+ htc_tag); |
+ |
+ HCI_TransportSendPkt(pHcidevInfo->pHCIDev,pPacket,FALSE); |
+ pPacket = NULL; |
+ |
+ } while (FALSE); |
+ |
+ return status; |
+} |
+ |
+void ar6000_set_default_ar3kconfig(AR_SOFTC_T *ar, void *ar3kconfig) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)ar->hcidev_info; |
+ AR3K_CONFIG_INFO *config = (AR3K_CONFIG_INFO *)ar3kconfig; |
+ |
+ config->pHCIDev = pHcidevInfo->pHCIDev; |
+ config->pHCIProps = &pHcidevInfo->HCIProps; |
+ config->pHIFDevice = ar->arHifDevice; |
+ config->pBtStackHCIDev = pHcidevInfo->pBtStackHCIDev; |
+ config->Flags |= AR3K_CONFIG_FLAG_SET_AR3K_BAUD; |
+ config->AR3KBaudRate = 115200; |
+} |
+ |
+#ifdef CONFIG_BLUEZ_HCI_BRIDGE |
+/*** BT Stack Entrypoints *******/ |
+ |
+/* |
+ * bt_open - open a handle to the device |
+*/ |
+static int bt_open(struct hci_dev *hdev) |
+{ |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_open - enter - x\n")); |
+ set_bit(HCI_RUNNING, &hdev->flags); |
+ set_bit(HCI_UP, &hdev->flags); |
+ set_bit(HCI_INIT, &hdev->flags); |
+ return 0; |
+} |
+ |
+/* |
+ * bt_close - close handle to the device |
+*/ |
+static int bt_close(struct hci_dev *hdev) |
+{ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_close - enter\n")); |
+ clear_bit(HCI_RUNNING, &hdev->flags); |
+ return 0; |
+} |
+ |
+/* |
+ * bt_send_frame - send data frames |
+*/ |
+static int bt_send_frame(struct sk_buff *skb) |
+{ |
+ struct hci_dev *hdev = (struct hci_dev *)skb->dev; |
+ HCI_TRANSPORT_PACKET_TYPE type; |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo; |
+ A_UINT8 *pTemp; |
+ HTC_PACKET *pPacket; |
+ A_STATUS status = A_OK; |
+ struct sk_buff *txSkb = NULL; |
+ |
+ if (!hdev) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HCI Bridge: bt_send_frame - no device\n")); |
+ return -ENODEV; |
+ } |
+ |
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_send_frame - not open\n")); |
+ return -EBUSY; |
+ } |
+ |
+ pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)hdev->driver_data; |
+ A_ASSERT(pHcidevInfo != NULL); |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("+bt_send_frame type: %d \n",bt_cb(skb)->pkt_type)); |
+ type = HCI_COMMAND_TYPE; |
+ |
+ switch (bt_cb(skb)->pkt_type) { |
+ case HCI_COMMAND_PKT: |
+ type = HCI_COMMAND_TYPE; |
+ hdev->stat.cmd_tx++; |
+ break; |
+ |
+ case HCI_ACLDATA_PKT: |
+ type = HCI_ACL_TYPE; |
+ hdev->stat.acl_tx++; |
+ break; |
+ |
+ case HCI_SCODATA_PKT: |
+ /* we don't support SCO over the bridge */ |
+ kfree_skb(skb); |
+ return 0; |
+ default: |
+ A_ASSERT(FALSE); |
+ kfree_skb(skb); |
+ return 0; |
+ } |
+ |
+ if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(">>> Send HCI %s packet len: %d\n", |
+ (type == HCI_COMMAND_TYPE) ? "COMMAND" : "ACL", |
+ skb->len)); |
+ if (type == HCI_COMMAND_TYPE) { |
+ A_UINT16 opcode = HCI_GET_OP_CODE(skb->data); |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(" HCI Command: OGF:0x%X OCF:0x%X \r\n", |
+ opcode >> 10, opcode & 0x3FF)); |
+ } |
+ AR_DEBUG_PRINTBUF(skb->data,skb->len,"BT HCI SEND Packet Dump"); |
+ } |
+ |
+ do { |
+ |
+ txSkb = bt_skb_alloc(TX_PACKET_RSV_OFFSET + pHcidevInfo->HCIProps.HeadRoom + |
+ pHcidevInfo->HCIProps.TailRoom + skb->len, |
+ GFP_ATOMIC); |
+ |
+ if (txSkb == NULL) { |
+ status = A_NO_MEMORY; |
+ break; |
+ } |
+ |
+ bt_cb(txSkb)->pkt_type = bt_cb(skb)->pkt_type; |
+ txSkb->dev = (void *)pHcidevInfo->pBtStackHCIDev; |
+ skb_reserve(txSkb, TX_PACKET_RSV_OFFSET + pHcidevInfo->HCIProps.HeadRoom); |
+ A_MEMCPY(txSkb->data, skb->data, skb->len); |
+ skb_put(txSkb,skb->len); |
+ |
+ /* push on header transport space */ |
+ pTemp = (A_UINT8 *)skb_push(txSkb, pHcidevInfo->HCIProps.HeadRoom); |
+ pPacket = AllocHTCStruct(pHcidevInfo); |
+ if (NULL == pPacket) { |
+ status = A_NO_MEMORY; |
+ break; |
+ } |
+ |
+ SET_HTC_PACKET_INFO_TX(pPacket, |
+ txSkb, |
+ pTemp + pHcidevInfo->HCIProps.HeadRoom, |
+ txSkb->len, |
+ type, |
+ AR6K_CONTROL_PKT_TAG); /* HCI packets cannot be dropped */ |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("HCI Bridge: bt_send_frame skb:0x%X \n",(A_UINT32)txSkb)); |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("HCI Bridge: type:%d, Total Length:%d Bytes \n", |
+ type, txSkb->len)); |
+ |
+ status = HCI_TransportSendPkt(pHcidevInfo->pHCIDev,pPacket,FALSE); |
+ pPacket = NULL; |
+ txSkb = NULL; |
+ |
+ } while (FALSE); |
+ |
+ if (txSkb != NULL) { |
+ kfree_skb(txSkb); |
+ } |
+ |
+ kfree_skb(skb); |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_SEND, ("-bt_send_frame \n")); |
+ return 0; |
+} |
+ |
+/* |
+ * bt_ioctl - ioctl processing |
+*/ |
+static int bt_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) |
+{ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_ioctl - enter\n")); |
+ return -ENOIOCTLCMD; |
+} |
+ |
+/* |
+ * bt_flush - flush outstandingbpackets |
+*/ |
+static int bt_flush(struct hci_dev *hdev) |
+{ |
+ AR6K_HCI_BRIDGE_INFO *pHcidevInfo; |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_flush - enter\n")); |
+ |
+ pHcidevInfo = (AR6K_HCI_BRIDGE_INFO *)hdev->driver_data; |
+ |
+ /* TODO??? */ |
+ |
+ return 0; |
+} |
+ |
+ |
+/* |
+ * bt_destruct - |
+*/ |
+static void bt_destruct(struct hci_dev *hdev) |
+{ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HCI Bridge: bt_destruct - enter\n")); |
+ /* nothing to do here */ |
+} |
+ |
+static A_STATUS bt_setup_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) |
+{ |
+ A_STATUS status = A_OK; |
+ struct hci_dev *pHciDev = NULL; |
+ HIF_DEVICE_OS_DEVICE_INFO osDevInfo; |
+ |
+ if (!setupbtdev) { |
+ return A_OK; |
+ } |
+ |
+ do { |
+ |
+ A_MEMZERO(&osDevInfo,sizeof(osDevInfo)); |
+ /* get the underlying OS device */ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+ status = ar6000_get_hif_dev((HIF_DEVICE *)(pHcidevInfo->HCITransHdl.hifDevice), |
+ &osDevInfo); |
+#else |
+ status = HIFConfigureDevice(pHcidevInfo->ar->arHifDevice, |
+ HIF_DEVICE_GET_OS_DEVICE, |
+ &osDevInfo, |
+ sizeof(osDevInfo)); |
+#endif |
+ |
+ if (A_FAILED(status)) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to OS device info from HIF\n")); |
+ break; |
+ } |
+ |
+ /* allocate a BT HCI struct for this device */ |
+ pHciDev = hci_alloc_dev(); |
+ if (NULL == pHciDev) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge - failed to allocate bt struct \n")); |
+ status = A_NO_MEMORY; |
+ break; |
+ } |
+ /* save the device, we'll register this later */ |
+ pHcidevInfo->pBtStackHCIDev = pHciDev; |
+ SET_HCIDEV_DEV(pHciDev,osDevInfo.pOSDevice); |
+ pHciDev->type = HCI_VIRTUAL; |
+ pHciDev->driver_data = pHcidevInfo; |
+ pHciDev->open = bt_open; |
+ pHciDev->close = bt_close; |
+ pHciDev->send = bt_send_frame; |
+ pHciDev->ioctl = bt_ioctl; |
+ pHciDev->flush = bt_flush; |
+ pHciDev->destruct = bt_destruct; |
+ pHciDev->owner = THIS_MODULE; |
+ /* driver is running in normal BT mode */ |
+ pHcidevInfo->HciNormalMode = TRUE; |
+ |
+ } while (FALSE); |
+ |
+ if (A_FAILED(status)) { |
+ bt_cleanup_hci(pHcidevInfo); |
+ } |
+ |
+ return status; |
+} |
+ |
+static void bt_cleanup_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) |
+{ |
+ int err; |
+ |
+ if (pHcidevInfo->HciRegistered) { |
+ pHcidevInfo->HciRegistered = FALSE; |
+ clear_bit(HCI_RUNNING, &pHcidevInfo->pBtStackHCIDev->flags); |
+ clear_bit(HCI_UP, &pHcidevInfo->pBtStackHCIDev->flags); |
+ clear_bit(HCI_INIT, &pHcidevInfo->pBtStackHCIDev->flags); |
+ A_ASSERT(pHcidevInfo->pBtStackHCIDev != NULL); |
+ /* unregister */ |
+ if ((err = hci_unregister_dev(pHcidevInfo->pBtStackHCIDev)) < 0) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to unregister with bluetooth %d\n",err)); |
+ } |
+ } |
+ |
+ if (pHcidevInfo->pBtStackHCIDev != NULL) { |
+ kfree(pHcidevInfo->pBtStackHCIDev); |
+ pHcidevInfo->pBtStackHCIDev = NULL; |
+ } |
+} |
+ |
+static A_STATUS bt_register_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) |
+{ |
+ int err; |
+ A_STATUS status = A_OK; |
+ |
+ do { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: registering HCI... \n")); |
+ A_ASSERT(pHcidevInfo->pBtStackHCIDev != NULL); |
+ /* mark that we are registered */ |
+ pHcidevInfo->HciRegistered = TRUE; |
+ if ((err = hci_register_dev(pHcidevInfo->pBtStackHCIDev)) < 0) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: failed to register with bluetooth %d\n",err)); |
+ pHcidevInfo->HciRegistered = FALSE; |
+ status = A_ERROR; |
+ break; |
+ } |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_BRIDGE, ("HCI Bridge: HCI registered \n")); |
+ |
+ } while (FALSE); |
+ |
+ return status; |
+} |
+ |
+static A_BOOL bt_indicate_recv(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, |
+ HCI_TRANSPORT_PACKET_TYPE Type, |
+ struct sk_buff *skb) |
+{ |
+ A_UINT8 btType; |
+ int len; |
+ A_BOOL success = FALSE; |
+ BT_HCI_EVENT_HEADER *pEvent; |
+ |
+ do { |
+ |
+ if (!test_bit(HCI_RUNNING, &pHcidevInfo->pBtStackHCIDev->flags)) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HCI Bridge: bt_indicate_recv - not running\n")); |
+ break; |
+ } |
+ |
+ switch (Type) { |
+ case HCI_ACL_TYPE: |
+ btType = HCI_ACLDATA_PKT; |
+ break; |
+ case HCI_EVENT_TYPE: |
+ btType = HCI_EVENT_PKT; |
+ break; |
+ default: |
+ btType = 0; |
+ A_ASSERT(FALSE); |
+ break; |
+ } |
+ |
+ if (0 == btType) { |
+ break; |
+ } |
+ |
+ /* set the final type */ |
+ bt_cb(skb)->pkt_type = btType; |
+ /* set dev */ |
+ skb->dev = (void *)pHcidevInfo->pBtStackHCIDev; |
+ len = skb->len; |
+ |
+ if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_RECV)) { |
+ if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) { |
+ pEvent = (BT_HCI_EVENT_HEADER *)skb->data; |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_RECV, ("BT HCI EventCode: %d, len:%d \n", |
+ pEvent->EventCode, pEvent->ParamLength)); |
+ } |
+ } |
+ |
+ /* pass receive packet up the stack */ |
+ if (hci_recv_frame(skb) != 0) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HCI Bridge: hci_recv_frame failed \n")); |
+ break; |
+ } else { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_HCI_RECV, |
+ ("HCI Bridge: Indicated RCV of type:%d, Length:%d \n",btType,len)); |
+ } |
+ |
+ success = TRUE; |
+ |
+ } while (FALSE); |
+ |
+ return success; |
+} |
+ |
+static struct sk_buff* bt_alloc_buffer(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, int Length) |
+{ |
+ struct sk_buff *skb; |
+ /* in normal HCI mode we need to alloc from the bt core APIs */ |
+ skb = bt_skb_alloc(Length, GFP_ATOMIC); |
+ if (NULL == skb) { |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc bt sk_buff \n")); |
+ } |
+ return skb; |
+} |
+ |
+static void bt_free_buffer(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, struct sk_buff *skb) |
+{ |
+ kfree_skb(skb); |
+} |
+ |
+#else // { CONFIG_BLUEZ_HCI_BRIDGE |
+ |
+ /* stubs when we only want to test the HCI bridging Interface without the HT stack */ |
+static A_STATUS bt_setup_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) |
+{ |
+ return A_OK; |
+} |
+static void bt_cleanup_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) |
+{ |
+ |
+} |
+static A_STATUS bt_register_hci(AR6K_HCI_BRIDGE_INFO *pHcidevInfo) |
+{ |
+ A_ASSERT(FALSE); |
+ return A_ERROR; |
+} |
+ |
+static A_BOOL bt_indicate_recv(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, |
+ HCI_TRANSPORT_PACKET_TYPE Type, |
+ struct sk_buff *skb) |
+{ |
+ A_ASSERT(FALSE); |
+ return FALSE; |
+} |
+ |
+static struct sk_buff* bt_alloc_buffer(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, int Length) |
+{ |
+ A_ASSERT(FALSE); |
+ return NULL; |
+} |
+static void bt_free_buffer(AR6K_HCI_BRIDGE_INFO *pHcidevInfo, struct sk_buff *skb) |
+{ |
+ A_ASSERT(FALSE); |
+} |
+ |
+#endif // } CONFIG_BLUEZ_HCI_BRIDGE |
+ |
+#else // { ATH_AR6K_ENABLE_GMBOX |
+ |
+ /* stubs when GMBOX support is not needed */ |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+A_STATUS ar6000_setup_hci(void *ar) |
+#else |
+A_STATUS ar6000_setup_hci(AR_SOFTC_T *ar) |
+#endif |
+{ |
+ return A_OK; |
+} |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+void ar6000_cleanup_hci(void *ar) |
+#else |
+void ar6000_cleanup_hci(AR_SOFTC_T *ar) |
+#endif |
+{ |
+ return; |
+} |
+ |
+#ifndef EXPORT_HCI_BRIDGE_INTERFACE |
+void ar6000_set_default_ar3kconfig(AR_SOFTC_T *ar, void *ar3kconfig) |
+{ |
+ return; |
+} |
+#endif |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+int hci_test_send(void *ar, struct sk_buff *skb) |
+#else |
+int hci_test_send(AR_SOFTC_T *ar, struct sk_buff *skb) |
+#endif |
+{ |
+ return -EOPNOTSUPP; |
+} |
+ |
+#endif // } ATH_AR6K_ENABLE_GMBOX |
+ |
+ |
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE |
+static int __init |
+hcibridge_init_module(void) |
+{ |
+ A_STATUS status; |
+ HCI_TRANSPORT_CALLBACKS hciTransCallbacks; |
+ |
+ hciTransCallbacks.setupTransport = ar6000_setup_hci; |
+ hciTransCallbacks.cleanupTransport = ar6000_cleanup_hci; |
+ |
+ status = ar6000_register_hci_transport(&hciTransCallbacks); |
+ if(status != A_OK) |
+ return -ENODEV; |
+ |
+ return 0; |
+} |
+ |
+static void __exit |
+hcibridge_cleanup_module(void) |
+{ |
+} |
+ |
+module_init(hcibridge_init_module); |
+module_exit(hcibridge_cleanup_module); |
+MODULE_LICENSE("GPL and additional rights"); |
+#endif |