summaryrefslogtreecommitdiff
path: root/drivers/staging/ath6kl/miscdrv
diff options
context:
space:
mode:
authorVipin Mehta <vmehta@atheros.com>2010-09-01 12:06:33 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-09-02 11:43:26 -0700
commit30295c8936f3a426985e99bebb17d72bd7847910 (patch)
tree28ff0c23bfa931b73a35e7b11df1bf104260c6fa /drivers/staging/ath6kl/miscdrv
parent9b9913d80b2896ecd9e0a1a8f167ccad66fac79c (diff)
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>
Diffstat (limited to 'drivers/staging/ath6kl/miscdrv')
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kconfig.c566
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c572
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h79
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c980
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h127
-rw-r--r--drivers/staging/ath6kl/miscdrv/common_drv.c1027
-rw-r--r--drivers/staging/ath6kl/miscdrv/credit_dist.c418
-rw-r--r--drivers/staging/ath6kl/miscdrv/miscdrv.h42
8 files changed, 3811 insertions, 0 deletions
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kconfig.c
new file mode 100644
index 000000000000..83bc5be3ef1b
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/ar3kconfig.c
@@ -0,0 +1,566 @@
+//------------------------------------------------------------------------------
+// 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.
+//
+//
+//------------------------------------------------------------------------------
+//==============================================================================
+// AR3K configuration implementation
+//
+// Author(s): ="Atheros"
+//==============================================================================
+
+#include "a_config.h"
+#include "athdefs.h"
+#include "a_types.h"
+#include "a_osapi.h"
+#define ATH_MODULE_NAME misc
+#include "a_debug.h"
+#include "common_drv.h"
+#ifdef EXPORT_HCI_BRIDGE_INTERFACE
+#include "export_hci_transport.h"
+#else
+#include "hci_transport_api.h"
+#endif
+#include "ar3kconfig.h"
+#include "tlpm.h"
+
+#define BAUD_CHANGE_COMMAND_STATUS_OFFSET 5
+#define HCI_EVENT_RESP_TIMEOUTMS 3000
+#define HCI_CMD_OPCODE_BYTE_LOW_OFFSET 0
+#define HCI_CMD_OPCODE_BYTE_HI_OFFSET 1
+#define HCI_EVENT_OPCODE_BYTE_LOW 3
+#define HCI_EVENT_OPCODE_BYTE_HI 4
+#define HCI_CMD_COMPLETE_EVENT_CODE 0xE
+#define HCI_MAX_EVT_RECV_LENGTH 257
+#define EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET 5
+
+A_STATUS AthPSInitialize(AR3K_CONFIG_INFO *hdev);
+
+static A_STATUS SendHCICommand(AR3K_CONFIG_INFO *pConfig,
+ A_UINT8 *pBuffer,
+ int Length)
+{
+ HTC_PACKET *pPacket = NULL;
+ A_STATUS status = A_OK;
+
+ do {
+
+ pPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET));
+ if (NULL == pPacket) {
+ status = A_NO_MEMORY;
+ break;
+ }
+
+ A_MEMZERO(pPacket,sizeof(HTC_PACKET));
+ SET_HTC_PACKET_INFO_TX(pPacket,
+ NULL,
+ pBuffer,
+ Length,
+ HCI_COMMAND_TYPE,
+ AR6K_CONTROL_PKT_TAG);
+
+ /* issue synchronously */
+ status = HCI_TransportSendPkt(pConfig->pHCIDev,pPacket,TRUE);
+
+ } while (FALSE);
+
+ if (pPacket != NULL) {
+ A_FREE(pPacket);
+ }
+
+ return status;
+}
+
+static A_STATUS RecvHCIEvent(AR3K_CONFIG_INFO *pConfig,
+ A_UINT8 *pBuffer,
+ int *pLength)
+{
+ A_STATUS status = A_OK;
+ HTC_PACKET *pRecvPacket = NULL;
+
+ do {
+
+ pRecvPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET));
+ if (NULL == pRecvPacket) {
+ status = A_NO_MEMORY;
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n"));
+ break;
+ }
+
+ A_MEMZERO(pRecvPacket,sizeof(HTC_PACKET));
+
+ SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket,NULL,pBuffer,*pLength,HCI_EVENT_TYPE);
+
+ status = HCI_TransportRecvHCIEventSync(pConfig->pHCIDev,
+ pRecvPacket,
+ HCI_EVENT_RESP_TIMEOUTMS);
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ *pLength = pRecvPacket->ActualLength;
+
+ } while (FALSE);
+
+ if (pRecvPacket != NULL) {
+ A_FREE(pRecvPacket);
+ }
+
+ return status;
+}
+
+A_STATUS SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig,
+ A_UINT8 *pHCICommand,
+ int CmdLength,
+ A_UINT8 **ppEventBuffer,
+ A_UINT8 **ppBufferToFree)
+{
+ A_STATUS status = A_OK;
+ A_UINT8 *pBuffer = NULL;
+ A_UINT8 *pTemp;
+ int length;
+ A_BOOL commandComplete = FALSE;
+ A_UINT8 opCodeBytes[2];
+
+ do {
+
+ length = max(HCI_MAX_EVT_RECV_LENGTH,CmdLength);
+ length += pConfig->pHCIProps->HeadRoom + pConfig->pHCIProps->TailRoom;
+ length += pConfig->pHCIProps->IOBlockPad;
+
+ pBuffer = (A_UINT8 *)A_MALLOC(length);
+ if (NULL == pBuffer) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to allocate bt buffer \n"));
+ status = A_NO_MEMORY;
+ break;
+ }
+
+ /* get the opcodes to check the command complete event */
+ opCodeBytes[0] = pHCICommand[HCI_CMD_OPCODE_BYTE_LOW_OFFSET];
+ opCodeBytes[1] = pHCICommand[HCI_CMD_OPCODE_BYTE_HI_OFFSET];
+
+ /* copy HCI command */
+ A_MEMCPY(pBuffer + pConfig->pHCIProps->HeadRoom,pHCICommand,CmdLength);
+ /* send command */
+ status = SendHCICommand(pConfig,
+ pBuffer + pConfig->pHCIProps->HeadRoom,
+ CmdLength);
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to send HCI Command (%d) \n", status));
+ AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
+ break;
+ }
+
+ /* reuse buffer to capture command complete event */
+ A_MEMZERO(pBuffer,length);
+ status = RecvHCIEvent(pConfig,pBuffer,&length);
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI event recv failed \n"));
+ AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command");
+ break;
+ }
+
+ pTemp = pBuffer + pConfig->pHCIProps->HeadRoom;
+ if (pTemp[0] == HCI_CMD_COMPLETE_EVENT_CODE) {
+ if ((pTemp[HCI_EVENT_OPCODE_BYTE_LOW] == opCodeBytes[0]) &&
+ (pTemp[HCI_EVENT_OPCODE_BYTE_HI] == opCodeBytes[1])) {
+ commandComplete = TRUE;
+ }
+ }
+
+ if (!commandComplete) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Unexpected HCI event : %d \n",pTemp[0]));
+ AR_DEBUG_PRINTBUF(pTemp,pTemp[1],"Unexpected HCI event");
+ status = A_ECOMM;
+ break;
+ }
+
+ if (ppEventBuffer != NULL) {
+ /* caller wants to look at the event */
+ *ppEventBuffer = pTemp;
+ if (ppBufferToFree == NULL) {
+ status = A_EINVAL;
+ break;
+ }
+ /* caller must free the buffer */
+ *ppBufferToFree = pBuffer;
+ pBuffer = NULL;
+ }
+
+ } while (FALSE);
+
+ if (pBuffer != NULL) {
+ A_FREE(pBuffer);
+ }
+
+ return status;
+}
+
+static A_STATUS AR3KConfigureHCIBaud(AR3K_CONFIG_INFO *pConfig)
+{
+ A_STATUS status = A_OK;
+ A_UINT8 hciBaudChangeCommand[] = {0x0c,0xfc,0x2,0,0};
+ A_UINT16 baudVal;
+ A_UINT8 *pEvent = NULL;
+ A_UINT8 *pBufferToFree = NULL;
+
+ do {
+
+ if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR3K_BAUD) {
+ baudVal = (A_UINT16)(pConfig->AR3KBaudRate / 100);
+ hciBaudChangeCommand[3] = (A_UINT8)baudVal;
+ hciBaudChangeCommand[4] = (A_UINT8)(baudVal >> 8);
+
+ status = SendHCICommandWaitCommandComplete(pConfig,
+ hciBaudChangeCommand,
+ sizeof(hciBaudChangeCommand),
+ &pEvent,
+ &pBufferToFree);
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Baud rate change failed! \n"));
+ break;
+ }
+
+ if (pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET] != 0) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
+ ("AR3K Config: Baud change command event status failed: %d \n",
+ pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET]));
+ status = A_ECOMM;
+ break;
+ }
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
+ ("AR3K Config: Baud Changed to %d \n",pConfig->AR3KBaudRate));
+ }
+
+ if (pConfig->Flags & AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY) {
+ /* some versions of AR3K do not switch baud immediately, up to 300MS */
+ A_MDELAY(325);
+ }
+
+ if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP) {
+ /* Tell target to change UART baud rate for AR6K */
+ status = HCI_TransportSetBaudRate(pConfig->pHCIDev, pConfig->AR3KBaudRate);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
+ ("AR3K Config: failed to set scale and step values: %d \n", status));
+ break;
+ }
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
+ ("AR3K Config: Baud changed to %d for AR6K\n", pConfig->AR3KBaudRate));
+ }
+
+ } while (FALSE);
+
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+
+ return status;
+}
+
+static A_STATUS AR3KExitMinBoot(AR3K_CONFIG_INFO *pConfig)
+{
+ A_STATUS status;
+ A_CHAR exitMinBootCmd[] = {0x25,0xFC,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00};
+ A_UINT8 *pEvent = NULL;
+ A_UINT8 *pBufferToFree = NULL;
+
+ status = SendHCICommandWaitCommandComplete(pConfig,
+ exitMinBootCmd,
+ sizeof(exitMinBootCmd),
+ &pEvent,
+ &pBufferToFree);
+
+ if (A_SUCCESS(status)) {
+ if (pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET] != 0) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
+ ("AR3K Config: MinBoot exit command event status failed: %d \n",
+ pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET]));
+ status = A_ECOMM;
+ } else {
+ AR_DEBUG_PRINTF(ATH_DEBUG_INFO,
+ ("AR3K Config: MinBoot Exit Command Complete (Success) \n"));
+ A_MDELAY(1);
+ }
+ } else {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: MinBoot Exit Failed! \n"));
+ }
+
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+
+ return status;
+}
+
+static A_STATUS AR3KConfigureSendHCIReset(AR3K_CONFIG_INFO *pConfig)
+{
+ A_STATUS status = A_OK;
+ A_UINT8 hciResetCommand[] = {0x03,0x0c,0x0};
+ A_UINT8 *pEvent = NULL;
+ A_UINT8 *pBufferToFree = NULL;
+
+ status = SendHCICommandWaitCommandComplete( pConfig,
+ hciResetCommand,
+ sizeof(hciResetCommand),
+ &pEvent,
+ &pBufferToFree );
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI reset failed! \n"));
+ }
+
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+
+ return status;
+}
+
+static A_STATUS AR3KEnableTLPM(AR3K_CONFIG_INFO *pConfig)
+{
+ A_STATUS status;
+ /* AR3K vendor specific command for Host Wakeup Config */
+ A_CHAR hostWakeupConfig[] = {0x31,0xFC,0x18,
+ 0x02,0x00,0x00,0x00,
+ 0x01,0x00,0x00,0x00,
+ TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
+ 0x00,0x00,0x00,0x00,
+ TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms
+ 0x00,0x00,0x00,0x00};
+ /* AR3K vendor specific command for Target Wakeup Config */
+ A_CHAR targetWakeupConfig[] = {0x31,0xFC,0x18,
+ 0x04,0x00,0x00,0x00,
+ 0x01,0x00,0x00,0x00,
+ TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms
+ 0x00,0x00,0x00,0x00,
+ TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms
+ 0x00,0x00,0x00,0x00};
+ /* AR3K vendor specific command for Host Wakeup Enable */
+ A_CHAR hostWakeupEnable[] = {0x31,0xFC,0x4,
+ 0x01,0x00,0x00,0x00};
+ /* AR3K vendor specific command for Target Wakeup Enable */
+ A_CHAR targetWakeupEnable[] = {0x31,0xFC,0x4,
+ 0x06,0x00,0x00,0x00};
+ /* AR3K vendor specific command for Sleep Enable */
+ A_CHAR sleepEnable[] = {0x4,0xFC,0x1,
+ 0x1};
+ A_UINT8 *pEvent = NULL;
+ A_UINT8 *pBufferToFree = NULL;
+
+ if (0 != pConfig->IdleTimeout) {
+ A_UINT8 idle_lsb = pConfig->IdleTimeout & 0xFF;
+ A_UINT8 idle_msb = (pConfig->IdleTimeout & 0xFF00) >> 8;
+ hostWakeupConfig[11] = targetWakeupConfig[11] = idle_lsb;
+ hostWakeupConfig[12] = targetWakeupConfig[12] = idle_msb;
+ }
+
+ if (0 != pConfig->WakeupTimeout) {
+ hostWakeupConfig[19] = targetWakeupConfig[19] = (pConfig->WakeupTimeout & 0xFF);
+ }
+
+ status = SendHCICommandWaitCommandComplete(pConfig,
+ hostWakeupConfig,
+ sizeof(hostWakeupConfig),
+ &pEvent,
+ &pBufferToFree);
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Config Failed! \n"));
+ return status;
+ }
+
+ pEvent = NULL;
+ pBufferToFree = NULL;
+ status = SendHCICommandWaitCommandComplete(pConfig,
+ targetWakeupConfig,
+ sizeof(targetWakeupConfig),
+ &pEvent,
+ &pBufferToFree);
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Config Failed! \n"));
+ return status;
+ }
+
+ pEvent = NULL;
+ pBufferToFree = NULL;
+ status = SendHCICommandWaitCommandComplete(pConfig,
+ hostWakeupEnable,
+ sizeof(hostWakeupEnable),
+ &pEvent,
+ &pBufferToFree);
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Enable Failed! \n"));
+ return status;
+ }
+
+ pEvent = NULL;
+ pBufferToFree = NULL;
+ status = SendHCICommandWaitCommandComplete(pConfig,
+ targetWakeupEnable,
+ sizeof(targetWakeupEnable),
+ &pEvent,
+ &pBufferToFree);
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Enable Failed! \n"));
+ return status;
+ }
+
+ pEvent = NULL;
+ pBufferToFree = NULL;
+ status = SendHCICommandWaitCommandComplete(pConfig,
+ sleepEnable,
+ sizeof(sleepEnable),
+ &pEvent,
+ &pBufferToFree);
+ if (pBufferToFree != NULL) {
+ A_FREE(pBufferToFree);
+ }
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Sleep Enable Failed! \n"));
+ }
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Enable TLPM Completed (status = %d) \n",status));
+
+ return status;
+}
+
+A_STATUS AR3KConfigure(AR3K_CONFIG_INFO *pConfig)
+{
+ A_STATUS status = A_OK;
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuring AR3K ...\n"));
+
+ do {
+
+ if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
+ status = A_EINVAL;
+ break;
+ }
+
+ /* disable asynchronous recv while we issue commands and receive events synchronously */
+ status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,FALSE);
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ if (pConfig->Flags & AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT) {
+ status = AR3KExitMinBoot(pConfig);
+ if (A_FAILED(status)) {
+ break;
+ }
+ }
+
+
+ /* Load patching and PST file if available*/
+ if (A_OK != AthPSInitialize(pConfig)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch Download Failed!\n"));
+ }
+
+ /* Send HCI reset to make PS tags take effect*/
+ AR3KConfigureSendHCIReset(pConfig);
+
+ if (pConfig->Flags &
+ (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
+ status = AR3KConfigureHCIBaud(pConfig);
+ if (A_FAILED(status)) {
+ break;
+ }
+ }
+
+
+
+ if (pConfig->PwrMgmtEnabled) {
+ /* the delay is required after the previous HCI reset before further
+ * HCI commands can be issued
+ */
+ A_MDELAY(200);
+ AR3KEnableTLPM(pConfig);
+ }
+
+ /* re-enable asynchronous recv */
+ status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,TRUE);
+ if (A_FAILED(status)) {
+ break;
+ }
+
+
+ } while (FALSE);
+
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuration Complete (status = %d) \n",status));
+
+ return status;
+}
+
+A_STATUS AR3KConfigureExit(void *config)
+{
+ A_STATUS status = A_OK;
+ AR3K_CONFIG_INFO *pConfig = (AR3K_CONFIG_INFO *)config;
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleaning up AR3K ...\n"));
+
+ do {
+
+ if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) {
+ status = A_EINVAL;
+ break;
+ }
+
+ /* disable asynchronous recv while we issue commands and receive events synchronously */
+ status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,FALSE);
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ if (pConfig->Flags &
+ (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) {
+ status = AR3KConfigureHCIBaud(pConfig);
+ if (A_FAILED(status)) {
+ break;
+ }
+ }
+
+ /* re-enable asynchronous recv */
+ status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,TRUE);
+ if (A_FAILED(status)) {
+ break;
+ }
+
+
+ } while (FALSE);
+
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleanup Complete (status = %d) \n",status));
+
+ return status;
+}
+
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
new file mode 100644
index 000000000000..0e298dba9fc8
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2004-2010 Atheros Communications Inc.
+ * All rights reserved.
+ *
+ * This file implements the Atheros PS and patch downloaded for HCI UART Transport driver.
+ * This file can be used for HCI SDIO transport implementation for AR6002 with HCI_TRANSPORT_SDIO
+ * defined.
+ *
+ *
+ * ar3kcpsconfig.c
+ *
+ *
+ *
+ * The software source and binaries included in this development package are
+ * licensed, not sold. You, or your company, received the package under one
+ * or more license agreements. The rights granted to you are specifically
+ * listed in these license agreement(s). All other rights remain with Atheros
+ * Communications, Inc., its subsidiaries, or the respective owner including
+ * those listed on the included copyright notices.. Distribution of any
+ * portion of this package must be in strict compliance with the license
+ * agreement(s) terms.
+ *
+ *
+ *
+ */
+
+
+
+#include "ar3kpsconfig.h"
+#ifndef HCI_TRANSPORT_SDIO
+#include "hci_ath.h"
+#include "hci_uart.h"
+#endif /* #ifndef HCI_TRANSPORT_SDIO */
+
+#define MAX_FW_PATH_LEN 50
+#define MAX_BDADDR_FORMAT_LENGTH 30
+
+/*
+ * Structure used to send HCI packet, hci packet length and device info
+ * together as parameter to PSThread.
+ */
+typedef struct {
+
+ PSCmdPacket *HciCmdList;
+ A_UINT32 num_packets;
+ AR3K_CONFIG_INFO *dev;
+}HciCommandListParam;
+
+A_STATUS SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig,
+ A_UINT8 *pHCICommand,
+ int CmdLength,
+ A_UINT8 **ppEventBuffer,
+ A_UINT8 **ppBufferToFree);
+
+A_UINT32 Rom_Version;
+A_UINT32 Build_Version;
+extern A_BOOL BDADDR;
+
+A_STATUS getDeviceType(AR3K_CONFIG_INFO *pConfig, A_UINT32 * code);
+A_STATUS ReadVersionInfo(AR3K_CONFIG_INFO *pConfig);
+#ifndef HCI_TRANSPORT_SDIO
+
+DECLARE_WAIT_QUEUE_HEAD(PsCompleteEvent);
+DECLARE_WAIT_QUEUE_HEAD(HciEvent);
+A_UCHAR *HciEventpacket;
+rwlock_t syncLock;
+wait_queue_t Eventwait;
+
+int PSHciWritepacket(struct hci_dev*,A_UCHAR* Data, A_UINT32 len);
+extern char *bdaddr;
+#endif /* HCI_TRANSPORT_SDIO */
+
+A_STATUS write_bdaddr(AR3K_CONFIG_INFO *pConfig,A_UCHAR *bdaddr,int type);
+
+int PSSendOps(void *arg);
+
+#ifdef BT_PS_DEBUG
+void Hci_log(A_UCHAR * log_string,A_UCHAR *data,A_UINT32 len)
+{
+ int i;
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s : ",log_string));
+ for (i = 0; i < len; i++) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("0x%02x ", data[i]));
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("\n...................................\n"));
+}
+#else
+#define Hci_log(string,data,len)
+#endif /* BT_PS_DEBUG */
+
+
+
+
+A_STATUS AthPSInitialize(AR3K_CONFIG_INFO *hdev)
+{
+ A_STATUS status = A_OK;
+ if(hdev == NULL) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Device handle received\n"));
+ return A_ERROR;
+ }
+
+#ifndef HCI_TRANSPORT_SDIO
+ DECLARE_WAITQUEUE(wait, current);
+#endif /* HCI_TRANSPORT_SDIO */
+
+
+#ifdef HCI_TRANSPORT_SDIO
+ status = PSSendOps((void*)hdev);
+#else
+ if(InitPSState(hdev) == -1) {
+ return A_ERROR;
+ }
+ allow_signal(SIGKILL);
+ add_wait_queue(&PsCompleteEvent,&wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if(!kernel_thread(PSSendOps,(void*)hdev,CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Kthread Failed\n"));
+ remove_wait_queue(&PsCompleteEvent,&wait);
+ return A_ERROR;
+ }
+ wait_event_interruptible(PsCompleteEvent,(PSTagMode == FALSE));
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&PsCompleteEvent,&wait);
+
+#endif /* HCI_TRANSPORT_SDIO */
+
+
+ return status;
+
+}
+
+int PSSendOps(void *arg)
+{
+ int i;
+ int status = 0;
+ PSCmdPacket *HciCmdList; /* List storing the commands */
+ const struct firmware* firmware;
+ A_UINT32 numCmds;
+ A_UINT8 *event;
+ A_UINT8 *bufferToFree;
+ struct hci_dev *device;
+ A_UCHAR *buffer;
+ A_UINT32 len;
+ A_UINT32 DevType;
+ A_UCHAR *PsFileName;
+ A_UCHAR *patchFileName;
+ A_UCHAR *path = NULL;
+ A_UCHAR *config_path = NULL;
+ A_UCHAR config_bdaddr[MAX_BDADDR_FORMAT_LENGTH];
+ AR3K_CONFIG_INFO *hdev = (AR3K_CONFIG_INFO*)arg;
+ struct device *firmwareDev = NULL;
+ status = 0;
+ HciCmdList = NULL;
+#ifdef HCI_TRANSPORT_SDIO
+ device = hdev->pBtStackHCIDev;
+ firmwareDev = device->parent;
+#else
+ device = hdev;
+ firmwareDev = &device->dev;
+ AthEnableSyncCommandOp(TRUE);
+#endif /* HCI_TRANSPORT_SDIO */
+ /* First verify if the controller is an FPGA or ASIC, so depending on the device type the PS file to be written will be different.
+ */
+
+ path =(A_UCHAR *)A_MALLOC(MAX_FW_PATH_LEN);
+ if(path == NULL) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Malloc failed to allocate %d bytes for path\n", MAX_FW_PATH_LEN));
+ goto complete;
+ }
+ config_path = (A_UCHAR *) A_MALLOC(MAX_FW_PATH_LEN);
+ if(config_path == NULL) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Malloc failed to allocate %d bytes for config_path\n", MAX_FW_PATH_LEN));
+ goto complete;
+ }
+
+ if(A_ERROR == getDeviceType(hdev,&DevType)) {
+ status = 1;
+ goto complete;
+ }
+ if(A_ERROR == ReadVersionInfo(hdev)) {
+ status = 1;
+ goto complete;
+ }
+
+ patchFileName = PATCH_FILE;
+ snprintf(path, MAX_FW_PATH_LEN, "%s/%xcoex/",CONFIG_PATH,Rom_Version);
+ if(DevType){
+ if(DevType == 0xdeadc0de){
+ PsFileName = PS_ASIC_FILE;
+ } else{
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" FPGA Test Image : %x %x \n",Rom_Version,Build_Version));
+ if((Rom_Version == 0x99999999) && (Build_Version == 1)){
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("FPGA Test Image : Skipping Patch File load\n"));
+ patchFileName = NULL;
+ }
+ PsFileName = PS_FPGA_FILE;
+ }
+ }
+ else{
+ PsFileName = PS_ASIC_FILE;
+ }
+
+ snprintf(config_path, MAX_FW_PATH_LEN, "%s%s",path,PsFileName);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%x: FPGA/ASIC PS File Name %s\n", DevType,config_path));
+ /* Read the PS file to a dynamically allocated buffer */
+ if(A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ ));
+ status = 1;
+ goto complete;
+
+ }
+ if(NULL == firmware || firmware->size == 0) {
+ status = 1;
+ goto complete;
+ }
+ buffer = (A_UCHAR *)A_MALLOC(firmware->size);
+ if(buffer != NULL) {
+ /* Copy the read file to a local Dynamic buffer */
+ memcpy(buffer,firmware->data,firmware->size);
+ len = firmware->size;
+ A_RELEASE_FIRMWARE(firmware);
+ /* Parse the PS buffer to a global variable */
+ status = AthDoParsePS(buffer,len);
+ A_FREE(buffer);
+ } else {
+ A_RELEASE_FIRMWARE(firmware);
+ }
+
+
+ /* Read the patch file to a dynamically allocated buffer */
+ if(patchFileName != NULL)
+ snprintf(config_path,
+ MAX_FW_PATH_LEN, "%s%s",path,patchFileName);
+ else {
+ status = 0;
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch File Name %s\n", config_path));
+ if((patchFileName == NULL) || (A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ ));
+ /*
+ * It is not necessary that Patch file be available, continue with PS Operations if.
+ * failed.
+ */
+ status = 0;
+
+ } else {
+ if(NULL == firmware || firmware->size == 0) {
+ status = 0;
+ } else {
+ buffer = (A_UCHAR *)A_MALLOC(firmware->size);
+ if(buffer != NULL) {
+ /* Copy the read file to a local Dynamic buffer */
+ memcpy(buffer,firmware->data,firmware->size);
+ len = firmware->size;
+ A_RELEASE_FIRMWARE(firmware);
+ /* parse and store the Patch file contents to a global variables */
+ status = AthDoParsePatch(buffer,len);
+ A_FREE(buffer);
+ } else {
+ A_RELEASE_FIRMWARE(firmware);
+ }
+ }
+ }
+
+ /* Create an HCI command list from the parsed PS and patch information */
+ AthCreateCommandList(&HciCmdList,&numCmds);
+
+ /* Form the parameter for PSSendOps() API */
+
+
+ /*
+ * First Send the CRC packet,
+ * We have to continue with the PS operations only if the CRC packet has been replied with
+ * a Command complete event with status Error.
+ */
+
+ if(SendHCICommandWaitCommandComplete
+ (hdev,
+ HciCmdList[0].Hcipacket,
+ HciCmdList[0].packetLen,
+ &event,
+ &bufferToFree) == A_OK) {
+ if(ReadPSEvent(event) == A_OK) { /* Exit if the status is success */
+ if(bufferToFree != NULL) {
+ A_FREE(bufferToFree);
+ }
+
+#ifndef HCI_TRANSPORT_SDIO
+ if(bdaddr && bdaddr[0] !='\0') {
+ write_bdaddr(hdev,bdaddr,BDADDR_TYPE_STRING);
+ }
+#endif
+ status = 1;
+ goto complete;
+ }
+ if(bufferToFree != NULL) {
+ A_FREE(bufferToFree);
+ }
+ } else {
+ status = 0;
+ goto complete;
+ }
+
+ for(i = 1; i <numCmds; i++) {
+
+ if(SendHCICommandWaitCommandComplete
+ (hdev,
+ HciCmdList[i].Hcipacket,
+ HciCmdList[i].packetLen,
+ &event,
+ &bufferToFree) == A_OK) {
+ if(ReadPSEvent(event) != A_OK) { /* Exit if the status is success */
+ if(bufferToFree != NULL) {
+ A_FREE(bufferToFree);
+ }
+ status = 1;
+ goto complete;
+ }
+ if(bufferToFree != NULL) {
+ A_FREE(bufferToFree);
+ }
+ } else {
+ status = 0;
+ goto complete;
+ }
+ }
+#ifdef HCI_TRANSPORT_SDIO
+ if(BDADDR == FALSE)
+ if(hdev->bdaddr[0] !=0x00 ||
+ hdev->bdaddr[1] !=0x00 ||
+ hdev->bdaddr[2] !=0x00 ||
+ hdev->bdaddr[3] !=0x00 ||
+ hdev->bdaddr[4] !=0x00 ||
+ hdev->bdaddr[5] !=0x00)
+ write_bdaddr(hdev,hdev->bdaddr,BDADDR_TYPE_HEX);
+
+#ifndef HCI_TRANSPORT_SDIO
+
+ if(bdaddr && bdaddr[0] != '\0') {
+ write_bdaddr(hdev,bdaddr,BDADDR_TYPE_STRING);
+ } else
+#endif /* HCI_TRANSPORT_SDIO */
+ /* Write BDADDR Read from OTP here */
+
+
+
+#endif
+
+ {
+ /* Read Contents of BDADDR file if user has not provided any option */
+ snprintf(config_path,MAX_FW_PATH_LEN, "%s%s",path,BDADDR_FILE);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch File Name %s\n", config_path));
+ if(A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ ));
+ status = 1;
+ goto complete;
+ }
+ if(NULL == firmware || firmware->size == 0) {
+ status = 1;
+ goto complete;
+ }
+ len = (firmware->size > MAX_BDADDR_FORMAT_LENGTH)? MAX_BDADDR_FORMAT_LENGTH: firmware->size;
+ memcpy(config_bdaddr, firmware->data,len);
+ config_bdaddr[len] = '\0';
+ write_bdaddr(hdev,config_bdaddr,BDADDR_TYPE_STRING);
+ A_RELEASE_FIRMWARE(firmware);
+ }
+complete:
+#ifndef HCI_TRANSPORT_SDIO
+ AthEnableSyncCommandOp(FALSE);
+ PSTagMode = FALSE;
+ wake_up_interruptible(&PsCompleteEvent);
+#endif /* HCI_TRANSPORT_SDIO */
+ if(NULL != HciCmdList) {
+ AthFreeCommandList(&HciCmdList,numCmds);
+ }
+ if(path) {
+ A_FREE(path);
+ }
+ if(config_path) {
+ A_FREE(config_path);
+ }
+ return status;
+}
+#ifndef HCI_TRANSPORT_SDIO
+/*
+ * This API is used to send the HCI command to controller and return
+ * with a HCI Command Complete event.
+ * For HCI SDIO transport, this will be internally defined.
+ */
+A_STATUS SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig,
+ A_UINT8 *pHCICommand,
+ int CmdLength,
+ A_UINT8 **ppEventBuffer,
+ A_UINT8 **ppBufferToFree)
+{
+ if(CmdLength == 0) {
+ return A_ERROR;
+ }
+ Hci_log("COM Write -->",pHCICommand,CmdLength);
+ PSAcked = FALSE;
+ if(PSHciWritepacket(pConfig,pHCICommand,CmdLength) == 0) {
+ /* If the controller is not available, return Error */
+ return A_ERROR;
+ }
+ //add_timer(&psCmdTimer);
+ wait_event_interruptible(HciEvent,(PSAcked == TRUE));
+ if(NULL != HciEventpacket) {
+ *ppEventBuffer = HciEventpacket;
+ *ppBufferToFree = HciEventpacket;
+ } else {
+ /* Did not get an event from controller. return error */
+ *ppBufferToFree = NULL;
+ return A_ERROR;
+ }
+
+ return A_OK;
+}
+#endif /* HCI_TRANSPORT_SDIO */
+
+A_STATUS ReadPSEvent(A_UCHAR* Data){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" PS Event %x %x %x\n",Data[4],Data[5],Data[3]));
+
+ if(Data[4] == 0xFC && Data[5] == 0x00)
+ {
+ switch(Data[3]){
+ case 0x0B:
+ return A_OK;
+ break;
+ case 0x0C:
+ /* Change Baudrate */
+ return A_OK;
+ break;
+ case 0x04:
+ return A_OK;
+ break;
+ case 0x1E:
+ Rom_Version = Data[9];
+ Rom_Version = ((Rom_Version << 8) |Data[8]);
+ Rom_Version = ((Rom_Version << 8) |Data[7]);
+ Rom_Version = ((Rom_Version << 8) |Data[6]);
+
+ Build_Version = Data[13];
+ Build_Version = ((Build_Version << 8) |Data[12]);
+ Build_Version = ((Build_Version << 8) |Data[11]);
+ Build_Version = ((Build_Version << 8) |Data[10]);
+ return A_OK;
+ break;
+
+
+ }
+ }
+
+ return A_ERROR;
+}
+int str2ba(unsigned char *str_bdaddr,unsigned char *bdaddr)
+{
+ unsigned char bdbyte[3];
+ unsigned char *str_byte = str_bdaddr;
+ int i,j;
+ unsigned char colon_present = 0;
+
+ if(NULL != strstr(str_bdaddr,":")) {
+ colon_present = 1;
+ }
+
+
+ bdbyte[2] = '\0';
+
+ for( i = 0,j = 5; i < 6; i++, j--) {
+ bdbyte[0] = str_byte[0];
+ bdbyte[1] = str_byte[1];
+ bdaddr[j] = A_STRTOL(bdbyte,NULL,16);
+ if(colon_present == 1) {
+ str_byte+=3;
+ } else {
+ str_byte+=2;
+ }
+ }
+ return 0;
+}
+
+A_STATUS write_bdaddr(AR3K_CONFIG_INFO *pConfig,A_UCHAR *bdaddr,int type)
+{
+ A_UCHAR bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A, 0x01, 0x01,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ A_UINT8 *event;
+ A_UINT8 *bufferToFree = NULL;
+ A_STATUS result = A_ERROR;
+ int inc,outc;
+
+ if (type == BDADDR_TYPE_STRING)
+ str2ba(bdaddr,&bdaddr_cmd[7]);
+ else {
+ /* Bdaddr has to be sent as LAP first */
+ for(inc = 5 ,outc = 7; inc >=0; inc--, outc++)
+ bdaddr_cmd[outc] = bdaddr[inc];
+ }
+
+ if(A_OK == SendHCICommandWaitCommandComplete(pConfig,bdaddr_cmd,
+ sizeof(bdaddr_cmd),
+ &event,&bufferToFree)) {
+
+ if(event[4] == 0xFC && event[5] == 0x00){
+ if(event[3] == 0x0B){
+ result = A_OK;
+ }
+ }
+
+ }
+ if(bufferToFree != NULL) {
+ A_FREE(bufferToFree);
+ }
+ return result;
+
+}
+A_STATUS ReadVersionInfo(AR3K_CONFIG_INFO *pConfig)
+{
+ A_UINT8 hciCommand[] = {0x1E,0xfc,0x00};
+ A_UINT8 *event;
+ A_UINT8 *bufferToFree = NULL;
+ A_STATUS result = A_ERROR;
+ if(A_OK == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCommand),&event,&bufferToFree)) {
+ result = ReadPSEvent(event);
+
+ }
+ if(bufferToFree != NULL) {
+ A_FREE(bufferToFree);
+ }
+ return result;
+}
+A_STATUS getDeviceType(AR3K_CONFIG_INFO *pConfig, A_UINT32 * code)
+{
+ A_UINT8 hciCommand[] = {0x05,0xfc,0x05,0x00,0x00,0x00,0x00,0x04};
+ A_UINT8 *event;
+ A_UINT8 *bufferToFree = NULL;
+ A_UINT32 reg;
+ A_STATUS result = A_ERROR;
+ *code = 0;
+ hciCommand[3] = (A_UINT8)(FPGA_REGISTER & 0xFF);
+ hciCommand[4] = (A_UINT8)((FPGA_REGISTER >> 8) & 0xFF);
+ hciCommand[5] = (A_UINT8)((FPGA_REGISTER >> 16) & 0xFF);
+ hciCommand[6] = (A_UINT8)((FPGA_REGISTER >> 24) & 0xFF);
+ if(A_OK == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCommand),&event,&bufferToFree)) {
+
+ if(event[4] == 0xFC && event[5] == 0x00){
+ switch(event[3]){
+ case 0x05:
+ reg = event[9];
+ reg = ((reg << 8) |event[8]);
+ reg = ((reg << 8) |event[7]);
+ reg = ((reg << 8) |event[6]);
+ *code = reg;
+ result = A_OK;
+
+ break;
+ case 0x06:
+ //Sleep(500);
+ break;
+ }
+ }
+
+ }
+ if(bufferToFree != NULL) {
+ A_FREE(bufferToFree);
+ }
+ return result;
+}
+
+
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h
new file mode 100644
index 000000000000..4358834f6d71
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2004-2010 Atheros Communications Inc.
+ * All rights reserved.
+ *
+ * This file defines the symbols exported by Atheros PS and patch download module.
+ * define the constant HCI_TRANSPORT_SDIO if the module is being used for HCI SDIO transport.
+ * defined.
+ *
+ *
+ * ar3kcpsconfig.h
+ *
+ *
+ *
+ * The software source and binaries included in this development package are
+ * licensed, not sold. You, or your company, received the package under one
+ * or more license agreements. The rights granted to you are specifically
+ * listed in these license agreement(s). All other rights remain with Atheros
+ * Communications, Inc., its subsidiaries, or the respective owner including
+ * those listed on the included copyright notices.. Distribution of any
+ * portion of this package must be in strict compliance with the license
+ * agreement(s) terms.
+ *
+ *
+ *
+ */
+
+
+
+#ifndef __AR3KPSCONFIG_H
+#define __AR3KPSCONFIG_H
+
+/*
+ * Define the flag HCI_TRANSPORT_SDIO and undefine HCI_TRANSPORT_UART if the transport being used is SDIO.
+ */
+#undef HCI_TRANSPORT_UART
+
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+
+
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/wait.h>
+
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "ar3kpsparser.h"
+
+#define FPGA_REGISTER 0x4FFC
+#define BDADDR_TYPE_STRING 0
+#define BDADDR_TYPE_HEX 1
+#define CONFIG_PATH "ar3k"
+
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+
+#define PATCH_FILE "RamPatch.txt"
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+#define ROM_VER_AR3001_3_1_0 30000
+#define ROM_VER_AR3001_3_1_1 30101
+
+
+#ifndef HCI_TRANSPORT_SDIO
+#define AR3K_CONFIG_INFO struct hci_dev
+extern wait_queue_head_t HciEvent;
+extern wait_queue_t Eventwait;
+extern A_UCHAR *HciEventpacket;
+#endif /* #ifndef HCI_TRANSPORT_SDIO */
+
+A_STATUS AthPSInitialize(AR3K_CONFIG_INFO *hdev);
+A_STATUS ReadPSEvent(A_UCHAR* Data);
+#endif /* __AR3KPSCONFIG_H */
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
new file mode 100644
index 000000000000..5eed8ac00390
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
@@ -0,0 +1,980 @@
+/*
+ * Copyright (c) 2004-2010 Atheros Communications Inc.
+ * All rights reserved.
+ *
+ * This file implements the Atheros PS and patch parser.
+ * It implements APIs to parse data buffer with patch and PS information and convert it to HCI commands.
+ *
+ *
+ *
+ * ar3kpsparser.c
+ *
+ *
+ *
+ * The software source and binaries included in this development package are
+ * licensed, not sold. You, or your company, received the package under one
+ * or more license agreements. The rights granted to you are specifically
+ * listed in these license agreement(s). All other rights remain with Atheros
+ * Communications, Inc., its subsidiaries, or the respective owner including
+ * those listed on the included copyright notices.. Distribution of any
+ * portion of this package must be in strict compliance with the license
+ * agreement(s) terms.
+ *
+ *
+ *
+ */
+
+
+#include "ar3kpsparser.h"
+
+#define BD_ADDR_SIZE 6
+#define WRITE_PATCH 8
+#define ENABLE_PATCH 11
+#define PS_RESET 2
+#define PS_WRITE 1
+#define PS_VERIFY_CRC 9
+#define CHANGE_BDADDR 15
+
+#define HCI_COMMAND_HEADER 7
+
+#define HCI_EVENT_SIZE 7
+
+#define WRITE_PATCH_COMMAND_STATUS_OFFSET 5
+
+#define PS_RAM_SIZE 2048
+
+#define RAM_PS_REGION (1<<0)
+#define RAM_PATCH_REGION (1<<1)
+#define RAMPS_MAX_PS_DATA_PER_TAG 20000
+#define MAX_RADIO_CFG_TABLE_SIZE 244
+#define RAMPS_MAX_PS_TAGS_PER_FILE 50
+
+#define PS_MAX_LEN 500
+#define LINE_SIZE_MAX (PS_MAX_LEN *2)
+
+/* Constant values used by parser */
+#define BYTES_OF_PS_DATA_PER_LINE 16
+#define RAMPS_MAX_PS_DATA_PER_TAG 20000
+
+
+/* Number pf PS/Patch entries in an HCI packet */
+#define MAX_BYTE_LENGTH 244
+
+#define SKIP_BLANKS(str) while (*str == ' ') str++
+#define MIN(x, y) (((x) <= (y))? (x):(y))
+#define MAX(x, y) (((x) >= (y))? (x):(y))
+
+#define UNUSED(x) (x=x)
+
+#define IS_BETWEEN(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
+#define IS_DIGIT(c) (IS_BETWEEN((c), '0', '9'))
+#define IS_HEX(c) (IS_BETWEEN((c), '0', '9') || IS_BETWEEN((c), 'a', 'f') || IS_BETWEEN((c), 'A', 'F'))
+#define TO_LOWER(c) (IS_BETWEEN((c), 'A', 'Z') ? ((c) - 'A' + 'a') : (c))
+#define IS_BLANK(c) ((c) == ' ')
+#define CONV_DEC_DIGIT_TO_VALUE(c) ((c) - '0')
+#define CONV_HEX_DIGIT_TO_VALUE(c) (IS_DIGIT(c) ? ((c) - '0') : (IS_BETWEEN((c), 'A', 'Z') ? ((c) - 'A' + 10) : ((c) - 'a' + 10)))
+#define CONV_VALUE_TO_HEX(v) ((A_UINT8)( ((v & 0x0F) <= 9) ? ((v & 0x0F) + '0') : ((v & 0x0F) - 10 + 'A') ) )
+
+
+enum MinBootFileFormatE
+{
+ MB_FILEFORMAT_RADIOTBL,
+ MB_FILEFORMAT_PATCH,
+ MB_FILEFORMAT_COEXCONFIG
+};
+
+enum RamPsSection
+{
+ RAM_PS_SECTION,
+ RAM_PATCH_SECTION,
+ RAM_DYN_MEM_SECTION
+};
+
+enum eType {
+ eHex,
+ edecimal
+};
+
+
+typedef struct tPsTagEntry
+{
+ A_UINT32 TagId;
+ A_UINT32 TagLen;
+ A_UINT8 *TagData;
+} tPsTagEntry, *tpPsTagEntry;
+
+typedef struct tRamPatch
+{
+ A_UINT16 Len;
+ A_UINT8 * Data;
+} tRamPatch, *ptRamPatch;
+
+
+
+typedef struct ST_PS_DATA_FORMAT {
+ enum eType eDataType;
+ A_BOOL bIsArray;
+}ST_PS_DATA_FORMAT;
+
+typedef struct ST_READ_STATUS {
+ unsigned uTagID;
+ unsigned uSection;
+ unsigned uLineCount;
+ unsigned uCharCount;
+ unsigned uByteCount;
+}ST_READ_STATUS;
+
+
+/* Stores the number of PS Tags */
+static A_UINT32 Tag_Count = 0;
+
+/* Stores the number of patch commands */
+static A_UINT32 Patch_Count = 0;
+static A_UINT32 Total_tag_lenght = 0;
+A_BOOL BDADDR = FALSE;
+A_UINT32 StartTagId;
+
+tPsTagEntry PsTagEntry[RAMPS_MAX_PS_TAGS_PER_FILE];
+tRamPatch RamPatch[MAX_NUM_PATCH_ENTRY];
+
+
+A_STATUS AthParseFilesUnified(A_UCHAR *srcbuffer,A_UINT32 srclen, int FileFormat);
+char AthReadChar(A_UCHAR *buffer, A_UINT32 len,A_UINT32 *pos);
+char * AthGetLine(char * buffer, int maxlen, A_UCHAR *srcbuffer,A_UINT32 len,A_UINT32 *pos);
+static A_STATUS AthPSCreateHCICommand(A_UCHAR Opcode, A_UINT32 Param1,PSCmdPacket *PSPatchPacket,A_UINT32 *index);
+
+/* Function to reads the next character from the input buffer */
+char AthReadChar(A_UCHAR *buffer, A_UINT32 len,A_UINT32 *pos)
+{
+ char Ch;
+ if(buffer == NULL || *pos >=len )
+ {
+ return '\0';
+ } else {
+ Ch = buffer[*pos];
+ (*pos)++;
+ return Ch;
+ }
+}
+/* PS parser helper function */
+unsigned int uGetInputDataFormat(char* pCharLine, ST_PS_DATA_FORMAT *pstFormat)
+{
+ if(pCharLine[0] != '[') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ return 0;
+ }
+ switch(pCharLine[1]) {
+ case 'H':
+ case 'h':
+ if(pCharLine[2]==':') {
+ if((pCharLine[3]== 'a') || (pCharLine[3]== 'A')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 5;
+ return 0;
+ }
+ else {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); //[H:A
+ return 1;
+ }
+ }
+ if((pCharLine[3]== 'S') || (pCharLine[3]== 's')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = false;
+ pCharLine += 5;
+ return 0;
+ }
+ else {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); //[H:A
+ return 1;
+ }
+ }
+ else if(pCharLine[3] == ']') { //[H:]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 4;
+ return 0;
+ }
+ else { //[H:
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n"));
+ return 1;
+ }
+ }
+ else if(pCharLine[2]==']') { //[H]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 3;
+ return 0;
+ }
+ else { //[H
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n"));
+ return 1;
+ }
+ break;
+
+ case 'A':
+ case 'a':
+ if(pCharLine[2]==':') {
+ if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 5;
+ return 0;
+ }
+ else {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 1\n")); //[A:H
+ return 1;
+ }
+ }
+ else if(pCharLine[3]== ']') { //[A:]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 4;
+ return 0;
+ }
+ else { //[A:
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 2\n"));
+ return 1;
+ }
+ }
+ else if(pCharLine[2]==']') { //[H]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 3;
+ return 0;
+ }
+ else { //[H
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 3\n"));
+ return 1;
+ }
+ break;
+
+ case 'S':
+ case 's':
+ if(pCharLine[2]==':') {
+ if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 5;
+ return 0;
+ }
+ else {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 5\n")); //[A:H
+ return 1;
+ }
+ }
+ else if(pCharLine[3]== ']') { //[A:]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 4;
+ return 0;
+ }
+ else { //[A:
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 6\n"));
+ return 1;
+ }
+ }
+ else if(pCharLine[2]==']') { //[H]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = true;
+ pCharLine += 3;
+ return 0;
+ }
+ else { //[H
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 7\n"));
+ return 1;
+ }
+ break;
+
+ default:
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 8\n"));
+ return 1;
+ }
+}
+
+unsigned int uReadDataInSection(char *pCharLine, ST_PS_DATA_FORMAT stPS_DataFormat)
+{
+ char *pTokenPtr = pCharLine;
+
+ if(pTokenPtr[0] == '[') {
+ while(pTokenPtr[0] != ']' && pTokenPtr[0] != '\0') {
+ pTokenPtr++;
+ }
+ if(pTokenPtr[0] == '\0') {
+ return (0x0FFF);
+ }
+ pTokenPtr++;
+
+
+ }
+ if(stPS_DataFormat.eDataType == eHex) {
+ if(stPS_DataFormat.bIsArray == true) {
+ //Not implemented
+ return (0x0FFF);
+ }
+ else {
+ return (A_STRTOL(pTokenPtr, NULL, 16));
+ }
+ }
+ else {
+ //Not implemented
+ return (0x0FFF);
+ }
+}
+A_STATUS AthParseFilesUnified(A_UCHAR *srcbuffer,A_UINT32 srclen, int FileFormat)
+{
+ char *Buffer;
+ char *pCharLine;
+ A_UINT8 TagCount;
+ A_UINT16 ByteCount;
+ A_UINT8 ParseSection=RAM_PS_SECTION;
+ A_UINT32 pos;
+
+
+
+ int uReadCount;
+ ST_PS_DATA_FORMAT stPS_DataFormat;
+ ST_READ_STATUS stReadStatus = {0, 0, 0,0};
+ pos = 0;
+ Buffer = NULL;
+
+ if (srcbuffer == NULL || srclen == 0)
+ {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Could not open .\n"));
+ return A_ERROR;
+ }
+ TagCount = 0;
+ ByteCount = 0;
+ Buffer = A_MALLOC(LINE_SIZE_MAX + 1);
+ if(NULL == Buffer) {
+ return A_ERROR;
+ }
+ if (FileFormat == MB_FILEFORMAT_PATCH)
+ {
+ int LineRead = 0;
+ while((pCharLine = AthGetLine(Buffer, LINE_SIZE_MAX, srcbuffer,srclen,&pos)) != NULL)
+ {
+
+ SKIP_BLANKS(pCharLine);
+
+ // Comment line or empty line
+ if ((pCharLine[0] == '/') && (pCharLine[1] == '/'))
+ {
+ continue;
+ }
+
+ if ((pCharLine[0] == '#')) {
+ if (stReadStatus.uSection != 0)
+ {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("error\n"));
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ }
+ else {
+ stReadStatus.uSection = 1;
+ continue;
+ }
+ }
+ if ((pCharLine[0] == '/') && (pCharLine[1] == '*'))
+ {
+ pCharLine+=2;
+ SKIP_BLANKS(pCharLine);
+
+ if(!strncmp(pCharLine,"PA",2)||!strncmp(pCharLine,"Pa",2)||!strncmp(pCharLine,"pa",2))
+ ParseSection=RAM_PATCH_SECTION;
+
+ if(!strncmp(pCharLine,"DY",2)||!strncmp(pCharLine,"Dy",2)||!strncmp(pCharLine,"dy",2))
+ ParseSection=RAM_DYN_MEM_SECTION;
+
+ if(!strncmp(pCharLine,"PS",2)||!strncmp(pCharLine,"Ps",2)||!strncmp(pCharLine,"ps",2))
+ ParseSection=RAM_PS_SECTION;
+
+ LineRead = 0;
+ stReadStatus.uSection = 0;
+
+ continue;
+ }
+
+ switch(ParseSection)
+ {
+ case RAM_PS_SECTION:
+ {
+ if (stReadStatus.uSection == 1) //TagID
+ {
+ SKIP_BLANKS(pCharLine);
+ if(uGetInputDataFormat(pCharLine, &stPS_DataFormat)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat fail\n"));
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ }
+ //pCharLine +=5;
+ PsTagEntry[TagCount].TagId = uReadDataInSection(pCharLine, stPS_DataFormat);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" TAG ID %d \n",PsTagEntry[TagCount].TagId));
+
+ //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("tag # %x\n", PsTagEntry[TagCount].TagId);
+ if (TagCount == 0)
+ {
+ StartTagId = PsTagEntry[TagCount].TagId;
+ }
+ stReadStatus.uSection = 2;
+ }
+ else if (stReadStatus.uSection == 2) //TagLength
+ {
+
+ if(uGetInputDataFormat(pCharLine, &stPS_DataFormat)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat fail \n"));
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ }
+ //pCharLine +=5;
+ ByteCount = uReadDataInSection(pCharLine, stPS_DataFormat);
+
+ //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("tag length %x\n", ByteCount));
+ if (ByteCount > LINE_SIZE_MAX/2)
+ {
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ }
+ PsTagEntry[TagCount].TagLen = ByteCount;
+ PsTagEntry[TagCount].TagData = (A_UINT8*)A_MALLOC(ByteCount);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" TAG Length %d Tag Index %d \n",PsTagEntry[TagCount].TagLen,TagCount));
+ stReadStatus.uSection = 3;
+ stReadStatus.uLineCount = 0;
+ }
+ else if( stReadStatus.uSection == 3) { //Data
+
+ if(stReadStatus.uLineCount == 0) {
+ if(uGetInputDataFormat(pCharLine,&stPS_DataFormat)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat Fail\n"));
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ }
+ //pCharLine +=5;
+ }
+ SKIP_BLANKS(pCharLine);
+ stReadStatus.uCharCount = 0;
+ if(pCharLine[stReadStatus.uCharCount] == '[') {
+ while(pCharLine[stReadStatus.uCharCount] != ']' && pCharLine[stReadStatus.uCharCount] != '\0' ) {
+ stReadStatus.uCharCount++;
+ }
+ if(pCharLine[stReadStatus.uCharCount] == ']' ) {
+ stReadStatus.uCharCount++;
+ } else {
+ stReadStatus.uCharCount = 0;
+ }
+ }
+ uReadCount = (ByteCount > BYTES_OF_PS_DATA_PER_LINE)? BYTES_OF_PS_DATA_PER_LINE: ByteCount;
+ //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" "));
+ if((stPS_DataFormat.eDataType == eHex) && stPS_DataFormat.bIsArray == true) {
+ while(uReadCount > 0) {
+ PsTagEntry[TagCount].TagData[stReadStatus.uByteCount] =
+ (A_UINT8)(CONV_HEX_DIGIT_TO_VALUE(pCharLine[stReadStatus.uCharCount]) << 4)
+ | (A_UINT8)(CONV_HEX_DIGIT_TO_VALUE(pCharLine[stReadStatus.uCharCount + 1]));
+
+ PsTagEntry[TagCount].TagData[stReadStatus.uByteCount+1] =
+ (A_UINT8)(CONV_HEX_DIGIT_TO_VALUE(pCharLine[stReadStatus.uCharCount + 3]) << 4)
+ | (A_UINT8)(CONV_HEX_DIGIT_TO_VALUE(pCharLine[stReadStatus.uCharCount + 4]));
+
+ stReadStatus.uCharCount += 6; // read two bytes, plus a space;
+ stReadStatus.uByteCount += 2;
+ uReadCount -= 2;
+ }
+ if(ByteCount > BYTES_OF_PS_DATA_PER_LINE) {
+ ByteCount -= BYTES_OF_PS_DATA_PER_LINE;
+ }
+ else {
+ ByteCount = 0;
+ }
+ }
+ else {
+ //to be implemented
+ }
+
+ stReadStatus.uLineCount++;
+
+ if(ByteCount == 0) {
+ stReadStatus.uSection = 0;
+ stReadStatus.uCharCount = 0;
+ stReadStatus.uLineCount = 0;
+ stReadStatus.uByteCount = 0;
+ }
+ else {
+ stReadStatus.uCharCount = 0;
+ }
+
+ if((stReadStatus.uSection == 0)&&(++TagCount == RAMPS_MAX_PS_TAGS_PER_FILE))
+ {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("\n Buffer over flow PS File too big!!!"));
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ //Sleep (3000);
+ //exit(1);
+ }
+
+ }
+ }
+
+ break;
+ default:
+ {
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ }
+ break;
+ }
+ LineRead++;
+ }
+ Tag_Count = TagCount;
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Number of Tags %d\n", Tag_Count));
+ }
+
+
+ if (TagCount > RAMPS_MAX_PS_TAGS_PER_FILE)
+ {
+
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_ERROR;
+ }
+
+ if(Buffer != NULL) {
+ A_FREE(Buffer);
+ }
+ return A_OK;
+
+}
+
+
+
+/********************/
+
+
+A_STATUS GetNextTwoChar(A_UCHAR *srcbuffer,A_UINT32 len, A_UINT32 *pos, char * buffer)
+{
+ unsigned char ch;
+
+ ch = AthReadChar(srcbuffer,len,pos);
+ if(ch != '\0' && IS_HEX(ch)) {
+ buffer[0] = ch;
+ } else
+ {
+ return A_ERROR;
+ }
+ ch = AthReadChar(srcbuffer,len,pos);
+ if(ch != '\0' && IS_HEX(ch)) {
+ buffer[1] = ch;
+ } else
+ {
+ return A_ERROR;
+ }
+ return A_OK;
+}
+
+A_STATUS AthDoParsePatch(A_UCHAR *patchbuffer, A_UINT32 patchlen)
+{
+
+ char Byte[3];
+ char Line[MAX_BYTE_LENGTH + 1];
+ int ByteCount,ByteCount_Org;
+ int count;
+ int i,j,k;
+ int data;
+ A_UINT32 filepos;
+ Byte[2] = '\0';
+ j = 0;
+ filepos = 0;
+ Patch_Count = 0;
+
+ while(NULL != AthGetLine(Line,MAX_BYTE_LENGTH,patchbuffer,patchlen,&filepos)) {
+ if(strlen(Line) <= 1 || !IS_HEX(Line[0])) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ ByteCount = A_STRTOL(Line, NULL, 16);
+ ByteCount_Org = ByteCount;
+
+ while(ByteCount > MAX_BYTE_LENGTH){
+
+ /* Handle case when the number of patch buffer is more than the 20K */
+ if(MAX_NUM_PATCH_ENTRY == Patch_Count) {
+ for(i = 0; i < Patch_Count; i++) {
+ A_FREE(RamPatch[i].Data);
+ }
+ return A_ERROR;
+ }
+ RamPatch[Patch_Count].Len= MAX_BYTE_LENGTH;
+ RamPatch[Patch_Count].Data = (A_UINT8*)A_MALLOC(MAX_BYTE_LENGTH);
+ Patch_Count ++;
+
+
+ ByteCount= ByteCount - MAX_BYTE_LENGTH;
+ }
+
+ RamPatch[Patch_Count].Len= (ByteCount & 0xFF);
+ if(ByteCount != 0) {
+ RamPatch[Patch_Count].Data = (A_UINT8*)A_MALLOC(ByteCount);
+ Patch_Count ++;
+ }
+ count = 0;
+ while(ByteCount_Org > MAX_BYTE_LENGTH){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Index [%d]\n",j));
+ for (i = 0,k=0; i < MAX_BYTE_LENGTH*2; i += 2,k++,count +=2) {
+ if(GetNextTwoChar(patchbuffer,patchlen,&filepos,Byte) == A_ERROR) {
+ return A_ERROR;
+ }
+ data = A_STRTOUL(&Byte[0], NULL, 16);
+ RamPatch[j].Data[k] = (data & 0xFF);
+
+
+ }
+ j++;
+ ByteCount_Org = ByteCount_Org - MAX_BYTE_LENGTH;
+ }
+ if(j == 0){
+ j++;
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Index [%d]\n",j));
+ for (k=0; k < ByteCount_Org; i += 2,k++,count+=2) {
+ if(GetNextTwoChar(patchbuffer,patchlen,&filepos,Byte) == A_ERROR) {
+ return A_ERROR;
+ }
+ data = A_STRTOUL(Byte, NULL, 16);
+ RamPatch[j].Data[k] = (data & 0xFF);
+
+
+ }
+ return A_OK;
+}
+
+
+/********************/
+A_STATUS AthDoParsePS(A_UCHAR *srcbuffer, A_UINT32 srclen)
+{
+ A_STATUS status;
+ int i;
+ A_BOOL BDADDR_Present = A_ERROR;
+
+ Tag_Count = 0;
+
+ Total_tag_lenght = 0;
+ BDADDR = FALSE;
+
+
+ status = A_ERROR;
+
+ if(NULL != srcbuffer && srclen != 0)
+ {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("File Open Operation Successful\n"));
+
+ status = AthParseFilesUnified(srcbuffer,srclen,MB_FILEFORMAT_PATCH);
+ }
+
+
+
+ if(Tag_Count == 0){
+ Total_tag_lenght = 10;
+
+ }
+ else{
+ for(i=0; i<Tag_Count; i++){
+ if(PsTagEntry[i].TagId == 1){
+ BDADDR_Present = A_OK;
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR is present in Patch File \r\n"));
+
+ }
+ if(PsTagEntry[i].TagLen % 2 == 1){
+ Total_tag_lenght = Total_tag_lenght + PsTagEntry[i].TagLen + 1;
+ }
+ else{
+ Total_tag_lenght = Total_tag_lenght + PsTagEntry[i].TagLen;
+ }
+
+ }
+ }
+
+ if(Tag_Count > 0 && !BDADDR_Present){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR is not present adding 10 extra bytes \r\n"));
+ Total_tag_lenght=Total_tag_lenght + 10;
+ }
+ Total_tag_lenght = Total_tag_lenght+ 10 + (Tag_Count*4);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Total Length %d\n",Total_tag_lenght));
+
+
+ return status;
+}
+char * AthGetLine(char * buffer, int maxlen, A_UCHAR *srcbuffer,A_UINT32 len,A_UINT32 *pos)
+{
+
+ int count;
+ static short flag;
+ char CharRead;
+ count = 0;
+ flag = A_ERROR;
+
+ do
+ {
+ CharRead = AthReadChar(srcbuffer,len,pos);
+ if( CharRead == '\0' ) {
+ buffer[count+1] = '\0';
+ if(count == 0) {
+ return NULL;
+ }
+ else {
+ return buffer;
+ }
+ }
+
+ if(CharRead == 13) {
+ } else if(CharRead == 10) {
+ buffer[count] ='\0';
+ flag = A_ERROR;
+ return buffer;
+ }else {
+ buffer[count++] = CharRead;
+ }
+
+ }
+ while(count < maxlen-1 && CharRead != '\0');
+ buffer[count] = '\0';
+
+ return buffer;
+}
+
+static void LoadHeader(A_UCHAR *HCI_PS_Command,A_UCHAR opcode,int length,int index){
+
+ HCI_PS_Command[0]= 0x0B;
+ HCI_PS_Command[1]= 0xFC;
+ HCI_PS_Command[2]= length + 4;
+ HCI_PS_Command[3]= opcode;
+ HCI_PS_Command[4]= (index & 0xFF);
+ HCI_PS_Command[5]= ((index>>8) & 0xFF);
+ HCI_PS_Command[6]= length;
+}
+
+/////////////////////////
+//
+int AthCreateCommandList(PSCmdPacket **HciPacketList, A_UINT32 *numPackets)
+{
+
+ A_UINT8 count;
+ A_UINT32 NumcmdEntry = 0;
+
+ A_UINT32 Crc = 0;
+ *numPackets = 0;
+
+
+ if(Patch_Count > 0)
+ Crc |= RAM_PATCH_REGION;
+ if(Tag_Count > 0)
+ Crc |= RAM_PS_REGION;
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("PS Thread Started CRC %x Patch Count %d Tag Count %d \n",Crc,Patch_Count,Tag_Count));
+
+ if(Patch_Count || Tag_Count ){
+ NumcmdEntry+=(2 + Patch_Count + Tag_Count); /* CRC Packet + PS Reset Packet + Patch List + PS List*/
+ if(Patch_Count > 0) {
+ NumcmdEntry++; /* Patch Enable Command */
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Num Cmd Entries %d Size %d \r\n",NumcmdEntry,(A_UINT32)sizeof(PSCmdPacket) * NumcmdEntry));
+ (*HciPacketList) = A_MALLOC(sizeof(PSCmdPacket) * NumcmdEntry);
+ if(NULL == *HciPacketList) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("memory allocation failed \r\n"));
+ }
+ AthPSCreateHCICommand(PS_VERIFY_CRC,Crc,*HciPacketList,numPackets);
+ if(Patch_Count > 0){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** Write Patch**** \r\n"));
+ AthPSCreateHCICommand(WRITE_PATCH,Patch_Count,*HciPacketList,numPackets);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** Enable Patch**** \r\n"));
+ AthPSCreateHCICommand(ENABLE_PATCH,0,*HciPacketList,numPackets);
+ }
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** PS Reset**** %d[0x%x] \r\n",PS_RAM_SIZE,PS_RAM_SIZE));
+ AthPSCreateHCICommand(PS_RESET,PS_RAM_SIZE,*HciPacketList,numPackets);
+ if(Tag_Count > 0){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** PS Write**** \r\n"));
+ AthPSCreateHCICommand(PS_WRITE,Tag_Count,*HciPacketList,numPackets);
+ }
+ }
+ if(!BDADDR){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR not present \r\n"));
+
+ }
+ for(count = 0; count < Patch_Count; count++) {
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing Patch Buffer %d \r\n",count));
+ A_FREE(RamPatch[Patch_Count].Data);
+ }
+
+ for(count = 0; count < Tag_Count; count++) {
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing PS Buffer %d \r\n",count));
+ A_FREE(PsTagEntry[count].TagData);
+ }
+
+/*
+ * SDIO Transport uses synchronous mode of data transfer
+ * So, AthPSOperations() call returns only after receiving the
+ * command complete event.
+ */
+ return *numPackets;
+}
+
+
+////////////////////////
+
+/////////////
+static A_STATUS AthPSCreateHCICommand(A_UCHAR Opcode, A_UINT32 Param1,PSCmdPacket *PSPatchPacket,A_UINT32 *index)
+{
+ A_UCHAR *HCI_PS_Command;
+ A_UINT32 Length;
+ int i,j;
+
+ switch(Opcode)
+ {
+ case WRITE_PATCH:
+
+
+ for(i=0;i< Param1;i++){
+
+ HCI_PS_Command = (A_UCHAR *) A_MALLOC(RamPatch[i].Len+HCI_COMMAND_HEADER);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Allocated Buffer Size %d\n",RamPatch[i].Len+HCI_COMMAND_HEADER));
+ if(HCI_PS_Command == NULL){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
+ return A_ERROR;
+ }
+ memset (HCI_PS_Command, 0, RamPatch[i].Len+HCI_COMMAND_HEADER);
+ LoadHeader(HCI_PS_Command,Opcode,RamPatch[i].Len,i);
+ for(j=0;j<RamPatch[i].Len;j++){
+ HCI_PS_Command[HCI_COMMAND_HEADER+j]=RamPatch[i].Data[j];
+ }
+ PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
+ PSPatchPacket[*index].packetLen = RamPatch[i].Len+HCI_COMMAND_HEADER;
+ (*index)++;
+
+
+ }
+
+ break;
+
+ case ENABLE_PATCH:
+
+
+ Length = 0;
+ i= 0;
+ HCI_PS_Command = (A_UCHAR *) A_MALLOC(Length+HCI_COMMAND_HEADER);
+ if(HCI_PS_Command == NULL){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
+ return A_ERROR;
+ }
+
+ memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER);
+ LoadHeader(HCI_PS_Command,Opcode,Length,i);
+ PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
+ PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER;
+ (*index)++;
+
+ break;
+
+ case PS_RESET:
+ Length = 0x06;
+ i=0;
+ HCI_PS_Command = (A_UCHAR *) A_MALLOC(Length+HCI_COMMAND_HEADER);
+ if(HCI_PS_Command == NULL){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
+ return A_ERROR;
+ }
+ memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER);
+ LoadHeader(HCI_PS_Command,Opcode,Length,i);
+ HCI_PS_Command[7]= 0x00;
+ HCI_PS_Command[Length+HCI_COMMAND_HEADER -2]= (Param1 & 0xFF);
+ HCI_PS_Command[Length+HCI_COMMAND_HEADER -1]= ((Param1 >> 8) & 0xFF);
+ PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
+ PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER;
+ (*index)++;
+
+ break;
+
+ case PS_WRITE:
+ for(i=0;i< Param1;i++){
+ if(PsTagEntry[i].TagId ==1)
+ BDADDR = TRUE;
+
+ HCI_PS_Command = (A_UCHAR *) A_MALLOC(PsTagEntry[i].TagLen+HCI_COMMAND_HEADER);
+ if(HCI_PS_Command == NULL){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
+ return A_ERROR;
+ }
+
+ memset (HCI_PS_Command, 0, PsTagEntry[i].TagLen+HCI_COMMAND_HEADER);
+ LoadHeader(HCI_PS_Command,Opcode,PsTagEntry[i].TagLen,PsTagEntry[i].TagId);
+
+ for(j=0;j<PsTagEntry[i].TagLen;j++){
+ HCI_PS_Command[HCI_COMMAND_HEADER+j]=PsTagEntry[i].TagData[j];
+ }
+
+ PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
+ PSPatchPacket[*index].packetLen = PsTagEntry[i].TagLen+HCI_COMMAND_HEADER;
+ (*index)++;
+
+ }
+
+ break;
+
+
+ case PS_VERIFY_CRC:
+ Length = 0x0;
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("VALUE of CRC:%d At index %d\r\n",Param1,*index));
+
+ HCI_PS_Command = (A_UCHAR *) A_MALLOC(Length+HCI_COMMAND_HEADER);
+ if(HCI_PS_Command == NULL){
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n"));
+ return A_ERROR;
+ }
+ memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER);
+ LoadHeader(HCI_PS_Command,Opcode,Length,Param1);
+
+ PSPatchPacket[*index].Hcipacket = HCI_PS_Command;
+ PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER;
+ (*index)++;
+
+ break;
+
+ case CHANGE_BDADDR:
+ break;
+ }
+ return A_OK;
+}
+A_STATUS AthFreeCommandList(PSCmdPacket **HciPacketList, A_UINT32 numPackets)
+{
+ int i;
+ if(*HciPacketList == NULL) {
+ return A_ERROR;
+ }
+ for(i = 0; i < numPackets;i++) {
+ A_FREE((*HciPacketList)[i].Hcipacket);
+ }
+ A_FREE(*HciPacketList);
+ return A_OK;
+}
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h
new file mode 100644
index 000000000000..007b0eb950d2
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h
@@ -0,0 +1,127 @@
+//------------------------------------------------------------------------------
+//
+// Copyright (c) 2004-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.
+//
+//
+//------------------------------------------------------------------------------
+//
+// This file is the include file for Atheros PS and patch parser.
+// It implements APIs to parse data buffer with patch and PS information and convert it to HCI commands.
+//
+
+#ifndef __AR3KPSPARSER_H
+#define __AR3KPSPARSER_H
+
+
+
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "athdefs.h"
+#ifdef HCI_TRANSPORT_SDIO
+#include "a_config.h"
+#include "a_types.h"
+#include "a_osapi.h"
+#define ATH_MODULE_NAME misc
+#include "a_debug.h"
+#include "common_drv.h"
+#include "hci_transport_api.h"
+#include "ar3kconfig.h"
+#else
+#ifndef A_PRINTF
+#define A_PRINTF(args...) printk(KERN_ALERT args)
+#endif /* A_PRINTF */
+#include "debug_linux.h"
+
+/* Helper data type declaration */
+
+#ifndef A_UINT32
+#define A_UCHAR unsigned char
+#define A_UINT32 unsigned long
+#define A_UINT16 unsigned short
+#define A_UINT8 unsigned char
+#define A_BOOL unsigned char
+#endif /* A_UINT32 */
+
+#define ATH_DEBUG_ERR (1 << 0)
+#define ATH_DEBUG_WARN (1 << 1)
+#define ATH_DEBUG_INFO (1 << 2)
+
+
+
+#define FALSE 0
+#define TRUE 1
+
+#ifndef A_MALLOC
+#define A_MALLOC(size) kmalloc((size),GFP_KERNEL)
+#endif /* A_MALLOC */
+
+
+#ifndef A_FREE
+#define A_FREE(addr) kfree((addr))
+#endif /* A_MALLOC */
+#endif /* HCI_TRANSPORT_UART */
+
+/* String manipulation APIs */
+#ifndef A_STRTOUL
+#define A_STRTOUL simple_strtoul
+#endif /* A_STRTOL */
+
+#ifndef A_STRTOL
+#define A_STRTOL simple_strtol
+#endif /* A_STRTOL */
+
+
+/* The maximum number of bytes possible in a patch entry */
+#define MAX_PATCH_SIZE 20000
+
+/* Maximum HCI packets that will be formed from the Patch file */
+#define MAX_NUM_PATCH_ENTRY (MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1
+
+
+
+
+
+
+
+typedef struct PSCmdPacket
+{
+ A_UCHAR *Hcipacket;
+ int packetLen;
+} PSCmdPacket;
+
+/* Parses a Patch information buffer and store it in global structure */
+A_STATUS AthDoParsePatch(A_UCHAR *, A_UINT32);
+
+/* parses a PS information buffer and stores it in a global structure */
+A_STATUS AthDoParsePS(A_UCHAR *, A_UINT32);
+
+/*
+ * Uses the output of Both AthDoParsePS and AthDoParsePatch APIs to form HCI command array with
+ * all the PS and patch commands.
+ * The list will have the below mentioned commands in order.
+ * CRC command packet
+ * Download patch command(s)
+ * Enable patch Command
+ * PS Reset Command
+ * PS Tag Command(s)
+ *
+ */
+int AthCreateCommandList(PSCmdPacket **, A_UINT32 *);
+
+/* Cleanup the dynamically allicated HCI command list */
+A_STATUS AthFreeCommandList(PSCmdPacket **HciPacketList, A_UINT32 numPackets);
+#endif /* __AR3KPSPARSER_H */
diff --git a/drivers/staging/ath6kl/miscdrv/common_drv.c b/drivers/staging/ath6kl/miscdrv/common_drv.c
new file mode 100644
index 000000000000..6754fde467de
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/common_drv.c
@@ -0,0 +1,1027 @@
+//------------------------------------------------------------------------------
+// <copyright file="common_drv.c" company="Atheros">
+// Copyright (c) 2004-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.
+//
+//
+//------------------------------------------------------------------------------
+//==============================================================================
+// Author(s): ="Atheros"
+//==============================================================================
+
+#include "a_config.h"
+#include "athdefs.h"
+#include "a_types.h"
+
+#include "AR6002/hw2.0/hw/mbox_host_reg.h"
+#include "AR6002/hw2.0/hw/apb_map.h"
+#include "AR6002/hw2.0/hw/si_reg.h"
+#include "AR6002/hw2.0/hw/gpio_reg.h"
+#include "AR6002/hw2.0/hw/rtc_reg.h"
+#include "AR6002/hw2.0/hw/vmc_reg.h"
+#include "AR6002/hw2.0/hw/mbox_reg.h"
+
+#include "a_osapi.h"
+#include "targaddrs.h"
+#include "hif.h"
+#include "htc_api.h"
+#include "wmi.h"
+#include "bmi.h"
+#include "bmi_msg.h"
+#include "common_drv.h"
+#define ATH_MODULE_NAME misc
+#include "a_debug.h"
+#include "ar6000_diag.h"
+
+static ATH_DEBUG_MODULE_DBG_INFO *g_pModuleInfoHead = NULL;
+static A_MUTEX_T g_ModuleListLock;
+static A_BOOL g_ModuleDebugInit = FALSE;
+
+#ifdef ATH_DEBUG_MODULE
+
+ATH_DEBUG_INSTANTIATE_MODULE_VAR(misc,
+ "misc",
+ "Common and misc APIs",
+ ATH_DEBUG_MASK_DEFAULTS,
+ 0,
+ NULL);
+
+#endif
+
+#define HOST_INTEREST_ITEM_ADDRESS(target, item) \
+ ((((target) == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \
+ (((target) == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : 0)))
+
+
+#define AR6001_LOCAL_COUNT_ADDRESS 0x0c014080
+#define AR6002_LOCAL_COUNT_ADDRESS 0x00018080
+#define AR6003_LOCAL_COUNT_ADDRESS 0x00018080
+#define CPU_DBG_SEL_ADDRESS 0x00000483
+#define CPU_DBG_ADDRESS 0x00000484
+
+static A_UINT8 custDataAR6002[AR6002_CUST_DATA_SIZE];
+static A_UINT8 custDataAR6003[AR6003_CUST_DATA_SIZE];
+
+/* Compile the 4BYTE version of the window register setup routine,
+ * This mitigates host interconnect issues with non-4byte aligned bus requests, some
+ * interconnects use bus adapters that impose strict limitations.
+ * Since diag window access is not intended for performance critical operations, the 4byte mode should
+ * be satisfactory even though it generates 4X the bus activity. */
+
+#ifdef USE_4BYTE_REGISTER_ACCESS
+
+ /* set the window address register (using 4-byte register access ). */
+A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address)
+{
+ A_STATUS status;
+ A_UINT8 addrValue[4];
+ A_INT32 i;
+
+ /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
+ * last to initiate the access cycle */
+
+ for (i = 1; i <= 3; i++) {
+ /* fill the buffer with the address byte value we want to hit 4 times*/
+ addrValue[0] = ((A_UINT8 *)&Address)[i];
+ addrValue[1] = addrValue[0];
+ addrValue[2] = addrValue[0];
+ addrValue[3] = addrValue[0];
+
+ /* hit each byte of the register address with a 4-byte write operation to the same address,
+ * this is a harmless operation */
+ status = HIFReadWrite(hifDevice,
+ RegisterAddr+i,
+ addrValue,
+ 4,
+ HIF_WR_SYNC_BYTE_FIX,
+ NULL);
+ if (status != A_OK) {
+ break;
+ }
+ }
+
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
+ Address, RegisterAddr));
+ return status;
+ }
+
+ /* write the address register again, this time write the whole 4-byte value.
+ * The effect here is that the LSB write causes the cycle to start, the extra
+ * 3 byte write to bytes 1,2,3 has no effect since we are writing the same values again */
+ status = HIFReadWrite(hifDevice,
+ RegisterAddr,
+ (A_UCHAR *)(&Address),
+ 4,
+ HIF_WR_SYNC_BYTE_INC,
+ NULL);
+
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
+ Address, RegisterAddr));
+ return status;
+ }
+
+ return A_OK;
+
+
+
+}
+
+
+#else
+
+ /* set the window address register */
+A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address)
+{
+ A_STATUS status;
+
+ /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written
+ * last to initiate the access cycle */
+ status = HIFReadWrite(hifDevice,
+ RegisterAddr+1, /* write upper 3 bytes */
+ ((A_UCHAR *)(&Address))+1,
+ sizeof(A_UINT32)-1,
+ HIF_WR_SYNC_BYTE_INC,
+ NULL);
+
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n",
+ RegisterAddr, Address));
+ return status;
+ }
+
+ /* write the LSB of the register, this initiates the operation */
+ status = HIFReadWrite(hifDevice,
+ RegisterAddr,
+ (A_UCHAR *)(&Address),
+ sizeof(A_UINT8),
+ HIF_WR_SYNC_BYTE_INC,
+ NULL);
+
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n",
+ RegisterAddr, Address));
+ return status;
+ }
+
+ return A_OK;
+}
+
+#endif
+
+/*
+ * Read from the AR6000 through its diagnostic window.
+ * No cooperation from the Target is required for this.
+ */
+A_STATUS
+ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data)
+{
+ A_STATUS status;
+
+ /* set window register to start read cycle */
+ status = ar6000_SetAddressWindowRegister(hifDevice,
+ WINDOW_READ_ADDR_ADDRESS,
+ *address);
+
+ if (status != A_OK) {
+ return status;
+ }
+
+ /* read the data */
+ status = HIFReadWrite(hifDevice,
+ WINDOW_DATA_ADDRESS,
+ (A_UCHAR *)data,
+ sizeof(A_UINT32),
+ HIF_RD_SYNC_BYTE_INC,
+ NULL);
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from WINDOW_DATA_ADDRESS\n"));
+ return status;
+ }
+
+ return status;
+}
+
+
+/*
+ * Write to the AR6000 through its diagnostic window.
+ * No cooperation from the Target is required for this.
+ */
+A_STATUS
+ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data)
+{
+ A_STATUS status;
+
+ /* set write data */
+ status = HIFReadWrite(hifDevice,
+ WINDOW_DATA_ADDRESS,
+ (A_UCHAR *)data,
+ sizeof(A_UINT32),
+ HIF_WR_SYNC_BYTE_INC,
+ NULL);
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data));
+ return status;
+ }
+
+ /* set window register, which starts the write cycle */
+ return ar6000_SetAddressWindowRegister(hifDevice,
+ WINDOW_WRITE_ADDR_ADDRESS,
+ *address);
+ }
+
+A_STATUS
+ar6000_ReadDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
+ A_UCHAR *data, A_UINT32 length)
+{
+ A_UINT32 count;
+ A_STATUS status = A_OK;
+
+ for (count = 0; count < length; count += 4, address += 4) {
+ if ((status = ar6000_ReadRegDiag(hifDevice, &address,
+ (A_UINT32 *)&data[count])) != A_OK)
+ {
+ break;
+ }
+ }
+
+ return status;
+}
+
+A_STATUS
+ar6000_WriteDataDiag(HIF_DEVICE *hifDevice, A_UINT32 address,
+ A_UCHAR *data, A_UINT32 length)
+{
+ A_UINT32 count;
+ A_STATUS status = A_OK;
+
+ for (count = 0; count < length; count += 4, address += 4) {
+ if ((status = ar6000_WriteRegDiag(hifDevice, &address,
+ (A_UINT32 *)&data[count])) != A_OK)
+ {
+ break;
+ }
+ }
+
+ return status;
+}
+
+A_STATUS
+ar6k_ReadTargetRegister(HIF_DEVICE *hifDevice, int regsel, A_UINT32 *regval)
+{
+ A_STATUS status;
+ A_UCHAR vals[4];
+ A_UCHAR register_selection[4];
+
+ register_selection[0] = register_selection[1] = register_selection[2] = register_selection[3] = (regsel & 0xff);
+ status = HIFReadWrite(hifDevice,
+ CPU_DBG_SEL_ADDRESS,
+ register_selection,
+ 4,
+ HIF_WR_SYNC_BYTE_FIX,
+ NULL);
+
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write CPU_DBG_SEL (%d)\n", regsel));
+ return status;
+ }
+
+ status = HIFReadWrite(hifDevice,
+ CPU_DBG_ADDRESS,
+ (A_UCHAR *)vals,
+ sizeof(vals),
+ HIF_RD_SYNC_BYTE_INC,
+ NULL);
+ if (status != A_OK) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from CPU_DBG_ADDRESS\n"));
+ return status;
+ }
+
+ *regval = vals[0]<<0 | vals[1]<<8 | vals[2]<<16 | vals[3]<<24;
+
+ return status;
+}
+
+void
+ar6k_FetchTargetRegs(HIF_DEVICE *hifDevice, A_UINT32 *targregs)
+{
+ int i;
+ A_UINT32 val;
+
+ for (i=0; i<AR6003_FETCH_TARG_REGS_COUNT; i++) {
+ val=0xffffffff;
+ (void)ar6k_ReadTargetRegister(hifDevice, i, &val);
+ targregs[i] = val;
+ }
+}
+
+#if 0
+static A_STATUS
+_do_write_diag(HIF_DEVICE *hifDevice, A_UINT32 addr, A_UINT32 value)
+{
+ A_STATUS status;
+
+ status = ar6000_WriteRegDiag(hifDevice, &addr, &value);
+ if (status != A_OK)
+ {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n"));
+ }
+
+ return status;
+}
+#endif
+
+
+/*
+ * Delay up to wait_msecs millisecs to allow Target to enter BMI phase,
+ * which is a good sign that it's alive and well. This is used after
+ * explicitly forcing the Target to reset.
+ *
+ * The wait_msecs time should be sufficiently long to cover any reasonable
+ * boot-time delay. For instance, AR6001 firmware allow one second for a
+ * low frequency crystal to settle before it calibrates the refclk frequency.
+ *
+ * TBD: Might want to add special handling for AR6K_OPTION_BMI_DISABLE.
+ */
+#if 0
+static A_STATUS
+_delay_until_target_alive(HIF_DEVICE *hifDevice, A_INT32 wait_msecs, A_UINT32 TargetType)
+{
+ A_INT32 actual_wait;
+ A_INT32 i;
+ A_UINT32 address;
+
+ actual_wait = 0;
+
+ /* Hardcode the address of LOCAL_COUNT_ADDRESS based on the target type */
+ if (TargetType == TARGET_TYPE_AR6002) {
+ address = AR6002_LOCAL_COUNT_ADDRESS;
+ } else if (TargetType == TARGET_TYPE_AR6003) {
+ address = AR6003_LOCAL_COUNT_ADDRESS;
+ } else {
+ A_ASSERT(0);
+ }
+ address += 0x10;
+ for (i=0; actual_wait < wait_msecs; i++) {
+ A_UINT32 data;
+
+ A_MDELAY(100);
+ actual_wait += 100;
+
+ data = 0;
+ if (ar6000_ReadRegDiag(hifDevice, &address, &data) != A_OK) {
+ return A_ERROR;
+ }
+
+ if (data != 0) {
+ /* No need to wait longer -- we have a BMI credit */
+ return A_OK;
+ }
+ }
+ return A_ERROR; /* timed out */
+}
+#endif
+
+#define AR6001_RESET_CONTROL_ADDRESS 0x0C000000
+#define AR6002_RESET_CONTROL_ADDRESS 0x00004000
+#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
+/* reset device */
+A_STATUS ar6000_reset_device(HIF_DEVICE *hifDevice, A_UINT32 TargetType, A_BOOL waitForCompletion, A_BOOL coldReset)
+{
+ A_STATUS status = A_OK;
+ A_UINT32 address;
+ A_UINT32 data;
+
+ do {
+// Workaround BEGIN
+ // address = RESET_CONTROL_ADDRESS;
+
+ if (coldReset) {
+ data = RESET_CONTROL_COLD_RST_MASK;
+ }
+ else {
+ data = RESET_CONTROL_MBOX_RST_MASK;
+ }
+
+ /* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */
+ if (TargetType == TARGET_TYPE_AR6002) {
+ address = AR6002_RESET_CONTROL_ADDRESS;
+ } else if (TargetType == TARGET_TYPE_AR6003) {
+ address = AR6003_RESET_CONTROL_ADDRESS;
+ } else {
+ A_ASSERT(0);
+ }
+
+
+ status = ar6000_WriteRegDiag(hifDevice, &address, &data);
+
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ if (!waitForCompletion) {
+ break;
+ }
+
+#if 0
+ /* Up to 2 second delay to allow things to settle down */
+ (void)_delay_until_target_alive(hifDevice, 2000, TargetType);
+
+ /*
+ * Read back the RESET CAUSE register to ensure that the cold reset
+ * went through.
+ */
+
+ // address = RESET_CAUSE_ADDRESS;
+ /* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */
+ if (TargetType == TARGET_TYPE_AR6002) {
+ address = 0x000040C0;
+ } else if (TargetType == TARGET_TYPE_AR6003) {
+ address = 0x000040C0;
+ } else {
+ A_ASSERT(0);
+ }
+
+ data = 0;
+ status = ar6000_ReadRegDiag(hifDevice, &address, &data);
+
+ if (A_FAILED(status)) {
+ break;
+ }
+
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data));
+ data &= RESET_CAUSE_LAST_MASK;
+ if (data != 2) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n"));
+ }
+#endif
+// Workaroud END
+
+ } while (FALSE);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n"));
+ }
+
+ return A_OK;
+}
+
+/* This should be called in BMI phase after firmware is downloaded */
+void
+ar6000_copy_cust_data_from_target(HIF_DEVICE *hifDevice, A_UINT32 TargetType)
+{
+ A_UINT32 eepHeaderAddr;
+ A_UINT8 AR6003CustDataShadow[AR6003_CUST_DATA_SIZE+4];
+ A_INT32 i;
+
+ if (BMIReadMemory(hifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_board_data),
+ (A_UCHAR *)&eepHeaderAddr,
+ 4)!= A_OK)
+ {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadMemory for reading board data address failed \n"));
+ return;
+ }
+
+ if (TargetType == TARGET_TYPE_AR6003) {
+ eepHeaderAddr += 36; /* AR6003 customer data section offset is 37 */
+
+ for (i=0; i<AR6003_CUST_DATA_SIZE+4; i+=4){
+ if (BMIReadSOCRegister(hifDevice, eepHeaderAddr, (A_UINT32 *)&AR6003CustDataShadow[i])!= A_OK) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadSOCRegister () failed \n"));
+ return ;
+ }
+ eepHeaderAddr +=4;
+ }
+
+ memcpy(custDataAR6003, AR6003CustDataShadow+1, AR6003_CUST_DATA_SIZE);
+ }
+
+ if (TargetType == TARGET_TYPE_AR6002) {
+ eepHeaderAddr += 64; /* AR6002 customer data sectioin offset is 64 */
+
+ for (i=0; i<AR6002_CUST_DATA_SIZE; i+=4){
+ if (BMIReadSOCRegister(hifDevice, eepHeaderAddr, (A_UINT32 *)&custDataAR6002[i])!= A_OK) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadSOCRegister () failed \n"));
+ return ;
+ }
+ eepHeaderAddr +=4;
+ }
+ }
+
+ return;
+}
+
+/* This is the function to call when need to use the cust data */
+A_UINT8 *
+ar6000_get_cust_data_buffer(A_UINT32 TargetType)
+{
+ if (TargetType == TARGET_TYPE_AR6003)
+ return custDataAR6003;
+
+ if (TargetType == TARGET_TYPE_AR6002)
+ return custDataAR6002;
+
+ return NULL;
+}
+
+#define REG_DUMP_COUNT_AR6001 38 /* WORDs, derived from AR600x_regdump.h */
+#define REG_DUMP_COUNT_AR6002 60
+#define REG_DUMP_COUNT_AR6003 60
+#define REGISTER_DUMP_LEN_MAX 60
+#if REG_DUMP_COUNT_AR6001 > REGISTER_DUMP_LEN_MAX
+#error "REG_DUMP_COUNT_AR6001 too large"
+#endif
+#if REG_DUMP_COUNT_AR6002 > REGISTER_DUMP_LEN_MAX
+#error "REG_DUMP_COUNT_AR6002 too large"
+#endif
+#if REG_DUMP_COUNT_AR6003 > REGISTER_DUMP_LEN_MAX
+#error "REG_DUMP_COUNT_AR6003 too large"
+#endif
+
+
+void ar6000_dump_target_assert_info(HIF_DEVICE *hifDevice, A_UINT32 TargetType)
+{
+ A_UINT32 address;
+ A_UINT32 regDumpArea = 0;
+ A_STATUS status;
+ A_UINT32 regDumpValues[REGISTER_DUMP_LEN_MAX];
+ A_UINT32 regDumpCount = 0;
+ A_UINT32 i;
+
+ do {
+
+ /* the reg dump pointer is copied to the host interest area */
+ address = HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_failure_state);
+ address = TARG_VTOP(TargetType, address);
+
+ if (TargetType == TARGET_TYPE_AR6002) {
+ regDumpCount = REG_DUMP_COUNT_AR6002;
+ } else if (TargetType == TARGET_TYPE_AR6003) {
+ regDumpCount = REG_DUMP_COUNT_AR6003;
+ } else {
+ A_ASSERT(0);
+ }
+
+ /* read RAM location through diagnostic window */
+ status = ar6000_ReadRegDiag(hifDevice, &address, &regDumpArea);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get ptr to register dump area \n"));
+ break;
+ }
+
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Location of register dump data: 0x%X \n",regDumpArea));
+
+ if (regDumpArea == 0) {
+ /* no reg dump */
+ break;
+ }
+
+ regDumpArea = TARG_VTOP(TargetType, regDumpArea);
+
+ /* fetch register dump data */
+ status = ar6000_ReadDataDiag(hifDevice,
+ regDumpArea,
+ (A_UCHAR *)&regDumpValues[0],
+ regDumpCount * (sizeof(A_UINT32)));
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get register dump \n"));
+ break;
+ }
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Register Dump: \n"));
+
+ for (i = 0; i < regDumpCount; i++) {
+ //ATHR_DISPLAY_MSG (_T(" %d : 0x%8.8X \n"), i, regDumpValues[i]);
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" %d : 0x%8.8X \n",i, regDumpValues[i]));
+
+#ifdef UNDER_CE
+ /*
+ * For Every logPrintf() Open the File so that in case of Crashes
+ * We will have until the Last Message Flushed on to the File
+ * So use logPrintf Sparingly..!!
+ */
+ tgtassertPrintf (ATH_DEBUG_TRC," %d: 0x%8.8X \n",i, regDumpValues[i]);
+#endif
+ }
+
+ } while (FALSE);
+
+}
+
+/* set HTC/Mbox operational parameters, this can only be called when the target is in the
+ * BMI phase */
+A_STATUS ar6000_set_htc_params(HIF_DEVICE *hifDevice,
+ A_UINT32 TargetType,
+ A_UINT32 MboxIsrYieldValue,
+ A_UINT8 HtcControlBuffers)
+{
+ A_STATUS status;
+ A_UINT32 blocksizes[HTC_MAILBOX_NUM_MAX];
+
+ do {
+ /* get the block sizes */
+ status = HIFConfigureDevice(hifDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
+ blocksizes, sizeof(blocksizes));
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR,("Failed to get block size info from HIF layer...\n"));
+ break;
+ }
+ /* note: we actually get the block size for mailbox 1, for SDIO the block
+ * size on mailbox 0 is artificially set to 1 */
+ /* must be a power of 2 */
+ A_ASSERT((blocksizes[1] & (blocksizes[1] - 1)) == 0);
+
+ if (HtcControlBuffers != 0) {
+ /* set override for number of control buffers to use */
+ blocksizes[1] |= ((A_UINT32)HtcControlBuffers) << 16;
+ }
+
+ /* set the host interest area for the block size */
+ status = BMIWriteMemory(hifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz),
+ (A_UCHAR *)&blocksizes[1],
+ 4);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for IO block size failed \n"));
+ break;
+ }
+
+ AR_DEBUG_PRINTF(ATH_LOG_INF,("Block Size Set: %d (target address:0x%X)\n",
+ blocksizes[1], HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz)));
+
+ if (MboxIsrYieldValue != 0) {
+ /* set the host interest area for the mbox ISR yield limit */
+ status = BMIWriteMemory(hifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_isr_yield_limit),
+ (A_UCHAR *)&MboxIsrYieldValue,
+ 4);
+
+ if (A_FAILED(status)) {
+ AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for yield limit failed \n"));
+ break;
+ }
+ }
+
+ } while (FALSE);
+
+ return status;
+}
+
+
+static A_STATUS prepare_ar6002(HIF_DEVICE *hifDevice, A_UINT32 TargetVersion)
+{
+ A_STATUS status = A_OK;
+
+ /* placeholder */
+
+ return status;
+}
+
+static A_STATUS prepare_ar6003(HIF_DEVICE *hifDevice, A_UINT32 TargetVersion)
+{
+ A_STATUS status = A_OK;
+
+ /* placeholder */
+
+ return status;
+}
+
+/* this function assumes the caller has already initialized the BMI APIs */
+A_STATUS ar6000_prepare_target(HIF_DEVICE *hifDevice,
+ A_UINT32 TargetType,
+ A_UINT32 TargetVersion)
+{
+ if (TargetType == TARGET_TYPE_AR6002) {
+ /* do any preparations for AR6002 devices */
+ return prepare_ar6002(hifDevice,TargetVersion);
+ } else if (TargetType == TARGET_TYPE_AR6003) {
+ return prepare_ar6003(hifDevice,TargetVersion);
+ }
+
+ return A_OK;
+}
+
+#if defined(CONFIG_AR6002_REV1_FORCE_HOST)
+/*
+ * Call this function just before the call to BMIInit
+ * in order to force* AR6002 rev 1.x firmware to detect a Host.
+ * THIS IS FOR USE ONLY WITH AR6002 REV 1.x.
+ * TBDXXX: Remove this function when REV 1.x is desupported.
+ */
+A_STATUS
+ar6002_REV1_reset_force_host (HIF_DEVICE *hifDevice)
+{
+ A_INT32 i;
+ struct forceROM_s {
+ A_UINT32 addr;
+ A_UINT32 data;
+ };
+ struct forceROM_s *ForceROM;
+ A_INT32 szForceROM;
+ A_STATUS status = A_OK;
+ A_UINT32 address;
+ A_UINT32 data;
+
+ /* Force AR6002 REV1.x to recognize Host presence.
+ *
+ * Note: Use RAM at 0x52df80..0x52dfa0 with ROM Remap entry 0
+ * so that this workaround functions with AR6002.war1.sh. We
+ * could fold that entire workaround into this one, but it's not
+ * worth the effort at this point. This workaround cannot be
+ * merged into the other workaround because this must be done
+ * before BMI.
+ */
+
+ static struct forceROM_s ForceROM_NEW[] = {
+ {0x52df80, 0x20f31c07},
+ {0x52df84, 0x92374420},
+ {0x52df88, 0x1d120c03},
+ {0x52df8c, 0xff8216f0},
+ {0x52df90, 0xf01d120c},
+ {0x52df94, 0x81004136},
+ {0x52df98, 0xbc9100bd},
+ {0x52df9c, 0x00bba100},
+
+ {0x00008000|MC_TCAM_TARGET_ADDRESS, 0x0012dfe0}, /* Use remap entry 0 */
+ {0x00008000|MC_TCAM_COMPARE_ADDRESS, 0x000e2380},
+ {0x00008000|MC_TCAM_MASK_ADDRESS, 0x00000000},
+ {0x00008000|MC_TCAM_VALID_ADDRESS, 0x00000001},
+
+ {0x00018000|(LOCAL_COUNT_ADDRESS+0x10), 0}, /* clear BMI credit counter */
+
+ {0x00004000|AR6002_RESET_CONTROL_ADDRESS, RESET_CONTROL_WARM_RST_MASK},
+ };
+
+ address = 0x004ed4b0; /* REV1 target software ID is stored here */
+ status = ar6000_ReadRegDiag(hifDevice, &address, &data);
+ if (A_FAILED(status) || (data != AR6002_VERSION_REV1)) {
+ return A_ERROR; /* Not AR6002 REV1 */
+ }
+
+ ForceROM = ForceROM_NEW;
+ szForceROM = sizeof(ForceROM_NEW)/sizeof(*ForceROM);
+
+ ATH_DEBUG_PRINTF (DBG_MISC_DRV, ATH_DEBUG_TRC, ("Force Target to recognize Host....\n"));
+ for (i = 0; i < szForceROM; i++)
+ {
+ if (ar6000_WriteRegDiag(hifDevice,
+ &ForceROM[i].addr,
+ &ForceROM[i].data) != A_OK)
+ {
+ ATH_DEBUG_PRINTF (DBG_MISC_DRV, ATH_DEBUG_TRC, ("Cannot force Target to recognize Host!\n"));
+ return A_ERROR;
+ }
+ }
+
+ A_MDELAY(1000);
+
+ return A_OK;
+}
+
+#endif /* CONFIG_AR6002_REV1_FORCE_HOST */
+
+void DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription)
+{
+ A_CHAR stream[60];
+ A_CHAR byteOffsetStr[10];
+ A_UINT32 i;
+ A_UINT16 offset, count, byteOffset;
+
+ A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length, pDescription);
+
+ count = 0;
+ offset = 0;
+ byteOffset = 0;
+ for(i = 0; i < length; i++) {
+ A_SPRINTF(stream + offset, "%2.2X ", buffer[i]);
+ count ++;
+ offset += 3;
+
+ if(count == 16) {
+ count = 0;
+ offset = 0;
+ A_SPRINTF(byteOffsetStr,"%4.4X",byteOffset);
+ A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
+ A_MEMZERO(stream, 60);
+ byteOffset += 16;
+ }
+ }
+
+ if(offset != 0) {
+ A_SPRINTF(byteOffsetStr,"%4.4X",byteOffset);
+ A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
+ }
+
+ A_PRINTF("<------------------------------------------------->\n");
+}
+
+void a_dump_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo)
+{
+ int i;
+ ATH_DEBUG_MASK_DESCRIPTION *pDesc;
+
+ if (pInfo == NULL) {
+ return;
+ }
+
+ pDesc = pInfo->pMaskDescriptions;
+
+ A_PRINTF("========================================================\n\n");
+ A_PRINTF("Module Debug Info => Name : %s \n", pInfo->ModuleName);
+ A_PRINTF(" => Descr. : %s \n", pInfo->ModuleDescription);
+ A_PRINTF("\n Current mask => 0x%8.8X \n", pInfo->CurrentMask);
+ A_PRINTF("\n Avail. Debug Masks :\n\n");
+
+ for (i = 0; i < pInfo->MaxDescriptions; i++,pDesc++) {
+ A_PRINTF(" => 0x%8.8X -- %s \n", pDesc->Mask, pDesc->Description);
+ }
+
+ if (0 == i) {
+ A_PRINTF(" => * none defined * \n");
+ }
+
+ A_PRINTF("\n Standard Debug Masks :\n\n");
+ /* print standard masks */
+ A_PRINTF(" => 0x%8.8X -- Errors \n", ATH_DEBUG_ERR);
+ A_PRINTF(" => 0x%8.8X -- Warnings \n", ATH_DEBUG_WARN);
+ A_PRINTF(" => 0x%8.8X -- Informational \n", ATH_DEBUG_INFO);
+ A_PRINTF(" => 0x%8.8X -- Tracing \n", ATH_DEBUG_TRC);
+ A_PRINTF("\n========================================================\n");
+
+}
+
+
+static ATH_DEBUG_MODULE_DBG_INFO *FindModule(A_CHAR *module_name)
+{
+ ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead;
+
+ if (!g_ModuleDebugInit) {
+ return NULL;
+ }
+
+ while (pInfo != NULL) {
+ /* TODO: need to use something other than strlen */
+ if (A_MEMCMP(pInfo->ModuleName,module_name,strlen(module_name)) == 0) {
+ break;
+ }
+ pInfo = pInfo->pNext;
+ }
+
+ return pInfo;
+}
+
+
+void a_register_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo)
+{
+ if (!g_ModuleDebugInit) {
+ return;
+ }
+
+ A_MUTEX_LOCK(&g_ModuleListLock);
+
+ if (!(pInfo->Flags & ATH_DEBUG_INFO_FLAGS_REGISTERED)) {
+ if (g_pModuleInfoHead == NULL) {
+ g_pModuleInfoHead = pInfo;
+ } else {
+ pInfo->pNext = g_pModuleInfoHead;
+ g_pModuleInfoHead = pInfo;
+ }
+ pInfo->Flags |= ATH_DEBUG_INFO_FLAGS_REGISTERED;
+ }
+
+ A_MUTEX_UNLOCK(&g_ModuleListLock);
+}
+
+void a_dump_module_debug_info_by_name(A_CHAR *module_name)
+{
+ ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead;
+
+ if (!g_ModuleDebugInit) {
+ return;
+ }
+
+ if (A_MEMCMP(module_name,"all",3) == 0) {
+ /* dump all */
+ while (pInfo != NULL) {
+ a_dump_module_debug_info(pInfo);
+ pInfo = pInfo->pNext;
+ }
+ return;
+ }
+
+ pInfo = FindModule(module_name);
+
+ if (pInfo != NULL) {
+ a_dump_module_debug_info(pInfo);
+ }
+
+}
+
+A_STATUS a_get_module_mask(A_CHAR *module_name, A_UINT32 *pMask)
+{
+ ATH_DEBUG_MODULE_DBG_INFO *pInfo = FindModule(module_name);
+
+ if (NULL == pInfo) {
+ return A_ERROR;
+ }
+
+ *pMask = pInfo->CurrentMask;
+ return A_OK;
+}
+
+A_STATUS a_set_module_mask(A_CHAR *module_name, A_UINT32 Mask)
+{
+ ATH_DEBUG_MODULE_DBG_INFO *pInfo = FindModule(module_name);
+
+ if (NULL == pInfo) {
+ return A_ERROR;
+ }
+
+ pInfo->CurrentMask = Mask;
+ A_PRINTF("Module %s, new mask: 0x%8.8X \n",module_name,pInfo->CurrentMask);
+ return A_OK;
+}
+
+
+void a_module_debug_support_init(void)
+{
+ if (g_ModuleDebugInit) {
+ return;
+ }
+ A_MUTEX_INIT(&g_ModuleListLock);
+ g_pModuleInfoHead = NULL;
+ g_ModuleDebugInit = TRUE;
+ A_REGISTER_MODULE_DEBUG_INFO(misc);
+}
+
+void a_module_debug_support_cleanup(void)
+{
+ ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead;
+ ATH_DEBUG_MODULE_DBG_INFO *pCur;
+
+ if (!g_ModuleDebugInit) {
+ return;
+ }
+
+ g_ModuleDebugInit = FALSE;
+
+ A_MUTEX_LOCK(&g_ModuleListLock);
+
+ while (pInfo != NULL) {
+ pCur = pInfo;
+ pInfo = pInfo->pNext;
+ pCur->pNext = NULL;
+ /* clear registered flag */
+ pCur->Flags &= ~ATH_DEBUG_INFO_FLAGS_REGISTERED;
+ }
+
+ A_MUTEX_UNLOCK(&g_ModuleListLock);
+
+ A_MUTEX_DELETE(&g_ModuleListLock);
+ g_pModuleInfoHead = NULL;
+}
+
+ /* can only be called during bmi init stage */
+A_STATUS ar6000_set_hci_bridge_flags(HIF_DEVICE *hifDevice,
+ A_UINT32 TargetType,
+ A_UINT32 Flags)
+{
+ A_STATUS status = A_OK;
+
+ do {
+
+ if (TargetType != TARGET_TYPE_AR6003) {
+ AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Target Type:%d, does not support HCI bridging! \n",
+ TargetType));
+ break;
+ }
+
+ /* set hci bridge flags */
+ status = BMIWriteMemory(hifDevice,
+ HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_hci_bridge_flags),
+ (A_UCHAR *)&Flags,
+ 4);
+
+
+ } while (FALSE);
+
+ return status;
+}
+
diff --git a/drivers/staging/ath6kl/miscdrv/credit_dist.c b/drivers/staging/ath6kl/miscdrv/credit_dist.c
new file mode 100644
index 000000000000..91316e0b109e
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/credit_dist.c
@@ -0,0 +1,418 @@
+//------------------------------------------------------------------------------
+// <copyright file="credit_dist.c" company="Atheros">
+// Copyright (c) 2004-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.
+//
+//
+//------------------------------------------------------------------------------
+//==============================================================================
+// Author(s): ="Atheros"
+//==============================================================================
+
+#include "a_config.h"
+#include "athdefs.h"
+#include "a_types.h"
+#include "a_osapi.h"
+#define ATH_MODULE_NAME misc
+#include "a_debug.h"
+#include "htc_api.h"
+#include "common_drv.h"
+
+/********* CREDIT DISTRIBUTION FUNCTIONS ******************************************/
+
+#define NO_VO_SERVICE 1 /* currently WMI only uses 3 data streams, so we leave VO service inactive */
+#define CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS 1
+
+#ifdef NO_VO_SERVICE
+#define DATA_SVCS_USED 3
+#else
+#define DATA_SVCS_USED 4
+#endif
+
+static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
+ HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
+
+static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
+ HTC_ENDPOINT_CREDIT_DIST *pEPDistList);
+
+/* reduce an ep's credits back to a set limit */
+static INLINE void ReduceCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
+ HTC_ENDPOINT_CREDIT_DIST *pEpDist,
+ int Limit)
+{
+ int credits;
+
+ /* set the new limit */
+ pEpDist->TxCreditsAssigned = Limit;
+
+ if (pEpDist->TxCredits <= Limit) {
+ return;
+ }
+
+ /* figure out how much to take away */
+ credits = pEpDist->TxCredits - Limit;
+ /* take them away */
+ pEpDist->TxCredits -= credits;
+ pCredInfo->CurrentFreeCredits += credits;
+}
+
+/* give an endpoint some credits from the free credit pool */
+#define GiveCredits(pCredInfo,pEpDist,credits) \
+{ \
+ (pEpDist)->TxCredits += (credits); \
+ (pEpDist)->TxCreditsAssigned += (credits); \
+ (pCredInfo)->CurrentFreeCredits -= (credits); \
+}
+
+
+/* default credit init callback.
+ * This function is called in the context of HTCStart() to setup initial (application-specific)
+ * credit distributions */
+static void ar6000_credit_init(void *Context,
+ HTC_ENDPOINT_CREDIT_DIST *pEPList,
+ int TotalCredits)
+{
+ HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
+ int count;
+ COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
+
+ pCredInfo->CurrentFreeCredits = TotalCredits;
+ pCredInfo->TotalAvailableCredits = TotalCredits;
+
+ pCurEpDist = pEPList;
+
+ /* run through the list and initialize */
+ while (pCurEpDist != NULL) {
+
+ /* set minimums for each endpoint */
+ pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg;
+
+#ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
+
+ if (TotalCredits > 4)
+ {
+ if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)){
+ /* assign at least min credits to lower than VO priority services */
+ GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
+ /* force active */
+ SET_EP_ACTIVE(pCurEpDist);
+ }
+ }
+
+#endif
+
+ if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
+ /* give control service some credits */
+ GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin);
+ /* control service is always marked active, it never goes inactive EVER */
+ SET_EP_ACTIVE(pCurEpDist);
+ } else if (pCurEpDist->ServiceID == WMI_DATA_BK_SVC) {
+ /* this is the lowest priority data endpoint, save this off for easy access */
+ pCredInfo->pLowestPriEpDist = pCurEpDist;
+ }
+
+ /* Streams have to be created (explicit | implicit)for all kinds
+ * of traffic. BE endpoints are also inactive in the beginning.
+ * When BE traffic starts it creates implicit streams that
+ * redistributes credits.
+ */
+
+ /* note, all other endpoints have minimums set but are initially given NO credits.
+ * Credits will be distributed as traffic activity demands */
+ pCurEpDist = pCurEpDist->pNext;
+ }
+
+ if (pCredInfo->CurrentFreeCredits <= 0) {
+ AR_DEBUG_PRINTF(ATH_LOG_INF, ("Not enough credits (%d) to do credit distributions \n", TotalCredits));
+ A_ASSERT(FALSE);
+ return;
+ }
+
+ /* reset list */
+ pCurEpDist = pEPList;
+ /* now run through the list and set max operating credit limits for everyone */
+ while (pCurEpDist != NULL) {
+ if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) {
+ /* control service max is just 1 max message */
+ pCurEpDist->TxCreditsNorm = pCurEpDist->TxCreditsPerMaxMsg;
+ } else {
+ /* for the remaining data endpoints, we assume that each TxCreditsPerMaxMsg are
+ * the same.
+ * We use a simple calculation here, we take the remaining credits and
+ * determine how many max messages this can cover and then set each endpoint's
+ * normal value equal to 3/4 this amount.
+ * */
+ count = (pCredInfo->CurrentFreeCredits/pCurEpDist->TxCreditsPerMaxMsg) * pCurEpDist->TxCreditsPerMaxMsg;
+ count = (count * 3) >> 2;
+ count = max(count,pCurEpDist->TxCreditsPerMaxMsg);
+ /* set normal */
+ pCurEpDist->TxCreditsNorm = count;
+
+ }
+ pCurEpDist = pCurEpDist->pNext;
+ }
+
+}
+
+
+/* default credit distribution callback
+ * This callback is invoked whenever endpoints require credit distributions.
+ * A lock is held while this function is invoked, this function shall NOT block.
+ * The pEPDistList is a list of distribution structures in prioritized order as
+ * defined by the call to the HTCSetCreditDistribution() api.
+ *
+ */
+static void ar6000_credit_distribute(void *Context,
+ HTC_ENDPOINT_CREDIT_DIST *pEPDistList,
+ HTC_CREDIT_DIST_REASON Reason)
+{
+ HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
+ COMMON_CREDIT_STATE_INFO *pCredInfo = (COMMON_CREDIT_STATE_INFO *)Context;
+
+ switch (Reason) {
+ case HTC_CREDIT_DIST_SEND_COMPLETE :
+ pCurEpDist = pEPDistList;
+ /* we are given the start of the endpoint distribution list.
+ * There may be one or more endpoints to service.
+ * Run through the list and distribute credits */
+ while (pCurEpDist != NULL) {
+
+ if (pCurEpDist->TxCreditsToDist > 0) {
+ /* return the credits back to the endpoint */
+ pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist;
+ /* always zero out when we are done */
+ pCurEpDist->TxCreditsToDist = 0;
+
+ if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) {
+ /* reduce to the assigned limit, previous credit reductions
+ * could have caused the limit to change */
+ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned);
+ }
+
+ if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) {
+ /* oversubscribed endpoints need to reduce back to normal */
+ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm);
+ }
+
+ if (!IS_EP_ACTIVE(pCurEpDist)) {
+ /* endpoint is inactive, now check for messages waiting for credits */
+ if (pCurEpDist->TxQueueDepth == 0) {
+ /* EP is inactive and there are no pending messages,
+ * reduce credits back to zero to recover credits */
+ ReduceCredits(pCredInfo, pCurEpDist, 0);
+ }
+ }
+ }
+
+ pCurEpDist = pCurEpDist->pNext;
+ }
+
+ break;
+
+ case HTC_CREDIT_DIST_ACTIVITY_CHANGE :
+ RedistributeCredits(pCredInfo,pEPDistList);
+ break;
+ case HTC_CREDIT_DIST_SEEK_CREDITS :
+ SeekCredits(pCredInfo,pEPDistList);
+ break;
+ case HTC_DUMP_CREDIT_STATE :
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Credit Distribution, total : %d, free : %d\n",
+ pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits));
+ break;
+ default:
+ break;
+
+ }
+
+ /* sanity checks done after each distribution action */
+ A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits);
+ A_ASSERT(pCredInfo->CurrentFreeCredits >= 0);
+
+}
+
+/* redistribute credits based on activity change */
+static void RedistributeCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
+ HTC_ENDPOINT_CREDIT_DIST *pEPDistList)
+{
+ HTC_ENDPOINT_CREDIT_DIST *pCurEpDist = pEPDistList;
+
+ /* walk through the list and remove credits from inactive endpoints */
+ while (pCurEpDist != NULL) {
+
+#ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
+
+ if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)) {
+ /* force low priority streams to always be active to retain their minimum credit distribution */
+ SET_EP_ACTIVE(pCurEpDist);
+ }
+#endif
+
+ if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) {
+ if (!IS_EP_ACTIVE(pCurEpDist)) {
+ if (pCurEpDist->TxQueueDepth == 0) {
+ /* EP is inactive and there are no pending messages, reduce credits back to zero */
+ ReduceCredits(pCredInfo, pCurEpDist, 0);
+ } else {
+ /* we cannot zero the credits assigned to this EP, but to keep
+ * the credits available for these leftover packets, reduce to
+ * a minimum */
+ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsMin);
+ }
+ }
+ }
+
+ /* NOTE in the active case, we do not need to do anything further,
+ * when an EP goes active and needs credits, HTC will call into
+ * our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */
+
+ pCurEpDist = pCurEpDist->pNext;
+ }
+
+}
+
+/* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */
+static void SeekCredits(COMMON_CREDIT_STATE_INFO *pCredInfo,
+ HTC_ENDPOINT_CREDIT_DIST *pEPDist)
+{
+ HTC_ENDPOINT_CREDIT_DIST *pCurEpDist;
+ int credits = 0;
+ int need;
+
+ do {
+
+ if (pEPDist->ServiceID == WMI_CONTROL_SVC) {
+ /* we never oversubscribe on the control service, this is not
+ * a high performance path and the target never holds onto control
+ * credits for too long */
+ break;
+ }
+
+#ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS
+ if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
+ if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
+ /* limit VI service from oversubscribing */
+ break;
+ }
+ }
+
+ if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
+ if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) {
+ /* limit VO service from oversubscribing */
+ break;
+ }
+ }
+#else
+ if (pEPDist->ServiceID == WMI_DATA_VI_SVC) {
+ if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
+ (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
+ /* limit VI service from oversubscribing */
+ /* at least one free credit will not be used by VI */
+ break;
+ }
+ }
+
+ if (pEPDist->ServiceID == WMI_DATA_VO_SVC) {
+ if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) ||
+ (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) {
+ /* limit VO service from oversubscribing */
+ /* at least one free credit will not be used by VO */
+ break;
+ }
+ }
+#endif
+
+ /* for all other services, we follow a simple algorithm of
+ * 1. checking the free pool for credits
+ * 2. checking lower priority endpoints for credits to take */
+
+ /* give what we can */
+ credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
+
+ if (credits >= pEPDist->TxCreditsSeek) {
+ /* we found some to fullfill the seek request */
+ break;
+ }
+
+ /* we don't have enough in the free pool, try taking away from lower priority services
+ *
+ * The rule for taking away credits:
+ * 1. Only take from lower priority endpoints
+ * 2. Only take what is allocated above the minimum (never starve an endpoint completely)
+ * 3. Only take what you need.
+ *
+ * */
+
+ /* starting at the lowest priority */
+ pCurEpDist = pCredInfo->pLowestPriEpDist;
+
+ /* work backwards until we hit the endpoint again */
+ while (pCurEpDist != pEPDist) {
+ /* calculate how many we need so far */
+ need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits;
+
+ if ((pCurEpDist->TxCreditsAssigned - need) >= pCurEpDist->TxCreditsMin) {
+ /* the current one has been allocated more than it's minimum and it
+ * has enough credits assigned above it's minimum to fullfill our need
+ * try to take away just enough to fullfill our need */
+ ReduceCredits(pCredInfo,
+ pCurEpDist,
+ pCurEpDist->TxCreditsAssigned - need);
+
+ if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) {
+ /* we have enough */
+ break;
+ }
+ }
+
+ pCurEpDist = pCurEpDist->pPrev;
+ }
+
+ /* return what we can get */
+ credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek);
+
+ } while (FALSE);
+
+ /* did we find some credits? */
+ if (credits) {
+ /* give what we can */
+ GiveCredits(pCredInfo, pEPDist, credits);
+ }
+
+}
+
+/* initialize and setup credit distribution */
+A_STATUS ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, COMMON_CREDIT_STATE_INFO *pCredInfo)
+{
+ HTC_SERVICE_ID servicepriority[5];
+
+ A_MEMZERO(pCredInfo,sizeof(COMMON_CREDIT_STATE_INFO));
+
+ servicepriority[0] = WMI_CONTROL_SVC; /* highest */
+ servicepriority[1] = WMI_DATA_VO_SVC;
+ servicepriority[2] = WMI_DATA_VI_SVC;
+ servicepriority[3] = WMI_DATA_BE_SVC;
+ servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */
+
+ /* set callbacks and priority list */
+ HTCSetCreditDistribution(HTCHandle,
+ pCredInfo,
+ ar6000_credit_distribute,
+ ar6000_credit_init,
+ servicepriority,
+ 5);
+
+ return A_OK;
+}
+
diff --git a/drivers/staging/ath6kl/miscdrv/miscdrv.h b/drivers/staging/ath6kl/miscdrv/miscdrv.h
new file mode 100644
index 000000000000..ae24b728c4ad
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/miscdrv.h
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+// <copyright file="miscdrv.h" company="Atheros">
+// Copyright (c) 2004-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.
+//
+//
+//------------------------------------------------------------------------------
+//==============================================================================
+// Author(s): ="Atheros"
+//==============================================================================
+#ifndef _MISCDRV_H
+#define _MISCDRV_H
+
+
+#define HOST_INTEREST_ITEM_ADDRESS(target, item) \
+ AR6002_HOST_INTEREST_ITEM_ADDRESS(item)
+
+A_UINT32 ar6kRev2Array[][128] = {
+ {0xFFFF, 0xFFFF}, // No Patches
+ };
+
+#define CFG_REV2_ITEMS 0 // no patches so far
+#define AR6K_RESET_ADDR 0x4000
+#define AR6K_RESET_VAL 0x100
+
+#define EEPROM_SZ 768
+#define EEPROM_WAIT_LIMIT 4
+
+#endif
+