staging: add ath6kl driver for AR6003 chip
AR6003 is a single stream, SDIO based 802.11 chipset from
Atheros optimized for mobile and embedded devices. ath6kl is a
cfg80211 driver for AR6003 and supports both the station and
AP mode of operation.
Station mode supports 802.11 a/b/g/n with HT20 on 2.4/5GHz and
HT40 only on 5GHz. Some of the other features include WPA/WPA2,
WPS, WMM, WMM-PS, and BT coexistence. AP mode can be operated
only in b/g mode with support for a subset of features mentioned
above.
The driver supports cfg80211 but comes with its own set of
wext ioctls which have historically supported some of our
customers with features like BT 3.0 and AP mode of operation.
For further details, please refer to:
http://wireless.kernel.org/en/users/Drivers/ath6kl
The driver requires firmware that runs on the chip's network
processor. The majority of it is stored in ROM. The binaries
that are downloaded and executed from RAM are as follows:
1) Patch against the code in ROM for bug fixes and feature
enhancements.
2) Code to copy the data from the OTP region of the memory
into RAM.
3) Calibration file carrying board specific data.
The above files need to be present in the directory
'/lib/firmware/ath6k/AR6003/hw2.0/' for the driver to initialize
the chip upon enumeration. The files can be downloaded from the
link specified at the following location:
http://wireless.kernel.org/en/users/Drivers/ath6kl#Download
This driver is only provided in the interim while we work on
the mac80211 replacement, ath6k. Once the mac80211 driver
achieves feature parity with the ath6kl driver, the ath6kl will
be deprecated and removed from staging.
Signed-off-by: Vipin Mehta <vmehta@atheros.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/ath6kl/os/linux/hci_bridge.c b/drivers/staging/ath6kl/os/linux/hci_bridge.c
new file mode 100644
index 0000000..5cdc3b8
--- /dev/null
+++ b/drivers/staging/ath6kl/os/linux/hci_bridge.c
@@ -0,0 +1,1144 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2009-2010 Atheros Corporation. All rights reserved.
+//
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+//
+//------------------------------------------------------------------------------
+//==============================================================================
+// 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>
+
+ /* only build on newer kernels which have BT configured */
+#if defined(CONFIG_BT_MODULE) || defined(CONFIG_BT)
+#define CONFIG_BLUEZ_HCI_BRIDGE
+#endif
+
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE
+unsigned int ar3khcibaud = 0;
+unsigned int hciuartscale = 0;
+unsigned int hciuartstep = 0;
+
+module_param(ar3khcibaud, int, 0644);
+module_param(hciuartscale, int, 0644);
+module_param(hciuartstep, int, 0644);
+#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;
+AR3K_CONFIG_INFO ar3kconfig;
+
+#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);
+ }
+}
+
+#define HOST_INTEREST_ITEM_ADDRESS(ar, item) \
+ (((ar)->arTargetType == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \
+ (((ar)->arTargetType == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : 0))
+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;
+ A_UINT32 address, hci_uart_pwr_mgmt_params;
+// 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%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 (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;
+ }
+
+ /* 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 (A_OK == 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 (A_FAILED(status)) {
+ break;
+ }
+
+ /* Make sure both AR6K and AR3K have power management enabled */
+ if (ar3kconfig.PwrMgmtEnabled) {
+ 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;
+}
+
+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;
+ 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);
+
+ pPacket = AllocHTCStruct(pHcidevInfo);
+ if (NULL == pPacket) {
+ status = A_NO_MEMORY;
+ break;
+ }
+
+ /* HCI packet length here doesn't include the 1-byte transport header which
+ * will be handled by the HCI transport layer. Enough headroom has already
+ * been reserved above for the transport header
+ */
+ SET_HTC_PACKET_INFO_TX(pPacket,
+ txSkb,
+ txSkb->data,
+ 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%lX \n",(unsigned long)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);
+ SET_HCI_BUS_TYPE(pHciDev, HCI_VIRTUAL, HCI_BREDR);
+ 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("Dual BSD/GPL");
+#endif