| Index: chromeos/drivers/ath6kl/os/linux/ar6k_pal.c
|
| diff --git a/chromeos/drivers/ath6kl/os/linux/ar6k_pal.c b/chromeos/drivers/ath6kl/os/linux/ar6k_pal.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6c98a8817aed88107c5b9d687faa54f8cb48187d
|
| --- /dev/null
|
| +++ b/chromeos/drivers/ath6kl/os/linux/ar6k_pal.c
|
| @@ -0,0 +1,481 @@
|
| +//------------------------------------------------------------------------------
|
| +// 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 */
|
| + AR_SOFTC_T *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;
|
| + A_STATUS status = A_OK;
|
| + struct sk_buff *txSkb = NULL;
|
| + AR_SOFTC_T *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) != A_OK)
|
| + {
|
| + 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));
|
| + A_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) != A_OK) {
|
| + 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);
|
| + }
|
| + }
|
| +
|
| + if (pHciPalInfo->hdev != NULL) {
|
| + kfree(pHciPalInfo->hdev);
|
| + pHciPalInfo->hdev = NULL;
|
| + }
|
| +}
|
| +
|
| +/*********************************************************
|
| + * Allocate HCI device and store in PAL private info structure.
|
| + *********************************************************/
|
| +static A_STATUS bt_setup_hci_pal(ar6k_hci_pal_info_t *pHciPalInfo)
|
| +{
|
| + A_STATUS status = A_OK;
|
| + struct hci_dev *pHciDev = NULL;
|
| +
|
| + if (!setupbtdev) {
|
| + return A_OK;
|
| + }
|
| +
|
| + 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 (A_FAILED(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)
|
| +{
|
| + AR_SOFTC_T *ar = (AR_SOFTC_T *)ar_p;
|
| + ar6k_hci_pal_info_t *pHciPalInfo = (ar6k_hci_pal_info_t *)ar->hcipal_info;
|
| +
|
| + if (pHciPalInfo != NULL) {
|
| + bt_cleanup_hci_pal(pHciPalInfo);
|
| + A_FREE(pHciPalInfo);
|
| + ar->hcipal_info = NULL;
|
| + }
|
| +}
|
| +
|
| +/****************************
|
| + * Register HCI device
|
| + ****************************/
|
| +static A_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.
|
| + **************************************************/
|
| +A_BOOL ar6k_pal_recv_pkt(void *pHciPal, void *osbuf)
|
| +{
|
| + struct sk_buff *skb = (struct sk_buff *)osbuf;
|
| + ar6k_hci_pal_info_t *pHciPalInfo;
|
| + A_BOOL success = FALSE;
|
| + A_UINT8 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
|
| + **********************************************************/
|
| +A_STATUS ar6k_setup_hci_pal(void *ar_p)
|
| +{
|
| + A_STATUS status = A_OK;
|
| + ar6k_hci_pal_info_t *pHciPalInfo;
|
| + ar6k_pal_config_t ar6k_pal_config;
|
| + AR_SOFTC_T *ar = (AR_SOFTC_T *)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 (A_FAILED(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 (A_FAILED(status)) {
|
| + ar6k_cleanup_hci_pal(ar);
|
| + }
|
| + return status;
|
| +}
|
| +#else /* AR6K_ENABLE_HCI_PAL */
|
| +A_STATUS ar6k_setup_hci_pal(void *ar_p)
|
| +{
|
| + return A_OK;
|
| +}
|
| +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.
|
| + ****************************************************/
|
| +A_STATUS ar6k_register_hci_pal(HCI_TRANSPORT_CALLBACKS *hciTransCallbacks);
|
| +static int __init pal_init_module(void)
|
| +{
|
| + HCI_TRANSPORT_CALLBACKS hciTransCallbacks;
|
| +
|
| + hciTransCallbacks.setupTransport = ar6k_setup_hci_pal;
|
| + hciTransCallbacks.cleanupTransport = ar6k_cleanup_hci_pal;
|
| +
|
| + if(ar6k_register_hci_pal(&hciTransCallbacks) != A_OK)
|
| + 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
|
|
|