| 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
|
|
|