Index: chromeos/drivers/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c |
diff --git a/chromeos/drivers/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c b/chromeos/drivers/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d4048c8efd0cad151ef8a7883645984b3a374df4 |
--- /dev/null |
+++ b/chromeos/drivers/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c |
@@ -0,0 +1,506 @@ |
+/* |
+ * Copyright (c) 2004-2008 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 */ |
+ |
+/* |
+ * 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; |
+ |
+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 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; |
+ 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. |
+ */ |
+ if(A_ERROR == getDeviceType(hdev,&DevType)) { |
+ status = 1; |
+ goto complete; |
+ } |
+ if(A_ERROR == ReadVersionInfo(hdev)) { |
+ status = 1; |
+ goto complete; |
+ } |
+ patchFileName = PATCH_FILE; |
+ 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; |
+ } |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%x: FPGA/ASIC PS File Name %s\n", DevType,PsFileName)); |
+ /* Read the PS file to a dynamically allocated buffer */ |
+ if(request_firmware(&firmware,PsFileName,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; |
+ release_firmware(firmware); |
+ /* Parse the PS buffer to a global variable */ |
+ status = AthDoParsePS(buffer,len); |
+ A_FREE(buffer); |
+ } else { |
+ release_firmware(firmware); |
+ } |
+ |
+ |
+ /* Read the patch file to a dynamically allocated buffer */ |
+ if((patchFileName == NULL) || (request_firmware(&firmware,patchFileName,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; |
+ release_firmware(firmware); |
+ /* parse and store the Patch file contents to a global variables */ |
+ status = AthDoParsePatch(buffer,len); |
+ A_FREE(buffer); |
+ } else { |
+ 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[0] !='\0') { |
+ write_bdaddr(hdev,bdaddr); |
+ } |
+#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; |
+ } |
+ } |
+#ifndef HCI_TRANSPORT_SDIO |
+ if(bdaddr[0] != '\0') { |
+ write_bdaddr(hdev,bdaddr); |
+ } else |
+#endif /* HCI_TRANSPORT_SDIO */ |
+ { |
+ /* Read Contents of BDADDR file if user has not provided any option */ |
+ if(request_firmware(&firmware,BDADDR_FILE,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; |
+ } |
+ write_bdaddr(hdev,(A_UCHAR *)firmware->data); |
+ 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); |
+ } |
+ 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) |
+{ |
+ 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; |
+ |
+ str2ba(bdaddr,&bdaddr_cmd[7]); |
+ |
+ 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; |
+} |
+ |
+ |