diff options
Diffstat (limited to 'drivers/net/wireless/rtlwifi/rtl8723as/os_dep/linux/gspi_intf.c')
-rwxr-xr-x | drivers/net/wireless/rtlwifi/rtl8723as/os_dep/linux/gspi_intf.c | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtlwifi/rtl8723as/os_dep/linux/gspi_intf.c b/drivers/net/wireless/rtlwifi/rtl8723as/os_dep/linux/gspi_intf.c new file mode 100755 index 000000000000..d579b533b7d2 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rtl8723as/os_dep/linux/gspi_intf.c @@ -0,0 +1,949 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _HCI_INTF_C_ + +#include <drv_conf.h> +#include <osdep_service.h> +#include <drv_types.h> +#include <recv_osdep.h> +#include <xmit_osdep.h> +#include <rtw_version.h> + +#ifndef CONFIG_GSPI_HCI +#error "CONFIG_GSPI_HCI should be on!\n" +#endif + +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> +//#include <mach/ldo.h> +#include <asm/mach-types.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <mach/board.h> +#include <mach/hardware.h> +#include <mach/irqs.h> + +#ifdef CONFIG_RTL8723A +#include <rtl8723a_hal.h> +#include <HalPwrSeqCmd.h> +#include <Hal8723PwrSeq.h> +#endif + +#ifdef CONFIG_RTL8188E +#include <rtl8188e_hal.h> +#endif + +#include <hal_intf.h> +#include <gspi_hal.h> +#include <gspi_ops.h> + +#include <custom_gpio.h> + + +extern char* ifname; + +typedef struct _driver_priv { + int drv_registered; +} drv_priv, *pdrv_priv; + +unsigned int oob_irq; +static drv_priv drvpriv = { + +}; + +static void decide_chip_type_by_device_id(PADAPTER padapter) +{ + padapter->chip_type = NULL_CHIP_TYPE; + +#if defined(CONFIG_RTL8723A) + padapter->chip_type = RTL8723A; + padapter->HardwareType = HARDWARE_TYPE_RTL8723AS; +#elif defined(CONFIG_RTL8188E) + padapter->chip_type = RTL8188E; + padapter->HardwareType = HARDWARE_TYPE_RTL8188ES; +#endif +} + +static irqreturn_t spi_interrupt_thread(int irq, void *data) +{ + struct dvobj_priv *dvobj; + PGSPI_DATA pgspi_data; + + + dvobj = (struct dvobj_priv*)data; + pgspi_data = &dvobj->intf_data; + + //spi_int_hdl(padapter); + if (pgspi_data->priv_wq) + queue_delayed_work(pgspi_data->priv_wq, &pgspi_data->irq_work, 0); + + return IRQ_HANDLED; +} + +static u8 gspi_alloc_irq(struct dvobj_priv *dvobj) +{ + PGSPI_DATA pgspi_data; + struct spi_device *spi; + int err; + + + pgspi_data = &dvobj->intf_data; + spi = pgspi_data->func; + + err = request_irq(oob_irq, spi_interrupt_thread, + IRQF_TRIGGER_FALLING,//IRQF_TRIGGER_HIGH;//|IRQF_ONESHOT, + DRV_NAME, dvobj); + //err = request_threaded_irq(oob_irq, NULL, spi_interrupt_thread, + // IRQF_TRIGGER_FALLING, + // DRV_NAME, dvobj); + if (err < 0) { + DBG_871X("Oops: can't allocate irq %d err:%d\n", oob_irq, err); + goto exit; + } + enable_irq_wake(oob_irq); + disable_irq(oob_irq); + +exit: + return err?_FAIL:_SUCCESS; +} + +static u8 gspi_init(struct dvobj_priv *dvobj) +{ + PGSPI_DATA pgspi_data; + int err = 0; + +_func_enter_; + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+gspi_init\n")); + + if (NULL == dvobj) { + DBG_8192C(KERN_ERR "%s: driver object is NULL!\n", __func__); + err = -1; + goto exit; + } + + pgspi_data = &dvobj->intf_data; + + pgspi_data->block_transfer_len = 512; + pgspi_data->tx_block_mode = 0; + pgspi_data->rx_block_mode = 0; + +exit: + _func_exit_; + + if (err) return _FAIL; + return _SUCCESS; +} + +static void gspi_deinit(struct dvobj_priv *dvobj) +{ + PGSPI_DATA pgspi_data; + struct spi_device *spi; + int err; + + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+gspi_deinit\n")); + + if (NULL == dvobj) { + DBG_8192C(KERN_ERR "%s: driver object is NULL!\n", __FUNCTION__); + return; + } + + pgspi_data = &dvobj->intf_data; + spi = pgspi_data->func; + + if (spi) { + free_irq(oob_irq, dvobj); + } +} + +static struct dvobj_priv *gspi_dvobj_init(struct spi_device *spi) +{ + int status = _FAIL; + struct dvobj_priv *dvobj = NULL; + PGSPI_DATA pgspi; + +_func_enter_; + + dvobj = (struct dvobj_priv*)rtw_zmalloc(sizeof(*dvobj)); + if (NULL == dvobj) { + goto exit; + } + + _rtw_mutex_init(&dvobj->hw_init_mutex); + _rtw_mutex_init(&dvobj->h2c_fwcmd_mutex); + _rtw_mutex_init(&dvobj->setch_mutex); + _rtw_mutex_init(&dvobj->setbw_mutex); + dvobj->processing_dev_remove = _FALSE; + _rtw_spinlock_init(&dvobj->lock); + dvobj->macid[1] = _TRUE; //macid=1 for bc/mc stainfo + //spi init + /* This is the only SPI value that we need to set here, the rest + * comes from the board-peripherals file */ + spi->bits_per_word = 32; + spi->max_speed_hz = 48 * 1000 * 1000; + //here mode 0 and 3 all ok, + //3 can run under 48M clock when SPI_CTL4 bit14 IS_FST set to 1 + //0 can run under 24M clock, but can run under 48M when SPI_CTL4 bit14 IS_FST set to 1 and Ctl0_reg[1:0] set to 3. + spi->mode = SPI_MODE_3; + spi_setup(spi); + +#if 1 + //DBG_8192C("set spi ==========================%d \n", spi_setup(spi)); + + DBG_871X("%s, mode = %d \n", __func__, spi->mode); + DBG_871X("%s, bit_per_word = %d \n", __func__, spi->bits_per_word); + DBG_871X("%s, speed = %d \n", __func__, spi->max_speed_hz); + DBG_871X("%s, chip_select = %d \n", __func__, spi->chip_select); + DBG_871X("%s, controller_data = %d \n", __func__, *(int *)spi->controller_data); + DBG_871X("%s, irq= %d \n", __func__, oob_irq); +#endif + + spi_set_drvdata(spi, dvobj); + pgspi = &dvobj->intf_data; + pgspi->func = spi; + + if (gspi_init(dvobj) != _SUCCESS) { + DBG_871X("%s: initialize GSPI Failed!\n", __FUNCTION__); + goto free_dvobj; + } + rtw_reset_continual_io_error(dvobj); + status = _SUCCESS; + +free_dvobj: + if (status != _SUCCESS && dvobj) { + spi_set_drvdata(spi, NULL); + _rtw_spinlock_free(&dvobj->lock); + _rtw_mutex_free(&dvobj->hw_init_mutex); + _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); + _rtw_mutex_free(&dvobj->setch_mutex); + _rtw_mutex_free(&dvobj->setbw_mutex); + rtw_mfree((u8*)dvobj, sizeof(*dvobj)); + dvobj = NULL; + } + +exit: +_func_exit_; + + return dvobj; +} + +static void gspi_dvobj_deinit(struct spi_device *spi) +{ + struct dvobj_priv *dvobj = spi_get_drvdata(spi); + +_func_enter_; + + spi_set_drvdata(spi, NULL); + if (dvobj) { + gspi_deinit(dvobj); + _rtw_spinlock_free(&dvobj->lock); + _rtw_mutex_free(&dvobj->hw_init_mutex); + _rtw_mutex_free(&dvobj->h2c_fwcmd_mutex); + _rtw_mutex_free(&dvobj->setch_mutex); + _rtw_mutex_free(&dvobj->setbw_mutex); + rtw_mfree((u8*)dvobj, sizeof(*dvobj)); + } + +_func_exit_; +} + +static void spi_irq_work(void *data) +{ + struct delayed_work *dwork; + PGSPI_DATA pgspi; + struct dvobj_priv *dvobj; + + + dwork = container_of(data, struct delayed_work, work); + pgspi = container_of(dwork, GSPI_DATA, irq_work); + + dvobj = spi_get_drvdata(pgspi->func); + if (!dvobj->if1) { + DBG_871X("%s if1 == NULL !!\n", __FUNCTION__); + return; + } + spi_int_hdl(dvobj->if1); +} + +static void gspi_intf_start(PADAPTER padapter) +{ + PGSPI_DATA pgspi; + + + if (padapter == NULL) { + DBG_871X(KERN_ERR "%s: padapter is NULL!\n", __FUNCTION__); + return; + } + + pgspi = &adapter_to_dvobj(padapter)->intf_data; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) + pgspi->priv_wq = alloc_workqueue("spi_wq", 0, 0); +#else + pgspi->priv_wq = create_workqueue("spi_wq"); +#endif + INIT_DELAYED_WORK(&pgspi->irq_work, (void*)spi_irq_work); + + enable_irq(oob_irq); + //hal dep + rtw_hal_enable_interrupt(padapter); +} + +static void gspi_intf_stop(PADAPTER padapter) +{ + PGSPI_DATA pgspi; + + + if (padapter == NULL) { + DBG_871X(KERN_ERR "%s: padapter is NULL!\n", __FUNCTION__); + return; + } + + pgspi = &adapter_to_dvobj(padapter)->intf_data; + + if (pgspi->priv_wq) { + cancel_delayed_work_sync(&pgspi->irq_work); + flush_workqueue(pgspi->priv_wq); + destroy_workqueue(pgspi->priv_wq); + pgspi->priv_wq = NULL; + } + + //hal dep + rtw_hal_disable_interrupt(padapter); + disable_irq(oob_irq); +} + +/* + * Do deinit job corresponding to netdev_open() + */ +void rtw_dev_unload(PADAPTER padapter) +{ + struct net_device *pnetdev = (struct net_device*)padapter->pnetdev; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_unload\n")); + + padapter->bDriverStopped = _TRUE; + #ifdef CONFIG_XMIT_ACK + if (padapter->xmitpriv.ack_tx) + rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); + #endif + + if (padapter->bup == _TRUE) + { +#if 0 + if (padapter->intf_stop) + padapter->intf_stop(padapter); +#else + gspi_intf_stop(padapter); +#endif + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop intf complete!\n")); + + if (!adapter_to_pwrctl(padapter)->bInternalAutoSuspend) + rtw_stop_drv_threads(padapter); + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: stop thread complete!\n")); + + if (padapter->bSurpriseRemoved == _FALSE) + { +#ifdef CONFIG_WOWLAN + if (adapter_to_pwrctl(padapter)->bSupportRemoteWakeup == _TRUE) { + DBG_871X("%s bSupportRemoteWakeup==_TRUE do not run rtw_hal_deinit()\n",__FUNCTION__); + } + else +#endif + { + rtw_hal_deinit(padapter); + } + padapter->bSurpriseRemoved = _TRUE; + } + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("@ rtw_dev_unload: deinit hal complelt!\n")); + + padapter->bup = _FALSE; + } + else { + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("rtw_dev_unload: bup==_FALSE\n")); + } + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_unload\n")); +} + +static PADAPTER rtw_gspi_if1_init(struct dvobj_priv *dvobj) +{ + int status = _FAIL; + struct net_device *pnetdev; + PADAPTER padapter = NULL; + + + padapter = (PADAPTER)rtw_zvmalloc(sizeof(*padapter)); + if (NULL == padapter) { + goto exit; + } + + padapter->dvobj = dvobj; + dvobj->if1 = padapter; + + padapter->bDriverStopped = _TRUE; + + dvobj->padapters[dvobj->iface_nums++] = padapter; + padapter->iface_id = IFACE_ID0; + +#if defined(CONFIG_CONCURRENT_MODE) || defined(CONFIG_DUALMAC_CONCURRENT) + //set adapter_type/iface type for primary padapter + padapter->isprimary = _TRUE; + padapter->adapter_type = PRIMARY_ADAPTER; + #ifndef CONFIG_HWPORT_SWAP + padapter->iface_type = IFACE_PORT0; + #else + padapter->iface_type = IFACE_PORT1; + #endif +#endif + + padapter->interface_type = RTW_GSPI; + decide_chip_type_by_device_id(padapter); + + //3 1. init network device data + pnetdev = rtw_init_netdev(padapter); + if (!pnetdev) + goto free_adapter; + + SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); + +#ifdef CONFIG_IOCTL_CFG80211 + rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)); +#endif + + + //3 3. init driver special setting, interface, OS and hardware relative + //4 3.1 set hardware operation functions + hal_set_hal_ops(padapter); + + + //3 5. initialize Chip version + padapter->intf_start = &gspi_intf_start; + padapter->intf_stop = &gspi_intf_stop; + + if (rtw_init_io_priv(padapter, spi_set_intf_ops) == _FAIL) + { + RT_TRACE(_module_hci_intfs_c_, _drv_err_, + ("rtw_drv_init: Can't init io_priv\n")); + goto free_hal_data; + } + + { + u32 ret = 0; + DBG_8192C("read start:\n"); + //spi_write8_endian(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x01, 1); + rtw_write8(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x03); + ret = rtw_read32(padapter, SPI_LOCAL_OFFSET | 0xF0); + DBG_8192C("read end 0xF0 read32:%x:\n", ret); + DBG_8192C("read end 0xF0 read8:%x:\n", rtw_read8(padapter, SPI_LOCAL_OFFSET | 0xF0)); + + } + + rtw_hal_read_chip_version(padapter); + + rtw_hal_chip_configure(padapter); + + + //3 6. read efuse/eeprom data + rtw_hal_read_chip_info(padapter); + + + //3 7. init driver common data + if (rtw_init_drv_sw(padapter) == _FAIL) { + RT_TRACE(_module_hci_intfs_c_, _drv_err_, + ("rtw_drv_init: Initialize driver software resource Failed!\n")); + goto free_hal_data; + } + + + //3 8. get WLan MAC address + // set mac addr + rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); + rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr, padapter->eeprompriv.mac_addr); + + rtw_hal_disable_interrupt(padapter); + + DBG_871X("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" + ,padapter->bDriverStopped + ,padapter->bSurpriseRemoved + ,padapter->bup + ,padapter->hw_init_completed + ); + + status = _SUCCESS; + +free_hal_data: + if (status != _SUCCESS && padapter->HalData) + rtw_mfree(padapter->HalData, sizeof(*(padapter->HalData))); + +free_wdev: + if (status != _SUCCESS) { + #ifdef CONFIG_IOCTL_CFG80211 + rtw_wdev_unregister(padapter->rtw_wdev); + rtw_wdev_free(padapter->rtw_wdev); + #endif + } + +free_adapter: + if (status != _SUCCESS) { + if (pnetdev) + rtw_free_netdev(pnetdev); + else if (padapter) + rtw_vmfree((u8*)padapter, sizeof(*padapter)); + padapter = NULL; + } + +exit: + return padapter; +} + +static void rtw_gspi_if1_deinit(PADAPTER if1) +{ + struct net_device *pnetdev = if1->pnetdev; + struct mlme_priv *pmlmepriv = &if1->mlmepriv; + + if (check_fwstate(pmlmepriv, _FW_LINKED)) + rtw_disassoc_cmd(if1, 0, _FALSE); + +#ifdef CONFIG_AP_MODE + free_mlme_ap_info(if1); + #ifdef CONFIG_HOSTAPD_MLME + hostapd_mode_unload(if1); +#endif +#endif +/* + if(if1->DriverState != DRIVER_DISAPPEAR) { + if(pnetdev) { + unregister_netdev(pnetdev); //will call netdev_close() + rtw_proc_remove_one(pnetdev); + } + } +*/ + rtw_cancel_all_timer(if1); + + rtw_dev_unload(if1); + DBG_871X("+r871xu_dev_remove, hw_init_completed=%d\n", if1->hw_init_completed); + + rtw_handle_dualmac(if1, 0); + +#ifdef CONFIG_IOCTL_CFG80211 + if (if1->rtw_wdev) + { + //rtw_wdev_unregister(if1->rtw_wdev); + rtw_wdev_free(if1->rtw_wdev); + } +#endif + + rtw_free_drv_sw(if1); + + if(pnetdev) + rtw_free_netdev(pnetdev); +} + +/* + * drv_init() - a device potentially for us + * + * notes: drv_init() is called when the bus driver has located a card for us to support. + * We accept the new device by returning 0. + */ +static int /*__devinit*/ rtw_drv_probe(struct spi_device *spi) +{ + int status = _FAIL; + struct dvobj_priv *dvobj; + struct net_device *pnetdev; + PADAPTER if1 = NULL, if2 = NULL; + + + DBG_8192C("RTW: %s line:%d", __FUNCTION__, __LINE__); + + if ((dvobj = gspi_dvobj_init(spi)) == NULL) { + DBG_871X("%s: Initialize device object priv Failed!\n", __FUNCTION__); + goto exit; + } + + if ((if1 = rtw_gspi_if1_init(dvobj)) == NULL) { + DBG_871X("rtw_init_primary_adapter Failed!\n"); + goto free_dvobj; + } + +#ifdef CONFIG_CONCURRENT_MODE + if ((if2 = rtw_drv_if2_init(if1, NULL, spi_set_intf_ops)) == NULL) { + goto free_if1; + } +#endif + + //dev_alloc_name && register_netdev + if((status = rtw_drv_register_netdev(if1)) != _SUCCESS) { + goto free_if2; + } + +#ifdef CONFIG_HOSTAPD_MLME + hostapd_mode_init(if1); +#endif + +#ifdef CONFIG_PLATFORM_RTD2880B + DBG_871X("wlan link up\n"); + rtd2885_wlan_netlink_sendMsg("linkup", "8712"); +#endif + +#ifdef RTK_DMP_PLATFORM + rtw_proc_init_one(if1->pnetdev); +#endif + + if (gspi_alloc_irq(dvobj) != _SUCCESS) + goto free_if2; + +#ifdef CONFIG_GLOBAL_UI_PID + if(ui_pid[1]!=0) { + DBG_871X("ui_pid[1]:%d\n",ui_pid[1]); + rtw_signal_process(ui_pid[1], SIGUSR2); + } +#endif + + RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-871x_drv - drv_init, success!\n")); + + status = _SUCCESS; + +free_if2: + if (status != _SUCCESS && if2) { + #ifdef CONFIG_CONCURRENT_MODE + rtw_drv_if2_stop(if2); + rtw_drv_if2_free(if2); + #endif + } + +free_if1: + if (status != _SUCCESS && if1) { + rtw_gspi_if1_deinit(if1); + } + +free_dvobj: + if (status != _SUCCESS) + gspi_dvobj_deinit(spi); + +exit: + return status == _SUCCESS?0:-ENODEV; +} +extern void rtw_unregister_netdevs(struct dvobj_priv *dvobj); +static int /*__devexit*/ rtw_dev_remove(struct spi_device *spi) +{ + struct dvobj_priv *dvobj = spi_get_drvdata(spi); + PADAPTER padapter = dvobj->if1; + +_func_enter_; + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n")); + + dvobj->processing_dev_remove = _TRUE; + rtw_unregister_netdevs(dvobj); + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) + rtw_unregister_early_suspend(dvobj_to_pwrctl(dvobj)); +#endif + + rtw_pm_set_ips(padapter, IPS_NONE); + rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); + + LeaveAllPowerSaveMode(padapter); + +#ifdef CONFIG_CONCURRENT_MODE + rtw_drv_if2_stop(dvobj->if2); +#endif + + rtw_gspi_if1_deinit(padapter); + +#ifdef CONFIG_CONCURRENT_MODE + rtw_drv_if2_free(dvobj->if2); +#endif + + gspi_dvobj_deinit(spi); + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n")); + +_func_exit_; + + return 0; +} + +static int rtw_gspi_suspend(struct spi_device *spi, pm_message_t mesg) +{ + struct dvobj_priv *dvobj = spi_get_drvdata(spi); + PADAPTER padapter = dvobj->if1; + struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct net_device *pnetdev = padapter->pnetdev; + int ret = 0; + + u32 start_time = rtw_get_current_time(); + + _func_enter_; + + DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); + + pwrpriv->bInSuspend = _TRUE; + + while (pwrpriv->bips_processing == _TRUE) + rtw_msleep_os(1); + + if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved)) + { + DBG_871X("%s bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", __FUNCTION__ + ,padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved); + goto exit; + } + + rtw_cancel_all_timer(padapter); + LeaveAllPowerSaveMode(padapter); + + //padapter->net_closed = _TRUE; + //s1. + if(pnetdev) + { + netif_carrier_off(pnetdev); + rtw_netif_stop_queue(pnetdev); + } +#ifdef CONFIG_WOWLAN + pwrpriv->bSupportRemoteWakeup=_TRUE; +#else + //s2. + rtw_disassoc_cmd(padapter, 0, _FALSE); +#endif + +#ifdef CONFIG_LAYER2_ROAMING_RESUME + if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) ) + { + DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__, + pmlmepriv->cur_network.network.Ssid.Ssid, + MAC_ARG(pmlmepriv->cur_network.network.MacAddress), + pmlmepriv->cur_network.network.Ssid.SsidLength, + pmlmepriv->assoc_ssid.SsidLength); + + rtw_set_roaming(padapter, 1); + } +#endif + + //s2-2. indicate disconnect to os + rtw_indicate_disconnect(padapter); + //s2-3. + rtw_free_assoc_resources(padapter, 1); + + //s2-4. + rtw_free_network_queue(padapter, _TRUE); + + rtw_led_control(padapter, LED_CTL_POWER_OFF); + + rtw_dev_unload(padapter); + + if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) + rtw_indicate_scan_done(padapter, 1); + + if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) + rtw_indicate_disconnect(padapter); + + // interface deinit + gspi_deinit(dvobj); + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("%s: deinit GSPI complete!\n", __FUNCTION__)); + + rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_OFF); + rtw_mdelay_os(1); +exit: + DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ + , ret, rtw_get_passing_time_ms(start_time)); + + _func_exit_; + return ret; +} + +extern int pm_netdev_open(struct net_device *pnetdev,u8 bnormal); +int rtw_resume_process(_adapter *padapter) +{ + struct net_device *pnetdev; + struct pwrctrl_priv *pwrpriv; + u8 is_pwrlock_hold_by_caller; + u8 is_directly_called_by_auto_resume; + int ret = 0; + u32 start_time = rtw_get_current_time(); + + _func_enter_; + + DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); + + rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_ON); + rtw_mdelay_os(1); + + { + u32 ret = 0; + DBG_8192C("read start:\n"); + //spi_write8_endian(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x01, 1); + rtw_write8(padapter, SPI_LOCAL_OFFSET | 0xF0, 0x03); + ret = rtw_read32(padapter, SPI_LOCAL_OFFSET | 0xF0); + DBG_8192C("read end 0xF0 read32:%x:\n", ret); + DBG_8192C("read end 0xF0 read8:%x:\n", rtw_read8(padapter, SPI_LOCAL_OFFSET | 0xF0)); + + } + + if (padapter) { + pnetdev = padapter->pnetdev; + pwrpriv = adapter_to_pwrctl(padapter); + } else { + ret = -1; + goto exit; + } + + // interface init + if (gspi_init(adapter_to_dvobj(padapter)) != _SUCCESS) + { + ret = -1; + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: initialize SDIO Failed!!\n", __FUNCTION__)); + goto exit; + } + rtw_hal_disable_interrupt(padapter); + if (gspi_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) + { + ret = -1; + RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("%s: gspi_alloc_irq Failed!!\n", __FUNCTION__)); + goto exit; + } + + rtw_reset_drv_sw(padapter); + pwrpriv->bkeepfwalive = _FALSE; + + DBG_871X("bkeepfwalive(%x)\n",pwrpriv->bkeepfwalive); + if(pm_netdev_open(pnetdev,_TRUE) != 0) { + ret = -1; + goto exit; + } + + netif_device_attach(pnetdev); + netif_carrier_on(pnetdev); + + if( padapter->pid[1]!=0) { + DBG_871X("pid[1]:%d\n",padapter->pid[1]); + rtw_signal_process(padapter->pid[1], SIGUSR2); + } + + #ifdef CONFIG_LAYER2_ROAMING_RESUME + rtw_roaming(padapter, NULL); + #endif + + #ifdef CONFIG_RESUME_IN_WORKQUEUE + rtw_unlock_suspend(); + #endif //CONFIG_RESUME_IN_WORKQUEUE + +exit: + pwrpriv->bInSuspend = _FALSE; + DBG_871X("<=== %s return %d.............. in %dms\n", __FUNCTION__ + , ret, rtw_get_passing_time_ms(start_time)); + + _func_exit_; + + return ret; +} + +static int rtw_gspi_resume(struct spi_device *spi) +{ + struct dvobj_priv *dvobj = spi_get_drvdata(spi); + PADAPTER padapter = dvobj->if1; + struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); + int ret = 0; + + + DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); + + if(pwrpriv->bInternalAutoSuspend ){ + ret = rtw_resume_process(padapter); + } else { +#ifdef CONFIG_RESUME_IN_WORKQUEUE + rtw_resume_in_workqueue(pwrpriv); +#else + if(rtw_is_earlysuspend_registered(pwrpriv)) { + /* jeff: bypass resume here, do in late_resume */ + rtw_set_do_late_resume(pwrpriv, _TRUE); + } else { + ret = rtw_resume_process(padapter); + } +#endif /* CONFIG_RESUME_IN_WORKQUEUE */ + } + + DBG_871X("<======== %s return %d\n", __FUNCTION__, ret); + return ret; + +} + + +static struct spi_driver rtw_spi_drv = { + .probe = rtw_drv_probe, + .remove = rtw_dev_remove, + .suspend = rtw_gspi_suspend, + .resume = rtw_gspi_resume, + .driver = { + .name = "wlan_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + } + +}; + +static int __init rtw_drv_entry(void) +{ + int ret; + + + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_drv_entry\n")); + DBG_8192C("RTW: rtw_drv_entry enter\n"); + + rtw_suspend_lock_init(); + + drvpriv.drv_registered = _TRUE; + + rtw_wifi_gpio_init(); + rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_ON); + ret = spi_register_driver(&rtw_spi_drv); + + DBG_8192C("RTW: rtw_drv_entry exit %d\n", ret); + + return 0; +} + +static void __exit rtw_drv_halt(void) +{ + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_drv_halt\n")); + DBG_8192C("RTW: rtw_drv_halt enter\n"); + + drvpriv.drv_registered = _FALSE; + + spi_unregister_driver(&rtw_spi_drv); + + + rtw_wifi_gpio_wlan_ctrl(WLAN_PWDN_OFF); + rtw_wifi_gpio_deinit(); + + rtw_suspend_lock_uninit(); + DBG_8192C("RTW: rtw_drv_halt enter\n"); + RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_drv_halt\n")); + + rtw_mstat_dump(); +} +module_init(rtw_drv_entry); +module_exit(rtw_drv_halt); |