|
@@ -1,479 +0,0 @@
|
|
|
-//------------------------------------------------------------------------------
|
|
|
-// Copyright (c) 2004-2010 Atheros Communications Inc.
|
|
|
-// 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.
|
|
|
-//
|
|
|
-//
|
|
|
-//
|
|
|
-// Author(s): ="Atheros"
|
|
|
-//------------------------------------------------------------------------------
|
|
|
-
|
|
|
-#include "ar6000_drv.h"
|
|
|
-#ifdef AR6K_ENABLE_HCI_PAL
|
|
|
-#include <net/bluetooth/bluetooth.h>
|
|
|
-#include <net/bluetooth/hci_core.h>
|
|
|
-#include <ar6k_pal.h>
|
|
|
-
|
|
|
-extern unsigned int setupbtdev;
|
|
|
-#define bt_check_bit(val, bit) (val & bit)
|
|
|
-#define bt_set_bit(val, bit) (val |= bit)
|
|
|
-#define bt_clear_bit(val, bit) (val &= ~bit)
|
|
|
-
|
|
|
-/* export ATH_AR6K_DEBUG_HCI_PAL=yes in host/localmake.linux.inc
|
|
|
- * to enable debug information */
|
|
|
-#ifdef HCIPAL_DEBUG
|
|
|
-#define PRIN_LOG(format, args...) printk(KERN_ALERT "%s:%d - %s Msg:" format "\n",__FUNCTION__, __LINE__, __FILE__, ## args)
|
|
|
-#else
|
|
|
-#define PRIN_LOG(format, args...)
|
|
|
-#endif
|
|
|
-
|
|
|
-/**********************************
|
|
|
- * HCI PAL private info structure
|
|
|
- *********************************/
|
|
|
-typedef struct ar6k_hci_pal_info_s{
|
|
|
-
|
|
|
- unsigned long ulFlags;
|
|
|
-#define HCI_NORMAL_MODE (1)
|
|
|
-#define HCI_REGISTERED (1<<1)
|
|
|
- struct hci_dev *hdev; /* BT Stack HCI dev */
|
|
|
- struct ar6_softc *ar;
|
|
|
-
|
|
|
-}ar6k_hci_pal_info_t;
|
|
|
-
|
|
|
-/*** BT Stack Entrypoints *******/
|
|
|
-/***************************************
|
|
|
- * bt_open - open a handle to the device
|
|
|
- ***************************************/
|
|
|
-static int bt_open(struct hci_dev *hdev)
|
|
|
-{
|
|
|
- PRIN_LOG("HCI PAL: 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)
|
|
|
-{
|
|
|
- PRIN_LOG("HCI PAL: bt_close - enter\n");
|
|
|
- clear_bit(HCI_RUNNING, &hdev->flags);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*****************************
|
|
|
- * bt_ioctl - ioctl processing
|
|
|
- *****************************/
|
|
|
-static int bt_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
|
|
|
-{
|
|
|
- PRIN_LOG("HCI PAL: bt_ioctl - enter\n");
|
|
|
- return -ENOIOCTLCMD;
|
|
|
-}
|
|
|
-
|
|
|
-/**************************************
|
|
|
- * bt_flush - flush outstanding packets
|
|
|
- **************************************/
|
|
|
-static int bt_flush(struct hci_dev *hdev)
|
|
|
-{
|
|
|
- PRIN_LOG("HCI PAL: bt_flush - enter\n");
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/***************
|
|
|
- * bt_destruct
|
|
|
- ***************/
|
|
|
-static void bt_destruct(struct hci_dev *hdev)
|
|
|
-{
|
|
|
- PRIN_LOG("HCI PAL: bt_destruct - enter\n");
|
|
|
- /* nothing to do here */
|
|
|
-}
|
|
|
-
|
|
|
-/****************************************************
|
|
|
- * Invoked from bluetooth stack via hdev->send()
|
|
|
- * to send the packet out via ar6k to PAL firmware.
|
|
|
- *
|
|
|
- * For HCI command packet wmi_send_hci_cmd() is invoked.
|
|
|
- * wmi_send_hci_cmd adds WMI_CMD_HDR and sends the packet
|
|
|
- * to PAL firmware.
|
|
|
- *
|
|
|
- * For HCI ACL data packet wmi_data_hdr_add is invoked
|
|
|
- * to add WMI_DATA_HDR to the packet. ar6000_acl_data_tx
|
|
|
- * is then invoked to send the packet to PAL firmware.
|
|
|
- ******************************************************/
|
|
|
-static int btpal_send_frame(struct sk_buff *skb)
|
|
|
-{
|
|
|
- struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
|
|
- HCI_TRANSPORT_PACKET_TYPE type;
|
|
|
- ar6k_hci_pal_info_t *pHciPalInfo;
|
|
|
- int status = 0;
|
|
|
- struct sk_buff *txSkb = NULL;
|
|
|
- struct ar6_softc *ar;
|
|
|
-
|
|
|
- if (!hdev) {
|
|
|
- PRIN_LOG("HCI PAL: btpal_send_frame - no device\n");
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
-
|
|
|
- if (!test_bit(HCI_RUNNING, &hdev->flags)) {
|
|
|
- PRIN_LOG("HCI PAL: btpal_send_frame - not open\n");
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- pHciPalInfo = (ar6k_hci_pal_info_t *)hdev->driver_data;
|
|
|
- A_ASSERT(pHciPalInfo != NULL);
|
|
|
- ar = pHciPalInfo->ar;
|
|
|
-
|
|
|
- PRIN_LOG("+btpal_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 pal */
|
|
|
- kfree_skb(skb);
|
|
|
- return 0;
|
|
|
- default:
|
|
|
- A_ASSERT(false);
|
|
|
- kfree_skb(skb);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_HCI_DUMP)) {
|
|
|
- A_PRINTF(">>> Send HCI %s packet len: %d\n",
|
|
|
- (type == HCI_COMMAND_TYPE) ? "COMMAND" : "ACL",
|
|
|
- skb->len);
|
|
|
- if (type == HCI_COMMAND_TYPE) {
|
|
|
- PRIN_LOG(" HCI Command: OGF:0x%X OCF:0x%X \r\n",
|
|
|
- HCI_GET_OP_CODE(skb-data) >> 10, HCI_GET_OP_CODE(skb-data) & 0x3FF);
|
|
|
- }
|
|
|
- AR_DEBUG_PRINTBUF(skb->data,skb->len,"BT HCI SEND Packet Dump");
|
|
|
- }
|
|
|
-
|
|
|
- do {
|
|
|
- if(type == HCI_COMMAND_TYPE)
|
|
|
- {
|
|
|
- PRIN_LOG("HCI command");
|
|
|
-
|
|
|
- if (ar->arWmiReady == false)
|
|
|
- {
|
|
|
- PRIN_LOG("WMI not ready ");
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (wmi_send_hci_cmd(ar->arWmi, skb->data, skb->len) != 0)
|
|
|
- {
|
|
|
- PRIN_LOG("send hci cmd error");
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- else if(type == HCI_ACL_TYPE)
|
|
|
- {
|
|
|
- void *osbuf;
|
|
|
-
|
|
|
- PRIN_LOG("ACL data");
|
|
|
- if (ar->arWmiReady == false)
|
|
|
- {
|
|
|
- PRIN_LOG("WMI not ready");
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* need to add WMI header so allocate a skb with more space */
|
|
|
- txSkb = bt_skb_alloc(TX_PACKET_RSV_OFFSET + WMI_MAX_TX_META_SZ +
|
|
|
- sizeof(WMI_DATA_HDR) + skb->len,
|
|
|
- GFP_ATOMIC);
|
|
|
-
|
|
|
- if (txSkb == NULL) {
|
|
|
- status = A_NO_MEMORY;
|
|
|
- PRIN_LOG("No memory");
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- bt_cb(txSkb)->pkt_type = bt_cb(skb)->pkt_type;
|
|
|
- txSkb->dev = (void *)pHciPalInfo->hdev;
|
|
|
- skb_reserve(txSkb, TX_PACKET_RSV_OFFSET + WMI_MAX_TX_META_SZ + sizeof(WMI_DATA_HDR));
|
|
|
- memcpy(txSkb->data, skb->data, skb->len);
|
|
|
- skb_put(txSkb,skb->len);
|
|
|
- /* Add WMI packet type */
|
|
|
- osbuf = (void *)txSkb;
|
|
|
-
|
|
|
- if (wmi_data_hdr_add(ar->arWmi, osbuf, DATA_MSGTYPE, 0, WMI_DATA_HDR_DATA_TYPE_ACL,0,NULL) != 0) {
|
|
|
- PRIN_LOG("XIOCTL_ACL_DATA - wmi_data_hdr_add failed\n");
|
|
|
- } else {
|
|
|
- /* Send data buffer over HTC */
|
|
|
- PRIN_LOG("acl data tx");
|
|
|
- ar6000_acl_data_tx(osbuf, ar->arNetDev);
|
|
|
- }
|
|
|
- txSkb = NULL;
|
|
|
- }
|
|
|
- } while (false);
|
|
|
-
|
|
|
- if (txSkb != NULL) {
|
|
|
- PRIN_LOG("Free skb");
|
|
|
- kfree_skb(txSkb);
|
|
|
- }
|
|
|
- kfree_skb(skb);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/***********************************************
|
|
|
- * Unregister HCI device and free HCI device info
|
|
|
- ***********************************************/
|
|
|
-static void bt_cleanup_hci_pal(ar6k_hci_pal_info_t *pHciPalInfo)
|
|
|
-{
|
|
|
- int err;
|
|
|
-
|
|
|
- if (bt_check_bit(pHciPalInfo->ulFlags, HCI_REGISTERED)) {
|
|
|
- bt_clear_bit(pHciPalInfo->ulFlags, HCI_REGISTERED);
|
|
|
- clear_bit(HCI_RUNNING, &pHciPalInfo->hdev->flags);
|
|
|
- clear_bit(HCI_UP, &pHciPalInfo->hdev->flags);
|
|
|
- clear_bit(HCI_INIT, &pHciPalInfo->hdev->flags);
|
|
|
- A_ASSERT(pHciPalInfo->hdev != NULL);
|
|
|
- /* unregister */
|
|
|
- PRIN_LOG("Unregister PAL device");
|
|
|
- if ((err = hci_unregister_dev(pHciPalInfo->hdev)) < 0) {
|
|
|
- PRIN_LOG("HCI PAL: failed to unregister with bluetooth %d\n",err);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- kfree(pHciPalInfo->hdev);
|
|
|
- pHciPalInfo->hdev = NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/*********************************************************
|
|
|
- * Allocate HCI device and store in PAL private info structure.
|
|
|
- *********************************************************/
|
|
|
-static int bt_setup_hci_pal(ar6k_hci_pal_info_t *pHciPalInfo)
|
|
|
-{
|
|
|
- int status = 0;
|
|
|
- struct hci_dev *pHciDev = NULL;
|
|
|
-
|
|
|
- if (!setupbtdev) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- do {
|
|
|
- /* allocate a BT HCI struct for this device */
|
|
|
- pHciDev = hci_alloc_dev();
|
|
|
- if (NULL == pHciDev) {
|
|
|
- PRIN_LOG("HCI PAL driver - failed to allocate BT HCI struct \n");
|
|
|
- status = A_NO_MEMORY;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* save the device, we'll register this later */
|
|
|
- pHciPalInfo->hdev = pHciDev;
|
|
|
- SET_HCI_BUS_TYPE(pHciDev, HCI_VIRTUAL, HCI_80211);
|
|
|
- pHciDev->driver_data = pHciPalInfo;
|
|
|
- pHciDev->open = bt_open;
|
|
|
- pHciDev->close = bt_close;
|
|
|
- pHciDev->send = btpal_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 */
|
|
|
- PRIN_LOG("Normal mode enabled");
|
|
|
- bt_set_bit(pHciPalInfo->ulFlags, HCI_NORMAL_MODE);
|
|
|
-
|
|
|
- } while (false);
|
|
|
-
|
|
|
- if (status) {
|
|
|
- bt_cleanup_hci_pal(pHciPalInfo);
|
|
|
- }
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/**********************************************
|
|
|
- * Cleanup HCI device and free HCI PAL private info
|
|
|
- *********************************************/
|
|
|
-void ar6k_cleanup_hci_pal(void *ar_p)
|
|
|
-{
|
|
|
- struct ar6_softc *ar = (struct ar6_softc *)ar_p;
|
|
|
- ar6k_hci_pal_info_t *pHciPalInfo = (ar6k_hci_pal_info_t *)ar->hcipal_info;
|
|
|
-
|
|
|
- if (pHciPalInfo != NULL) {
|
|
|
- bt_cleanup_hci_pal(pHciPalInfo);
|
|
|
- kfree(pHciPalInfo);
|
|
|
- ar->hcipal_info = NULL;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/****************************
|
|
|
- * Register HCI device
|
|
|
- ****************************/
|
|
|
-static bool ar6k_pal_transport_ready(void *pHciPal)
|
|
|
-{
|
|
|
- ar6k_hci_pal_info_t *pHciPalInfo = (ar6k_hci_pal_info_t *)pHciPal;
|
|
|
-
|
|
|
- PRIN_LOG("HCI device transport ready");
|
|
|
- if(pHciPalInfo == NULL)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (hci_register_dev(pHciPalInfo->hdev) < 0) {
|
|
|
- PRIN_LOG("Can't register HCI device");
|
|
|
- hci_free_dev(pHciPalInfo->hdev);
|
|
|
- return false;
|
|
|
- }
|
|
|
- PRIN_LOG("HCI device registered");
|
|
|
- pHciPalInfo->ulFlags |= HCI_REGISTERED;
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-/**************************************************
|
|
|
- * Called from ar6k driver when command or ACL data
|
|
|
- * packet is received. Pass the packet to bluetooth
|
|
|
- * stack via hci_recv_frame.
|
|
|
- **************************************************/
|
|
|
-bool ar6k_pal_recv_pkt(void *pHciPal, void *osbuf)
|
|
|
-{
|
|
|
- struct sk_buff *skb = (struct sk_buff *)osbuf;
|
|
|
- ar6k_hci_pal_info_t *pHciPalInfo;
|
|
|
- bool success = false;
|
|
|
- u8 btType = 0;
|
|
|
- pHciPalInfo = (ar6k_hci_pal_info_t *)pHciPal;
|
|
|
-
|
|
|
- do {
|
|
|
-
|
|
|
- /* if normal mode is not enabled pass on to the stack
|
|
|
- * by returning failure */
|
|
|
- if(!(pHciPalInfo->ulFlags & HCI_NORMAL_MODE))
|
|
|
- {
|
|
|
- PRIN_LOG("Normal mode not enabled");
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (!test_bit(HCI_RUNNING, &pHciPalInfo->hdev->flags)) {
|
|
|
- PRIN_LOG("HCI PAL: HCI - not running\n");
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if(*((short *)A_NETBUF_DATA(skb)) == WMI_ACL_DATA_EVENTID)
|
|
|
- btType = HCI_ACLDATA_PKT;
|
|
|
- else
|
|
|
- btType = HCI_EVENT_PKT;
|
|
|
- /* pull 4 bytes which contains WMI packet type */
|
|
|
- A_NETBUF_PULL(skb, sizeof(int));
|
|
|
- bt_cb(skb)->pkt_type = btType;
|
|
|
- skb->dev = (void *)pHciPalInfo->hdev;
|
|
|
-
|
|
|
- /* pass the received event packet up the stack */
|
|
|
- if (hci_recv_frame(skb) != 0) {
|
|
|
- PRIN_LOG("HCI PAL: hci_recv_frame failed \n");
|
|
|
- break;
|
|
|
- } else {
|
|
|
- PRIN_LOG("HCI PAL: Indicated RCV of type:%d, Length:%d \n",HCI_EVENT_PKT, skb->len);
|
|
|
- }
|
|
|
- PRIN_LOG("hci recv success");
|
|
|
- success = true;
|
|
|
- }while(false);
|
|
|
- return success;
|
|
|
-}
|
|
|
-
|
|
|
-/**********************************************************
|
|
|
- * HCI PAL init function called from ar6k when it is loaded..
|
|
|
- * Allocates PAL private info, stores the same in ar6k private info.
|
|
|
- * Registers a HCI device.
|
|
|
- * Registers packet receive callback function with ar6k
|
|
|
- **********************************************************/
|
|
|
-int ar6k_setup_hci_pal(void *ar_p)
|
|
|
-{
|
|
|
- int status = 0;
|
|
|
- ar6k_hci_pal_info_t *pHciPalInfo;
|
|
|
- ar6k_pal_config_t ar6k_pal_config;
|
|
|
- struct ar6_softc *ar = (struct ar6_softc *)ar_p;
|
|
|
-
|
|
|
- do {
|
|
|
-
|
|
|
- pHciPalInfo = (ar6k_hci_pal_info_t *)A_MALLOC(sizeof(ar6k_hci_pal_info_t));
|
|
|
-
|
|
|
- if (NULL == pHciPalInfo) {
|
|
|
- status = A_NO_MEMORY;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- A_MEMZERO(pHciPalInfo, sizeof(ar6k_hci_pal_info_t));
|
|
|
- ar->hcipal_info = pHciPalInfo;
|
|
|
- pHciPalInfo->ar = ar;
|
|
|
-
|
|
|
- status = bt_setup_hci_pal(pHciPalInfo);
|
|
|
- if (status) {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if(bt_check_bit(pHciPalInfo->ulFlags, HCI_NORMAL_MODE))
|
|
|
- PRIN_LOG("HCI PAL: running in normal mode... \n");
|
|
|
- else
|
|
|
- PRIN_LOG("HCI PAL: running in test mode... \n");
|
|
|
-
|
|
|
- ar6k_pal_config.fpar6k_pal_recv_pkt = ar6k_pal_recv_pkt;
|
|
|
- register_pal_cb(&ar6k_pal_config);
|
|
|
- ar6k_pal_transport_ready(ar->hcipal_info);
|
|
|
- } while (false);
|
|
|
-
|
|
|
- if (status) {
|
|
|
- ar6k_cleanup_hci_pal(ar);
|
|
|
- }
|
|
|
- return status;
|
|
|
-}
|
|
|
-#else /* AR6K_ENABLE_HCI_PAL */
|
|
|
-int ar6k_setup_hci_pal(void *ar_p)
|
|
|
-{
|
|
|
- return 0;
|
|
|
-}
|
|
|
-void ar6k_cleanup_hci_pal(void *ar_p)
|
|
|
-{
|
|
|
-}
|
|
|
-#endif /* AR6K_ENABLE_HCI_PAL */
|
|
|
-
|
|
|
-#ifdef EXPORT_HCI_PAL_INTERFACE
|
|
|
-/*****************************************************
|
|
|
- * Register init and callback function with ar6k
|
|
|
- * when PAL driver is a separate kernel module.
|
|
|
- ****************************************************/
|
|
|
-int ar6k_register_hci_pal(struct hci_transport_callbacks *hciTransCallbacks);
|
|
|
-static int __init pal_init_module(void)
|
|
|
-{
|
|
|
- struct hci_transport_callbacks hciTransCallbacks;
|
|
|
-
|
|
|
- hciTransCallbacks.setupTransport = ar6k_setup_hci_pal;
|
|
|
- hciTransCallbacks.cleanupTransport = ar6k_cleanup_hci_pal;
|
|
|
-
|
|
|
- if(ar6k_register_hci_pal(&hciTransCallbacks) != 0)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void __exit pal_cleanup_module(void)
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-module_init(pal_init_module);
|
|
|
-module_exit(pal_cleanup_module);
|
|
|
-MODULE_LICENSE("Dual BSD/GPL");
|
|
|
-#endif
|