/* * --------------------------------------------------------------------------- * 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() */