d04486c35b0e74e97e6aabf360beae4153511d9b
[openwrt.git] / target / linux / s3c24xx / files-2.6.31 / drivers / ar6000 / hif / hif.c
1 /*
2  * @file: hif.c
3  *
4  * @abstract: HIF layer reference implementation for Atheros SDIO stack
5  *
6  * @notice: Copyright (c) 2004-2006 Atheros Communications Inc.
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2 as
11  *  published by the Free Software Foundation;
12  *
13  *  Software distributed under the License is distributed on an "AS
14  *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
15  *  implied. See the License for the specific language governing
16  *  rights and limitations under the License.
17  *
18  *
19  *
20  */
21
22 #include "hif_internal.h"
23
24 /* ------ Static Variables ------ */
25
26 /* ------ Global Variable Declarations ------- */
27 SD_PNP_INFO Ids[] = {
28     {
29         .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xB,
30         .SDIO_ManufacturerCode = MANUFACTURER_CODE,
31         .SDIO_FunctionClass = FUNCTION_CLASS,
32         .SDIO_FunctionNo = 1
33     },
34     {
35         .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0xA,
36         .SDIO_ManufacturerCode = MANUFACTURER_CODE,
37         .SDIO_FunctionClass = FUNCTION_CLASS,
38         .SDIO_FunctionNo = 1
39     },
40     {
41         .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x9,
42         .SDIO_ManufacturerCode = MANUFACTURER_CODE,
43         .SDIO_FunctionClass = FUNCTION_CLASS,
44         .SDIO_FunctionNo = 1
45     },
46     {
47         .SDIO_ManufacturerID = MANUFACTURER_ID_AR6001_BASE | 0x8,
48         .SDIO_ManufacturerCode = MANUFACTURER_CODE,
49         .SDIO_FunctionClass = FUNCTION_CLASS,
50         .SDIO_FunctionNo = 1
51     },
52     {
53         .SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x0,
54         .SDIO_ManufacturerCode = MANUFACTURER_CODE,
55         .SDIO_FunctionClass = FUNCTION_CLASS,
56         .SDIO_FunctionNo = 1
57     },
58     {
59         .SDIO_ManufacturerID = MANUFACTURER_ID_AR6002_BASE | 0x1,
60         .SDIO_ManufacturerCode = MANUFACTURER_CODE,
61         .SDIO_FunctionClass = FUNCTION_CLASS,
62         .SDIO_FunctionNo = 1
63     },
64     {
65     }                      //list is null termintaed
66 };
67
68 TARGET_FUNCTION_CONTEXT FunctionContext = {
69     .function.Version    = CT_SDIO_STACK_VERSION_CODE,
70     .function.pName      = "sdio_wlan",
71     .function.MaxDevices = 1,
72     .function.NumDevices = 0,
73     .function.pIds       = Ids,
74     .function.pProbe     = hifDeviceInserted,
75     .function.pRemove    = hifDeviceRemoved,
76     .function.pSuspend   = NULL,
77     .function.pResume    = NULL,
78     .function.pWake      = NULL,
79     .function.pContext   = &FunctionContext,
80 };
81
82 HIF_DEVICE hifDevice[HIF_MAX_DEVICES];
83 HTC_CALLBACKS htcCallbacks;
84 BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM];
85 static BUS_REQUEST *s_busRequestFreeQueue = NULL;
86 OS_CRITICALSECTION lock;
87 extern A_UINT32 onebitmode;
88 extern A_UINT32 busspeedlow;
89
90 #ifdef DEBUG
91 extern A_UINT32 debughif;
92 #define ATH_DEBUG_ERROR 1
93 #define ATH_DEBUG_WARN  2
94 #define ATH_DEBUG_TRACE 3
95 #define _AR_DEBUG_PRINTX_ARG(arg...) arg
96 #define AR_DEBUG_PRINTF(lvl, args)\
97     {if (lvl <= debughif)\
98         A_PRINTF(KERN_ALERT _AR_DEBUG_PRINTX_ARG args);\
99     }
100 #else
101 #define AR_DEBUG_PRINTF(lvl, args)
102 #endif
103
104 static BUS_REQUEST *hifAllocateBusRequest(void);
105 static void hifFreeBusRequest(BUS_REQUEST *busrequest);
106 static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper);
107 static void ResetAllCards(void);
108
109 /* ------ Functions ------ */
110 int HIFInit(HTC_CALLBACKS *callbacks)
111 {
112     SDIO_STATUS status;
113     DBG_ASSERT(callbacks != NULL);
114
115     /* Store the callback and event handlers */
116     htcCallbacks.deviceInsertedHandler = callbacks->deviceInsertedHandler;
117     htcCallbacks.deviceRemovedHandler = callbacks->deviceRemovedHandler;
118     htcCallbacks.deviceSuspendHandler = callbacks->deviceSuspendHandler;
119     htcCallbacks.deviceResumeHandler = callbacks->deviceResumeHandler;
120     htcCallbacks.deviceWakeupHandler = callbacks->deviceWakeupHandler;
121     htcCallbacks.rwCompletionHandler = callbacks->rwCompletionHandler;
122     htcCallbacks.dsrHandler = callbacks->dsrHandler;
123
124     CriticalSectionInit(&lock);
125
126     /* Register with bus driver core */
127     status = SDIO_RegisterFunction(&FunctionContext.function);
128     DBG_ASSERT(SDIO_SUCCESS(status));
129
130     return(0);
131 }
132
133 A_STATUS
134 HIFReadWrite(HIF_DEVICE *device,
135              A_UINT32 address,
136              A_UCHAR *buffer,
137              A_UINT32 length,
138              A_UINT32 request,
139              void *context)
140 {
141     A_UINT8 rw;
142     A_UINT8 mode;
143     A_UINT8 funcNo;
144     A_UINT8 opcode;
145     A_UINT16 count;
146     SDREQUEST *sdrequest;
147     SDIO_STATUS sdiostatus;
148     BUS_REQUEST *busrequest;
149     A_STATUS    status = A_OK;
150
151     DBG_ASSERT(device != NULL);
152     DBG_ASSERT(device->handle != NULL);
153
154     AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
155
156     do {
157         busrequest = hifAllocateBusRequest();
158         if (busrequest == NULL) {
159             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF Unable to allocate bus request\n"));
160             status = A_NO_RESOURCE;
161             break;
162         }
163
164         sdrequest = busrequest->request;
165         busrequest->context = context;
166
167         sdrequest->pDataBuffer = buffer;
168         if (request & HIF_SYNCHRONOUS) {
169             sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS;
170             sdrequest->pCompleteContext = NULL;
171             sdrequest->pCompletion = NULL;
172             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Synchronous\n"));
173         } else if (request & HIF_ASYNCHRONOUS) {
174             sdrequest->Flags = SDREQ_FLAGS_RESP_SDIO_R5 | SDREQ_FLAGS_DATA_TRANS |
175                                SDREQ_FLAGS_TRANS_ASYNC;
176             sdrequest->pCompleteContext = busrequest;
177             sdrequest->pCompletion = hifRWCompletionHandler;
178             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Execution mode: Asynchronous\n"));
179         } else {
180             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
181                             ("Invalid execution mode: 0x%08x\n", request));
182             status = A_EINVAL;
183             break;
184         }
185
186         if (request & HIF_EXTENDED_IO) {
187             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Command type: CMD53\n"));
188             sdrequest->Command = CMD53;
189         } else {
190             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
191                             ("Invalid command type: 0x%08x\n", request));
192             status = A_EINVAL;
193             break;
194         }
195
196         if (request & HIF_BLOCK_BASIS) {
197             mode = CMD53_BLOCK_BASIS;
198             sdrequest->BlockLen = HIF_MBOX_BLOCK_SIZE;
199             sdrequest->BlockCount = length / HIF_MBOX_BLOCK_SIZE;
200             count = sdrequest->BlockCount;
201             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
202                             ("Block mode (BlockLen: %d, BlockCount: %d)\n",
203                             sdrequest->BlockLen, sdrequest->BlockCount));
204         } else if (request & HIF_BYTE_BASIS) {
205             mode = CMD53_BYTE_BASIS;
206             sdrequest->BlockLen = length;
207             sdrequest->BlockCount = 1;
208             count = sdrequest->BlockLen;
209             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
210                             ("Byte mode (BlockLen: %d, BlockCount: %d)\n",
211                             sdrequest->BlockLen, sdrequest->BlockCount));
212         } else {
213             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
214                             ("Invalid data mode: 0x%08x\n", request));
215             status = A_EINVAL;
216             break;
217         }
218
219 #if 0
220         /* useful for checking register accesses */
221         if (length & 0x3) {
222             A_PRINTF(KERN_ALERT"HIF (%s) is not a multiple of 4 bytes, addr:0x%X, len:%d\n",
223                                 request & HIF_WRITE ? "write":"read", address, length);
224         }
225 #endif
226
227         if ((address >= HIF_MBOX_START_ADDR(0)) &&
228             (address <= HIF_MBOX_END_ADDR(3)))
229         {
230
231             DBG_ASSERT(length <= HIF_MBOX_WIDTH);
232
233             /*
234              * Mailbox write. Adjust the address so that the last byte
235              * falls on the EOM address.
236              */
237             address += (HIF_MBOX_WIDTH - length);
238         }
239
240
241
242         if (request & HIF_WRITE) {
243             rw = CMD53_WRITE;
244             sdrequest->Flags |= SDREQ_FLAGS_DATA_WRITE;
245             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Write\n"));
246         } else if (request & HIF_READ) {
247             rw = CMD53_READ;
248             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Direction: Read\n"));
249         } else {
250             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
251                             ("Invalid direction: 0x%08x\n", request));
252             status = A_EINVAL;
253             break;
254         }
255
256         if (request & HIF_FIXED_ADDRESS) {
257             opcode = CMD53_FIXED_ADDRESS;
258             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Fixed\n"));
259         } else if (request & HIF_INCREMENTAL_ADDRESS) {
260             opcode = CMD53_INCR_ADDRESS;
261             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Address mode: Incremental\n"));
262         } else {
263             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
264                             ("Invalid address mode: 0x%08x\n", request));
265             status = A_EINVAL;
266             break;
267         }
268
269         funcNo = SDDEVICE_GET_SDIO_FUNCNO(device->handle);
270         AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Function number: %d\n", funcNo));
271         SDIO_SET_CMD53_ARG(sdrequest->Argument, rw, funcNo,
272                            mode, opcode, address, count);
273
274         /* Send the command out */
275         sdiostatus = SDDEVICE_CALL_REQUEST_FUNC(device->handle, sdrequest);
276
277         if (!SDIO_SUCCESS(sdiostatus)) {
278             status = A_ERROR;
279         }
280
281     } while (FALSE);
282
283     if (A_FAILED(status) || (request & HIF_SYNCHRONOUS)) {
284         if (busrequest != NULL) {
285             hifFreeBusRequest(busrequest);
286         }
287     }
288
289     if (A_FAILED(status) && (request & HIF_ASYNCHRONOUS)) {
290             /* call back async handler on failure */
291         htcCallbacks.rwCompletionHandler(context, status);
292     }
293
294     return status;
295 }
296
297 A_STATUS
298 HIFConfigureDevice(HIF_DEVICE *device, HIF_DEVICE_CONFIG_OPCODE opcode,
299                    void *config, A_UINT32 configLen)
300 {
301     A_UINT32 count;
302
303     switch(opcode) {
304         case HIF_DEVICE_GET_MBOX_BLOCK_SIZE:
305             ((A_UINT32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE;
306             ((A_UINT32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE;
307             ((A_UINT32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE;
308             ((A_UINT32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE;
309             break;
310
311         case HIF_DEVICE_GET_MBOX_ADDR:
312             for (count = 0; count < 4; count ++) {
313                 ((A_UINT32 *)config)[count] = HIF_MBOX_START_ADDR(count);
314             }
315             break;
316         case HIF_DEVICE_GET_IRQ_PROC_MODE:
317                 /* the SDIO stack allows the interrupts to be processed either way, ASYNC or SYNC */
318             *((HIF_DEVICE_IRQ_PROCESSING_MODE *)config) = HIF_DEVICE_IRQ_ASYNC_SYNC;
319             break;
320         default:
321             AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
322                             ("Unsupported configuration opcode: %d\n", opcode));
323             return A_ERROR;
324     }
325
326     return A_OK;
327 }
328
329 void
330 HIFShutDownDevice(HIF_DEVICE *device)
331 {
332     A_UINT8 data;
333     A_UINT32 count;
334     SDIO_STATUS status;
335     SDCONFIG_BUS_MODE_DATA busSettings;
336     SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
337
338     if (device != NULL) {
339         DBG_ASSERT(device->handle != NULL);
340
341         /* Remove the allocated current if any */
342         status = SDLIB_IssueConfig(device->handle,
343                                    SDCONFIG_FUNC_FREE_SLOT_CURRENT, NULL, 0);
344         DBG_ASSERT(SDIO_SUCCESS(status));
345
346         /* Disable the card */
347         fData.EnableFlags = SDCONFIG_DISABLE_FUNC;
348         fData.TimeOut = 1;
349         status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ENABLE_DISABLE,
350                                    &fData, sizeof(fData));
351         DBG_ASSERT(SDIO_SUCCESS(status));
352
353         /* Perform a soft I/O reset */
354         data = SDIO_IO_RESET;
355         status = SDLIB_IssueCMD52(device->handle, 0, SDIO_IO_ABORT_REG,
356                                   &data, 1, 1);
357         DBG_ASSERT(SDIO_SUCCESS(status));
358
359         /*
360          * WAR - Codetelligence driver does not seem to shutdown correctly in 1
361          * bit mode. By default it configures the HC in the 4 bit. Its later in
362          * our driver that we switch to 1 bit mode. If we try to shutdown, the
363          * driver hangs so we revert to 4 bit mode, to be transparent to the
364          * underlying bus driver.
365          */
366         if (onebitmode) {
367             ZERO_OBJECT(busSettings);
368             busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(device->handle);
369             SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
370                                    SDCONFIG_BUS_WIDTH_4_BIT);
371
372             /* Issue config request to change the bus width to 4 bit */
373             status = SDLIB_IssueConfig(device->handle, SDCONFIG_BUS_MODE_CTRL,
374                                        &busSettings,
375                                        sizeof(SDCONFIG_BUS_MODE_DATA));
376             DBG_ASSERT(SDIO_SUCCESS(status));
377         }
378
379         /* Free the bus requests */
380         for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
381             SDDeviceFreeRequest(device->handle, busRequest[count].request);
382         }
383         /* Clean up the queue */
384         s_busRequestFreeQueue = NULL;
385     } else {
386             /* since we are unloading the driver anyways, reset all cards in case the SDIO card
387              * is externally powered and we are unloading the SDIO stack.  This avoids the problem when
388              * the SDIO stack is reloaded and attempts are made to re-enumerate a card that is already
389              * enumerated */
390         ResetAllCards();
391         /* Unregister with bus driver core */
392         AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
393                         ("Unregistering with the bus driver\n"));
394         status = SDIO_UnregisterFunction(&FunctionContext.function);
395         DBG_ASSERT(SDIO_SUCCESS(status));
396     }
397 }
398
399 void
400 hifRWCompletionHandler(SDREQUEST *request)
401 {
402     A_STATUS status;
403     void *context;
404     BUS_REQUEST *busrequest;
405
406     if (SDIO_SUCCESS(request->Status)) {
407         status = A_OK;
408     } else {
409         status = A_ERROR;
410     }
411
412     DBG_ASSERT(status == A_OK);
413     busrequest = (BUS_REQUEST *) request->pCompleteContext;
414     context = (void *) busrequest->context;
415         /* free the request before calling the callback, in case the
416          * callback submits another request, this guarantees that
417          * there is at least 1 free request available everytime the callback
418          * is invoked */
419     hifFreeBusRequest(busrequest);
420     htcCallbacks.rwCompletionHandler(context, status);
421 }
422
423 void
424 hifIRQHandler(void *context)
425 {
426     A_STATUS status;
427     HIF_DEVICE *device;
428
429     device = (HIF_DEVICE *)context;
430     AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
431     status = htcCallbacks.dsrHandler(device->htc_handle);
432     DBG_ASSERT(status == A_OK);
433 }
434
435 BOOL
436 hifDeviceInserted(SDFUNCTION *function, SDDEVICE *handle)
437 {
438     BOOL enabled;
439     A_UINT8 data;
440     A_UINT32 count;
441     HIF_DEVICE *device;
442     SDIO_STATUS status;
443     A_UINT16 maxBlocks;
444     A_UINT16 maxBlockSize;
445     SDCONFIG_BUS_MODE_DATA busSettings;
446     SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
447     TARGET_FUNCTION_CONTEXT *functionContext;
448     SDCONFIG_FUNC_SLOT_CURRENT_DATA slotCurrent;
449     SD_BUSCLOCK_RATE                currentBusClock;
450
451     DBG_ASSERT(function != NULL);
452     DBG_ASSERT(handle != NULL);
453
454     device = addHifDevice(handle);
455     AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device: %p\n", device));
456     functionContext =  (TARGET_FUNCTION_CONTEXT *)function->pContext;
457
458     /*
459      * Issue commands to get the manufacturer ID and stuff and compare it
460      * against the rev Id derived from the ID registered during the
461      * initialization process. Report the device only in the case there
462      * is a match. In the case od SDIO, the bus driver has already queried
463      * these details so we just need to use their data structures to get the
464      * relevant values. Infact, the driver has already matched it against
465      * the Ids that we registered with it so we dont need to the step here.
466      */
467
468     /* Configure the SDIO Bus Width */
469     if (onebitmode) {
470         data = SDIO_BUS_WIDTH_1_BIT;
471         status = SDLIB_IssueCMD52(handle, 0, SDIO_BUS_IF_REG, &data, 1, 1);
472         if (!SDIO_SUCCESS(status)) {
473             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
474                             ("Unable to set the bus width to 1 bit\n"));
475             return FALSE;
476         }
477     }
478
479     /* Get current bus flags */
480     ZERO_OBJECT(busSettings);
481
482     busSettings.BusModeFlags = SDDEVICE_GET_BUSMODE_FLAGS(handle);
483     if (onebitmode) {
484         SDCONFIG_SET_BUS_WIDTH(busSettings.BusModeFlags,
485                                SDCONFIG_BUS_WIDTH_1_BIT);
486     }
487
488         /* get the current operating clock, the bus driver sets us up based
489          * on what our CIS reports and what the host controller can handle
490          * we can use this to determine whether we want to drop our clock rate
491          * down */
492     currentBusClock = SDDEVICE_GET_OPER_CLOCK(handle);
493     busSettings.ClockRate = currentBusClock;
494
495     AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
496                         ("HIF currently running at: %d \n",currentBusClock));
497
498         /* see if HIF wants to run at a lower clock speed, we may already be
499          * at that lower clock speed */
500     if (currentBusClock > (SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow)) {
501         busSettings.ClockRate = SDIO_CLOCK_FREQUENCY_DEFAULT >> busspeedlow;
502         AR_DEBUG_PRINTF(ATH_DEBUG_WARN,
503                         ("HIF overriding clock to %d \n",busSettings.ClockRate));
504     }
505
506     /* Issue config request to override clock rate */
507     status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_CHANGE_BUS_MODE, &busSettings,
508                                sizeof(SDCONFIG_BUS_MODE_DATA));
509     if (!SDIO_SUCCESS(status)) {
510         AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
511                         ("Unable to configure the host clock\n"));
512         return FALSE;
513     } else {
514         AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
515                         ("Configured clock: %d, Maximum clock: %d\n",
516                         busSettings.ActualClockRate,
517                         SDDEVICE_GET_MAX_CLOCK(handle)));
518     }
519
520     /*
521      * Check if the target supports block mode. This result of this check
522      * can be used to implement the HIFReadWrite API.
523      */
524     if (SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle)) {
525         /* Limit block size to operational block limit or card function
526            capability */
527         maxBlockSize = min(SDDEVICE_GET_OPER_BLOCK_LEN(handle),
528                            SDDEVICE_GET_SDIO_FUNC_MAXBLKSIZE(handle));
529
530         /* check if the card support multi-block transfers */
531         if (!(SDDEVICE_GET_SDIOCARD_CAPS(handle) & SDIO_CAPS_MULTI_BLOCK)) {
532             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Byte basis only\n"));
533
534             /* Limit block size to max byte basis */
535             maxBlockSize =  min(maxBlockSize,
536                                 (A_UINT16)SDIO_MAX_LENGTH_BYTE_BASIS);
537             maxBlocks = 1;
538         } else {
539             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Multi-block capable\n"));
540             maxBlocks = SDDEVICE_GET_OPER_BLOCKS(handle);
541             status = SDLIB_SetFunctionBlockSize(handle, HIF_MBOX_BLOCK_SIZE);
542             if (!SDIO_SUCCESS(status)) {
543                 AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
544                                 ("Failed to set block size. Err:%d\n", status));
545                 return FALSE;
546             }
547         }
548
549         AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
550                         ("Bytes Per Block: %d bytes, Block Count:%d \n",
551                         maxBlockSize, maxBlocks));
552     } else {
553         AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
554                         ("Function does not support Block Mode!\n"));
555         return FALSE;
556     }
557
558     /* Allocate the slot current */
559     status = SDLIB_GetDefaultOpCurrent(handle, &slotCurrent.SlotCurrent);
560     if (SDIO_SUCCESS(status)) {
561         AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Allocating Slot current: %d mA\n",
562                                 slotCurrent.SlotCurrent));
563         status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ALLOC_SLOT_CURRENT,
564                                    &slotCurrent, sizeof(slotCurrent));
565         if (!SDIO_SUCCESS(status)) {
566             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
567                             ("Failed to allocate slot current %d\n", status));
568             return FALSE;
569         }
570     }
571
572     /* Enable the dragon function */
573     count = 0;
574     enabled = FALSE;
575     fData.TimeOut = 1;
576     fData.EnableFlags = SDCONFIG_ENABLE_FUNC;
577     while ((count++ < SDWLAN_ENABLE_DISABLE_TIMEOUT) && !enabled)
578     {
579         /* Enable dragon */
580         status = SDLIB_IssueConfig(handle, SDCONFIG_FUNC_ENABLE_DISABLE,
581                                    &fData, sizeof(fData));
582         if (!SDIO_SUCCESS(status)) {
583             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
584                             ("Attempting to enable the card again\n"));
585             continue;
586         }
587
588         /* Mark the status as enabled */
589         enabled = TRUE;
590     }
591
592     /* Check if we were succesful in enabling the target */
593     if (!enabled) {
594         AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,
595                         ("Failed to communicate with the target\n"));
596         return FALSE;
597     }
598
599     /* Allocate the bus requests to be used later */
600     A_MEMZERO(busRequest, sizeof(busRequest));
601     for (count = 0; count < BUS_REQUEST_MAX_NUM; count ++) {
602         if ((busRequest[count].request = SDDeviceAllocRequest(handle)) == NULL){
603             AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("Unable to allocate memory\n"));
604             /* TODO: Free the memory that has already been allocated */
605             return FALSE;
606         }
607         hifFreeBusRequest(&busRequest[count]);
608
609         AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
610                 ("0x%08x = busRequest[%d].request = 0x%08x\n",
611                                 (unsigned int) &busRequest[count], count,
612                                 (unsigned int) busRequest[count].request));
613     }
614
615         /* Schedule a worker to handle device inserted, this is a temporary workaround
616          * to fix a deadlock if the device fails to intialize in the insertion handler
617          * The failure causes the instance to shutdown the HIF layer and unregister the
618          * function driver within the busdriver probe context which can deadlock
619          *
620          * NOTE: we cannot use the default work queue because that would block
621          * SD bus request processing for all synchronous I/O. We must use a kernel
622          * thread that is creating using the helper library.
623          * */
624
625     if (SDIO_SUCCESS(SDLIB_OSCreateHelper(&device->insert_helper,
626                          insert_helper_func,
627                          device))) {
628         device->helper_started = TRUE;
629     }
630
631     return TRUE;
632 }
633
634 static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper)
635 {
636
637     /*
638      * Adding a wait of around a second before we issue the very first
639      * command to dragon. During the process of loading/unloading the
640      * driver repeatedly it was observed that we get a data timeout
641      * while accessing function 1 registers in the chip. The theory at
642      * this point is that some initialization delay in dragon is
643      * causing the SDIO state in dragon core to be not ready even after
644      * the ready bit indicates that function 1 is ready. Accomodating
645      * for this behavior by adding some delay in the driver before it
646      * issues the first command after switching on dragon. Need to
647      * investigate this a bit more - TODO
648      */
649
650     A_MDELAY(1000);
651         /* Inform HTC */
652     if ((htcCallbacks.deviceInsertedHandler(SD_GET_OS_HELPER_CONTEXT(pHelper))) != A_OK) {
653         AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("Device rejected\n"));
654     }
655
656     return 0;
657 }
658
659 void
660 HIFAckInterrupt(HIF_DEVICE *device)
661 {
662     SDIO_STATUS status;
663     DBG_ASSERT(device != NULL);
664     DBG_ASSERT(device->handle != NULL);
665
666     /* Acknowledge our function IRQ */
667     status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_ACK_IRQ,
668                                NULL, 0);
669     DBG_ASSERT(SDIO_SUCCESS(status));
670 }
671
672 void
673 HIFUnMaskInterrupt(HIF_DEVICE *device)
674 {
675     SDIO_STATUS status;
676
677     DBG_ASSERT(device != NULL);
678     DBG_ASSERT(device->handle != NULL);
679
680     /* Register the IRQ Handler */
681     SDDEVICE_SET_IRQ_HANDLER(device->handle, hifIRQHandler, device);
682
683     /* Unmask our function IRQ */
684     status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_UNMASK_IRQ,
685                                NULL, 0);
686     DBG_ASSERT(SDIO_SUCCESS(status));
687 }
688
689 void HIFMaskInterrupt(HIF_DEVICE *device)
690 {
691     SDIO_STATUS status;
692     DBG_ASSERT(device != NULL);
693     DBG_ASSERT(device->handle != NULL);
694
695     /* Mask our function IRQ */
696     status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_MASK_IRQ,
697                                NULL, 0);
698     DBG_ASSERT(SDIO_SUCCESS(status));
699
700     /* Unregister the IRQ Handler */
701     SDDEVICE_SET_IRQ_HANDLER(device->handle, NULL, NULL);
702 }
703
704 static BUS_REQUEST *hifAllocateBusRequest(void)
705 {
706     BUS_REQUEST *busrequest;
707
708     /* Acquire lock */
709     CriticalSectionAcquire(&lock);
710
711     /* Remove first in list */
712     if((busrequest = s_busRequestFreeQueue) != NULL)
713     {
714         s_busRequestFreeQueue = busrequest->next;
715     }
716
717     /* Release lock */
718     CriticalSectionRelease(&lock);
719
720     return busrequest;
721 }
722
723 static void
724 hifFreeBusRequest(BUS_REQUEST *busrequest)
725 {
726     DBG_ASSERT(busrequest != NULL);
727
728     /* Acquire lock */
729     CriticalSectionAcquire(&lock);
730
731     /* Insert first in list */
732     busrequest->next = s_busRequestFreeQueue;
733     s_busRequestFreeQueue = busrequest;
734
735     /* Release lock */
736     CriticalSectionRelease(&lock);
737 }
738
739 void
740 hifDeviceRemoved(SDFUNCTION *function, SDDEVICE *handle)
741 {
742     A_STATUS status;
743     HIF_DEVICE *device;
744     DBG_ASSERT(function != NULL);
745     DBG_ASSERT(handle != NULL);
746
747     device = getHifDevice(handle);
748     status = htcCallbacks.deviceRemovedHandler(device->htc_handle, A_OK);
749
750         /* cleanup the helper thread */
751     if (device->helper_started) {
752         SDLIB_OSDeleteHelper(&device->insert_helper);
753         device->helper_started = FALSE;
754     }
755
756     delHifDevice(handle);
757     DBG_ASSERT(status == A_OK);
758 }
759
760 HIF_DEVICE *
761 addHifDevice(SDDEVICE *handle)
762 {
763     DBG_ASSERT(handle != NULL);
764     hifDevice[0].handle = handle;
765     return &hifDevice[0];
766 }
767
768 HIF_DEVICE *
769 getHifDevice(SDDEVICE *handle)
770 {
771     DBG_ASSERT(handle != NULL);
772     return &hifDevice[0];
773 }
774
775 void
776 delHifDevice(SDDEVICE *handle)
777 {
778     DBG_ASSERT(handle != NULL);
779     hifDevice[0].handle = NULL;
780 }
781
782 struct device*
783 HIFGetOSDevice(HIF_DEVICE *device)
784 {
785     return &device->handle->Device->dev;
786 }
787
788 static void ResetAllCards(void)
789 {
790     UINT8       data;
791     SDIO_STATUS status;
792     int         i;
793
794     data = SDIO_IO_RESET;
795
796     /* set the I/O CARD reset bit:
797      * NOTE: we are exploiting a "feature" of the SDIO core that resets the core when you
798      * set the RES bit in the SDIO_IO_ABORT register.  This bit however "normally" resets the
799      * I/O functions leaving the SDIO core in the same state (as per SDIO spec).
800      * In this design, this reset can be used to reset the SDIO core itself */
801     for (i = 0; i < HIF_MAX_DEVICES; i++) {
802         if (hifDevice[i].handle != NULL) {
803             AR_DEBUG_PRINTF(ATH_DEBUG_TRACE,
804                         ("Issuing I/O Card reset for instance: %d \n",i));
805                 /* set the I/O Card reset bit */
806             status = SDLIB_IssueCMD52(hifDevice[i].handle,
807                                       0,                    /* function 0 space */
808                                       SDIO_IO_ABORT_REG,
809                                       &data,
810                                       1,                    /* 1 byte */
811                                       TRUE);                /* write */
812         }
813     }
814
815 }
816
817 void HIFSetHandle(void *hif_handle, void *handle)
818 {
819     HIF_DEVICE *device = (HIF_DEVICE *) hif_handle;
820
821     device->htc_handle = handle;
822
823     return;
824 }