summaryrefslogtreecommitdiffstats
path: root/drivers/staging/ath6kl/miscdrv/ar3kps
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/ath6kl/miscdrv/ar3kps')
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c572
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h75
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c969
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h127
4 files changed, 1743 insertions, 0 deletions
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
new file mode 100644
index 0000000..0e298db
--- /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 0000000..4e5b7bf
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h
@@ -0,0 +1,75 @@
+/*
+ * 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/signal.h>
+
+
+#include <linux/ioctl.h>
+#include <linux/firmware.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 0000000..8dce054
--- /dev/null
+++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c
@@ -0,0 +1,969 @@
+/*
+ * 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"
+
+#include <linux/ctype.h>
+#include <linux/kernel.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++
+
+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)(hex_to_bin(pCharLine[stReadStatus.uCharCount]) << 4)
+ | (A_UINT8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 1]));
+
+ PsTagEntry[TagCount].TagData[stReadStatus.uByteCount+1] =
+ (A_UINT8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 3]) << 4)
+ | (A_UINT8)(hex_to_bin(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' && isxdigit(ch)) {
+ buffer[0] = ch;
+ } else
+ {
+ return A_ERROR;
+ }
+ ch = AthReadChar(srcbuffer,len,pos);
+ if(ch != '\0' && isxdigit(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 || !isxdigit(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 0000000..007b0eb
--- /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 */
OpenPOWER on IntegriCloud