diff options
Diffstat (limited to 'drivers/staging/ath6kl/miscdrv')
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/ar3kconfig.c | 565 | ||||
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c | 572 | ||||
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h | 75 | ||||
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c | 969 | ||||
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h | 113 | ||||
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/common_drv.c | 910 | ||||
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/credit_dist.c | 417 | ||||
-rw-r--r-- | drivers/staging/ath6kl/miscdrv/miscdrv.h | 42 |
8 files changed, 3663 insertions, 0 deletions
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kconfig.c new file mode 100644 index 00000000000..e0ea2183019 --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/ar3kconfig.c | |||
@@ -0,0 +1,565 @@ | |||
1 | //------------------------------------------------------------------------------ | ||
2 | // Copyright (c) 2009-2010 Atheros Corporation. All rights reserved. | ||
3 | // | ||
4 | // | ||
5 | // Permission to use, copy, modify, and/or distribute this software for any | ||
6 | // purpose with or without fee is hereby granted, provided that the above | ||
7 | // copyright notice and this permission notice appear in all copies. | ||
8 | // | ||
9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | // | ||
17 | // | ||
18 | //------------------------------------------------------------------------------ | ||
19 | //============================================================================== | ||
20 | // AR3K configuration implementation | ||
21 | // | ||
22 | // Author(s): ="Atheros" | ||
23 | //============================================================================== | ||
24 | |||
25 | #include "a_config.h" | ||
26 | #include "athdefs.h" | ||
27 | #include "a_osapi.h" | ||
28 | #define ATH_MODULE_NAME misc | ||
29 | #include "a_debug.h" | ||
30 | #include "common_drv.h" | ||
31 | #ifdef EXPORT_HCI_BRIDGE_INTERFACE | ||
32 | #include "export_hci_transport.h" | ||
33 | #else | ||
34 | #include "hci_transport_api.h" | ||
35 | #endif | ||
36 | #include "ar3kconfig.h" | ||
37 | #include "tlpm.h" | ||
38 | |||
39 | #define BAUD_CHANGE_COMMAND_STATUS_OFFSET 5 | ||
40 | #define HCI_EVENT_RESP_TIMEOUTMS 3000 | ||
41 | #define HCI_CMD_OPCODE_BYTE_LOW_OFFSET 0 | ||
42 | #define HCI_CMD_OPCODE_BYTE_HI_OFFSET 1 | ||
43 | #define HCI_EVENT_OPCODE_BYTE_LOW 3 | ||
44 | #define HCI_EVENT_OPCODE_BYTE_HI 4 | ||
45 | #define HCI_CMD_COMPLETE_EVENT_CODE 0xE | ||
46 | #define HCI_MAX_EVT_RECV_LENGTH 257 | ||
47 | #define EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET 5 | ||
48 | |||
49 | int AthPSInitialize(struct ar3k_config_info *hdev); | ||
50 | |||
51 | static int SendHCICommand(struct ar3k_config_info *pConfig, | ||
52 | u8 *pBuffer, | ||
53 | int Length) | ||
54 | { | ||
55 | struct htc_packet *pPacket = NULL; | ||
56 | int status = 0; | ||
57 | |||
58 | do { | ||
59 | |||
60 | pPacket = (struct htc_packet *)A_MALLOC(sizeof(struct htc_packet)); | ||
61 | if (NULL == pPacket) { | ||
62 | status = A_NO_MEMORY; | ||
63 | break; | ||
64 | } | ||
65 | |||
66 | A_MEMZERO(pPacket,sizeof(struct htc_packet)); | ||
67 | SET_HTC_PACKET_INFO_TX(pPacket, | ||
68 | NULL, | ||
69 | pBuffer, | ||
70 | Length, | ||
71 | HCI_COMMAND_TYPE, | ||
72 | AR6K_CONTROL_PKT_TAG); | ||
73 | |||
74 | /* issue synchronously */ | ||
75 | status = HCI_TransportSendPkt(pConfig->pHCIDev,pPacket,true); | ||
76 | |||
77 | } while (false); | ||
78 | |||
79 | if (pPacket != NULL) { | ||
80 | kfree(pPacket); | ||
81 | } | ||
82 | |||
83 | return status; | ||
84 | } | ||
85 | |||
86 | static int RecvHCIEvent(struct ar3k_config_info *pConfig, | ||
87 | u8 *pBuffer, | ||
88 | int *pLength) | ||
89 | { | ||
90 | int status = 0; | ||
91 | struct htc_packet *pRecvPacket = NULL; | ||
92 | |||
93 | do { | ||
94 | |||
95 | pRecvPacket = (struct htc_packet *)A_MALLOC(sizeof(struct htc_packet)); | ||
96 | if (NULL == pRecvPacket) { | ||
97 | status = A_NO_MEMORY; | ||
98 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to alloc HTC struct \n")); | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | A_MEMZERO(pRecvPacket,sizeof(struct htc_packet)); | ||
103 | |||
104 | SET_HTC_PACKET_INFO_RX_REFILL(pRecvPacket,NULL,pBuffer,*pLength,HCI_EVENT_TYPE); | ||
105 | |||
106 | status = HCI_TransportRecvHCIEventSync(pConfig->pHCIDev, | ||
107 | pRecvPacket, | ||
108 | HCI_EVENT_RESP_TIMEOUTMS); | ||
109 | if (status) { | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | *pLength = pRecvPacket->ActualLength; | ||
114 | |||
115 | } while (false); | ||
116 | |||
117 | if (pRecvPacket != NULL) { | ||
118 | kfree(pRecvPacket); | ||
119 | } | ||
120 | |||
121 | return status; | ||
122 | } | ||
123 | |||
124 | int SendHCICommandWaitCommandComplete(struct ar3k_config_info *pConfig, | ||
125 | u8 *pHCICommand, | ||
126 | int CmdLength, | ||
127 | u8 **ppEventBuffer, | ||
128 | u8 **ppBufferToFree) | ||
129 | { | ||
130 | int status = 0; | ||
131 | u8 *pBuffer = NULL; | ||
132 | u8 *pTemp; | ||
133 | int length; | ||
134 | bool commandComplete = false; | ||
135 | u8 opCodeBytes[2]; | ||
136 | |||
137 | do { | ||
138 | |||
139 | length = max(HCI_MAX_EVT_RECV_LENGTH,CmdLength); | ||
140 | length += pConfig->pHCIProps->HeadRoom + pConfig->pHCIProps->TailRoom; | ||
141 | length += pConfig->pHCIProps->IOBlockPad; | ||
142 | |||
143 | pBuffer = (u8 *)A_MALLOC(length); | ||
144 | if (NULL == pBuffer) { | ||
145 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to allocate bt buffer \n")); | ||
146 | status = A_NO_MEMORY; | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | /* get the opcodes to check the command complete event */ | ||
151 | opCodeBytes[0] = pHCICommand[HCI_CMD_OPCODE_BYTE_LOW_OFFSET]; | ||
152 | opCodeBytes[1] = pHCICommand[HCI_CMD_OPCODE_BYTE_HI_OFFSET]; | ||
153 | |||
154 | /* copy HCI command */ | ||
155 | memcpy(pBuffer + pConfig->pHCIProps->HeadRoom,pHCICommand,CmdLength); | ||
156 | /* send command */ | ||
157 | status = SendHCICommand(pConfig, | ||
158 | pBuffer + pConfig->pHCIProps->HeadRoom, | ||
159 | CmdLength); | ||
160 | if (status) { | ||
161 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Failed to send HCI Command (%d) \n", status)); | ||
162 | AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command"); | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | /* reuse buffer to capture command complete event */ | ||
167 | A_MEMZERO(pBuffer,length); | ||
168 | status = RecvHCIEvent(pConfig,pBuffer,&length); | ||
169 | if (status) { | ||
170 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI event recv failed \n")); | ||
171 | AR_DEBUG_PRINTBUF(pHCICommand,CmdLength,"HCI Bridge Failed HCI Command"); | ||
172 | break; | ||
173 | } | ||
174 | |||
175 | pTemp = pBuffer + pConfig->pHCIProps->HeadRoom; | ||
176 | if (pTemp[0] == HCI_CMD_COMPLETE_EVENT_CODE) { | ||
177 | if ((pTemp[HCI_EVENT_OPCODE_BYTE_LOW] == opCodeBytes[0]) && | ||
178 | (pTemp[HCI_EVENT_OPCODE_BYTE_HI] == opCodeBytes[1])) { | ||
179 | commandComplete = true; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | if (!commandComplete) { | ||
184 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Unexpected HCI event : %d \n",pTemp[0])); | ||
185 | AR_DEBUG_PRINTBUF(pTemp,pTemp[1],"Unexpected HCI event"); | ||
186 | status = A_ECOMM; | ||
187 | break; | ||
188 | } | ||
189 | |||
190 | if (ppEventBuffer != NULL) { | ||
191 | /* caller wants to look at the event */ | ||
192 | *ppEventBuffer = pTemp; | ||
193 | if (ppBufferToFree == NULL) { | ||
194 | status = A_EINVAL; | ||
195 | break; | ||
196 | } | ||
197 | /* caller must free the buffer */ | ||
198 | *ppBufferToFree = pBuffer; | ||
199 | pBuffer = NULL; | ||
200 | } | ||
201 | |||
202 | } while (false); | ||
203 | |||
204 | if (pBuffer != NULL) { | ||
205 | kfree(pBuffer); | ||
206 | } | ||
207 | |||
208 | return status; | ||
209 | } | ||
210 | |||
211 | static int AR3KConfigureHCIBaud(struct ar3k_config_info *pConfig) | ||
212 | { | ||
213 | int status = 0; | ||
214 | u8 hciBaudChangeCommand[] = {0x0c,0xfc,0x2,0,0}; | ||
215 | u16 baudVal; | ||
216 | u8 *pEvent = NULL; | ||
217 | u8 *pBufferToFree = NULL; | ||
218 | |||
219 | do { | ||
220 | |||
221 | if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR3K_BAUD) { | ||
222 | baudVal = (u16)(pConfig->AR3KBaudRate / 100); | ||
223 | hciBaudChangeCommand[3] = (u8)baudVal; | ||
224 | hciBaudChangeCommand[4] = (u8)(baudVal >> 8); | ||
225 | |||
226 | status = SendHCICommandWaitCommandComplete(pConfig, | ||
227 | hciBaudChangeCommand, | ||
228 | sizeof(hciBaudChangeCommand), | ||
229 | &pEvent, | ||
230 | &pBufferToFree); | ||
231 | if (status) { | ||
232 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Baud rate change failed! \n")); | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | if (pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET] != 0) { | ||
237 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, | ||
238 | ("AR3K Config: Baud change command event status failed: %d \n", | ||
239 | pEvent[BAUD_CHANGE_COMMAND_STATUS_OFFSET])); | ||
240 | status = A_ECOMM; | ||
241 | break; | ||
242 | } | ||
243 | |||
244 | AR_DEBUG_PRINTF(ATH_DEBUG_ANY, | ||
245 | ("AR3K Config: Baud Changed to %d \n",pConfig->AR3KBaudRate)); | ||
246 | } | ||
247 | |||
248 | if (pConfig->Flags & AR3K_CONFIG_FLAG_AR3K_BAUD_CHANGE_DELAY) { | ||
249 | /* some versions of AR3K do not switch baud immediately, up to 300MS */ | ||
250 | A_MDELAY(325); | ||
251 | } | ||
252 | |||
253 | if (pConfig->Flags & AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP) { | ||
254 | /* Tell target to change UART baud rate for AR6K */ | ||
255 | status = HCI_TransportSetBaudRate(pConfig->pHCIDev, pConfig->AR3KBaudRate); | ||
256 | |||
257 | if (status) { | ||
258 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, | ||
259 | ("AR3K Config: failed to set scale and step values: %d \n", status)); | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | AR_DEBUG_PRINTF(ATH_DEBUG_ANY, | ||
264 | ("AR3K Config: Baud changed to %d for AR6K\n", pConfig->AR3KBaudRate)); | ||
265 | } | ||
266 | |||
267 | } while (false); | ||
268 | |||
269 | if (pBufferToFree != NULL) { | ||
270 | kfree(pBufferToFree); | ||
271 | } | ||
272 | |||
273 | return status; | ||
274 | } | ||
275 | |||
276 | static int AR3KExitMinBoot(struct ar3k_config_info *pConfig) | ||
277 | { | ||
278 | int status; | ||
279 | char exitMinBootCmd[] = {0x25,0xFC,0x0c,0x03,0x00,0x00,0x00,0x00,0x00,0x00, | ||
280 | 0x00,0x00,0x00,0x00,0x00}; | ||
281 | u8 *pEvent = NULL; | ||
282 | u8 *pBufferToFree = NULL; | ||
283 | |||
284 | status = SendHCICommandWaitCommandComplete(pConfig, | ||
285 | exitMinBootCmd, | ||
286 | sizeof(exitMinBootCmd), | ||
287 | &pEvent, | ||
288 | &pBufferToFree); | ||
289 | |||
290 | if (!status) { | ||
291 | if (pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET] != 0) { | ||
292 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, | ||
293 | ("AR3K Config: MinBoot exit command event status failed: %d \n", | ||
294 | pEvent[EXIT_MIN_BOOT_COMMAND_STATUS_OFFSET])); | ||
295 | status = A_ECOMM; | ||
296 | } else { | ||
297 | AR_DEBUG_PRINTF(ATH_DEBUG_INFO, | ||
298 | ("AR3K Config: MinBoot Exit Command Complete (Success) \n")); | ||
299 | A_MDELAY(1); | ||
300 | } | ||
301 | } else { | ||
302 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: MinBoot Exit Failed! \n")); | ||
303 | } | ||
304 | |||
305 | if (pBufferToFree != NULL) { | ||
306 | kfree(pBufferToFree); | ||
307 | } | ||
308 | |||
309 | return status; | ||
310 | } | ||
311 | |||
312 | static int AR3KConfigureSendHCIReset(struct ar3k_config_info *pConfig) | ||
313 | { | ||
314 | int status = 0; | ||
315 | u8 hciResetCommand[] = {0x03,0x0c,0x0}; | ||
316 | u8 *pEvent = NULL; | ||
317 | u8 *pBufferToFree = NULL; | ||
318 | |||
319 | status = SendHCICommandWaitCommandComplete( pConfig, | ||
320 | hciResetCommand, | ||
321 | sizeof(hciResetCommand), | ||
322 | &pEvent, | ||
323 | &pBufferToFree ); | ||
324 | |||
325 | if (status) { | ||
326 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: HCI reset failed! \n")); | ||
327 | } | ||
328 | |||
329 | if (pBufferToFree != NULL) { | ||
330 | kfree(pBufferToFree); | ||
331 | } | ||
332 | |||
333 | return status; | ||
334 | } | ||
335 | |||
336 | static int AR3KEnableTLPM(struct ar3k_config_info *pConfig) | ||
337 | { | ||
338 | int status; | ||
339 | /* AR3K vendor specific command for Host Wakeup Config */ | ||
340 | char hostWakeupConfig[] = {0x31,0xFC,0x18, | ||
341 | 0x02,0x00,0x00,0x00, | ||
342 | 0x01,0x00,0x00,0x00, | ||
343 | TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms | ||
344 | 0x00,0x00,0x00,0x00, | ||
345 | TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms | ||
346 | 0x00,0x00,0x00,0x00}; | ||
347 | /* AR3K vendor specific command for Target Wakeup Config */ | ||
348 | char targetWakeupConfig[] = {0x31,0xFC,0x18, | ||
349 | 0x04,0x00,0x00,0x00, | ||
350 | 0x01,0x00,0x00,0x00, | ||
351 | TLPM_DEFAULT_IDLE_TIMEOUT_LSB,TLPM_DEFAULT_IDLE_TIMEOUT_MSB,0x00,0x00, //idle timeout in ms | ||
352 | 0x00,0x00,0x00,0x00, | ||
353 | TLPM_DEFAULT_WAKEUP_TIMEOUT_MS,0x00,0x00,0x00, //wakeup timeout in ms | ||
354 | 0x00,0x00,0x00,0x00}; | ||
355 | /* AR3K vendor specific command for Host Wakeup Enable */ | ||
356 | char hostWakeupEnable[] = {0x31,0xFC,0x4, | ||
357 | 0x01,0x00,0x00,0x00}; | ||
358 | /* AR3K vendor specific command for Target Wakeup Enable */ | ||
359 | char targetWakeupEnable[] = {0x31,0xFC,0x4, | ||
360 | 0x06,0x00,0x00,0x00}; | ||
361 | /* AR3K vendor specific command for Sleep Enable */ | ||
362 | char sleepEnable[] = {0x4,0xFC,0x1, | ||
363 | 0x1}; | ||
364 | u8 *pEvent = NULL; | ||
365 | u8 *pBufferToFree = NULL; | ||
366 | |||
367 | if (0 != pConfig->IdleTimeout) { | ||
368 | u8 idle_lsb = pConfig->IdleTimeout & 0xFF; | ||
369 | u8 idle_msb = (pConfig->IdleTimeout & 0xFF00) >> 8; | ||
370 | hostWakeupConfig[11] = targetWakeupConfig[11] = idle_lsb; | ||
371 | hostWakeupConfig[12] = targetWakeupConfig[12] = idle_msb; | ||
372 | } | ||
373 | |||
374 | if (0 != pConfig->WakeupTimeout) { | ||
375 | hostWakeupConfig[19] = targetWakeupConfig[19] = (pConfig->WakeupTimeout & 0xFF); | ||
376 | } | ||
377 | |||
378 | status = SendHCICommandWaitCommandComplete(pConfig, | ||
379 | hostWakeupConfig, | ||
380 | sizeof(hostWakeupConfig), | ||
381 | &pEvent, | ||
382 | &pBufferToFree); | ||
383 | if (pBufferToFree != NULL) { | ||
384 | kfree(pBufferToFree); | ||
385 | } | ||
386 | if (status) { | ||
387 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Config Failed! \n")); | ||
388 | return status; | ||
389 | } | ||
390 | |||
391 | pEvent = NULL; | ||
392 | pBufferToFree = NULL; | ||
393 | status = SendHCICommandWaitCommandComplete(pConfig, | ||
394 | targetWakeupConfig, | ||
395 | sizeof(targetWakeupConfig), | ||
396 | &pEvent, | ||
397 | &pBufferToFree); | ||
398 | if (pBufferToFree != NULL) { | ||
399 | kfree(pBufferToFree); | ||
400 | } | ||
401 | if (status) { | ||
402 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Config Failed! \n")); | ||
403 | return status; | ||
404 | } | ||
405 | |||
406 | pEvent = NULL; | ||
407 | pBufferToFree = NULL; | ||
408 | status = SendHCICommandWaitCommandComplete(pConfig, | ||
409 | hostWakeupEnable, | ||
410 | sizeof(hostWakeupEnable), | ||
411 | &pEvent, | ||
412 | &pBufferToFree); | ||
413 | if (pBufferToFree != NULL) { | ||
414 | kfree(pBufferToFree); | ||
415 | } | ||
416 | if (status) { | ||
417 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HostWakeup Enable Failed! \n")); | ||
418 | return status; | ||
419 | } | ||
420 | |||
421 | pEvent = NULL; | ||
422 | pBufferToFree = NULL; | ||
423 | status = SendHCICommandWaitCommandComplete(pConfig, | ||
424 | targetWakeupEnable, | ||
425 | sizeof(targetWakeupEnable), | ||
426 | &pEvent, | ||
427 | &pBufferToFree); | ||
428 | if (pBufferToFree != NULL) { | ||
429 | kfree(pBufferToFree); | ||
430 | } | ||
431 | if (status) { | ||
432 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Target Wakeup Enable Failed! \n")); | ||
433 | return status; | ||
434 | } | ||
435 | |||
436 | pEvent = NULL; | ||
437 | pBufferToFree = NULL; | ||
438 | status = SendHCICommandWaitCommandComplete(pConfig, | ||
439 | sleepEnable, | ||
440 | sizeof(sleepEnable), | ||
441 | &pEvent, | ||
442 | &pBufferToFree); | ||
443 | if (pBufferToFree != NULL) { | ||
444 | kfree(pBufferToFree); | ||
445 | } | ||
446 | if (status) { | ||
447 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Sleep Enable Failed! \n")); | ||
448 | } | ||
449 | |||
450 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR3K Config: Enable TLPM Completed (status = %d) \n",status)); | ||
451 | |||
452 | return status; | ||
453 | } | ||
454 | |||
455 | int AR3KConfigure(struct ar3k_config_info *pConfig) | ||
456 | { | ||
457 | int status = 0; | ||
458 | |||
459 | AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuring AR3K ...\n")); | ||
460 | |||
461 | do { | ||
462 | |||
463 | if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) { | ||
464 | status = A_EINVAL; | ||
465 | break; | ||
466 | } | ||
467 | |||
468 | /* disable asynchronous recv while we issue commands and receive events synchronously */ | ||
469 | status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,false); | ||
470 | if (status) { | ||
471 | break; | ||
472 | } | ||
473 | |||
474 | if (pConfig->Flags & AR3K_CONFIG_FLAG_FORCE_MINBOOT_EXIT) { | ||
475 | status = AR3KExitMinBoot(pConfig); | ||
476 | if (status) { | ||
477 | break; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | |||
482 | /* Load patching and PST file if available*/ | ||
483 | if (0 != AthPSInitialize(pConfig)) { | ||
484 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch Download Failed!\n")); | ||
485 | } | ||
486 | |||
487 | /* Send HCI reset to make PS tags take effect*/ | ||
488 | AR3KConfigureSendHCIReset(pConfig); | ||
489 | |||
490 | if (pConfig->Flags & | ||
491 | (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) { | ||
492 | status = AR3KConfigureHCIBaud(pConfig); | ||
493 | if (status) { | ||
494 | break; | ||
495 | } | ||
496 | } | ||
497 | |||
498 | |||
499 | |||
500 | if (pConfig->PwrMgmtEnabled) { | ||
501 | /* the delay is required after the previous HCI reset before further | ||
502 | * HCI commands can be issued | ||
503 | */ | ||
504 | A_MDELAY(200); | ||
505 | AR3KEnableTLPM(pConfig); | ||
506 | } | ||
507 | |||
508 | /* re-enable asynchronous recv */ | ||
509 | status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,true); | ||
510 | if (status) { | ||
511 | break; | ||
512 | } | ||
513 | |||
514 | |||
515 | } while (false); | ||
516 | |||
517 | |||
518 | AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Configuration Complete (status = %d) \n",status)); | ||
519 | |||
520 | return status; | ||
521 | } | ||
522 | |||
523 | int AR3KConfigureExit(void *config) | ||
524 | { | ||
525 | int status = 0; | ||
526 | struct ar3k_config_info *pConfig = (struct ar3k_config_info *)config; | ||
527 | |||
528 | AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleaning up AR3K ...\n")); | ||
529 | |||
530 | do { | ||
531 | |||
532 | if ((pConfig->pHCIDev == NULL) || (pConfig->pHCIProps == NULL) || (pConfig->pHIFDevice == NULL)) { | ||
533 | status = A_EINVAL; | ||
534 | break; | ||
535 | } | ||
536 | |||
537 | /* disable asynchronous recv while we issue commands and receive events synchronously */ | ||
538 | status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,false); | ||
539 | if (status) { | ||
540 | break; | ||
541 | } | ||
542 | |||
543 | if (pConfig->Flags & | ||
544 | (AR3K_CONFIG_FLAG_SET_AR3K_BAUD | AR3K_CONFIG_FLAG_SET_AR6K_SCALE_STEP)) { | ||
545 | status = AR3KConfigureHCIBaud(pConfig); | ||
546 | if (status) { | ||
547 | break; | ||
548 | } | ||
549 | } | ||
550 | |||
551 | /* re-enable asynchronous recv */ | ||
552 | status = HCI_TransportEnableDisableAsyncRecv(pConfig->pHCIDev,true); | ||
553 | if (status) { | ||
554 | break; | ||
555 | } | ||
556 | |||
557 | |||
558 | } while (false); | ||
559 | |||
560 | |||
561 | AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("AR3K Config: Cleanup Complete (status = %d) \n",status)); | ||
562 | |||
563 | return status; | ||
564 | } | ||
565 | |||
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c new file mode 100644 index 00000000000..282ceac597b --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c | |||
@@ -0,0 +1,572 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2010 Atheros Communications Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This file implements the Atheros PS and patch downloaded for HCI UART Transport driver. | ||
6 | * This file can be used for HCI SDIO transport implementation for AR6002 with HCI_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 | #define MAX_FW_PATH_LEN 50 | ||
36 | #define MAX_BDADDR_FORMAT_LENGTH 30 | ||
37 | |||
38 | /* | ||
39 | * Structure used to send HCI packet, hci packet length and device info | ||
40 | * together as parameter to PSThread. | ||
41 | */ | ||
42 | typedef struct { | ||
43 | |||
44 | struct ps_cmd_packet *HciCmdList; | ||
45 | u32 num_packets; | ||
46 | struct ar3k_config_info *dev; | ||
47 | }HciCommandListParam; | ||
48 | |||
49 | int SendHCICommandWaitCommandComplete(struct ar3k_config_info *pConfig, | ||
50 | u8 *pHCICommand, | ||
51 | int CmdLength, | ||
52 | u8 **ppEventBuffer, | ||
53 | u8 **ppBufferToFree); | ||
54 | |||
55 | u32 Rom_Version; | ||
56 | u32 Build_Version; | ||
57 | extern bool BDADDR; | ||
58 | |||
59 | int getDeviceType(struct ar3k_config_info *pConfig, u32 *code); | ||
60 | int ReadVersionInfo(struct ar3k_config_info *pConfig); | ||
61 | #ifndef HCI_TRANSPORT_SDIO | ||
62 | |||
63 | DECLARE_WAIT_QUEUE_HEAD(PsCompleteEvent); | ||
64 | DECLARE_WAIT_QUEUE_HEAD(HciEvent); | ||
65 | u8 *HciEventpacket; | ||
66 | rwlock_t syncLock; | ||
67 | wait_queue_t Eventwait; | ||
68 | |||
69 | int PSHciWritepacket(struct hci_dev*,u8* Data, u32 len); | ||
70 | extern char *bdaddr; | ||
71 | #endif /* HCI_TRANSPORT_SDIO */ | ||
72 | |||
73 | int write_bdaddr(struct ar3k_config_info *pConfig,u8 *bdaddr,int type); | ||
74 | |||
75 | int PSSendOps(void *arg); | ||
76 | |||
77 | #ifdef BT_PS_DEBUG | ||
78 | void Hci_log(u8 * log_string,u8 *data,u32 len) | ||
79 | { | ||
80 | int i; | ||
81 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s : ",log_string)); | ||
82 | for (i = 0; i < len; i++) { | ||
83 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("0x%02x ", data[i])); | ||
84 | } | ||
85 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("\n...................................\n")); | ||
86 | } | ||
87 | #else | ||
88 | #define Hci_log(string,data,len) | ||
89 | #endif /* BT_PS_DEBUG */ | ||
90 | |||
91 | |||
92 | |||
93 | |||
94 | int AthPSInitialize(struct ar3k_config_info *hdev) | ||
95 | { | ||
96 | int status = 0; | ||
97 | if(hdev == NULL) { | ||
98 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Invalid Device handle received\n")); | ||
99 | return A_ERROR; | ||
100 | } | ||
101 | |||
102 | #ifndef HCI_TRANSPORT_SDIO | ||
103 | DECLARE_WAITQUEUE(wait, current); | ||
104 | #endif /* HCI_TRANSPORT_SDIO */ | ||
105 | |||
106 | |||
107 | #ifdef HCI_TRANSPORT_SDIO | ||
108 | status = PSSendOps((void*)hdev); | ||
109 | #else | ||
110 | if(InitPSState(hdev) == -1) { | ||
111 | return A_ERROR; | ||
112 | } | ||
113 | allow_signal(SIGKILL); | ||
114 | add_wait_queue(&PsCompleteEvent,&wait); | ||
115 | set_current_state(TASK_INTERRUPTIBLE); | ||
116 | if(!kernel_thread(PSSendOps,(void*)hdev,CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD)) { | ||
117 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Kthread Failed\n")); | ||
118 | remove_wait_queue(&PsCompleteEvent,&wait); | ||
119 | return A_ERROR; | ||
120 | } | ||
121 | wait_event_interruptible(PsCompleteEvent,(PSTagMode == false)); | ||
122 | set_current_state(TASK_RUNNING); | ||
123 | remove_wait_queue(&PsCompleteEvent,&wait); | ||
124 | |||
125 | #endif /* HCI_TRANSPORT_SDIO */ | ||
126 | |||
127 | |||
128 | return status; | ||
129 | |||
130 | } | ||
131 | |||
132 | int PSSendOps(void *arg) | ||
133 | { | ||
134 | int i; | ||
135 | int status = 0; | ||
136 | struct ps_cmd_packet *HciCmdList; /* List storing the commands */ | ||
137 | const struct firmware* firmware; | ||
138 | u32 numCmds; | ||
139 | u8 *event; | ||
140 | u8 *bufferToFree; | ||
141 | struct hci_dev *device; | ||
142 | u8 *buffer; | ||
143 | u32 len; | ||
144 | u32 DevType; | ||
145 | u8 *PsFileName; | ||
146 | u8 *patchFileName; | ||
147 | u8 *path = NULL; | ||
148 | u8 *config_path = NULL; | ||
149 | u8 config_bdaddr[MAX_BDADDR_FORMAT_LENGTH]; | ||
150 | struct ar3k_config_info *hdev = (struct ar3k_config_info*)arg; | ||
151 | struct device *firmwareDev = NULL; | ||
152 | status = 0; | ||
153 | HciCmdList = NULL; | ||
154 | #ifdef HCI_TRANSPORT_SDIO | ||
155 | device = hdev->pBtStackHCIDev; | ||
156 | firmwareDev = device->parent; | ||
157 | #else | ||
158 | device = hdev; | ||
159 | firmwareDev = &device->dev; | ||
160 | AthEnableSyncCommandOp(true); | ||
161 | #endif /* HCI_TRANSPORT_SDIO */ | ||
162 | /* 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. | ||
163 | */ | ||
164 | |||
165 | path =(u8 *)A_MALLOC(MAX_FW_PATH_LEN); | ||
166 | if(path == NULL) { | ||
167 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Malloc failed to allocate %d bytes for path\n", MAX_FW_PATH_LEN)); | ||
168 | goto complete; | ||
169 | } | ||
170 | config_path = (u8 *) A_MALLOC(MAX_FW_PATH_LEN); | ||
171 | if(config_path == NULL) { | ||
172 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Malloc failed to allocate %d bytes for config_path\n", MAX_FW_PATH_LEN)); | ||
173 | goto complete; | ||
174 | } | ||
175 | |||
176 | if(A_ERROR == getDeviceType(hdev,&DevType)) { | ||
177 | status = 1; | ||
178 | goto complete; | ||
179 | } | ||
180 | if(A_ERROR == ReadVersionInfo(hdev)) { | ||
181 | status = 1; | ||
182 | goto complete; | ||
183 | } | ||
184 | |||
185 | patchFileName = PATCH_FILE; | ||
186 | snprintf(path, MAX_FW_PATH_LEN, "%s/%xcoex/",CONFIG_PATH,Rom_Version); | ||
187 | if(DevType){ | ||
188 | if(DevType == 0xdeadc0de){ | ||
189 | PsFileName = PS_ASIC_FILE; | ||
190 | } else{ | ||
191 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" FPGA Test Image : %x %x \n",Rom_Version,Build_Version)); | ||
192 | if((Rom_Version == 0x99999999) && (Build_Version == 1)){ | ||
193 | |||
194 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("FPGA Test Image : Skipping Patch File load\n")); | ||
195 | patchFileName = NULL; | ||
196 | } | ||
197 | PsFileName = PS_FPGA_FILE; | ||
198 | } | ||
199 | } | ||
200 | else{ | ||
201 | PsFileName = PS_ASIC_FILE; | ||
202 | } | ||
203 | |||
204 | snprintf(config_path, MAX_FW_PATH_LEN, "%s%s",path,PsFileName); | ||
205 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%x: FPGA/ASIC PS File Name %s\n", DevType,config_path)); | ||
206 | /* Read the PS file to a dynamically allocated buffer */ | ||
207 | if(A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0) { | ||
208 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ )); | ||
209 | status = 1; | ||
210 | goto complete; | ||
211 | |||
212 | } | ||
213 | if(NULL == firmware || firmware->size == 0) { | ||
214 | status = 1; | ||
215 | goto complete; | ||
216 | } | ||
217 | buffer = (u8 *)A_MALLOC(firmware->size); | ||
218 | if(buffer != NULL) { | ||
219 | /* Copy the read file to a local Dynamic buffer */ | ||
220 | memcpy(buffer,firmware->data,firmware->size); | ||
221 | len = firmware->size; | ||
222 | A_RELEASE_FIRMWARE(firmware); | ||
223 | /* Parse the PS buffer to a global variable */ | ||
224 | status = AthDoParsePS(buffer,len); | ||
225 | kfree(buffer); | ||
226 | } else { | ||
227 | A_RELEASE_FIRMWARE(firmware); | ||
228 | } | ||
229 | |||
230 | |||
231 | /* Read the patch file to a dynamically allocated buffer */ | ||
232 | if(patchFileName != NULL) | ||
233 | snprintf(config_path, | ||
234 | MAX_FW_PATH_LEN, "%s%s",path,patchFileName); | ||
235 | else { | ||
236 | status = 0; | ||
237 | } | ||
238 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch File Name %s\n", config_path)); | ||
239 | if((patchFileName == NULL) || (A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0)) { | ||
240 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ )); | ||
241 | /* | ||
242 | * It is not necessary that Patch file be available, continue with PS Operations if. | ||
243 | * failed. | ||
244 | */ | ||
245 | status = 0; | ||
246 | |||
247 | } else { | ||
248 | if(NULL == firmware || firmware->size == 0) { | ||
249 | status = 0; | ||
250 | } else { | ||
251 | buffer = (u8 *)A_MALLOC(firmware->size); | ||
252 | if(buffer != NULL) { | ||
253 | /* Copy the read file to a local Dynamic buffer */ | ||
254 | memcpy(buffer,firmware->data,firmware->size); | ||
255 | len = firmware->size; | ||
256 | A_RELEASE_FIRMWARE(firmware); | ||
257 | /* parse and store the Patch file contents to a global variables */ | ||
258 | status = AthDoParsePatch(buffer,len); | ||
259 | kfree(buffer); | ||
260 | } else { | ||
261 | A_RELEASE_FIRMWARE(firmware); | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* Create an HCI command list from the parsed PS and patch information */ | ||
267 | AthCreateCommandList(&HciCmdList,&numCmds); | ||
268 | |||
269 | /* Form the parameter for PSSendOps() API */ | ||
270 | |||
271 | |||
272 | /* | ||
273 | * First Send the CRC packet, | ||
274 | * We have to continue with the PS operations only if the CRC packet has been replied with | ||
275 | * a Command complete event with status Error. | ||
276 | */ | ||
277 | |||
278 | if(SendHCICommandWaitCommandComplete | ||
279 | (hdev, | ||
280 | HciCmdList[0].Hcipacket, | ||
281 | HciCmdList[0].packetLen, | ||
282 | &event, | ||
283 | &bufferToFree) == 0) { | ||
284 | if(ReadPSEvent(event) == 0) { /* Exit if the status is success */ | ||
285 | if(bufferToFree != NULL) { | ||
286 | kfree(bufferToFree); | ||
287 | } | ||
288 | |||
289 | #ifndef HCI_TRANSPORT_SDIO | ||
290 | if(bdaddr && bdaddr[0] !='\0') { | ||
291 | write_bdaddr(hdev,bdaddr,BDADDR_TYPE_STRING); | ||
292 | } | ||
293 | #endif | ||
294 | status = 1; | ||
295 | goto complete; | ||
296 | } | ||
297 | if(bufferToFree != NULL) { | ||
298 | kfree(bufferToFree); | ||
299 | } | ||
300 | } else { | ||
301 | status = 0; | ||
302 | goto complete; | ||
303 | } | ||
304 | |||
305 | for(i = 1; i <numCmds; i++) { | ||
306 | |||
307 | if(SendHCICommandWaitCommandComplete | ||
308 | (hdev, | ||
309 | HciCmdList[i].Hcipacket, | ||
310 | HciCmdList[i].packetLen, | ||
311 | &event, | ||
312 | &bufferToFree) == 0) { | ||
313 | if(ReadPSEvent(event) != 0) { /* Exit if the status is success */ | ||
314 | if(bufferToFree != NULL) { | ||
315 | kfree(bufferToFree); | ||
316 | } | ||
317 | status = 1; | ||
318 | goto complete; | ||
319 | } | ||
320 | if(bufferToFree != NULL) { | ||
321 | kfree(bufferToFree); | ||
322 | } | ||
323 | } else { | ||
324 | status = 0; | ||
325 | goto complete; | ||
326 | } | ||
327 | } | ||
328 | #ifdef HCI_TRANSPORT_SDIO | ||
329 | if(BDADDR == false) | ||
330 | if(hdev->bdaddr[0] !=0x00 || | ||
331 | hdev->bdaddr[1] !=0x00 || | ||
332 | hdev->bdaddr[2] !=0x00 || | ||
333 | hdev->bdaddr[3] !=0x00 || | ||
334 | hdev->bdaddr[4] !=0x00 || | ||
335 | hdev->bdaddr[5] !=0x00) | ||
336 | write_bdaddr(hdev,hdev->bdaddr,BDADDR_TYPE_HEX); | ||
337 | |||
338 | #ifndef HCI_TRANSPORT_SDIO | ||
339 | |||
340 | if(bdaddr && bdaddr[0] != '\0') { | ||
341 | write_bdaddr(hdev,bdaddr,BDADDR_TYPE_STRING); | ||
342 | } else | ||
343 | #endif /* HCI_TRANSPORT_SDIO */ | ||
344 | /* Write BDADDR Read from OTP here */ | ||
345 | |||
346 | |||
347 | |||
348 | #endif | ||
349 | |||
350 | { | ||
351 | /* Read Contents of BDADDR file if user has not provided any option */ | ||
352 | snprintf(config_path,MAX_FW_PATH_LEN, "%s%s",path,BDADDR_FILE); | ||
353 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Patch File Name %s\n", config_path)); | ||
354 | if(A_REQUEST_FIRMWARE(&firmware,config_path,firmwareDev) < 0) { | ||
355 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: firmware file open error\n", __FUNCTION__ )); | ||
356 | status = 1; | ||
357 | goto complete; | ||
358 | } | ||
359 | if(NULL == firmware || firmware->size == 0) { | ||
360 | status = 1; | ||
361 | goto complete; | ||
362 | } | ||
363 | len = min_t(size_t, firmware->size, MAX_BDADDR_FORMAT_LENGTH - 1); | ||
364 | memcpy(config_bdaddr, firmware->data, len); | ||
365 | config_bdaddr[len] = '\0'; | ||
366 | write_bdaddr(hdev,config_bdaddr,BDADDR_TYPE_STRING); | ||
367 | A_RELEASE_FIRMWARE(firmware); | ||
368 | } | ||
369 | complete: | ||
370 | #ifndef HCI_TRANSPORT_SDIO | ||
371 | AthEnableSyncCommandOp(false); | ||
372 | PSTagMode = false; | ||
373 | wake_up_interruptible(&PsCompleteEvent); | ||
374 | #endif /* HCI_TRANSPORT_SDIO */ | ||
375 | if(NULL != HciCmdList) { | ||
376 | AthFreeCommandList(&HciCmdList,numCmds); | ||
377 | } | ||
378 | if(path) { | ||
379 | kfree(path); | ||
380 | } | ||
381 | if(config_path) { | ||
382 | kfree(config_path); | ||
383 | } | ||
384 | return status; | ||
385 | } | ||
386 | #ifndef HCI_TRANSPORT_SDIO | ||
387 | /* | ||
388 | * This API is used to send the HCI command to controller and return | ||
389 | * with a HCI Command Complete event. | ||
390 | * For HCI SDIO transport, this will be internally defined. | ||
391 | */ | ||
392 | int SendHCICommandWaitCommandComplete(struct ar3k_config_info *pConfig, | ||
393 | u8 *pHCICommand, | ||
394 | int CmdLength, | ||
395 | u8 **ppEventBuffer, | ||
396 | u8 **ppBufferToFree) | ||
397 | { | ||
398 | if(CmdLength == 0) { | ||
399 | return A_ERROR; | ||
400 | } | ||
401 | Hci_log("COM Write -->",pHCICommand,CmdLength); | ||
402 | PSAcked = false; | ||
403 | if(PSHciWritepacket(pConfig,pHCICommand,CmdLength) == 0) { | ||
404 | /* If the controller is not available, return Error */ | ||
405 | return A_ERROR; | ||
406 | } | ||
407 | //add_timer(&psCmdTimer); | ||
408 | wait_event_interruptible(HciEvent,(PSAcked == true)); | ||
409 | if(NULL != HciEventpacket) { | ||
410 | *ppEventBuffer = HciEventpacket; | ||
411 | *ppBufferToFree = HciEventpacket; | ||
412 | } else { | ||
413 | /* Did not get an event from controller. return error */ | ||
414 | *ppBufferToFree = NULL; | ||
415 | return A_ERROR; | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | #endif /* HCI_TRANSPORT_SDIO */ | ||
421 | |||
422 | int ReadPSEvent(u8* Data){ | ||
423 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" PS Event %x %x %x\n",Data[4],Data[5],Data[3])); | ||
424 | |||
425 | if(Data[4] == 0xFC && Data[5] == 0x00) | ||
426 | { | ||
427 | switch(Data[3]){ | ||
428 | case 0x0B: | ||
429 | return 0; | ||
430 | break; | ||
431 | case 0x0C: | ||
432 | /* Change Baudrate */ | ||
433 | return 0; | ||
434 | break; | ||
435 | case 0x04: | ||
436 | return 0; | ||
437 | break; | ||
438 | case 0x1E: | ||
439 | Rom_Version = Data[9]; | ||
440 | Rom_Version = ((Rom_Version << 8) |Data[8]); | ||
441 | Rom_Version = ((Rom_Version << 8) |Data[7]); | ||
442 | Rom_Version = ((Rom_Version << 8) |Data[6]); | ||
443 | |||
444 | Build_Version = Data[13]; | ||
445 | Build_Version = ((Build_Version << 8) |Data[12]); | ||
446 | Build_Version = ((Build_Version << 8) |Data[11]); | ||
447 | Build_Version = ((Build_Version << 8) |Data[10]); | ||
448 | return 0; | ||
449 | break; | ||
450 | |||
451 | |||
452 | } | ||
453 | } | ||
454 | |||
455 | return A_ERROR; | ||
456 | } | ||
457 | int str2ba(unsigned char *str_bdaddr,unsigned char *bdaddr) | ||
458 | { | ||
459 | unsigned char bdbyte[3]; | ||
460 | unsigned char *str_byte = str_bdaddr; | ||
461 | int i,j; | ||
462 | unsigned char colon_present = 0; | ||
463 | |||
464 | if(NULL != strstr(str_bdaddr,":")) { | ||
465 | colon_present = 1; | ||
466 | } | ||
467 | |||
468 | |||
469 | bdbyte[2] = '\0'; | ||
470 | |||
471 | for( i = 0,j = 5; i < 6; i++, j--) { | ||
472 | bdbyte[0] = str_byte[0]; | ||
473 | bdbyte[1] = str_byte[1]; | ||
474 | bdaddr[j] = A_STRTOL(bdbyte,NULL,16); | ||
475 | if(colon_present == 1) { | ||
476 | str_byte+=3; | ||
477 | } else { | ||
478 | str_byte+=2; | ||
479 | } | ||
480 | } | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | int write_bdaddr(struct ar3k_config_info *pConfig,u8 *bdaddr,int type) | ||
485 | { | ||
486 | u8 bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A, 0x01, 0x01, | ||
487 | 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
488 | |||
489 | u8 *event; | ||
490 | u8 *bufferToFree = NULL; | ||
491 | int result = A_ERROR; | ||
492 | int inc,outc; | ||
493 | |||
494 | if (type == BDADDR_TYPE_STRING) | ||
495 | str2ba(bdaddr,&bdaddr_cmd[7]); | ||
496 | else { | ||
497 | /* Bdaddr has to be sent as LAP first */ | ||
498 | for(inc = 5 ,outc = 7; inc >=0; inc--, outc++) | ||
499 | bdaddr_cmd[outc] = bdaddr[inc]; | ||
500 | } | ||
501 | |||
502 | if(0 == SendHCICommandWaitCommandComplete(pConfig,bdaddr_cmd, | ||
503 | sizeof(bdaddr_cmd), | ||
504 | &event,&bufferToFree)) { | ||
505 | |||
506 | if(event[4] == 0xFC && event[5] == 0x00){ | ||
507 | if(event[3] == 0x0B){ | ||
508 | result = 0; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | } | ||
513 | if(bufferToFree != NULL) { | ||
514 | kfree(bufferToFree); | ||
515 | } | ||
516 | return result; | ||
517 | |||
518 | } | ||
519 | int ReadVersionInfo(struct ar3k_config_info *pConfig) | ||
520 | { | ||
521 | u8 hciCommand[] = {0x1E,0xfc,0x00}; | ||
522 | u8 *event; | ||
523 | u8 *bufferToFree = NULL; | ||
524 | int result = A_ERROR; | ||
525 | if(0 == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCommand),&event,&bufferToFree)) { | ||
526 | result = ReadPSEvent(event); | ||
527 | |||
528 | } | ||
529 | if(bufferToFree != NULL) { | ||
530 | kfree(bufferToFree); | ||
531 | } | ||
532 | return result; | ||
533 | } | ||
534 | int getDeviceType(struct ar3k_config_info *pConfig, u32 *code) | ||
535 | { | ||
536 | u8 hciCommand[] = {0x05,0xfc,0x05,0x00,0x00,0x00,0x00,0x04}; | ||
537 | u8 *event; | ||
538 | u8 *bufferToFree = NULL; | ||
539 | u32 reg; | ||
540 | int result = A_ERROR; | ||
541 | *code = 0; | ||
542 | hciCommand[3] = (u8)(FPGA_REGISTER & 0xFF); | ||
543 | hciCommand[4] = (u8)((FPGA_REGISTER >> 8) & 0xFF); | ||
544 | hciCommand[5] = (u8)((FPGA_REGISTER >> 16) & 0xFF); | ||
545 | hciCommand[6] = (u8)((FPGA_REGISTER >> 24) & 0xFF); | ||
546 | if(0 == SendHCICommandWaitCommandComplete(pConfig,hciCommand,sizeof(hciCommand),&event,&bufferToFree)) { | ||
547 | |||
548 | if(event[4] == 0xFC && event[5] == 0x00){ | ||
549 | switch(event[3]){ | ||
550 | case 0x05: | ||
551 | reg = event[9]; | ||
552 | reg = ((reg << 8) |event[8]); | ||
553 | reg = ((reg << 8) |event[7]); | ||
554 | reg = ((reg << 8) |event[6]); | ||
555 | *code = reg; | ||
556 | result = 0; | ||
557 | |||
558 | break; | ||
559 | case 0x06: | ||
560 | //Sleep(500); | ||
561 | break; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | } | ||
566 | if(bufferToFree != NULL) { | ||
567 | kfree(bufferToFree); | ||
568 | } | ||
569 | return result; | ||
570 | } | ||
571 | |||
572 | |||
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h new file mode 100644 index 00000000000..d4435130780 --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2010 Atheros Communications Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This file defines the symbols exported by Atheros PS and patch download module. | ||
6 | * define the constant HCI_TRANSPORT_SDIO if the module is being used for HCI SDIO transport. | ||
7 | * defined. | ||
8 | * | ||
9 | * | ||
10 | * ar3kcpsconfig.h | ||
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 | #ifndef __AR3KPSCONFIG_H | ||
30 | #define __AR3KPSCONFIG_H | ||
31 | |||
32 | /* | ||
33 | * Define the flag HCI_TRANSPORT_SDIO and undefine HCI_TRANSPORT_UART if the transport being used is SDIO. | ||
34 | */ | ||
35 | #undef HCI_TRANSPORT_UART | ||
36 | |||
37 | #include <linux/fs.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/signal.h> | ||
40 | |||
41 | |||
42 | #include <linux/ioctl.h> | ||
43 | #include <linux/firmware.h> | ||
44 | |||
45 | |||
46 | #include <net/bluetooth/bluetooth.h> | ||
47 | #include <net/bluetooth/hci_core.h> | ||
48 | |||
49 | #include "ar3kpsparser.h" | ||
50 | |||
51 | #define FPGA_REGISTER 0x4FFC | ||
52 | #define BDADDR_TYPE_STRING 0 | ||
53 | #define BDADDR_TYPE_HEX 1 | ||
54 | #define CONFIG_PATH "ar3k" | ||
55 | |||
56 | #define PS_ASIC_FILE "PS_ASIC.pst" | ||
57 | #define PS_FPGA_FILE "PS_FPGA.pst" | ||
58 | |||
59 | #define PATCH_FILE "RamPatch.txt" | ||
60 | #define BDADDR_FILE "ar3kbdaddr.pst" | ||
61 | |||
62 | #define ROM_VER_AR3001_3_1_0 30000 | ||
63 | #define ROM_VER_AR3001_3_1_1 30101 | ||
64 | |||
65 | |||
66 | #ifndef HCI_TRANSPORT_SDIO | ||
67 | #define struct ar3k_config_info struct hci_dev | ||
68 | extern wait_queue_head_t HciEvent; | ||
69 | extern wait_queue_t Eventwait; | ||
70 | extern u8 *HciEventpacket; | ||
71 | #endif /* #ifndef HCI_TRANSPORT_SDIO */ | ||
72 | |||
73 | int AthPSInitialize(struct ar3k_config_info *hdev); | ||
74 | int ReadPSEvent(u8* Data); | ||
75 | #endif /* __AR3KPSCONFIG_H */ | ||
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c new file mode 100644 index 00000000000..b99a11a9dd6 --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c | |||
@@ -0,0 +1,969 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2010 Atheros Communications Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This file implements the Atheros PS and patch parser. | ||
6 | * It implements APIs to parse data buffer with patch and PS information and convert it to HCI commands. | ||
7 | * | ||
8 | * | ||
9 | * | ||
10 | * ar3kpsparser.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 | #include "ar3kpsparser.h" | ||
29 | |||
30 | #include <linux/ctype.h> | ||
31 | #include <linux/kernel.h> | ||
32 | |||
33 | #define BD_ADDR_SIZE 6 | ||
34 | #define WRITE_PATCH 8 | ||
35 | #define ENABLE_PATCH 11 | ||
36 | #define PS_RESET 2 | ||
37 | #define PS_WRITE 1 | ||
38 | #define PS_VERIFY_CRC 9 | ||
39 | #define CHANGE_BDADDR 15 | ||
40 | |||
41 | #define HCI_COMMAND_HEADER 7 | ||
42 | |||
43 | #define HCI_EVENT_SIZE 7 | ||
44 | |||
45 | #define WRITE_PATCH_COMMAND_STATUS_OFFSET 5 | ||
46 | |||
47 | #define PS_RAM_SIZE 2048 | ||
48 | |||
49 | #define RAM_PS_REGION (1<<0) | ||
50 | #define RAM_PATCH_REGION (1<<1) | ||
51 | #define RAMPS_MAX_PS_DATA_PER_TAG 20000 | ||
52 | #define MAX_RADIO_CFG_TABLE_SIZE 244 | ||
53 | #define RAMPS_MAX_PS_TAGS_PER_FILE 50 | ||
54 | |||
55 | #define PS_MAX_LEN 500 | ||
56 | #define LINE_SIZE_MAX (PS_MAX_LEN *2) | ||
57 | |||
58 | /* Constant values used by parser */ | ||
59 | #define BYTES_OF_PS_DATA_PER_LINE 16 | ||
60 | #define RAMPS_MAX_PS_DATA_PER_TAG 20000 | ||
61 | |||
62 | |||
63 | /* Number pf PS/Patch entries in an HCI packet */ | ||
64 | #define MAX_BYTE_LENGTH 244 | ||
65 | |||
66 | #define SKIP_BLANKS(str) while (*str == ' ') str++ | ||
67 | |||
68 | enum MinBootFileFormatE | ||
69 | { | ||
70 | MB_FILEFORMAT_RADIOTBL, | ||
71 | MB_FILEFORMAT_PATCH, | ||
72 | MB_FILEFORMAT_COEXCONFIG | ||
73 | }; | ||
74 | |||
75 | enum RamPsSection | ||
76 | { | ||
77 | RAM_PS_SECTION, | ||
78 | RAM_PATCH_SECTION, | ||
79 | RAM_DYN_MEM_SECTION | ||
80 | }; | ||
81 | |||
82 | enum eType { | ||
83 | eHex, | ||
84 | edecimal | ||
85 | }; | ||
86 | |||
87 | |||
88 | typedef struct tPsTagEntry | ||
89 | { | ||
90 | u32 TagId; | ||
91 | u32 TagLen; | ||
92 | u8 *TagData; | ||
93 | } tPsTagEntry, *tpPsTagEntry; | ||
94 | |||
95 | typedef struct tRamPatch | ||
96 | { | ||
97 | u16 Len; | ||
98 | u8 *Data; | ||
99 | } tRamPatch, *ptRamPatch; | ||
100 | |||
101 | |||
102 | |||
103 | struct st_ps_data_format { | ||
104 | enum eType eDataType; | ||
105 | bool bIsArray; | ||
106 | }; | ||
107 | |||
108 | struct st_read_status { | ||
109 | unsigned uTagID; | ||
110 | unsigned uSection; | ||
111 | unsigned uLineCount; | ||
112 | unsigned uCharCount; | ||
113 | unsigned uByteCount; | ||
114 | }; | ||
115 | |||
116 | |||
117 | /* Stores the number of PS Tags */ | ||
118 | static u32 Tag_Count = 0; | ||
119 | |||
120 | /* Stores the number of patch commands */ | ||
121 | static u32 Patch_Count = 0; | ||
122 | static u32 Total_tag_lenght = 0; | ||
123 | bool BDADDR = false; | ||
124 | u32 StartTagId; | ||
125 | |||
126 | tPsTagEntry PsTagEntry[RAMPS_MAX_PS_TAGS_PER_FILE]; | ||
127 | tRamPatch RamPatch[MAX_NUM_PATCH_ENTRY]; | ||
128 | |||
129 | |||
130 | int AthParseFilesUnified(u8 *srcbuffer,u32 srclen, int FileFormat); | ||
131 | char AthReadChar(u8 *buffer, u32 len,u32 *pos); | ||
132 | char *AthGetLine(char *buffer, int maxlen, u8 *srcbuffer,u32 len,u32 *pos); | ||
133 | static int AthPSCreateHCICommand(u8 Opcode, u32 Param1,struct ps_cmd_packet *PSPatchPacket,u32 *index); | ||
134 | |||
135 | /* Function to reads the next character from the input buffer */ | ||
136 | char AthReadChar(u8 *buffer, u32 len,u32 *pos) | ||
137 | { | ||
138 | char Ch; | ||
139 | if(buffer == NULL || *pos >=len ) | ||
140 | { | ||
141 | return '\0'; | ||
142 | } else { | ||
143 | Ch = buffer[*pos]; | ||
144 | (*pos)++; | ||
145 | return Ch; | ||
146 | } | ||
147 | } | ||
148 | /* PS parser helper function */ | ||
149 | unsigned int uGetInputDataFormat(char *pCharLine, struct st_ps_data_format *pstFormat) | ||
150 | { | ||
151 | if(pCharLine[0] != '[') { | ||
152 | pstFormat->eDataType = eHex; | ||
153 | pstFormat->bIsArray = true; | ||
154 | return 0; | ||
155 | } | ||
156 | switch(pCharLine[1]) { | ||
157 | case 'H': | ||
158 | case 'h': | ||
159 | if(pCharLine[2]==':') { | ||
160 | if((pCharLine[3]== 'a') || (pCharLine[3]== 'A')) { | ||
161 | if(pCharLine[4] == ']') { | ||
162 | pstFormat->eDataType = eHex; | ||
163 | pstFormat->bIsArray = true; | ||
164 | pCharLine += 5; | ||
165 | return 0; | ||
166 | } | ||
167 | else { | ||
168 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); //[H:A | ||
169 | return 1; | ||
170 | } | ||
171 | } | ||
172 | if((pCharLine[3]== 'S') || (pCharLine[3]== 's')) { | ||
173 | if(pCharLine[4] == ']') { | ||
174 | pstFormat->eDataType = eHex; | ||
175 | pstFormat->bIsArray = false; | ||
176 | pCharLine += 5; | ||
177 | return 0; | ||
178 | } | ||
179 | else { | ||
180 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); //[H:A | ||
181 | return 1; | ||
182 | } | ||
183 | } | ||
184 | else if(pCharLine[3] == ']') { //[H:] | ||
185 | pstFormat->eDataType = eHex; | ||
186 | pstFormat->bIsArray = true; | ||
187 | pCharLine += 4; | ||
188 | return 0; | ||
189 | } | ||
190 | else { //[H: | ||
191 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); | ||
192 | return 1; | ||
193 | } | ||
194 | } | ||
195 | else if(pCharLine[2]==']') { //[H] | ||
196 | pstFormat->eDataType = eHex; | ||
197 | pstFormat->bIsArray = true; | ||
198 | pCharLine += 3; | ||
199 | return 0; | ||
200 | } | ||
201 | else { //[H | ||
202 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format\n")); | ||
203 | return 1; | ||
204 | } | ||
205 | break; | ||
206 | |||
207 | case 'A': | ||
208 | case 'a': | ||
209 | if(pCharLine[2]==':') { | ||
210 | if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) { | ||
211 | if(pCharLine[4] == ']') { | ||
212 | pstFormat->eDataType = eHex; | ||
213 | pstFormat->bIsArray = true; | ||
214 | pCharLine += 5; | ||
215 | return 0; | ||
216 | } | ||
217 | else { | ||
218 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 1\n")); //[A:H | ||
219 | return 1; | ||
220 | } | ||
221 | } | ||
222 | else if(pCharLine[3]== ']') { //[A:] | ||
223 | pstFormat->eDataType = eHex; | ||
224 | pstFormat->bIsArray = true; | ||
225 | pCharLine += 4; | ||
226 | return 0; | ||
227 | } | ||
228 | else { //[A: | ||
229 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 2\n")); | ||
230 | return 1; | ||
231 | } | ||
232 | } | ||
233 | else if(pCharLine[2]==']') { //[H] | ||
234 | pstFormat->eDataType = eHex; | ||
235 | pstFormat->bIsArray = true; | ||
236 | pCharLine += 3; | ||
237 | return 0; | ||
238 | } | ||
239 | else { //[H | ||
240 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 3\n")); | ||
241 | return 1; | ||
242 | } | ||
243 | break; | ||
244 | |||
245 | case 'S': | ||
246 | case 's': | ||
247 | if(pCharLine[2]==':') { | ||
248 | if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) { | ||
249 | if(pCharLine[4] == ']') { | ||
250 | pstFormat->eDataType = eHex; | ||
251 | pstFormat->bIsArray = true; | ||
252 | pCharLine += 5; | ||
253 | return 0; | ||
254 | } | ||
255 | else { | ||
256 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 5\n")); //[A:H | ||
257 | return 1; | ||
258 | } | ||
259 | } | ||
260 | else if(pCharLine[3]== ']') { //[A:] | ||
261 | pstFormat->eDataType = eHex; | ||
262 | pstFormat->bIsArray = true; | ||
263 | pCharLine += 4; | ||
264 | return 0; | ||
265 | } | ||
266 | else { //[A: | ||
267 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 6\n")); | ||
268 | return 1; | ||
269 | } | ||
270 | } | ||
271 | else if(pCharLine[2]==']') { //[H] | ||
272 | pstFormat->eDataType = eHex; | ||
273 | pstFormat->bIsArray = true; | ||
274 | pCharLine += 3; | ||
275 | return 0; | ||
276 | } | ||
277 | else { //[H | ||
278 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 7\n")); | ||
279 | return 1; | ||
280 | } | ||
281 | break; | ||
282 | |||
283 | default: | ||
284 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Illegal Data format 8\n")); | ||
285 | return 1; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | unsigned int uReadDataInSection(char *pCharLine, struct st_ps_data_format stPS_DataFormat) | ||
290 | { | ||
291 | char *pTokenPtr = pCharLine; | ||
292 | |||
293 | if(pTokenPtr[0] == '[') { | ||
294 | while(pTokenPtr[0] != ']' && pTokenPtr[0] != '\0') { | ||
295 | pTokenPtr++; | ||
296 | } | ||
297 | if(pTokenPtr[0] == '\0') { | ||
298 | return (0x0FFF); | ||
299 | } | ||
300 | pTokenPtr++; | ||
301 | |||
302 | |||
303 | } | ||
304 | if(stPS_DataFormat.eDataType == eHex) { | ||
305 | if(stPS_DataFormat.bIsArray == true) { | ||
306 | //Not implemented | ||
307 | return (0x0FFF); | ||
308 | } | ||
309 | else { | ||
310 | return (A_STRTOL(pTokenPtr, NULL, 16)); | ||
311 | } | ||
312 | } | ||
313 | else { | ||
314 | //Not implemented | ||
315 | return (0x0FFF); | ||
316 | } | ||
317 | } | ||
318 | int AthParseFilesUnified(u8 *srcbuffer,u32 srclen, int FileFormat) | ||
319 | { | ||
320 | char *Buffer; | ||
321 | char *pCharLine; | ||
322 | u8 TagCount; | ||
323 | u16 ByteCount; | ||
324 | u8 ParseSection=RAM_PS_SECTION; | ||
325 | u32 pos; | ||
326 | |||
327 | |||
328 | |||
329 | int uReadCount; | ||
330 | struct st_ps_data_format stPS_DataFormat; | ||
331 | struct st_read_status stReadStatus = {0, 0, 0,0}; | ||
332 | pos = 0; | ||
333 | Buffer = NULL; | ||
334 | |||
335 | if (srcbuffer == NULL || srclen == 0) | ||
336 | { | ||
337 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Could not open .\n")); | ||
338 | return A_ERROR; | ||
339 | } | ||
340 | TagCount = 0; | ||
341 | ByteCount = 0; | ||
342 | Buffer = A_MALLOC(LINE_SIZE_MAX + 1); | ||
343 | if(NULL == Buffer) { | ||
344 | return A_ERROR; | ||
345 | } | ||
346 | if (FileFormat == MB_FILEFORMAT_PATCH) | ||
347 | { | ||
348 | int LineRead = 0; | ||
349 | while((pCharLine = AthGetLine(Buffer, LINE_SIZE_MAX, srcbuffer,srclen,&pos)) != NULL) | ||
350 | { | ||
351 | |||
352 | SKIP_BLANKS(pCharLine); | ||
353 | |||
354 | // Comment line or empty line | ||
355 | if ((pCharLine[0] == '/') && (pCharLine[1] == '/')) | ||
356 | { | ||
357 | continue; | ||
358 | } | ||
359 | |||
360 | if ((pCharLine[0] == '#')) { | ||
361 | if (stReadStatus.uSection != 0) | ||
362 | { | ||
363 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("error\n")); | ||
364 | if(Buffer != NULL) { | ||
365 | kfree(Buffer); | ||
366 | } | ||
367 | return A_ERROR; | ||
368 | } | ||
369 | else { | ||
370 | stReadStatus.uSection = 1; | ||
371 | continue; | ||
372 | } | ||
373 | } | ||
374 | if ((pCharLine[0] == '/') && (pCharLine[1] == '*')) | ||
375 | { | ||
376 | pCharLine+=2; | ||
377 | SKIP_BLANKS(pCharLine); | ||
378 | |||
379 | if(!strncmp(pCharLine,"PA",2)||!strncmp(pCharLine,"Pa",2)||!strncmp(pCharLine,"pa",2)) | ||
380 | ParseSection=RAM_PATCH_SECTION; | ||
381 | |||
382 | if(!strncmp(pCharLine,"DY",2)||!strncmp(pCharLine,"Dy",2)||!strncmp(pCharLine,"dy",2)) | ||
383 | ParseSection=RAM_DYN_MEM_SECTION; | ||
384 | |||
385 | if(!strncmp(pCharLine,"PS",2)||!strncmp(pCharLine,"Ps",2)||!strncmp(pCharLine,"ps",2)) | ||
386 | ParseSection=RAM_PS_SECTION; | ||
387 | |||
388 | LineRead = 0; | ||
389 | stReadStatus.uSection = 0; | ||
390 | |||
391 | continue; | ||
392 | } | ||
393 | |||
394 | switch(ParseSection) | ||
395 | { | ||
396 | case RAM_PS_SECTION: | ||
397 | { | ||
398 | if (stReadStatus.uSection == 1) //TagID | ||
399 | { | ||
400 | SKIP_BLANKS(pCharLine); | ||
401 | if(uGetInputDataFormat(pCharLine, &stPS_DataFormat)) { | ||
402 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat fail\n")); | ||
403 | if(Buffer != NULL) { | ||
404 | kfree(Buffer); | ||
405 | } | ||
406 | return A_ERROR; | ||
407 | } | ||
408 | //pCharLine +=5; | ||
409 | PsTagEntry[TagCount].TagId = uReadDataInSection(pCharLine, stPS_DataFormat); | ||
410 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" TAG ID %d \n",PsTagEntry[TagCount].TagId)); | ||
411 | |||
412 | //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("tag # %x\n", PsTagEntry[TagCount].TagId); | ||
413 | if (TagCount == 0) | ||
414 | { | ||
415 | StartTagId = PsTagEntry[TagCount].TagId; | ||
416 | } | ||
417 | stReadStatus.uSection = 2; | ||
418 | } | ||
419 | else if (stReadStatus.uSection == 2) //TagLength | ||
420 | { | ||
421 | |||
422 | if(uGetInputDataFormat(pCharLine, &stPS_DataFormat)) { | ||
423 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat fail \n")); | ||
424 | if(Buffer != NULL) { | ||
425 | kfree(Buffer); | ||
426 | } | ||
427 | return A_ERROR; | ||
428 | } | ||
429 | //pCharLine +=5; | ||
430 | ByteCount = uReadDataInSection(pCharLine, stPS_DataFormat); | ||
431 | |||
432 | //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("tag length %x\n", ByteCount)); | ||
433 | if (ByteCount > LINE_SIZE_MAX/2) | ||
434 | { | ||
435 | if(Buffer != NULL) { | ||
436 | kfree(Buffer); | ||
437 | } | ||
438 | return A_ERROR; | ||
439 | } | ||
440 | PsTagEntry[TagCount].TagLen = ByteCount; | ||
441 | PsTagEntry[TagCount].TagData = (u8 *)A_MALLOC(ByteCount); | ||
442 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" TAG Length %d Tag Index %d \n",PsTagEntry[TagCount].TagLen,TagCount)); | ||
443 | stReadStatus.uSection = 3; | ||
444 | stReadStatus.uLineCount = 0; | ||
445 | } | ||
446 | else if( stReadStatus.uSection == 3) { //Data | ||
447 | |||
448 | if(stReadStatus.uLineCount == 0) { | ||
449 | if(uGetInputDataFormat(pCharLine,&stPS_DataFormat)) { | ||
450 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("uGetInputDataFormat Fail\n")); | ||
451 | if(Buffer != NULL) { | ||
452 | kfree(Buffer); | ||
453 | } | ||
454 | return A_ERROR; | ||
455 | } | ||
456 | //pCharLine +=5; | ||
457 | } | ||
458 | SKIP_BLANKS(pCharLine); | ||
459 | stReadStatus.uCharCount = 0; | ||
460 | if(pCharLine[stReadStatus.uCharCount] == '[') { | ||
461 | while(pCharLine[stReadStatus.uCharCount] != ']' && pCharLine[stReadStatus.uCharCount] != '\0' ) { | ||
462 | stReadStatus.uCharCount++; | ||
463 | } | ||
464 | if(pCharLine[stReadStatus.uCharCount] == ']' ) { | ||
465 | stReadStatus.uCharCount++; | ||
466 | } else { | ||
467 | stReadStatus.uCharCount = 0; | ||
468 | } | ||
469 | } | ||
470 | uReadCount = (ByteCount > BYTES_OF_PS_DATA_PER_LINE)? BYTES_OF_PS_DATA_PER_LINE: ByteCount; | ||
471 | //AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" ")); | ||
472 | if((stPS_DataFormat.eDataType == eHex) && stPS_DataFormat.bIsArray == true) { | ||
473 | while(uReadCount > 0) { | ||
474 | PsTagEntry[TagCount].TagData[stReadStatus.uByteCount] = | ||
475 | (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount]) << 4) | ||
476 | | (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 1])); | ||
477 | |||
478 | PsTagEntry[TagCount].TagData[stReadStatus.uByteCount+1] = | ||
479 | (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 3]) << 4) | ||
480 | | (u8)(hex_to_bin(pCharLine[stReadStatus.uCharCount + 4])); | ||
481 | |||
482 | stReadStatus.uCharCount += 6; // read two bytes, plus a space; | ||
483 | stReadStatus.uByteCount += 2; | ||
484 | uReadCount -= 2; | ||
485 | } | ||
486 | if(ByteCount > BYTES_OF_PS_DATA_PER_LINE) { | ||
487 | ByteCount -= BYTES_OF_PS_DATA_PER_LINE; | ||
488 | } | ||
489 | else { | ||
490 | ByteCount = 0; | ||
491 | } | ||
492 | } | ||
493 | else { | ||
494 | //to be implemented | ||
495 | } | ||
496 | |||
497 | stReadStatus.uLineCount++; | ||
498 | |||
499 | if(ByteCount == 0) { | ||
500 | stReadStatus.uSection = 0; | ||
501 | stReadStatus.uCharCount = 0; | ||
502 | stReadStatus.uLineCount = 0; | ||
503 | stReadStatus.uByteCount = 0; | ||
504 | } | ||
505 | else { | ||
506 | stReadStatus.uCharCount = 0; | ||
507 | } | ||
508 | |||
509 | if((stReadStatus.uSection == 0)&&(++TagCount == RAMPS_MAX_PS_TAGS_PER_FILE)) | ||
510 | { | ||
511 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("\n Buffer over flow PS File too big!!!")); | ||
512 | if(Buffer != NULL) { | ||
513 | kfree(Buffer); | ||
514 | } | ||
515 | return A_ERROR; | ||
516 | //Sleep (3000); | ||
517 | //exit(1); | ||
518 | } | ||
519 | |||
520 | } | ||
521 | } | ||
522 | |||
523 | break; | ||
524 | default: | ||
525 | { | ||
526 | if(Buffer != NULL) { | ||
527 | kfree(Buffer); | ||
528 | } | ||
529 | return A_ERROR; | ||
530 | } | ||
531 | break; | ||
532 | } | ||
533 | LineRead++; | ||
534 | } | ||
535 | Tag_Count = TagCount; | ||
536 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Number of Tags %d\n", Tag_Count)); | ||
537 | } | ||
538 | |||
539 | |||
540 | if (TagCount > RAMPS_MAX_PS_TAGS_PER_FILE) | ||
541 | { | ||
542 | |||
543 | if(Buffer != NULL) { | ||
544 | kfree(Buffer); | ||
545 | } | ||
546 | return A_ERROR; | ||
547 | } | ||
548 | |||
549 | if(Buffer != NULL) { | ||
550 | kfree(Buffer); | ||
551 | } | ||
552 | return 0; | ||
553 | |||
554 | } | ||
555 | |||
556 | |||
557 | |||
558 | /********************/ | ||
559 | |||
560 | |||
561 | int GetNextTwoChar(u8 *srcbuffer,u32 len, u32 *pos, char *buffer) | ||
562 | { | ||
563 | unsigned char ch; | ||
564 | |||
565 | ch = AthReadChar(srcbuffer,len,pos); | ||
566 | if(ch != '\0' && isxdigit(ch)) { | ||
567 | buffer[0] = ch; | ||
568 | } else | ||
569 | { | ||
570 | return A_ERROR; | ||
571 | } | ||
572 | ch = AthReadChar(srcbuffer,len,pos); | ||
573 | if(ch != '\0' && isxdigit(ch)) { | ||
574 | buffer[1] = ch; | ||
575 | } else | ||
576 | { | ||
577 | return A_ERROR; | ||
578 | } | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | int AthDoParsePatch(u8 *patchbuffer, u32 patchlen) | ||
583 | { | ||
584 | |||
585 | char Byte[3]; | ||
586 | char Line[MAX_BYTE_LENGTH + 1]; | ||
587 | int ByteCount,ByteCount_Org; | ||
588 | int count; | ||
589 | int i,j,k; | ||
590 | int data; | ||
591 | u32 filepos; | ||
592 | Byte[2] = '\0'; | ||
593 | j = 0; | ||
594 | filepos = 0; | ||
595 | Patch_Count = 0; | ||
596 | |||
597 | while(NULL != AthGetLine(Line,MAX_BYTE_LENGTH,patchbuffer,patchlen,&filepos)) { | ||
598 | if(strlen(Line) <= 1 || !isxdigit(Line[0])) { | ||
599 | continue; | ||
600 | } else { | ||
601 | break; | ||
602 | } | ||
603 | } | ||
604 | ByteCount = A_STRTOL(Line, NULL, 16); | ||
605 | ByteCount_Org = ByteCount; | ||
606 | |||
607 | while(ByteCount > MAX_BYTE_LENGTH){ | ||
608 | |||
609 | /* Handle case when the number of patch buffer is more than the 20K */ | ||
610 | if(MAX_NUM_PATCH_ENTRY == Patch_Count) { | ||
611 | for(i = 0; i < Patch_Count; i++) { | ||
612 | kfree(RamPatch[i].Data); | ||
613 | } | ||
614 | return A_ERROR; | ||
615 | } | ||
616 | RamPatch[Patch_Count].Len= MAX_BYTE_LENGTH; | ||
617 | RamPatch[Patch_Count].Data = (u8 *)A_MALLOC(MAX_BYTE_LENGTH); | ||
618 | Patch_Count ++; | ||
619 | |||
620 | |||
621 | ByteCount= ByteCount - MAX_BYTE_LENGTH; | ||
622 | } | ||
623 | |||
624 | RamPatch[Patch_Count].Len= (ByteCount & 0xFF); | ||
625 | if(ByteCount != 0) { | ||
626 | RamPatch[Patch_Count].Data = (u8 *)A_MALLOC(ByteCount); | ||
627 | Patch_Count ++; | ||
628 | } | ||
629 | count = 0; | ||
630 | while(ByteCount_Org > MAX_BYTE_LENGTH){ | ||
631 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Index [%d]\n",j)); | ||
632 | for (i = 0,k=0; i < MAX_BYTE_LENGTH*2; i += 2,k++,count +=2) { | ||
633 | if(GetNextTwoChar(patchbuffer,patchlen,&filepos,Byte) == A_ERROR) { | ||
634 | return A_ERROR; | ||
635 | } | ||
636 | data = A_STRTOUL(&Byte[0], NULL, 16); | ||
637 | RamPatch[j].Data[k] = (data & 0xFF); | ||
638 | |||
639 | |||
640 | } | ||
641 | j++; | ||
642 | ByteCount_Org = ByteCount_Org - MAX_BYTE_LENGTH; | ||
643 | } | ||
644 | if(j == 0){ | ||
645 | j++; | ||
646 | } | ||
647 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" Index [%d]\n",j)); | ||
648 | for (k=0; k < ByteCount_Org; i += 2,k++,count+=2) { | ||
649 | if(GetNextTwoChar(patchbuffer,patchlen,&filepos,Byte) == A_ERROR) { | ||
650 | return A_ERROR; | ||
651 | } | ||
652 | data = A_STRTOUL(Byte, NULL, 16); | ||
653 | RamPatch[j].Data[k] = (data & 0xFF); | ||
654 | |||
655 | |||
656 | } | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | |||
661 | /********************/ | ||
662 | int AthDoParsePS(u8 *srcbuffer, u32 srclen) | ||
663 | { | ||
664 | int status; | ||
665 | int i; | ||
666 | bool BDADDR_Present = false; | ||
667 | |||
668 | Tag_Count = 0; | ||
669 | |||
670 | Total_tag_lenght = 0; | ||
671 | BDADDR = false; | ||
672 | |||
673 | |||
674 | status = A_ERROR; | ||
675 | |||
676 | if(NULL != srcbuffer && srclen != 0) | ||
677 | { | ||
678 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("File Open Operation Successful\n")); | ||
679 | |||
680 | status = AthParseFilesUnified(srcbuffer,srclen,MB_FILEFORMAT_PATCH); | ||
681 | } | ||
682 | |||
683 | |||
684 | |||
685 | if(Tag_Count == 0){ | ||
686 | Total_tag_lenght = 10; | ||
687 | |||
688 | } | ||
689 | else{ | ||
690 | for(i=0; i<Tag_Count; i++){ | ||
691 | if(PsTagEntry[i].TagId == 1){ | ||
692 | BDADDR_Present = true; | ||
693 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR is present in Patch File \r\n")); | ||
694 | |||
695 | } | ||
696 | if(PsTagEntry[i].TagLen % 2 == 1){ | ||
697 | Total_tag_lenght = Total_tag_lenght + PsTagEntry[i].TagLen + 1; | ||
698 | } | ||
699 | else{ | ||
700 | Total_tag_lenght = Total_tag_lenght + PsTagEntry[i].TagLen; | ||
701 | } | ||
702 | |||
703 | } | ||
704 | } | ||
705 | |||
706 | if(Tag_Count > 0 && !BDADDR_Present){ | ||
707 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR is not present adding 10 extra bytes \r\n")); | ||
708 | Total_tag_lenght=Total_tag_lenght + 10; | ||
709 | } | ||
710 | Total_tag_lenght = Total_tag_lenght+ 10 + (Tag_Count*4); | ||
711 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Total Length %d\n",Total_tag_lenght)); | ||
712 | |||
713 | |||
714 | return status; | ||
715 | } | ||
716 | char *AthGetLine(char *buffer, int maxlen, u8 *srcbuffer,u32 len,u32 *pos) | ||
717 | { | ||
718 | |||
719 | int count; | ||
720 | static short flag; | ||
721 | char CharRead; | ||
722 | count = 0; | ||
723 | flag = A_ERROR; | ||
724 | |||
725 | do | ||
726 | { | ||
727 | CharRead = AthReadChar(srcbuffer,len,pos); | ||
728 | if( CharRead == '\0' ) { | ||
729 | buffer[count+1] = '\0'; | ||
730 | if(count == 0) { | ||
731 | return NULL; | ||
732 | } | ||
733 | else { | ||
734 | return buffer; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | if(CharRead == 13) { | ||
739 | } else if(CharRead == 10) { | ||
740 | buffer[count] ='\0'; | ||
741 | flag = A_ERROR; | ||
742 | return buffer; | ||
743 | }else { | ||
744 | buffer[count++] = CharRead; | ||
745 | } | ||
746 | |||
747 | } | ||
748 | while(count < maxlen-1 && CharRead != '\0'); | ||
749 | buffer[count] = '\0'; | ||
750 | |||
751 | return buffer; | ||
752 | } | ||
753 | |||
754 | static void LoadHeader(u8 *HCI_PS_Command,u8 opcode,int length,int index){ | ||
755 | |||
756 | HCI_PS_Command[0]= 0x0B; | ||
757 | HCI_PS_Command[1]= 0xFC; | ||
758 | HCI_PS_Command[2]= length + 4; | ||
759 | HCI_PS_Command[3]= opcode; | ||
760 | HCI_PS_Command[4]= (index & 0xFF); | ||
761 | HCI_PS_Command[5]= ((index>>8) & 0xFF); | ||
762 | HCI_PS_Command[6]= length; | ||
763 | } | ||
764 | |||
765 | ///////////////////////// | ||
766 | // | ||
767 | int AthCreateCommandList(struct ps_cmd_packet **HciPacketList, u32 *numPackets) | ||
768 | { | ||
769 | |||
770 | u8 count; | ||
771 | u32 NumcmdEntry = 0; | ||
772 | |||
773 | u32 Crc = 0; | ||
774 | *numPackets = 0; | ||
775 | |||
776 | |||
777 | if(Patch_Count > 0) | ||
778 | Crc |= RAM_PATCH_REGION; | ||
779 | if(Tag_Count > 0) | ||
780 | Crc |= RAM_PS_REGION; | ||
781 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("PS Thread Started CRC %x Patch Count %d Tag Count %d \n",Crc,Patch_Count,Tag_Count)); | ||
782 | |||
783 | if(Patch_Count || Tag_Count ){ | ||
784 | NumcmdEntry+=(2 + Patch_Count + Tag_Count); /* CRC Packet + PS Reset Packet + Patch List + PS List*/ | ||
785 | if(Patch_Count > 0) { | ||
786 | NumcmdEntry++; /* Patch Enable Command */ | ||
787 | } | ||
788 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Num Cmd Entries %d Size %d \r\n",NumcmdEntry,(u32)sizeof(struct ps_cmd_packet) * NumcmdEntry)); | ||
789 | (*HciPacketList) = A_MALLOC(sizeof(struct ps_cmd_packet) * NumcmdEntry); | ||
790 | if(NULL == *HciPacketList) { | ||
791 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("memory allocation failed \r\n")); | ||
792 | } | ||
793 | AthPSCreateHCICommand(PS_VERIFY_CRC,Crc,*HciPacketList,numPackets); | ||
794 | if(Patch_Count > 0){ | ||
795 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** Write Patch**** \r\n")); | ||
796 | AthPSCreateHCICommand(WRITE_PATCH,Patch_Count,*HciPacketList,numPackets); | ||
797 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** Enable Patch**** \r\n")); | ||
798 | AthPSCreateHCICommand(ENABLE_PATCH,0,*HciPacketList,numPackets); | ||
799 | } | ||
800 | |||
801 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** PS Reset**** %d[0x%x] \r\n",PS_RAM_SIZE,PS_RAM_SIZE)); | ||
802 | AthPSCreateHCICommand(PS_RESET,PS_RAM_SIZE,*HciPacketList,numPackets); | ||
803 | if(Tag_Count > 0){ | ||
804 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("*** PS Write**** \r\n")); | ||
805 | AthPSCreateHCICommand(PS_WRITE,Tag_Count,*HciPacketList,numPackets); | ||
806 | } | ||
807 | } | ||
808 | if(!BDADDR){ | ||
809 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BD ADDR not present \r\n")); | ||
810 | |||
811 | } | ||
812 | for(count = 0; count < Patch_Count; count++) { | ||
813 | |||
814 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing Patch Buffer %d \r\n",count)); | ||
815 | kfree(RamPatch[count].Data); | ||
816 | } | ||
817 | |||
818 | for(count = 0; count < Tag_Count; count++) { | ||
819 | |||
820 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Freeing PS Buffer %d \r\n",count)); | ||
821 | kfree(PsTagEntry[count].TagData); | ||
822 | } | ||
823 | |||
824 | /* | ||
825 | * SDIO Transport uses synchronous mode of data transfer | ||
826 | * So, AthPSOperations() call returns only after receiving the | ||
827 | * command complete event. | ||
828 | */ | ||
829 | return *numPackets; | ||
830 | } | ||
831 | |||
832 | |||
833 | //////////////////////// | ||
834 | |||
835 | ///////////// | ||
836 | static int AthPSCreateHCICommand(u8 Opcode, u32 Param1,struct ps_cmd_packet *PSPatchPacket,u32 *index) | ||
837 | { | ||
838 | u8 *HCI_PS_Command; | ||
839 | u32 Length; | ||
840 | int i,j; | ||
841 | |||
842 | switch(Opcode) | ||
843 | { | ||
844 | case WRITE_PATCH: | ||
845 | |||
846 | |||
847 | for(i=0;i< Param1;i++){ | ||
848 | |||
849 | HCI_PS_Command = (u8 *) A_MALLOC(RamPatch[i].Len+HCI_COMMAND_HEADER); | ||
850 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Allocated Buffer Size %d\n",RamPatch[i].Len+HCI_COMMAND_HEADER)); | ||
851 | if(HCI_PS_Command == NULL){ | ||
852 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n")); | ||
853 | return A_ERROR; | ||
854 | } | ||
855 | memset (HCI_PS_Command, 0, RamPatch[i].Len+HCI_COMMAND_HEADER); | ||
856 | LoadHeader(HCI_PS_Command,Opcode,RamPatch[i].Len,i); | ||
857 | for(j=0;j<RamPatch[i].Len;j++){ | ||
858 | HCI_PS_Command[HCI_COMMAND_HEADER+j]=RamPatch[i].Data[j]; | ||
859 | } | ||
860 | PSPatchPacket[*index].Hcipacket = HCI_PS_Command; | ||
861 | PSPatchPacket[*index].packetLen = RamPatch[i].Len+HCI_COMMAND_HEADER; | ||
862 | (*index)++; | ||
863 | |||
864 | |||
865 | } | ||
866 | |||
867 | break; | ||
868 | |||
869 | case ENABLE_PATCH: | ||
870 | |||
871 | |||
872 | Length = 0; | ||
873 | i= 0; | ||
874 | HCI_PS_Command = (u8 *) A_MALLOC(Length+HCI_COMMAND_HEADER); | ||
875 | if(HCI_PS_Command == NULL){ | ||
876 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n")); | ||
877 | return A_ERROR; | ||
878 | } | ||
879 | |||
880 | memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER); | ||
881 | LoadHeader(HCI_PS_Command,Opcode,Length,i); | ||
882 | PSPatchPacket[*index].Hcipacket = HCI_PS_Command; | ||
883 | PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER; | ||
884 | (*index)++; | ||
885 | |||
886 | break; | ||
887 | |||
888 | case PS_RESET: | ||
889 | Length = 0x06; | ||
890 | i=0; | ||
891 | HCI_PS_Command = (u8 *) A_MALLOC(Length+HCI_COMMAND_HEADER); | ||
892 | if(HCI_PS_Command == NULL){ | ||
893 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n")); | ||
894 | return A_ERROR; | ||
895 | } | ||
896 | memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER); | ||
897 | LoadHeader(HCI_PS_Command,Opcode,Length,i); | ||
898 | HCI_PS_Command[7]= 0x00; | ||
899 | HCI_PS_Command[Length+HCI_COMMAND_HEADER -2]= (Param1 & 0xFF); | ||
900 | HCI_PS_Command[Length+HCI_COMMAND_HEADER -1]= ((Param1 >> 8) & 0xFF); | ||
901 | PSPatchPacket[*index].Hcipacket = HCI_PS_Command; | ||
902 | PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER; | ||
903 | (*index)++; | ||
904 | |||
905 | break; | ||
906 | |||
907 | case PS_WRITE: | ||
908 | for(i=0;i< Param1;i++){ | ||
909 | if(PsTagEntry[i].TagId ==1) | ||
910 | BDADDR = true; | ||
911 | |||
912 | HCI_PS_Command = (u8 *) A_MALLOC(PsTagEntry[i].TagLen+HCI_COMMAND_HEADER); | ||
913 | if(HCI_PS_Command == NULL){ | ||
914 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n")); | ||
915 | return A_ERROR; | ||
916 | } | ||
917 | |||
918 | memset (HCI_PS_Command, 0, PsTagEntry[i].TagLen+HCI_COMMAND_HEADER); | ||
919 | LoadHeader(HCI_PS_Command,Opcode,PsTagEntry[i].TagLen,PsTagEntry[i].TagId); | ||
920 | |||
921 | for(j=0;j<PsTagEntry[i].TagLen;j++){ | ||
922 | HCI_PS_Command[HCI_COMMAND_HEADER+j]=PsTagEntry[i].TagData[j]; | ||
923 | } | ||
924 | |||
925 | PSPatchPacket[*index].Hcipacket = HCI_PS_Command; | ||
926 | PSPatchPacket[*index].packetLen = PsTagEntry[i].TagLen+HCI_COMMAND_HEADER; | ||
927 | (*index)++; | ||
928 | |||
929 | } | ||
930 | |||
931 | break; | ||
932 | |||
933 | |||
934 | case PS_VERIFY_CRC: | ||
935 | Length = 0x0; | ||
936 | |||
937 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("VALUE of CRC:%d At index %d\r\n",Param1,*index)); | ||
938 | |||
939 | HCI_PS_Command = (u8 *) A_MALLOC(Length+HCI_COMMAND_HEADER); | ||
940 | if(HCI_PS_Command == NULL){ | ||
941 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("MALLOC Failed\r\n")); | ||
942 | return A_ERROR; | ||
943 | } | ||
944 | memset (HCI_PS_Command, 0, Length+HCI_COMMAND_HEADER); | ||
945 | LoadHeader(HCI_PS_Command,Opcode,Length,Param1); | ||
946 | |||
947 | PSPatchPacket[*index].Hcipacket = HCI_PS_Command; | ||
948 | PSPatchPacket[*index].packetLen = Length+HCI_COMMAND_HEADER; | ||
949 | (*index)++; | ||
950 | |||
951 | break; | ||
952 | |||
953 | case CHANGE_BDADDR: | ||
954 | break; | ||
955 | } | ||
956 | return 0; | ||
957 | } | ||
958 | int AthFreeCommandList(struct ps_cmd_packet **HciPacketList, u32 numPackets) | ||
959 | { | ||
960 | int i; | ||
961 | if(*HciPacketList == NULL) { | ||
962 | return A_ERROR; | ||
963 | } | ||
964 | for(i = 0; i < numPackets;i++) { | ||
965 | kfree((*HciPacketList)[i].Hcipacket); | ||
966 | } | ||
967 | kfree(*HciPacketList); | ||
968 | return 0; | ||
969 | } | ||
diff --git a/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h new file mode 100644 index 00000000000..4e0f2f713a4 --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h | |||
@@ -0,0 +1,113 @@ | |||
1 | //------------------------------------------------------------------------------ | ||
2 | // | ||
3 | // Copyright (c) 2004-2010 Atheros Corporation. All rights reserved. | ||
4 | // | ||
5 | // | ||
6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
7 | // purpose with or without fee is hereby granted, provided that the above | ||
8 | // copyright notice and this permission notice appear in all copies. | ||
9 | // | ||
10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | // | ||
18 | // | ||
19 | //------------------------------------------------------------------------------ | ||
20 | // | ||
21 | // This file is the include file for Atheros PS and patch parser. | ||
22 | // It implements APIs to parse data buffer with patch and PS information and convert it to HCI commands. | ||
23 | // | ||
24 | |||
25 | #ifndef __AR3KPSPARSER_H | ||
26 | #define __AR3KPSPARSER_H | ||
27 | |||
28 | |||
29 | |||
30 | |||
31 | #include <linux/fs.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include "athdefs.h" | ||
34 | #ifdef HCI_TRANSPORT_SDIO | ||
35 | #include "a_config.h" | ||
36 | #include "a_osapi.h" | ||
37 | #define ATH_MODULE_NAME misc | ||
38 | #include "a_debug.h" | ||
39 | #include "common_drv.h" | ||
40 | #include "hci_transport_api.h" | ||
41 | #include "ar3kconfig.h" | ||
42 | #else | ||
43 | #ifndef A_PRINTF | ||
44 | #define A_PRINTF(args...) printk(KERN_ALERT args) | ||
45 | #endif /* A_PRINTF */ | ||
46 | #include "debug_linux.h" | ||
47 | |||
48 | /* Helper data type declaration */ | ||
49 | |||
50 | #define ATH_DEBUG_ERR (1 << 0) | ||
51 | #define ATH_DEBUG_WARN (1 << 1) | ||
52 | #define ATH_DEBUG_INFO (1 << 2) | ||
53 | |||
54 | |||
55 | |||
56 | #define false 0 | ||
57 | #define true 1 | ||
58 | |||
59 | #ifndef A_MALLOC | ||
60 | #define A_MALLOC(size) kmalloc((size),GFP_KERNEL) | ||
61 | #endif /* A_MALLOC */ | ||
62 | #endif /* HCI_TRANSPORT_UART */ | ||
63 | |||
64 | /* String manipulation APIs */ | ||
65 | #ifndef A_STRTOUL | ||
66 | #define A_STRTOUL simple_strtoul | ||
67 | #endif /* A_STRTOL */ | ||
68 | |||
69 | #ifndef A_STRTOL | ||
70 | #define A_STRTOL simple_strtol | ||
71 | #endif /* A_STRTOL */ | ||
72 | |||
73 | |||
74 | /* The maximum number of bytes possible in a patch entry */ | ||
75 | #define MAX_PATCH_SIZE 20000 | ||
76 | |||
77 | /* Maximum HCI packets that will be formed from the Patch file */ | ||
78 | #define MAX_NUM_PATCH_ENTRY (MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1 | ||
79 | |||
80 | |||
81 | |||
82 | |||
83 | |||
84 | |||
85 | |||
86 | struct ps_cmd_packet | ||
87 | { | ||
88 | u8 *Hcipacket; | ||
89 | int packetLen; | ||
90 | }; | ||
91 | |||
92 | /* Parses a Patch information buffer and store it in global structure */ | ||
93 | int AthDoParsePatch(u8 *, u32 ); | ||
94 | |||
95 | /* parses a PS information buffer and stores it in a global structure */ | ||
96 | int AthDoParsePS(u8 *, u32 ); | ||
97 | |||
98 | /* | ||
99 | * Uses the output of Both AthDoParsePS and AthDoParsePatch APIs to form HCI command array with | ||
100 | * all the PS and patch commands. | ||
101 | * The list will have the below mentioned commands in order. | ||
102 | * CRC command packet | ||
103 | * Download patch command(s) | ||
104 | * Enable patch Command | ||
105 | * PS Reset Command | ||
106 | * PS Tag Command(s) | ||
107 | * | ||
108 | */ | ||
109 | int AthCreateCommandList(struct ps_cmd_packet **, u32 *); | ||
110 | |||
111 | /* Cleanup the dynamically allicated HCI command list */ | ||
112 | int AthFreeCommandList(struct ps_cmd_packet **HciPacketList, u32 numPackets); | ||
113 | #endif /* __AR3KPSPARSER_H */ | ||
diff --git a/drivers/staging/ath6kl/miscdrv/common_drv.c b/drivers/staging/ath6kl/miscdrv/common_drv.c new file mode 100644 index 00000000000..1ce539aa019 --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/common_drv.c | |||
@@ -0,0 +1,910 @@ | |||
1 | //------------------------------------------------------------------------------ | ||
2 | // <copyright file="common_drv.c" company="Atheros"> | ||
3 | // Copyright (c) 2004-2010 Atheros Corporation. All rights reserved. | ||
4 | // | ||
5 | // | ||
6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
7 | // purpose with or without fee is hereby granted, provided that the above | ||
8 | // copyright notice and this permission notice appear in all copies. | ||
9 | // | ||
10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | // | ||
18 | // | ||
19 | //------------------------------------------------------------------------------ | ||
20 | //============================================================================== | ||
21 | // Author(s): ="Atheros" | ||
22 | //============================================================================== | ||
23 | |||
24 | #include "a_config.h" | ||
25 | #include "athdefs.h" | ||
26 | |||
27 | #include "hw/mbox_host_reg.h" | ||
28 | #include "gpio_reg.h" | ||
29 | #include "hw/rtc_reg.h" | ||
30 | #include "hw/mbox_reg.h" | ||
31 | #include "hw/apb_map.h" | ||
32 | |||
33 | #include "a_osapi.h" | ||
34 | #include "targaddrs.h" | ||
35 | #include "hif.h" | ||
36 | #include "htc_api.h" | ||
37 | #include "wmi.h" | ||
38 | #include "bmi.h" | ||
39 | #include "bmi_msg.h" | ||
40 | #include "common_drv.h" | ||
41 | #define ATH_MODULE_NAME misc | ||
42 | #include "a_debug.h" | ||
43 | #include "ar6000_diag.h" | ||
44 | |||
45 | static ATH_DEBUG_MODULE_DBG_INFO *g_pModuleInfoHead = NULL; | ||
46 | static A_MUTEX_T g_ModuleListLock; | ||
47 | static bool g_ModuleDebugInit = false; | ||
48 | |||
49 | #ifdef ATH_DEBUG_MODULE | ||
50 | |||
51 | ATH_DEBUG_INSTANTIATE_MODULE_VAR(misc, | ||
52 | "misc", | ||
53 | "Common and misc APIs", | ||
54 | ATH_DEBUG_MASK_DEFAULTS, | ||
55 | 0, | ||
56 | NULL); | ||
57 | |||
58 | #endif | ||
59 | |||
60 | #define HOST_INTEREST_ITEM_ADDRESS(target, item) \ | ||
61 | ((((target) == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \ | ||
62 | (((target) == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : 0))) | ||
63 | |||
64 | |||
65 | #define AR6001_LOCAL_COUNT_ADDRESS 0x0c014080 | ||
66 | #define AR6002_LOCAL_COUNT_ADDRESS 0x00018080 | ||
67 | #define AR6003_LOCAL_COUNT_ADDRESS 0x00018080 | ||
68 | #define CPU_DBG_SEL_ADDRESS 0x00000483 | ||
69 | #define CPU_DBG_ADDRESS 0x00000484 | ||
70 | |||
71 | static u8 custDataAR6002[AR6002_CUST_DATA_SIZE]; | ||
72 | static u8 custDataAR6003[AR6003_CUST_DATA_SIZE]; | ||
73 | |||
74 | /* Compile the 4BYTE version of the window register setup routine, | ||
75 | * This mitigates host interconnect issues with non-4byte aligned bus requests, some | ||
76 | * interconnects use bus adapters that impose strict limitations. | ||
77 | * Since diag window access is not intended for performance critical operations, the 4byte mode should | ||
78 | * be satisfactory even though it generates 4X the bus activity. */ | ||
79 | |||
80 | #ifdef USE_4BYTE_REGISTER_ACCESS | ||
81 | |||
82 | /* set the window address register (using 4-byte register access ). */ | ||
83 | int ar6000_SetAddressWindowRegister(struct hif_device *hifDevice, u32 RegisterAddr, u32 Address) | ||
84 | { | ||
85 | int status; | ||
86 | u8 addrValue[4]; | ||
87 | s32 i; | ||
88 | |||
89 | /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written | ||
90 | * last to initiate the access cycle */ | ||
91 | |||
92 | for (i = 1; i <= 3; i++) { | ||
93 | /* fill the buffer with the address byte value we want to hit 4 times*/ | ||
94 | addrValue[0] = ((u8 *)&Address)[i]; | ||
95 | addrValue[1] = addrValue[0]; | ||
96 | addrValue[2] = addrValue[0]; | ||
97 | addrValue[3] = addrValue[0]; | ||
98 | |||
99 | /* hit each byte of the register address with a 4-byte write operation to the same address, | ||
100 | * this is a harmless operation */ | ||
101 | status = HIFReadWrite(hifDevice, | ||
102 | RegisterAddr+i, | ||
103 | addrValue, | ||
104 | 4, | ||
105 | HIF_WR_SYNC_BYTE_FIX, | ||
106 | NULL); | ||
107 | if (status) { | ||
108 | break; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | if (status) { | ||
113 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n", | ||
114 | Address, RegisterAddr)); | ||
115 | return status; | ||
116 | } | ||
117 | |||
118 | /* write the address register again, this time write the whole 4-byte value. | ||
119 | * The effect here is that the LSB write causes the cycle to start, the extra | ||
120 | * 3 byte write to bytes 1,2,3 has no effect since we are writing the same values again */ | ||
121 | status = HIFReadWrite(hifDevice, | ||
122 | RegisterAddr, | ||
123 | (u8 *)(&Address), | ||
124 | 4, | ||
125 | HIF_WR_SYNC_BYTE_INC, | ||
126 | NULL); | ||
127 | |||
128 | if (status) { | ||
129 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n", | ||
130 | Address, RegisterAddr)); | ||
131 | return status; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | |||
136 | |||
137 | |||
138 | } | ||
139 | |||
140 | |||
141 | #else | ||
142 | |||
143 | /* set the window address register */ | ||
144 | int ar6000_SetAddressWindowRegister(struct hif_device *hifDevice, u32 RegisterAddr, u32 Address) | ||
145 | { | ||
146 | int status; | ||
147 | |||
148 | /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written | ||
149 | * last to initiate the access cycle */ | ||
150 | status = HIFReadWrite(hifDevice, | ||
151 | RegisterAddr+1, /* write upper 3 bytes */ | ||
152 | ((u8 *)(&Address))+1, | ||
153 | sizeof(u32)-1, | ||
154 | HIF_WR_SYNC_BYTE_INC, | ||
155 | NULL); | ||
156 | |||
157 | if (status) { | ||
158 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n", | ||
159 | RegisterAddr, Address)); | ||
160 | return status; | ||
161 | } | ||
162 | |||
163 | /* write the LSB of the register, this initiates the operation */ | ||
164 | status = HIFReadWrite(hifDevice, | ||
165 | RegisterAddr, | ||
166 | (u8 *)(&Address), | ||
167 | sizeof(u8), | ||
168 | HIF_WR_SYNC_BYTE_INC, | ||
169 | NULL); | ||
170 | |||
171 | if (status) { | ||
172 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n", | ||
173 | RegisterAddr, Address)); | ||
174 | return status; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | #endif | ||
181 | |||
182 | /* | ||
183 | * Read from the AR6000 through its diagnostic window. | ||
184 | * No cooperation from the Target is required for this. | ||
185 | */ | ||
186 | int | ||
187 | ar6000_ReadRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data) | ||
188 | { | ||
189 | int status; | ||
190 | |||
191 | /* set window register to start read cycle */ | ||
192 | status = ar6000_SetAddressWindowRegister(hifDevice, | ||
193 | WINDOW_READ_ADDR_ADDRESS, | ||
194 | *address); | ||
195 | |||
196 | if (status) { | ||
197 | return status; | ||
198 | } | ||
199 | |||
200 | /* read the data */ | ||
201 | status = HIFReadWrite(hifDevice, | ||
202 | WINDOW_DATA_ADDRESS, | ||
203 | (u8 *)data, | ||
204 | sizeof(u32), | ||
205 | HIF_RD_SYNC_BYTE_INC, | ||
206 | NULL); | ||
207 | if (status) { | ||
208 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from WINDOW_DATA_ADDRESS\n")); | ||
209 | return status; | ||
210 | } | ||
211 | |||
212 | return status; | ||
213 | } | ||
214 | |||
215 | |||
216 | /* | ||
217 | * Write to the AR6000 through its diagnostic window. | ||
218 | * No cooperation from the Target is required for this. | ||
219 | */ | ||
220 | int | ||
221 | ar6000_WriteRegDiag(struct hif_device *hifDevice, u32 *address, u32 *data) | ||
222 | { | ||
223 | int status; | ||
224 | |||
225 | /* set write data */ | ||
226 | status = HIFReadWrite(hifDevice, | ||
227 | WINDOW_DATA_ADDRESS, | ||
228 | (u8 *)data, | ||
229 | sizeof(u32), | ||
230 | HIF_WR_SYNC_BYTE_INC, | ||
231 | NULL); | ||
232 | if (status) { | ||
233 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data)); | ||
234 | return status; | ||
235 | } | ||
236 | |||
237 | /* set window register, which starts the write cycle */ | ||
238 | return ar6000_SetAddressWindowRegister(hifDevice, | ||
239 | WINDOW_WRITE_ADDR_ADDRESS, | ||
240 | *address); | ||
241 | } | ||
242 | |||
243 | int | ||
244 | ar6000_ReadDataDiag(struct hif_device *hifDevice, u32 address, | ||
245 | u8 *data, u32 length) | ||
246 | { | ||
247 | u32 count; | ||
248 | int status = 0; | ||
249 | |||
250 | for (count = 0; count < length; count += 4, address += 4) { | ||
251 | if ((status = ar6000_ReadRegDiag(hifDevice, &address, | ||
252 | (u32 *)&data[count])) != 0) | ||
253 | { | ||
254 | break; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | return status; | ||
259 | } | ||
260 | |||
261 | int | ||
262 | ar6000_WriteDataDiag(struct hif_device *hifDevice, u32 address, | ||
263 | u8 *data, u32 length) | ||
264 | { | ||
265 | u32 count; | ||
266 | int status = 0; | ||
267 | |||
268 | for (count = 0; count < length; count += 4, address += 4) { | ||
269 | if ((status = ar6000_WriteRegDiag(hifDevice, &address, | ||
270 | (u32 *)&data[count])) != 0) | ||
271 | { | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | return status; | ||
277 | } | ||
278 | |||
279 | int | ||
280 | ar6k_ReadTargetRegister(struct hif_device *hifDevice, int regsel, u32 *regval) | ||
281 | { | ||
282 | int status; | ||
283 | u8 vals[4]; | ||
284 | u8 register_selection[4]; | ||
285 | |||
286 | register_selection[0] = register_selection[1] = register_selection[2] = register_selection[3] = (regsel & 0xff); | ||
287 | status = HIFReadWrite(hifDevice, | ||
288 | CPU_DBG_SEL_ADDRESS, | ||
289 | register_selection, | ||
290 | 4, | ||
291 | HIF_WR_SYNC_BYTE_FIX, | ||
292 | NULL); | ||
293 | |||
294 | if (status) { | ||
295 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write CPU_DBG_SEL (%d)\n", regsel)); | ||
296 | return status; | ||
297 | } | ||
298 | |||
299 | status = HIFReadWrite(hifDevice, | ||
300 | CPU_DBG_ADDRESS, | ||
301 | (u8 *)vals, | ||
302 | sizeof(vals), | ||
303 | HIF_RD_SYNC_BYTE_INC, | ||
304 | NULL); | ||
305 | if (status) { | ||
306 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from CPU_DBG_ADDRESS\n")); | ||
307 | return status; | ||
308 | } | ||
309 | |||
310 | *regval = vals[0]<<0 | vals[1]<<8 | vals[2]<<16 | vals[3]<<24; | ||
311 | |||
312 | return status; | ||
313 | } | ||
314 | |||
315 | void | ||
316 | ar6k_FetchTargetRegs(struct hif_device *hifDevice, u32 *targregs) | ||
317 | { | ||
318 | int i; | ||
319 | u32 val; | ||
320 | |||
321 | for (i=0; i<AR6003_FETCH_TARG_REGS_COUNT; i++) { | ||
322 | val=0xffffffff; | ||
323 | (void)ar6k_ReadTargetRegister(hifDevice, i, &val); | ||
324 | targregs[i] = val; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | #if 0 | ||
329 | static int | ||
330 | _do_write_diag(struct hif_device *hifDevice, u32 addr, u32 value) | ||
331 | { | ||
332 | int status; | ||
333 | |||
334 | status = ar6000_WriteRegDiag(hifDevice, &addr, &value); | ||
335 | if (status) | ||
336 | { | ||
337 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot force Target to execute ROM!\n")); | ||
338 | } | ||
339 | |||
340 | return status; | ||
341 | } | ||
342 | #endif | ||
343 | |||
344 | |||
345 | /* | ||
346 | * Delay up to wait_msecs millisecs to allow Target to enter BMI phase, | ||
347 | * which is a good sign that it's alive and well. This is used after | ||
348 | * explicitly forcing the Target to reset. | ||
349 | * | ||
350 | * The wait_msecs time should be sufficiently long to cover any reasonable | ||
351 | * boot-time delay. For instance, AR6001 firmware allow one second for a | ||
352 | * low frequency crystal to settle before it calibrates the refclk frequency. | ||
353 | * | ||
354 | * TBD: Might want to add special handling for AR6K_OPTION_BMI_DISABLE. | ||
355 | */ | ||
356 | #if 0 | ||
357 | static int | ||
358 | _delay_until_target_alive(struct hif_device *hifDevice, s32 wait_msecs, u32 TargetType) | ||
359 | { | ||
360 | s32 actual_wait; | ||
361 | s32 i; | ||
362 | u32 address; | ||
363 | |||
364 | actual_wait = 0; | ||
365 | |||
366 | /* Hardcode the address of LOCAL_COUNT_ADDRESS based on the target type */ | ||
367 | if (TargetType == TARGET_TYPE_AR6002) { | ||
368 | address = AR6002_LOCAL_COUNT_ADDRESS; | ||
369 | } else if (TargetType == TARGET_TYPE_AR6003) { | ||
370 | address = AR6003_LOCAL_COUNT_ADDRESS; | ||
371 | } else { | ||
372 | A_ASSERT(0); | ||
373 | } | ||
374 | address += 0x10; | ||
375 | for (i=0; actual_wait < wait_msecs; i++) { | ||
376 | u32 data; | ||
377 | |||
378 | A_MDELAY(100); | ||
379 | actual_wait += 100; | ||
380 | |||
381 | data = 0; | ||
382 | if (ar6000_ReadRegDiag(hifDevice, &address, &data) != 0) { | ||
383 | return A_ERROR; | ||
384 | } | ||
385 | |||
386 | if (data != 0) { | ||
387 | /* No need to wait longer -- we have a BMI credit */ | ||
388 | return 0; | ||
389 | } | ||
390 | } | ||
391 | return A_ERROR; /* timed out */ | ||
392 | } | ||
393 | #endif | ||
394 | |||
395 | #define AR6001_RESET_CONTROL_ADDRESS 0x0C000000 | ||
396 | #define AR6002_RESET_CONTROL_ADDRESS 0x00004000 | ||
397 | #define AR6003_RESET_CONTROL_ADDRESS 0x00004000 | ||
398 | /* reset device */ | ||
399 | int ar6000_reset_device(struct hif_device *hifDevice, u32 TargetType, bool waitForCompletion, bool coldReset) | ||
400 | { | ||
401 | int status = 0; | ||
402 | u32 address; | ||
403 | u32 data; | ||
404 | |||
405 | do { | ||
406 | // Workaround BEGIN | ||
407 | // address = RESET_CONTROL_ADDRESS; | ||
408 | |||
409 | if (coldReset) { | ||
410 | data = RESET_CONTROL_COLD_RST_MASK; | ||
411 | } | ||
412 | else { | ||
413 | data = RESET_CONTROL_MBOX_RST_MASK; | ||
414 | } | ||
415 | |||
416 | /* Hardcode the address of RESET_CONTROL_ADDRESS based on the target type */ | ||
417 | if (TargetType == TARGET_TYPE_AR6002) { | ||
418 | address = AR6002_RESET_CONTROL_ADDRESS; | ||
419 | } else if (TargetType == TARGET_TYPE_AR6003) { | ||
420 | address = AR6003_RESET_CONTROL_ADDRESS; | ||
421 | } else { | ||
422 | A_ASSERT(0); | ||
423 | } | ||
424 | |||
425 | |||
426 | status = ar6000_WriteRegDiag(hifDevice, &address, &data); | ||
427 | |||
428 | if (status) { | ||
429 | break; | ||
430 | } | ||
431 | |||
432 | if (!waitForCompletion) { | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | #if 0 | ||
437 | /* Up to 2 second delay to allow things to settle down */ | ||
438 | (void)_delay_until_target_alive(hifDevice, 2000, TargetType); | ||
439 | |||
440 | /* | ||
441 | * Read back the RESET CAUSE register to ensure that the cold reset | ||
442 | * went through. | ||
443 | */ | ||
444 | |||
445 | // address = RESET_CAUSE_ADDRESS; | ||
446 | /* Hardcode the address of RESET_CAUSE_ADDRESS based on the target type */ | ||
447 | if (TargetType == TARGET_TYPE_AR6002) { | ||
448 | address = 0x000040C0; | ||
449 | } else if (TargetType == TARGET_TYPE_AR6003) { | ||
450 | address = 0x000040C0; | ||
451 | } else { | ||
452 | A_ASSERT(0); | ||
453 | } | ||
454 | |||
455 | data = 0; | ||
456 | status = ar6000_ReadRegDiag(hifDevice, &address, &data); | ||
457 | |||
458 | if (status) { | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Reset Cause readback: 0x%X \n",data)); | ||
463 | data &= RESET_CAUSE_LAST_MASK; | ||
464 | if (data != 2) { | ||
465 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Unable to cold reset the target \n")); | ||
466 | } | ||
467 | #endif | ||
468 | // Workaroud END | ||
469 | |||
470 | } while (false); | ||
471 | |||
472 | if (status) { | ||
473 | AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Failed to reset target \n")); | ||
474 | } | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | /* This should be called in BMI phase after firmware is downloaded */ | ||
480 | void | ||
481 | ar6000_copy_cust_data_from_target(struct hif_device *hifDevice, u32 TargetType) | ||
482 | { | ||
483 | u32 eepHeaderAddr; | ||
484 | u8 AR6003CustDataShadow[AR6003_CUST_DATA_SIZE+4]; | ||
485 | s32 i; | ||
486 | |||
487 | if (BMIReadMemory(hifDevice, | ||
488 | HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_board_data), | ||
489 | (u8 *)&eepHeaderAddr, | ||
490 | 4)!= 0) | ||
491 | { | ||
492 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadMemory for reading board data address failed \n")); | ||
493 | return; | ||
494 | } | ||
495 | |||
496 | if (TargetType == TARGET_TYPE_AR6003) { | ||
497 | eepHeaderAddr += 36; /* AR6003 customer data section offset is 37 */ | ||
498 | |||
499 | for (i=0; i<AR6003_CUST_DATA_SIZE+4; i+=4){ | ||
500 | if (BMIReadSOCRegister(hifDevice, eepHeaderAddr, (u32 *)&AR6003CustDataShadow[i])!= 0) { | ||
501 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadSOCRegister () failed \n")); | ||
502 | return ; | ||
503 | } | ||
504 | eepHeaderAddr +=4; | ||
505 | } | ||
506 | |||
507 | memcpy(custDataAR6003, AR6003CustDataShadow+1, AR6003_CUST_DATA_SIZE); | ||
508 | } | ||
509 | |||
510 | if (TargetType == TARGET_TYPE_AR6002) { | ||
511 | eepHeaderAddr += 64; /* AR6002 customer data sectioin offset is 64 */ | ||
512 | |||
513 | for (i=0; i<AR6002_CUST_DATA_SIZE; i+=4){ | ||
514 | if (BMIReadSOCRegister(hifDevice, eepHeaderAddr, (u32 *)&custDataAR6002[i])!= 0) { | ||
515 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMIReadSOCRegister () failed \n")); | ||
516 | return ; | ||
517 | } | ||
518 | eepHeaderAddr +=4; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | return; | ||
523 | } | ||
524 | |||
525 | /* This is the function to call when need to use the cust data */ | ||
526 | u8 *ar6000_get_cust_data_buffer(u32 TargetType) | ||
527 | { | ||
528 | if (TargetType == TARGET_TYPE_AR6003) | ||
529 | return custDataAR6003; | ||
530 | |||
531 | if (TargetType == TARGET_TYPE_AR6002) | ||
532 | return custDataAR6002; | ||
533 | |||
534 | return NULL; | ||
535 | } | ||
536 | |||
537 | #define REG_DUMP_COUNT_AR6001 38 /* WORDs, derived from AR600x_regdump.h */ | ||
538 | #define REG_DUMP_COUNT_AR6002 60 | ||
539 | #define REG_DUMP_COUNT_AR6003 60 | ||
540 | #define REGISTER_DUMP_LEN_MAX 60 | ||
541 | #if REG_DUMP_COUNT_AR6001 > REGISTER_DUMP_LEN_MAX | ||
542 | #error "REG_DUMP_COUNT_AR6001 too large" | ||
543 | #endif | ||
544 | #if REG_DUMP_COUNT_AR6002 > REGISTER_DUMP_LEN_MAX | ||
545 | #error "REG_DUMP_COUNT_AR6002 too large" | ||
546 | #endif | ||
547 | #if REG_DUMP_COUNT_AR6003 > REGISTER_DUMP_LEN_MAX | ||
548 | #error "REG_DUMP_COUNT_AR6003 too large" | ||
549 | #endif | ||
550 | |||
551 | |||
552 | void ar6000_dump_target_assert_info(struct hif_device *hifDevice, u32 TargetType) | ||
553 | { | ||
554 | u32 address; | ||
555 | u32 regDumpArea = 0; | ||
556 | int status; | ||
557 | u32 regDumpValues[REGISTER_DUMP_LEN_MAX]; | ||
558 | u32 regDumpCount = 0; | ||
559 | u32 i; | ||
560 | |||
561 | do { | ||
562 | |||
563 | /* the reg dump pointer is copied to the host interest area */ | ||
564 | address = HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_failure_state); | ||
565 | address = TARG_VTOP(TargetType, address); | ||
566 | |||
567 | if (TargetType == TARGET_TYPE_AR6002) { | ||
568 | regDumpCount = REG_DUMP_COUNT_AR6002; | ||
569 | } else if (TargetType == TARGET_TYPE_AR6003) { | ||
570 | regDumpCount = REG_DUMP_COUNT_AR6003; | ||
571 | } else { | ||
572 | A_ASSERT(0); | ||
573 | } | ||
574 | |||
575 | /* read RAM location through diagnostic window */ | ||
576 | status = ar6000_ReadRegDiag(hifDevice, &address, ®DumpArea); | ||
577 | |||
578 | if (status) { | ||
579 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get ptr to register dump area \n")); | ||
580 | break; | ||
581 | } | ||
582 | |||
583 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Location of register dump data: 0x%X \n",regDumpArea)); | ||
584 | |||
585 | if (regDumpArea == 0) { | ||
586 | /* no reg dump */ | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | regDumpArea = TARG_VTOP(TargetType, regDumpArea); | ||
591 | |||
592 | /* fetch register dump data */ | ||
593 | status = ar6000_ReadDataDiag(hifDevice, | ||
594 | regDumpArea, | ||
595 | (u8 *)®DumpValues[0], | ||
596 | regDumpCount * (sizeof(u32))); | ||
597 | |||
598 | if (status) { | ||
599 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Failed to get register dump \n")); | ||
600 | break; | ||
601 | } | ||
602 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("AR6K: Register Dump: \n")); | ||
603 | |||
604 | for (i = 0; i < regDumpCount; i++) { | ||
605 | //ATHR_DISPLAY_MSG (_T(" %d : 0x%8.8X \n"), i, regDumpValues[i]); | ||
606 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" %d : 0x%8.8X \n",i, regDumpValues[i])); | ||
607 | |||
608 | #ifdef UNDER_CE | ||
609 | /* | ||
610 | * For Every logPrintf() Open the File so that in case of Crashes | ||
611 | * We will have until the Last Message Flushed on to the File | ||
612 | * So use logPrintf Sparingly..!! | ||
613 | */ | ||
614 | tgtassertPrintf (ATH_DEBUG_TRC," %d: 0x%8.8X \n",i, regDumpValues[i]); | ||
615 | #endif | ||
616 | } | ||
617 | |||
618 | } while (false); | ||
619 | |||
620 | } | ||
621 | |||
622 | /* set HTC/Mbox operational parameters, this can only be called when the target is in the | ||
623 | * BMI phase */ | ||
624 | int ar6000_set_htc_params(struct hif_device *hifDevice, | ||
625 | u32 TargetType, | ||
626 | u32 MboxIsrYieldValue, | ||
627 | u8 HtcControlBuffers) | ||
628 | { | ||
629 | int status; | ||
630 | u32 blocksizes[HTC_MAILBOX_NUM_MAX]; | ||
631 | |||
632 | do { | ||
633 | /* get the block sizes */ | ||
634 | status = HIFConfigureDevice(hifDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, | ||
635 | blocksizes, sizeof(blocksizes)); | ||
636 | |||
637 | if (status) { | ||
638 | AR_DEBUG_PRINTF(ATH_LOG_ERR,("Failed to get block size info from HIF layer...\n")); | ||
639 | break; | ||
640 | } | ||
641 | /* note: we actually get the block size for mailbox 1, for SDIO the block | ||
642 | * size on mailbox 0 is artificially set to 1 */ | ||
643 | /* must be a power of 2 */ | ||
644 | A_ASSERT((blocksizes[1] & (blocksizes[1] - 1)) == 0); | ||
645 | |||
646 | if (HtcControlBuffers != 0) { | ||
647 | /* set override for number of control buffers to use */ | ||
648 | blocksizes[1] |= ((u32)HtcControlBuffers) << 16; | ||
649 | } | ||
650 | |||
651 | /* set the host interest area for the block size */ | ||
652 | status = BMIWriteMemory(hifDevice, | ||
653 | HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz), | ||
654 | (u8 *)&blocksizes[1], | ||
655 | 4); | ||
656 | |||
657 | if (status) { | ||
658 | AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for IO block size failed \n")); | ||
659 | break; | ||
660 | } | ||
661 | |||
662 | AR_DEBUG_PRINTF(ATH_LOG_INF,("Block Size Set: %d (target address:0x%X)\n", | ||
663 | blocksizes[1], HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_io_block_sz))); | ||
664 | |||
665 | if (MboxIsrYieldValue != 0) { | ||
666 | /* set the host interest area for the mbox ISR yield limit */ | ||
667 | status = BMIWriteMemory(hifDevice, | ||
668 | HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_mbox_isr_yield_limit), | ||
669 | (u8 *)&MboxIsrYieldValue, | ||
670 | 4); | ||
671 | |||
672 | if (status) { | ||
673 | AR_DEBUG_PRINTF(ATH_LOG_ERR,("BMIWriteMemory for yield limit failed \n")); | ||
674 | break; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | } while (false); | ||
679 | |||
680 | return status; | ||
681 | } | ||
682 | |||
683 | void DebugDumpBytes(u8 *buffer, u16 length, char *pDescription) | ||
684 | { | ||
685 | char stream[60]; | ||
686 | char byteOffsetStr[10]; | ||
687 | u32 i; | ||
688 | u16 offset, count, byteOffset; | ||
689 | |||
690 | A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length, pDescription); | ||
691 | |||
692 | count = 0; | ||
693 | offset = 0; | ||
694 | byteOffset = 0; | ||
695 | for(i = 0; i < length; i++) { | ||
696 | A_SPRINTF(stream + offset, "%2.2X ", buffer[i]); | ||
697 | count ++; | ||
698 | offset += 3; | ||
699 | |||
700 | if(count == 16) { | ||
701 | count = 0; | ||
702 | offset = 0; | ||
703 | A_SPRINTF(byteOffsetStr,"%4.4X",byteOffset); | ||
704 | A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); | ||
705 | A_MEMZERO(stream, 60); | ||
706 | byteOffset += 16; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | if(offset != 0) { | ||
711 | A_SPRINTF(byteOffsetStr,"%4.4X",byteOffset); | ||
712 | A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); | ||
713 | } | ||
714 | |||
715 | A_PRINTF("<------------------------------------------------->\n"); | ||
716 | } | ||
717 | |||
718 | void a_dump_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo) | ||
719 | { | ||
720 | int i; | ||
721 | struct ath_debug_mask_description *pDesc; | ||
722 | |||
723 | if (pInfo == NULL) { | ||
724 | return; | ||
725 | } | ||
726 | |||
727 | pDesc = pInfo->pMaskDescriptions; | ||
728 | |||
729 | A_PRINTF("========================================================\n\n"); | ||
730 | A_PRINTF("Module Debug Info => Name : %s \n", pInfo->ModuleName); | ||
731 | A_PRINTF(" => Descr. : %s \n", pInfo->ModuleDescription); | ||
732 | A_PRINTF("\n Current mask => 0x%8.8X \n", pInfo->CurrentMask); | ||
733 | A_PRINTF("\n Avail. Debug Masks :\n\n"); | ||
734 | |||
735 | for (i = 0; i < pInfo->MaxDescriptions; i++,pDesc++) { | ||
736 | A_PRINTF(" => 0x%8.8X -- %s \n", pDesc->Mask, pDesc->Description); | ||
737 | } | ||
738 | |||
739 | if (0 == i) { | ||
740 | A_PRINTF(" => * none defined * \n"); | ||
741 | } | ||
742 | |||
743 | A_PRINTF("\n Standard Debug Masks :\n\n"); | ||
744 | /* print standard masks */ | ||
745 | A_PRINTF(" => 0x%8.8X -- Errors \n", ATH_DEBUG_ERR); | ||
746 | A_PRINTF(" => 0x%8.8X -- Warnings \n", ATH_DEBUG_WARN); | ||
747 | A_PRINTF(" => 0x%8.8X -- Informational \n", ATH_DEBUG_INFO); | ||
748 | A_PRINTF(" => 0x%8.8X -- Tracing \n", ATH_DEBUG_TRC); | ||
749 | A_PRINTF("\n========================================================\n"); | ||
750 | |||
751 | } | ||
752 | |||
753 | |||
754 | static ATH_DEBUG_MODULE_DBG_INFO *FindModule(char *module_name) | ||
755 | { | ||
756 | ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead; | ||
757 | |||
758 | if (!g_ModuleDebugInit) { | ||
759 | return NULL; | ||
760 | } | ||
761 | |||
762 | while (pInfo != NULL) { | ||
763 | /* TODO: need to use something other than strlen */ | ||
764 | if (memcmp(pInfo->ModuleName,module_name,strlen(module_name)) == 0) { | ||
765 | break; | ||
766 | } | ||
767 | pInfo = pInfo->pNext; | ||
768 | } | ||
769 | |||
770 | return pInfo; | ||
771 | } | ||
772 | |||
773 | |||
774 | void a_register_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo) | ||
775 | { | ||
776 | if (!g_ModuleDebugInit) { | ||
777 | return; | ||
778 | } | ||
779 | |||
780 | A_MUTEX_LOCK(&g_ModuleListLock); | ||
781 | |||
782 | if (!(pInfo->Flags & ATH_DEBUG_INFO_FLAGS_REGISTERED)) { | ||
783 | if (g_pModuleInfoHead == NULL) { | ||
784 | g_pModuleInfoHead = pInfo; | ||
785 | } else { | ||
786 | pInfo->pNext = g_pModuleInfoHead; | ||
787 | g_pModuleInfoHead = pInfo; | ||
788 | } | ||
789 | pInfo->Flags |= ATH_DEBUG_INFO_FLAGS_REGISTERED; | ||
790 | } | ||
791 | |||
792 | A_MUTEX_UNLOCK(&g_ModuleListLock); | ||
793 | } | ||
794 | |||
795 | void a_dump_module_debug_info_by_name(char *module_name) | ||
796 | { | ||
797 | ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead; | ||
798 | |||
799 | if (!g_ModuleDebugInit) { | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | if (memcmp(module_name,"all",3) == 0) { | ||
804 | /* dump all */ | ||
805 | while (pInfo != NULL) { | ||
806 | a_dump_module_debug_info(pInfo); | ||
807 | pInfo = pInfo->pNext; | ||
808 | } | ||
809 | return; | ||
810 | } | ||
811 | |||
812 | pInfo = FindModule(module_name); | ||
813 | |||
814 | if (pInfo != NULL) { | ||
815 | a_dump_module_debug_info(pInfo); | ||
816 | } | ||
817 | |||
818 | } | ||
819 | |||
820 | int a_get_module_mask(char *module_name, u32 *pMask) | ||
821 | { | ||
822 | ATH_DEBUG_MODULE_DBG_INFO *pInfo = FindModule(module_name); | ||
823 | |||
824 | if (NULL == pInfo) { | ||
825 | return A_ERROR; | ||
826 | } | ||
827 | |||
828 | *pMask = pInfo->CurrentMask; | ||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | int a_set_module_mask(char *module_name, u32 Mask) | ||
833 | { | ||
834 | ATH_DEBUG_MODULE_DBG_INFO *pInfo = FindModule(module_name); | ||
835 | |||
836 | if (NULL == pInfo) { | ||
837 | return A_ERROR; | ||
838 | } | ||
839 | |||
840 | pInfo->CurrentMask = Mask; | ||
841 | A_PRINTF("Module %s, new mask: 0x%8.8X \n",module_name,pInfo->CurrentMask); | ||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | |||
846 | void a_module_debug_support_init(void) | ||
847 | { | ||
848 | if (g_ModuleDebugInit) { | ||
849 | return; | ||
850 | } | ||
851 | A_MUTEX_INIT(&g_ModuleListLock); | ||
852 | g_pModuleInfoHead = NULL; | ||
853 | g_ModuleDebugInit = true; | ||
854 | A_REGISTER_MODULE_DEBUG_INFO(misc); | ||
855 | } | ||
856 | |||
857 | void a_module_debug_support_cleanup(void) | ||
858 | { | ||
859 | ATH_DEBUG_MODULE_DBG_INFO *pInfo = g_pModuleInfoHead; | ||
860 | ATH_DEBUG_MODULE_DBG_INFO *pCur; | ||
861 | |||
862 | if (!g_ModuleDebugInit) { | ||
863 | return; | ||
864 | } | ||
865 | |||
866 | g_ModuleDebugInit = false; | ||
867 | |||
868 | A_MUTEX_LOCK(&g_ModuleListLock); | ||
869 | |||
870 | while (pInfo != NULL) { | ||
871 | pCur = pInfo; | ||
872 | pInfo = pInfo->pNext; | ||
873 | pCur->pNext = NULL; | ||
874 | /* clear registered flag */ | ||
875 | pCur->Flags &= ~ATH_DEBUG_INFO_FLAGS_REGISTERED; | ||
876 | } | ||
877 | |||
878 | A_MUTEX_UNLOCK(&g_ModuleListLock); | ||
879 | |||
880 | A_MUTEX_DELETE(&g_ModuleListLock); | ||
881 | g_pModuleInfoHead = NULL; | ||
882 | } | ||
883 | |||
884 | /* can only be called during bmi init stage */ | ||
885 | int ar6000_set_hci_bridge_flags(struct hif_device *hifDevice, | ||
886 | u32 TargetType, | ||
887 | u32 Flags) | ||
888 | { | ||
889 | int status = 0; | ||
890 | |||
891 | do { | ||
892 | |||
893 | if (TargetType != TARGET_TYPE_AR6003) { | ||
894 | AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("Target Type:%d, does not support HCI bridging! \n", | ||
895 | TargetType)); | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | /* set hci bridge flags */ | ||
900 | status = BMIWriteMemory(hifDevice, | ||
901 | HOST_INTEREST_ITEM_ADDRESS(TargetType, hi_hci_bridge_flags), | ||
902 | (u8 *)&Flags, | ||
903 | 4); | ||
904 | |||
905 | |||
906 | } while (false); | ||
907 | |||
908 | return status; | ||
909 | } | ||
910 | |||
diff --git a/drivers/staging/ath6kl/miscdrv/credit_dist.c b/drivers/staging/ath6kl/miscdrv/credit_dist.c new file mode 100644 index 00000000000..c777e98a756 --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/credit_dist.c | |||
@@ -0,0 +1,417 @@ | |||
1 | //------------------------------------------------------------------------------ | ||
2 | // <copyright file="credit_dist.c" company="Atheros"> | ||
3 | // Copyright (c) 2004-2010 Atheros Corporation. All rights reserved. | ||
4 | // | ||
5 | // | ||
6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
7 | // purpose with or without fee is hereby granted, provided that the above | ||
8 | // copyright notice and this permission notice appear in all copies. | ||
9 | // | ||
10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | // | ||
18 | // | ||
19 | //------------------------------------------------------------------------------ | ||
20 | //============================================================================== | ||
21 | // Author(s): ="Atheros" | ||
22 | //============================================================================== | ||
23 | |||
24 | #include "a_config.h" | ||
25 | #include "athdefs.h" | ||
26 | #include "a_osapi.h" | ||
27 | #define ATH_MODULE_NAME misc | ||
28 | #include "a_debug.h" | ||
29 | #include "htc_api.h" | ||
30 | #include "common_drv.h" | ||
31 | |||
32 | /********* CREDIT DISTRIBUTION FUNCTIONS ******************************************/ | ||
33 | |||
34 | #define NO_VO_SERVICE 1 /* currently WMI only uses 3 data streams, so we leave VO service inactive */ | ||
35 | #define CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS 1 | ||
36 | |||
37 | #ifdef NO_VO_SERVICE | ||
38 | #define DATA_SVCS_USED 3 | ||
39 | #else | ||
40 | #define DATA_SVCS_USED 4 | ||
41 | #endif | ||
42 | |||
43 | static void RedistributeCredits(struct common_credit_state_info *pCredInfo, | ||
44 | struct htc_endpoint_credit_dist *pEPDistList); | ||
45 | |||
46 | static void SeekCredits(struct common_credit_state_info *pCredInfo, | ||
47 | struct htc_endpoint_credit_dist *pEPDistList); | ||
48 | |||
49 | /* reduce an ep's credits back to a set limit */ | ||
50 | static INLINE void ReduceCredits(struct common_credit_state_info *pCredInfo, | ||
51 | struct htc_endpoint_credit_dist *pEpDist, | ||
52 | int Limit) | ||
53 | { | ||
54 | int credits; | ||
55 | |||
56 | /* set the new limit */ | ||
57 | pEpDist->TxCreditsAssigned = Limit; | ||
58 | |||
59 | if (pEpDist->TxCredits <= Limit) { | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | /* figure out how much to take away */ | ||
64 | credits = pEpDist->TxCredits - Limit; | ||
65 | /* take them away */ | ||
66 | pEpDist->TxCredits -= credits; | ||
67 | pCredInfo->CurrentFreeCredits += credits; | ||
68 | } | ||
69 | |||
70 | /* give an endpoint some credits from the free credit pool */ | ||
71 | #define GiveCredits(pCredInfo,pEpDist,credits) \ | ||
72 | { \ | ||
73 | (pEpDist)->TxCredits += (credits); \ | ||
74 | (pEpDist)->TxCreditsAssigned += (credits); \ | ||
75 | (pCredInfo)->CurrentFreeCredits -= (credits); \ | ||
76 | } | ||
77 | |||
78 | |||
79 | /* default credit init callback. | ||
80 | * This function is called in the context of HTCStart() to setup initial (application-specific) | ||
81 | * credit distributions */ | ||
82 | static void ar6000_credit_init(void *Context, | ||
83 | struct htc_endpoint_credit_dist *pEPList, | ||
84 | int TotalCredits) | ||
85 | { | ||
86 | struct htc_endpoint_credit_dist *pCurEpDist; | ||
87 | int count; | ||
88 | struct common_credit_state_info *pCredInfo = (struct common_credit_state_info *)Context; | ||
89 | |||
90 | pCredInfo->CurrentFreeCredits = TotalCredits; | ||
91 | pCredInfo->TotalAvailableCredits = TotalCredits; | ||
92 | |||
93 | pCurEpDist = pEPList; | ||
94 | |||
95 | /* run through the list and initialize */ | ||
96 | while (pCurEpDist != NULL) { | ||
97 | |||
98 | /* set minimums for each endpoint */ | ||
99 | pCurEpDist->TxCreditsMin = pCurEpDist->TxCreditsPerMaxMsg; | ||
100 | |||
101 | #ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS | ||
102 | |||
103 | if (TotalCredits > 4) | ||
104 | { | ||
105 | if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)){ | ||
106 | /* assign at least min credits to lower than VO priority services */ | ||
107 | GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin); | ||
108 | /* force active */ | ||
109 | SET_EP_ACTIVE(pCurEpDist); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | #endif | ||
114 | |||
115 | if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) { | ||
116 | /* give control service some credits */ | ||
117 | GiveCredits(pCredInfo,pCurEpDist,pCurEpDist->TxCreditsMin); | ||
118 | /* control service is always marked active, it never goes inactive EVER */ | ||
119 | SET_EP_ACTIVE(pCurEpDist); | ||
120 | } else if (pCurEpDist->ServiceID == WMI_DATA_BK_SVC) { | ||
121 | /* this is the lowest priority data endpoint, save this off for easy access */ | ||
122 | pCredInfo->pLowestPriEpDist = pCurEpDist; | ||
123 | } | ||
124 | |||
125 | /* Streams have to be created (explicit | implicit)for all kinds | ||
126 | * of traffic. BE endpoints are also inactive in the beginning. | ||
127 | * When BE traffic starts it creates implicit streams that | ||
128 | * redistributes credits. | ||
129 | */ | ||
130 | |||
131 | /* note, all other endpoints have minimums set but are initially given NO credits. | ||
132 | * Credits will be distributed as traffic activity demands */ | ||
133 | pCurEpDist = pCurEpDist->pNext; | ||
134 | } | ||
135 | |||
136 | if (pCredInfo->CurrentFreeCredits <= 0) { | ||
137 | AR_DEBUG_PRINTF(ATH_LOG_INF, ("Not enough credits (%d) to do credit distributions \n", TotalCredits)); | ||
138 | A_ASSERT(false); | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | /* reset list */ | ||
143 | pCurEpDist = pEPList; | ||
144 | /* now run through the list and set max operating credit limits for everyone */ | ||
145 | while (pCurEpDist != NULL) { | ||
146 | if (pCurEpDist->ServiceID == WMI_CONTROL_SVC) { | ||
147 | /* control service max is just 1 max message */ | ||
148 | pCurEpDist->TxCreditsNorm = pCurEpDist->TxCreditsPerMaxMsg; | ||
149 | } else { | ||
150 | /* for the remaining data endpoints, we assume that each TxCreditsPerMaxMsg are | ||
151 | * the same. | ||
152 | * We use a simple calculation here, we take the remaining credits and | ||
153 | * determine how many max messages this can cover and then set each endpoint's | ||
154 | * normal value equal to 3/4 this amount. | ||
155 | * */ | ||
156 | count = (pCredInfo->CurrentFreeCredits/pCurEpDist->TxCreditsPerMaxMsg) * pCurEpDist->TxCreditsPerMaxMsg; | ||
157 | count = (count * 3) >> 2; | ||
158 | count = max(count,pCurEpDist->TxCreditsPerMaxMsg); | ||
159 | /* set normal */ | ||
160 | pCurEpDist->TxCreditsNorm = count; | ||
161 | |||
162 | } | ||
163 | pCurEpDist = pCurEpDist->pNext; | ||
164 | } | ||
165 | |||
166 | } | ||
167 | |||
168 | |||
169 | /* default credit distribution callback | ||
170 | * This callback is invoked whenever endpoints require credit distributions. | ||
171 | * A lock is held while this function is invoked, this function shall NOT block. | ||
172 | * The pEPDistList is a list of distribution structures in prioritized order as | ||
173 | * defined by the call to the HTCSetCreditDistribution() api. | ||
174 | * | ||
175 | */ | ||
176 | static void ar6000_credit_distribute(void *Context, | ||
177 | struct htc_endpoint_credit_dist *pEPDistList, | ||
178 | HTC_CREDIT_DIST_REASON Reason) | ||
179 | { | ||
180 | struct htc_endpoint_credit_dist *pCurEpDist; | ||
181 | struct common_credit_state_info *pCredInfo = (struct common_credit_state_info *)Context; | ||
182 | |||
183 | switch (Reason) { | ||
184 | case HTC_CREDIT_DIST_SEND_COMPLETE : | ||
185 | pCurEpDist = pEPDistList; | ||
186 | /* we are given the start of the endpoint distribution list. | ||
187 | * There may be one or more endpoints to service. | ||
188 | * Run through the list and distribute credits */ | ||
189 | while (pCurEpDist != NULL) { | ||
190 | |||
191 | if (pCurEpDist->TxCreditsToDist > 0) { | ||
192 | /* return the credits back to the endpoint */ | ||
193 | pCurEpDist->TxCredits += pCurEpDist->TxCreditsToDist; | ||
194 | /* always zero out when we are done */ | ||
195 | pCurEpDist->TxCreditsToDist = 0; | ||
196 | |||
197 | if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsAssigned) { | ||
198 | /* reduce to the assigned limit, previous credit reductions | ||
199 | * could have caused the limit to change */ | ||
200 | ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned); | ||
201 | } | ||
202 | |||
203 | if (pCurEpDist->TxCredits > pCurEpDist->TxCreditsNorm) { | ||
204 | /* oversubscribed endpoints need to reduce back to normal */ | ||
205 | ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsNorm); | ||
206 | } | ||
207 | |||
208 | if (!IS_EP_ACTIVE(pCurEpDist)) { | ||
209 | /* endpoint is inactive, now check for messages waiting for credits */ | ||
210 | if (pCurEpDist->TxQueueDepth == 0) { | ||
211 | /* EP is inactive and there are no pending messages, | ||
212 | * reduce credits back to zero to recover credits */ | ||
213 | ReduceCredits(pCredInfo, pCurEpDist, 0); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | |||
218 | pCurEpDist = pCurEpDist->pNext; | ||
219 | } | ||
220 | |||
221 | break; | ||
222 | |||
223 | case HTC_CREDIT_DIST_ACTIVITY_CHANGE : | ||
224 | RedistributeCredits(pCredInfo,pEPDistList); | ||
225 | break; | ||
226 | case HTC_CREDIT_DIST_SEEK_CREDITS : | ||
227 | SeekCredits(pCredInfo,pEPDistList); | ||
228 | break; | ||
229 | case HTC_DUMP_CREDIT_STATE : | ||
230 | AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Credit Distribution, total : %d, free : %d\n", | ||
231 | pCredInfo->TotalAvailableCredits, pCredInfo->CurrentFreeCredits)); | ||
232 | break; | ||
233 | default: | ||
234 | break; | ||
235 | |||
236 | } | ||
237 | |||
238 | /* sanity checks done after each distribution action */ | ||
239 | A_ASSERT(pCredInfo->CurrentFreeCredits <= pCredInfo->TotalAvailableCredits); | ||
240 | A_ASSERT(pCredInfo->CurrentFreeCredits >= 0); | ||
241 | |||
242 | } | ||
243 | |||
244 | /* redistribute credits based on activity change */ | ||
245 | static void RedistributeCredits(struct common_credit_state_info *pCredInfo, | ||
246 | struct htc_endpoint_credit_dist *pEPDistList) | ||
247 | { | ||
248 | struct htc_endpoint_credit_dist *pCurEpDist = pEPDistList; | ||
249 | |||
250 | /* walk through the list and remove credits from inactive endpoints */ | ||
251 | while (pCurEpDist != NULL) { | ||
252 | |||
253 | #ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS | ||
254 | |||
255 | if ((pCurEpDist->ServiceID == WMI_DATA_BK_SVC) || (pCurEpDist->ServiceID == WMI_DATA_BE_SVC)) { | ||
256 | /* force low priority streams to always be active to retain their minimum credit distribution */ | ||
257 | SET_EP_ACTIVE(pCurEpDist); | ||
258 | } | ||
259 | #endif | ||
260 | |||
261 | if (pCurEpDist->ServiceID != WMI_CONTROL_SVC) { | ||
262 | if (!IS_EP_ACTIVE(pCurEpDist)) { | ||
263 | if (pCurEpDist->TxQueueDepth == 0) { | ||
264 | /* EP is inactive and there are no pending messages, reduce credits back to zero */ | ||
265 | ReduceCredits(pCredInfo, pCurEpDist, 0); | ||
266 | } else { | ||
267 | /* we cannot zero the credits assigned to this EP, but to keep | ||
268 | * the credits available for these leftover packets, reduce to | ||
269 | * a minimum */ | ||
270 | ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsMin); | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* NOTE in the active case, we do not need to do anything further, | ||
276 | * when an EP goes active and needs credits, HTC will call into | ||
277 | * our distribution function using a reason code of HTC_CREDIT_DIST_SEEK_CREDITS */ | ||
278 | |||
279 | pCurEpDist = pCurEpDist->pNext; | ||
280 | } | ||
281 | |||
282 | } | ||
283 | |||
284 | /* HTC has an endpoint that needs credits, pEPDist is the endpoint in question */ | ||
285 | static void SeekCredits(struct common_credit_state_info *pCredInfo, | ||
286 | struct htc_endpoint_credit_dist *pEPDist) | ||
287 | { | ||
288 | struct htc_endpoint_credit_dist *pCurEpDist; | ||
289 | int credits = 0; | ||
290 | int need; | ||
291 | |||
292 | do { | ||
293 | |||
294 | if (pEPDist->ServiceID == WMI_CONTROL_SVC) { | ||
295 | /* we never oversubscribe on the control service, this is not | ||
296 | * a high performance path and the target never holds onto control | ||
297 | * credits for too long */ | ||
298 | break; | ||
299 | } | ||
300 | |||
301 | #ifdef CONFIG_GIVE_LOW_PRIORITY_STREAMS_MIN_CREDITS | ||
302 | if (pEPDist->ServiceID == WMI_DATA_VI_SVC) { | ||
303 | if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) { | ||
304 | /* limit VI service from oversubscribing */ | ||
305 | break; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | if (pEPDist->ServiceID == WMI_DATA_VO_SVC) { | ||
310 | if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm)) { | ||
311 | /* limit VO service from oversubscribing */ | ||
312 | break; | ||
313 | } | ||
314 | } | ||
315 | #else | ||
316 | if (pEPDist->ServiceID == WMI_DATA_VI_SVC) { | ||
317 | if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) || | ||
318 | (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) { | ||
319 | /* limit VI service from oversubscribing */ | ||
320 | /* at least one free credit will not be used by VI */ | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | if (pEPDist->ServiceID == WMI_DATA_VO_SVC) { | ||
326 | if ((pEPDist->TxCreditsAssigned >= pEPDist->TxCreditsNorm) || | ||
327 | (pCredInfo->CurrentFreeCredits <= pEPDist->TxCreditsPerMaxMsg)) { | ||
328 | /* limit VO service from oversubscribing */ | ||
329 | /* at least one free credit will not be used by VO */ | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | #endif | ||
334 | |||
335 | /* for all other services, we follow a simple algorithm of | ||
336 | * 1. checking the free pool for credits | ||
337 | * 2. checking lower priority endpoints for credits to take */ | ||
338 | |||
339 | /* give what we can */ | ||
340 | credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek); | ||
341 | |||
342 | if (credits >= pEPDist->TxCreditsSeek) { | ||
343 | /* we found some to fulfill the seek request */ | ||
344 | break; | ||
345 | } | ||
346 | |||
347 | /* we don't have enough in the free pool, try taking away from lower priority services | ||
348 | * | ||
349 | * The rule for taking away credits: | ||
350 | * 1. Only take from lower priority endpoints | ||
351 | * 2. Only take what is allocated above the minimum (never starve an endpoint completely) | ||
352 | * 3. Only take what you need. | ||
353 | * | ||
354 | * */ | ||
355 | |||
356 | /* starting at the lowest priority */ | ||
357 | pCurEpDist = pCredInfo->pLowestPriEpDist; | ||
358 | |||
359 | /* work backwards until we hit the endpoint again */ | ||
360 | while (pCurEpDist != pEPDist) { | ||
361 | /* calculate how many we need so far */ | ||
362 | need = pEPDist->TxCreditsSeek - pCredInfo->CurrentFreeCredits; | ||
363 | |||
364 | if ((pCurEpDist->TxCreditsAssigned - need) >= pCurEpDist->TxCreditsMin) { | ||
365 | /* the current one has been allocated more than it's minimum and it | ||
366 | * has enough credits assigned above it's minimum to fulfill our need | ||
367 | * try to take away just enough to fulfill our need */ | ||
368 | ReduceCredits(pCredInfo, | ||
369 | pCurEpDist, | ||
370 | pCurEpDist->TxCreditsAssigned - need); | ||
371 | |||
372 | if (pCredInfo->CurrentFreeCredits >= pEPDist->TxCreditsSeek) { | ||
373 | /* we have enough */ | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | pCurEpDist = pCurEpDist->pPrev; | ||
379 | } | ||
380 | |||
381 | /* return what we can get */ | ||
382 | credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek); | ||
383 | |||
384 | } while (false); | ||
385 | |||
386 | /* did we find some credits? */ | ||
387 | if (credits) { | ||
388 | /* give what we can */ | ||
389 | GiveCredits(pCredInfo, pEPDist, credits); | ||
390 | } | ||
391 | |||
392 | } | ||
393 | |||
394 | /* initialize and setup credit distribution */ | ||
395 | int ar6000_setup_credit_dist(HTC_HANDLE HTCHandle, struct common_credit_state_info *pCredInfo) | ||
396 | { | ||
397 | HTC_SERVICE_ID servicepriority[5]; | ||
398 | |||
399 | A_MEMZERO(pCredInfo,sizeof(struct common_credit_state_info)); | ||
400 | |||
401 | servicepriority[0] = WMI_CONTROL_SVC; /* highest */ | ||
402 | servicepriority[1] = WMI_DATA_VO_SVC; | ||
403 | servicepriority[2] = WMI_DATA_VI_SVC; | ||
404 | servicepriority[3] = WMI_DATA_BE_SVC; | ||
405 | servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ | ||
406 | |||
407 | /* set callbacks and priority list */ | ||
408 | HTCSetCreditDistribution(HTCHandle, | ||
409 | pCredInfo, | ||
410 | ar6000_credit_distribute, | ||
411 | ar6000_credit_init, | ||
412 | servicepriority, | ||
413 | 5); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
diff --git a/drivers/staging/ath6kl/miscdrv/miscdrv.h b/drivers/staging/ath6kl/miscdrv/miscdrv.h new file mode 100644 index 00000000000..41be5670db4 --- /dev/null +++ b/drivers/staging/ath6kl/miscdrv/miscdrv.h | |||
@@ -0,0 +1,42 @@ | |||
1 | //------------------------------------------------------------------------------ | ||
2 | // <copyright file="miscdrv.h" company="Atheros"> | ||
3 | // Copyright (c) 2004-2010 Atheros Corporation. All rights reserved. | ||
4 | // | ||
5 | // | ||
6 | // Permission to use, copy, modify, and/or distribute this software for any | ||
7 | // purpose with or without fee is hereby granted, provided that the above | ||
8 | // copyright notice and this permission notice appear in all copies. | ||
9 | // | ||
10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | // | ||
18 | // | ||
19 | //------------------------------------------------------------------------------ | ||
20 | //============================================================================== | ||
21 | // Author(s): ="Atheros" | ||
22 | //============================================================================== | ||
23 | #ifndef _MISCDRV_H | ||
24 | #define _MISCDRV_H | ||
25 | |||
26 | |||
27 | #define HOST_INTEREST_ITEM_ADDRESS(target, item) \ | ||
28 | AR6002_HOST_INTEREST_ITEM_ADDRESS(item) | ||
29 | |||
30 | u32 ar6kRev2Array[][128] = { | ||
31 | {0xFFFF, 0xFFFF}, // No Patches | ||
32 | }; | ||
33 | |||
34 | #define CFG_REV2_ITEMS 0 // no patches so far | ||
35 | #define AR6K_RESET_ADDR 0x4000 | ||
36 | #define AR6K_RESET_VAL 0x100 | ||
37 | |||
38 | #define EEPROM_SZ 768 | ||
39 | #define EEPROM_WAIT_LIMIT 4 | ||
40 | |||
41 | #endif | ||
42 | |||