Root/target/linux/s3c24xx/files-2.6.30/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 ------- */
27SD_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
68TARGET_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
82HIF_DEVICE hifDevice[HIF_MAX_DEVICES];
83HTC_CALLBACKS htcCallbacks;
84BUS_REQUEST busRequest[BUS_REQUEST_MAX_NUM];
85static BUS_REQUEST *s_busRequestFreeQueue = NULL;
86OS_CRITICALSECTION lock;
87extern A_UINT32 onebitmode;
88extern A_UINT32 busspeedlow;
89
90#ifdef DEBUG
91extern 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
104static BUS_REQUEST *hifAllocateBusRequest(void);
105static void hifFreeBusRequest(BUS_REQUEST *busrequest);
106static THREAD_RETURN insert_helper_func(POSKERNEL_HELPER pHelper);
107static void ResetAllCards(void);
108
109/* ------ Functions ------ */
110int 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
133A_STATUS
134HIFReadWrite(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
297A_STATUS
298HIFConfigureDevice(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
329void
330HIFShutDownDevice(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
399void
400hifRWCompletionHandler(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
423void
424hifIRQHandler(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
435BOOL
436hifDeviceInserted(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
634static 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
659void
660HIFAckInterrupt(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
672void
673HIFUnMaskInterrupt(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
689void 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
704static 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
723static void
724hifFreeBusRequest(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
739void
740hifDeviceRemoved(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
760HIF_DEVICE *
761addHifDevice(SDDEVICE *handle)
762{
763    DBG_ASSERT(handle != NULL);
764    hifDevice[0].handle = handle;
765    return &hifDevice[0];
766}
767
768HIF_DEVICE *
769getHifDevice(SDDEVICE *handle)
770{
771    DBG_ASSERT(handle != NULL);
772    return &hifDevice[0];
773}
774
775void
776delHifDevice(SDDEVICE *handle)
777{
778    DBG_ASSERT(handle != NULL);
779    hifDevice[0].handle = NULL;
780}
781
782struct device*
783HIFGetOSDevice(HIF_DEVICE *device)
784{
785    return &device->handle->Device->dev;
786}
787
788static 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
817void 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}
825

Archive Download this file



interactive