OLD | NEW |
(Empty) | |
| 1 //------------------------------------------------------------------------------ |
| 2 // <copyright file="ar3kconfig.c" company="Atheros"> |
| 3 // Copyright (c) 2009 Atheros Corporation. All rights reserved. |
| 4 // |
| 5 // This program is free software; you can redistribute it and/or modify |
| 6 // it under the terms of the GNU General Public License version 2 as |
| 7 // published by the Free Software Foundation; |
| 8 // |
| 9 // Software distributed under the License is distributed on an "AS |
| 10 // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
| 11 // implied. See the License for the specific language governing |
| 12 // rights and limitations under the License. |
| 13 // |
| 14 // |
| 15 //------------------------------------------------------------------------------ |
| 16 //============================================================================== |
| 17 // AR3K configuration implementation |
| 18 // |
| 19 // Author(s): ="Atheros" |
| 20 //============================================================================== |
| 21 |
| 22 #include "a_config.h" |
| 23 #include "athdefs.h" |
| 24 #include "a_types.h" |
| 25 #include "a_osapi.h" |
| 26 #define ATH_MODULE_NAME misc |
| 27 #include "a_debug.h" |
| 28 #include "common_drv.h" |
| 29 #ifdef EXPORT_HCI_BRIDGE_INTERFACE |
| 30 #include "export_hci_transport.h" |
| 31 #else |
| 32 #include "hci_transport_api.h" |
| 33 #endif |
| 34 #include "ar3kconfig.h" |
| 35 |
| 36 #define BAUD_CHANGE_COMMAND_STATUS_OFFSET 5 |
| 37 #define HCI_EVENT_RESP_TIMEOUTMS 3000 |
| 38 #define HCI_CMD_OPCODE_BYTE_LOW_OFFSET 0 |
| 39 #define HCI_CMD_OPCODE_BYTE_HI_OFFSET 1 |
| 40 #define HCI_EVENT_OPCODE_BYTE_LOW 3 |
| 41 #define HCI_EVENT_OPCODE_BYTE_HI 4 |
| 42 #define HCI_CMD_COMPLETE_EVENT_CODE 0xE |
| 43 #define HCI_MAX_EVT_RECV_LENGTH 257 |
| 44 #define EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET 5 |
| 45 |
| 46 A_STATUS AthPSInitialize(AR3K_CONFIG_INFO *hdev); |
| 47 |
| 48 static A_STATUS SendHCICommand(AR3K_CONFIG_INFO *pConfig, |
| 49 A_UINT8 *pBuffer, |
| 50 int Length) |
| 51 { |
| 52 HTC_PACKET *pPacket = NULL; |
| 53 A_STATUS status = A_OK; |
| 54 |
| 55 do { |
| 56 |
| 57 pPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET)); |
| 58 if (NULL == pPacket) { |
| 59 status = A_NO_MEMORY; |
| 60 break; |
| 61 } |
| 62 |
| 63 A_MEMZERO(pPacket,sizeof(HTC_PACKET)); |
| 64 SET_HTC_PACKET_INFO_TX(pPacket, |
| 65 NULL, |
| 66 pBuffer, |
| 67 Length, |
| 68 HCI_COMMAND_TYPE, |
| 69 AR6K_CONTROL_PKT_TAG); |
| 70 |
| 71 /* issue synchronously */ |
| 72 status = HCI_TransportSendPkt(pConfig->pHCIDev,pPacket,TRUE); |
| 73 |
| 74 } while (FALSE); |
| 75 |
| 76 if (pPacket != NULL) { |
| 77 A_FREE(pPacket); |
| 78 } |
| 79 |
| 80 return status; |
| 81 } |
| 82 |
| 83 static A_STATUS RecvHCIEvent(AR3K_CONFIG_INFO *pConfig, |
| 84 A_UINT8 *pBuffer, |
| 85 int *pLength) |
| 86 { |
| 87 A_STATUS status = A_OK; |
| 88 HTC_PACKET *pRecvPacket = NULL; |
| 89 |
| 90 do { |
| 91 |
| 92 pRecvPacket = (HTC_PACKET *)A_MALLOC(sizeof(HTC_PACKET)); |
| 93 if (NULL == pRecvPacket) { |
| 94 status = A_NO_MEMORY; |
| 95 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n")); |
| 96 break; |
| 97 } |
| 98 |
| 99 A_MEMZERO(pRecvPacket,sizeof(HTC_PACKET)); |
| 100 |
| 101 SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket,NULL,pBuffer,*pLength,HCI_EVEN
T_TYPE); |
| 102 |
| 103 status = HCI_TransportRecvHCIEventSync(pConfig->pHCIDev, |
| 104 pRecvPacket, |
| 105 HCI_EVENT_RESP_TIMEOUTMS); |
| 106 if (A_FAILED(status)) { |
| 107 break; |
| 108 } |
| 109 |
| 110 *pLength = pRecvPacket->ActualLength; |
| 111 |
| 112 } while (FALSE); |
| 113 |
| 114 if (pRecvPacket != NULL) { |
| 115 A_FREE(pRecvPacket); |
| 116 } |
| 117 |
| 118 return status; |
| 119 } |
| 120 |
| 121 A_STATUS SendHCICommandWaitCommandComplete(AR3K_CONFIG_INFO *pConfig, |
| 122 A_UINT8 *pHCICommand, |
| 123 int CmdLength, |
| 124 A_UINT8 **ppEventBuffer, |
| 125 A_UINT8 **ppBufferToFree) |
| 126 { |
| 127 A_STATUS status = A_OK; |
| 128 A_UINT8 *pBuffer = NULL; |
| 129 A_UINT8 *pTemp; |
| 130 int length; |
| 131 A_BOOL commandComplete = FALSE; |
| 132 A_UINT8 opCodeBytes[2]; |
| 133 |
| 134 do { |
| 135 |
| 136 length = max(HCI_MAX_EVT_RECV_LENGTH,CmdLength); |
| 137 length += pConfig->pHCIProps->HeadRoom + pConfig->pHCIProps->TailRoom; |
| 138 length += pConfig->pHCIProps->IOBlockPad; |
| 139 |
| 140 pBuffer = (A_UINT8 *)A_MALLOC(length); |
| 141 if (NULL == pBuffer) { |
| 142 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to allocate bt b
uffer \n")); |
| 143 status = A_NO_MEMORY; |
| 144 break; |
| 145 } |
| 146 |
| 147 /* get the opcodes to check the command complete event */ |
| 148 opCodeBytes[0] = pHCICommand[HCI_CMD_OPCODE_BYTE_LOW_OFFSET]; |
| 149 opCodeBytes[1] = pHCICommand[HCI_CMD_OPCODE_BYTE_HI_OFFSET]; |
| 150 |
| 151 /* copy HCI command */ |
| 152 A_MEMCPY(pBuffer + pConfig->pHCIProps->HeadRoom,pHCICommand,CmdLength);
|
| 153 /* send command */ |
| 154 status = SendHCICommand(pConfig, |
| 155 pBuffer + pConfig->pHCIProps->HeadRoom, |
| 156 CmdLength); |
| 157 if (A_FAILED(status)) { |
| 158 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to send HCI Comm
and (%d) \n", status)); |
| 159 AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Comma
nd"); |
| 160 break; |
| 161 } |
| 162 |
| 163 /* reuse buffer to capture command complete event */ |
| 164 A_MEMZERO(pBuffer,length); |
| 165 status = RecvHCIEvent(pConfig,pBuffer,&length); |
| 166 if (A_FAILED(status)) { |
| 167 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI event recv failed \
n")); |
| 168 AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Comma
nd"); |
| 169 break; |
| 170 } |
| 171 |
| 172 pTemp = pBuffer + pConfig->pHCIProps->HeadRoom; |
| 173 if (pTemp[0] == HCI_CMD_COMPLETE_EVENT_CODE) { |
| 174 if ((pTemp[HCI_EVENT_OPCODE_BYTE_LOW] == opCodeBytes[0]) && |
| 175 (pTemp[HCI_EVENT_OPCODE_BYTE_HI] == opCodeBytes[1])) { |
| 176 commandComplete = TRUE; |
| 177 } |
| 178 } |
| 179 |
| 180 if (!commandComplete) { |
| 181 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Unexpected HCI event :
%d \n",pTemp[0])); |
| 182 AR_DEBUG_PRINTBUF(pTemp,pTemp[1],"Unexpected HCI event"); |
| 183 status = A_ECOMM; |
| 184 break; |
| 185 } |
| 186 |
| 187 if (ppEventBuffer != NULL) { |
| 188 /* caller wants to look at the event */ |
| 189 *ppEventBuffer = pTemp; |
| 190 if (ppBufferToFree == NULL) { |
| 191 status = A_EINVAL; |
| 192 break; |
| 193 } |
| 194 /* caller must free the buffer */ |
| 195 *ppBufferToFree = pBuffer; |
| 196 pBuffer = NULL; |
| 197 } |
| 198 |
| 199 } while (FALSE); |
| 200 |
| 201 if (pBuffer != NULL) { |
| 202 A_FREE(pBuffer); |
| 203 } |
| 204 |
| 205 return status; |
| 206 } |
| 207 |
| 208 static A_STATUS AR3KConfigureHCIBaud(AR3K_CONFIG_INFO *pConfig) |
| 209 { |
| 210 A_STATUS status = A_OK; |
| 211 A_UINT8 hciBaudChangeCommand[] = {0x0c,0xfc,0x2,0,0}; |
| 212 A_UINT16 baudVal; |
| 213 A_UINT8 *pEvent = NULL; |
| 214 A_UINT8 *pBufferToFree = NULL; |
| 215 #ifndef EXPORT_HCI_BRIDGE_INTERFACE |
| 216 A_UINT32 regAddress; |
| 217 A_UINT32 regVal; |
| 218 #endif |
| 219 |
| 220 |
| 221 do { |
| 222 |
| 223 if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR3K_BAUD) { |
| 224 baudVal = (A_UINT16)(pConfig->AR3KBaudRate / 100); |
| 225 hciBaudChangeCommand[3] = (A_UINT8)baudVal; |
| 226 hciBaudChangeCommand[4] = (A_UINT8)(baudVal >> 8); |
| 227 |
| 228 status = SendHCICommandWaitCommandComplete(pConfig, |
| 229 hciBaudChangeCommand, |
| 230 sizeof(hciBaudChangeComma
nd), |
| 231 &pEvent, |
| 232 &pBufferToFree);
|
| 233 if (A_FAILED(status)) { |
| 234 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Baud rate change fa
iled! \n")); |
| 235 break; |
| 236 } |
| 237 |
| 238 if (pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET] != 0) { |
| 239 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, |
| 240 ("AR3K Config: Baud change command event status failed: %d \
n", |
| 241 pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET])); |
| 242 status = A_ECOMM; |
| 243 break; |
| 244 } |
| 245 |
| 246 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, |
| 247 ("AR3K Config: Baud Changed to %d \n",pConfig->AR3KBaudRate)
); |
| 248 } |
| 249 |
| 250 if (pConfig->Flags & AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY) { |
| 251 /* some versions of AR3K do not switch baud immediately, up to 3
00MS */ |
| 252 A_MDELAY(325); |
| 253 } |
| 254 |
| 255 if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP) { |
| 256 #ifdef EXPORT_HCI_BRIDGE_INTERFACE |
| 257 status = ar6000_set_uart_config(pConfig->pHIFDevice, |
| 258 pConfig->AR6KScale, |
| 259 pConfig->AR6KStep);
|
| 260 #else |
| 261 regAddress = 0xc008; |
| 262 regVal = ((A_UINT32)pConfig->AR6KScale << 16) | pConfig->AR6KStep; |
| 263 /* change the HCI UART scale/step values through the diagnostic
window */ |
| 264 status = ar6000_WriteRegDiag(pConfig->pHIFDevice,®Address,®Val
); |
| 265 #endif |
| 266 if (A_FAILED(status)) { |
| 267 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, |
| 268 ("AR3K Config: failed to set scale and step values: %d \n",
status)); |
| 269 break; |
| 270 } |
| 271 |
| 272 AR_DEBUG_PRINTF(ATH_DEBUG_ANY, |
| 273 ("AR3K Config: UART Bridge scale:%d, step:%d set \n", |
| 274 pConfig->AR6KScale, pConfig->AR6KStep)); |
| 275 } |
| 276 |
| 277 } while (FALSE); |
| 278 |
| 279 if (pBufferToFree != NULL) { |
| 280 A_FREE(pBufferToFree); |
| 281 } |
| 282 |
| 283 return status; |
| 284 } |
| 285 |
| 286 static A_STATUS AR3KExitMinBoot(AR3K_CONFIG_INFO *pConfig) |
| 287 { |
| 288 A_STATUS status; |
| 289 A_CHAR exitMinBootCmd[] = {0x25,0xFC,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0
x00, |
| 290 0x00,0x00,0x00,0x00,0x00}; |
| 291 A_UINT8 *pEvent = NULL; |
| 292 A_UINT8 *pBufferToFree = NULL; |
| 293 |
| 294 status = SendHCICommandWaitCommandComplete(pConfig, |
| 295 exitMinBootCmd, |
| 296 sizeof(exitMinBootCmd), |
| 297 &pEvent, |
| 298 &pBufferToFree); |
| 299 |
| 300 if (A_SUCCESS(status)) { |
| 301 if (pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET] != 0) { |
| 302 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, |
| 303 ("AR3K Config: MinBoot exit command event status failed: %d \n",
|
| 304 pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET])); |
| 305 status = A_ECOMM; |
| 306 } else { |
| 307 AR_DEBUG_PRINTF(ATH_DEBUG_INFO, |
| 308 ("AR3K Config: MinBoot Exit Command Complete (Su
ccess) \n")); |
| 309 A_MDELAY(1); |
| 310 } |
| 311 } else { |
| 312 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: MinBoot Exit Failed! \n"));
|
| 313 } |
| 314 |
| 315 if (pBufferToFree != NULL) { |
| 316 A_FREE(pBufferToFree); |
| 317 } |
| 318 |
| 319 return status; |
| 320 } |
| 321 |
| 322 static A_STATUS AR3KConfigureSendHCIReset(AR3K_CONFIG_INFO *pConfig) |
| 323 { |
| 324 A_STATUS status = A_OK; |
| 325 A_UINT8 hciResetCommand[] = {0x03,0x0c,0x0}; |
| 326 A_UINT8 *pEvent = NULL; |
| 327 A_UINT8 *pBufferToFree = NULL; |
| 328 |
| 329 status = SendHCICommandWaitCommandComplete( pConfig, |
| 330 hciResetCommand, |
| 331 sizeof(hciResetCommand), |
| 332 &pEvent, |
| 333 &pBufferToFree ); |
| 334 |
| 335 if (A_FAILED(status)) { |
| 336 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI reset failed! \n")); |
| 337 } |
| 338 |
| 339 if (pBufferToFree != NULL) { |
| 340 A_FREE(pBufferToFree); |
| 341 } |
| 342 |
| 343 return status; |
| 344 } |
| 345 |
| 346 A_STATUS AR3KConfigure(AR3K_CONFIG_INFO *pConfig) |
| 347 { |
| 348 A_STATUS status = A_OK; |
| 349 |
| 350 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuring AR3K ...\n")); |
| 351 |
| 352 do { |
| 353 |
| 354 if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConf
ig->pHIFDevice == NULL)) { |
| 355 status = A_EINVAL; |
| 356 break; |
| 357 } |
| 358 |
| 359 /* disable asynchronous recv while we issue commands and receive eve
nts synchronously */ |
| 360 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,FALSE); |
| 361 if (A_FAILED(status)) { |
| 362 break; |
| 363 } |
| 364 |
| 365 if (pConfig->Flags & AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT) { |
| 366 status = AR3KExitMinBoot(pConfig); |
| 367 if (A_FAILED(status)) { |
| 368 break; |
| 369 } |
| 370 } |
| 371 |
| 372 if (pConfig->Flags & |
| 373 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCAL
E_STEP)) { |
| 374 status = AR3KConfigureHCIBaud(pConfig); |
| 375 if (A_FAILED(status)) { |
| 376 break; |
| 377 } |
| 378 } |
| 379 |
| 380 /* Load patching and PST file if available*/ |
| 381 if (A_OK != AthPSInitialize(pConfig)) { |
| 382 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch Download Failed!\n")); |
| 383 } |
| 384 |
| 385 /* Send HCI reset to make PS tags take effect*/ |
| 386 AR3KConfigureSendHCIReset(pConfig); |
| 387 |
| 388 /* re-enable asynchronous recv */ |
| 389 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,TRUE); |
| 390 if (A_FAILED(status)) { |
| 391 break; |
| 392 } |
| 393 |
| 394 |
| 395 } while (FALSE); |
| 396 |
| 397 |
| 398 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuration Complete (status
= %d) \n",status)); |
| 399 |
| 400 return status; |
| 401 } |
| 402 |
| 403 A_STATUS AR3KConfigureExit(void *config) |
| 404 { |
| 405 A_STATUS status = A_OK; |
| 406 AR3K_CONFIG_INFO *pConfig = (AR3K_CONFIG_INFO *)config; |
| 407 |
| 408 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleaning up AR3K ...\n")); |
| 409 |
| 410 do { |
| 411 |
| 412 if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConf
ig->pHIFDevice == NULL)) { |
| 413 status = A_EINVAL; |
| 414 break; |
| 415 } |
| 416 |
| 417 /* disable asynchronous recv while we issue commands and receive eve
nts synchronously */ |
| 418 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,FALSE); |
| 419 if (A_FAILED(status)) { |
| 420 break; |
| 421 } |
| 422 |
| 423 if (pConfig->Flags & |
| 424 (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCAL
E_STEP)) { |
| 425 status = AR3KConfigureHCIBaud(pConfig); |
| 426 if (A_FAILED(status)) { |
| 427 break; |
| 428 } |
| 429 } |
| 430 |
| 431 /* re-enable asynchronous recv */ |
| 432 status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,TRUE); |
| 433 if (A_FAILED(status)) { |
| 434 break; |
| 435 } |
| 436 |
| 437 |
| 438 } while (FALSE); |
| 439 |
| 440 |
| 441 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleanup Complete (status = %d)
\n",status)); |
| 442 |
| 443 return status; |
| 444 } |
| 445 |
OLD | NEW |