| 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;
|
| +}
|
| +
|
| +
|
|
|