diff options
Diffstat (limited to 'drivers/staging/csr/sdio_events.c')
-rw-r--r-- | drivers/staging/csr/sdio_events.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/staging/csr/sdio_events.c b/drivers/staging/csr/sdio_events.c new file mode 100644 index 000000000000..6892c2e281bc --- /dev/null +++ b/drivers/staging/csr/sdio_events.c @@ -0,0 +1,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]); + } + UF_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]); + UF_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() */ + |