diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-28 09:44:56 -0700 |
commit | e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7 (patch) | |
tree | ea51b391f7d74ca695dcb9f5e46eb02688a92ed9 /drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c | |
parent | 81280572ca6f54009edfa4deee563e8678784218 (diff) | |
parent | a4ac0d847af9dd34d5953a5e264400326144b6b2 (diff) | |
download | op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.zip op-kernel-dev-e4c5bf8e3dca827a1b3a6fac494eae8c74b7e1e7.tar.gz |
Merge 'staging-next' to Linus's tree
This merges the staging-next tree to Linus's tree and resolves
some conflicts that were present due to changes in other trees that were
affected by files here.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c')
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c | 572 |
1 files changed, 572 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; +} + + |