aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/csr/sdio_events.c
blob: 2a80b9eb0200abc62fd3d61a6a5bef0bf976293a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * ---------------------------------------------------------------------------
 * FILE:     sdio_events.c
 *
 * PURPOSE:
 *      Process the events received by the SDIO glue layer.
 *      Optional part of the porting exercise.
 *
 * Copyright (C) 2009 by Cambridge Silicon Radio Ltd.
 *
 * Refer to LICENSE.txt included with this source code for details on
 * the license terms.
 *
 * ---------------------------------------------------------------------------
 */
#include "unifi_priv.h"


/*
 * Porting Notes:
 * There are two ways to support the suspend/resume system events in a driver.
 * In some operating systems these events are delivered to the OS driver
 * directly from the system. In this case, the OS driver needs to pass these
 * events to the API described in the CSR SDIO Abstration API document.
 * In Linux, and other embedded operating systems, the suspend/resume events
 * come from the SDIO driver. In this case, simply get these events in the
 * SDIO glue layer and notify the OS layer.
 *
 * In either case, typically, the events are processed by the SME.
 * Use the unifi_sys_suspend_ind() and unifi_sys_resume_ind() to pass
 * the events to the SME.
 */

/*
 * ---------------------------------------------------------------------------
 *  unifi_suspend
 *
 *      Handles a suspend request from the SDIO driver.
 *
 *  Arguments:
 *      ospriv          Pointer to OS driver context.
 *
 * ---------------------------------------------------------------------------
 */
void unifi_suspend(void *ospriv)
{
    unifi_priv_t *priv = ospriv;
    int interfaceTag=0;

    /* For powered suspend, tell the resume's wifi_on() not to reinit UniFi */
    priv->wol_suspend = (enable_wol == UNIFI_WOL_OFF) ? FALSE : TRUE;

    unifi_trace(priv, UDBG1, "unifi_suspend: wol_suspend %d, enable_wol %d",
                priv->wol_suspend, enable_wol );

    /* Stop network traffic. */
    /* need to stop all the netdevices*/
    for( interfaceTag=0;interfaceTag<CSR_WIFI_NUM_INTERFACES;interfaceTag++)
    {
        netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
        if (interfacePriv->netdev_registered == 1)
        {
            if( priv->wol_suspend ) {
                unifi_trace(priv, UDBG1, "unifi_suspend: Don't netif_carrier_off");
            } else {
                unifi_trace(priv, UDBG1, "unifi_suspend: netif_carrier_off");
                netif_carrier_off(priv->netdev[interfaceTag]);
            }
            netif_tx_stop_all_queues(priv->netdev[interfaceTag]);
        }
    }

    unifi_trace(priv, UDBG1, "unifi_suspend: suspend SME");

    sme_sys_suspend(priv);

} /* unifi_suspend() */


/*
 * ---------------------------------------------------------------------------
 *  unifi_resume
 *
 *      Handles a resume request from the SDIO driver.
 *
 *  Arguments:
 *      ospriv          Pointer to OS driver context.
 *
 * ---------------------------------------------------------------------------
 */
void unifi_resume(void *ospriv)
{
    unifi_priv_t *priv = ospriv;
    int interfaceTag=0;
    int r;
    int wol = priv->wol_suspend;

    unifi_trace(priv, UDBG1, "unifi_resume: resume SME, enable_wol=%d", enable_wol);

    /* The resume causes wifi-on which will re-enable the BH and reinstall the ISR */
    r = sme_sys_resume(priv);
    if (r) {
        unifi_error(priv, "Failed to resume UniFi\n");
    }

    /* Resume the network interfaces. For the cold resume case, this will
     * happen upon reconnection.
     */
    if (wol) {
        unifi_trace(priv, UDBG1, "unifi_resume: try to enable carrier");

        /* need to start all the netdevices*/
        for( interfaceTag=0;interfaceTag<CSR_WIFI_NUM_INTERFACES;interfaceTag++) {
            netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];

            unifi_trace(priv, UDBG1, "unifi_resume: interfaceTag %d netdev_registered %d mode %d\n",
                   interfaceTag, interfacePriv->netdev_registered, interfacePriv->interfaceMode);

            if (interfacePriv->netdev_registered == 1)
            {
                netif_carrier_on(priv->netdev[interfaceTag]);
                netif_tx_start_all_queues(priv->netdev[interfaceTag]);
            }
        }

        /* Kick the BH thread (with reason=host) to poll for data that may have
         * arrived during a powered suspend. This caters for the case where the SME
         * doesn't interact with the chip (e.g install autonomous scans) during resume.
         */
        unifi_send_signal(priv->card, NULL, 0, NULL);
    }

} /* unifi_resume() */