From 30295c8936f3a426985e99bebb17d72bd7847910 Mon Sep 17 00:00:00 2001 From: Vipin Mehta Date: Wed, 1 Sep 2010 12:06:33 -0700 Subject: 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 Signed-off-by: Greg Kroah-Hartman --- .../staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c | 980 +++++++++++++++++++++ 1 file changed, 980 insertions(+) create mode 100644 drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c (limited to 'drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c') diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c new file mode 100644 index 00000000000..5eed8ac0039 --- /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 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> 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