OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2004-2008 Atheros Communications Inc. |
| 3 * All rights reserved. |
| 4 * |
| 5 * This file implements the Atheros PS and patch downloaded for HCI UART Transpo
rt driver. |
| 6 * This file can be used for HCI SDIO transport implementation for AR6002 with H
CI_TRANSPORT_SDIO |
| 7 * defined. |
| 8 * |
| 9 * |
| 10 * ar3kcpsconfig.c |
| 11 * |
| 12 * |
| 13 * |
| 14 * The software source and binaries included in this development package are |
| 15 * licensed, not sold. You, or your company, received the package under one |
| 16 * or more license agreements. The rights granted to you are specifically |
| 17 * listed in these license agreement(s). All other rights remain with Atheros |
| 18 * Communications, Inc., its subsidiaries, or the respective owner including |
| 19 * those listed on the included copyright notices.. Distribution of any |
| 20 * portion of this package must be in strict compliance with the license |
| 21 * agreement(s) terms. |
| 22 * |
| 23 * |
| 24 * |
| 25 */ |
| 26 |
| 27 |
| 28 |
| 29 #include "ar3kpsconfig.h" |
| 30 #ifndef HCI_TRANSPORT_SDIO |
| 31 #include "hci_ath.h" |
| 32 #include "hci_uart.h" |
| 33 #endif /* #ifndef HCI_TRANSPORT_SDIO */ |
| 34 |
| 35 /* |
| 36 * Structure used to send HCI packet, hci packet length and device info |
| 37 * together as parameter to PSThread. |
| 38 */ |
| 39 typedef struct { |
| 40 |
| 41 PSCmdPacket *HciCmdList; |
| 42 A_UINT32 num_packets; |
| 43 AR3K_CONFIG_INFO *dev; |
| 44 }HciCommandListParam; |
| 45 |
| 46 A_STATUS SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig, |
| 47 A_UINT8 *pHCICommand, |
| 48 int CmdLength, |
| 49 A_UINT8 **ppEventBuffer, |
| 50 A_UINT8 **ppBufferToFree); |
| 51 |
| 52 A_UINT32 Rom_Version; |
| 53 A_UINT32 Build_Version; |
| 54 |
| 55 A_STATUS getDeviceType(AR3K_CONFIG_INFO *pConfig, A_UINT32 * code); |
| 56 A_STATUS ReadVersionInfo(AR3K_CONFIG_INFO *pConfig); |
| 57 #ifndef HCI_TRANSPORT_SDIO |
| 58 |
| 59 DECLARE_WAIT_QUEUE_HEAD(PsCompleteEvent); |
| 60 DECLARE_WAIT_QUEUE_HEAD(HciEvent); |
| 61 A_UCHAR *HciEventpacket; |
| 62 rwlock_t syncLock; |
| 63 wait_queue_t Eventwait; |
| 64 |
| 65 int PSHciWritepacket(struct hci_dev*,A_UCHAR* Data, A_UINT32 len); |
| 66 extern char *bdaddr; |
| 67 #endif /* HCI_TRANSPORT_SDIO */ |
| 68 |
| 69 A_STATUS write_bdaddr(AR3K_CONFIG_INFO *pConfig,A_UCHAR *bdaddr); |
| 70 |
| 71 int PSSendOps(void *arg); |
| 72 |
| 73 #ifdef BT_PS_DEBUG |
| 74 void Hci_log(A_UCHAR * log_string,A_UCHAR *data,A_UINT32 len) |
| 75 { |
| 76 int i; |
| 77 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s : ",log_string)); |
| 78 for (i = 0; i < len; i++) { |
| 79 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("0x%02x ", data[i])); |
| 80 } |
| 81 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("\n...................................\n")); |
| 82 } |
| 83 #else |
| 84 #define Hci_log(string,data,len) |
| 85 #endif /* BT_PS_DEBUG */ |
| 86 |
| 87 |
| 88 |
| 89 |
| 90 A_STATUS AthPSInitialize(AR3K_CONFIG_INFO *hdev) |
| 91 { |
| 92 A_STATUS status = A_OK; |
| 93 if(hdev == NULL) { |
| 94 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Device handle received\n")); |
| 95 return A_ERROR; |
| 96 } |
| 97 |
| 98 #ifndef HCI_TRANSPORT_SDIO |
| 99 DECLARE_WAITQUEUE(wait, current); |
| 100 #endif /* HCI_TRANSPORT_SDIO */ |
| 101 |
| 102 |
| 103 #ifdef HCI_TRANSPORT_SDIO |
| 104 status = PSSendOps((void*)hdev); |
| 105 #else |
| 106 if(InitPSState(hdev) == -1) { |
| 107 return A_ERROR; |
| 108 } |
| 109 allow_signal(SIGKILL); |
| 110 add_wait_queue(&PsCompleteEvent,&wait); |
| 111 set_current_state(TASK_INTERRUPTIBLE); |
| 112 if(!kernel_thread(PSSendOps,(void*)hdev,CLONE_FS|CLONE_FILES|CLONE_SIGHAND|S
IGCHLD)) { |
| 113 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Kthread Failed\n")); |
| 114 remove_wait_queue(&PsCompleteEvent,&wait); |
| 115 return A_ERROR; |
| 116 } |
| 117 wait_event_interruptible(PsCompleteEvent,(PSTagMode == FALSE)); |
| 118 set_current_state(TASK_RUNNING); |
| 119 remove_wait_queue(&PsCompleteEvent,&wait); |
| 120 |
| 121 #endif /* HCI_TRANSPORT_SDIO */ |
| 122 |
| 123 |
| 124 return status; |
| 125 |
| 126 } |
| 127 |
| 128 int PSSendOps(void *arg) |
| 129 { |
| 130 int i; |
| 131 int status = 0; |
| 132 PSCmdPacket *HciCmdList; /* List storing the commands */ |
| 133 const struct firmware* firmware; |
| 134 A_UINT32 numCmds; |
| 135 A_UINT8 *event; |
| 136 A_UINT8 *bufferToFree; |
| 137 struct hci_dev *device; |
| 138 A_UCHAR *buffer; |
| 139 A_UINT32 len; |
| 140 A_UINT32 DevType; |
| 141 A_UCHAR *PsFileName; |
| 142 A_UCHAR *patchFileName; |
| 143 AR3K_CONFIG_INFO *hdev = (AR3K_CONFIG_INFO*)arg; |
| 144 struct device *firmwareDev = NULL; |
| 145 status = 0; |
| 146 HciCmdList = NULL; |
| 147 #ifdef HCI_TRANSPORT_SDIO |
| 148 device = hdev->pBtStackHCIDev; |
| 149 firmwareDev = device->parent; |
| 150 #else |
| 151 device = hdev; |
| 152 firmwareDev = &device->dev; |
| 153 AthEnableSyncCommandOp(TRUE); |
| 154 #endif /* HCI_TRANSPORT_SDIO */ |
| 155 /* First verify if the controller is an FPGA or ASIC, so depending on the de
vice type the PS file to be written will be different. |
| 156 */ |
| 157 if(A_ERROR == getDeviceType(hdev,&DevType)) { |
| 158 status = 1; |
| 159 goto complete; |
| 160 } |
| 161 if(A_ERROR == ReadVersionInfo(hdev)) { |
| 162 status = 1; |
| 163 goto complete; |
| 164 } |
| 165 patchFileName = PATCH_FILE; |
| 166 if(DevType){ |
| 167 if(DevType == 0xdeadc0de){ |
| 168 PsFileName = PS_ASIC_FILE; |
| 169 } else{ |
| 170 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" FPGA Test Image : %x %x \n",Ro
m_Version,Build_Version)); |
| 171 if((Rom_Version == 0x99999999) && (Build_Version == 1)){ |
| 172 |
| 173 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("FPGA Test Image : Skippi
ng Patch File load\n")); |
| 174 patchFileName = NULL; |
| 175 } |
| 176 PsFileName = PS_FPGA_FILE; |
| 177 } |
| 178 } |
| 179 else{ |
| 180 PsFileName = PS_ASIC_FILE; |
| 181 } |
| 182 |
| 183 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%x: FPGA/ASIC PS File Name %s\n", DevType,Ps
FileName)); |
| 184 /* Read the PS file to a dynamically allocated buffer */ |
| 185 if(request_firmware(&firmware,PsFileName,firmwareDev) < 0) { |
| 186 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCT
ION__ )); |
| 187 status = 1; |
| 188 goto complete; |
| 189 |
| 190 } |
| 191 if(NULL == firmware || firmware->size == 0) { |
| 192 status = 1; |
| 193 goto complete; |
| 194 } |
| 195 buffer = (A_UCHAR *)A_MALLOC(firmware->size); |
| 196 if(buffer != NULL) { |
| 197 /* Copy the read file to a local Dynamic buffer */ |
| 198 memcpy(buffer,firmware->data,firmware->size); |
| 199 len = firmware->size; |
| 200 release_firmware(firmware); |
| 201 /* Parse the PS buffer to a global variable */ |
| 202 status = AthDoParsePS(buffer,len); |
| 203 A_FREE(buffer); |
| 204 } else { |
| 205 release_firmware(firmware); |
| 206 } |
| 207 |
| 208 |
| 209 /* Read the patch file to a dynamically allocated buffer */ |
| 210 if((patchFileName == NULL) || (request_firmware(&firmware,patchFileName,firm
wareDev) < 0)) { |
| 211 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCT
ION__ )); |
| 212 /* |
| 213 * It is not necessary that Patch file be available, continue with PS O
perations if. |
| 214 * failed. |
| 215 */ |
| 216 status = 0; |
| 217 |
| 218 } else { |
| 219 if(NULL == firmware || firmware->size == 0) { |
| 220 status = 0; |
| 221 } else { |
| 222 buffer = (A_UCHAR *)A_MALLOC(firmware->size); |
| 223 if(buffer != NULL) { |
| 224 /* Copy the read file to a local Dynamic buffer */ |
| 225 memcpy(buffer,firmware->data,firmware->size); |
| 226 len = firmware->size; |
| 227 release_firmware(firmware); |
| 228 /* parse and store the Patch file contents to a global variables
*/ |
| 229 status = AthDoParsePatch(buffer,len); |
| 230 A_FREE(buffer); |
| 231 } else { |
| 232 release_firmware(firmware); |
| 233 } |
| 234 } |
| 235 } |
| 236 |
| 237 /* Create an HCI command list from the parsed PS and patch information */ |
| 238 AthCreateCommandList(&HciCmdList,&numCmds); |
| 239 |
| 240 /* Form the parameter for PSSendOps() API */ |
| 241 |
| 242 |
| 243 /* |
| 244 * First Send the CRC packet, |
| 245 * We have to continue with the PS operations only if the CRC packet has bee
n replied with |
| 246 * a Command complete event with status Error. |
| 247 */ |
| 248 |
| 249 if(SendHCICommandWaitCommandComplete |
| 250 (hdev, |
| 251 HciCmdList[0].Hcipacket, |
| 252 HciCmdList[0].packetLen, |
| 253 &event, |
| 254 &bufferToFree) == A_OK) { |
| 255 if(ReadPSEvent(event) == A_OK) { /* Exit if the status is success */ |
| 256 if(bufferToFree != NULL) { |
| 257 A_FREE(bufferToFree); |
| 258 } |
| 259 #ifndef HCI_TRANSPORT_SDIO |
| 260 if(bdaddr[0] !='\0') { |
| 261 write_bdaddr(hdev,bdaddr); |
| 262 } |
| 263 #endif |
| 264 status = 1; |
| 265 goto complete; |
| 266 } |
| 267 if(bufferToFree != NULL) { |
| 268 A_FREE(bufferToFree); |
| 269 } |
| 270 } else { |
| 271 status = 0; |
| 272 goto complete; |
| 273 } |
| 274 |
| 275 for(i = 1; i <numCmds; i++) { |
| 276 |
| 277 if(SendHCICommandWaitCommandComplete |
| 278 (hdev, |
| 279 HciCmdList[i].Hcipacket, |
| 280 HciCmdList[i].packetLen, |
| 281 &event, |
| 282 &bufferToFree) == A_OK) { |
| 283 if(ReadPSEvent(event) != A_OK) { /* Exit if the status is success */ |
| 284 if(bufferToFree != NULL) { |
| 285 A_FREE(bufferToFree); |
| 286 } |
| 287 status = 1; |
| 288 goto complete; |
| 289 } |
| 290 if(bufferToFree != NULL) { |
| 291 A_FREE(bufferToFree); |
| 292 } |
| 293 } else { |
| 294 status = 0; |
| 295 goto complete; |
| 296 } |
| 297 } |
| 298 #ifndef HCI_TRANSPORT_SDIO |
| 299 if(bdaddr[0] != '\0') { |
| 300 write_bdaddr(hdev,bdaddr); |
| 301 } else |
| 302 #endif /* HCI_TRANSPORT_SDIO */ |
| 303 { |
| 304 /* Read Contents of BDADDR file if user has not provided any op
tion */ |
| 305 if(request_firmware(&firmware,BDADDR_FILE,firmwareDev) < 0) { |
| 306 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n",
__FUNCTION__ )); |
| 307 status = 1; |
| 308 goto complete; |
| 309 } |
| 310 if(NULL == firmware || firmware->size == 0) { |
| 311 status = 1; |
| 312 goto complete; |
| 313 } |
| 314 write_bdaddr(hdev,(A_UCHAR *)firmware->data); |
| 315 release_firmware(firmware); |
| 316 } |
| 317 complete: |
| 318 #ifndef HCI_TRANSPORT_SDIO |
| 319 AthEnableSyncCommandOp(FALSE); |
| 320 PSTagMode = FALSE; |
| 321 wake_up_interruptible(&PsCompleteEvent); |
| 322 #endif /* HCI_TRANSPORT_SDIO */ |
| 323 if(NULL != HciCmdList) { |
| 324 AthFreeCommandList(&HciCmdList,numCmds); |
| 325 } |
| 326 return status; |
| 327 } |
| 328 #ifndef HCI_TRANSPORT_SDIO |
| 329 /* |
| 330 * This API is used to send the HCI command to controller and return |
| 331 * with a HCI Command Complete event. |
| 332 * For HCI SDIO transport, this will be internally defined. |
| 333 */ |
| 334 A_STATUS SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig, |
| 335 A_UINT8 *pHCICommand, |
| 336 int CmdLength, |
| 337 A_UINT8 **ppEventBuffer, |
| 338 A_UINT8 **ppBufferToFree) |
| 339 { |
| 340 if(CmdLength == 0) { |
| 341 return A_ERROR; |
| 342 } |
| 343 Hci_log("COM Write -->",pHCICommand,CmdLength); |
| 344 PSAcked = FALSE; |
| 345 if(PSHciWritepacket(pConfig,pHCICommand,CmdLength) == 0) { |
| 346 /* If the controller is not available, return Error */ |
| 347 return A_ERROR; |
| 348 } |
| 349 //add_timer(&psCmdTimer); |
| 350 wait_event_interruptible(HciEvent,(PSAcked == TRUE)); |
| 351 if(NULL != HciEventpacket) { |
| 352 *ppEventBuffer = HciEventpacket; |
| 353 *ppBufferToFree = HciEventpacket; |
| 354 } else { |
| 355 /* Did not get an event from controller. return error */ |
| 356 *ppBufferToFree = NULL; |
| 357 return A_ERROR; |
| 358 } |
| 359 |
| 360 return A_OK; |
| 361 } |
| 362 #endif /* HCI_TRANSPORT_SDIO */ |
| 363 |
| 364 A_STATUS ReadPSEvent(A_UCHAR* Data){ |
| 365 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" PS Event %x %x %x\n",Data[4],Data[5],Data[3
])); |
| 366 |
| 367 if(Data[4] == 0xFC && Data[5] == 0x00) |
| 368 { |
| 369 switch(Data[3]){ |
| 370 case 0x0B: |
| 371 return A_OK; |
| 372 break; |
| 373 case 0x0C: |
| 374 /* Change Baudrate */ |
| 375 return A_OK; |
| 376 break; |
| 377 case 0x04: |
| 378 return A_OK; |
| 379 break; |
| 380 case 0x1E: |
| 381 Rom_Version = Data[9]; |
| 382 Rom_Version = ((Rom_Version << 8) |Data[8]); |
| 383 Rom_Version = ((Rom_Version << 8) |Data[7]); |
| 384 Rom_Version = ((Rom_Version << 8) |Data[6]); |
| 385 |
| 386 Build_Version = Data[13]; |
| 387 Build_Version = ((Build_Version << 8) |Data[12]); |
| 388 Build_Version = ((Build_Version << 8) |Data[11]); |
| 389 Build_Version = ((Build_Version << 8) |Data[10]); |
| 390 return A_OK; |
| 391 break; |
| 392 |
| 393 |
| 394 } |
| 395 } |
| 396 |
| 397 return A_ERROR; |
| 398 } |
| 399 int str2ba(unsigned char *str_bdaddr,unsigned char *bdaddr) |
| 400 { |
| 401 unsigned char bdbyte[3]; |
| 402 unsigned char *str_byte = str_bdaddr; |
| 403 int i,j; |
| 404 unsigned char colon_present = 0; |
| 405 |
| 406 if(NULL != strstr(str_bdaddr,":")) { |
| 407 colon_present = 1; |
| 408 } |
| 409 |
| 410 |
| 411 bdbyte[2] = '\0'; |
| 412 |
| 413 for( i = 0,j = 5; i < 6; i++, j--) { |
| 414 bdbyte[0] = str_byte[0]; |
| 415 bdbyte[1] = str_byte[1]; |
| 416 bdaddr[j] = A_STRTOL(bdbyte,NULL,16); |
| 417 if(colon_present == 1) { |
| 418 str_byte+=3; |
| 419 } else { |
| 420 str_byte+=2; |
| 421 } |
| 422 } |
| 423 return 0; |
| 424 } |
| 425 |
| 426 A_STATUS write_bdaddr(AR3K_CONFIG_INFO *pConfig,A_UCHAR *bdaddr) |
| 427 { |
| 428 A_UCHAR bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A, 0x01, 0x01, |
| 429 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 }; |
| 430 A_UINT8 *event; |
| 431 A_UINT8 *bufferToFree = NULL; |
| 432 A_STATUS result = A_ERROR; |
| 433 |
| 434 str2ba(bdaddr,&bdaddr_cmd[7]); |
| 435 |
| 436 if(A_OK == SendHCICommandWaitCommandComplete(pConfig,bdaddr_cmd, |
| 437
sizeof(bdaddr_cmd), |
| 438
&event,&bufferToFree)) { |
| 439 |
| 440 if(event[4] == 0xFC && event[5] == 0x00){ |
| 441 if(event[3] == 0x0B){ |
| 442 result = A_OK; |
| 443 } |
| 444 } |
| 445 |
| 446 } |
| 447 if(bufferToFree != NULL) { |
| 448 A_FREE(bufferToFree); |
| 449 } |
| 450 return result; |
| 451 |
| 452 } |
| 453 A_STATUS ReadVersionInfo(AR3K_CONFIG_INFO *pConfig) |
| 454 { |
| 455 A_UINT8 hciCommand[] = {0x1E,0xfc,0x00}; |
| 456 A_UINT8 *event; |
| 457 A_UINT8 *bufferToFree = NULL; |
| 458 A_STATUS result = A_ERROR; |
| 459 if(A_OK == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCo
mmand),&event,&bufferToFree)) { |
| 460 result = ReadPSEvent(event); |
| 461 |
| 462 } |
| 463 if(bufferToFree != NULL) { |
| 464 A_FREE(bufferToFree); |
| 465 } |
| 466 return result; |
| 467 } |
| 468 A_STATUS getDeviceType(AR3K_CONFIG_INFO *pConfig, A_UINT32 * code) |
| 469 { |
| 470 A_UINT8 hciCommand[] = {0x05,0xfc,0x05,0x00,0x00,0x00,0x00,0x04}; |
| 471 A_UINT8 *event; |
| 472 A_UINT8 *bufferToFree = NULL; |
| 473 A_UINT32 reg; |
| 474 A_STATUS result = A_ERROR; |
| 475 *code = 0; |
| 476 hciCommand[3] = (A_UINT8)(FPGA_REGISTER & 0xFF); |
| 477 hciCommand[4] = (A_UINT8)((FPGA_REGISTER >> 8) & 0xFF); |
| 478 hciCommand[5] = (A_UINT8)((FPGA_REGISTER >> 16) & 0xFF); |
| 479 hciCommand[6] = (A_UINT8)((FPGA_REGISTER >> 24) & 0xFF); |
| 480 if(A_OK == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCo
mmand),&event,&bufferToFree)) { |
| 481 |
| 482 if(event[4] == 0xFC && event[5] == 0x00){ |
| 483 switch(event[3]){ |
| 484 case 0x05: |
| 485 reg = event[9]; |
| 486 reg = ((reg << 8) |event[8]); |
| 487 reg = ((reg << 8) |event[7]); |
| 488 reg = ((reg << 8) |event[6]); |
| 489 *code = reg; |
| 490 result = A_OK; |
| 491 |
| 492 break; |
| 493 case 0x06: |
| 494 //Sleep(500); |
| 495 break; |
| 496 } |
| 497 } |
| 498 |
| 499 } |
| 500 if(bufferToFree != NULL) { |
| 501 A_FREE(bufferToFree); |
| 502 } |
| 503 return result; |
| 504 } |
| 505 |
| 506 |
OLD | NEW |