From e09b41010ba33a20a87472ee821fa407a5b8da36 Mon Sep 17 00:00:00 2001 From: José Pekkarinen Date: Mon, 11 Apr 2016 10:41:07 +0300 Subject: These changes are the raw update to linux-4.4.6-rt14. Kernel sources are taken from kernel.org, and rt patch from the rt wiki download page. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen --- kernel/drivers/staging/wilc1000/Kconfig | 75 + kernel/drivers/staging/wilc1000/Makefile | 28 + kernel/drivers/staging/wilc1000/TODO | 14 + kernel/drivers/staging/wilc1000/coreconfigurator.c | 633 +++ kernel/drivers/staging/wilc1000/coreconfigurator.h | 142 + kernel/drivers/staging/wilc1000/host_interface.c | 5005 ++++++++++++++++++++ kernel/drivers/staging/wilc1000/host_interface.h | 1130 +++++ kernel/drivers/staging/wilc1000/linux_mon.c | 391 ++ kernel/drivers/staging/wilc1000/linux_wlan.c | 1832 +++++++ .../drivers/staging/wilc1000/linux_wlan_common.h | 170 + kernel/drivers/staging/wilc1000/linux_wlan_sdio.c | 251 + kernel/drivers/staging/wilc1000/linux_wlan_sdio.h | 14 + kernel/drivers/staging/wilc1000/linux_wlan_spi.c | 409 ++ kernel/drivers/staging/wilc1000/linux_wlan_spi.h | 14 + kernel/drivers/staging/wilc1000/wilc_debugfs.c | 181 + kernel/drivers/staging/wilc1000/wilc_msgqueue.c | 178 + kernel/drivers/staging/wilc1000/wilc_msgqueue.h | 94 + kernel/drivers/staging/wilc1000/wilc_sdio.c | 1014 ++++ kernel/drivers/staging/wilc1000/wilc_spi.c | 1276 +++++ .../staging/wilc1000/wilc_wfi_cfgoperations.c | 3535 ++++++++++++++ .../staging/wilc1000/wilc_wfi_cfgoperations.h | 109 + .../drivers/staging/wilc1000/wilc_wfi_netdevice.h | 221 + kernel/drivers/staging/wilc1000/wilc_wlan.c | 2070 ++++++++ kernel/drivers/staging/wilc1000/wilc_wlan.h | 312 ++ kernel/drivers/staging/wilc1000/wilc_wlan_cfg.c | 566 +++ kernel/drivers/staging/wilc1000/wilc_wlan_cfg.h | 39 + kernel/drivers/staging/wilc1000/wilc_wlan_if.h | 946 ++++ 27 files changed, 20649 insertions(+) create mode 100644 kernel/drivers/staging/wilc1000/Kconfig create mode 100644 kernel/drivers/staging/wilc1000/Makefile create mode 100644 kernel/drivers/staging/wilc1000/TODO create mode 100644 kernel/drivers/staging/wilc1000/coreconfigurator.c create mode 100644 kernel/drivers/staging/wilc1000/coreconfigurator.h create mode 100644 kernel/drivers/staging/wilc1000/host_interface.c create mode 100644 kernel/drivers/staging/wilc1000/host_interface.h create mode 100644 kernel/drivers/staging/wilc1000/linux_mon.c create mode 100644 kernel/drivers/staging/wilc1000/linux_wlan.c create mode 100644 kernel/drivers/staging/wilc1000/linux_wlan_common.h create mode 100644 kernel/drivers/staging/wilc1000/linux_wlan_sdio.c create mode 100644 kernel/drivers/staging/wilc1000/linux_wlan_sdio.h create mode 100644 kernel/drivers/staging/wilc1000/linux_wlan_spi.c create mode 100644 kernel/drivers/staging/wilc1000/linux_wlan_spi.h create mode 100644 kernel/drivers/staging/wilc1000/wilc_debugfs.c create mode 100644 kernel/drivers/staging/wilc1000/wilc_msgqueue.c create mode 100644 kernel/drivers/staging/wilc1000/wilc_msgqueue.h create mode 100644 kernel/drivers/staging/wilc1000/wilc_sdio.c create mode 100644 kernel/drivers/staging/wilc1000/wilc_spi.c create mode 100644 kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c create mode 100644 kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h create mode 100644 kernel/drivers/staging/wilc1000/wilc_wfi_netdevice.h create mode 100644 kernel/drivers/staging/wilc1000/wilc_wlan.c create mode 100644 kernel/drivers/staging/wilc1000/wilc_wlan.h create mode 100644 kernel/drivers/staging/wilc1000/wilc_wlan_cfg.c create mode 100644 kernel/drivers/staging/wilc1000/wilc_wlan_cfg.h create mode 100644 kernel/drivers/staging/wilc1000/wilc_wlan_if.h (limited to 'kernel/drivers/staging/wilc1000') diff --git a/kernel/drivers/staging/wilc1000/Kconfig b/kernel/drivers/staging/wilc1000/Kconfig new file mode 100644 index 000000000..ee51b4278 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/Kconfig @@ -0,0 +1,75 @@ +config WILC1000_DRIVER + bool "WILC1000 support (WiFi only)" + depends on CFG80211 && WEXT_CORE && INET + ---help--- + This module only support IEEE 802.11n WiFi. + +if WILC1000_DRIVER + +config WILC1000 + tristate + +choice + prompt "Memory Allocation" + default WILC1000_PREALLOCATE_AT_LOADING_DRIVER + +config WILC1000_PREALLOCATE_AT_LOADING_DRIVER + bool "Preallocate memory at loading driver" + ---help--- + This choice supports static allocation of the memory + for the receive buffer. The driver will allocate the RX buffer + during initial time. The driver will also free the buffer + by calling network device stop. + +config WILC1000_DYNAMICALLY_ALLOCATE_MEMROY + bool "Dynamically allocate memory in real time" + ---help--- + This choice supports dynamic allocation of the memory + for the receive buffer. The driver will allocate the RX buffer + when it is required. +endchoice + +choice + prompt "Bus Type" + default WILC1000_SDIO + +config WILC1000_SDIO + bool "SDIO support" + depends on MMC + select WILC1000 + ---help--- + This module adds support for the SDIO interface of adapters using + WILC1000 chipset. The Atmel WILC1000 SDIO is a full speed interface. + It meets SDIO card specification version 2.0. The interface supports + the 1-bit/4-bit SD transfer mode at the clock range of 0-50 MHz. + The host can use this interface to read and write from any register + within the chip as well as configure the WILC1000 for data DMA. + To use this interface, pin9 (SDIO_SPI_CFG) must be grounded. Select + this if your platform is using the SDIO bus. + +config WILC1000_SPI + depends on SPI + select WILC1000 + bool "SPI support" + ---help--- + This module adds support for the SPI interface of adapters using + WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral + Interface (SPI) that operates as a SPI slave. This SPI interface can + be used for control and for serial I/O of 802.11 data. The SPI is a + full-duplex slave synchronous serial interface that is available + immediately following reset when pin 9 (SDIO_SPI_CFG) is tied to + VDDIO. Select this if your platform is using the SPI bus. +endchoice + +config WILC1000_HW_OOB_INTR + bool "Use out of band interrupt" + depends on WILC1000_SDIO + default n + ---help--- + This option enables out-of-band interrupt support for the WILC1000 + chipset. This OOB interrupt is intended to provide a faster interrupt + mechanism for SDIO host controllers that don't support SDIO interrupt. + Select this option If the SDIO host controller in your platform + doesn't support SDIO time devision interrupt. + +endif diff --git a/kernel/drivers/staging/wilc1000/Makefile b/kernel/drivers/staging/wilc1000/Makefile new file mode 100644 index 000000000..64c2f1b83 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/Makefile @@ -0,0 +1,28 @@ +obj-$(CONFIG_WILC1000) += wilc1000.o + +ccflags-$(CONFIG_WILC1000_SDIO) += -DWILC_SDIO -DCOMPLEMENT_BOOT +ccflags-$(CONFIG_WILC1000_HW_OOB_INTR) += -DWILC_SDIO_IRQ_GPIO +ccflags-$(CONFIG_WILC1000_SPI) += -DWILC_SPI + +ccflags-y += -DSTA_FIRMWARE=\"atmel/wilc1000_fw.bin\" \ + -DAP_FIRMWARE=\"atmel/wilc1000_ap_fw.bin\" \ + -DP2P_CONCURRENCY_FIRMWARE=\"atmel/wilc1000_p2p_fw.bin\" + +ccflags-y += -I$(src)/ -D__CHECK_ENDIAN__ -DWILC_ASIC_A0 \ + -Wno-unused-function -DWILC_DEBUGFS +#ccflags-y += -DTCP_ACK_FILTER + +ccflags-$(CONFIG_WILC1000_PREALLOCATE_AT_LOADING_DRIVER) += -DMEMORY_STATIC \ + -DWILC_PREALLOC_AT_INSMOD + +ccflags-$(CONFIG_WILC1000_DYNAMICALLY_ALLOCATE_MEMROY) += -DWILC_NORMAL_ALLOC + + +wilc1000-objs := wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \ + wilc_msgqueue.o \ + coreconfigurator.o host_interface.o \ + wilc_sdio.o wilc_spi.o wilc_wlan_cfg.o wilc_debugfs.o \ + wilc_wlan.o + +wilc1000-$(CONFIG_WILC1000_SDIO) += linux_wlan_sdio.o +wilc1000-$(CONFIG_WILC1000_SPI) += linux_wlan_spi.o diff --git a/kernel/drivers/staging/wilc1000/TODO b/kernel/drivers/staging/wilc1000/TODO new file mode 100644 index 000000000..95199d80a --- /dev/null +++ b/kernel/drivers/staging/wilc1000/TODO @@ -0,0 +1,14 @@ +TODO: +- remove the defined feature as kernel versions +- remove OS wrapper functions +- remove custom debug and tracing functions +- rework comments and function headers(also coding style) +- replace all semaphores with mutexes or completions +- make spi and sdio components coexist in one build +- turn compile-time platform configuration (BEAGLE_BOARD, + PANDA_BOARD, PLAT_WMS8304, PLAT_RKXXXX, CUSTOMER_PLATFORM, ...) + into run-time options that are read from DT +- support soft-ap and p2p mode +- support resume/suspend function +- replace SIOCDEVPRIVATE commands with generic API functions +- use wext-core handling instead of private SIOCSIWPRIV implementation diff --git a/kernel/drivers/staging/wilc1000/coreconfigurator.c b/kernel/drivers/staging/wilc1000/coreconfigurator.c new file mode 100644 index 000000000..9568bdb63 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/coreconfigurator.c @@ -0,0 +1,633 @@ + +/*! + * @file coreconfigurator.c + * @brief + * @author + * @sa coreconfigurator.h + * @date 1 Mar 2012 + * @version 1.0 + */ + +#include "coreconfigurator.h" +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" +#include +#include +#define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \ + BEACON_INTERVAL_LEN + CAP_INFO_LEN) + +/* Basic Frame Type Codes (2-bit) */ +enum basic_frame_type { + FRAME_TYPE_CONTROL = 0x04, + FRAME_TYPE_DATA = 0x08, + FRAME_TYPE_MANAGEMENT = 0x00, + FRAME_TYPE_RESERVED = 0x0C, + FRAME_TYPE_FORCE_32BIT = 0xFFFFFFFF +}; + +/* Frame Type and Subtype Codes (6-bit) */ +enum sub_frame_type { + ASSOC_REQ = 0x00, + ASSOC_RSP = 0x10, + REASSOC_REQ = 0x20, + REASSOC_RSP = 0x30, + PROBE_REQ = 0x40, + PROBE_RSP = 0x50, + BEACON = 0x80, + ATIM = 0x90, + DISASOC = 0xA0, + AUTH = 0xB0, + DEAUTH = 0xC0, + ACTION = 0xD0, + PS_POLL = 0xA4, + RTS = 0xB4, + CTS = 0xC4, + ACK = 0xD4, + CFEND = 0xE4, + CFEND_ACK = 0xF4, + DATA = 0x08, + DATA_ACK = 0x18, + DATA_POLL = 0x28, + DATA_POLL_ACK = 0x38, + NULL_FRAME = 0x48, + CFACK = 0x58, + CFPOLL = 0x68, + CFPOLL_ACK = 0x78, + QOS_DATA = 0x88, + QOS_DATA_ACK = 0x98, + QOS_DATA_POLL = 0xA8, + QOS_DATA_POLL_ACK = 0xB8, + QOS_NULL_FRAME = 0xC8, + QOS_CFPOLL = 0xE8, + QOS_CFPOLL_ACK = 0xF8, + BLOCKACK_REQ = 0x84, + BLOCKACK = 0x94, + FRAME_SUBTYPE_FORCE_32BIT = 0xFFFFFFFF +}; + +/* Element ID of various Information Elements */ +enum info_element_id { + ISSID = 0, /* Service Set Identifier */ + ISUPRATES = 1, /* Supported Rates */ + IFHPARMS = 2, /* FH parameter set */ + IDSPARMS = 3, /* DS parameter set */ + ICFPARMS = 4, /* CF parameter set */ + ITIM = 5, /* Traffic Information Map */ + IIBPARMS = 6, /* IBSS parameter set */ + ICOUNTRY = 7, /* Country element */ + IEDCAPARAMS = 12, /* EDCA parameter set */ + ITSPEC = 13, /* Traffic Specification */ + ITCLAS = 14, /* Traffic Classification */ + ISCHED = 15, /* Schedule */ + ICTEXT = 16, /* Challenge Text */ + IPOWERCONSTRAINT = 32, /* Power Constraint */ + IPOWERCAPABILITY = 33, /* Power Capability */ + ITPCREQUEST = 34, /* TPC Request */ + ITPCREPORT = 35, /* TPC Report */ + ISUPCHANNEL = 36, /* Supported channel list */ + ICHSWANNOUNC = 37, /* Channel Switch Announcement */ + IMEASUREMENTREQUEST = 38, /* Measurement request */ + IMEASUREMENTREPORT = 39, /* Measurement report */ + IQUIET = 40, /* Quiet element Info */ + IIBSSDFS = 41, /* IBSS DFS */ + IERPINFO = 42, /* ERP Information */ + ITSDELAY = 43, /* TS Delay */ + ITCLASPROCESS = 44, /* TCLAS Processing */ + IHTCAP = 45, /* HT Capabilities */ + IQOSCAP = 46, /* QoS Capability */ + IRSNELEMENT = 48, /* RSN Information Element */ + IEXSUPRATES = 50, /* Extended Supported Rates */ + IEXCHSWANNOUNC = 60, /* Extended Ch Switch Announcement*/ + IHTOPERATION = 61, /* HT Information */ + ISECCHOFF = 62, /* Secondary Channel Offeset */ + I2040COEX = 72, /* 20/40 Coexistence IE */ + I2040INTOLCHREPORT = 73, /* 20/40 Intolerant channel report*/ + IOBSSSCAN = 74, /* OBSS Scan parameters */ + IEXTCAP = 127, /* Extended capability */ + IWMM = 221, /* WMM parameters */ + IWPAELEMENT = 221, /* WPA Information Element */ + INFOELEM_ID_FORCE_32BIT = 0xFFFFFFFF +}; + +/* This function extracts the beacon period field from the beacon or probe */ +/* response frame. */ +static inline u16 get_beacon_period(u8 *data) +{ + u16 bcn_per; + + bcn_per = data[0]; + bcn_per |= (data[1] << 8); + + return bcn_per; +} + +static inline u32 get_beacon_timestamp_lo(u8 *data) +{ + u32 time_stamp = 0; + u32 index = MAC_HDR_LEN; + + time_stamp |= data[index++]; + time_stamp |= (data[index++] << 8); + time_stamp |= (data[index++] << 16); + time_stamp |= (data[index] << 24); + + return time_stamp; +} + +static inline u32 get_beacon_timestamp_hi(u8 *data) +{ + u32 time_stamp = 0; + u32 index = (MAC_HDR_LEN + 4); + + time_stamp |= data[index++]; + time_stamp |= (data[index++] << 8); + time_stamp |= (data[index++] << 16); + time_stamp |= (data[index] << 24); + + return time_stamp; +} + +/* This function extracts the 'frame type and sub type' bits from the MAC */ +/* header of the input frame. */ +/* Returns the value in the LSB of the returned value. */ +static inline enum sub_frame_type get_sub_type(u8 *header) +{ + return ((enum sub_frame_type)(header[0] & 0xFC)); +} + +/* This function extracts the 'to ds' bit from the MAC header of the input */ +/* frame. */ +/* Returns the value in the LSB of the returned value. */ +static inline u8 get_to_ds(u8 *header) +{ + return (header[1] & 0x01); +} + +/* This function extracts the 'from ds' bit from the MAC header of the input */ +/* frame. */ +/* Returns the value in the LSB of the returned value. */ +static inline u8 get_from_ds(u8 *header) +{ + return ((header[1] & 0x02) >> 1); +} + +/* This function extracts the MAC Address in 'address1' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +static inline void get_address1(u8 *pu8msa, u8 *addr) +{ + memcpy(addr, pu8msa + 4, 6); +} + +/* This function extracts the MAC Address in 'address2' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +static inline void get_address2(u8 *pu8msa, u8 *addr) +{ + memcpy(addr, pu8msa + 10, 6); +} + +/* This function extracts the MAC Address in 'address3' field of the MAC */ +/* header and updates the MAC Address in the allocated 'addr' variable. */ +static inline void get_address3(u8 *pu8msa, u8 *addr) +{ + memcpy(addr, pu8msa + 16, 6); +} + +/* This function extracts the BSSID from the incoming WLAN packet based on */ +/* the 'from ds' bit, and updates the MAC Address in the allocated 'addr' */ +/* variable. */ +static inline void get_BSSID(u8 *data, u8 *bssid) +{ + if (get_from_ds(data) == 1) + get_address2(data, bssid); + else if (get_to_ds(data) == 1) + get_address1(data, bssid); + else + get_address3(data, bssid); +} + +/* This function extracts the SSID from a beacon/probe response frame */ +static inline void get_ssid(u8 *data, u8 *ssid, u8 *p_ssid_len) +{ + u8 len = 0; + u8 i = 0; + u8 j = 0; + + len = data[MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + + CAP_INFO_LEN + 1]; + j = MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + + CAP_INFO_LEN + 2; + + /* If the SSID length field is set wrongly to a value greater than the */ + /* allowed maximum SSID length limit, reset the length to 0 */ + if (len >= MAX_SSID_LEN) + len = 0; + + for (i = 0; i < len; i++, j++) + ssid[i] = data[j]; + + ssid[len] = '\0'; + + *p_ssid_len = len; +} + +/* This function extracts the capability info field from the beacon or probe */ +/* response frame. */ +static inline u16 get_cap_info(u8 *data) +{ + u16 cap_info = 0; + u16 index = MAC_HDR_LEN; + enum sub_frame_type st; + + st = get_sub_type(data); + + /* Location of the Capability field is different for Beacon and */ + /* Association frames. */ + if ((st == BEACON) || (st == PROBE_RSP)) + index += TIME_STAMP_LEN + BEACON_INTERVAL_LEN; + + cap_info = data[index]; + cap_info |= (data[index + 1] << 8); + + return cap_info; +} + +/* This function extracts the capability info field from the Association */ +/* response frame. */ +static inline u16 get_assoc_resp_cap_info(u8 *data) +{ + u16 cap_info; + + cap_info = data[0]; + cap_info |= (data[1] << 8); + + return cap_info; +} + +/* This function extracts the association status code from the incoming */ +/* association response frame and returns association status code */ +static inline u16 get_asoc_status(u8 *data) +{ + u16 asoc_status; + + asoc_status = data[3]; + asoc_status = (asoc_status << 8) | data[2]; + + return asoc_status; +} + +/* This function extracts association ID from the incoming association */ +/* response frame */ +static inline u16 get_asoc_id(u8 *data) +{ + u16 asoc_id; + + asoc_id = data[4]; + asoc_id |= (data[5] << 8); + + return asoc_id; +} + +u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset) +{ + u16 u16index; + + /*************************************************************************/ + /* Beacon Frame - Frame Body */ + /* --------------------------------------------------------------------- */ + /* |Timestamp |BeaconInt |CapInfo |SSID |SupRates |DSParSet |TIM elm | */ + /* --------------------------------------------------------------------- */ + /* |8 |2 |2 |2-34 |3-10 |3 |4-256 | */ + /* --------------------------------------------------------------------- */ + /* */ + /*************************************************************************/ + + u16index = u16TagParamOffset; + + /* Search for the TIM Element Field and return if the element is found */ + while (u16index < (u16RxLen - FCS_LEN)) { + if (pu8msa[u16index] == ITIM) + return &pu8msa[u16index]; + u16index += (IE_HDR_LEN + pu8msa[u16index + 1]); + } + + return NULL; +} + +/* This function gets the current channel information from + * the 802.11n beacon/probe response frame */ +u8 get_current_channel_802_11n(u8 *pu8msa, u16 u16RxLen) +{ + u16 index; + + index = TAG_PARAM_OFFSET; + while (index < (u16RxLen - FCS_LEN)) { + if (pu8msa[index] == IDSPARMS) + return pu8msa[index + 2]; + /* Increment index by length information and header */ + index += pu8msa[index + 1] + IE_HDR_LEN; + } + + /* Return current channel information from the MIB, if beacon/probe */ + /* response frame does not contain the DS parameter set IE */ + /* return (mget_CurrentChannel() + 1); */ + return 0; /* no MIB here */ +} + +/** + * @brief parses the received 'N' message + * @details + * @param[in] pu8MsgBuffer The message to be parsed + * @param[out] ppstrNetworkInfo pointer to pointer to the structure containing the parsed Network Info + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ +s32 parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo) +{ + tstrNetworkInfo *pstrNetworkInfo = NULL; + u8 u8MsgType = 0; + u8 u8MsgID = 0; + u16 u16MsgLen = 0; + + u16 u16WidID = (u16)WID_NIL; + u16 u16WidLen = 0; + u8 *pu8WidVal = NULL; + + u8MsgType = pu8MsgBuffer[0]; + + /* Check whether the received message type is 'N' */ + if ('N' != u8MsgType) { + PRINT_ER("Received Message format incorrect.\n"); + return -EFAULT; + } + + /* Extract message ID */ + u8MsgID = pu8MsgBuffer[1]; + + /* Extract message Length */ + u16MsgLen = MAKE_WORD16(pu8MsgBuffer[2], pu8MsgBuffer[3]); + + /* Extract WID ID */ + u16WidID = MAKE_WORD16(pu8MsgBuffer[4], pu8MsgBuffer[5]); + + /* Extract WID Length */ + u16WidLen = MAKE_WORD16(pu8MsgBuffer[6], pu8MsgBuffer[7]); + + /* Assign a pointer to the WID value */ + pu8WidVal = &pu8MsgBuffer[8]; + + /* parse the WID value of the WID "WID_NEWORK_INFO" */ + { + u8 *pu8msa = NULL; + u16 u16RxLen = 0; + u8 *pu8TimElm = NULL; + u8 *pu8IEs = NULL; + u16 u16IEsLen = 0; + u8 u8index = 0; + u32 u32Tsf_Lo; + u32 u32Tsf_Hi; + + pstrNetworkInfo = kzalloc(sizeof(tstrNetworkInfo), GFP_KERNEL); + if (!pstrNetworkInfo) + return -ENOMEM; + + pstrNetworkInfo->s8rssi = pu8WidVal[0]; + + /* Assign a pointer to msa "Mac Header Start Address" */ + pu8msa = &pu8WidVal[1]; + + u16RxLen = u16WidLen - 1; + + /* parse msa*/ + + /* Get the cap_info */ + pstrNetworkInfo->u16CapInfo = get_cap_info(pu8msa); + /* Get time-stamp [Low only 32 bit] */ + pstrNetworkInfo->u32Tsf = get_beacon_timestamp_lo(pu8msa); + PRINT_D(CORECONFIG_DBG, "TSF :%x\n", pstrNetworkInfo->u32Tsf); + + /* Get full time-stamp [Low and High 64 bit] */ + u32Tsf_Lo = get_beacon_timestamp_lo(pu8msa); + u32Tsf_Hi = get_beacon_timestamp_hi(pu8msa); + + pstrNetworkInfo->u64Tsf = u32Tsf_Lo | ((u64)u32Tsf_Hi << 32); + + /* Get SSID */ + get_ssid(pu8msa, pstrNetworkInfo->au8ssid, &pstrNetworkInfo->u8SsidLen); + + /* Get BSSID */ + get_BSSID(pu8msa, pstrNetworkInfo->au8bssid); + + /* + * Extract current channel information from + * the beacon/probe response frame + */ + pstrNetworkInfo->u8channel = get_current_channel_802_11n(pu8msa, + u16RxLen + FCS_LEN); + + /* Get beacon period */ + u8index = MAC_HDR_LEN + TIME_STAMP_LEN; + + pstrNetworkInfo->u16BeaconPeriod = get_beacon_period(pu8msa + u8index); + + u8index += BEACON_INTERVAL_LEN + CAP_INFO_LEN; + + /* Get DTIM Period */ + pu8TimElm = get_tim_elm(pu8msa, u16RxLen + FCS_LEN, u8index); + if (pu8TimElm != NULL) + pstrNetworkInfo->u8DtimPeriod = pu8TimElm[3]; + pu8IEs = &pu8msa[MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN]; + u16IEsLen = u16RxLen - (MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN); + + if (u16IEsLen > 0) { + pstrNetworkInfo->pu8IEs = kmemdup(pu8IEs, u16IEsLen, + GFP_KERNEL); + if (!pstrNetworkInfo->pu8IEs) + return -ENOMEM; + } + pstrNetworkInfo->u16IEsLen = u16IEsLen; + + } + + *ppstrNetworkInfo = pstrNetworkInfo; + + return 0; +} + +/** + * @brief Deallocates the parsed Network Info + * @details + * @param[in] pstrNetworkInfo Network Info to be deallocated + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ +s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo) +{ + s32 s32Error = 0; + + if (pstrNetworkInfo != NULL) { + if (pstrNetworkInfo->pu8IEs != NULL) { + kfree(pstrNetworkInfo->pu8IEs); + pstrNetworkInfo->pu8IEs = NULL; + } else { + s32Error = -EFAULT; + } + + kfree(pstrNetworkInfo); + pstrNetworkInfo = NULL; + + } else { + s32Error = -EFAULT; + } + + return s32Error; +} + +/** + * @brief parses the received Association Response frame + * @details + * @param[in] pu8Buffer The Association Response frame to be parsed + * @param[out] ppstrConnectRespInfo pointer to pointer to the structure containing the parsed Association Response Info + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 2 Apr 2012 + * @version 1.0 + */ +s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen, + tstrConnectRespInfo **ppstrConnectRespInfo) +{ + s32 s32Error = 0; + tstrConnectRespInfo *pstrConnectRespInfo = NULL; + u16 u16AssocRespLen = 0; + u8 *pu8IEs = NULL; + u16 u16IEsLen = 0; + + pstrConnectRespInfo = kzalloc(sizeof(tstrConnectRespInfo), GFP_KERNEL); + if (!pstrConnectRespInfo) + return -ENOMEM; + + /* u16AssocRespLen = pu8Buffer[0]; */ + u16AssocRespLen = (u16)u32BufferLen; + + /* get the status code */ + pstrConnectRespInfo->u16ConnectStatus = get_asoc_status(pu8Buffer); + if (pstrConnectRespInfo->u16ConnectStatus == SUCCESSFUL_STATUSCODE) { + + /* get the capability */ + pstrConnectRespInfo->u16capability = get_assoc_resp_cap_info(pu8Buffer); + + /* get the Association ID */ + pstrConnectRespInfo->u16AssocID = get_asoc_id(pu8Buffer); + + /* get the Information Elements */ + pu8IEs = &pu8Buffer[CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN]; + u16IEsLen = u16AssocRespLen - (CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN); + + pstrConnectRespInfo->pu8RespIEs = kmemdup(pu8IEs, u16IEsLen, GFP_KERNEL); + if (!pstrConnectRespInfo->pu8RespIEs) + return -ENOMEM; + + pstrConnectRespInfo->u16RespIEsLen = u16IEsLen; + } + + *ppstrConnectRespInfo = pstrConnectRespInfo; + + return s32Error; +} + +/** + * @brief Deallocates the parsed Association Response Info + * @details + * @param[in] pstrNetworkInfo Network Info to be deallocated + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 2 Apr 2012 + * @version 1.0 + */ +s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo) +{ + s32 s32Error = 0; + + if (pstrConnectRespInfo != NULL) { + if (pstrConnectRespInfo->pu8RespIEs != NULL) { + kfree(pstrConnectRespInfo->pu8RespIEs); + pstrConnectRespInfo->pu8RespIEs = NULL; + } else { + s32Error = -EFAULT; + } + + kfree(pstrConnectRespInfo); + pstrConnectRespInfo = NULL; + + } else { + s32Error = -EFAULT; + } + + return s32Error; +} + +/** + * @brief sends certain Configuration Packet based on the input WIDs pstrWIDs + * using driver config layer + * + * @details + * @param[in] pstrWIDs WIDs to be sent in the configuration packet + * @param[in] u32WIDsCount number of WIDs to be sent in the configuration packet + * @param[out] pu8RxResp The received Packet Response + * @param[out] ps32RxRespLen Length of the received Packet Response + * @return Error code indicating success/failure + * @note + * @author mabubakr + * @date 1 Mar 2012 + * @version 1.0 + */ +s32 send_config_pkt(u8 mode, struct wid *wids, u32 count, u32 drv) +{ + s32 counter = 0, ret = 0; + + if (mode == GET_CFG) { + for (counter = 0; counter < count; counter++) { + PRINT_INFO(CORECONFIG_DBG, "Sending CFG packet [%d][%d]\n", !counter, + (counter == count - 1)); + if (!wilc_wlan_cfg_get(!counter, + wids[counter].id, + (counter == count - 1), + drv)) { + ret = -1; + printk("[Sendconfigpkt]Get Timed out\n"); + break; + } + } + counter = 0; + for (counter = 0; counter < count; counter++) { + wids[counter].size = wilc_wlan_cfg_get_val( + wids[counter].id, + wids[counter].val, + wids[counter].size); + + } + } else if (mode == SET_CFG) { + for (counter = 0; counter < count; counter++) { + PRINT_D(CORECONFIG_DBG, "Sending config SET PACKET WID:%x\n", wids[counter].id); + if (!wilc_wlan_cfg_set(!counter, + wids[counter].id, + wids[counter].val, + wids[counter].size, + (counter == count - 1), + drv)) { + ret = -1; + printk("[Sendconfigpkt]Set Timed out\n"); + break; + } + } + } + + return ret; +} diff --git a/kernel/drivers/staging/wilc1000/coreconfigurator.h b/kernel/drivers/staging/wilc1000/coreconfigurator.h new file mode 100644 index 000000000..6294d929a --- /dev/null +++ b/kernel/drivers/staging/wilc1000/coreconfigurator.h @@ -0,0 +1,142 @@ + +/*! + * @file coreconfigurator.h + * @brief + * @author + * @sa coreconfigurator.c + * @date 1 Mar 2012 + * @version 1.0 + */ + +#ifndef CORECONFIGURATOR_H +#define CORECONFIGURATOR_H + +#include "wilc_wlan_if.h" + +#define NUM_BASIC_SWITCHES 45 +#define NUM_FHSS_SWITCHES 0 + +#define NUM_RSSI 5 + +#ifdef MAC_802_11N +#define NUM_11N_BASIC_SWITCHES 25 +#define NUM_11N_HUT_SWITCHES 47 +#else +#define NUM_11N_BASIC_SWITCHES 0 +#define NUM_11N_HUT_SWITCHES 0 +#endif + +#define MAC_HDR_LEN 24 +#define MAX_SSID_LEN 33 +#define FCS_LEN 4 +#define TIME_STAMP_LEN 8 +#define BEACON_INTERVAL_LEN 2 +#define CAP_INFO_LEN 2 +#define STATUS_CODE_LEN 2 +#define AID_LEN 2 +#define IE_HDR_LEN 2 + +#define SET_CFG 0 +#define GET_CFG 1 + +#define MAX_STRING_LEN 256 +#define MAX_SURVEY_RESULT_FRAG_SIZE MAX_STRING_LEN +#define SURVEY_RESULT_LENGTH 44 +#define MAX_ASSOC_RESP_FRAME_SIZE MAX_STRING_LEN + +#define MAC_CONNECTED 1 +#define MAC_DISCONNECTED 0 + +#define MAKE_WORD16(lsb, msb) ((((u16)(msb) << 8) & 0xFF00) | (lsb)) +#define MAKE_WORD32(lsw, msw) ((((u32)(msw) << 16) & 0xFFFF0000) | (lsw)) + +typedef enum { + SUCCESSFUL_STATUSCODE = 0, + UNSPEC_FAIL = 1, + UNSUP_CAP = 10, + REASOC_NO_ASOC = 11, + FAIL_OTHER = 12, + UNSUPT_ALG = 13, + AUTH_SEQ_FAIL = 14, + CHLNG_FAIL = 15, + AUTH_TIMEOUT = 16, + AP_FULL = 17, + UNSUP_RATE = 18, + SHORT_PREAMBLE_UNSUP = 19, + PBCC_UNSUP = 20, + CHANNEL_AGIL_UNSUP = 21, + SHORT_SLOT_UNSUP = 25, + OFDM_DSSS_UNSUP = 26, + CONNECT_STS_FORCE_16_BIT = 0xFFFF +} tenuConnectSts; + +struct wid { + u16 id; + enum WID_TYPE type; + s32 size; + s8 *val; +}; + +typedef struct { + u8 u8Full; + u8 u8Index; + s8 as8RSSI[NUM_RSSI]; +} tstrRSSI; + +typedef struct { + s8 s8rssi; + u16 u16CapInfo; + u8 au8ssid[MAX_SSID_LEN]; + u8 u8SsidLen; + u8 au8bssid[6]; + u16 u16BeaconPeriod; + u8 u8DtimPeriod; + u8 u8channel; + unsigned long u32TimeRcvdInScanCached; + unsigned long u32TimeRcvdInScan; + bool bNewNetwork; + u8 u8Found; + u32 u32Tsf; + u8 *pu8IEs; + u16 u16IEsLen; + void *pJoinParams; + tstrRSSI strRssi; + u64 u64Tsf; +} tstrNetworkInfo; + +typedef struct { + u16 u16capability; + u16 u16ConnectStatus; + u16 u16AssocID; + u8 *pu8RespIEs; + u16 u16RespIEsLen; +} tstrConnectRespInfo; + +typedef struct { + u8 au8bssid[6]; + u8 *pu8ReqIEs; + size_t ReqIEsLen; + u8 *pu8RespIEs; + u16 u16RespIEsLen; + u16 u16ConnectStatus; +} tstrConnectInfo; + +typedef struct { + u16 u16reason; + u8 *ie; + size_t ie_len; +} tstrDisconnectNotifInfo; + +s32 send_config_pkt(u8 mode, struct wid *wids, u32 count, u32 drv); +s32 parse_network_info(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo); +s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo); + +s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen, + tstrConnectRespInfo **ppstrConnectRespInfo); +s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo); + +void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length); +void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length); +void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length); + +#endif diff --git a/kernel/drivers/staging/wilc1000/host_interface.c b/kernel/drivers/staging/wilc1000/host_interface.c new file mode 100644 index 000000000..dbbe72c7e --- /dev/null +++ b/kernel/drivers/staging/wilc1000/host_interface.c @@ -0,0 +1,5005 @@ +#include +#include +#include +#include +#include "host_interface.h" +#include "coreconfigurator.h" +#include "wilc_wlan_if.h" +#include "wilc_msgqueue.h" +#include +#include "wilc_wfi_netdevice.h" + +extern u8 connecting; + +extern struct timer_list hDuringIpTimer; + +extern u8 g_wilc_initialized; + +#define HOST_IF_MSG_SCAN 0 +#define HOST_IF_MSG_CONNECT 1 +#define HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO 2 +#define HOST_IF_MSG_KEY 3 +#define HOST_IF_MSG_RCVD_NTWRK_INFO 4 +#define HOST_IF_MSG_RCVD_SCAN_COMPLETE 5 +#define HOST_IF_MSG_CFG_PARAMS 6 +#define HOST_IF_MSG_SET_CHANNEL 7 +#define HOST_IF_MSG_DISCONNECT 8 +#define HOST_IF_MSG_GET_RSSI 9 +#define HOST_IF_MSG_GET_CHNL 10 +#define HOST_IF_MSG_ADD_BEACON 11 +#define HOST_IF_MSG_DEL_BEACON 12 +#define HOST_IF_MSG_ADD_STATION 13 +#define HOST_IF_MSG_DEL_STATION 14 +#define HOST_IF_MSG_EDIT_STATION 15 +#define HOST_IF_MSG_SCAN_TIMER_FIRED 16 +#define HOST_IF_MSG_CONNECT_TIMER_FIRED 17 +#define HOST_IF_MSG_POWER_MGMT 18 +#define HOST_IF_MSG_GET_INACTIVETIME 19 +#define HOST_IF_MSG_REMAIN_ON_CHAN 20 +#define HOST_IF_MSG_REGISTER_FRAME 21 +#define HOST_IF_MSG_LISTEN_TIMER_FIRED 22 +#define HOST_IF_MSG_GET_LINKSPEED 23 +#define HOST_IF_MSG_SET_WFIDRV_HANDLER 24 +#define HOST_IF_MSG_SET_MAC_ADDRESS 25 +#define HOST_IF_MSG_GET_MAC_ADDRESS 26 +#define HOST_IF_MSG_SET_OPERATION_MODE 27 +#define HOST_IF_MSG_SET_IPADDRESS 28 +#define HOST_IF_MSG_GET_IPADDRESS 29 +#define HOST_IF_MSG_FLUSH_CONNECT 30 +#define HOST_IF_MSG_GET_STATISTICS 31 +#define HOST_IF_MSG_SET_MULTICAST_FILTER 32 +#define HOST_IF_MSG_ADD_BA_SESSION 33 +#define HOST_IF_MSG_DEL_BA_SESSION 34 +#define HOST_IF_MSG_Q_IDLE 35 +#define HOST_IF_MSG_DEL_ALL_STA 36 +#define HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS 34 +#define HOST_IF_MSG_EXIT 100 + +#define HOST_IF_SCAN_TIMEOUT 4000 +#define HOST_IF_CONNECT_TIMEOUT 9500 + +#define BA_SESSION_DEFAULT_BUFFER_SIZE 16 +#define BA_SESSION_DEFAULT_TIMEOUT 1000 +#define BLOCK_ACK_REQ_SIZE 0x14 +#define FALSE_FRMWR_CHANNEL 100 + +struct cfg_param_attr { + struct cfg_param_val cfg_attr_info; +}; + +struct host_if_wpa_attr { + u8 *key; + const u8 *mac_addr; + u8 *seq; + u8 seq_len; + u8 index; + u8 key_len; + u8 mode; +}; + +struct host_if_wep_attr { + u8 *key; + u8 key_len; + u8 index; + u8 mode; + enum AUTHTYPE auth_type; +}; + +union host_if_key_attr { + struct host_if_wep_attr wep; + struct host_if_wpa_attr wpa; + struct host_if_pmkid_attr pmkid; +}; + +struct key_attr { + enum KEY_TYPE type; + u8 action; + union host_if_key_attr attr; +}; + +struct scan_attr { + u8 src; + u8 type; + u8 *ch_freq_list; + u8 ch_list_len; + u8 *ies; + size_t ies_len; + wilc_scan_result result; + void *arg; + struct hidden_network hidden_network; +}; + +struct connect_attr { + u8 *bssid; + u8 *ssid; + size_t ssid_len; + u8 *ies; + size_t ies_len; + u8 security; + wilc_connect_result result; + void *arg; + enum AUTHTYPE auth_type; + u8 ch; + void *params; +}; + +struct rcvd_async_info { + u8 *buffer; + u32 len; +}; + +struct channel_attr { + u8 set_ch; +}; + +struct beacon_attr { + u32 interval; + u32 dtim_period; + u32 head_len; + u8 *head; + u32 tail_len; + u8 *tail; +}; + +struct set_multicast { + bool enabled; + u32 cnt; +}; + +struct del_all_sta { + u8 del_all_sta[MAX_NUM_STA][ETH_ALEN]; + u8 assoc_sta; +}; + +struct del_sta { + u8 mac_addr[ETH_ALEN]; +}; + +struct power_mgmt_param { + bool enabled; + u32 timeout; +}; + +struct set_ip_addr { + u8 *ip_addr; + u8 idx; +}; + +struct sta_inactive_t { + u8 mac[6]; +}; + +union message_body { + struct scan_attr scan_info; + struct connect_attr con_info; + struct rcvd_net_info net_info; + struct rcvd_async_info async_info; + struct key_attr key_info; + struct cfg_param_attr cfg_info; + struct channel_attr channel_info; + struct beacon_attr beacon_info; + struct add_sta_param add_sta_info; + struct del_sta del_sta_info; + struct add_sta_param edit_sta_info; + struct power_mgmt_param pwr_mgmt_info; + struct sta_inactive_t mac_info; + struct set_ip_addr ip_info; + struct drv_handler drv; + struct set_multicast multicast_info; + struct op_mode mode; + struct set_mac_addr set_mac_info; + struct get_mac_addr get_mac_info; + struct ba_session_info session_info; + struct remain_ch remain_on_ch; + struct reg_frame reg_frame; + char *data; + struct del_all_sta del_all_sta_info; +}; + +struct host_if_msg { + u16 id; + union message_body body; + struct host_if_drv *drv; +}; + +struct join_bss_param { + BSSTYPE_T bss_type; + u8 dtim_period; + u16 beacon_period; + u16 cap_info; + u8 au8bssid[6]; + char ssid[MAX_SSID_LEN]; + u8 ssid_len; + u8 supp_rates[MAX_RATES_SUPPORTED + 1]; + u8 ht_capable; + u8 wmm_cap; + u8 uapsd_cap; + bool rsn_found; + u8 rsn_grp_policy; + u8 mode_802_11i; + u8 rsn_pcip_policy[3]; + u8 rsn_auth_policy[3]; + u8 rsn_cap[2]; + u32 tsf; + u8 noa_enabled; + u8 opp_enabled; + u8 ct_window; + u8 cnt; + u8 idx; + u8 duration[4]; + u8 interval[4]; + u8 start_time[4]; +}; + +static struct host_if_drv *wfidrv_list[NUM_CONCURRENT_IFC + 1]; +struct host_if_drv *terminated_handle; +bool g_obtainingIP; +u8 P2P_LISTEN_STATE; +static struct task_struct *hif_thread_handler; +static WILC_MsgQueueHandle hif_msg_q; +static struct semaphore hif_sema_thread; +static struct semaphore hif_sema_driver; +static struct semaphore hif_sema_wait_response; +static struct semaphore hif_sema_deinit; +static struct timer_list periodic_rssi; + +u8 gau8MulticastMacAddrList[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN]; + +static u8 rcv_assoc_resp[MAX_ASSOC_RESP_FRAME_SIZE]; + +static bool scan_while_connected; + +static s8 rssi; +static s8 link_speed; +static u8 ch_no; +static u8 set_ip[2][4]; +static u8 get_ip[2][4]; +static u32 inactive_time; +static u8 del_beacon; +static u32 clients_count; + +static u8 *join_req; +u8 *info_element; +static u8 mode_11i; +u8 auth_type; +u32 join_req_size; +static u32 info_element_size; +static struct host_if_drv *join_req_drv; +#define REAL_JOIN_REQ 0 +#define FLUSHED_JOIN_REQ 1 +#define FLUSHED_BYTE_POS 79 + +static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo); + +extern void chip_sleep_manually(u32 u32SleepTime); +extern int linux_wlan_get_num_conn_ifcs(void); + +static int add_handler_in_list(struct host_if_drv *handler) +{ + int i; + + for (i = 1; i < ARRAY_SIZE(wfidrv_list); i++) { + if (!wfidrv_list[i]) { + wfidrv_list[i] = handler; + return 0; + } + } + + return -ENOBUFS; +} + +static int remove_handler_in_list(struct host_if_drv *handler) +{ + int i; + + for (i = 1; i < ARRAY_SIZE(wfidrv_list); i++) { + if (wfidrv_list[i] == handler) { + wfidrv_list[i] = NULL; + return 0; + } + } + + return -EINVAL; +} + +static int get_id_from_handler(struct host_if_drv *handler) +{ + int i; + + if (!handler) + return 0; + + for (i = 1; i < ARRAY_SIZE(wfidrv_list); i++) { + if (wfidrv_list[i] == handler) + return i; + } + + return 0; +} + +static struct host_if_drv *get_handler_from_id(int id) +{ + if (id <= 0 || id >= ARRAY_SIZE(wfidrv_list)) + return NULL; + return wfidrv_list[id]; +} + +static s32 Handle_SetChannel(struct host_if_drv *hif_drv, + struct channel_attr *pstrHostIFSetChan) +{ + s32 result = 0; + struct wid wid; + + wid.id = (u16)WID_CURRENT_CHANNEL; + wid.type = WID_CHAR; + wid.val = (char *)&pstrHostIFSetChan->set_ch; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Setting channel\n"); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to set channel\n"); + return -EINVAL; + } + + return result; +} + +static s32 Handle_SetWfiDrvHandler(struct host_if_drv *hif_drv, + struct drv_handler *pstrHostIfSetDrvHandler) +{ + s32 result = 0; + struct wid wid; + + wid.id = (u16)WID_SET_DRV_HANDLER; + wid.type = WID_INT; + wid.val = (s8 *)&pstrHostIfSetDrvHandler->handler; + wid.size = sizeof(u32); + + result = send_config_pkt(SET_CFG, &wid, 1, + pstrHostIfSetDrvHandler->handler); + + if (!hif_drv) + up(&hif_sema_driver); + + if (result) { + PRINT_ER("Failed to set driver handler\n"); + return -EINVAL; + } + + return result; +} + +static s32 Handle_SetOperationMode(struct host_if_drv *hif_drv, + struct op_mode *pstrHostIfSetOperationMode) +{ + s32 result = 0; + struct wid wid; + + wid.id = (u16)WID_SET_OPERATION_MODE; + wid.type = WID_INT; + wid.val = (s8 *)&pstrHostIfSetOperationMode->mode; + wid.size = sizeof(u32); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if ((pstrHostIfSetOperationMode->mode) == IDLE_MODE) + up(&hif_sema_driver); + + if (result) { + PRINT_ER("Failed to set driver handler\n"); + return -EINVAL; + } + + return result; +} + +s32 Handle_set_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx) +{ + s32 result = 0; + struct wid wid; + char firmwareIPAddress[4] = {0}; + + if (pu8IPAddr[0] < 192) + pu8IPAddr[0] = 0; + + PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %pI4\n", idx, pu8IPAddr); + + memcpy(set_ip[idx], pu8IPAddr, IP_ALEN); + + wid.id = (u16)WID_IP_ADDRESS; + wid.type = WID_STR; + wid.val = (u8 *)pu8IPAddr; + wid.size = IP_ALEN; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + host_int_get_ipaddress(hif_drv, firmwareIPAddress, idx); + + if (result) { + PRINT_ER("Failed to set IP address\n"); + return -EINVAL; + } + + PRINT_INFO(HOSTINF_DBG, "IP address set\n"); + + return result; +} + +s32 Handle_get_IPAddress(struct host_if_drv *hif_drv, u8 *pu8IPAddr, u8 idx) +{ + s32 result = 0; + struct wid wid; + + wid.id = (u16)WID_IP_ADDRESS; + wid.type = WID_STR; + wid.val = kmalloc(IP_ALEN, GFP_KERNEL); + wid.size = IP_ALEN; + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + PRINT_INFO(HOSTINF_DBG, "%pI4\n", wid.val); + + memcpy(get_ip[idx], wid.val, IP_ALEN); + + kfree(wid.val); + + if (memcmp(get_ip[idx], set_ip[idx], IP_ALEN) != 0) + host_int_setup_ipaddress(hif_drv, set_ip[idx], idx); + + if (result != 0) { + PRINT_ER("Failed to get IP address\n"); + return -EINVAL; + } + + PRINT_INFO(HOSTINF_DBG, "IP address retrieved:: u8IfIdx = %d\n", idx); + PRINT_INFO(HOSTINF_DBG, "%pI4\n", get_ip[idx]); + PRINT_INFO(HOSTINF_DBG, "\n"); + + return result; +} + +static s32 Handle_SetMacAddress(struct host_if_drv *hif_drv, + struct set_mac_addr *pstrHostIfSetMacAddress) +{ + s32 result = 0; + struct wid wid; + u8 *mac_buf = kmalloc(ETH_ALEN, GFP_KERNEL); + + if (!mac_buf) { + PRINT_ER("No buffer to send mac address\n"); + return -EFAULT; + } + memcpy(mac_buf, pstrHostIfSetMacAddress->mac_addr, ETH_ALEN); + + wid.id = (u16)WID_MAC_ADDR; + wid.type = WID_STR; + wid.val = mac_buf; + wid.size = ETH_ALEN; + PRINT_D(GENERIC_DBG, "mac addr = :%pM\n", wid.val); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) { + PRINT_ER("Failed to set mac address\n"); + result = -EFAULT; + } + + kfree(mac_buf); + return result; +} + +static s32 Handle_GetMacAddress(struct host_if_drv *hif_drv, + struct get_mac_addr *pstrHostIfGetMacAddress) +{ + s32 result = 0; + struct wid wid; + + wid.id = (u16)WID_MAC_ADDR; + wid.type = WID_STR; + wid.val = pstrHostIfGetMacAddress->mac_addr; + wid.size = ETH_ALEN; + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to get mac address\n"); + result = -EFAULT; + } + up(&hif_sema_wait_response); + + return result; +} + +static s32 Handle_CfgParam(struct host_if_drv *hif_drv, + struct cfg_param_attr *strHostIFCfgParamAttr) +{ + s32 result = 0; + struct wid strWIDList[32]; + u8 u8WidCnt = 0; + + down(&hif_drv->gtOsCfgValuesSem); + + PRINT_D(HOSTINF_DBG, "Setting CFG params\n"); + + if (strHostIFCfgParamAttr->cfg_attr_info.flag & BSS_TYPE) { + if (strHostIFCfgParamAttr->cfg_attr_info.bss_type < 6) { + strWIDList[u8WidCnt].id = WID_BSS_TYPE; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.bss_type; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.bss_type = (u8)strHostIFCfgParamAttr->cfg_attr_info.bss_type; + } else { + PRINT_ER("check value 6 over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & AUTH_TYPE) { + if ((strHostIFCfgParamAttr->cfg_attr_info.auth_type) == 1 || (strHostIFCfgParamAttr->cfg_attr_info.auth_type) == 2 || (strHostIFCfgParamAttr->cfg_attr_info.auth_type) == 5) { + strWIDList[u8WidCnt].id = WID_AUTH_TYPE; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.auth_type; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.auth_type = (u8)strHostIFCfgParamAttr->cfg_attr_info.auth_type; + } else { + PRINT_ER("Impossible value \n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & AUTHEN_TIMEOUT) { + if (strHostIFCfgParamAttr->cfg_attr_info.auth_timeout > 0 && strHostIFCfgParamAttr->cfg_attr_info.auth_timeout < 65536) { + strWIDList[u8WidCnt].id = WID_AUTH_TIMEOUT; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.auth_timeout; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.auth_timeout = strHostIFCfgParamAttr->cfg_attr_info.auth_timeout; + } else { + PRINT_ER("Range(1 ~ 65535) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & POWER_MANAGEMENT) { + if (strHostIFCfgParamAttr->cfg_attr_info.power_mgmt_mode < 5) { + strWIDList[u8WidCnt].id = WID_POWER_MANAGEMENT; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.power_mgmt_mode; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.power_mgmt_mode = (u8)strHostIFCfgParamAttr->cfg_attr_info.power_mgmt_mode; + } else { + PRINT_ER("Invalide power mode\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & RETRY_SHORT) { + if ((strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit > 0) && (strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit < 256)) { + strWIDList[u8WidCnt].id = WID_SHORT_RETRY_LIMIT; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.short_retry_limit = strHostIFCfgParamAttr->cfg_attr_info.short_retry_limit; + } else { + PRINT_ER("Range(1~256) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & RETRY_LONG) { + if ((strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit > 0) && (strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit < 256)) { + strWIDList[u8WidCnt].id = WID_LONG_RETRY_LIMIT; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit; + + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.long_retry_limit = strHostIFCfgParamAttr->cfg_attr_info.long_retry_limit; + } else { + PRINT_ER("Range(1~256) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & FRAG_THRESHOLD) { + if (strHostIFCfgParamAttr->cfg_attr_info.frag_threshold > 255 && strHostIFCfgParamAttr->cfg_attr_info.frag_threshold < 7937) { + strWIDList[u8WidCnt].id = WID_FRAG_THRESHOLD; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.frag_threshold; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.frag_threshold = strHostIFCfgParamAttr->cfg_attr_info.frag_threshold; + } else { + PRINT_ER("Threshold Range fail\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & RTS_THRESHOLD) { + if (strHostIFCfgParamAttr->cfg_attr_info.rts_threshold > 255 && strHostIFCfgParamAttr->cfg_attr_info.rts_threshold < 65536) { + strWIDList[u8WidCnt].id = WID_RTS_THRESHOLD; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.rts_threshold; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.rts_threshold = strHostIFCfgParamAttr->cfg_attr_info.rts_threshold; + } else { + PRINT_ER("Threshold Range fail\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & PREAMBLE) { + if (strHostIFCfgParamAttr->cfg_attr_info.preamble_type < 3) { + strWIDList[u8WidCnt].id = WID_PREAMBLE; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.preamble_type; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.preamble_type = strHostIFCfgParamAttr->cfg_attr_info.preamble_type; + } else { + PRINT_ER("Preamle Range(0~2) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & SHORT_SLOT_ALLOWED) { + if (strHostIFCfgParamAttr->cfg_attr_info.short_slot_allowed < 2) { + strWIDList[u8WidCnt].id = WID_SHORT_SLOT_ALLOWED; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.short_slot_allowed; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.short_slot_allowed = (u8)strHostIFCfgParamAttr->cfg_attr_info.short_slot_allowed; + } else { + PRINT_ER("Short slot(2) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & TXOP_PROT_DISABLE) { + if (strHostIFCfgParamAttr->cfg_attr_info.txop_prot_disabled < 2) { + strWIDList[u8WidCnt].id = WID_11N_TXOP_PROT_DISABLE; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.txop_prot_disabled; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.txop_prot_disabled = (u8)strHostIFCfgParamAttr->cfg_attr_info.txop_prot_disabled; + } else { + PRINT_ER("TXOP prot disable\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & BEACON_INTERVAL) { + if (strHostIFCfgParamAttr->cfg_attr_info.beacon_interval > 0 && strHostIFCfgParamAttr->cfg_attr_info.beacon_interval < 65536) { + strWIDList[u8WidCnt].id = WID_BEACON_INTERVAL; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.beacon_interval; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.beacon_interval = strHostIFCfgParamAttr->cfg_attr_info.beacon_interval; + } else { + PRINT_ER("Beacon interval(1~65535) fail\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & DTIM_PERIOD) { + if (strHostIFCfgParamAttr->cfg_attr_info.dtim_period > 0 && strHostIFCfgParamAttr->cfg_attr_info.dtim_period < 256) { + strWIDList[u8WidCnt].id = WID_DTIM_PERIOD; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.dtim_period; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.dtim_period = strHostIFCfgParamAttr->cfg_attr_info.dtim_period; + } else { + PRINT_ER("DTIM range(1~255) fail\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & SITE_SURVEY) { + if (strHostIFCfgParamAttr->cfg_attr_info.site_survey_enabled < 3) { + strWIDList[u8WidCnt].id = WID_SITE_SURVEY; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.site_survey_enabled; + strWIDList[u8WidCnt].type = WID_CHAR; + strWIDList[u8WidCnt].size = sizeof(char); + hif_drv->strCfgValues.site_survey_enabled = (u8)strHostIFCfgParamAttr->cfg_attr_info.site_survey_enabled; + } else { + PRINT_ER("Site survey disable\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & SITE_SURVEY_SCAN_TIME) { + if (strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time > 0 && strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time < 65536) { + strWIDList[u8WidCnt].id = WID_SITE_SURVEY_SCAN_TIME; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.site_survey_scan_time = strHostIFCfgParamAttr->cfg_attr_info.site_survey_scan_time; + } else { + PRINT_ER("Site survey scan time(1~65535) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & ACTIVE_SCANTIME) { + if (strHostIFCfgParamAttr->cfg_attr_info.active_scan_time > 0 && strHostIFCfgParamAttr->cfg_attr_info.active_scan_time < 65536) { + strWIDList[u8WidCnt].id = WID_ACTIVE_SCAN_TIME; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.active_scan_time; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.active_scan_time = strHostIFCfgParamAttr->cfg_attr_info.active_scan_time; + } else { + PRINT_ER("Active scan time(1~65535) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & PASSIVE_SCANTIME) { + if (strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time > 0 && strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time < 65536) { + strWIDList[u8WidCnt].id = WID_PASSIVE_SCAN_TIME; + strWIDList[u8WidCnt].val = (s8 *)&strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.passive_scan_time = strHostIFCfgParamAttr->cfg_attr_info.passive_scan_time; + } else { + PRINT_ER("Passive scan time(1~65535) over\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + if (strHostIFCfgParamAttr->cfg_attr_info.flag & CURRENT_TX_RATE) { + enum CURRENT_TXRATE curr_tx_rate = strHostIFCfgParamAttr->cfg_attr_info.curr_tx_rate; + + if (curr_tx_rate == AUTORATE || curr_tx_rate == MBPS_1 + || curr_tx_rate == MBPS_2 || curr_tx_rate == MBPS_5_5 + || curr_tx_rate == MBPS_11 || curr_tx_rate == MBPS_6 + || curr_tx_rate == MBPS_9 || curr_tx_rate == MBPS_12 + || curr_tx_rate == MBPS_18 || curr_tx_rate == MBPS_24 + || curr_tx_rate == MBPS_36 || curr_tx_rate == MBPS_48 || curr_tx_rate == MBPS_54) { + strWIDList[u8WidCnt].id = WID_CURRENT_TX_RATE; + strWIDList[u8WidCnt].val = (s8 *)&curr_tx_rate; + strWIDList[u8WidCnt].type = WID_SHORT; + strWIDList[u8WidCnt].size = sizeof(u16); + hif_drv->strCfgValues.curr_tx_rate = (u8)curr_tx_rate; + } else { + PRINT_ER("out of TX rate\n"); + result = -EINVAL; + goto ERRORHANDLER; + } + u8WidCnt++; + } + + result = send_config_pkt(SET_CFG, strWIDList, u8WidCnt, + get_id_from_handler(hif_drv)); + + if (result) + PRINT_ER("Error in setting CFG params\n"); + +ERRORHANDLER: + up(&hif_drv->gtOsCfgValuesSem); + return result; +} + +static s32 Handle_wait_msg_q_empty(void) +{ + g_wilc_initialized = 0; + up(&hif_sema_wait_response); + return 0; +} + +static s32 Handle_Scan(struct host_if_drv *hif_drv, + struct scan_attr *pstrHostIFscanAttr) +{ + s32 result = 0; + struct wid strWIDList[5]; + u32 u32WidsCount = 0; + u32 i; + u8 *pu8Buffer; + u8 valuesize = 0; + u8 *pu8HdnNtwrksWidVal = NULL; + + PRINT_D(HOSTINF_DBG, "Setting SCAN params\n"); + PRINT_D(HOSTINF_DBG, "Scanning: In [%d] state\n", hif_drv->enuHostIFstate); + + hif_drv->usr_scan_req.pfUserScanResult = pstrHostIFscanAttr->result; + hif_drv->usr_scan_req.u32UserScanPvoid = pstrHostIFscanAttr->arg; + + if ((hif_drv->enuHostIFstate >= HOST_IF_SCANNING) && (hif_drv->enuHostIFstate < HOST_IF_CONNECTED)) { + PRINT_D(GENERIC_DBG, "Don't scan we are already in [%d] state\n", hif_drv->enuHostIFstate); + PRINT_ER("Already scan\n"); + result = -EBUSY; + goto ERRORHANDLER; + } + + if (g_obtainingIP || connecting) { + PRINT_D(GENERIC_DBG, "[handle_scan]: Don't do obss scan until IP adresss is obtained\n"); + PRINT_ER("Don't do obss scan\n"); + result = -EBUSY; + goto ERRORHANDLER; + } + + PRINT_D(HOSTINF_DBG, "Setting SCAN params\n"); + + hif_drv->usr_scan_req.u32RcvdChCount = 0; + + strWIDList[u32WidsCount].id = (u16)WID_SSID_PROBE_REQ; + strWIDList[u32WidsCount].type = WID_STR; + + for (i = 0; i < pstrHostIFscanAttr->hidden_network.u8ssidnum; i++) + valuesize += ((pstrHostIFscanAttr->hidden_network.pstrHiddenNetworkInfo[i].u8ssidlen) + 1); + pu8HdnNtwrksWidVal = kmalloc(valuesize + 1, GFP_KERNEL); + strWIDList[u32WidsCount].val = pu8HdnNtwrksWidVal; + if (strWIDList[u32WidsCount].val) { + pu8Buffer = strWIDList[u32WidsCount].val; + + *pu8Buffer++ = pstrHostIFscanAttr->hidden_network.u8ssidnum; + + PRINT_D(HOSTINF_DBG, "In Handle_ProbeRequest number of ssid %d\n", pstrHostIFscanAttr->hidden_network.u8ssidnum); + + for (i = 0; i < pstrHostIFscanAttr->hidden_network.u8ssidnum; i++) { + *pu8Buffer++ = pstrHostIFscanAttr->hidden_network.pstrHiddenNetworkInfo[i].u8ssidlen; + memcpy(pu8Buffer, pstrHostIFscanAttr->hidden_network.pstrHiddenNetworkInfo[i].pu8ssid, pstrHostIFscanAttr->hidden_network.pstrHiddenNetworkInfo[i].u8ssidlen); + pu8Buffer += pstrHostIFscanAttr->hidden_network.pstrHiddenNetworkInfo[i].u8ssidlen; + } + + strWIDList[u32WidsCount].size = (s32)(valuesize + 1); + u32WidsCount++; + } + + { + strWIDList[u32WidsCount].id = WID_INFO_ELEMENT_PROBE; + strWIDList[u32WidsCount].type = WID_BIN_DATA; + strWIDList[u32WidsCount].val = pstrHostIFscanAttr->ies; + strWIDList[u32WidsCount].size = pstrHostIFscanAttr->ies_len; + u32WidsCount++; + } + + strWIDList[u32WidsCount].id = WID_SCAN_TYPE; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)&pstrHostIFscanAttr->type; + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_SCAN_CHANNEL_LIST; + strWIDList[u32WidsCount].type = WID_BIN_DATA; + + if (pstrHostIFscanAttr->ch_freq_list && + pstrHostIFscanAttr->ch_list_len > 0) { + int i; + + for (i = 0; i < pstrHostIFscanAttr->ch_list_len; i++) { + if (pstrHostIFscanAttr->ch_freq_list[i] > 0) + pstrHostIFscanAttr->ch_freq_list[i] = pstrHostIFscanAttr->ch_freq_list[i] - 1; + } + } + + strWIDList[u32WidsCount].val = pstrHostIFscanAttr->ch_freq_list; + strWIDList[u32WidsCount].size = pstrHostIFscanAttr->ch_list_len; + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_START_SCAN_REQ; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)&pstrHostIFscanAttr->src; + u32WidsCount++; + + if (hif_drv->enuHostIFstate == HOST_IF_CONNECTED) + scan_while_connected = true; + else if (hif_drv->enuHostIFstate == HOST_IF_IDLE) + scan_while_connected = false; + + result = send_config_pkt(SET_CFG, strWIDList, u32WidsCount, + get_id_from_handler(hif_drv)); + + if (result) + PRINT_ER("Failed to send scan paramters config packet\n"); + else + PRINT_D(HOSTINF_DBG, "Successfully sent SCAN params config packet\n"); + +ERRORHANDLER: + if (result) { + del_timer(&hif_drv->hScanTimer); + Handle_ScanDone(hif_drv, SCAN_EVENT_ABORTED); + } + + kfree(pstrHostIFscanAttr->ch_freq_list); + pstrHostIFscanAttr->ch_freq_list = NULL; + + kfree(pstrHostIFscanAttr->ies); + pstrHostIFscanAttr->ies = NULL; + kfree(pstrHostIFscanAttr->hidden_network.pstrHiddenNetworkInfo); + pstrHostIFscanAttr->hidden_network.pstrHiddenNetworkInfo = NULL; + + kfree(pu8HdnNtwrksWidVal); + + return result; +} + +static s32 Handle_ScanDone(struct host_if_drv *hif_drv, + enum scan_event enuEvent) +{ + s32 result = 0; + u8 u8abort_running_scan; + struct wid wid; + + PRINT_D(HOSTINF_DBG, "in Handle_ScanDone()\n"); + + if (enuEvent == SCAN_EVENT_ABORTED) { + PRINT_D(GENERIC_DBG, "Abort running scan\n"); + u8abort_running_scan = 1; + wid.id = (u16)WID_ABORT_RUNNING_SCAN; + wid.type = WID_CHAR; + wid.val = (s8 *)&u8abort_running_scan; + wid.size = sizeof(char); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to set abort running scan\n"); + result = -EFAULT; + } + } + + if (!hif_drv) { + PRINT_ER("Driver handler is NULL\n"); + return result; + } + + if (hif_drv->usr_scan_req.pfUserScanResult) { + hif_drv->usr_scan_req.pfUserScanResult(enuEvent, NULL, + hif_drv->usr_scan_req.u32UserScanPvoid, NULL); + hif_drv->usr_scan_req.pfUserScanResult = NULL; + } + + return result; +} + +u8 u8ConnectedSSID[6] = {0}; +static s32 Handle_Connect(struct host_if_drv *hif_drv, + struct connect_attr *pstrHostIFconnectAttr) +{ + s32 result = 0; + struct wid strWIDList[8]; + u32 u32WidsCount = 0, dummyval = 0; + u8 *pu8CurrByte = NULL; + struct join_bss_param *ptstrJoinBssParam; + + PRINT_D(GENERIC_DBG, "Handling connect request\n"); + + if (memcmp(pstrHostIFconnectAttr->bssid, u8ConnectedSSID, ETH_ALEN) == 0) { + result = 0; + PRINT_ER("Trying to connect to an already connected AP, Discard connect request\n"); + return result; + } + + PRINT_INFO(HOSTINF_DBG, "Saving connection parameters in global structure\n"); + + ptstrJoinBssParam = (struct join_bss_param *)pstrHostIFconnectAttr->params; + if (!ptstrJoinBssParam) { + PRINT_ER("Required BSSID not found\n"); + result = -ENOENT; + goto ERRORHANDLER; + } + + if (pstrHostIFconnectAttr->bssid) { + hif_drv->usr_conn_req.pu8bssid = kmalloc(6, GFP_KERNEL); + memcpy(hif_drv->usr_conn_req.pu8bssid, pstrHostIFconnectAttr->bssid, 6); + } + + hif_drv->usr_conn_req.ssidLen = pstrHostIFconnectAttr->ssid_len; + if (pstrHostIFconnectAttr->ssid) { + hif_drv->usr_conn_req.pu8ssid = kmalloc(pstrHostIFconnectAttr->ssid_len + 1, GFP_KERNEL); + memcpy(hif_drv->usr_conn_req.pu8ssid, + pstrHostIFconnectAttr->ssid, + pstrHostIFconnectAttr->ssid_len); + hif_drv->usr_conn_req.pu8ssid[pstrHostIFconnectAttr->ssid_len] = '\0'; + } + + hif_drv->usr_conn_req.ConnReqIEsLen = pstrHostIFconnectAttr->ies_len; + if (pstrHostIFconnectAttr->ies) { + hif_drv->usr_conn_req.pu8ConnReqIEs = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL); + memcpy(hif_drv->usr_conn_req.pu8ConnReqIEs, + pstrHostIFconnectAttr->ies, + pstrHostIFconnectAttr->ies_len); + } + + hif_drv->usr_conn_req.u8security = pstrHostIFconnectAttr->security; + hif_drv->usr_conn_req.tenuAuth_type = pstrHostIFconnectAttr->auth_type; + hif_drv->usr_conn_req.pfUserConnectResult = pstrHostIFconnectAttr->result; + hif_drv->usr_conn_req.u32UserConnectPvoid = pstrHostIFconnectAttr->arg; + + strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT; + strWIDList[u32WidsCount].type = WID_INT; + strWIDList[u32WidsCount].size = sizeof(u32); + strWIDList[u32WidsCount].val = (s8 *)(&(dummyval)); + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT; + strWIDList[u32WidsCount].type = WID_INT; + strWIDList[u32WidsCount].size = sizeof(u32); + strWIDList[u32WidsCount].val = (s8 *)(&(dummyval)); + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_FAILED_COUNT; + strWIDList[u32WidsCount].type = WID_INT; + strWIDList[u32WidsCount].size = sizeof(u32); + strWIDList[u32WidsCount].val = (s8 *)(&(dummyval)); + u32WidsCount++; + + { + strWIDList[u32WidsCount].id = WID_INFO_ELEMENT_ASSOCIATE; + strWIDList[u32WidsCount].type = WID_BIN_DATA; + strWIDList[u32WidsCount].val = hif_drv->usr_conn_req.pu8ConnReqIEs; + strWIDList[u32WidsCount].size = hif_drv->usr_conn_req.ConnReqIEsLen; + u32WidsCount++; + + if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) { + info_element_size = hif_drv->usr_conn_req.ConnReqIEsLen; + info_element = kmalloc(info_element_size, GFP_KERNEL); + memcpy(info_element, hif_drv->usr_conn_req.pu8ConnReqIEs, + info_element_size); + } + } + strWIDList[u32WidsCount].id = (u16)WID_11I_MODE; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.u8security; + u32WidsCount++; + + if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) + mode_11i = hif_drv->usr_conn_req.u8security; + + PRINT_INFO(HOSTINF_DBG, "Encrypt Mode = %x\n", hif_drv->usr_conn_req.u8security); + + strWIDList[u32WidsCount].id = (u16)WID_AUTH_TYPE; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)(&hif_drv->usr_conn_req.tenuAuth_type); + u32WidsCount++; + + if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) + auth_type = (u8)hif_drv->usr_conn_req.tenuAuth_type; + + PRINT_INFO(HOSTINF_DBG, "Authentication Type = %x\n", hif_drv->usr_conn_req.tenuAuth_type); + PRINT_D(HOSTINF_DBG, "Connecting to network of SSID %s on channel %d\n", + hif_drv->usr_conn_req.pu8ssid, pstrHostIFconnectAttr->ch); + + strWIDList[u32WidsCount].id = (u16)WID_JOIN_REQ_EXTENDED; + strWIDList[u32WidsCount].type = WID_STR; + strWIDList[u32WidsCount].size = 112; + strWIDList[u32WidsCount].val = kmalloc(strWIDList[u32WidsCount].size, GFP_KERNEL); + + if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) { + join_req_size = strWIDList[u32WidsCount].size; + join_req = kmalloc(join_req_size, GFP_KERNEL); + } + if (!strWIDList[u32WidsCount].val) { + result = -EFAULT; + goto ERRORHANDLER; + } + + pu8CurrByte = strWIDList[u32WidsCount].val; + + if (pstrHostIFconnectAttr->ssid) { + memcpy(pu8CurrByte, pstrHostIFconnectAttr->ssid, pstrHostIFconnectAttr->ssid_len); + pu8CurrByte[pstrHostIFconnectAttr->ssid_len] = '\0'; + } + pu8CurrByte += MAX_SSID_LEN; + *(pu8CurrByte++) = INFRASTRUCTURE; + + if ((pstrHostIFconnectAttr->ch >= 1) && (pstrHostIFconnectAttr->ch <= 14)) { + *(pu8CurrByte++) = pstrHostIFconnectAttr->ch; + } else { + PRINT_ER("Channel out of range\n"); + *(pu8CurrByte++) = 0xFF; + } + *(pu8CurrByte++) = (ptstrJoinBssParam->cap_info) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->cap_info) >> 8) & 0xFF; + PRINT_D(HOSTINF_DBG, "* Cap Info %0x*\n", (*(pu8CurrByte - 2) | ((*(pu8CurrByte - 1)) << 8))); + + if (pstrHostIFconnectAttr->bssid) + memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6); + pu8CurrByte += 6; + + if (pstrHostIFconnectAttr->bssid) + memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6); + pu8CurrByte += 6; + + *(pu8CurrByte++) = (ptstrJoinBssParam->beacon_period) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->beacon_period) >> 8) & 0xFF; + PRINT_D(HOSTINF_DBG, "* Beacon Period %d*\n", (*(pu8CurrByte - 2) | ((*(pu8CurrByte - 1)) << 8))); + *(pu8CurrByte++) = ptstrJoinBssParam->dtim_period; + PRINT_D(HOSTINF_DBG, "* DTIM Period %d*\n", (*(pu8CurrByte - 1))); + + memcpy(pu8CurrByte, ptstrJoinBssParam->supp_rates, MAX_RATES_SUPPORTED + 1); + pu8CurrByte += (MAX_RATES_SUPPORTED + 1); + + *(pu8CurrByte++) = ptstrJoinBssParam->wmm_cap; + PRINT_D(HOSTINF_DBG, "* wmm cap%d*\n", (*(pu8CurrByte - 1))); + *(pu8CurrByte++) = ptstrJoinBssParam->uapsd_cap; + + *(pu8CurrByte++) = ptstrJoinBssParam->ht_capable; + hif_drv->usr_conn_req.IsHTCapable = ptstrJoinBssParam->ht_capable; + + *(pu8CurrByte++) = ptstrJoinBssParam->rsn_found; + PRINT_D(HOSTINF_DBG, "* rsn found %d*\n", *(pu8CurrByte - 1)); + *(pu8CurrByte++) = ptstrJoinBssParam->rsn_grp_policy; + PRINT_D(HOSTINF_DBG, "* rsn group policy %0x*\n", (*(pu8CurrByte - 1))); + *(pu8CurrByte++) = ptstrJoinBssParam->mode_802_11i; + PRINT_D(HOSTINF_DBG, "* mode_802_11i %d*\n", (*(pu8CurrByte - 1))); + + memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_pcip_policy, sizeof(ptstrJoinBssParam->rsn_pcip_policy)); + pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_pcip_policy); + + memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_auth_policy, sizeof(ptstrJoinBssParam->rsn_auth_policy)); + pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_auth_policy); + + memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_cap, sizeof(ptstrJoinBssParam->rsn_cap)); + pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_cap); + + *(pu8CurrByte++) = REAL_JOIN_REQ; + *(pu8CurrByte++) = ptstrJoinBssParam->noa_enabled; + + if (ptstrJoinBssParam->noa_enabled) { + PRINT_D(HOSTINF_DBG, "NOA present\n"); + + *(pu8CurrByte++) = (ptstrJoinBssParam->tsf) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 8) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 16) & 0xFF; + *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 24) & 0xFF; + + *(pu8CurrByte++) = ptstrJoinBssParam->opp_enabled; + *(pu8CurrByte++) = ptstrJoinBssParam->idx; + + if (ptstrJoinBssParam->opp_enabled) + *(pu8CurrByte++) = ptstrJoinBssParam->ct_window; + + *(pu8CurrByte++) = ptstrJoinBssParam->cnt; + + memcpy(pu8CurrByte, ptstrJoinBssParam->duration, sizeof(ptstrJoinBssParam->duration)); + pu8CurrByte += sizeof(ptstrJoinBssParam->duration); + + memcpy(pu8CurrByte, ptstrJoinBssParam->interval, sizeof(ptstrJoinBssParam->interval)); + pu8CurrByte += sizeof(ptstrJoinBssParam->interval); + + memcpy(pu8CurrByte, ptstrJoinBssParam->start_time, sizeof(ptstrJoinBssParam->start_time)); + pu8CurrByte += sizeof(ptstrJoinBssParam->start_time); + } else + PRINT_D(HOSTINF_DBG, "NOA not present\n"); + + pu8CurrByte = strWIDList[u32WidsCount].val; + u32WidsCount++; + + if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) { + memcpy(join_req, pu8CurrByte, join_req_size); + join_req_drv = hif_drv; + } + + PRINT_D(GENERIC_DBG, "send HOST_IF_WAITING_CONN_RESP\n"); + + if (pstrHostIFconnectAttr->bssid) { + memcpy(u8ConnectedSSID, pstrHostIFconnectAttr->bssid, ETH_ALEN); + + PRINT_D(GENERIC_DBG, "save Bssid = %pM\n", pstrHostIFconnectAttr->bssid); + PRINT_D(GENERIC_DBG, "save bssid = %pM\n", u8ConnectedSSID); + } + + result = send_config_pkt(SET_CFG, strWIDList, u32WidsCount, + get_id_from_handler(hif_drv)); + if (result) { + PRINT_ER("failed to send config packet\n"); + result = -EFAULT; + goto ERRORHANDLER; + } else { + PRINT_D(GENERIC_DBG, "set HOST_IF_WAITING_CONN_RESP\n"); + hif_drv->enuHostIFstate = HOST_IF_WAITING_CONN_RESP; + } + +ERRORHANDLER: + if (result) { + tstrConnectInfo strConnectInfo; + + del_timer(&hif_drv->hConnectTimer); + + PRINT_D(HOSTINF_DBG, "could not start connecting to the required network\n"); + + memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + + if (pstrHostIFconnectAttr->result) { + if (pstrHostIFconnectAttr->bssid) + memcpy(strConnectInfo.au8bssid, pstrHostIFconnectAttr->bssid, 6); + + if (pstrHostIFconnectAttr->ies) { + strConnectInfo.ReqIEsLen = pstrHostIFconnectAttr->ies_len; + strConnectInfo.pu8ReqIEs = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL); + memcpy(strConnectInfo.pu8ReqIEs, + pstrHostIFconnectAttr->ies, + pstrHostIFconnectAttr->ies_len); + } + + pstrHostIFconnectAttr->result(CONN_DISCONN_EVENT_CONN_RESP, + &strConnectInfo, + MAC_DISCONNECTED, + NULL, + pstrHostIFconnectAttr->arg); + hif_drv->enuHostIFstate = HOST_IF_IDLE; + kfree(strConnectInfo.pu8ReqIEs); + strConnectInfo.pu8ReqIEs = NULL; + + } else { + PRINT_ER("Connect callback function pointer is NULL\n"); + } + } + + PRINT_D(HOSTINF_DBG, "Deallocating connection parameters\n"); + kfree(pstrHostIFconnectAttr->bssid); + pstrHostIFconnectAttr->bssid = NULL; + + kfree(pstrHostIFconnectAttr->ssid); + pstrHostIFconnectAttr->ssid = NULL; + + kfree(pstrHostIFconnectAttr->ies); + pstrHostIFconnectAttr->ies = NULL; + + kfree(pu8CurrByte); + return result; +} + +static s32 Handle_FlushConnect(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct wid strWIDList[5]; + u32 u32WidsCount = 0; + u8 *pu8CurrByte = NULL; + + strWIDList[u32WidsCount].id = WID_INFO_ELEMENT_ASSOCIATE; + strWIDList[u32WidsCount].type = WID_BIN_DATA; + strWIDList[u32WidsCount].val = info_element; + strWIDList[u32WidsCount].size = info_element_size; + u32WidsCount++; + + strWIDList[u32WidsCount].id = (u16)WID_11I_MODE; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)(&(mode_11i)); + u32WidsCount++; + + strWIDList[u32WidsCount].id = (u16)WID_AUTH_TYPE; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)(&auth_type); + u32WidsCount++; + + strWIDList[u32WidsCount].id = (u16)WID_JOIN_REQ_EXTENDED; + strWIDList[u32WidsCount].type = WID_STR; + strWIDList[u32WidsCount].size = join_req_size; + strWIDList[u32WidsCount].val = (s8 *)join_req; + pu8CurrByte = strWIDList[u32WidsCount].val; + + pu8CurrByte += FLUSHED_BYTE_POS; + *(pu8CurrByte) = FLUSHED_JOIN_REQ; + + u32WidsCount++; + + result = send_config_pkt(SET_CFG, strWIDList, u32WidsCount, + get_id_from_handler(join_req_drv)); + if (result) { + PRINT_ER("failed to send config packet\n"); + result = -EINVAL; + } + + return result; +} + +static s32 Handle_ConnectTimeout(struct host_if_drv *hif_drv) +{ + s32 result = 0; + tstrConnectInfo strConnectInfo; + struct wid wid; + u16 u16DummyReasonCode = 0; + + if (!hif_drv) { + PRINT_ER("Driver handler is NULL\n"); + return result; + } + + hif_drv->enuHostIFstate = HOST_IF_IDLE; + + scan_while_connected = false; + + memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + + if (hif_drv->usr_conn_req.pfUserConnectResult) { + if (hif_drv->usr_conn_req.pu8bssid) { + memcpy(strConnectInfo.au8bssid, + hif_drv->usr_conn_req.pu8bssid, 6); + } + + if (hif_drv->usr_conn_req.pu8ConnReqIEs) { + strConnectInfo.ReqIEsLen = hif_drv->usr_conn_req.ConnReqIEsLen; + strConnectInfo.pu8ReqIEs = kmalloc(hif_drv->usr_conn_req.ConnReqIEsLen, GFP_KERNEL); + memcpy(strConnectInfo.pu8ReqIEs, + hif_drv->usr_conn_req.pu8ConnReqIEs, + hif_drv->usr_conn_req.ConnReqIEsLen); + } + + hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_CONN_RESP, + &strConnectInfo, + MAC_DISCONNECTED, + NULL, + hif_drv->usr_conn_req.u32UserConnectPvoid); + + kfree(strConnectInfo.pu8ReqIEs); + strConnectInfo.pu8ReqIEs = NULL; + } else { + PRINT_ER("Connect callback function pointer is NULL\n"); + } + + wid.id = (u16)WID_DISCONNECT; + wid.type = WID_CHAR; + wid.val = (s8 *)&u16DummyReasonCode; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Sending disconnect request\n"); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send dissconect config packet\n"); + + hif_drv->usr_conn_req.ssidLen = 0; + kfree(hif_drv->usr_conn_req.pu8ssid); + kfree(hif_drv->usr_conn_req.pu8bssid); + hif_drv->usr_conn_req.ConnReqIEsLen = 0; + kfree(hif_drv->usr_conn_req.pu8ConnReqIEs); + + eth_zero_addr(u8ConnectedSSID); + + if (join_req && join_req_drv == hif_drv) { + kfree(join_req); + join_req = NULL; + } + + if (info_element && join_req_drv == hif_drv) { + kfree(info_element); + info_element = NULL; + } + + return result; +} + +static s32 Handle_RcvdNtwrkInfo(struct host_if_drv *hif_drv, + struct rcvd_net_info *pstrRcvdNetworkInfo) +{ + u32 i; + bool bNewNtwrkFound; + s32 result = 0; + tstrNetworkInfo *pstrNetworkInfo = NULL; + void *pJoinParams = NULL; + + bNewNtwrkFound = true; + PRINT_INFO(HOSTINF_DBG, "Handling received network info\n"); + + if (hif_drv->usr_scan_req.pfUserScanResult) { + PRINT_D(HOSTINF_DBG, "State: Scanning, parsing network information received\n"); + parse_network_info(pstrRcvdNetworkInfo->buffer, &pstrNetworkInfo); + if ((!pstrNetworkInfo) || + (!hif_drv->usr_scan_req.pfUserScanResult)) { + PRINT_ER("driver is null\n"); + result = -EINVAL; + goto done; + } + + for (i = 0; i < hif_drv->usr_scan_req.u32RcvdChCount; i++) { + if ((hif_drv->usr_scan_req.astrFoundNetworkInfo[i].au8bssid) && + (pstrNetworkInfo->au8bssid)) { + if (memcmp(hif_drv->usr_scan_req.astrFoundNetworkInfo[i].au8bssid, + pstrNetworkInfo->au8bssid, 6) == 0) { + if (pstrNetworkInfo->s8rssi <= hif_drv->usr_scan_req.astrFoundNetworkInfo[i].s8rssi) { + PRINT_D(HOSTINF_DBG, "Network previously discovered\n"); + goto done; + } else { + hif_drv->usr_scan_req.astrFoundNetworkInfo[i].s8rssi = pstrNetworkInfo->s8rssi; + bNewNtwrkFound = false; + break; + } + } + } + } + + if (bNewNtwrkFound) { + PRINT_D(HOSTINF_DBG, "New network found\n"); + + if (hif_drv->usr_scan_req.u32RcvdChCount < MAX_NUM_SCANNED_NETWORKS) { + hif_drv->usr_scan_req.astrFoundNetworkInfo[hif_drv->usr_scan_req.u32RcvdChCount].s8rssi = pstrNetworkInfo->s8rssi; + + if (hif_drv->usr_scan_req.astrFoundNetworkInfo[hif_drv->usr_scan_req.u32RcvdChCount].au8bssid && + pstrNetworkInfo->au8bssid) { + memcpy(hif_drv->usr_scan_req.astrFoundNetworkInfo[hif_drv->usr_scan_req.u32RcvdChCount].au8bssid, + pstrNetworkInfo->au8bssid, 6); + + hif_drv->usr_scan_req.u32RcvdChCount++; + + pstrNetworkInfo->bNewNetwork = true; + pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo); + + hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, + hif_drv->usr_scan_req.u32UserScanPvoid, + pJoinParams); + } + } else { + PRINT_WRN(HOSTINF_DBG, "Discovered networks exceeded max. limit\n"); + } + } else { + pstrNetworkInfo->bNewNetwork = false; + hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, + hif_drv->usr_scan_req.u32UserScanPvoid, NULL); + } + } + +done: + kfree(pstrRcvdNetworkInfo->buffer); + pstrRcvdNetworkInfo->buffer = NULL; + + if (pstrNetworkInfo) { + DeallocateNetworkInfo(pstrNetworkInfo); + pstrNetworkInfo = NULL; + } + + return result; +} + +static s32 Handle_RcvdGnrlAsyncInfo(struct host_if_drv *hif_drv, + struct rcvd_async_info *pstrRcvdGnrlAsyncInfo) +{ + s32 result = 0; + u8 u8MsgType = 0; + u8 u8MsgID = 0; + u16 u16MsgLen = 0; + u16 u16WidID = (u16)WID_NIL; + u8 u8WidLen = 0; + u8 u8MacStatus; + u8 u8MacStatusReasonCode; + u8 u8MacStatusAdditionalInfo; + tstrConnectInfo strConnectInfo; + tstrDisconnectNotifInfo strDisconnectNotifInfo; + s32 s32Err = 0; + + if (!hif_drv) { + PRINT_ER("Driver handler is NULL\n"); + return -ENODEV; + } + PRINT_D(GENERIC_DBG, "Current State = %d,Received state = %d\n", hif_drv->enuHostIFstate, + pstrRcvdGnrlAsyncInfo->buffer[7]); + + if ((hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) || + (hif_drv->enuHostIFstate == HOST_IF_CONNECTED) || + hif_drv->usr_scan_req.pfUserScanResult) { + if (!pstrRcvdGnrlAsyncInfo->buffer || + !hif_drv->usr_conn_req.pfUserConnectResult) { + PRINT_ER("driver is null\n"); + return -EINVAL; + } + + u8MsgType = pstrRcvdGnrlAsyncInfo->buffer[0]; + + if ('I' != u8MsgType) { + PRINT_ER("Received Message format incorrect.\n"); + return -EFAULT; + } + + u8MsgID = pstrRcvdGnrlAsyncInfo->buffer[1]; + u16MsgLen = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->buffer[2], pstrRcvdGnrlAsyncInfo->buffer[3]); + u16WidID = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->buffer[4], pstrRcvdGnrlAsyncInfo->buffer[5]); + u8WidLen = pstrRcvdGnrlAsyncInfo->buffer[6]; + u8MacStatus = pstrRcvdGnrlAsyncInfo->buffer[7]; + u8MacStatusReasonCode = pstrRcvdGnrlAsyncInfo->buffer[8]; + u8MacStatusAdditionalInfo = pstrRcvdGnrlAsyncInfo->buffer[9]; + PRINT_INFO(HOSTINF_DBG, "Recieved MAC status = %d with Reason = %d , Info = %d\n", u8MacStatus, u8MacStatusReasonCode, u8MacStatusAdditionalInfo); + if (hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) { + u32 u32RcvdAssocRespInfoLen; + tstrConnectRespInfo *pstrConnectRespInfo = NULL; + + PRINT_D(HOSTINF_DBG, "Recieved MAC status = %d with Reason = %d , Code = %d\n", u8MacStatus, u8MacStatusReasonCode, u8MacStatusAdditionalInfo); + + memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + + if (u8MacStatus == MAC_CONNECTED) { + memset(rcv_assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE); + + host_int_get_assoc_res_info(hif_drv, + rcv_assoc_resp, + MAX_ASSOC_RESP_FRAME_SIZE, + &u32RcvdAssocRespInfoLen); + + PRINT_INFO(HOSTINF_DBG, "Received association response with length = %d\n", u32RcvdAssocRespInfoLen); + + if (u32RcvdAssocRespInfoLen != 0) { + PRINT_D(HOSTINF_DBG, "Parsing association response\n"); + s32Err = ParseAssocRespInfo(rcv_assoc_resp, u32RcvdAssocRespInfoLen, + &pstrConnectRespInfo); + if (s32Err) { + PRINT_ER("ParseAssocRespInfo() returned error %d\n", s32Err); + } else { + strConnectInfo.u16ConnectStatus = pstrConnectRespInfo->u16ConnectStatus; + + if (strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE) { + PRINT_INFO(HOSTINF_DBG, "Association response received : Successful connection status\n"); + if (pstrConnectRespInfo->pu8RespIEs) { + strConnectInfo.u16RespIEsLen = pstrConnectRespInfo->u16RespIEsLen; + strConnectInfo.pu8RespIEs = kmalloc(pstrConnectRespInfo->u16RespIEsLen, GFP_KERNEL); + memcpy(strConnectInfo.pu8RespIEs, pstrConnectRespInfo->pu8RespIEs, + pstrConnectRespInfo->u16RespIEsLen); + } + } + + if (pstrConnectRespInfo) { + DeallocateAssocRespInfo(pstrConnectRespInfo); + pstrConnectRespInfo = NULL; + } + } + } + } + + if ((u8MacStatus == MAC_CONNECTED) && + (strConnectInfo.u16ConnectStatus != SUCCESSFUL_STATUSCODE)) { + PRINT_ER("Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n"); + eth_zero_addr(u8ConnectedSSID); + + } else if (u8MacStatus == MAC_DISCONNECTED) { + PRINT_ER("Received MAC status is MAC_DISCONNECTED\n"); + eth_zero_addr(u8ConnectedSSID); + } + + if (hif_drv->usr_conn_req.pu8bssid) { + PRINT_D(HOSTINF_DBG, "Retrieving actual BSSID from AP\n"); + memcpy(strConnectInfo.au8bssid, hif_drv->usr_conn_req.pu8bssid, 6); + + if ((u8MacStatus == MAC_CONNECTED) && + (strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE)) { + memcpy(hif_drv->au8AssociatedBSSID, + hif_drv->usr_conn_req.pu8bssid, ETH_ALEN); + } + } + + if (hif_drv->usr_conn_req.pu8ConnReqIEs) { + strConnectInfo.ReqIEsLen = hif_drv->usr_conn_req.ConnReqIEsLen; + strConnectInfo.pu8ReqIEs = kmalloc(hif_drv->usr_conn_req.ConnReqIEsLen, GFP_KERNEL); + memcpy(strConnectInfo.pu8ReqIEs, + hif_drv->usr_conn_req.pu8ConnReqIEs, + hif_drv->usr_conn_req.ConnReqIEsLen); + } + + del_timer(&hif_drv->hConnectTimer); + hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_CONN_RESP, + &strConnectInfo, + u8MacStatus, + NULL, + hif_drv->usr_conn_req.u32UserConnectPvoid); + + if ((u8MacStatus == MAC_CONNECTED) && + (strConnectInfo.u16ConnectStatus == SUCCESSFUL_STATUSCODE)) { + host_int_set_power_mgmt(hif_drv, 0, 0); + + PRINT_D(HOSTINF_DBG, "MAC status : CONNECTED and Connect Status : Successful\n"); + hif_drv->enuHostIFstate = HOST_IF_CONNECTED; + + PRINT_D(GENERIC_DBG, "Obtaining an IP, Disable Scan\n"); + g_obtainingIP = true; + mod_timer(&hDuringIpTimer, + jiffies + msecs_to_jiffies(10000)); + } else { + PRINT_D(HOSTINF_DBG, "MAC status : %d and Connect Status : %d\n", u8MacStatus, strConnectInfo.u16ConnectStatus); + hif_drv->enuHostIFstate = HOST_IF_IDLE; + scan_while_connected = false; + } + + kfree(strConnectInfo.pu8RespIEs); + strConnectInfo.pu8RespIEs = NULL; + + kfree(strConnectInfo.pu8ReqIEs); + strConnectInfo.pu8ReqIEs = NULL; + hif_drv->usr_conn_req.ssidLen = 0; + kfree(hif_drv->usr_conn_req.pu8ssid); + kfree(hif_drv->usr_conn_req.pu8bssid); + hif_drv->usr_conn_req.ConnReqIEsLen = 0; + kfree(hif_drv->usr_conn_req.pu8ConnReqIEs); + } else if ((u8MacStatus == MAC_DISCONNECTED) && + (hif_drv->enuHostIFstate == HOST_IF_CONNECTED)) { + PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW\n"); + + memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); + + if (hif_drv->usr_scan_req.pfUserScanResult) { + PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running OBSS Scan >>\n\n"); + del_timer(&hif_drv->hScanTimer); + Handle_ScanDone((void *)hif_drv, SCAN_EVENT_ABORTED); + } + + strDisconnectNotifInfo.u16reason = 0; + strDisconnectNotifInfo.ie = NULL; + strDisconnectNotifInfo.ie_len = 0; + + if (hif_drv->usr_conn_req.pfUserConnectResult) { + g_obtainingIP = false; + host_int_set_power_mgmt(hif_drv, 0, 0); + + hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_DISCONN_NOTIF, + NULL, + 0, + &strDisconnectNotifInfo, + hif_drv->usr_conn_req.u32UserConnectPvoid); + } else { + PRINT_ER("Connect result callback function is NULL\n"); + } + + eth_zero_addr(hif_drv->au8AssociatedBSSID); + + hif_drv->usr_conn_req.ssidLen = 0; + kfree(hif_drv->usr_conn_req.pu8ssid); + kfree(hif_drv->usr_conn_req.pu8bssid); + hif_drv->usr_conn_req.ConnReqIEsLen = 0; + kfree(hif_drv->usr_conn_req.pu8ConnReqIEs); + + if (join_req && join_req_drv == hif_drv) { + kfree(join_req); + join_req = NULL; + } + + if (info_element && join_req_drv == hif_drv) { + kfree(info_element); + info_element = NULL; + } + + hif_drv->enuHostIFstate = HOST_IF_IDLE; + scan_while_connected = false; + + } else if ((u8MacStatus == MAC_DISCONNECTED) && + (hif_drv->usr_scan_req.pfUserScanResult)) { + PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW while scanning\n"); + PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running Scan >>\n\n"); + + del_timer(&hif_drv->hScanTimer); + if (hif_drv->usr_scan_req.pfUserScanResult) + Handle_ScanDone(hif_drv, SCAN_EVENT_ABORTED); + } + } + + kfree(pstrRcvdGnrlAsyncInfo->buffer); + pstrRcvdGnrlAsyncInfo->buffer = NULL; + + return result; +} + +static int Handle_Key(struct host_if_drv *hif_drv, + struct key_attr *pstrHostIFkeyAttr) +{ + s32 result = 0; + struct wid wid; + struct wid strWIDList[5]; + u8 i; + u8 *pu8keybuf; + s8 s8idxarray[1]; + s8 ret = 0; + + switch (pstrHostIFkeyAttr->type) { + case WEP: + + if (pstrHostIFkeyAttr->action & ADDKEY_AP) { + PRINT_D(HOSTINF_DBG, "Handling WEP key\n"); + PRINT_D(GENERIC_DBG, "ID Hostint is %d\n", pstrHostIFkeyAttr->attr.wep.index); + strWIDList[0].id = (u16)WID_11I_MODE; + strWIDList[0].type = WID_CHAR; + strWIDList[0].size = sizeof(char); + strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.mode; + + strWIDList[1].id = WID_AUTH_TYPE; + strWIDList[1].type = WID_CHAR; + strWIDList[1].size = sizeof(char); + strWIDList[1].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.auth_type; + + strWIDList[2].id = (u16)WID_KEY_ID; + strWIDList[2].type = WID_CHAR; + + strWIDList[2].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.index; + strWIDList[2].size = sizeof(char); + + pu8keybuf = kmemdup(pstrHostIFkeyAttr->attr.wep.key, + pstrHostIFkeyAttr->attr.wep.key_len, + GFP_KERNEL); + + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send Key\n"); + return -ENOMEM; + } + + kfree(pstrHostIFkeyAttr->attr.wep.key); + + strWIDList[3].id = (u16)WID_WEP_KEY_VALUE; + strWIDList[3].type = WID_STR; + strWIDList[3].size = pstrHostIFkeyAttr->attr.wep.key_len; + strWIDList[3].val = (s8 *)pu8keybuf; + + result = send_config_pkt(SET_CFG, strWIDList, 4, + get_id_from_handler(hif_drv)); + kfree(pu8keybuf); + } + + if (pstrHostIFkeyAttr->action & ADDKEY) { + PRINT_D(HOSTINF_DBG, "Handling WEP key\n"); + pu8keybuf = kmalloc(pstrHostIFkeyAttr->attr.wep.key_len + 2, GFP_KERNEL); + if (!pu8keybuf) { + PRINT_ER("No buffer to send Key\n"); + return -ENOMEM; + } + pu8keybuf[0] = pstrHostIFkeyAttr->attr.wep.index; + memcpy(pu8keybuf + 1, &pstrHostIFkeyAttr->attr.wep.key_len, 1); + memcpy(pu8keybuf + 2, pstrHostIFkeyAttr->attr.wep.key, + pstrHostIFkeyAttr->attr.wep.key_len); + kfree(pstrHostIFkeyAttr->attr.wep.key); + + wid.id = (u16)WID_ADD_WEP_KEY; + wid.type = WID_STR; + wid.val = (s8 *)pu8keybuf; + wid.size = pstrHostIFkeyAttr->attr.wep.key_len + 2; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + kfree(pu8keybuf); + } else if (pstrHostIFkeyAttr->action & REMOVEKEY) { + PRINT_D(HOSTINF_DBG, "Removing key\n"); + wid.id = (u16)WID_REMOVE_WEP_KEY; + wid.type = WID_STR; + + s8idxarray[0] = (s8)pstrHostIFkeyAttr->attr.wep.index; + wid.val = s8idxarray; + wid.size = 1; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + } else { + wid.id = (u16)WID_KEY_ID; + wid.type = WID_CHAR; + wid.val = (s8 *)&pstrHostIFkeyAttr->attr.wep.index; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Setting default key index\n"); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + } + up(&hif_drv->hSemTestKeyBlock); + break; + + case WPARxGtk: + if (pstrHostIFkeyAttr->action & ADDKEY_AP) { + pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL); + if (!pu8keybuf) { + PRINT_ER("No buffer to send RxGTK Key\n"); + ret = -ENOMEM; + goto _WPARxGtk_end_case_; + } + + if (pstrHostIFkeyAttr->attr.wpa.seq) + memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->attr.wpa.seq, 8); + + memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->attr.wpa.index, 1); + memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); + memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->attr.wpa.key, + pstrHostIFkeyAttr->attr.wpa.key_len); + + strWIDList[0].id = (u16)WID_11I_MODE; + strWIDList[0].type = WID_CHAR; + strWIDList[0].size = sizeof(char); + strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode; + + strWIDList[1].id = (u16)WID_ADD_RX_GTK; + strWIDList[1].type = WID_STR; + strWIDList[1].val = (s8 *)pu8keybuf; + strWIDList[1].size = RX_MIC_KEY_MSG_LEN; + + result = send_config_pkt(SET_CFG, strWIDList, 2, + get_id_from_handler(hif_drv)); + + kfree(pu8keybuf); + up(&hif_drv->hSemTestKeyBlock); + } + + if (pstrHostIFkeyAttr->action & ADDKEY) { + PRINT_D(HOSTINF_DBG, "Handling group key(Rx) function\n"); + + pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL); + if (pu8keybuf == NULL) { + PRINT_ER("No buffer to send RxGTK Key\n"); + ret = -ENOMEM; + goto _WPARxGtk_end_case_; + } + + if (hif_drv->enuHostIFstate == HOST_IF_CONNECTED) + memcpy(pu8keybuf, hif_drv->au8AssociatedBSSID, ETH_ALEN); + else + PRINT_ER("Couldn't handle WPARxGtk while enuHostIFstate is not HOST_IF_CONNECTED\n"); + + memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->attr.wpa.seq, 8); + memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->attr.wpa.index, 1); + memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); + memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->attr.wpa.key, + pstrHostIFkeyAttr->attr.wpa.key_len); + + wid.id = (u16)WID_ADD_RX_GTK; + wid.type = WID_STR; + wid.val = (s8 *)pu8keybuf; + wid.size = RX_MIC_KEY_MSG_LEN; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + kfree(pu8keybuf); + up(&hif_drv->hSemTestKeyBlock); + } +_WPARxGtk_end_case_: + kfree(pstrHostIFkeyAttr->attr.wpa.key); + kfree(pstrHostIFkeyAttr->attr.wpa.seq); + if (ret) + return ret; + + break; + + case WPAPtk: + if (pstrHostIFkeyAttr->action & ADDKEY_AP) { + pu8keybuf = kmalloc(PTK_KEY_MSG_LEN + 1, GFP_KERNEL); + if (!pu8keybuf) { + PRINT_ER("No buffer to send PTK Key\n"); + ret = -ENOMEM; + goto _WPAPtk_end_case_; + } + + memcpy(pu8keybuf, pstrHostIFkeyAttr->attr.wpa.mac_addr, 6); + memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->attr.wpa.index, 1); + memcpy(pu8keybuf + 7, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); + memcpy(pu8keybuf + 8, pstrHostIFkeyAttr->attr.wpa.key, + pstrHostIFkeyAttr->attr.wpa.key_len); + + strWIDList[0].id = (u16)WID_11I_MODE; + strWIDList[0].type = WID_CHAR; + strWIDList[0].size = sizeof(char); + strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode; + + strWIDList[1].id = (u16)WID_ADD_PTK; + strWIDList[1].type = WID_STR; + strWIDList[1].val = (s8 *)pu8keybuf; + strWIDList[1].size = PTK_KEY_MSG_LEN + 1; + + result = send_config_pkt(SET_CFG, strWIDList, 2, + get_id_from_handler(hif_drv)); + kfree(pu8keybuf); + up(&hif_drv->hSemTestKeyBlock); + } + if (pstrHostIFkeyAttr->action & ADDKEY) { + pu8keybuf = kmalloc(PTK_KEY_MSG_LEN, GFP_KERNEL); + if (!pu8keybuf) { + PRINT_ER("No buffer to send PTK Key\n"); + ret = -ENOMEM; + goto _WPAPtk_end_case_; + } + + memcpy(pu8keybuf, pstrHostIFkeyAttr->attr.wpa.mac_addr, 6); + memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); + memcpy(pu8keybuf + 7, pstrHostIFkeyAttr->attr.wpa.key, + pstrHostIFkeyAttr->attr.wpa.key_len); + + wid.id = (u16)WID_ADD_PTK; + wid.type = WID_STR; + wid.val = (s8 *)pu8keybuf; + wid.size = PTK_KEY_MSG_LEN; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + kfree(pu8keybuf); + up(&hif_drv->hSemTestKeyBlock); + } + +_WPAPtk_end_case_: + kfree(pstrHostIFkeyAttr->attr.wpa.key); + if (ret) + return ret; + + break; + + case PMKSA: + + PRINT_D(HOSTINF_DBG, "Handling PMKSA key\n"); + + pu8keybuf = kmalloc((pstrHostIFkeyAttr->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1, GFP_KERNEL); + if (!pu8keybuf) { + PRINT_ER("No buffer to send PMKSA Key\n"); + return -ENOMEM; + } + + pu8keybuf[0] = pstrHostIFkeyAttr->attr.pmkid.numpmkid; + + for (i = 0; i < pstrHostIFkeyAttr->attr.pmkid.numpmkid; i++) { + memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + 1), pstrHostIFkeyAttr->attr.pmkid.pmkidlist[i].bssid, ETH_ALEN); + memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + ETH_ALEN + 1), pstrHostIFkeyAttr->attr.pmkid.pmkidlist[i].pmkid, PMKID_LEN); + } + + wid.id = (u16)WID_PMKID_INFO; + wid.type = WID_STR; + wid.val = (s8 *)pu8keybuf; + wid.size = (pstrHostIFkeyAttr->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + kfree(pu8keybuf); + break; + } + + if (result) + PRINT_ER("Failed to send key config packet\n"); + + return result; +} + +static void Handle_Disconnect(struct host_if_drv *hif_drv) +{ + struct wid wid; + + s32 result = 0; + u16 u16DummyReasonCode = 0; + + wid.id = (u16)WID_DISCONNECT; + wid.type = WID_CHAR; + wid.val = (s8 *)&u16DummyReasonCode; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Sending disconnect request\n"); + + g_obtainingIP = false; + host_int_set_power_mgmt(hif_drv, 0, 0); + + eth_zero_addr(u8ConnectedSSID); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to send dissconect config packet\n"); + } else { + tstrDisconnectNotifInfo strDisconnectNotifInfo; + + memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); + + strDisconnectNotifInfo.u16reason = 0; + strDisconnectNotifInfo.ie = NULL; + strDisconnectNotifInfo.ie_len = 0; + + if (hif_drv->usr_scan_req.pfUserScanResult) { + del_timer(&hif_drv->hScanTimer); + hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_ABORTED, NULL, + hif_drv->usr_scan_req.u32UserScanPvoid, NULL); + + hif_drv->usr_scan_req.pfUserScanResult = NULL; + } + + if (hif_drv->usr_conn_req.pfUserConnectResult) { + if (hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) { + PRINT_D(HOSTINF_DBG, "Upper layer requested termination of connection\n"); + del_timer(&hif_drv->hConnectTimer); + } + + hif_drv->usr_conn_req.pfUserConnectResult(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, + 0, &strDisconnectNotifInfo, hif_drv->usr_conn_req.u32UserConnectPvoid); + } else { + PRINT_ER("usr_conn_req.pfUserConnectResult = NULL\n"); + } + + scan_while_connected = false; + + hif_drv->enuHostIFstate = HOST_IF_IDLE; + + eth_zero_addr(hif_drv->au8AssociatedBSSID); + + hif_drv->usr_conn_req.ssidLen = 0; + kfree(hif_drv->usr_conn_req.pu8ssid); + kfree(hif_drv->usr_conn_req.pu8bssid); + hif_drv->usr_conn_req.ConnReqIEsLen = 0; + kfree(hif_drv->usr_conn_req.pu8ConnReqIEs); + + if (join_req && join_req_drv == hif_drv) { + kfree(join_req); + join_req = NULL; + } + + if (info_element && join_req_drv == hif_drv) { + kfree(info_element); + info_element = NULL; + } + } + + up(&hif_drv->hSemTestDisconnectBlock); +} + +void resolve_disconnect_aberration(struct host_if_drv *hif_drv) +{ + if (!hif_drv) + return; + if ((hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) || (hif_drv->enuHostIFstate == HOST_IF_CONNECTING)) { + PRINT_D(HOSTINF_DBG, "\n\n<< correcting Supplicant state machine >>\n\n"); + host_int_disconnect(hif_drv, 1); + } +} + +static s32 Handle_GetChnl(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct wid wid; + + wid.id = (u16)WID_CURRENT_CHANNEL; + wid.type = WID_CHAR; + wid.val = (s8 *)&ch_no; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Getting channel value\n"); + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to get channel number\n"); + result = -EFAULT; + } + + up(&hif_drv->hSemGetCHNL); + + return result; +} + +static void Handle_GetRssi(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct wid wid; + + wid.id = (u16)WID_RSSI; + wid.type = WID_CHAR; + wid.val = &rssi; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Getting RSSI value\n"); + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) { + PRINT_ER("Failed to get RSSI value\n"); + result = -EFAULT; + } + + up(&hif_drv->hSemGetRSSI); +} + +static void Handle_GetLinkspeed(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct wid wid; + + link_speed = 0; + + wid.id = (u16)WID_LINKSPEED; + wid.type = WID_CHAR; + wid.val = &link_speed; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Getting LINKSPEED value\n"); + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) { + PRINT_ER("Failed to get LINKSPEED value\n"); + result = -EFAULT; + } + + up(&hif_drv->hSemGetLINKSPEED); +} + +s32 Handle_GetStatistics(struct host_if_drv *hif_drv, struct rf_info *pstrStatistics) +{ + struct wid strWIDList[5]; + u32 u32WidsCount = 0, result = 0; + + strWIDList[u32WidsCount].id = WID_LINKSPEED; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u8LinkSpeed; + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_RSSI; + strWIDList[u32WidsCount].type = WID_CHAR; + strWIDList[u32WidsCount].size = sizeof(char); + strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->s8RSSI; + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT; + strWIDList[u32WidsCount].type = WID_INT; + strWIDList[u32WidsCount].size = sizeof(u32); + strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u32TxCount; + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT; + strWIDList[u32WidsCount].type = WID_INT; + strWIDList[u32WidsCount].size = sizeof(u32); + strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u32RxCount; + u32WidsCount++; + + strWIDList[u32WidsCount].id = WID_FAILED_COUNT; + strWIDList[u32WidsCount].type = WID_INT; + strWIDList[u32WidsCount].size = sizeof(u32); + strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->u32TxFailureCount; + u32WidsCount++; + + result = send_config_pkt(GET_CFG, strWIDList, u32WidsCount, + get_id_from_handler(hif_drv)); + + if (result) + PRINT_ER("Failed to send scan paramters config packet\n"); + + up(&hif_sema_wait_response); + return 0; +} + +static s32 Handle_Get_InActiveTime(struct host_if_drv *hif_drv, + struct sta_inactive_t *strHostIfStaInactiveT) +{ + s32 result = 0; + u8 *stamac; + struct wid wid; + + wid.id = (u16)WID_SET_STA_MAC_INACTIVE_TIME; + wid.type = WID_STR; + wid.size = ETH_ALEN; + wid.val = kmalloc(wid.size, GFP_KERNEL); + + stamac = wid.val; + memcpy(stamac, strHostIfStaInactiveT->mac, ETH_ALEN); + + PRINT_D(CFG80211_DBG, "SETING STA inactive time\n"); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to SET incative time\n"); + return -EFAULT; + } + + wid.id = (u16)WID_GET_INACTIVE_TIME; + wid.type = WID_INT; + wid.val = (s8 *)&inactive_time; + wid.size = sizeof(u32); + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to get incative time\n"); + return -EFAULT; + } + + PRINT_D(CFG80211_DBG, "Getting inactive time : %d\n", inactive_time); + + up(&hif_drv->hSemInactiveTime); + + return result; +} + +static void Handle_AddBeacon(struct host_if_drv *hif_drv, + struct beacon_attr *pstrSetBeaconParam) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + + PRINT_D(HOSTINF_DBG, "Adding BEACON\n"); + + wid.id = (u16)WID_ADD_BEACON; + wid.type = WID_BIN; + wid.size = pstrSetBeaconParam->head_len + pstrSetBeaconParam->tail_len + 16; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + goto ERRORHANDLER; + + pu8CurrByte = wid.val; + *pu8CurrByte++ = (pstrSetBeaconParam->interval & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 24) & 0xFF); + + *pu8CurrByte++ = (pstrSetBeaconParam->dtim_period & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 24) & 0xFF); + + *pu8CurrByte++ = (pstrSetBeaconParam->head_len & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 24) & 0xFF); + + memcpy(pu8CurrByte, pstrSetBeaconParam->head, pstrSetBeaconParam->head_len); + pu8CurrByte += pstrSetBeaconParam->head_len; + + *pu8CurrByte++ = (pstrSetBeaconParam->tail_len & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 8) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 16) & 0xFF); + *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 24) & 0xFF); + + if (pstrSetBeaconParam->tail > 0) + memcpy(pu8CurrByte, pstrSetBeaconParam->tail, pstrSetBeaconParam->tail_len); + pu8CurrByte += pstrSetBeaconParam->tail_len; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send add beacon config packet\n"); + +ERRORHANDLER: + kfree(wid.val); + kfree(pstrSetBeaconParam->head); + kfree(pstrSetBeaconParam->tail); +} + +static void Handle_DelBeacon(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + + wid.id = (u16)WID_DEL_BEACON; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = &del_beacon; + + if (!wid.val) + return; + + pu8CurrByte = wid.val; + + PRINT_D(HOSTINF_DBG, "Deleting BEACON\n"); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send delete beacon config packet\n"); +} + +static u32 WILC_HostIf_PackStaParam(u8 *pu8Buffer, + struct add_sta_param *pstrStationParam) +{ + u8 *pu8CurrByte; + + pu8CurrByte = pu8Buffer; + + PRINT_D(HOSTINF_DBG, "Packing STA params\n"); + memcpy(pu8CurrByte, pstrStationParam->au8BSSID, ETH_ALEN); + pu8CurrByte += ETH_ALEN; + + *pu8CurrByte++ = pstrStationParam->u16AssocID & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16AssocID >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u8NumRates; + if (pstrStationParam->u8NumRates > 0) + memcpy(pu8CurrByte, pstrStationParam->pu8Rates, pstrStationParam->u8NumRates); + pu8CurrByte += pstrStationParam->u8NumRates; + + *pu8CurrByte++ = pstrStationParam->bIsHTSupported; + *pu8CurrByte++ = pstrStationParam->u16HTCapInfo & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16HTCapInfo >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u8AmpduParams; + memcpy(pu8CurrByte, pstrStationParam->au8SuppMCsSet, WILC_SUPP_MCS_SET_SIZE); + pu8CurrByte += WILC_SUPP_MCS_SET_SIZE; + + *pu8CurrByte++ = pstrStationParam->u16HTExtParams & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16HTExtParams >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u32TxBeamformingCap & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 8) & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 16) & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u32TxBeamformingCap >> 24) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u8ASELCap; + + *pu8CurrByte++ = pstrStationParam->u16FlagsMask & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16FlagsMask >> 8) & 0xFF; + + *pu8CurrByte++ = pstrStationParam->u16FlagsSet & 0xFF; + *pu8CurrByte++ = (pstrStationParam->u16FlagsSet >> 8) & 0xFF; + + return pu8CurrByte - pu8Buffer; +} + +static void Handle_AddStation(struct host_if_drv *hif_drv, + struct add_sta_param *pstrStationParam) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + + PRINT_D(HOSTINF_DBG, "Handling add station\n"); + wid.id = (u16)WID_ADD_STA; + wid.type = WID_BIN; + wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->u8NumRates; + + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + goto ERRORHANDLER; + + pu8CurrByte = wid.val; + pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result != 0) + PRINT_ER("Failed to send add station config packet\n"); + +ERRORHANDLER: + kfree(pstrStationParam->pu8Rates); + kfree(wid.val); +} + +static void Handle_DelAllSta(struct host_if_drv *hif_drv, + struct del_all_sta *pstrDelAllStaParam) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + u8 i; + u8 au8Zero_Buff[6] = {0}; + + wid.id = (u16)WID_DEL_ALL_STA; + wid.type = WID_STR; + wid.size = (pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1; + + PRINT_D(HOSTINF_DBG, "Handling delete station\n"); + + wid.val = kmalloc((pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL); + if (!wid.val) + goto ERRORHANDLER; + + pu8CurrByte = wid.val; + + *(pu8CurrByte++) = pstrDelAllStaParam->assoc_sta; + + for (i = 0; i < MAX_NUM_STA; i++) { + if (memcmp(pstrDelAllStaParam->del_all_sta[i], au8Zero_Buff, ETH_ALEN)) + memcpy(pu8CurrByte, pstrDelAllStaParam->del_all_sta[i], ETH_ALEN); + else + continue; + + pu8CurrByte += ETH_ALEN; + } + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send add station config packet\n"); + +ERRORHANDLER: + kfree(wid.val); + + up(&hif_sema_wait_response); +} + +static void Handle_DelStation(struct host_if_drv *hif_drv, + struct del_sta *pstrDelStaParam) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + + wid.id = (u16)WID_REMOVE_STA; + wid.type = WID_BIN; + wid.size = ETH_ALEN; + + PRINT_D(HOSTINF_DBG, "Handling delete station\n"); + + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + goto ERRORHANDLER; + + pu8CurrByte = wid.val; + + memcpy(pu8CurrByte, pstrDelStaParam->mac_addr, ETH_ALEN); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send add station config packet\n"); + +ERRORHANDLER: + kfree(wid.val); +} + +static void Handle_EditStation(struct host_if_drv *hif_drv, + struct add_sta_param *pstrStationParam) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + + wid.id = (u16)WID_EDIT_STA; + wid.type = WID_BIN; + wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->u8NumRates; + + PRINT_D(HOSTINF_DBG, "Handling edit station\n"); + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + goto ERRORHANDLER; + + pu8CurrByte = wid.val; + pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send edit station config packet\n"); + +ERRORHANDLER: + kfree(pstrStationParam->pu8Rates); + kfree(wid.val); +} + +static int Handle_RemainOnChan(struct host_if_drv *hif_drv, + struct remain_ch *pstrHostIfRemainOnChan) +{ + s32 result = 0; + u8 u8remain_on_chan_flag; + struct wid wid; + + if (!hif_drv->remain_on_ch_pending) { + hif_drv->remain_on_ch.pVoid = pstrHostIfRemainOnChan->pVoid; + hif_drv->remain_on_ch.pRemainOnChanExpired = pstrHostIfRemainOnChan->pRemainOnChanExpired; + hif_drv->remain_on_ch.pRemainOnChanReady = pstrHostIfRemainOnChan->pRemainOnChanReady; + hif_drv->remain_on_ch.u16Channel = pstrHostIfRemainOnChan->u16Channel; + hif_drv->remain_on_ch.u32ListenSessionID = pstrHostIfRemainOnChan->u32ListenSessionID; + } else { + pstrHostIfRemainOnChan->u16Channel = hif_drv->remain_on_ch.u16Channel; + } + + if (hif_drv->usr_scan_req.pfUserScanResult) { + PRINT_INFO(GENERIC_DBG, "Required to remain on chan while scanning return\n"); + hif_drv->remain_on_ch_pending = 1; + result = -EBUSY; + goto ERRORHANDLER; + } + if (hif_drv->enuHostIFstate == HOST_IF_WAITING_CONN_RESP) { + PRINT_INFO(GENERIC_DBG, "Required to remain on chan while connecting return\n"); + result = -EBUSY; + goto ERRORHANDLER; + } + + if (g_obtainingIP || connecting) { + PRINT_D(GENERIC_DBG, "[handle_scan]: Don't do obss scan until IP adresss is obtained\n"); + result = -EBUSY; + goto ERRORHANDLER; + } + + PRINT_D(HOSTINF_DBG, "Setting channel :%d\n", pstrHostIfRemainOnChan->u16Channel); + + u8remain_on_chan_flag = true; + wid.id = (u16)WID_REMAIN_ON_CHAN; + wid.type = WID_STR; + wid.size = 2; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) { + result = -ENOMEM; + goto ERRORHANDLER; + } + + wid.val[0] = u8remain_on_chan_flag; + wid.val[1] = (s8)pstrHostIfRemainOnChan->u16Channel; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result != 0) + PRINT_ER("Failed to set remain on channel\n"); + +ERRORHANDLER: + { + P2P_LISTEN_STATE = 1; + hif_drv->hRemainOnChannel.data = (unsigned long)hif_drv; + mod_timer(&hif_drv->hRemainOnChannel, + jiffies + + msecs_to_jiffies(pstrHostIfRemainOnChan->u32duration)); + + if (hif_drv->remain_on_ch.pRemainOnChanReady) + hif_drv->remain_on_ch.pRemainOnChanReady(hif_drv->remain_on_ch.pVoid); + + if (hif_drv->remain_on_ch_pending) + hif_drv->remain_on_ch_pending = 0; + } + + return result; +} + +static int Handle_RegisterFrame(struct host_if_drv *hif_drv, + struct reg_frame *pstrHostIfRegisterFrame) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + + PRINT_D(HOSTINF_DBG, "Handling frame register Flag : %d FrameType: %d\n", pstrHostIfRegisterFrame->bReg, pstrHostIfRegisterFrame->u16FrameType); + + wid.id = (u16)WID_REGISTER_FRAME; + wid.type = WID_STR; + wid.val = kmalloc(sizeof(u16) + 2, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + pu8CurrByte = wid.val; + + *pu8CurrByte++ = pstrHostIfRegisterFrame->bReg; + *pu8CurrByte++ = pstrHostIfRegisterFrame->u8Regid; + memcpy(pu8CurrByte, &pstrHostIfRegisterFrame->u16FrameType, + sizeof(u16)); + + wid.size = sizeof(u16) + 2; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) { + PRINT_ER("Failed to frame register config packet\n"); + result = -EINVAL; + } + + return result; +} + +static u32 Handle_ListenStateExpired(struct host_if_drv *hif_drv, + struct remain_ch *pstrHostIfRemainOnChan) +{ + u8 u8remain_on_chan_flag; + struct wid wid; + s32 result = 0; + + PRINT_D(HOSTINF_DBG, "CANCEL REMAIN ON CHAN\n"); + + if (P2P_LISTEN_STATE) { + u8remain_on_chan_flag = false; + wid.id = (u16)WID_REMAIN_ON_CHAN; + wid.type = WID_STR; + wid.size = 2; + wid.val = kmalloc(wid.size, GFP_KERNEL); + + if (!wid.val) + PRINT_ER("Failed to allocate memory\n"); + + wid.val[0] = u8remain_on_chan_flag; + wid.val[1] = FALSE_FRMWR_CHANNEL; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result != 0) { + PRINT_ER("Failed to set remain on channel\n"); + goto _done_; + } + + if (hif_drv->remain_on_ch.pRemainOnChanExpired) { + hif_drv->remain_on_ch.pRemainOnChanExpired(hif_drv->remain_on_ch.pVoid, + pstrHostIfRemainOnChan->u32ListenSessionID); + } + P2P_LISTEN_STATE = 0; + } else { + PRINT_D(GENERIC_DBG, "Not in listen state\n"); + result = -EFAULT; + } + +_done_: + return result; +} + +static void ListenTimerCB(unsigned long arg) +{ + s32 result = 0; + struct host_if_msg msg; + struct host_if_drv *hif_drv = (struct host_if_drv *)arg; + + del_timer(&hif_drv->hRemainOnChannel); + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_LISTEN_TIMER_FIRED; + msg.drv = hif_drv; + msg.body.remain_on_ch.u32ListenSessionID = hif_drv->remain_on_ch.u32ListenSessionID; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); +} + +static void Handle_PowerManagement(struct host_if_drv *hif_drv, + struct power_mgmt_param *strPowerMgmtParam) +{ + s32 result = 0; + struct wid wid; + s8 s8PowerMode; + + wid.id = (u16)WID_POWER_MANAGEMENT; + + if (strPowerMgmtParam->enabled) + s8PowerMode = MIN_FAST_PS; + else + s8PowerMode = NO_POWERSAVE; + PRINT_D(HOSTINF_DBG, "Handling power mgmt to %d\n", s8PowerMode); + wid.val = &s8PowerMode; + wid.size = sizeof(char); + + PRINT_D(HOSTINF_DBG, "Handling Power Management\n"); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send power management config packet\n"); +} + +static void Handle_SetMulticastFilter(struct host_if_drv *hif_drv, + struct set_multicast *strHostIfSetMulti) +{ + s32 result = 0; + struct wid wid; + u8 *pu8CurrByte; + + PRINT_D(HOSTINF_DBG, "Setup Multicast Filter\n"); + + wid.id = (u16)WID_SETUP_MULTICAST_FILTER; + wid.type = WID_BIN; + wid.size = sizeof(struct set_multicast) + ((strHostIfSetMulti->cnt) * ETH_ALEN); + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + goto ERRORHANDLER; + + pu8CurrByte = wid.val; + *pu8CurrByte++ = (strHostIfSetMulti->enabled & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->enabled >> 8) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->enabled >> 16) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->enabled >> 24) & 0xFF); + + *pu8CurrByte++ = (strHostIfSetMulti->cnt & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 8) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 16) & 0xFF); + *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 24) & 0xFF); + + if ((strHostIfSetMulti->cnt) > 0) + memcpy(pu8CurrByte, gau8MulticastMacAddrList, ((strHostIfSetMulti->cnt) * ETH_ALEN)); + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_ER("Failed to send setup multicast config packet\n"); + +ERRORHANDLER: + kfree(wid.val); +} + +static s32 Handle_AddBASession(struct host_if_drv *hif_drv, + struct ba_session_info *strHostIfBASessionInfo) +{ + s32 result = 0; + struct wid wid; + int AddbaTimeout = 100; + char *ptr = NULL; + + PRINT_D(HOSTINF_DBG, "Opening Block Ack session with\nBSSID = %.2x:%.2x:%.2x\nTID=%d\nBufferSize == %d\nSessionTimeOut = %d\n", + strHostIfBASessionInfo->au8Bssid[0], + strHostIfBASessionInfo->au8Bssid[1], + strHostIfBASessionInfo->au8Bssid[2], + strHostIfBASessionInfo->u16BufferSize, + strHostIfBASessionInfo->u16SessionTimeout, + strHostIfBASessionInfo->u8Ted); + + wid.id = (u16)WID_11E_P_ACTION_REQ; + wid.type = WID_STR; + wid.val = kmalloc(BLOCK_ACK_REQ_SIZE, GFP_KERNEL); + wid.size = BLOCK_ACK_REQ_SIZE; + ptr = wid.val; + *ptr++ = 0x14; + *ptr++ = 0x3; + *ptr++ = 0x0; + memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + *ptr++ = strHostIfBASessionInfo->u8Ted; + *ptr++ = 1; + *ptr++ = (strHostIfBASessionInfo->u16BufferSize & 0xFF); + *ptr++ = ((strHostIfBASessionInfo->u16BufferSize >> 16) & 0xFF); + *ptr++ = (strHostIfBASessionInfo->u16SessionTimeout & 0xFF); + *ptr++ = ((strHostIfBASessionInfo->u16SessionTimeout >> 16) & 0xFF); + *ptr++ = (AddbaTimeout & 0xFF); + *ptr++ = ((AddbaTimeout >> 16) & 0xFF); + *ptr++ = 8; + *ptr++ = 0; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_D(HOSTINF_DBG, "Couldn't open BA Session\n"); + + wid.id = (u16)WID_11E_P_ACTION_REQ; + wid.type = WID_STR; + wid.size = 15; + ptr = wid.val; + *ptr++ = 15; + *ptr++ = 7; + *ptr++ = 0x2; + memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + *ptr++ = strHostIfBASessionInfo->u8Ted; + *ptr++ = 8; + *ptr++ = (strHostIfBASessionInfo->u16BufferSize & 0xFF); + *ptr++ = ((strHostIfBASessionInfo->u16SessionTimeout >> 16) & 0xFF); + *ptr++ = 3; + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + kfree(wid.val); + + return result; +} + +static s32 Handle_DelAllRxBASessions(struct host_if_drv *hif_drv, + struct ba_session_info *strHostIfBASessionInfo) +{ + s32 result = 0; + struct wid wid; + char *ptr = NULL; + + PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x\nTID=%d\n", + strHostIfBASessionInfo->au8Bssid[0], + strHostIfBASessionInfo->au8Bssid[1], + strHostIfBASessionInfo->au8Bssid[2], + strHostIfBASessionInfo->u8Ted); + + wid.id = (u16)WID_DEL_ALL_RX_BA; + wid.type = WID_STR; + wid.val = kmalloc(BLOCK_ACK_REQ_SIZE, GFP_KERNEL); + wid.size = BLOCK_ACK_REQ_SIZE; + ptr = wid.val; + *ptr++ = 0x14; + *ptr++ = 0x3; + *ptr++ = 0x2; + memcpy(ptr, strHostIfBASessionInfo->au8Bssid, ETH_ALEN); + ptr += ETH_ALEN; + *ptr++ = strHostIfBASessionInfo->u8Ted; + *ptr++ = 0; + *ptr++ = 32; + + result = send_config_pkt(SET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) + PRINT_D(HOSTINF_DBG, "Couldn't delete BA Session\n"); + + kfree(wid.val); + + up(&hif_sema_wait_response); + + return result; +} + +static int hostIFthread(void *pvArg) +{ + u32 u32Ret; + struct host_if_msg msg; + struct host_if_drv *hif_drv; + + memset(&msg, 0, sizeof(struct host_if_msg)); + + while (1) { + wilc_mq_recv(&hif_msg_q, &msg, sizeof(struct host_if_msg), &u32Ret); + hif_drv = (struct host_if_drv *)msg.drv; + if (msg.id == HOST_IF_MSG_EXIT) { + PRINT_D(GENERIC_DBG, "THREAD: Exiting HostIfThread\n"); + break; + } + + if ((!g_wilc_initialized)) { + PRINT_D(GENERIC_DBG, "--WAIT--"); + usleep_range(200 * 1000, 200 * 1000); + wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + continue; + } + + if (msg.id == HOST_IF_MSG_CONNECT && + hif_drv->usr_scan_req.pfUserScanResult) { + PRINT_D(HOSTINF_DBG, "Requeue connect request till scan done received\n"); + wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + usleep_range(2 * 1000, 2 * 1000); + continue; + } + + switch (msg.id) { + case HOST_IF_MSG_Q_IDLE: + Handle_wait_msg_q_empty(); + break; + + case HOST_IF_MSG_SCAN: + Handle_Scan(msg.drv, &msg.body.scan_info); + break; + + case HOST_IF_MSG_CONNECT: + Handle_Connect(msg.drv, &msg.body.con_info); + break; + + case HOST_IF_MSG_FLUSH_CONNECT: + Handle_FlushConnect(msg.drv); + break; + + case HOST_IF_MSG_RCVD_NTWRK_INFO: + Handle_RcvdNtwrkInfo(msg.drv, &msg.body.net_info); + break; + + case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO: + Handle_RcvdGnrlAsyncInfo(msg.drv, &msg.body.async_info); + break; + + case HOST_IF_MSG_KEY: + Handle_Key(msg.drv, &msg.body.key_info); + break; + + case HOST_IF_MSG_CFG_PARAMS: + + Handle_CfgParam(msg.drv, &msg.body.cfg_info); + break; + + case HOST_IF_MSG_SET_CHANNEL: + Handle_SetChannel(msg.drv, &msg.body.channel_info); + break; + + case HOST_IF_MSG_DISCONNECT: + Handle_Disconnect(msg.drv); + break; + + case HOST_IF_MSG_RCVD_SCAN_COMPLETE: + del_timer(&hif_drv->hScanTimer); + PRINT_D(HOSTINF_DBG, "scan completed successfully\n"); + + if (!linux_wlan_get_num_conn_ifcs()) + chip_sleep_manually(INFINITE_SLEEP_TIME); + + Handle_ScanDone(msg.drv, SCAN_EVENT_DONE); + + if (hif_drv->remain_on_ch_pending) + Handle_RemainOnChan(msg.drv, &msg.body.remain_on_ch); + + break; + + case HOST_IF_MSG_GET_RSSI: + Handle_GetRssi(msg.drv); + break; + + case HOST_IF_MSG_GET_LINKSPEED: + Handle_GetLinkspeed(msg.drv); + break; + + case HOST_IF_MSG_GET_STATISTICS: + Handle_GetStatistics(msg.drv, (struct rf_info *)msg.body.data); + break; + + case HOST_IF_MSG_GET_CHNL: + Handle_GetChnl(msg.drv); + break; + + case HOST_IF_MSG_ADD_BEACON: + Handle_AddBeacon(msg.drv, &msg.body.beacon_info); + break; + + case HOST_IF_MSG_DEL_BEACON: + Handle_DelBeacon(msg.drv); + break; + + case HOST_IF_MSG_ADD_STATION: + Handle_AddStation(msg.drv, &msg.body.add_sta_info); + break; + + case HOST_IF_MSG_DEL_STATION: + Handle_DelStation(msg.drv, &msg.body.del_sta_info); + break; + + case HOST_IF_MSG_EDIT_STATION: + Handle_EditStation(msg.drv, &msg.body.edit_sta_info); + break; + + case HOST_IF_MSG_GET_INACTIVETIME: + Handle_Get_InActiveTime(msg.drv, &msg.body.mac_info); + break; + + case HOST_IF_MSG_SCAN_TIMER_FIRED: + PRINT_D(HOSTINF_DBG, "Scan Timeout\n"); + + Handle_ScanDone(msg.drv, SCAN_EVENT_ABORTED); + break; + + case HOST_IF_MSG_CONNECT_TIMER_FIRED: + PRINT_D(HOSTINF_DBG, "Connect Timeout\n"); + Handle_ConnectTimeout(msg.drv); + break; + + case HOST_IF_MSG_POWER_MGMT: + Handle_PowerManagement(msg.drv, &msg.body.pwr_mgmt_info); + break; + + case HOST_IF_MSG_SET_WFIDRV_HANDLER: + Handle_SetWfiDrvHandler(msg.drv, + &msg.body.drv); + break; + + case HOST_IF_MSG_SET_OPERATION_MODE: + Handle_SetOperationMode(msg.drv, &msg.body.mode); + break; + + case HOST_IF_MSG_SET_IPADDRESS: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_IPADDRESS\n"); + Handle_set_IPAddress(msg.drv, msg.body.ip_info.ip_addr, msg.body.ip_info.idx); + break; + + case HOST_IF_MSG_GET_IPADDRESS: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_IPADDRESS\n"); + Handle_get_IPAddress(msg.drv, msg.body.ip_info.ip_addr, msg.body.ip_info.idx); + break; + + case HOST_IF_MSG_SET_MAC_ADDRESS: + Handle_SetMacAddress(msg.drv, &msg.body.set_mac_info); + break; + + case HOST_IF_MSG_GET_MAC_ADDRESS: + Handle_GetMacAddress(msg.drv, &msg.body.get_mac_info); + break; + + case HOST_IF_MSG_REMAIN_ON_CHAN: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_REMAIN_ON_CHAN\n"); + Handle_RemainOnChan(msg.drv, &msg.body.remain_on_ch); + break; + + case HOST_IF_MSG_REGISTER_FRAME: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_REGISTER_FRAME\n"); + Handle_RegisterFrame(msg.drv, &msg.body.reg_frame); + break; + + case HOST_IF_MSG_LISTEN_TIMER_FIRED: + Handle_ListenStateExpired(msg.drv, &msg.body.remain_on_ch); + break; + + case HOST_IF_MSG_SET_MULTICAST_FILTER: + PRINT_D(HOSTINF_DBG, "HOST_IF_MSG_SET_MULTICAST_FILTER\n"); + Handle_SetMulticastFilter(msg.drv, &msg.body.multicast_info); + break; + + case HOST_IF_MSG_ADD_BA_SESSION: + Handle_AddBASession(msg.drv, &msg.body.session_info); + break; + + case HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS: + Handle_DelAllRxBASessions(msg.drv, &msg.body.session_info); + break; + + case HOST_IF_MSG_DEL_ALL_STA: + Handle_DelAllSta(msg.drv, &msg.body.del_all_sta_info); + break; + + default: + PRINT_ER("[Host Interface] undefined Received Msg ID\n"); + break; + } + } + + PRINT_D(HOSTINF_DBG, "Releasing thread exit semaphore\n"); + up(&hif_sema_thread); + return 0; +} + +static void TimerCB_Scan(unsigned long arg) +{ + void *pvArg = (void *)arg; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.drv = pvArg; + msg.id = HOST_IF_MSG_SCAN_TIMER_FIRED; + + wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); +} + +static void TimerCB_Connect(unsigned long arg) +{ + void *pvArg = (void *)arg; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.drv = pvArg; + msg.id = HOST_IF_MSG_CONNECT_TIMER_FIRED; + + wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); +} + +s32 host_int_remove_key(struct host_if_drv *hif_drv, const u8 *pu8StaAddress) +{ + struct wid wid; + + wid.id = (u16)WID_REMOVE_KEY; + wid.type = WID_STR; + wid.val = (s8 *)pu8StaAddress; + wid.size = 6; + + return 0; +} + +int host_int_remove_wep_key(struct host_if_drv *hif_drv, u8 index) +{ + int result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + result = -EFAULT; + PRINT_ER("Failed to send setup multicast config packet\n"); + return result; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_KEY; + msg.body.key_info.type = WEP; + msg.body.key_info.action = REMOVEKEY; + msg.drv = hif_drv; + msg.body.key_info.attr.wep.index = index; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Error in sending message queue : Request to remove WEP key\n"); + down(&hif_drv->hSemTestKeyBlock); + + return result; +} + +int host_int_set_wep_default_key(struct host_if_drv *hif_drv, u8 index) +{ + int result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + result = -EFAULT; + PRINT_ER("driver is null\n"); + return result; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_KEY; + msg.body.key_info.type = WEP; + msg.body.key_info.action = DEFAULTKEY; + msg.drv = hif_drv; + msg.body.key_info.attr.wep.index = index; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Error in sending message queue : Default key index\n"); + down(&hif_drv->hSemTestKeyBlock); + + return result; +} + +int host_int_add_wep_key_bss_sta(struct host_if_drv *hif_drv, + const u8 *key, + u8 len, + u8 index) +{ + int result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_KEY; + msg.body.key_info.type = WEP; + msg.body.key_info.action = ADDKEY; + msg.drv = hif_drv; + msg.body.key_info.attr.wep.key = kmemdup(key, len, GFP_KERNEL); + if (!msg.body.key_info.attr.wep.key) + return -ENOMEM; + + msg.body.key_info.attr.wep.key_len = len; + msg.body.key_info.attr.wep.index = index; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Error in sending message queue :WEP Key\n"); + down(&hif_drv->hSemTestKeyBlock); + + return result; +} + +int host_int_add_wep_key_bss_ap(struct host_if_drv *hif_drv, + const u8 *key, + u8 len, + u8 index, + u8 mode, + enum AUTHTYPE auth_type) +{ + int result = 0; + struct host_if_msg msg; + int i; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + if (INFO) { + for (i = 0; i < len; i++) + PRINT_INFO(HOSTAPD_DBG, "KEY is %x\n", key[i]); + } + msg.id = HOST_IF_MSG_KEY; + msg.body.key_info.type = WEP; + msg.body.key_info.action = ADDKEY_AP; + msg.drv = hif_drv; + msg.body.key_info.attr.wep.key = kmemdup(key, len, GFP_KERNEL); + if (!msg.body.key_info.attr.wep.key) + return -ENOMEM; + + msg.body.key_info.attr.wep.key_len = len; + msg.body.key_info.attr.wep.index = index; + msg.body.key_info.attr.wep.mode = mode; + msg.body.key_info.attr.wep.auth_type = auth_type; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + + if (result) + PRINT_ER("Error in sending message queue :WEP Key\n"); + down(&hif_drv->hSemTestKeyBlock); + + return result; +} + +s32 host_int_add_ptk(struct host_if_drv *hif_drv, const u8 *pu8Ptk, + u8 u8PtkKeylen, const u8 *mac_addr, + const u8 *pu8RxMic, const u8 *pu8TxMic, + u8 mode, u8 u8Ciphermode, u8 u8Idx) +{ + s32 result = 0; + struct host_if_msg msg; + u8 u8KeyLen = u8PtkKeylen; + u32 i; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + if (pu8RxMic) + u8KeyLen += RX_MIC_KEY_LEN; + + if (pu8TxMic) + u8KeyLen += TX_MIC_KEY_LEN; + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_KEY; + msg.body.key_info.type = WPAPtk; + if (mode == AP_MODE) { + msg.body.key_info.action = ADDKEY_AP; + msg.body.key_info.attr.wpa.index = u8Idx; + } + if (mode == STATION_MODE) + msg.body.key_info.action = ADDKEY; + + msg.body.key_info.attr.wpa.key = kmalloc(u8PtkKeylen, GFP_KERNEL); + memcpy(msg.body.key_info.attr.wpa.key, pu8Ptk, u8PtkKeylen); + + if (pu8RxMic) { + memcpy(msg.body.key_info.attr.wpa.key + 16, pu8RxMic, RX_MIC_KEY_LEN); + if (INFO) { + for (i = 0; i < RX_MIC_KEY_LEN; i++) + PRINT_INFO(CFG80211_DBG, "PairwiseRx[%d] = %x\n", i, pu8RxMic[i]); + } + } + if (pu8TxMic) { + memcpy(msg.body.key_info.attr.wpa.key + 24, pu8TxMic, TX_MIC_KEY_LEN); + if (INFO) { + for (i = 0; i < TX_MIC_KEY_LEN; i++) + PRINT_INFO(CFG80211_DBG, "PairwiseTx[%d] = %x\n", i, pu8TxMic[i]); + } + } + + msg.body.key_info.attr.wpa.key_len = u8KeyLen; + msg.body.key_info.attr.wpa.mac_addr = mac_addr; + msg.body.key_info.attr.wpa.mode = u8Ciphermode; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + + if (result) + PRINT_ER("Error in sending message queue: PTK Key\n"); + + down(&hif_drv->hSemTestKeyBlock); + + return result; +} + +s32 host_int_add_rx_gtk(struct host_if_drv *hif_drv, const u8 *pu8RxGtk, + u8 u8GtkKeylen, u8 u8KeyIdx, + u32 u32KeyRSClen, const u8 *KeyRSC, + const u8 *pu8RxMic, const u8 *pu8TxMic, + u8 mode, u8 u8Ciphermode) +{ + s32 result = 0; + struct host_if_msg msg; + u8 u8KeyLen = u8GtkKeylen; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + memset(&msg, 0, sizeof(struct host_if_msg)); + + if (pu8RxMic) + u8KeyLen += RX_MIC_KEY_LEN; + + if (pu8TxMic) + u8KeyLen += TX_MIC_KEY_LEN; + + if (KeyRSC) { + msg.body.key_info.attr.wpa.seq = kmalloc(u32KeyRSClen, GFP_KERNEL); + memcpy(msg.body.key_info.attr.wpa.seq, KeyRSC, u32KeyRSClen); + } + + msg.id = HOST_IF_MSG_KEY; + msg.body.key_info.type = WPARxGtk; + msg.drv = hif_drv; + + if (mode == AP_MODE) { + msg.body.key_info.action = ADDKEY_AP; + msg.body.key_info.attr.wpa.mode = u8Ciphermode; + } + if (mode == STATION_MODE) + msg.body.key_info.action = ADDKEY; + + msg.body.key_info.attr.wpa.key = kmalloc(u8KeyLen, GFP_KERNEL); + memcpy(msg.body.key_info.attr.wpa.key, pu8RxGtk, u8GtkKeylen); + + if (pu8RxMic) + memcpy(msg.body.key_info.attr.wpa.key + 16, pu8RxMic, + RX_MIC_KEY_LEN); + + if (pu8TxMic) + memcpy(msg.body.key_info.attr.wpa.key + 24, pu8TxMic, + TX_MIC_KEY_LEN); + + msg.body.key_info.attr.wpa.index = u8KeyIdx; + msg.body.key_info.attr.wpa.key_len = u8KeyLen; + msg.body.key_info.attr.wpa.seq_len = u32KeyRSClen; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Error in sending message queue: RX GTK\n"); + + down(&hif_drv->hSemTestKeyBlock); + + return result; +} + +s32 host_int_set_pmkid_info(struct host_if_drv *hif_drv, struct host_if_pmkid_attr *pu8PmkidInfoArray) +{ + s32 result = 0; + struct host_if_msg msg; + u32 i; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_KEY; + msg.body.key_info.type = PMKSA; + msg.body.key_info.action = ADDKEY; + msg.drv = hif_drv; + + for (i = 0; i < pu8PmkidInfoArray->numpmkid; i++) { + memcpy(msg.body.key_info.attr.pmkid.pmkidlist[i].bssid, + &pu8PmkidInfoArray->pmkidlist[i].bssid, ETH_ALEN); + memcpy(msg.body.key_info.attr.pmkid.pmkidlist[i].pmkid, + &pu8PmkidInfoArray->pmkidlist[i].pmkid, PMKID_LEN); + } + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER(" Error in sending messagequeue: PMKID Info\n"); + + return result; +} + +s32 host_int_get_pmkid_info(struct host_if_drv *hif_drv, + u8 *pu8PmkidInfoArray, + u32 u32PmkidInfoLen) +{ + struct wid wid; + + wid.id = (u16)WID_PMKID_INFO; + wid.type = WID_STR; + wid.size = u32PmkidInfoLen; + wid.val = pu8PmkidInfoArray; + + return 0; +} + +s32 host_int_set_RSNAConfigPSKPassPhrase(struct host_if_drv *hif_drv, + u8 *pu8PassPhrase, + u8 u8Psklength) +{ + struct wid wid; + + if ((u8Psklength > 7) && (u8Psklength < 65)) { + wid.id = (u16)WID_11I_PSK; + wid.type = WID_STR; + wid.val = pu8PassPhrase; + wid.size = u8Psklength; + } + + return 0; +} + +s32 host_int_get_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress) +{ + s32 result = 0; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_GET_MAC_ADDRESS; + msg.body.get_mac_info.mac_addr = pu8MacAddress; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Failed to send get mac address\n"); + return -EFAULT; + } + + down(&hif_sema_wait_response); + return result; +} + +s32 host_int_set_MacAddress(struct host_if_drv *hif_drv, u8 *pu8MacAddress) +{ + s32 result = 0; + struct host_if_msg msg; + + PRINT_D(GENERIC_DBG, "mac addr = %x:%x:%x\n", pu8MacAddress[0], pu8MacAddress[1], pu8MacAddress[2]); + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_SET_MAC_ADDRESS; + memcpy(msg.body.set_mac_info.mac_addr, pu8MacAddress, ETH_ALEN); + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Failed to send message queue: Set mac address\n"); + + return result; +} + +s32 host_int_get_RSNAConfigPSKPassPhrase(struct host_if_drv *hif_drv, + u8 *pu8PassPhrase, u8 u8Psklength) +{ + struct wid wid; + + wid.id = (u16)WID_11I_PSK; + wid.type = WID_STR; + wid.size = u8Psklength; + wid.val = pu8PassPhrase; + + return 0; +} + +s32 host_int_set_start_scan_req(struct host_if_drv *hif_drv, u8 scanSource) +{ + struct wid wid; + + wid.id = (u16)WID_START_SCAN_REQ; + wid.type = WID_CHAR; + wid.val = (s8 *)&scanSource; + wid.size = sizeof(char); + + return 0; +} + +s32 host_int_get_start_scan_req(struct host_if_drv *hif_drv, u8 *pu8ScanSource) +{ + struct wid wid; + + wid.id = (u16)WID_START_SCAN_REQ; + wid.type = WID_CHAR; + wid.val = (s8 *)pu8ScanSource; + wid.size = sizeof(char); + + return 0; +} + +s32 host_int_set_join_req(struct host_if_drv *hif_drv, u8 *pu8bssid, + const u8 *pu8ssid, size_t ssidLen, + const u8 *pu8IEs, size_t IEsLen, + wilc_connect_result pfConnectResult, void *pvUserArg, + u8 u8security, enum AUTHTYPE tenuAuth_type, + u8 u8channel, void *pJoinParams) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv || !pfConnectResult) { + PRINT_ER("Driver is null\n"); + return -EFAULT; + } + + if (!pJoinParams) { + PRINT_ER("Unable to Join - JoinParams is NULL\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_CONNECT; + + msg.body.con_info.security = u8security; + msg.body.con_info.auth_type = tenuAuth_type; + msg.body.con_info.ch = u8channel; + msg.body.con_info.result = pfConnectResult; + msg.body.con_info.arg = pvUserArg; + msg.body.con_info.params = pJoinParams; + msg.drv = hif_drv ; + + if (pu8bssid) { + msg.body.con_info.bssid = kmalloc(6, GFP_KERNEL); + memcpy(msg.body.con_info.bssid, pu8bssid, 6); + } + + if (pu8ssid) { + msg.body.con_info.ssid_len = ssidLen; + msg.body.con_info.ssid = kmalloc(ssidLen, GFP_KERNEL); + memcpy(msg.body.con_info.ssid, pu8ssid, ssidLen); + } + + if (pu8IEs) { + msg.body.con_info.ies_len = IEsLen; + msg.body.con_info.ies = kmalloc(IEsLen, GFP_KERNEL); + memcpy(msg.body.con_info.ies, pu8IEs, IEsLen); + } + if (hif_drv->enuHostIFstate < HOST_IF_CONNECTING) + hif_drv->enuHostIFstate = HOST_IF_CONNECTING; + else + PRINT_D(GENERIC_DBG, "Don't set state to 'connecting' as state is %d\n", hif_drv->enuHostIFstate); + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Failed to send message queue: Set join request\n"); + return -EFAULT; + } + + hif_drv->hConnectTimer.data = (unsigned long)hif_drv; + mod_timer(&hif_drv->hConnectTimer, + jiffies + msecs_to_jiffies(HOST_IF_CONNECT_TIMEOUT)); + + return result; +} + +s32 host_int_flush_join_req(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!join_req) + return -EFAULT; + + if (!hif_drv) { + PRINT_ER("Driver is null\n"); + return -EFAULT; + } + + msg.id = HOST_IF_MSG_FLUSH_CONNECT; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Failed to send message queue: Flush join request\n"); + return -EFAULT; + } + + return result; +} + +s32 host_int_disconnect(struct host_if_drv *hif_drv, u16 u16ReasonCode) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("Driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_DISCONNECT; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Failed to send message queue: disconnect\n"); + + down(&hif_drv->hSemTestDisconnectBlock); + + return result; +} + +s32 host_int_disconnect_station(struct host_if_drv *hif_drv, u8 assoc_id) +{ + struct wid wid; + + wid.id = (u16)WID_DISCONNECT; + wid.type = WID_CHAR; + wid.val = (s8 *)&assoc_id; + wid.size = sizeof(char); + + return 0; +} + +s32 host_int_get_assoc_req_info(struct host_if_drv *hif_drv, + u8 *pu8AssocReqInfo, + u32 u32AssocReqInfoLen) +{ + struct wid wid; + + wid.id = (u16)WID_ASSOC_REQ_INFO; + wid.type = WID_STR; + wid.val = pu8AssocReqInfo; + wid.size = u32AssocReqInfoLen; + + return 0; +} + +s32 host_int_get_assoc_res_info(struct host_if_drv *hif_drv, + u8 *pu8AssocRespInfo, + u32 u32MaxAssocRespInfoLen, + u32 *pu32RcvdAssocRespInfoLen) +{ + s32 result = 0; + struct wid wid; + + if (!hif_drv) { + PRINT_ER("Driver is null\n"); + return -EFAULT; + } + + wid.id = (u16)WID_ASSOC_RES_INFO; + wid.type = WID_STR; + wid.val = pu8AssocRespInfo; + wid.size = u32MaxAssocRespInfoLen; + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + if (result) { + *pu32RcvdAssocRespInfoLen = 0; + PRINT_ER("Failed to send association response config packet\n"); + return -EINVAL; + } else { + *pu32RcvdAssocRespInfoLen = wid.size; + } + + return result; +} + +s32 host_int_get_rx_power_level(struct host_if_drv *hif_drv, + u8 *pu8RxPowerLevel, + u32 u32RxPowerLevelLen) +{ + struct wid wid; + + wid.id = (u16)WID_RX_POWER_LEVEL; + wid.type = WID_STR; + wid.val = pu8RxPowerLevel; + wid.size = u32RxPowerLevelLen; + + return 0; +} + +int host_int_set_mac_chnl_num(struct host_if_drv *hif_drv, u8 channel) +{ + int result; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_SET_CHANNEL; + msg.body.channel_info.set_ch = channel; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("wilc mq send fail\n"); + return -EINVAL; + } + + return 0; +} + +int host_int_wait_msg_queue_idle(void) +{ + int result = 0; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_Q_IDLE; + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("wilc mq send fail\n"); + result = -EINVAL; + } + + down(&hif_sema_wait_response); + + return result; +} + +int host_int_set_wfi_drv_handler(struct host_if_drv *hif_drv) +{ + int result = 0; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_SET_WFIDRV_HANDLER; + msg.body.drv.handler = get_id_from_handler(hif_drv); + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("wilc mq send fail\n"); + result = -EINVAL; + } + + return result; +} + +int host_int_set_operation_mode(struct host_if_drv *hif_drv, u32 mode) +{ + int result = 0; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_SET_OPERATION_MODE; + msg.body.mode.mode = mode; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("wilc mq send fail\n"); + result = -EINVAL; + } + + return result; +} + +s32 host_int_get_host_chnl_num(struct host_if_drv *hif_drv, u8 *pu8ChNo) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_GET_CHNL; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc mq send fail\n"); + down(&hif_drv->hSemGetCHNL); + + *pu8ChNo = ch_no; + + return result; +} + +s32 host_int_get_inactive_time(struct host_if_drv *hif_drv, + const u8 *mac, u32 *pu32InactiveTime) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + memcpy(msg.body.mac_info.mac, mac, ETH_ALEN); + + msg.id = HOST_IF_MSG_GET_INACTIVETIME; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Failed to send get host channel param's message queue "); + + down(&hif_drv->hSemInactiveTime); + + *pu32InactiveTime = inactive_time; + + return result; +} + +s32 host_int_test_get_int_wid(struct host_if_drv *hif_drv, u32 *pu32TestMemAddr) +{ + s32 result = 0; + struct wid wid; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + wid.id = (u16)WID_MEMORY_ADDRESS; + wid.type = WID_INT; + wid.val = (s8 *)pu32TestMemAddr; + wid.size = sizeof(u32); + + result = send_config_pkt(GET_CFG, &wid, 1, + get_id_from_handler(hif_drv)); + + if (result) { + PRINT_ER("Failed to get wid value\n"); + return -EINVAL; + } else { + PRINT_D(HOSTINF_DBG, "Successfully got wid value\n"); + } + + return result; +} + +s32 host_int_get_rssi(struct host_if_drv *hif_drv, s8 *ps8Rssi) +{ + s32 result = 0; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_GET_RSSI; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Failed to send get host channel param's message queue "); + return -EFAULT; + } + + down(&hif_drv->hSemGetRSSI); + + if (!ps8Rssi) { + PRINT_ER("RSS pointer value is null"); + return -EFAULT; + } + + *ps8Rssi = rssi; + + return result; +} + +s32 host_int_get_link_speed(struct host_if_drv *hif_drv, s8 *ps8lnkspd) +{ + struct host_if_msg msg; + s32 result = 0; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_GET_LINKSPEED; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Failed to send GET_LINKSPEED to message queue "); + return -EFAULT; + } + + down(&hif_drv->hSemGetLINKSPEED); + + if (!ps8lnkspd) { + PRINT_ER("LINKSPEED pointer value is null"); + return -EFAULT; + } + + *ps8lnkspd = link_speed; + + return result; +} + +s32 host_int_get_statistics(struct host_if_drv *hif_drv, struct rf_info *pstrStatistics) +{ + s32 result = 0; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_GET_STATISTICS; + msg.body.data = (char *)pstrStatistics; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Failed to send get host channel param's message queue "); + return -EFAULT; + } + + down(&hif_sema_wait_response); + return result; +} + +s32 host_int_scan(struct host_if_drv *hif_drv, u8 u8ScanSource, + u8 u8ScanType, u8 *pu8ChnlFreqList, + u8 u8ChnlListLen, const u8 *pu8IEs, + size_t IEsLen, wilc_scan_result ScanResult, + void *pvUserArg, struct hidden_network *pstrHiddenNetwork) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv || !ScanResult) { + PRINT_ER("hif_drv or ScanResult = NULL\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_SCAN; + + if (pstrHiddenNetwork) { + msg.body.scan_info.hidden_network.pstrHiddenNetworkInfo = pstrHiddenNetwork->pstrHiddenNetworkInfo; + msg.body.scan_info.hidden_network.u8ssidnum = pstrHiddenNetwork->u8ssidnum; + + } else + PRINT_D(HOSTINF_DBG, "pstrHiddenNetwork IS EQUAL TO NULL\n"); + + msg.drv = hif_drv; + msg.body.scan_info.src = u8ScanSource; + msg.body.scan_info.type = u8ScanType; + msg.body.scan_info.result = ScanResult; + msg.body.scan_info.arg = pvUserArg; + + msg.body.scan_info.ch_list_len = u8ChnlListLen; + msg.body.scan_info.ch_freq_list = kmalloc(u8ChnlListLen, GFP_KERNEL); + memcpy(msg.body.scan_info.ch_freq_list, pu8ChnlFreqList, u8ChnlListLen); + + msg.body.scan_info.ies_len = IEsLen; + msg.body.scan_info.ies = kmalloc(IEsLen, GFP_KERNEL); + memcpy(msg.body.scan_info.ies, pu8IEs, IEsLen); + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Error in sending message queue\n"); + return -EINVAL; + } + + PRINT_D(HOSTINF_DBG, ">> Starting the SCAN timer\n"); + hif_drv->hScanTimer.data = (unsigned long)hif_drv; + mod_timer(&hif_drv->hScanTimer, + jiffies + msecs_to_jiffies(HOST_IF_SCAN_TIMEOUT)); + + return result; +} + +s32 hif_set_cfg(struct host_if_drv *hif_drv, + struct cfg_param_val *pstrCfgParamVal) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("hif_drv NULL\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_CFG_PARAMS; + msg.body.cfg_info.cfg_attr_info = *pstrCfgParamVal; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + + return result; +} + +s32 hif_get_cfg(struct host_if_drv *hif_drv, u16 u16WID, u16 *pu16WID_Value) +{ + s32 result = 0; + + down(&hif_drv->gtOsCfgValuesSem); + + if (!hif_drv) { + PRINT_ER("hif_drv NULL\n"); + return -EFAULT; + } + PRINT_D(HOSTINF_DBG, "Getting configuration parameters\n"); + switch (u16WID) { + case WID_BSS_TYPE: + *pu16WID_Value = (u16)hif_drv->strCfgValues.bss_type; + break; + + case WID_AUTH_TYPE: + *pu16WID_Value = (u16)hif_drv->strCfgValues.auth_type; + break; + + case WID_AUTH_TIMEOUT: + *pu16WID_Value = hif_drv->strCfgValues.auth_timeout; + break; + + case WID_POWER_MANAGEMENT: + *pu16WID_Value = (u16)hif_drv->strCfgValues.power_mgmt_mode; + break; + + case WID_SHORT_RETRY_LIMIT: + *pu16WID_Value = hif_drv->strCfgValues.short_retry_limit; + break; + + case WID_LONG_RETRY_LIMIT: + *pu16WID_Value = hif_drv->strCfgValues.long_retry_limit; + break; + + case WID_FRAG_THRESHOLD: + *pu16WID_Value = hif_drv->strCfgValues.frag_threshold; + break; + + case WID_RTS_THRESHOLD: + *pu16WID_Value = hif_drv->strCfgValues.rts_threshold; + break; + + case WID_PREAMBLE: + *pu16WID_Value = (u16)hif_drv->strCfgValues.preamble_type; + break; + + case WID_SHORT_SLOT_ALLOWED: + *pu16WID_Value = (u16) hif_drv->strCfgValues.short_slot_allowed; + break; + + case WID_11N_TXOP_PROT_DISABLE: + *pu16WID_Value = (u16)hif_drv->strCfgValues.txop_prot_disabled; + break; + + case WID_BEACON_INTERVAL: + *pu16WID_Value = hif_drv->strCfgValues.beacon_interval; + break; + + case WID_DTIM_PERIOD: + *pu16WID_Value = (u16)hif_drv->strCfgValues.dtim_period; + break; + + case WID_SITE_SURVEY: + *pu16WID_Value = (u16)hif_drv->strCfgValues.site_survey_enabled; + break; + + case WID_SITE_SURVEY_SCAN_TIME: + *pu16WID_Value = hif_drv->strCfgValues.site_survey_scan_time; + break; + + case WID_ACTIVE_SCAN_TIME: + *pu16WID_Value = hif_drv->strCfgValues.active_scan_time; + break; + + case WID_PASSIVE_SCAN_TIME: + *pu16WID_Value = hif_drv->strCfgValues.passive_scan_time; + break; + + case WID_CURRENT_TX_RATE: + *pu16WID_Value = hif_drv->strCfgValues.curr_tx_rate; + break; + + default: + break; + } + + up(&hif_drv->gtOsCfgValuesSem); + + return result; +} + +static void GetPeriodicRSSI(unsigned long arg) +{ + struct host_if_drv *hif_drv = (struct host_if_drv *)arg; + + if (!hif_drv) { + PRINT_ER("Driver handler is NULL\n"); + return; + } + + if (hif_drv->enuHostIFstate == HOST_IF_CONNECTED) { + s32 result = 0; + struct host_if_msg msg; + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_GET_RSSI; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) { + PRINT_ER("Failed to send get host channel param's message queue "); + return; + } + } + periodic_rssi.data = (unsigned long)hif_drv; + mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000)); +} + +s32 host_int_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) +{ + s32 result = 0; + struct host_if_drv *hif_drv; + int err; + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + PRINT_D(HOSTINF_DBG, "Initializing host interface for client %d\n", clients_count + 1); + + scan_while_connected = false; + + sema_init(&hif_sema_wait_response, 0); + + hif_drv = kzalloc(sizeof(struct host_if_drv), GFP_KERNEL); + if (!hif_drv) { + result = -ENOMEM; + goto _fail_; + } + *hif_drv_handler = hif_drv; + err = add_handler_in_list(hif_drv); + if (err) { + result = -EFAULT; + goto _fail_timer_2; + } + + g_obtainingIP = false; + + PRINT_D(HOSTINF_DBG, "Global handle pointer value=%p\n", hif_drv); + if (clients_count == 0) { + sema_init(&hif_sema_thread, 0); + sema_init(&hif_sema_driver, 0); + sema_init(&hif_sema_deinit, 1); + } + + sema_init(&hif_drv->hSemTestKeyBlock, 0); + sema_init(&hif_drv->hSemTestDisconnectBlock, 0); + sema_init(&hif_drv->hSemGetRSSI, 0); + sema_init(&hif_drv->hSemGetLINKSPEED, 0); + sema_init(&hif_drv->hSemGetCHNL, 0); + sema_init(&hif_drv->hSemInactiveTime, 0); + + PRINT_D(HOSTINF_DBG, "INIT: CLIENT COUNT %d\n", clients_count); + + if (clients_count == 0) { + result = wilc_mq_create(&hif_msg_q); + + if (result < 0) { + PRINT_ER("Failed to creat MQ\n"); + goto _fail_; + } + + hif_thread_handler = kthread_run(hostIFthread, wilc, + "WILC_kthread"); + + if (IS_ERR(hif_thread_handler)) { + PRINT_ER("Failed to creat Thread\n"); + result = -EFAULT; + goto _fail_mq_; + } + setup_timer(&periodic_rssi, GetPeriodicRSSI, + (unsigned long)hif_drv); + mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000)); + } + + setup_timer(&hif_drv->hScanTimer, TimerCB_Scan, 0); + + setup_timer(&hif_drv->hConnectTimer, TimerCB_Connect, 0); + + setup_timer(&hif_drv->hRemainOnChannel, ListenTimerCB, 0); + + sema_init(&hif_drv->gtOsCfgValuesSem, 1); + down(&hif_drv->gtOsCfgValuesSem); + + hif_drv->enuHostIFstate = HOST_IF_IDLE; + hif_drv->strCfgValues.site_survey_enabled = SITE_SURVEY_OFF; + hif_drv->strCfgValues.scan_source = DEFAULT_SCAN; + hif_drv->strCfgValues.active_scan_time = ACTIVE_SCAN_TIME; + hif_drv->strCfgValues.passive_scan_time = PASSIVE_SCAN_TIME; + hif_drv->strCfgValues.curr_tx_rate = AUTORATE; + + hif_drv->u64P2p_MgmtTimeout = 0; + + PRINT_INFO(HOSTINF_DBG, "Initialization values, Site survey value: %d\n Scan source: %d\n Active scan time: %d\n Passive scan time: %d\nCurrent tx Rate = %d\n", + + hif_drv->strCfgValues.site_survey_enabled, hif_drv->strCfgValues.scan_source, + hif_drv->strCfgValues.active_scan_time, hif_drv->strCfgValues.passive_scan_time, + hif_drv->strCfgValues.curr_tx_rate); + + up(&hif_drv->gtOsCfgValuesSem); + + clients_count++; + + return result; + +_fail_timer_2: + up(&hif_drv->gtOsCfgValuesSem); + del_timer_sync(&hif_drv->hConnectTimer); + del_timer_sync(&hif_drv->hScanTimer); + kthread_stop(hif_thread_handler); +_fail_mq_: + wilc_mq_destroy(&hif_msg_q); +_fail_: + return result; +} + +s32 host_int_deinit(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct host_if_msg msg; + int ret; + + if (!hif_drv) { + PRINT_ER("hif_drv = NULL\n"); + return 0; + } + + down(&hif_sema_deinit); + + terminated_handle = hif_drv; + PRINT_D(HOSTINF_DBG, "De-initializing host interface for client %d\n", clients_count); + + if (del_timer_sync(&hif_drv->hScanTimer)) + PRINT_D(HOSTINF_DBG, ">> Scan timer is active\n"); + + if (del_timer_sync(&hif_drv->hConnectTimer)) + PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n"); + + if (del_timer_sync(&periodic_rssi)) + PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n"); + + del_timer_sync(&hif_drv->hRemainOnChannel); + + host_int_set_wfi_drv_handler(NULL); + down(&hif_sema_driver); + + if (hif_drv->usr_scan_req.pfUserScanResult) { + hif_drv->usr_scan_req.pfUserScanResult(SCAN_EVENT_ABORTED, NULL, + hif_drv->usr_scan_req.u32UserScanPvoid, NULL); + + hif_drv->usr_scan_req.pfUserScanResult = NULL; + } + + hif_drv->enuHostIFstate = HOST_IF_IDLE; + + scan_while_connected = false; + + memset(&msg, 0, sizeof(struct host_if_msg)); + + if (clients_count == 1) { + if (del_timer_sync(&periodic_rssi)) + PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n"); + + msg.id = HOST_IF_MSG_EXIT; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result != 0) + PRINT_ER("Error in sending deinit's message queue message function: Error(%d)\n", result); + + down(&hif_sema_thread); + + wilc_mq_destroy(&hif_msg_q); + } + + down(&hif_drv->gtOsCfgValuesSem); + + ret = remove_handler_in_list(hif_drv); + if (ret) + result = -ENOENT; + + kfree(hif_drv); + + clients_count--; + terminated_handle = NULL; + up(&hif_sema_deinit); + return result; +} + +void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length) +{ + s32 result = 0; + struct host_if_msg msg; + int id; + struct host_if_drv *hif_drv = NULL; + + id = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); + hif_drv = get_handler_from_id(id); + + if (!hif_drv || hif_drv == terminated_handle) { + PRINT_ER("NetworkInfo received but driver not init[%p]\n", hif_drv); + return; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_RCVD_NTWRK_INFO; + msg.drv = hif_drv; + + msg.body.net_info.len = u32Length; + msg.body.net_info.buffer = kmalloc(u32Length, GFP_KERNEL); + memcpy(msg.body.net_info.buffer, pu8Buffer, u32Length); + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Error in sending network info message queue message parameters: Error(%d)\n", result); +} + +void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length) +{ + s32 result = 0; + struct host_if_msg msg; + int id; + struct host_if_drv *hif_drv = NULL; + + down(&hif_sema_deinit); + + id = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); + hif_drv = get_handler_from_id(id); + PRINT_D(HOSTINF_DBG, "General asynchronous info packet received\n"); + + if (!hif_drv || hif_drv == terminated_handle) { + PRINT_D(HOSTINF_DBG, "Wifi driver handler is equal to NULL\n"); + up(&hif_sema_deinit); + return; + } + + if (!hif_drv->usr_conn_req.pfUserConnectResult) { + PRINT_ER("Received mac status is not needed when there is no current Connect Reques\n"); + up(&hif_sema_deinit); + return; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO; + msg.drv = hif_drv; + + msg.body.async_info.len = u32Length; + msg.body.async_info.buffer = kmalloc(u32Length, GFP_KERNEL); + memcpy(msg.body.async_info.buffer, pu8Buffer, u32Length); + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Error in sending message queue asynchronous message info: Error(%d)\n", result); + + up(&hif_sema_deinit); +} + +void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length) +{ + s32 result = 0; + struct host_if_msg msg; + int id; + struct host_if_drv *hif_drv = NULL; + + id = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); + hif_drv = get_handler_from_id(id); + + PRINT_D(GENERIC_DBG, "Scan notification received %p\n", hif_drv); + + if (!hif_drv || hif_drv == terminated_handle) + return; + + if (hif_drv->usr_scan_req.pfUserScanResult) { + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_RCVD_SCAN_COMPLETE; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("Error in sending message queue scan complete parameters: Error(%d)\n", result); + } + + return; +} + +s32 host_int_remain_on_channel(struct host_if_drv *hif_drv, u32 u32SessionID, + u32 u32duration, u16 chan, + wilc_remain_on_chan_expired RemainOnChanExpired, + wilc_remain_on_chan_ready RemainOnChanReady, + void *pvUserArg) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_REMAIN_ON_CHAN; + msg.body.remain_on_ch.u16Channel = chan; + msg.body.remain_on_ch.pRemainOnChanExpired = RemainOnChanExpired; + msg.body.remain_on_ch.pRemainOnChanReady = RemainOnChanReady; + msg.body.remain_on_ch.pVoid = pvUserArg; + msg.body.remain_on_ch.u32duration = u32duration; + msg.body.remain_on_ch.u32ListenSessionID = u32SessionID; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc mq send fail\n"); + + return result; +} + +s32 host_int_ListenStateExpired(struct host_if_drv *hif_drv, u32 u32SessionID) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + del_timer(&hif_drv->hRemainOnChannel); + + memset(&msg, 0, sizeof(struct host_if_msg)); + msg.id = HOST_IF_MSG_LISTEN_TIMER_FIRED; + msg.drv = hif_drv; + msg.body.remain_on_ch.u32ListenSessionID = u32SessionID; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc mq send fail\n"); + + return result; +} + +s32 host_int_frame_register(struct host_if_drv *hif_drv, u16 u16FrameType, bool bReg) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_REGISTER_FRAME; + switch (u16FrameType) { + case ACTION: + PRINT_D(HOSTINF_DBG, "ACTION\n"); + msg.body.reg_frame.u8Regid = ACTION_FRM_IDX; + break; + + case PROBE_REQ: + PRINT_D(HOSTINF_DBG, "PROBE REQ\n"); + msg.body.reg_frame.u8Regid = PROBE_REQ_IDX; + break; + + default: + PRINT_D(HOSTINF_DBG, "Not valid frame type\n"); + break; + } + msg.body.reg_frame.u16FrameType = u16FrameType; + msg.body.reg_frame.bReg = bReg; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc mq send fail\n"); + + return result; +} + +s32 host_int_add_beacon(struct host_if_drv *hif_drv, u32 u32Interval, + u32 u32DTIMPeriod, u32 u32HeadLen, u8 *pu8Head, + u32 u32TailLen, u8 *pu8Tail) +{ + s32 result = 0; + struct host_if_msg msg; + struct beacon_attr *pstrSetBeaconParam = &msg.body.beacon_info; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + PRINT_D(HOSTINF_DBG, "Setting adding beacon message queue params\n"); + + msg.id = HOST_IF_MSG_ADD_BEACON; + msg.drv = hif_drv; + pstrSetBeaconParam->interval = u32Interval; + pstrSetBeaconParam->dtim_period = u32DTIMPeriod; + pstrSetBeaconParam->head_len = u32HeadLen; + pstrSetBeaconParam->head = kmemdup(pu8Head, u32HeadLen, GFP_KERNEL); + if (!pstrSetBeaconParam->head) { + result = -ENOMEM; + goto ERRORHANDLER; + } + pstrSetBeaconParam->tail_len = u32TailLen; + + if (u32TailLen > 0) { + pstrSetBeaconParam->tail = kmemdup(pu8Tail, u32TailLen, + GFP_KERNEL); + if (!pstrSetBeaconParam->tail) { + result = -ENOMEM; + goto ERRORHANDLER; + } + } else { + pstrSetBeaconParam->tail = NULL; + } + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc mq send fail\n"); + +ERRORHANDLER: + if (result) { + kfree(pstrSetBeaconParam->head); + + kfree(pstrSetBeaconParam->tail); + } + + return result; +} + +s32 host_int_del_beacon(struct host_if_drv *hif_drv) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + msg.id = HOST_IF_MSG_DEL_BEACON; + msg.drv = hif_drv; + PRINT_D(HOSTINF_DBG, "Setting deleting beacon message queue params\n"); + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + + return result; +} + +s32 host_int_add_station(struct host_if_drv *hif_drv, + struct add_sta_param *pstrStaParams) +{ + s32 result = 0; + struct host_if_msg msg; + struct add_sta_param *pstrAddStationMsg = &msg.body.add_sta_info; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + PRINT_D(HOSTINF_DBG, "Setting adding station message queue params\n"); + + msg.id = HOST_IF_MSG_ADD_STATION; + msg.drv = hif_drv; + + memcpy(pstrAddStationMsg, pstrStaParams, sizeof(struct add_sta_param)); + if (pstrAddStationMsg->u8NumRates > 0) { + u8 *rates = kmalloc(pstrAddStationMsg->u8NumRates, GFP_KERNEL); + + if (!rates) + return -ENOMEM; + + memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates); + pstrAddStationMsg->pu8Rates = rates; + } + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + return result; +} + +s32 host_int_del_station(struct host_if_drv *hif_drv, const u8 *pu8MacAddr) +{ + s32 result = 0; + struct host_if_msg msg; + struct del_sta *pstrDelStationMsg = &msg.body.del_sta_info; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + PRINT_D(HOSTINF_DBG, "Setting deleting station message queue params\n"); + + msg.id = HOST_IF_MSG_DEL_STATION; + msg.drv = hif_drv; + + if (!pu8MacAddr) + eth_broadcast_addr(pstrDelStationMsg->mac_addr); + else + memcpy(pstrDelStationMsg->mac_addr, pu8MacAddr, ETH_ALEN); + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + return result; +} + +s32 host_int_del_allstation(struct host_if_drv *hif_drv, + u8 pu8MacAddr[][ETH_ALEN]) +{ + s32 result = 0; + struct host_if_msg msg; + struct del_all_sta *pstrDelAllStationMsg = &msg.body.del_all_sta_info; + u8 au8Zero_Buff[ETH_ALEN] = {0}; + u32 i; + u8 u8AssocNumb = 0; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + PRINT_D(HOSTINF_DBG, "Setting deauthenticating station message queue params\n"); + + msg.id = HOST_IF_MSG_DEL_ALL_STA; + msg.drv = hif_drv; + + for (i = 0; i < MAX_NUM_STA; i++) { + if (memcmp(pu8MacAddr[i], au8Zero_Buff, ETH_ALEN)) { + memcpy(pstrDelAllStationMsg->del_all_sta[i], pu8MacAddr[i], ETH_ALEN); + PRINT_D(CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", + pstrDelAllStationMsg->del_all_sta[i][0], + pstrDelAllStationMsg->del_all_sta[i][1], + pstrDelAllStationMsg->del_all_sta[i][2], + pstrDelAllStationMsg->del_all_sta[i][3], + pstrDelAllStationMsg->del_all_sta[i][4], + pstrDelAllStationMsg->del_all_sta[i][5]); + u8AssocNumb++; + } + } + if (!u8AssocNumb) { + PRINT_D(CFG80211_DBG, "NO ASSOCIATED STAS\n"); + return result; + } + + pstrDelAllStationMsg->assoc_sta = u8AssocNumb; + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + + if (result) + PRINT_ER("wilc_mq_send fail\n"); + + down(&hif_sema_wait_response); + + return result; +} + +s32 host_int_edit_station(struct host_if_drv *hif_drv, + struct add_sta_param *pstrStaParams) +{ + s32 result = 0; + struct host_if_msg msg; + struct add_sta_param *pstrAddStationMsg = &msg.body.add_sta_info; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + PRINT_D(HOSTINF_DBG, "Setting editing station message queue params\n"); + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_EDIT_STATION; + msg.drv = hif_drv; + + memcpy(pstrAddStationMsg, pstrStaParams, sizeof(struct add_sta_param)); + if (pstrAddStationMsg->u8NumRates > 0) { + u8 *rates = kmalloc(pstrAddStationMsg->u8NumRates, GFP_KERNEL); + + if (!rates) + return -ENOMEM; + + memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates); + pstrAddStationMsg->pu8Rates = rates; + } + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + + return result; +} + +s32 host_int_set_power_mgmt(struct host_if_drv *hif_drv, + bool bIsEnabled, + u32 u32Timeout) +{ + s32 result = 0; + struct host_if_msg msg; + struct power_mgmt_param *pstrPowerMgmtParam = &msg.body.pwr_mgmt_info; + + PRINT_INFO(HOSTINF_DBG, "\n\n>> Setting PS to %d <<\n\n", bIsEnabled); + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + PRINT_D(HOSTINF_DBG, "Setting Power management message queue params\n"); + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_POWER_MGMT; + msg.drv = hif_drv; + + pstrPowerMgmtParam->enabled = bIsEnabled; + pstrPowerMgmtParam->timeout = u32Timeout; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + return result; +} + +s32 host_int_setup_multicast_filter(struct host_if_drv *hif_drv, + bool bIsEnabled, + u32 u32count) +{ + s32 result = 0; + struct host_if_msg msg; + struct set_multicast *pstrMulticastFilterParam = &msg.body.multicast_info; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + PRINT_D(HOSTINF_DBG, "Setting Multicast Filter params\n"); + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_SET_MULTICAST_FILTER; + msg.drv = hif_drv; + + pstrMulticastFilterParam->enabled = bIsEnabled; + pstrMulticastFilterParam->cnt = u32count; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + return result; +} + +static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) +{ + struct join_bss_param *pNewJoinBssParam = NULL; + u8 *pu8IEs; + u16 u16IEsLen; + u16 index = 0; + u8 suppRatesNo = 0; + u8 extSuppRatesNo; + u16 jumpOffset; + u8 pcipherCount; + u8 authCount; + u8 pcipherTotalCount = 0; + u8 authTotalCount = 0; + u8 i, j; + + pu8IEs = ptstrNetworkInfo->pu8IEs; + u16IEsLen = ptstrNetworkInfo->u16IEsLen; + + pNewJoinBssParam = kzalloc(sizeof(struct join_bss_param), GFP_KERNEL); + if (pNewJoinBssParam) { + pNewJoinBssParam->dtim_period = ptstrNetworkInfo->u8DtimPeriod; + pNewJoinBssParam->beacon_period = ptstrNetworkInfo->u16BeaconPeriod; + pNewJoinBssParam->cap_info = ptstrNetworkInfo->u16CapInfo; + memcpy(pNewJoinBssParam->au8bssid, ptstrNetworkInfo->au8bssid, 6); + memcpy((u8 *)pNewJoinBssParam->ssid, ptstrNetworkInfo->au8ssid, ptstrNetworkInfo->u8SsidLen + 1); + pNewJoinBssParam->ssid_len = ptstrNetworkInfo->u8SsidLen; + memset(pNewJoinBssParam->rsn_pcip_policy, 0xFF, 3); + memset(pNewJoinBssParam->rsn_auth_policy, 0xFF, 3); + + while (index < u16IEsLen) { + if (pu8IEs[index] == SUPP_RATES_IE) { + suppRatesNo = pu8IEs[index + 1]; + pNewJoinBssParam->supp_rates[0] = suppRatesNo; + index += 2; + + for (i = 0; i < suppRatesNo; i++) + pNewJoinBssParam->supp_rates[i + 1] = pu8IEs[index + i]; + + index += suppRatesNo; + continue; + } else if (pu8IEs[index] == EXT_SUPP_RATES_IE) { + extSuppRatesNo = pu8IEs[index + 1]; + if (extSuppRatesNo > (MAX_RATES_SUPPORTED - suppRatesNo)) + pNewJoinBssParam->supp_rates[0] = MAX_RATES_SUPPORTED; + else + pNewJoinBssParam->supp_rates[0] += extSuppRatesNo; + index += 2; + for (i = 0; i < (pNewJoinBssParam->supp_rates[0] - suppRatesNo); i++) + pNewJoinBssParam->supp_rates[suppRatesNo + i + 1] = pu8IEs[index + i]; + + index += extSuppRatesNo; + continue; + } else if (pu8IEs[index] == HT_CAPABILITY_IE) { + pNewJoinBssParam->ht_capable = true; + index += pu8IEs[index + 1] + 2; + continue; + } else if ((pu8IEs[index] == WMM_IE) && + (pu8IEs[index + 2] == 0x00) && (pu8IEs[index + 3] == 0x50) && + (pu8IEs[index + 4] == 0xF2) && + (pu8IEs[index + 5] == 0x02) && + ((pu8IEs[index + 6] == 0x00) || (pu8IEs[index + 6] == 0x01)) && + (pu8IEs[index + 7] == 0x01)) { + pNewJoinBssParam->wmm_cap = true; + + if (pu8IEs[index + 8] & BIT(7)) + pNewJoinBssParam->uapsd_cap = true; + index += pu8IEs[index + 1] + 2; + continue; + } else if ((pu8IEs[index] == P2P_IE) && + (pu8IEs[index + 2] == 0x50) && (pu8IEs[index + 3] == 0x6f) && + (pu8IEs[index + 4] == 0x9a) && + (pu8IEs[index + 5] == 0x09) && (pu8IEs[index + 6] == 0x0c)) { + u16 u16P2P_count; + + pNewJoinBssParam->tsf = ptstrNetworkInfo->u32Tsf; + pNewJoinBssParam->noa_enabled = 1; + pNewJoinBssParam->idx = pu8IEs[index + 9]; + + if (pu8IEs[index + 10] & BIT(7)) { + pNewJoinBssParam->opp_enabled = 1; + pNewJoinBssParam->ct_window = pu8IEs[index + 10]; + } else { + pNewJoinBssParam->opp_enabled = 0; + } + + PRINT_D(GENERIC_DBG, "P2P Dump\n"); + for (i = 0; i < pu8IEs[index + 7]; i++) + PRINT_D(GENERIC_DBG, " %x\n", pu8IEs[index + 9 + i]); + + pNewJoinBssParam->cnt = pu8IEs[index + 11]; + u16P2P_count = index + 12; + + memcpy(pNewJoinBssParam->duration, pu8IEs + u16P2P_count, 4); + u16P2P_count += 4; + + memcpy(pNewJoinBssParam->interval, pu8IEs + u16P2P_count, 4); + u16P2P_count += 4; + + memcpy(pNewJoinBssParam->start_time, pu8IEs + u16P2P_count, 4); + + index += pu8IEs[index + 1] + 2; + continue; + + } else if ((pu8IEs[index] == RSN_IE) || + ((pu8IEs[index] == WPA_IE) && (pu8IEs[index + 2] == 0x00) && + (pu8IEs[index + 3] == 0x50) && (pu8IEs[index + 4] == 0xF2) && + (pu8IEs[index + 5] == 0x01))) { + u16 rsnIndex = index; + + if (pu8IEs[rsnIndex] == RSN_IE) { + pNewJoinBssParam->mode_802_11i = 2; + } else { + if (pNewJoinBssParam->mode_802_11i == 0) + pNewJoinBssParam->mode_802_11i = 1; + rsnIndex += 4; + } + + rsnIndex += 7; + pNewJoinBssParam->rsn_grp_policy = pu8IEs[rsnIndex]; + rsnIndex++; + jumpOffset = pu8IEs[rsnIndex] * 4; + pcipherCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex]; + rsnIndex += 2; + + for (i = pcipherTotalCount, j = 0; i < pcipherCount + pcipherTotalCount && i < 3; i++, j++) + pNewJoinBssParam->rsn_pcip_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1]; + + pcipherTotalCount += pcipherCount; + rsnIndex += jumpOffset; + + jumpOffset = pu8IEs[rsnIndex] * 4; + + authCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex]; + rsnIndex += 2; + + for (i = authTotalCount, j = 0; i < authTotalCount + authCount; i++, j++) + pNewJoinBssParam->rsn_auth_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1]; + + authTotalCount += authCount; + rsnIndex += jumpOffset; + + if (pu8IEs[index] == RSN_IE) { + pNewJoinBssParam->rsn_cap[0] = pu8IEs[rsnIndex]; + pNewJoinBssParam->rsn_cap[1] = pu8IEs[rsnIndex + 1]; + rsnIndex += 2; + } + pNewJoinBssParam->rsn_found = true; + index += pu8IEs[index + 1] + 2; + continue; + } else + index += pu8IEs[index + 1] + 2; + } + } + + return (void *)pNewJoinBssParam; +} + +void host_int_freeJoinParams(void *pJoinParams) +{ + if ((struct bss_param *)pJoinParams) + kfree((struct bss_param *)pJoinParams); + else + PRINT_ER("Unable to FREE null pointer\n"); +} + +s32 host_int_delBASession(struct host_if_drv *hif_drv, char *pBSSID, char TID) +{ + s32 result = 0; + struct host_if_msg msg; + struct ba_session_info *pBASessionInfo = &msg.body.session_info; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_DEL_BA_SESSION; + + memcpy(pBASessionInfo->au8Bssid, pBSSID, ETH_ALEN); + pBASessionInfo->u8Ted = TID; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + + down(&hif_sema_wait_response); + + return result; +} + +s32 host_int_del_All_Rx_BASession(struct host_if_drv *hif_drv, + char *pBSSID, + char TID) +{ + s32 result = 0; + struct host_if_msg msg; + struct ba_session_info *pBASessionInfo = &msg.body.session_info; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS; + + memcpy(pBASessionInfo->au8Bssid, pBSSID, ETH_ALEN); + pBASessionInfo->u8Ted = TID; + msg.drv = hif_drv; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + + down(&hif_sema_wait_response); + + return result; +} + +s32 host_int_setup_ipaddress(struct host_if_drv *hif_drv, u8 *u16ipadd, u8 idx) +{ + s32 result = 0; + struct host_if_msg msg; + + return 0; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_SET_IPADDRESS; + + msg.body.ip_info.ip_addr = u16ipadd; + msg.drv = hif_drv; + msg.body.ip_info.idx = idx; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + + return result; +} + +s32 host_int_get_ipaddress(struct host_if_drv *hif_drv, u8 *u16ipadd, u8 idx) +{ + s32 result = 0; + struct host_if_msg msg; + + if (!hif_drv) { + PRINT_ER("driver is null\n"); + return -EFAULT; + } + + memset(&msg, 0, sizeof(struct host_if_msg)); + + msg.id = HOST_IF_MSG_GET_IPADDRESS; + + msg.body.ip_info.ip_addr = u16ipadd; + msg.drv = hif_drv; + msg.body.ip_info.idx = idx; + + result = wilc_mq_send(&hif_msg_q, &msg, sizeof(struct host_if_msg)); + if (result) + PRINT_ER("wilc_mq_send fail\n"); + + return result; +} diff --git a/kernel/drivers/staging/wilc1000/host_interface.h b/kernel/drivers/staging/wilc1000/host_interface.h new file mode 100644 index 000000000..b854db5ac --- /dev/null +++ b/kernel/drivers/staging/wilc1000/host_interface.h @@ -0,0 +1,1130 @@ +/*! + * @file host_interface.h + * @brief File containg host interface APIs + * @author zsalah + * @sa host_interface.c + * @date 8 March 2012 + * @version 1.0 + */ + +#ifndef HOST_INT_H +#define HOST_INT_H + +#include "coreconfigurator.h" + +#define IP_ALEN 4 + +#define IDLE_MODE 0x00 +#define AP_MODE 0x01 +#define STATION_MODE 0x02 +#define GO_MODE 0x03 +#define CLIENT_MODE 0x04 + + +#define MAX_NUM_STA 9 +#define ACTIVE_SCAN_TIME 10 +#define PASSIVE_SCAN_TIME 1200 +#define MIN_SCAN_TIME 10 +#define MAX_SCAN_TIME 1200 +#define DEFAULT_SCAN 0 +#define USER_SCAN BIT(0) +#define OBSS_PERIODIC_SCAN BIT(1) +#define OBSS_ONETIME_SCAN BIT(2) +#define GTK_RX_KEY_BUFF_LEN 24 +#define ADDKEY 0x1 +#define REMOVEKEY 0x2 +#define DEFAULTKEY 0x4 +#define ADDKEY_AP 0x8 +#define MAX_NUM_SCANNED_NETWORKS 100 +#define MAX_NUM_SCANNED_NETWORKS_SHADOW 130 +#define MAX_NUM_PROBED_SSID 10 +#define CHANNEL_SCAN_TIME 250 + +#define TX_MIC_KEY_LEN 8 +#define RX_MIC_KEY_LEN 8 +#define PTK_KEY_LEN 16 + +#define TX_MIC_KEY_MSG_LEN 26 +#define RX_MIC_KEY_MSG_LEN 48 +#define PTK_KEY_MSG_LEN 39 + +#define PMKSA_KEY_LEN 22 +#define ETH_ALEN 6 +#define PMKID_LEN 16 +#define WILC_MAX_NUM_PMKIDS 16 +#define WILC_SUPP_MCS_SET_SIZE 16 +#define WILC_ADD_STA_LENGTH 40 +#define SCAN_EVENT_DONE_ABORTED +#define NUM_CONCURRENT_IFC 2 + +struct rf_info { + u8 u8LinkSpeed; + s8 s8RSSI; + u32 u32TxCount; + u32 u32RxCount; + u32 u32TxFailureCount; +}; + +enum host_if_state { + HOST_IF_IDLE = 0, + HOST_IF_SCANNING = 1, + HOST_IF_CONNECTING = 2, + HOST_IF_WAITING_CONN_RESP = 3, + HOST_IF_CONNECTED = 4, + HOST_IF_P2P_LISTEN = 5, + HOST_IF_FORCE_32BIT = 0xFFFFFFFF +}; + +struct host_if_pmkid { + u8 bssid[ETH_ALEN]; + u8 pmkid[PMKID_LEN]; +}; + +struct host_if_pmkid_attr { + u8 numpmkid; + struct host_if_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS]; +}; + +enum CURRENT_TXRATE { + AUTORATE = 0, + MBPS_1 = 1, + MBPS_2 = 2, + MBPS_5_5 = 5, + MBPS_11 = 11, + MBPS_6 = 6, + MBPS_9 = 9, + MBPS_12 = 12, + MBPS_18 = 18, + MBPS_24 = 24, + MBPS_36 = 36, + MBPS_48 = 48, + MBPS_54 = 54 +}; + +struct cfg_param_val { + u32 flag; + u8 ht_enable; + u8 bss_type; + u8 auth_type; + u16 auth_timeout; + u8 power_mgmt_mode; + u16 short_retry_limit; + u16 long_retry_limit; + u16 frag_threshold; + u16 rts_threshold; + u16 preamble_type; + u8 short_slot_allowed; + u8 txop_prot_disabled; + u16 beacon_interval; + u16 dtim_period; + enum SITESURVEY site_survey_enabled; + u16 site_survey_scan_time; + u8 scan_source; + u16 active_scan_time; + u16 passive_scan_time; + enum CURRENT_TXRATE curr_tx_rate; + +}; + +enum cfg_param { + RETRY_SHORT = BIT(0), + RETRY_LONG = BIT(1), + FRAG_THRESHOLD = BIT(2), + RTS_THRESHOLD = BIT(3), + BSS_TYPE = BIT(4), + AUTH_TYPE = BIT(5), + AUTHEN_TIMEOUT = BIT(6), + POWER_MANAGEMENT = BIT(7), + PREAMBLE = BIT(8), + SHORT_SLOT_ALLOWED = BIT(9), + TXOP_PROT_DISABLE = BIT(10), + BEACON_INTERVAL = BIT(11), + DTIM_PERIOD = BIT(12), + SITE_SURVEY = BIT(13), + SITE_SURVEY_SCAN_TIME = BIT(14), + ACTIVE_SCANTIME = BIT(15), + PASSIVE_SCANTIME = BIT(16), + CURRENT_TX_RATE = BIT(17), + HT_ENABLE = BIT(18), +}; + +struct found_net_info { + u8 au8bssid[6]; + s8 s8rssi; +}; + +enum scan_event { + SCAN_EVENT_NETWORK_FOUND = 0, + SCAN_EVENT_DONE = 1, + SCAN_EVENT_ABORTED = 2, + SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF +}; + +enum conn_event { + CONN_DISCONN_EVENT_CONN_RESP = 0, + CONN_DISCONN_EVENT_DISCONN_NOTIF = 1, + CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF +}; + +enum KEY_TYPE { + WEP, + WPARxGtk, + WPAPtk, + PMKSA, +}; + + +/*Scan callBack function definition*/ +typedef void (*wilc_scan_result)(enum scan_event, tstrNetworkInfo *, + void *, void *); + +/*Connect callBack function definition*/ +typedef void (*wilc_connect_result)(enum conn_event, + tstrConnectInfo *, + u8, + tstrDisconnectNotifInfo *, + void *); + +typedef void (*wilc_remain_on_chan_expired)(void *, u32); /*Remain on channel expiration callback function*/ +typedef void (*wilc_remain_on_chan_ready)(void *); /*Remain on channel callback function*/ + +/*! + * @struct rcvd_net_info + * @brief Structure to hold Received Asynchronous Network info + * @details + * @todo + * @sa + * @author Mostafa Abu Bakr + * @date 25 March 2012 + * @version 1.0 + */ +struct rcvd_net_info { + u8 *buffer; + u32 len; +}; + +struct hidden_net_info { + u8 *pu8ssid; + u8 u8ssidlen; +}; + +struct hidden_network { + struct hidden_net_info *pstrHiddenNetworkInfo; + u8 u8ssidnum; +}; + +struct user_scan_req { + /* Scan user call back function */ + wilc_scan_result pfUserScanResult; + + /* User specific parameter to be delivered through the Scan User Callback function */ + void *u32UserScanPvoid; + + u32 u32RcvdChCount; + struct found_net_info astrFoundNetworkInfo[MAX_NUM_SCANNED_NETWORKS]; +}; + +struct user_conn_req { + u8 *pu8bssid; + u8 *pu8ssid; + u8 u8security; + enum AUTHTYPE tenuAuth_type; + size_t ssidLen; + u8 *pu8ConnReqIEs; + size_t ConnReqIEsLen; + /* Connect user call back function */ + wilc_connect_result pfUserConnectResult; + bool IsHTCapable; + /* User specific parameter to be delivered through the Connect User Callback function */ + void *u32UserConnectPvoid; +}; + +struct drv_handler { + u32 handler; +}; + +struct op_mode { + u32 mode; +}; + +struct set_mac_addr { + u8 mac_addr[ETH_ALEN]; +}; + +struct get_mac_addr { + u8 *mac_addr; +}; + +struct ba_session_info { + u8 au8Bssid[ETH_ALEN]; + u8 u8Ted; + u16 u16BufferSize; + u16 u16SessionTimeout; +}; + +struct remain_ch { + u16 u16Channel; + u32 u32duration; + wilc_remain_on_chan_expired pRemainOnChanExpired; + wilc_remain_on_chan_ready pRemainOnChanReady; + void *pVoid; + u32 u32ListenSessionID; +}; + +struct reg_frame { + bool bReg; + u16 u16FrameType; + u8 u8Regid; +}; + + +#define ACTION 0xD0 +#define PROBE_REQ 0x40 +#define PROBE_RESP 0x50 +#define ACTION_FRM_IDX 0 +#define PROBE_REQ_IDX 1 + + +enum p2p_listen_state { + P2P_IDLE, + P2P_LISTEN, + P2P_GRP_FORMATION +}; + +struct host_if_drv { + struct user_scan_req usr_scan_req; + struct user_conn_req usr_conn_req; + struct remain_ch remain_on_ch; + u8 remain_on_ch_pending; + u64 u64P2p_MgmtTimeout; + u8 u8P2PConnect; + + enum host_if_state enuHostIFstate; + + u8 au8AssociatedBSSID[ETH_ALEN]; + struct cfg_param_val strCfgValues; +/* semaphores */ + struct semaphore gtOsCfgValuesSem; + struct semaphore hSemTestKeyBlock; + + struct semaphore hSemTestDisconnectBlock; + struct semaphore hSemGetRSSI; + struct semaphore hSemGetLINKSPEED; + struct semaphore hSemGetCHNL; + struct semaphore hSemInactiveTime; +/* timer handlers */ + struct timer_list hScanTimer; + struct timer_list hConnectTimer; + struct timer_list hRemainOnChannel; + + bool IFC_UP; +}; + +struct add_sta_param { + u8 au8BSSID[ETH_ALEN]; + u16 u16AssocID; + u8 u8NumRates; + const u8 *pu8Rates; + bool bIsHTSupported; + u16 u16HTCapInfo; + u8 u8AmpduParams; + u8 au8SuppMCsSet[16]; + u16 u16HTExtParams; + u32 u32TxBeamformingCap; + u8 u8ASELCap; + u16 u16FlagsMask; /**/ + u16 u16FlagsSet; /*> 22) & 0x1ff) + +void WILC_WFI_monitor_rx(u8 *buff, u32 size) +{ + u32 header, pkt_offset; + struct sk_buff *skb = NULL; + struct wilc_wfi_radiotap_hdr *hdr; + struct wilc_wfi_radiotap_cb_hdr *cb_hdr; + + PRINT_INFO(HOSTAPD_DBG, "In monitor interface receive function\n"); + + if (wilc_wfi_mon == NULL) + return; + + if (!netif_running(wilc_wfi_mon)) { + PRINT_INFO(HOSTAPD_DBG, "Monitor interface already RUNNING\n"); + return; + } + + /* Get WILC header */ + memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET); + + /* The packet offset field conain info about what type of managment frame */ + /* we are dealing with and ack status */ + pkt_offset = GET_PKT_OFFSET(header); + + if (pkt_offset & IS_MANAGMEMENT_CALLBACK) { + + /* hostapd callback mgmt frame */ + + skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_cb_hdr)); + if (skb == NULL) { + PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb"); + return; + } + + memcpy(skb_put(skb, size), buff, size); + + cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb, sizeof(*cb_hdr)); + memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + + cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_TX_FLAGS)); + + cb_hdr->rate = 5; /* txrate->bitrate / 5; */ + + if (pkt_offset & IS_MGMT_STATUS_SUCCES) { + /* success */ + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS; + } else { + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL; + } + + } else { + + skb = dev_alloc_skb(size + sizeof(struct wilc_wfi_radiotap_hdr)); + + if (skb == NULL) { + PRINT_INFO(HOSTAPD_DBG, "Monitor if : No memory to allocate skb"); + return; + } + + memcpy(skb_put(skb, size), buff, size); + hdr = (struct wilc_wfi_radiotap_hdr *) skb_push(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr)); + hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_hdr)); + PRINT_INFO(HOSTAPD_DBG, "Radiotap len %d\n", hdr->hdr.it_len); + hdr->hdr.it_present = cpu_to_le32 + (1 << IEEE80211_RADIOTAP_RATE); /* | */ + PRINT_INFO(HOSTAPD_DBG, "Presentflags %d\n", hdr->hdr.it_present); + hdr->rate = 5; /* txrate->bitrate / 5; */ + + } + + + + skb->dev = wilc_wfi_mon; + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + + netif_rx(skb); + + +} + +struct tx_complete_mon_data { + int size; + void *buff; +}; + +static void mgmt_tx_complete(void *priv, int status) +{ + + struct tx_complete_mon_data *pv_data = (struct tx_complete_mon_data *)priv; + u8 *buf = pv_data->buff; + + + + if (status == 1) { + if (INFO || buf[0] == 0x10 || buf[0] == 0xb0) + PRINT_INFO(HOSTAPD_DBG, "Packet sent successfully - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff); + } else { + PRINT_INFO(HOSTAPD_DBG, "Couldn't send packet - Size = %d - Address = %p.\n", pv_data->size, pv_data->buff); + } + + + + /* incase of fully hosting mode, the freeing will be done in response to the cfg packet */ + kfree(pv_data->buff); + + kfree(pv_data); +} +static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len) +{ + struct tx_complete_mon_data *mgmt_tx = NULL; + + if (dev == NULL) { + PRINT_D(HOSTAPD_DBG, "ERROR: dev == NULL\n"); + return -EFAULT; + } + + netif_stop_queue(dev); + mgmt_tx = kmalloc(sizeof(struct tx_complete_mon_data), GFP_ATOMIC); + if (mgmt_tx == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx structure\n"); + return -EFAULT; + } + + mgmt_tx->buff = kmalloc(len, GFP_ATOMIC); + if (mgmt_tx->buff == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx buff\n"); + kfree(mgmt_tx); + return -EFAULT; + + } + + mgmt_tx->size = len; + + memcpy(mgmt_tx->buff, buf, len); + wilc_wlan_txq_add_mgmt_pkt(mgmt_tx, mgmt_tx->buff, mgmt_tx->size, + mgmt_tx_complete); + + netif_wake_queue(dev); + return 0; +} + +/** + * @brief WILC_WFI_mon_xmit + * @details + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 12 JUL 2012 + * @version 1.0 + */ +static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + u32 rtap_len, i, ret = 0; + struct WILC_WFI_mon_priv *mon_priv; + + struct sk_buff *skb2; + struct wilc_wfi_radiotap_cb_hdr *cb_hdr; + + if (wilc_wfi_mon == NULL) + return -EFAULT; + + mon_priv = netdev_priv(wilc_wfi_mon); + + if (mon_priv == NULL) { + PRINT_ER("Monitor interface private structure is NULL\n"); + return -EFAULT; + } + + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (skb->len < rtap_len) { + PRINT_ER("Error in radiotap header\n"); + return -1; + } + /* skip the radiotap header */ + PRINT_INFO(HOSTAPD_DBG, "Radiotap len: %d\n", rtap_len); + + if (INFO) { + for (i = 0; i < rtap_len; i++) + PRINT_INFO(HOSTAPD_DBG, "Radiotap_hdr[%d] %02x\n", i, skb->data[i]); + } + /* Skip the ratio tap header */ + skb_pull(skb, rtap_len); + + if (skb->data[0] == 0xc0) + PRINT_INFO(HOSTAPD_DBG, "%x:%x:%x:%x:%x%x\n", skb->data[4], skb->data[5], skb->data[6], skb->data[7], skb->data[8], skb->data[9]); + + if (skb->data[0] == 0xc0 && (!(memcmp(broadcast, &skb->data[4], 6)))) { + skb2 = dev_alloc_skb(skb->len + sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + memcpy(skb_put(skb2, skb->len), skb->data, skb->len); + + cb_hdr = (struct wilc_wfi_radiotap_cb_hdr *) skb_push(skb2, sizeof(*cb_hdr)); + memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + + cb_hdr->hdr.it_len = cpu_to_le16(sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_TX_FLAGS)); + + cb_hdr->rate = 5; /* txrate->bitrate / 5; */ + cb_hdr->tx_flags = 0x0004; + + skb2->dev = wilc_wfi_mon; + skb_set_mac_header(skb2, 0); + skb2->ip_summed = CHECKSUM_UNNECESSARY; + skb2->pkt_type = PACKET_OTHERHOST; + skb2->protocol = htons(ETH_P_802_2); + memset(skb2->cb, 0, sizeof(skb2->cb)); + + netif_rx(skb2); + + return 0; + } + skb->dev = mon_priv->real_ndev; + + PRINT_INFO(HOSTAPD_DBG, "Skipping the radiotap header\n"); + + + + /* actual deliver of data is device-specific, and not shown here */ + PRINT_INFO(HOSTAPD_DBG, "SKB netdevice name = %s\n", skb->dev->name); + PRINT_INFO(HOSTAPD_DBG, "MONITOR real dev name = %s\n", mon_priv->real_ndev->name); + + /* Identify if Ethernet or MAC header (data or mgmt) */ + memcpy(srcAdd, &skb->data[10], 6); + memcpy(bssid, &skb->data[16], 6); + /* if source address and bssid fields are equal>>Mac header */ + /*send it to mgmt frames handler */ + if (!(memcmp(srcAdd, bssid, 6))) { + mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len); + dev_kfree_skb(skb); + } else + ret = mac_xmit(skb, mon_priv->real_ndev); + + return ret; +} + +static const struct net_device_ops wilc_wfi_netdev_ops = { + .ndo_start_xmit = WILC_WFI_mon_xmit, + +}; + +/** + * @brief WILC_WFI_init_mon_interface + * @details + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 12 JUL 2012 + * @version 1.0 + */ +struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev) +{ + + + u32 ret = 0; + struct WILC_WFI_mon_priv *priv; + + /*If monitor interface is already initialized, return it*/ + if (wilc_wfi_mon) { + return wilc_wfi_mon; + } + + wilc_wfi_mon = alloc_etherdev(sizeof(struct WILC_WFI_mon_priv)); + if (!wilc_wfi_mon) { + PRINT_ER("failed to allocate memory\n"); + return NULL; + + } + + wilc_wfi_mon->type = ARPHRD_IEEE80211_RADIOTAP; + strncpy(wilc_wfi_mon->name, name, IFNAMSIZ); + wilc_wfi_mon->name[IFNAMSIZ - 1] = 0; + wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops; + + ret = register_netdevice(wilc_wfi_mon); + if (ret) { + PRINT_ER(" register_netdevice failed (%d)\n", ret); + return NULL; + } + priv = netdev_priv(wilc_wfi_mon); + if (priv == NULL) { + PRINT_ER("private structure is NULL\n"); + return NULL; + } + + priv->real_ndev = real_dev; + + return wilc_wfi_mon; +} + +/** + * @brief WILC_WFI_deinit_mon_interface + * @details + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 12 JUL 2012 + * @version 1.0 + */ +int WILC_WFI_deinit_mon_interface(void) +{ + bool rollback_lock = false; + + if (wilc_wfi_mon != NULL) { + PRINT_D(HOSTAPD_DBG, "In Deinit monitor interface\n"); + PRINT_D(HOSTAPD_DBG, "RTNL is being locked\n"); + if (rtnl_is_locked()) { + rtnl_unlock(); + rollback_lock = true; + } + PRINT_D(HOSTAPD_DBG, "Unregister netdev\n"); + unregister_netdev(wilc_wfi_mon); + + if (rollback_lock) { + rtnl_lock(); + rollback_lock = false; + } + wilc_wfi_mon = NULL; + } + return 0; + +} diff --git a/kernel/drivers/staging/wilc1000/linux_wlan.c b/kernel/drivers/staging/wilc1000/linux_wlan.c new file mode 100644 index 000000000..2a5b36fd8 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/linux_wlan.c @@ -0,0 +1,1832 @@ +#include "wilc_wfi_cfgoperations.h" +#include "linux_wlan_common.h" +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef WILC_SDIO +#include "linux_wlan_sdio.h" +#else +#include "linux_wlan_spi.h" +#endif + +#if defined(CUSTOMER_PLATFORM) +/* + TODO : Write power control functions as customer platform. + */ +#else + + #define _linux_wlan_device_power_on() {} + #define _linux_wlan_device_power_off() {} + + #define _linux_wlan_device_detection() {} + #define _linux_wlan_device_removal() {} +#endif + +extern bool g_obtainingIP; +extern void resolve_disconnect_aberration(void *drvHandler); +extern u8 gau8MulticastMacAddrList[WILC_MULTICAST_TABLE_SIZE][ETH_ALEN]; +extern struct timer_list hDuringIpTimer; + +static int linux_wlan_device_power(int on_off) +{ + PRINT_D(INIT_DBG, "linux_wlan_device_power.. (%d)\n", on_off); + + if (on_off) { + _linux_wlan_device_power_on(); + } else { + _linux_wlan_device_power_off(); + } + + return 0; +} + +static int linux_wlan_device_detection(int on_off) +{ + PRINT_D(INIT_DBG, "linux_wlan_device_detection.. (%d)\n", on_off); + +#ifdef WILC_SDIO + if (on_off) { + _linux_wlan_device_detection(); + } else { + _linux_wlan_device_removal(); + } +#endif + + return 0; +} + +static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr); + +static struct notifier_block g_dev_notifier = { + .notifier_call = dev_state_ev_handler +}; + +#define IRQ_WAIT 1 +#define IRQ_NO_WAIT 0 +/* + * to sync between mac_close and module exit. + * don't initialize or de-initialize from init/deinitlocks + * to be initialized from module wilc_netdev_init and + * deinitialized from mdoule_exit + */ +static struct semaphore close_exit_sync; + +static int wlan_deinit_locks(struct net_device *dev); +static void wlan_deinitialize_threads(struct net_device *dev); +extern void WILC_WFI_monitor_rx(u8 *buff, u32 size); +extern void WILC_WFI_p2p_rx(struct net_device *dev, u8 *buff, u32 size); + +static void linux_wlan_tx_complete(void *priv, int status); +static int mac_init_fn(struct net_device *ndev); +int mac_xmit(struct sk_buff *skb, struct net_device *dev); +int mac_open(struct net_device *ndev); +int mac_close(struct net_device *ndev); +static struct net_device_stats *mac_stats(struct net_device *dev); +static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd); +static void wilc_set_multicast_list(struct net_device *dev); + +/* + * for now - in frmw_to_linux there should be private data to be passed to it + * and this data should be pointer to net device + */ +struct wilc *g_linux_wlan; +bool bEnablePS = true; + +static const struct net_device_ops wilc_netdev_ops = { + .ndo_init = mac_init_fn, + .ndo_open = mac_open, + .ndo_stop = mac_close, + .ndo_start_xmit = mac_xmit, + .ndo_do_ioctl = mac_ioctl, + .ndo_get_stats = mac_stats, + .ndo_set_rx_mode = wilc_set_multicast_list, + +}; + +static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct in_ifaddr *dev_iface = (struct in_ifaddr *)ptr; + struct wilc_priv *priv; + struct host_if_drv *pstrWFIDrv; + struct net_device *dev; + u8 *pIP_Add_buff; + perInterface_wlan_t *nic; + u8 null_ip[4] = {0}; + char wlan_dev_name[5] = "wlan0"; + + if (dev_iface == NULL || dev_iface->ifa_dev == NULL || dev_iface->ifa_dev->dev == NULL) { + PRINT_D(GENERIC_DBG, "dev_iface = NULL\n"); + return NOTIFY_DONE; + } + + if ((memcmp(dev_iface->ifa_label, "wlan0", 5)) && (memcmp(dev_iface->ifa_label, "p2p0", 4))) { + PRINT_D(GENERIC_DBG, "Interface is neither WLAN0 nor P2P0\n"); + return NOTIFY_DONE; + } + + dev = (struct net_device *)dev_iface->ifa_dev->dev; + if (dev->ieee80211_ptr == NULL || dev->ieee80211_ptr->wiphy == NULL) { + PRINT_D(GENERIC_DBG, "No Wireless registerd\n"); + return NOTIFY_DONE; + } + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + if (priv == NULL) { + PRINT_D(GENERIC_DBG, "No Wireless Priv\n"); + return NOTIFY_DONE; + } + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + nic = netdev_priv(dev); + if (nic == NULL || pstrWFIDrv == NULL) { + PRINT_D(GENERIC_DBG, "No Wireless Priv\n"); + return NOTIFY_DONE; + } + + PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler +++\n"); /* tony */ + + switch (event) { + case NETDEV_UP: + PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_UP %p\n", dev); /* tony */ + + PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Obtained ===============\n\n"); + + /*If we are in station mode or client mode*/ + if (nic->iftype == STATION_MODE || nic->iftype == CLIENT_MODE) { + pstrWFIDrv->IFC_UP = 1; + g_obtainingIP = false; + del_timer(&hDuringIpTimer); + PRINT_D(GENERIC_DBG, "IP obtained , enable scan\n"); + } + + if (bEnablePS) + host_int_set_power_mgmt(pstrWFIDrv, 1, 0); + + PRINT_D(GENERIC_DBG, "[%s] Up IP\n", dev_iface->ifa_label); + + pIP_Add_buff = (char *) (&(dev_iface->ifa_address)); + PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); + host_int_setup_ipaddress(pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx); + + break; + + case NETDEV_DOWN: + PRINT_D(GENERIC_DBG, "dev_state_ev_handler event=NETDEV_DOWN %p\n", dev); /* tony */ + + PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Released ===============\n\n"); + if (nic->iftype == STATION_MODE || nic->iftype == CLIENT_MODE) { + pstrWFIDrv->IFC_UP = 0; + g_obtainingIP = false; + } + + if (memcmp(dev_iface->ifa_label, wlan_dev_name, 5) == 0) + host_int_set_power_mgmt(pstrWFIDrv, 0, 0); + + resolve_disconnect_aberration(pstrWFIDrv); + + PRINT_D(GENERIC_DBG, "[%s] Down IP\n", dev_iface->ifa_label); + + pIP_Add_buff = null_ip; + PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); + + host_int_setup_ipaddress(pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx); + + break; + + default: + PRINT_INFO(GENERIC_DBG, "dev_state_ev_handler event=default\n"); /* tony */ + PRINT_INFO(GENERIC_DBG, "[%s] unknown dev event: %lu\n", dev_iface->ifa_label, event); + + break; + } + + return NOTIFY_DONE; + +} + +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) +static irqreturn_t isr_uh_routine(int irq, void *user_data) +{ + perInterface_wlan_t *nic; + struct wilc *wilc; + struct net_device *dev = (struct net_device *)user_data; + + nic = netdev_priv(dev); + wilc = nic->wilc; + PRINT_D(INT_DBG, "Interrupt received UH\n"); + + /*While mac is closing cacncel the handling of any interrupts received*/ + if (wilc->close) { + PRINT_ER("Driver is CLOSING: Can't handle UH interrupt\n"); + return IRQ_HANDLED; + } + return IRQ_WAKE_THREAD; +} +#endif + +irqreturn_t isr_bh_routine(int irq, void *userdata) +{ + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(userdata); + wilc = nic->wilc; + + /*While mac is closing cacncel the handling of any interrupts received*/ + if (wilc->close) { + PRINT_ER("Driver is CLOSING: Can't handle BH interrupt\n"); + return IRQ_HANDLED; + } + + PRINT_D(INT_DBG, "Interrupt received BH\n"); + wilc_handle_isr(wilc); + + return IRQ_HANDLED; +} + +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) +static int init_irq(struct net_device *dev) +{ + int ret = 0; + perInterface_wlan_t *nic; + struct wilc *wl; + + nic = netdev_priv(dev); + wl = nic->wilc; + + /*initialize GPIO and register IRQ num*/ + /*GPIO request*/ + if ((gpio_request(GPIO_NUM, "WILC_INTR") == 0) && + (gpio_direction_input(GPIO_NUM) == 0)) { +#if defined(CUSTOMER_PLATFORM) +/* + TODO : save the registerd irq number to the private wilc context in kernel. + * + * ex) nic->dev_irq_num = gpio_to_irq(GPIO_NUM); + */ +#else + wl->dev_irq_num = gpio_to_irq(GPIO_NUM); +#endif + } else { + ret = -1; + PRINT_ER("could not obtain gpio for WILC_INTR\n"); + } + + if ((ret != -1) && (request_threaded_irq(wl->dev_irq_num, isr_uh_routine, isr_bh_routine, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, /*Without IRQF_ONESHOT the uh will remain kicked in and dont gave a chance to bh*/ + "WILC_IRQ", dev)) < 0) { + + PRINT_ER("Failed to request IRQ for GPIO: %d\n", GPIO_NUM); + ret = -1; + } else { + + PRINT_D(INIT_DBG, "IRQ request succeeded IRQ-NUM= %d on GPIO: %d\n", + wl->dev_irq_num, GPIO_NUM); + } + + return ret; +} +#endif + +static void deinit_irq(struct net_device *dev) +{ + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(dev); + wilc = nic->wilc; + +#if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) + /* Deintialize IRQ */ + if (&wilc->dev_irq_num != 0) { + free_irq(wilc->dev_irq_num, wilc); + + gpio_free(GPIO_NUM); + } +#endif +} + +/* + * OS functions + */ +void linux_wlan_dbg(u8 *buff) +{ + PRINT_D(INIT_DBG, "%d\n", *buff); +} + +int linux_wlan_lock_timeout(void *vp, u32 timeout) +{ + int error = -1; + + PRINT_D(LOCK_DBG, "Locking %p\n", vp); + if (vp != NULL) + error = down_timeout((struct semaphore *)vp, msecs_to_jiffies(timeout)); + else + PRINT_ER("Failed, mutex is NULL\n"); + return error; +} + +void linux_wlan_mac_indicate(struct wilc *wilc, int flag) +{ + /*I have to do it that way becuase there is no mean to encapsulate device pointer + * as a parameter + */ + int status; + + if (flag == WILC_MAC_INDICATE_STATUS) { + wilc_wlan_cfg_get_val(WID_STATUS, (unsigned char *)&status, 4); + if (wilc->mac_status == WILC_MAC_STATUS_INIT) { + wilc->mac_status = status; + up(&wilc->sync_event); + } else { + wilc->mac_status = status; + } + + if (wilc->mac_status == WILC_MAC_STATUS_CONNECT) { /* Connect */ + } + + } else if (flag == WILC_MAC_INDICATE_SCAN) { + PRINT_D(GENERIC_DBG, "Scanning ...\n"); + + } + +} + +struct net_device *GetIfHandler(struct wilc *wilc, u8 *pMacHeader) +{ + u8 *Bssid, *Bssid1; + int i = 0; + + Bssid = pMacHeader + 10; + Bssid1 = pMacHeader + 4; + + for (i = 0; i < wilc->vif_num; i++) + if (!memcmp(Bssid1, wilc->vif[i].bssid, ETH_ALEN) || + !memcmp(Bssid, wilc->vif[i].bssid, ETH_ALEN)) + return wilc->vif[i].ndev; + + PRINT_INFO(INIT_DBG, "Invalide handle\n"); + for (i = 0; i < 25; i++) + PRINT_D(INIT_DBG, "%02x ", pMacHeader[i]); + Bssid = pMacHeader + 18; + Bssid1 = pMacHeader + 12; + for (i = 0; i < wilc->vif_num; i++) + if (!memcmp(Bssid1, wilc->vif[i].bssid, ETH_ALEN) || + !memcmp(Bssid, wilc->vif[i].bssid, ETH_ALEN)) + return wilc->vif[i].ndev; + + PRINT_INFO(INIT_DBG, "\n"); + return NULL; +} + +int linux_wlan_set_bssid(struct net_device *wilc_netdev, u8 *pBSSID) +{ + int i = 0; + int ret = -1; + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(wilc_netdev); + wilc = nic->wilc; + + for (i = 0; i < wilc->vif_num; i++) + if (wilc->vif[i].ndev == wilc_netdev) { + memcpy(wilc->vif[i].bssid, pBSSID, 6); + ret = 0; + break; + } + + return ret; +} + +/*Function to get number of connected interfaces*/ +int linux_wlan_get_num_conn_ifcs(void) +{ + u8 i = 0; + u8 null_bssid[6] = {0}; + u8 ret_val = 0; + + for (i = 0; i < g_linux_wlan->vif_num; i++) + if (memcmp(g_linux_wlan->vif[i].bssid, null_bssid, 6)) + ret_val++; + + return ret_val; +} + +#define USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS + +static int linux_wlan_txq_task(void *vp) +{ + int ret, txq_count; + perInterface_wlan_t *nic; + struct wilc *wl; + struct net_device *dev = vp; +#if defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS +#define TX_BACKOFF_WEIGHT_INCR_STEP (1) +#define TX_BACKOFF_WEIGHT_DECR_STEP (1) +#define TX_BACKOFF_WEIGHT_MAX (7) +#define TX_BACKOFF_WEIGHT_MIN (0) +#define TX_BACKOFF_WEIGHT_UNIT_MS (10) + int backoff_weight = TX_BACKOFF_WEIGHT_MIN; +#endif + + nic = netdev_priv(dev); + wl = nic->wilc; + + /* inform wilc1000_wlan_init that TXQ task is started. */ + up(&wl->txq_thread_started); + while (1) { + + PRINT_D(TX_DBG, "txq_task Taking a nap :)\n"); + down(&wl->txq_event); + /* wait_for_completion(&pd->txq_event); */ + PRINT_D(TX_DBG, "txq_task Who waked me up :$\n"); + + if (wl->close) { + /*Unlock the mutex in the mac_close function to indicate the exiting of the TX thread */ + up(&wl->txq_thread_started); + + while (!kthread_should_stop()) + schedule(); + + PRINT_D(TX_DBG, "TX thread stopped\n"); + break; + } + PRINT_D(TX_DBG, "txq_task handle the sending packet and let me go to sleep.\n"); +#if !defined USE_TX_BACKOFF_DELAY_IF_NO_BUFFERS + ret = wilc_wlan_handle_txq(dev, &txq_count); +#else + do { + ret = wilc_wlan_handle_txq(dev, &txq_count); + if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD /* && netif_queue_stopped(pd->wilc_netdev)*/) { + PRINT_D(TX_DBG, "Waking up queue\n"); + /* netif_wake_queue(pd->wilc_netdev); */ + if (netif_queue_stopped(wl->vif[0].ndev)) + netif_wake_queue(wl->vif[0].ndev); + if (netif_queue_stopped(wl->vif[1].ndev)) + netif_wake_queue(wl->vif[1].ndev); + } + + if (ret == WILC_TX_ERR_NO_BUF) { /* failed to allocate buffers in chip. */ + do { + /* Back off from sending packets for some time. */ + /* schedule_timeout will allow RX task to run and free buffers.*/ + /* set_current_state(TASK_UNINTERRUPTIBLE); */ + /* timeout = schedule_timeout(timeout); */ + msleep(TX_BACKOFF_WEIGHT_UNIT_MS << backoff_weight); + } while (/*timeout*/ 0); + backoff_weight += TX_BACKOFF_WEIGHT_INCR_STEP; + if (backoff_weight > TX_BACKOFF_WEIGHT_MAX) + backoff_weight = TX_BACKOFF_WEIGHT_MAX; + } else { + if (backoff_weight > TX_BACKOFF_WEIGHT_MIN) { + backoff_weight -= TX_BACKOFF_WEIGHT_DECR_STEP; + if (backoff_weight < TX_BACKOFF_WEIGHT_MIN) + backoff_weight = TX_BACKOFF_WEIGHT_MIN; + } + } + /*TODO: drop packets after a certain time/number of retry count. */ + } while (ret == WILC_TX_ERR_NO_BUF && !wl->close); /* retry sending packets if no more buffers in chip. */ +#endif + } + return 0; +} + +void linux_wlan_rx_complete(void) +{ + PRINT_D(RX_DBG, "RX completed\n"); +} + +int linux_wlan_get_firmware(perInterface_wlan_t *p_nic) +{ + + perInterface_wlan_t *nic = p_nic; + int ret = 0; + const struct firmware *wilc_firmware; + char *firmware; + + if (nic->iftype == AP_MODE) + firmware = AP_FIRMWARE; + else if (nic->iftype == STATION_MODE) + firmware = STA_FIRMWARE; + + else { + PRINT_D(INIT_DBG, "Get P2P_CONCURRENCY_FIRMWARE\n"); + firmware = P2P_CONCURRENCY_FIRMWARE; + } + + if (nic == NULL) { + PRINT_ER("NIC is NULL\n"); + goto _fail_; + } + + if (&nic->wilc_netdev->dev == NULL) { + PRINT_ER("&nic->wilc_netdev->dev is NULL\n"); + goto _fail_; + } + + /* the firmare should be located in /lib/firmware in + * root file system with the name specified above */ + +#ifdef WILC_SDIO + if (request_firmware(&wilc_firmware, firmware, &g_linux_wlan->wilc_sdio_func->dev) != 0) { + PRINT_ER("%s - firmare not available\n", firmware); + ret = -1; + goto _fail_; + } +#else + if (request_firmware(&wilc_firmware, firmware, &g_linux_wlan->wilc_spidev->dev) != 0) { + PRINT_ER("%s - firmare not available\n", firmware); + ret = -1; + goto _fail_; + } +#endif + g_linux_wlan->firmware = wilc_firmware; + +_fail_: + + return ret; + +} + +static int linux_wlan_start_firmware(perInterface_wlan_t *nic) +{ + + int ret = 0; + /* start firmware */ + PRINT_D(INIT_DBG, "Starting Firmware ...\n"); + ret = wilc_wlan_start(); + if (ret < 0) { + PRINT_ER("Failed to start Firmware\n"); + goto _fail_; + } + + /* wait for mac ready */ + PRINT_D(INIT_DBG, "Waiting for Firmware to get ready ...\n"); + ret = linux_wlan_lock_timeout(&g_linux_wlan->sync_event, 5000); + if (ret) { + PRINT_D(INIT_DBG, "Firmware start timed out"); + goto _fail_; + } + /* + * TODO: Driver shouoldn't wait forever for firmware to get started - + * in case of timeout this should be handled properly + */ + PRINT_D(INIT_DBG, "Firmware successfully started\n"); + +_fail_: + return ret; +} +static int linux_wlan_firmware_download(struct wilc *p_nic) +{ + + int ret = 0; + + if (!g_linux_wlan->firmware) { + PRINT_ER("Firmware buffer is NULL\n"); + ret = -ENOBUFS; + goto _FAIL_; + } + /** + * do the firmware download + **/ + PRINT_D(INIT_DBG, "Downloading Firmware ...\n"); + ret = wilc_wlan_firmware_download(g_linux_wlan->firmware->data, + g_linux_wlan->firmware->size); + if (ret < 0) + goto _FAIL_; + + /* Freeing FW buffer */ + PRINT_D(INIT_DBG, "Freeing FW buffer ...\n"); + PRINT_D(INIT_DBG, "Releasing firmware\n"); + release_firmware(g_linux_wlan->firmware); + + PRINT_D(INIT_DBG, "Download Succeeded\n"); + +_FAIL_: + return ret; +} + +/* startup configuration - could be changed later using iconfig*/ +static int linux_wlan_init_test_config(struct net_device *dev, struct wilc *p_nic) +{ + + unsigned char c_val[64]; + unsigned char mac_add[] = {0x00, 0x80, 0xC2, 0x5E, 0xa2, 0xff}; + + struct wilc_priv *priv; + struct host_if_drv *pstrWFIDrv; + + PRINT_D(TX_DBG, "Start configuring Firmware\n"); + get_random_bytes(&mac_add[5], 1); + get_random_bytes(&mac_add[4], 1); + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + PRINT_D(INIT_DBG, "Host = %p\n", pstrWFIDrv); + + PRINT_D(INIT_DBG, "MAC address is : %02x-%02x-%02x-%02x-%02x-%02x\n", mac_add[0], mac_add[1], mac_add[2], mac_add[3], mac_add[4], mac_add[5]); + wilc_get_chipid(0); + + *(int *)c_val = 1; + + if (!wilc_wlan_cfg_set(1, WID_SET_DRV_HANDLER, c_val, 4, 0, 0)) + goto _fail_; + + /*to tell fw that we are going to use PC test - WILC specific*/ + c_val[0] = 0; + if (!wilc_wlan_cfg_set(0, WID_PC_TEST_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = INFRASTRUCTURE; + if (!wilc_wlan_cfg_set(0, WID_BSS_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + /* c_val[0] = RATE_AUTO; */ + c_val[0] = RATE_AUTO; + if (!wilc_wlan_cfg_set(0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = G_MIXED_11B_2_MODE; + if (!wilc_wlan_cfg_set(0, WID_11G_OPERATING_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; + if (!wilc_wlan_cfg_set(0, WID_CURRENT_CHANNEL, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = G_SHORT_PREAMBLE; + if (!wilc_wlan_cfg_set(0, WID_PREAMBLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = AUTO_PROT; + if (!wilc_wlan_cfg_set(0, WID_11N_PROT_MECH, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = ACTIVE_SCAN; + if (!wilc_wlan_cfg_set(0, WID_SCAN_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = SITE_SURVEY_OFF; + if (!wilc_wlan_cfg_set(0, WID_SITE_SURVEY, c_val, 1, 0, 0)) + goto _fail_; + + *((int *)c_val) = 0xffff; /* Never use RTS-CTS */ + if (!wilc_wlan_cfg_set(0, WID_RTS_THRESHOLD, c_val, 2, 0, 0)) + goto _fail_; + + *((int *)c_val) = 2346; + if (!wilc_wlan_cfg_set(0, WID_FRAG_THRESHOLD, c_val, 2, 0, 0)) + goto _fail_; + + /* SSID */ + /* -------------------------------------------------------------- */ + /* Configuration : String with length less than 32 bytes */ + /* Values to set : Any string with length less than 32 bytes */ + /* ( In BSS Station Set SSID to "" (null string) */ + /* to enable Broadcast SSID suppport ) */ + /* -------------------------------------------------------------- */ + c_val[0] = 0; + if (!wilc_wlan_cfg_set(0, WID_BCAST_SSID, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; + if (!wilc_wlan_cfg_set(0, WID_QOS_ENABLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = NO_POWERSAVE; + if (!wilc_wlan_cfg_set(0, WID_POWER_MANAGEMENT, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = NO_ENCRYPT; /* NO_ENCRYPT, 0x79 */ + if (!wilc_wlan_cfg_set(0, WID_11I_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = OPEN_SYSTEM; + if (!wilc_wlan_cfg_set(0, WID_AUTH_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + /* WEP/802 11I Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : WEP Key */ + /* Values (0x) : 5 byte for WEP40 and 13 bytes for WEP104 */ + /* In case more than 5 bytes are passed on for WEP 40 */ + /* only first 5 bytes will be used as the key */ + /* ------------------------------------------------------------------ */ + + strcpy(c_val, "123456790abcdef1234567890"); + if (!wilc_wlan_cfg_set(0, WID_WEP_KEY_VALUE, c_val, (strlen(c_val) + 1), 0, 0)) + goto _fail_; + + /* WEP/802 11I Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : AES/TKIP WPA/RSNA Pre-Shared Key */ + /* Values to set : Any string with length greater than equal to 8 bytes */ + /* and less than 64 bytes */ + /* ------------------------------------------------------------------ */ + strcpy(c_val, "12345678"); + if (!wilc_wlan_cfg_set(0, WID_11I_PSK, c_val, (strlen(c_val)), 0, 0)) + goto _fail_; + + /* IEEE802.1X Key Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : Radius Server Access Secret Key */ + /* Values to set : Any string with length greater than equal to 8 bytes */ + /* and less than 65 bytes */ + /* ------------------------------------------------------------------ */ + strcpy(c_val, "password"); + if (!wilc_wlan_cfg_set(0, WID_1X_KEY, c_val, (strlen(c_val) + 1), 0, 0)) + goto _fail_; + + /* IEEE802.1X Server Address Configuration */ + /* ------------------------------------------------------------------ */ + /* Configuration : Radius Server IP Address */ + /* Values to set : Any valid IP Address */ + /* ------------------------------------------------------------------ */ + c_val[0] = 192; + c_val[1] = 168; + c_val[2] = 1; + c_val[3] = 112; + if (!wilc_wlan_cfg_set(0, WID_1X_SERV_ADDR, c_val, 4, 0, 0)) + goto _fail_; + + c_val[0] = 3; + if (!wilc_wlan_cfg_set(0, WID_LISTEN_INTERVAL, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 3; + if (!wilc_wlan_cfg_set(0, WID_DTIM_PERIOD, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = NORMAL_ACK; + if (!wilc_wlan_cfg_set(0, WID_ACK_POLICY, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 0; + if (!wilc_wlan_cfg_set(0, WID_USER_CONTROL_ON_TX_POWER, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 48; + if (!wilc_wlan_cfg_set(0, WID_TX_POWER_LEVEL_11A, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 28; + if (!wilc_wlan_cfg_set(0, WID_TX_POWER_LEVEL_11B, c_val, 1, 0, 0)) + goto _fail_; + + /* Beacon Interval */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets the beacon interval value */ + /* Values to set : Any 16-bit value */ + /* -------------------------------------------------------------------- */ + + *((int *)c_val) = 100; + if (!wilc_wlan_cfg_set(0, WID_BEACON_INTERVAL, c_val, 2, 0, 0)) + goto _fail_; + + c_val[0] = REKEY_DISABLE; + if (!wilc_wlan_cfg_set(0, WID_REKEY_POLICY, c_val, 1, 0, 0)) + goto _fail_; + + /* Rekey Time (s) (Used only when the Rekey policy is 2 or 4) */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets the Rekey Time (s) */ + /* Values to set : 32-bit value */ + /* -------------------------------------------------------------------- */ + *((int *)c_val) = 84600; + if (!wilc_wlan_cfg_set(0, WID_REKEY_PERIOD, c_val, 4, 0, 0)) + goto _fail_; + + /* Rekey Packet Count (in 1000s; used when Rekey Policy is 3) */ + /* -------------------------------------------------------------------- */ + /* Configuration : Sets Rekey Group Packet count */ + /* Values to set : 32-bit Value */ + /* -------------------------------------------------------------------- */ + *((int *)c_val) = 500; + if (!wilc_wlan_cfg_set(0, WID_REKEY_PACKET_COUNT, c_val, 4, 0, 0)) + goto _fail_; + + c_val[0] = 1; + if (!wilc_wlan_cfg_set(0, WID_SHORT_SLOT_ALLOWED, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = G_SELF_CTS_PROT; + if (!wilc_wlan_cfg_set(0, WID_11N_ERP_PROT_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; /* Enable N */ + if (!wilc_wlan_cfg_set(0, WID_11N_ENABLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = HT_MIXED_MODE; + if (!wilc_wlan_cfg_set(0, WID_11N_OPERATING_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; /* TXOP Prot disable in N mode: No RTS-CTS on TX A-MPDUs to save air-time. */ + if (!wilc_wlan_cfg_set(0, WID_11N_TXOP_PROT_DISABLE, c_val, 1, 0, 0)) + goto _fail_; + + memcpy(c_val, mac_add, 6); + + if (!wilc_wlan_cfg_set(0, WID_MAC_ADDR, c_val, 6, 0, 0)) + goto _fail_; + + /** + * AP only + **/ + c_val[0] = DETECT_PROTECT_REPORT; + if (!wilc_wlan_cfg_set(0, WID_11N_OBSS_NONHT_DETECTION, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = RTS_CTS_NONHT_PROT; + if (!wilc_wlan_cfg_set(0, WID_11N_HT_PROT_TYPE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 0; + if (!wilc_wlan_cfg_set(0, WID_11N_RIFS_PROT_ENABLE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = MIMO_MODE; + if (!wilc_wlan_cfg_set(0, WID_11N_SMPS_MODE, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 7; + if (!wilc_wlan_cfg_set(0, WID_11N_CURRENT_TX_MCS, c_val, 1, 0, 0)) + goto _fail_; + + c_val[0] = 1; /* Enable N with immediate block ack. */ + if (!wilc_wlan_cfg_set(0, WID_11N_IMMEDIATE_BA_ENABLED, c_val, 1, 1, 1)) + goto _fail_; + + return 0; + +_fail_: + return -1; +} + +/**************************/ +void wilc1000_wlan_deinit(struct net_device *dev) +{ + perInterface_wlan_t *nic; + struct wilc *wl; + + nic = netdev_priv(dev); + wl = nic->wilc; + + if (!wl) { + netdev_err(dev, "wl is NULL\n"); + return; + } + + if (wl->initialized) { + netdev_info(dev, "Deinitializing wilc1000...\n"); + +#if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31) + /* johnny : remove */ + PRINT_D(INIT_DBG, "skip wilc_bus_set_default_speed\n"); +#else + wilc_bus_set_default_speed(); +#endif + + PRINT_D(INIT_DBG, "Disabling IRQ\n"); +#ifdef WILC_SDIO + mutex_lock(&wl->hif_cs); + disable_sdio_interrupt(); + mutex_unlock(&wl->hif_cs); +#endif + if (&wl->txq_event != NULL) + up(&wl->txq_event); + + PRINT_D(INIT_DBG, "Deinitializing Threads\n"); + wlan_deinitialize_threads(dev); + + PRINT_D(INIT_DBG, "Deinitializing IRQ\n"); + deinit_irq(dev); + + wilc_wlan_stop(); + + PRINT_D(INIT_DBG, "Deinitializing WILC Wlan\n"); + wilc_wlan_cleanup(dev); +#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO) + #if defined(PLAT_ALLWINNER_A20) || defined(PLAT_ALLWINNER_A23) || defined(PLAT_ALLWINNER_A31) + PRINT_D(INIT_DBG, "Disabling IRQ 2\n"); + + mutex_lock(&wl->hif_cs); + disable_sdio_interrupt(); + mutex_unlock(&wl->hif_cs); + #endif +#endif + + /*De-Initialize locks*/ + PRINT_D(INIT_DBG, "Deinitializing Locks\n"); + wlan_deinit_locks(dev); + + /* announce that wilc1000 is not initialized */ + wl->initialized = false; + + PRINT_D(INIT_DBG, "wilc1000 deinitialization Done\n"); + + } else { + PRINT_D(INIT_DBG, "wilc1000 is not initialized\n"); + } +} + +int wlan_init_locks(struct net_device *dev) +{ + perInterface_wlan_t *nic; + struct wilc *wl; + + nic = netdev_priv(dev); + wl = nic->wilc; + + PRINT_D(INIT_DBG, "Initializing Locks ...\n"); + + mutex_init(&wl->hif_cs); + mutex_init(&wl->rxq_cs); + + spin_lock_init(&wl->txq_spinlock); + sema_init(&wl->txq_add_to_head_cs, 1); + + sema_init(&wl->txq_event, 0); + + sema_init(&wl->cfg_event, 0); + sema_init(&wl->sync_event, 0); + + sema_init(&wl->txq_thread_started, 0); + + return 0; +} + +static int wlan_deinit_locks(struct net_device *dev) +{ + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + PRINT_D(INIT_DBG, "De-Initializing Locks\n"); + + if (&wilc->hif_cs != NULL) + mutex_destroy(&wilc->hif_cs); + + if (&wilc->rxq_cs != NULL) + mutex_destroy(&wilc->rxq_cs); + + return 0; +} +void linux_to_wlan(wilc_wlan_inp_t *nwi, struct wilc *nic) +{ + + PRINT_D(INIT_DBG, "Linux to Wlan services ...\n"); + + nwi->os_context.os_private = (void *)nic; + +#ifdef WILC_SDIO + nwi->io_func.io_type = HIF_SDIO; + nwi->io_func.io_init = linux_sdio_init; + nwi->io_func.io_deinit = linux_sdio_deinit; + nwi->io_func.u.sdio.sdio_cmd52 = linux_sdio_cmd52; + nwi->io_func.u.sdio.sdio_cmd53 = linux_sdio_cmd53; + nwi->io_func.u.sdio.sdio_set_max_speed = linux_sdio_set_max_speed; + nwi->io_func.u.sdio.sdio_set_default_speed = linux_sdio_set_default_speed; +#else + nwi->io_func.io_type = HIF_SPI; + nwi->io_func.io_init = linux_spi_init; + nwi->io_func.io_deinit = linux_spi_deinit; + nwi->io_func.u.spi.spi_tx = linux_spi_write; + nwi->io_func.u.spi.spi_rx = linux_spi_read; + nwi->io_func.u.spi.spi_trx = linux_spi_write_read; + nwi->io_func.u.spi.spi_max_speed = linux_spi_set_max_speed; +#endif +} + +int wlan_initialize_threads(struct net_device *dev) +{ + perInterface_wlan_t *nic; + struct wilc *wilc; + int ret = 0; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + PRINT_D(INIT_DBG, "Initializing Threads ...\n"); + + /* create tx task */ + PRINT_D(INIT_DBG, "Creating kthread for transmission\n"); + wilc->txq_thread = kthread_run(linux_wlan_txq_task, (void *)dev, + "K_TXQ_TASK"); + if (!wilc->txq_thread) { + PRINT_ER("couldn't create TXQ thread\n"); + ret = -ENOBUFS; + goto _fail_2; + } + /* wait for TXQ task to start. */ + down(&wilc->txq_thread_started); + + return 0; + +_fail_2: + /*De-Initialize 2nd thread*/ + wilc->close = 0; + return ret; +} + +static void wlan_deinitialize_threads(struct net_device *dev) +{ + perInterface_wlan_t *nic; + struct wilc *wl; + + nic = netdev_priv(dev); + wl = nic->wilc; + + wl->close = 1; + PRINT_D(INIT_DBG, "Deinitializing Threads\n"); + + if (&wl->txq_event != NULL) + up(&wl->txq_event); + + if (wl->txq_thread != NULL) { + kthread_stop(wl->txq_thread); + wl->txq_thread = NULL; + } +} + +int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic) +{ + wilc_wlan_inp_t nwi; + perInterface_wlan_t *nic = p_nic; + int ret = 0; + struct wilc *wl = nic->wilc; + + if (!wl->initialized) { + wl->mac_status = WILC_MAC_STATUS_INIT; + wl->close = 0; + + wlan_init_locks(dev); + + linux_to_wlan(&nwi, wl); + + ret = wilc_wlan_init(&nwi); + if (ret < 0) { + PRINT_ER("Initializing WILC_Wlan FAILED\n"); + ret = -EIO; + goto _fail_locks_; + } + +#if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO) + if (init_irq(dev)) { + PRINT_ER("couldn't initialize IRQ\n"); + ret = -EIO; + goto _fail_locks_; + } +#endif + + ret = wlan_initialize_threads(dev); + if (ret < 0) { + PRINT_ER("Initializing Threads FAILED\n"); + ret = -EIO; + goto _fail_wilc_wlan_; + } + +#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO) + if (enable_sdio_interrupt()) { + PRINT_ER("couldn't initialize IRQ\n"); + ret = -EIO; + goto _fail_irq_init_; + } +#endif + + if (linux_wlan_get_firmware(nic)) { + PRINT_ER("Can't get firmware\n"); + ret = -EIO; + goto _fail_irq_enable_; + } + + /*Download firmware*/ + ret = linux_wlan_firmware_download(wl); + if (ret < 0) { + PRINT_ER("Failed to download firmware\n"); + ret = -EIO; + goto _fail_irq_enable_; + } + + /* Start firmware*/ + ret = linux_wlan_start_firmware(nic); + if (ret < 0) { + PRINT_ER("Failed to start firmware\n"); + ret = -EIO; + goto _fail_irq_enable_; + } + + wilc_bus_set_max_speed(); + + if (wilc_wlan_cfg_get(1, WID_FIRMWARE_VERSION, 1, 0)) { + int size; + char Firmware_ver[20]; + + size = wilc_wlan_cfg_get_val( + WID_FIRMWARE_VERSION, + Firmware_ver, sizeof(Firmware_ver)); + Firmware_ver[size] = '\0'; + PRINT_D(INIT_DBG, "***** Firmware Ver = %s *******\n", Firmware_ver); + } + /* Initialize firmware with default configuration */ + ret = linux_wlan_init_test_config(dev, wl); + + if (ret < 0) { + PRINT_ER("Failed to configure firmware\n"); + ret = -EIO; + goto _fail_fw_start_; + } + + wl->initialized = true; + return 0; /*success*/ + +_fail_fw_start_: + wilc_wlan_stop(); + +_fail_irq_enable_: +#if (defined WILC_SDIO) && (!defined WILC_SDIO_IRQ_GPIO) + disable_sdio_interrupt(); +_fail_irq_init_: +#endif +#if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO) + deinit_irq(dev); + +#endif + wlan_deinitialize_threads(dev); +_fail_wilc_wlan_: + wilc_wlan_cleanup(dev); +_fail_locks_: + wlan_deinit_locks(dev); + PRINT_ER("WLAN Iinitialization FAILED\n"); + } else { + PRINT_D(INIT_DBG, "wilc1000 already initialized\n"); + } + return ret; +} + +/* + * - this function will be called automatically by OS when module inserted. + */ + +int mac_init_fn(struct net_device *ndev) +{ + + /*Why we do this !!!*/ + netif_start_queue(ndev); /* ma */ + netif_stop_queue(ndev); /* ma */ + + return 0; +} + +/* This fn is called, when this device is setup using ifconfig */ +int mac_open(struct net_device *ndev) +{ + perInterface_wlan_t *nic; + + /*No need for setting mac address here anymore,*/ + /*Just set it in init_test_config()*/ + unsigned char mac_add[ETH_ALEN] = {0}; + int ret = 0; + int i = 0; + struct wilc_priv *priv; + struct wilc *wl; + + nic = netdev_priv(ndev); + wl = nic->wilc; + +#ifdef WILC_SPI + if (!wl|| !wl->wilc_spidev) { + netdev_err(ndev, "wilc1000: SPI device not ready\n"); + return -ENODEV; + } +#endif + nic = netdev_priv(ndev); + priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy); + PRINT_D(INIT_DBG, "MAC OPEN[%p]\n", ndev); + + ret = wilc_init_host_int(ndev); + if (ret < 0) { + PRINT_ER("Failed to initialize host interface\n"); + + return ret; + } + + /*initialize platform*/ + PRINT_D(INIT_DBG, "*** re-init ***\n"); + ret = wilc1000_wlan_init(ndev, nic); + if (ret < 0) { + PRINT_ER("Failed to initialize wilc1000\n"); + wilc_deinit_host_int(ndev); + return ret; + } + + Set_machw_change_vir_if(ndev, false); + + host_int_get_MacAddress(priv->hWILCWFIDrv, mac_add); + PRINT_D(INIT_DBG, "Mac address: %pM\n", mac_add); + + /* loop through the NUM of supported devices and set the MAC address */ + for (i = 0; i < wl->vif_num; i++) { + if (ndev == wl->vif[i].ndev) { + memcpy(wl->vif[i].src_addr, mac_add, ETH_ALEN); + wl->vif[i].hif_drv = priv->hWILCWFIDrv; + break; + } + } + + /* TODO: get MAC address whenever the source is EPROM - hardcoded and copy it to ndev*/ + memcpy(ndev->dev_addr, wl->vif[i].src_addr, ETH_ALEN); + + if (!is_valid_ether_addr(ndev->dev_addr)) { + PRINT_ER("Error: Wrong MAC address\n"); + ret = -EINVAL; + goto _err_; + } + + wilc_mgmt_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev->ieee80211_ptr, + nic->g_struct_frame_reg[0].frame_type, nic->g_struct_frame_reg[0].reg); + wilc_mgmt_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev->ieee80211_ptr, + nic->g_struct_frame_reg[1].frame_type, nic->g_struct_frame_reg[1].reg); + netif_wake_queue(ndev); + wl->open_ifcs++; + nic->mac_opened = 1; + return 0; + +_err_: + wilc_deinit_host_int(ndev); + wilc1000_wlan_deinit(ndev); + return ret; +} + +struct net_device_stats *mac_stats(struct net_device *dev) +{ + perInterface_wlan_t *nic = netdev_priv(dev); + + return &nic->netstats; +} + +/* Setup the multicast filter */ +static void wilc_set_multicast_list(struct net_device *dev) +{ + + struct netdev_hw_addr *ha; + struct wilc_priv *priv; + struct host_if_drv *pstrWFIDrv; + int i = 0; + + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + + if (!dev) + return; + + PRINT_D(INIT_DBG, "Setting Multicast List with count = %d.\n", dev->mc.count); + + if (dev->flags & IFF_PROMISC) { + /* Normally, we should configure the chip to retrive all packets + * but we don't wanna support this right now */ + /* TODO: add promiscuous mode support */ + PRINT_D(INIT_DBG, "Set promiscuous mode ON, retrive all packets\n"); + return; + } + + /* If there's more addresses than we handle, get all multicast + * packets and sort them out in software. */ + if ((dev->flags & IFF_ALLMULTI) || (dev->mc.count) > WILC_MULTICAST_TABLE_SIZE) { + PRINT_D(INIT_DBG, "Disable multicast filter, retrive all multicast packets\n"); + /* get all multicast packets */ + host_int_setup_multicast_filter(pstrWFIDrv, false, 0); + return; + } + + /* No multicast? Just get our own stuff */ + if ((dev->mc.count) == 0) { + PRINT_D(INIT_DBG, "Enable multicast filter, retrive directed packets only.\n"); + host_int_setup_multicast_filter(pstrWFIDrv, true, 0); + return; + } + + /* Store all of the multicast addresses in the hardware filter */ + netdev_for_each_mc_addr(ha, dev) + { + memcpy(gau8MulticastMacAddrList[i], ha->addr, ETH_ALEN); + PRINT_D(INIT_DBG, "Entry[%d]: %x:%x:%x:%x:%x:%x\n", i, + gau8MulticastMacAddrList[i][0], gau8MulticastMacAddrList[i][1], gau8MulticastMacAddrList[i][2], gau8MulticastMacAddrList[i][3], gau8MulticastMacAddrList[i][4], gau8MulticastMacAddrList[i][5]); + i++; + } + + host_int_setup_multicast_filter(pstrWFIDrv, true, (dev->mc.count)); + + return; + +} + +static void linux_wlan_tx_complete(void *priv, int status) +{ + + struct tx_complete_data *pv_data = (struct tx_complete_data *)priv; + + if (status == 1) + PRINT_D(TX_DBG, "Packet sent successfully - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); + else + PRINT_D(TX_DBG, "Couldn't send packet - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); + /* Free the SK Buffer, its work is done */ + dev_kfree_skb(pv_data->skb); + kfree(pv_data); +} + +int mac_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + perInterface_wlan_t *nic; + struct tx_complete_data *tx_data = NULL; + int QueueCount; + char *pu8UdpBuffer; + struct iphdr *ih; + struct ethhdr *eth_h; + struct wilc *wilc; + + nic = netdev_priv(ndev); + wilc = nic->wilc; + + PRINT_D(TX_DBG, "Sending packet just received from TCP/IP\n"); + + /* Stop the network interface queue */ + if (skb->dev != ndev) { + PRINT_ER("Packet not destined to this device\n"); + return 0; + } + + tx_data = kmalloc(sizeof(struct tx_complete_data), GFP_ATOMIC); + if (tx_data == NULL) { + PRINT_ER("Failed to allocate memory for tx_data structure\n"); + dev_kfree_skb(skb); + netif_wake_queue(ndev); + return 0; + } + + tx_data->buff = skb->data; + tx_data->size = skb->len; + tx_data->skb = skb; + + eth_h = (struct ethhdr *)(skb->data); + if (eth_h->h_proto == 0x8e88) + PRINT_D(INIT_DBG, "EAPOL transmitted\n"); + + /*get source and dest ip addresses*/ + ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); + + pu8UdpBuffer = (char *)ih + sizeof(struct iphdr); + if ((pu8UdpBuffer[1] == 68 && pu8UdpBuffer[3] == 67) || (pu8UdpBuffer[1] == 67 && pu8UdpBuffer[3] == 68)) + PRINT_D(GENERIC_DBG, "DHCP Message transmitted, type:%x %x %x\n", pu8UdpBuffer[248], pu8UdpBuffer[249], pu8UdpBuffer[250]); + + PRINT_D(TX_DBG, "Sending packet - Size = %d - Address = %p - SKB = %p\n", tx_data->size, tx_data->buff, tx_data->skb); + + /* Send packet to MAC HW - for now the tx_complete function will be just status + * indicator. still not sure if I need to suspend host transmission till the tx_complete + * function called or not? + * allocated buffer will be freed in tx_complete function. + */ + PRINT_D(TX_DBG, "Adding tx packet to TX Queue\n"); + nic->netstats.tx_packets++; + nic->netstats.tx_bytes += tx_data->size; + tx_data->pBssid = wilc->vif[nic->u8IfIdx].bssid; + QueueCount = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data, + tx_data->buff, tx_data->size, + linux_wlan_tx_complete); + + if (QueueCount > FLOW_CONTROL_UPPER_THRESHOLD) { + netif_stop_queue(wilc->vif[0].ndev); + netif_stop_queue(wilc->vif[1].ndev); + } + + return 0; +} + +int mac_close(struct net_device *ndev) +{ + struct wilc_priv *priv; + perInterface_wlan_t *nic; + struct host_if_drv *pstrWFIDrv; + struct wilc *wl; + + nic = netdev_priv(ndev); + + if ((nic == NULL) || (nic->wilc_netdev == NULL) || (nic->wilc_netdev->ieee80211_ptr == NULL) || (nic->wilc_netdev->ieee80211_ptr->wiphy == NULL)) { + PRINT_ER("nic = NULL\n"); + return 0; + } + + priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy); + wl = nic->wilc; + + if (priv == NULL) { + PRINT_ER("priv = NULL\n"); + return 0; + } + + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + + PRINT_D(GENERIC_DBG, "Mac close\n"); + + if (!wl) { + PRINT_ER("wl = NULL\n"); + return 0; + } + + if (pstrWFIDrv == NULL) { + PRINT_ER("pstrWFIDrv = NULL\n"); + return 0; + } + + if ((wl->open_ifcs) > 0) { + wl->open_ifcs--; + } else { + PRINT_ER("ERROR: MAC close called while number of opened interfaces is zero\n"); + return 0; + } + + if (nic->wilc_netdev != NULL) { + /* Stop the network interface queue */ + netif_stop_queue(nic->wilc_netdev); + + wilc_deinit_host_int(nic->wilc_netdev); + } + + if (wl->open_ifcs == 0) { + PRINT_D(GENERIC_DBG, "Deinitializing wilc1000\n"); + wl->close = 1; + wilc1000_wlan_deinit(ndev); + WILC_WFI_deinit_mon_interface(); + } + + up(&close_exit_sync); + nic->mac_opened = 0; + + return 0; +} + +int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) +{ + + u8 *buff = NULL; + s8 rssi; + u32 size = 0, length = 0; + perInterface_wlan_t *nic; + struct wilc_priv *priv; + s32 s32Error = 0; + struct wilc *wilc; + + /* struct iwreq *wrq = (struct iwreq *) req; // tony moved to case SIOCSIWPRIV */ + nic = netdev_priv(ndev); + wilc = nic->wilc; + + if (!wilc->initialized) + return 0; + + switch (cmd) { + + /* ]] 2013-06-24 */ + case SIOCSIWPRIV: + { + struct iwreq *wrq = (struct iwreq *) req; /* added by tony */ + + size = wrq->u.data.length; + + if (size && wrq->u.data.pointer) { + + buff = memdup_user(wrq->u.data.pointer, wrq->u.data.length); + if (IS_ERR(buff)) + return PTR_ERR(buff); + + if (strncasecmp(buff, "RSSI", length) == 0) { + priv = wiphy_priv(nic->wilc_netdev->ieee80211_ptr->wiphy); + s32Error = host_int_get_rssi(priv->hWILCWFIDrv, &(rssi)); + if (s32Error) + PRINT_ER("Failed to send get rssi param's message queue "); + PRINT_INFO(GENERIC_DBG, "RSSI :%d\n", rssi); + + /*Rounding up the rssi negative value*/ + rssi += 5; + + snprintf(buff, size, "rssi %d", rssi); + + if (copy_to_user(wrq->u.data.pointer, buff, size)) { + PRINT_ER("%s: failed to copy data to user buffer\n", __func__); + s32Error = -EFAULT; + goto done; + } + } + } + } + break; + + default: + { + PRINT_INFO(GENERIC_DBG, "Command - %d - has been received\n", cmd); + s32Error = -EOPNOTSUPP; + goto done; + } + } + +done: + + kfree(buff); + + return s32Error; +} + +void frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset) +{ + + unsigned int frame_len = 0; + int stats; + unsigned char *buff_to_send = NULL; + struct sk_buff *skb; + struct net_device *wilc_netdev; + perInterface_wlan_t *nic; + + wilc_netdev = GetIfHandler(wilc, buff); + if (wilc_netdev == NULL) + return; + + buff += pkt_offset; + nic = netdev_priv(wilc_netdev); + + if (size > 0) { + + frame_len = size; + buff_to_send = buff; + + /* Need to send the packet up to the host, allocate a skb buffer */ + skb = dev_alloc_skb(frame_len); + if (skb == NULL) { + PRINT_ER("Low memory - packet droped\n"); + return; + } + + if (wilc == NULL || wilc_netdev == NULL) + PRINT_ER("wilc_netdev in wilc is NULL"); + skb->dev = wilc_netdev; + + if (skb->dev == NULL) + PRINT_ER("skb->dev is NULL\n"); + + /* + * for(i=0;i<40;i++) + * { + * if(iprotocol = eth_type_trans(skb, wilc_netdev); + /* Send the packet to the stack by giving it to the bridge */ + nic->netstats.rx_packets++; + nic->netstats.rx_bytes += frame_len; + skb->ip_summed = CHECKSUM_UNNECESSARY; + stats = netif_rx(skb); + PRINT_D(RX_DBG, "netif_rx ret value is: %d\n", stats); + } +} + +void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) +{ + int i = 0; + perInterface_wlan_t *nic; + + /*Pass the frame on the monitor interface, if any.*/ + /*Otherwise, pass it on p2p0 netdev, if registered on it*/ + for (i = 0; i < wilc->vif_num; i++) { + nic = netdev_priv(wilc->vif[i].ndev); + if (nic->monitor_flag) { + WILC_WFI_monitor_rx(buff, size); + return; + } + } + + nic = netdev_priv(wilc->vif[1].ndev); /* p2p0 */ + if ((buff[0] == nic->g_struct_frame_reg[0].frame_type && nic->g_struct_frame_reg[0].reg) || + (buff[0] == nic->g_struct_frame_reg[1].frame_type && nic->g_struct_frame_reg[1].reg)) + WILC_WFI_p2p_rx(wilc->vif[1].ndev, buff, size); +} + +void wl_wlan_cleanup(void) +{ + int i = 0; + perInterface_wlan_t *nic[NUM_CONCURRENT_IFC]; + + if (g_linux_wlan && + (g_linux_wlan->vif[0].ndev || g_linux_wlan->vif[1].ndev)) { + unregister_inetaddr_notifier(&g_dev_notifier); + + for (i = 0; i < NUM_CONCURRENT_IFC; i++) + nic[i] = netdev_priv(g_linux_wlan->vif[i].ndev); + } + + if (g_linux_wlan && g_linux_wlan->firmware) + release_firmware(g_linux_wlan->firmware); + + if (g_linux_wlan && + (g_linux_wlan->vif[0].ndev || g_linux_wlan->vif[1].ndev)) { + linux_wlan_lock_timeout(&close_exit_sync, 12 * 1000); + + for (i = 0; i < NUM_CONCURRENT_IFC; i++) + if (g_linux_wlan->vif[i].ndev) + if (nic[i]->mac_opened) + mac_close(g_linux_wlan->vif[i].ndev); + + for (i = 0; i < NUM_CONCURRENT_IFC; i++) { + unregister_netdev(g_linux_wlan->vif[i].ndev); + wilc_free_wiphy(g_linux_wlan->vif[i].ndev); + free_netdev(g_linux_wlan->vif[i].ndev); + } + } + + kfree(g_linux_wlan); + +#if defined(WILC_DEBUGFS) + wilc_debugfs_remove(); +#endif + linux_wlan_device_detection(0); + linux_wlan_device_power(0); +} + +int wilc_netdev_init(struct wilc **wilc) +{ + int i; + perInterface_wlan_t *nic; + struct net_device *ndev; + + sema_init(&close_exit_sync, 0); + + /*create the common structure*/ + g_linux_wlan = kzalloc(sizeof(*g_linux_wlan), GFP_KERNEL); + if (!g_linux_wlan) + return -ENOMEM; + + *wilc = g_linux_wlan; + + register_inetaddr_notifier(&g_dev_notifier); + + for (i = 0; i < NUM_CONCURRENT_IFC; i++) { + /*allocate first ethernet device with perinterface_wlan_t as its private data*/ + ndev = alloc_etherdev(sizeof(perInterface_wlan_t)); + if (!ndev) { + PRINT_ER("Failed to allocate ethernet dev\n"); + return -1; + } + + nic = netdev_priv(ndev); + memset(nic, 0, sizeof(perInterface_wlan_t)); + + /*Name the Devices*/ + if (i == 0) { + #if defined(NM73131) /* tony, 2012-09-20 */ + strcpy(ndev->name, "wilc_eth%d"); + #elif defined(PLAT_CLM9722) /* rachel */ + strcpy(ndev->name, "eth%d"); + #else /* PANDA_BOARD, PLAT_ALLWINNER_A10, PLAT_ALLWINNER_A20, PLAT_ALLWINNER_A31, PLAT_AML8726_M3 or PLAT_WMS8304 */ + strcpy(ndev->name, "wlan%d"); + #endif + } else + strcpy(ndev->name, "p2p%d"); + + nic->u8IfIdx = g_linux_wlan->vif_num; + nic->wilc_netdev = ndev; + nic->wilc = *wilc; + g_linux_wlan->vif[g_linux_wlan->vif_num].ndev = ndev; + g_linux_wlan->vif_num++; + ndev->netdev_ops = &wilc_netdev_ops; + + { + struct wireless_dev *wdev; + /*Register WiFi*/ + wdev = wilc_create_wiphy(ndev); + + #ifdef WILC_SDIO + /* set netdev, tony */ + SET_NETDEV_DEV(ndev, &local_sdio_func->dev); + #endif + + if (wdev == NULL) { + PRINT_ER("Can't register WILC Wiphy\n"); + return -1; + } + + /*linking the wireless_dev structure with the netdevice*/ + nic->wilc_netdev->ieee80211_ptr = wdev; + nic->wilc_netdev->ml_priv = nic; + wdev->netdev = nic->wilc_netdev; + nic->netstats.rx_packets = 0; + nic->netstats.tx_packets = 0; + nic->netstats.rx_bytes = 0; + nic->netstats.tx_bytes = 0; + + } + + if (register_netdev(ndev)) { + PRINT_ER("Device couldn't be registered - %s\n", ndev->name); + return -1; /* ERROR */ + } + + nic->iftype = STATION_MODE; + nic->mac_opened = 0; + + } + + #ifndef WILC_SDIO + if (!linux_spi_init(&g_linux_wlan->wilc_spidev)) { + PRINT_ER("Can't initialize SPI\n"); + return -1; /* ERROR */ + } + g_linux_wlan->wilc_spidev = wilc_spi_dev; + #else + g_linux_wlan->wilc_sdio_func = local_sdio_func; + #endif + + return 0; +} + +/*The 1st function called after module inserted*/ +static int __init init_wilc_driver(void) +{ +#ifdef WILC_SPI + struct wilc *wilc; +#endif + +#if defined(WILC_DEBUGFS) + if (wilc_debugfs_init() < 0) { + PRINT_D(GENERIC_DBG, "fail to create debugfs for wilc driver\n"); + return -1; + } +#endif + + printk("IN INIT FUNCTION\n"); + printk("*** WILC1000 driver VERSION=[10.2] FW_VER=[10.2] ***\n"); + + linux_wlan_device_power(1); + msleep(100); + linux_wlan_device_detection(1); + +#ifdef WILC_SDIO + { + int ret; + + ret = sdio_register_driver(&wilc_bus); + if (ret < 0) + PRINT_D(INIT_DBG, "init_wilc_driver: Failed register sdio driver\n"); + + return ret; + } +#else + PRINT_D(INIT_DBG, "Initializing netdev\n"); + if (wilc_netdev_init(&wilc)) + PRINT_ER("Couldn't initialize netdev\n"); + return 0; +#endif +} +late_initcall(init_wilc_driver); + +static void __exit exit_wilc_driver(void) +{ +#ifndef WILC_SDIO + PRINT_D(INIT_DBG, "SPI unregister...\n"); + spi_unregister_driver(&wilc_bus); +#else + PRINT_D(INIT_DBG, "SDIO unregister...\n"); + sdio_unregister_driver(&wilc_bus); +#endif +} +module_exit(exit_wilc_driver); + +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/staging/wilc1000/linux_wlan_common.h b/kernel/drivers/staging/wilc1000/linux_wlan_common.h new file mode 100644 index 000000000..2b76e41eb --- /dev/null +++ b/kernel/drivers/staging/wilc1000/linux_wlan_common.h @@ -0,0 +1,170 @@ +#ifndef LINUX_WLAN_COMMON_H +#define LINUX_WLAN_COMMON_H + +enum debug_region { + Generic_debug = 0, + Hostapd_debug, + Hostinf_debug, + CFG80211_debug, + Coreconfig_debug, + Interrupt_debug, + TX_debug, + RX_debug, + Lock_debug, + Tcp_enhance, + Spin_debug, + + Init_debug, + Bus_debug, + Mem_debug, + Firmware_debug, + COMP = 0xFFFFFFFF, +}; + +#define GENERIC_DBG (1 << Generic_debug) +#define HOSTAPD_DBG (1 << Hostapd_debug) +#define HOSTINF_DBG (1 << Hostinf_debug) +#define CORECONFIG_DBG (1 << Coreconfig_debug) +#define CFG80211_DBG (1 << CFG80211_debug) +#define INT_DBG (1 << Interrupt_debug) +#define TX_DBG (1 << TX_debug) +#define RX_DBG (1 << RX_debug) +#define LOCK_DBG (1 << Lock_debug) +#define TCP_ENH (1 << Tcp_enhance) +#define SPIN_DEBUG (1 << Spin_debug) +#define INIT_DBG (1 << Init_debug) +#define BUS_DBG (1 << Bus_debug) +#define MEM_DBG (1 << Mem_debug) +#define FIRM_DBG (1 << Firmware_debug) + +#if defined (WILC_DEBUGFS) +int wilc_debugfs_init(void); +void wilc_debugfs_remove(void); + +extern atomic_t REGION; +extern atomic_t DEBUG_LEVEL; + +#define DEBUG BIT(0) +#define INFO BIT(1) +#define WRN BIT(2) +#define ERR BIT(3) + +#define PRINT_D(region, ...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & DEBUG) && \ + ((atomic_read(®ION)) & (region))) { \ + printk("DBG [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_INFO(region, ...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & INFO) && \ + ((atomic_read(®ION)) & (region))) { \ + printk("INFO [%s]", __func__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_WRN(region, ...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & WRN) && \ + ((atomic_read(®ION)) & (region))) { \ + printk("WRN [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_ER(...) \ + do { \ + if ((atomic_read(&DEBUG_LEVEL) & ERR)) { \ + printk("ERR [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#else + +#define REGION (INIT_DBG | GENERIC_DBG | CFG80211_DBG | FIRM_DBG | HOSTAPD_DBG) + +#define DEBUG 1 +#define INFO 0 +#define WRN 0 + +#define PRINT_D(region, ...) \ + do { \ + if (DEBUG == 1 && ((REGION)&(region))) { \ + printk("DBG [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_INFO(region, ...) \ + do { \ + if (INFO == 1 && ((REGION)&(region))) { \ + printk("INFO [%s]", __func__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_WRN(region, ...) \ + do { \ + if (WRN == 1 && ((REGION)&(region))) { \ + printk("WRN [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } \ + } while (0) + +#define PRINT_ER(...) \ + do { \ + printk("ERR [%s: %d]", __func__, __LINE__); \ + printk(__VA_ARGS__); \ + } while (0) +#endif + +#define FN_IN /* PRINT_D(">>> \n") */ +#define FN_OUT /* PRINT_D("<<<\n") */ + +#ifdef MEMORY_STATIC +#define LINUX_RX_SIZE (96 * 1024) +#endif +#define LINUX_TX_SIZE (64 * 1024) + + +#define WILC_MULTICAST_TABLE_SIZE 8 + +#if defined (BEAGLE_BOARD) + #define SPI_CHANNEL 4 + + #if SPI_CHANNEL == 4 + #define MODALIAS "wilc_spi4" + #define GPIO_NUM 162 + #else + #define MODALIAS "wilc_spi3" + #define GPIO_NUM 133 + #endif +#elif defined(PLAT_WMS8304) /* rachel */ + #define MODALIAS "wilc_spi" + #define GPIO_NUM 139 +#elif defined (PLAT_RKXXXX) + #define MODALIAS "WILC_IRQ" + #define GPIO_NUM RK30_PIN3_PD2 /* RK30_PIN3_PA1 */ +/* RK30_PIN3_PD2 */ +/* RK2928_PIN1_PA7 */ + +#elif defined(CUSTOMER_PLATFORM) +/* + TODO : specify MODALIAS name and GPIO number. This is certainly necessary for SPI interface. + * + * ex) + * #define MODALIAS "WILC_SPI" + * #define GPIO_NUM 139 + */ + +#else +/* base on SAMA5D3_Xplained Board */ + #define MODALIAS "WILC_SPI" + #define GPIO_NUM 0x44 +#endif +#endif diff --git a/kernel/drivers/staging/wilc1000/linux_wlan_sdio.c b/kernel/drivers/staging/wilc1000/linux_wlan_sdio.c new file mode 100644 index 000000000..4aff953a8 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/linux_wlan_sdio.c @@ -0,0 +1,251 @@ +#include "wilc_wfi_netdevice.h" + +#include +#include +#include +#include +#include + + + +#define SDIO_MODALIAS "wilc1000_sdio" + +#if defined(CUSTOMER_PLATFORM) +/* TODO : User have to stable bus clock as user's environment. */ + #ifdef MAX_BUS_SPEED + #define MAX_SPEED MAX_BUS_SPEED + #else + #define MAX_SPEED 50000000 + #endif +#else + #define MAX_SPEED (6 * 1000000) /* Max 50M */ +#endif + +struct wilc_sdio { + struct sdio_func *func; + struct wilc *wilc; +}; + +struct sdio_func *local_sdio_func; + +static unsigned int sdio_default_speed; + +#define SDIO_VENDOR_ID_WILC 0x0296 +#define SDIO_DEVICE_ID_WILC 0x5347 + +static const struct sdio_device_id wilc_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) }, + { }, +}; + + +static void wilc_sdio_interrupt(struct sdio_func *func) +{ + struct wilc_sdio *wl_sdio; + + wl_sdio = sdio_get_drvdata(func); + +#ifndef WILC_SDIO_IRQ_GPIO + sdio_release_host(func); + wilc_handle_isr(wl_sdio->wilc); + sdio_claim_host(func); +#endif +} + + +int linux_sdio_cmd52(sdio_cmd52_t *cmd) +{ + struct sdio_func *func = g_linux_wlan->wilc_sdio_func; + int ret; + u8 data; + + sdio_claim_host(func); + + func->num = cmd->function; + if (cmd->read_write) { /* write */ + if (cmd->raw) { + sdio_writeb(func, cmd->data, cmd->address, &ret); + data = sdio_readb(func, cmd->address, &ret); + cmd->data = data; + } else { + sdio_writeb(func, cmd->data, cmd->address, &ret); + } + } else { /* read */ + data = sdio_readb(func, cmd->address, &ret); + cmd->data = data; + } + + sdio_release_host(func); + + if (ret < 0) { + PRINT_ER("wilc_sdio_cmd52..failed, err(%d)\n", ret); + return 0; + } + return 1; +} + + +int linux_sdio_cmd53(sdio_cmd53_t *cmd) +{ + struct sdio_func *func = g_linux_wlan->wilc_sdio_func; + int size, ret; + + sdio_claim_host(func); + + func->num = cmd->function; + func->cur_blksize = cmd->block_size; + if (cmd->block_mode) + size = cmd->count * cmd->block_size; + else + size = cmd->count; + + if (cmd->read_write) { /* write */ + ret = sdio_memcpy_toio(func, cmd->address, (void *)cmd->buffer, size); + } else { /* read */ + ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, cmd->address, size); + } + + sdio_release_host(func); + + + if (ret < 0) { + PRINT_ER("wilc_sdio_cmd53..failed, err(%d)\n", ret); + return 0; + } + + return 1; +} + +static int linux_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + struct wilc_sdio *wl_sdio; + struct wilc *wilc; + + PRINT_D(INIT_DBG, "probe function\n"); + wl_sdio = kzalloc(sizeof(struct wilc_sdio), GFP_KERNEL); + if (!wl_sdio) + return -ENOMEM; + + PRINT_D(INIT_DBG, "Initializing netdev\n"); + local_sdio_func = func; + if (wilc_netdev_init(&wilc)) { + PRINT_ER("Couldn't initialize netdev\n"); + kfree(wl_sdio); + return -1; + } + wl_sdio->func = func; + wl_sdio->wilc = wilc; + sdio_set_drvdata(func, wl_sdio); + + printk("Driver Initializing success\n"); + return 0; +} + +static void linux_sdio_remove(struct sdio_func *func) +{ + struct wilc_sdio *wl_sdio; + + wl_sdio = sdio_get_drvdata(func); + wl_wlan_cleanup(); + kfree(wl_sdio); +} + +struct sdio_driver wilc_bus = { + .name = SDIO_MODALIAS, + .id_table = wilc_sdio_ids, + .probe = linux_sdio_probe, + .remove = linux_sdio_remove, +}; + +int enable_sdio_interrupt(void) +{ + int ret = 0; +#ifndef WILC_SDIO_IRQ_GPIO + + sdio_claim_host(local_sdio_func); + ret = sdio_claim_irq(local_sdio_func, wilc_sdio_interrupt); + sdio_release_host(local_sdio_func); + + if (ret < 0) { + PRINT_ER("can't claim sdio_irq, err(%d)\n", ret); + ret = -EIO; + } +#endif + return ret; +} + +void disable_sdio_interrupt(void) +{ + +#ifndef WILC_SDIO_IRQ_GPIO + int ret; + + PRINT_D(INIT_DBG, "disable_sdio_interrupt IN\n"); + + sdio_claim_host(local_sdio_func); + ret = sdio_release_irq(local_sdio_func); + if (ret < 0) { + PRINT_ER("can't release sdio_irq, err(%d)\n", ret); + } + sdio_release_host(local_sdio_func); + + PRINT_D(INIT_DBG, "disable_sdio_interrupt OUT\n"); +#endif +} + +static int linux_sdio_set_speed(int speed) +{ + struct mmc_ios ios; + + sdio_claim_host(local_sdio_func); + + memcpy((void *)&ios, (void *)&local_sdio_func->card->host->ios, sizeof(struct mmc_ios)); + local_sdio_func->card->host->ios.clock = speed; + ios.clock = speed; + local_sdio_func->card->host->ops->set_ios(local_sdio_func->card->host, &ios); + sdio_release_host(local_sdio_func); + PRINT_INFO(INIT_DBG, "@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed); + + return 1; +} + +static int linux_sdio_get_speed(void) +{ + return local_sdio_func->card->host->ios.clock; +} + +int linux_sdio_init(void *pv) +{ + + /** + * TODO : + **/ + + + sdio_default_speed = linux_sdio_get_speed(); + return 1; +} + +void linux_sdio_deinit(void *pv) +{ + + /** + * TODO : + **/ + + + sdio_unregister_driver(&wilc_bus); +} + +int linux_sdio_set_max_speed(void) +{ + return linux_sdio_set_speed(MAX_SPEED); +} + +int linux_sdio_set_default_speed(void) +{ + return linux_sdio_set_speed(sdio_default_speed); +} + + + diff --git a/kernel/drivers/staging/wilc1000/linux_wlan_sdio.h b/kernel/drivers/staging/wilc1000/linux_wlan_sdio.h new file mode 100644 index 000000000..4b515f510 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/linux_wlan_sdio.h @@ -0,0 +1,14 @@ +extern struct sdio_func *local_sdio_func; +extern struct sdio_driver wilc_bus; + +#include + +int linux_sdio_init(void *); +void linux_sdio_deinit(void *); +int linux_sdio_cmd52(sdio_cmd52_t *cmd); +int linux_sdio_cmd53(sdio_cmd53_t *cmd); +int enable_sdio_interrupt(void); +void disable_sdio_interrupt(void); +int linux_sdio_set_max_speed(void); +int linux_sdio_set_default_speed(void); + diff --git a/kernel/drivers/staging/wilc1000/linux_wlan_spi.c b/kernel/drivers/staging/wilc1000/linux_wlan_spi.c new file mode 100644 index 000000000..039d06192 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/linux_wlan_spi.c @@ -0,0 +1,409 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux_wlan_common.h" +#include "linux_wlan_spi.h" + +#define USE_SPI_DMA 0 /* johnny add */ + +#ifdef WILC_ASIC_A0 + #if defined(PLAT_PANDA_ES_OMAP4460) + #define MIN_SPEED 12000000 + #define MAX_SPEED 24000000 + #elif defined(PLAT_WMS8304) + #define MIN_SPEED 12000000 + #define MAX_SPEED 24000000 /* 4000000 */ + #elif defined(CUSTOMER_PLATFORM) +/* + TODO : define Clock speed under 48M. + * + * ex) + * #define MIN_SPEED 24000000 + * #define MAX_SPEED 48000000 + */ + #else + #define MIN_SPEED 24000000 + #define MAX_SPEED 48000000 + #endif +#else /* WILC_ASIC_A0 */ +/* Limit clk to 6MHz on FPGA. */ + #define MIN_SPEED 6000000 + #define MAX_SPEED 6000000 +#endif /* WILC_ASIC_A0 */ + +static u32 SPEED = MIN_SPEED; + +struct spi_device *wilc_spi_dev; +void linux_spi_deinit(void *vp); + +static int __init wilc_bus_probe(struct spi_device *spi) +{ + + PRINT_D(BUS_DBG, "spiModalias: %s\n", spi->modalias); + PRINT_D(BUS_DBG, "spiMax-Speed: %d\n", spi->max_speed_hz); + wilc_spi_dev = spi; + + printk("Driver Initializing success\n"); + return 0; +} + +static int __exit wilc_bus_remove(struct spi_device *spi) +{ + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id wilc1000_of_match[] = { + { .compatible = "atmel,wilc_spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, wilc1000_of_match); +#endif + +struct spi_driver wilc_bus __refdata = { + .driver = { + .name = MODALIAS, +#ifdef CONFIG_OF + .of_match_table = wilc1000_of_match, +#endif + }, + .probe = wilc_bus_probe, + .remove = __exit_p(wilc_bus_remove), +}; + + +void linux_spi_deinit(void *vp) +{ + + spi_unregister_driver(&wilc_bus); + + SPEED = MIN_SPEED; + PRINT_ER("@@@@@@@@@@@@ restore SPI speed to %d @@@@@@@@@\n", SPEED); + +} + + + +int linux_spi_init(void *vp) +{ + int ret = 1; + static int called; + + + if (called == 0) { + called++; + ret = spi_register_driver(&wilc_bus); + } + + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +#if defined(PLAT_WMS8304) +#define TXRX_PHASE_SIZE (4096) +#endif + +#if defined(TXRX_PHASE_SIZE) + +int linux_spi_write(u8 *b, u32 len) +{ + int ret; + + if (len > 0 && b != NULL) { + int i = 0; + int blk = len / TXRX_PHASE_SIZE; + int remainder = len % TXRX_PHASE_SIZE; + + char *r_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL); + if (!r_buffer) + return -ENOMEM; + + if (blk) { + while (i < blk) { + struct spi_message msg; + struct spi_transfer tr = { + .tx_buf = b + (i * TXRX_PHASE_SIZE), + .len = TXRX_PHASE_SIZE, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + + tr.rx_buf = r_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + i++; + + } + } + if (remainder) { + struct spi_message msg; + struct spi_transfer tr = { + .tx_buf = b + (blk * TXRX_PHASE_SIZE), + .len = remainder, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + tr.rx_buf = r_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; /* rachel */ + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + } + kfree(r_buffer); + } else { + PRINT_ER("can't write data with the following length: %d\n", len); + PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len); + ret = -1; + } + + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; + +} + +#else +int linux_spi_write(u8 *b, u32 len) +{ + + int ret; + struct spi_message msg; + + if (len > 0 && b != NULL) { + struct spi_transfer tr = { + .tx_buf = b, + .len = len, + .speed_hz = SPEED, + .delay_usecs = 0, + }; + char *r_buffer = kzalloc(len, GFP_KERNEL); + if (!r_buffer) + return -ENOMEM; + + tr.rx_buf = r_buffer; + PRINT_D(BUS_DBG, "Request writing %d bytes\n", len); + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); +/* [[johnny add */ + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; +/* ]] */ + spi_message_add_tail(&tr, &msg); + + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + + kfree(r_buffer); + } else { + PRINT_ER("can't write data with the following length: %d\n", len); + PRINT_ER("FAILED due to NULL buffer or ZERO length check the following length: %d\n", len); + ret = -1; + } + + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + + return ret; +} + +#endif + +#if defined(TXRX_PHASE_SIZE) + +int linux_spi_read(u8 *rb, u32 rlen) +{ + int ret; + + if (rlen > 0) { + int i = 0; + + int blk = rlen / TXRX_PHASE_SIZE; + int remainder = rlen % TXRX_PHASE_SIZE; + + char *t_buffer = kzalloc(TXRX_PHASE_SIZE, GFP_KERNEL); + if (!t_buffer) + return -ENOMEM; + + if (blk) { + while (i < blk) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb + (i * TXRX_PHASE_SIZE), + .len = TXRX_PHASE_SIZE, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + tr.tx_buf = t_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + i++; + } + } + if (remainder) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb + (blk * TXRX_PHASE_SIZE), + .len = remainder, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + }; + tr.tx_buf = t_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; /* rachel */ + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + } + + kfree(t_buffer); + } else { + PRINT_ER("can't read data with the following length: %u\n", rlen); + ret = -1; + } + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +#else +int linux_spi_read(u8 *rb, u32 rlen) +{ + + int ret; + + if (rlen > 0) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .len = rlen, + .speed_hz = SPEED, + .delay_usecs = 0, + + }; + char *t_buffer = kzalloc(rlen, GFP_KERNEL); + if (!t_buffer) + return -ENOMEM; + + tr.tx_buf = t_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); +/* [[ johnny add */ + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; +/* ]] */ + spi_message_add_tail(&tr, &msg); + + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + kfree(t_buffer); + } else { + PRINT_ER("can't read data with the following length: %u\n", rlen); + ret = -1; + } + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +#endif + +int linux_spi_write_read(u8 *wb, u8 *rb, u32 rlen) +{ + + int ret; + + if (rlen > 0) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .tx_buf = wb, + .len = rlen, + .speed_hz = SPEED, + .bits_per_word = 8, + .delay_usecs = 0, + + }; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = wilc_spi_dev; + msg.is_dma_mapped = USE_SPI_DMA; + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(wilc_spi_dev, &msg); + if (ret < 0) { + PRINT_ER("SPI transaction failed\n"); + } + } else { + PRINT_ER("can't read data with the following length: %u\n", rlen); + ret = -1; + } + /* change return value to match WILC interface */ + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +int linux_spi_set_max_speed(void) +{ + SPEED = MAX_SPEED; + + PRINT_INFO(BUS_DBG, "@@@@@@@@@@@@ change SPI speed to %d @@@@@@@@@\n", SPEED); + return 1; +} diff --git a/kernel/drivers/staging/wilc1000/linux_wlan_spi.h b/kernel/drivers/staging/wilc1000/linux_wlan_spi.h new file mode 100644 index 000000000..735678529 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/linux_wlan_spi.h @@ -0,0 +1,14 @@ +#ifndef LINUX_WLAN_SPI_H +#define LINUX_WLAN_SPI_H + +#include +extern struct spi_device *wilc_spi_dev; +extern struct spi_driver wilc_bus; + +int linux_spi_init(void *vp); +void linux_spi_deinit(void *vp); +int linux_spi_write(u8 *b, u32 len); +int linux_spi_read(u8 *rb, u32 rlen); +int linux_spi_write_read(u8 *wb, u8 *rb, u32 rlen); +int linux_spi_set_max_speed(void); +#endif diff --git a/kernel/drivers/staging/wilc1000/wilc_debugfs.c b/kernel/drivers/staging/wilc1000/wilc_debugfs.c new file mode 100644 index 000000000..ae111862e --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_debugfs.c @@ -0,0 +1,181 @@ +/* + * NewportMedia WiFi chipset driver test tools - wilc-debug + * Copyright (c) 2012 NewportMedia Inc. + * Author: SSW + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#if defined(WILC_DEBUGFS) +#include +#include +#include +#include + +#include "wilc_wlan_if.h" + + +static struct dentry *wilc_dir; + +/* + * -------------------------------------------------------------------------------- + */ + +#define DBG_REGION_ALL (GENERIC_DBG | HOSTAPD_DBG | HOSTINF_DBG | CORECONFIG_DBG | CFG80211_DBG | INT_DBG | TX_DBG | RX_DBG | LOCK_DBG | INIT_DBG | BUS_DBG | MEM_DBG) +#define DBG_LEVEL_ALL (DEBUG | INFO | WRN | ERR) +atomic_t REGION = ATOMIC_INIT(INIT_DBG | GENERIC_DBG | CFG80211_DBG | FIRM_DBG | HOSTAPD_DBG); +atomic_t DEBUG_LEVEL = ATOMIC_INIT(ERR); + +/* + * -------------------------------------------------------------------------------- + */ + + +static ssize_t wilc_debug_level_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) +{ + char buf[128]; + int res = 0; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), "Debug Level: %x\n", atomic_read(&DEBUG_LEVEL)); + + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static ssize_t wilc_debug_level_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + int flag = 0; + int ret; + + ret = kstrtouint_from_user(buf, count, 16, &flag); + if (ret) + return ret; + + if (flag > DBG_LEVEL_ALL) { + printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(&DEBUG_LEVEL)); + return -EINVAL; + } + + atomic_set(&DEBUG_LEVEL, (int)flag); + + if (flag == 0) + printk("Debug-level disabled\n"); + else + printk("Debug-level enabled\n"); + + return count; +} + +static ssize_t wilc_debug_region_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) +{ + char buf[128]; + int res = 0; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), "Debug region: %x\n", atomic_read(®ION)); + + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +static ssize_t wilc_debug_region_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) +{ + char buffer[128] = {}; + int flag; + + if (count > sizeof(buffer)) + return -EINVAL; + + if (copy_from_user(buffer, buf, count)) { + return -EFAULT; + } + + flag = buffer[0] - '0'; + + if (flag > DBG_REGION_ALL) { + printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(®ION)); + return -EFAULT; + } + + atomic_set(®ION, (int)flag); + printk("new debug-region is %x\n", atomic_read(®ION)); + + return count; +} + +/* + * -------------------------------------------------------------------------------- + */ + +#define FOPS(_open, _read, _write, _poll) { \ + .owner = THIS_MODULE, \ + .open = (_open), \ + .read = (_read), \ + .write = (_write), \ + .poll = (_poll), \ +} + +struct wilc_debugfs_info_t { + const char *name; + int perm; + unsigned int data; + struct file_operations fops; +}; + +static struct wilc_debugfs_info_t debugfs_info[] = { + { "wilc_debug_level", 0666, (DEBUG | ERR), FOPS(NULL, wilc_debug_level_read, wilc_debug_level_write, NULL), }, + { "wilc_debug_region", 0666, (INIT_DBG | GENERIC_DBG | CFG80211_DBG), FOPS(NULL, wilc_debug_region_read, wilc_debug_region_write, NULL), }, +}; + +int wilc_debugfs_init(void) +{ + int i; + + struct dentry *debugfs_files; + struct wilc_debugfs_info_t *info; + + wilc_dir = debugfs_create_dir("wilc_wifi", NULL); + if (wilc_dir == ERR_PTR(-ENODEV)) { + /* it's not error. the debugfs is just not being enabled. */ + printk("ERR, kernel has built without debugfs support\n"); + return 0; + } + + if (!wilc_dir) { + printk("ERR, debugfs create dir\n"); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(debugfs_info); i++) { + info = &debugfs_info[i]; + debugfs_files = debugfs_create_file(info->name, + info->perm, + wilc_dir, + &info->data, + &info->fops); + + if (!debugfs_files) { + printk("ERR fail to create the debugfs file, %s\n", info->name); + debugfs_remove_recursive(wilc_dir); + return -1; + } + } + return 0; +} + +void wilc_debugfs_remove(void) +{ + debugfs_remove_recursive(wilc_dir); +} + +#endif + diff --git a/kernel/drivers/staging/wilc1000/wilc_msgqueue.c b/kernel/drivers/staging/wilc1000/wilc_msgqueue.c new file mode 100644 index 000000000..0eff121b8 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_msgqueue.c @@ -0,0 +1,178 @@ + +#include "wilc_msgqueue.h" +#include +#include "linux_wlan_common.h" +#include +#include + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +int wilc_mq_create(WILC_MsgQueueHandle *pHandle) +{ + spin_lock_init(&pHandle->strCriticalSection); + sema_init(&pHandle->hSem, 0); + pHandle->pstrMessageList = NULL; + pHandle->u32ReceiversCount = 0; + pHandle->bExiting = false; + return 0; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +int wilc_mq_destroy(WILC_MsgQueueHandle *pHandle) +{ + pHandle->bExiting = true; + + /* Release any waiting receiver thread. */ + while (pHandle->u32ReceiversCount > 0) { + up(&pHandle->hSem); + pHandle->u32ReceiversCount--; + } + + while (pHandle->pstrMessageList) { + Message *pstrMessge = pHandle->pstrMessageList->pstrNext; + + kfree(pHandle->pstrMessageList); + pHandle->pstrMessageList = pstrMessge; + } + + return 0; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +int wilc_mq_send(WILC_MsgQueueHandle *pHandle, + const void *pvSendBuffer, u32 u32SendBufferSize) +{ + unsigned long flags; + Message *pstrMessage = NULL; + + if ((!pHandle) || (u32SendBufferSize == 0) || (!pvSendBuffer)) { + PRINT_ER("pHandle or pvSendBuffer is null\n"); + return -EFAULT; + } + + if (pHandle->bExiting) { + PRINT_ER("pHandle fail\n"); + return -EFAULT; + } + + /* construct a new message */ + pstrMessage = kmalloc(sizeof(Message), GFP_ATOMIC); + if (!pstrMessage) + return -ENOMEM; + + pstrMessage->u32Length = u32SendBufferSize; + pstrMessage->pstrNext = NULL; + pstrMessage->pvBuffer = kmemdup(pvSendBuffer, u32SendBufferSize, + GFP_ATOMIC); + if (!pstrMessage->pvBuffer) { + kfree(pstrMessage); + return -ENOMEM; + } + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + + /* add it to the message queue */ + if (!pHandle->pstrMessageList) { + pHandle->pstrMessageList = pstrMessage; + } else { + Message *pstrTailMsg = pHandle->pstrMessageList; + + while (pstrTailMsg->pstrNext) + pstrTailMsg = pstrTailMsg->pstrNext; + + pstrTailMsg->pstrNext = pstrMessage; + } + + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + + up(&pHandle->hSem); + + return 0; +} + +/*! + * @author syounan + * @date 1 Sep 2010 + * @note copied from FLO glue implementatuion + * @version 1.0 + */ +int wilc_mq_recv(WILC_MsgQueueHandle *pHandle, + void *pvRecvBuffer, u32 u32RecvBufferSize, + u32 *pu32ReceivedLength) +{ + Message *pstrMessage; + int result = 0; + unsigned long flags; + + if ((!pHandle) || (u32RecvBufferSize == 0) + || (!pvRecvBuffer) || (!pu32ReceivedLength)) { + PRINT_ER("pHandle or pvRecvBuffer is null\n"); + return -EINVAL; + } + + if (pHandle->bExiting) { + PRINT_ER("pHandle fail\n"); + return -EFAULT; + } + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + pHandle->u32ReceiversCount++; + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + + down(&pHandle->hSem); + + /* other non-timeout scenarios */ + if (result) { + PRINT_ER("Non-timeout\n"); + return result; + } + + if (pHandle->bExiting) { + PRINT_ER("pHandle fail\n"); + return -EFAULT; + } + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + + pstrMessage = pHandle->pstrMessageList; + if (!pstrMessage) { + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + PRINT_ER("pstrMessage is null\n"); + return -EFAULT; + } + /* check buffer size */ + if (u32RecvBufferSize < pstrMessage->u32Length) { + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + up(&pHandle->hSem); + PRINT_ER("u32RecvBufferSize overflow\n"); + return -EOVERFLOW; + } + + /* consume the message */ + pHandle->u32ReceiversCount--; + memcpy(pvRecvBuffer, pstrMessage->pvBuffer, pstrMessage->u32Length); + *pu32ReceivedLength = pstrMessage->u32Length; + + pHandle->pstrMessageList = pstrMessage->pstrNext; + + kfree(pstrMessage->pvBuffer); + kfree(pstrMessage); + + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + + return result; +} diff --git a/kernel/drivers/staging/wilc1000/wilc_msgqueue.h b/kernel/drivers/staging/wilc1000/wilc_msgqueue.h new file mode 100644 index 000000000..d231c334e --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_msgqueue.h @@ -0,0 +1,94 @@ +#ifndef __WILC_MSG_QUEUE_H__ +#define __WILC_MSG_QUEUE_H__ + +/*! + * @file wilc_msgqueue.h + * @brief Message Queue OS wrapper functionality + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 30 Aug 2010 + * @version 1.0 + */ + +#include + +/* Message Queue type is a structure */ +typedef struct __Message_struct { + void *pvBuffer; + u32 u32Length; + struct __Message_struct *pstrNext; +} Message; + +typedef struct __MessageQueue_struct { + struct semaphore hSem; + spinlock_t strCriticalSection; + bool bExiting; + u32 u32ReceiversCount; + Message *pstrMessageList; +} WILC_MsgQueueHandle; + +/*! + * @brief Creates a new Message queue + * @details Creates a new Message queue, if the feature + * CONFIG_WILC_MSG_QUEUE_IPC_NAME is enabled and pstrAttrs->pcName + * is not Null, then this message queue can be used for IPC with + * any other message queue having the same name in the system + * @param[in,out] pHandle handle to the message queue object + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +int wilc_mq_create(WILC_MsgQueueHandle *pHandle); + +/*! + * @brief Sends a message + * @details Sends a message, this API will block unil the message is + * actually sent or until it is timedout (as long as the feature + * CONFIG_WILC_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout + * is not set to WILC_OS_INFINITY), zero timeout is a valid value + * @param[in] pHandle handle to the message queue object + * @param[in] pvSendBuffer pointer to the data to send + * @param[in] u32SendBufferSize the size of the data to send + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +int wilc_mq_send(WILC_MsgQueueHandle *pHandle, + const void *pvSendBuffer, u32 u32SendBufferSize); + +/*! + * @brief Receives a message + * @details Receives a message, this API will block unil a message is + * received or until it is timedout (as long as the feature + * CONFIG_WILC_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout + * is not set to WILC_OS_INFINITY), zero timeout is a valid value + * @param[in] pHandle handle to the message queue object + * @param[out] pvRecvBuffer pointer to a buffer to fill with the received message + * @param[in] u32RecvBufferSize the size of the receive buffer + * @param[out] pu32ReceivedLength the length of received data + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +int wilc_mq_recv(WILC_MsgQueueHandle *pHandle, + void *pvRecvBuffer, u32 u32RecvBufferSize, + u32 *pu32ReceivedLength); + +/*! + * @brief Destroys an existing Message queue + * @param[in] pHandle handle to the message queue object + * @param[in] pstrAttrs Optional attributes, NULL for default + * @return Error code indicating sucess/failure + * @author syounan + * @date 30 Aug 2010 + * @version 1.0 + */ +int wilc_mq_destroy(WILC_MsgQueueHandle *pHandle); + +#endif diff --git a/kernel/drivers/staging/wilc1000/wilc_sdio.c b/kernel/drivers/staging/wilc1000/wilc_sdio.c new file mode 100644 index 000000000..300c571e4 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_sdio.c @@ -0,0 +1,1014 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_sdio.c */ +/* */ +/* */ +/* //////////////////////////////////////////////////////////////////////////// */ + +#include +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" + +#define WILC_SDIO_BLOCK_SIZE 512 + +typedef struct { + void *os_context; + u32 block_size; + int (*sdio_cmd52)(sdio_cmd52_t *); + int (*sdio_cmd53)(sdio_cmd53_t *); + int (*sdio_set_max_speed)(void); + int (*sdio_set_default_speed)(void); + wilc_debug_func dPrint; + int nint; +#define MAX_NUN_INT_THRPT_ENH2 (5) /* Max num interrupts allowed in registers 0xf7, 0xf8 */ + int has_thrpt_enh3; +} wilc_sdio_t; + +static wilc_sdio_t g_sdio; + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_write_reg(u32 addr, u32 data); +static int sdio_read_reg(u32 addr, u32 *data); +#endif + +/******************************************** + * + * Function 0 + * + ********************************************/ + +static int sdio_set_func0_csa_address(u32 adr) +{ + sdio_cmd52_t cmd; + + /** + * Review: BIG ENDIAN + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10c; + cmd.data = (u8)adr; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10c data...\n"); + goto _fail_; + } + + cmd.address = 0x10d; + cmd.data = (u8)(adr >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10d data...\n"); + goto _fail_; + } + + cmd.address = 0x10e; + cmd.data = (u8)(adr >> 16); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10e data...\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_set_func0_block_size(u32 block_size) +{ + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10; + cmd.data = (u8)block_size; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x10 data...\n"); + goto _fail_; + } + + cmd.address = 0x11; + cmd.data = (u8)(block_size >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x11 data...\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +/******************************************** + * + * Function 1 + * + ********************************************/ + +static int sdio_set_func1_block_size(u32 block_size) +{ + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x110; + cmd.data = (u8)block_size; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x110 data...\n"); + goto _fail_; + } + cmd.address = 0x111; + cmd.data = (u8)(block_size >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0x111 data...\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_clear_int(void) +{ +#ifndef WILC_SDIO_IRQ_GPIO + /* u32 sts; */ + sdio_cmd52_t cmd; + + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x4; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + + return cmd.data; +#else + u32 reg; + + if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, ®)) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0); + return 0; + } + reg &= ~0x1; + sdio_write_reg(WILC_HOST_RX_CTRL_0, reg); + return 1; +#endif + +} + +u32 sdio_xfer_cnt(void) +{ + u32 cnt = 0; + sdio_cmd52_t cmd; + + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x1C; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + cnt = cmd.data; + + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x1D; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + cnt |= (cmd.data << 8); + + cmd.read_write = 0; + cmd.function = 1; + cmd.raw = 0; + cmd.address = 0x1E; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + cnt |= (cmd.data << 16); + + return cnt; +} + +/******************************************** + * + * Sdio interfaces + * + ********************************************/ +int sdio_check_bs(void) +{ + sdio_cmd52_t cmd; + + /** + * poll until BS is 0 + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xc; + cmd.data = 0; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get BS register...\n"); + goto _fail_; + } + + return 1; + +_fail_: + + return 0; +} + +static int sdio_write_reg(u32 addr, u32 data) +{ +#ifdef BIG_ENDIAN + data = BYTE_SWAP(data); +#endif + + if ((addr >= 0xf0) && (addr <= 0xff)) { + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + cmd.data = data; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr); + goto _fail_; + } + } else { + sdio_cmd53_t cmd; + + /** + * set the AHB address + **/ + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + + cmd.read_write = 1; + cmd.function = 0; + cmd.address = 0x10f; + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = 4; + cmd.buffer = (u8 *)&data; + cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ + + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, write reg (%08x)...\n", addr); + goto _fail_; + } + } + + return 1; + +_fail_: + + return 0; +} + +static int sdio_write(u32 addr, u8 *buf, u32 size) +{ + u32 block_size = g_sdio.block_size; + sdio_cmd53_t cmd; + int nblk, nleft; + + cmd.read_write = 1; + if (addr > 0) { + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } + + /** + * func 0 access + **/ + cmd.function = 0; + cmd.address = 0x10f; + } else { + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } + + /** + * func 1 access + **/ + cmd.function = 1; + cmd.address = 0; + } + + nblk = size / block_size; + nleft = size % block_size; + + if (nblk > 0) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = nblk; + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr); + goto _fail_; + } + if (addr > 0) + addr += nblk * block_size; + buf += nblk * block_size; + } + + if (nleft > 0) { + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = nleft; + cmd.buffer = buf; + + cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes send...\n", addr); + goto _fail_; + } + } + + return 1; + +_fail_: + + return 0; +} + +static int sdio_read_reg(u32 addr, u32 *data) +{ + if ((addr >= 0xf0) && (addr <= 0xff)) { + sdio_cmd52_t cmd; + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd 52, read reg (%08x) ...\n", addr); + goto _fail_; + } + *data = cmd.data; + } else { + sdio_cmd53_t cmd; + + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + + cmd.read_write = 0; + cmd.function = 0; + cmd.address = 0x10f; + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = 4; + cmd.buffer = (u8 *)data; + + cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ + + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53, read reg (%08x)...\n", addr); + goto _fail_; + } + } + +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + + return 1; + +_fail_: + + return 0; +} + +static int sdio_read(u32 addr, u8 *buf, u32 size) +{ + u32 block_size = g_sdio.block_size; + sdio_cmd53_t cmd; + int nblk, nleft; + + cmd.read_write = 0; + if (addr > 0) { + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } + + /** + * func 0 access + **/ + cmd.function = 0; + cmd.address = 0x10f; + } else { + /** + * has to be word aligned... + **/ + if (size & 0x3) { + size += 4; + size &= ~0x3; + } + + /** + * func 1 access + **/ + cmd.function = 1; + cmd.address = 0; + } + + nblk = size / block_size; + nleft = size % block_size; + + if (nblk > 0) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = nblk; + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); + goto _fail_; + } + if (addr > 0) + addr += nblk * block_size; + buf += nblk * block_size; + } /* if (nblk > 0) */ + + if (nleft > 0) { + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = nleft; + cmd.buffer = buf; + + cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes read...\n", addr); + goto _fail_; + } + } + + return 1; + +_fail_: + + return 0; +} + +/******************************************** + * + * Bus interfaces + * + ********************************************/ + +static int sdio_deinit(void *pv) +{ + return 1; +} + +static int sdio_sync(void) +{ + u32 reg; + + /** + * Disable power sequencer + **/ + if (!sdio_read_reg(WILC_MISC, ®)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n"); + return 0; + } + + reg &= ~BIT(8); + if (!sdio_write_reg(WILC_MISC, reg)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n"); + return 0; + } + +#ifdef WILC_SDIO_IRQ_GPIO + { + u32 reg; + int ret; + + /** + * interrupt pin mux select + **/ + ret = sdio_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= BIT(8); + ret = sdio_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = sdio_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + reg |= BIT(16); + ret = sdio_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + } +#endif + + return 1; +} + +static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func) +{ + sdio_cmd52_t cmd; + int loop; + u32 chipid; + + memset(&g_sdio, 0, sizeof(wilc_sdio_t)); + + g_sdio.dPrint = func; + g_sdio.os_context = inp->os_context.os_private; + + if (inp->io_func.io_init) { + if (!inp->io_func.io_init(g_sdio.os_context)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed io init bus...\n"); + return 0; + } + } else { + return 0; + } + + g_sdio.sdio_cmd52 = inp->io_func.u.sdio.sdio_cmd52; + g_sdio.sdio_cmd53 = inp->io_func.u.sdio.sdio_cmd53; + g_sdio.sdio_set_max_speed = inp->io_func.u.sdio.sdio_set_max_speed; + g_sdio.sdio_set_default_speed = inp->io_func.u.sdio.sdio_set_default_speed; + + /** + * function 0 csa enable + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = 0x100; + cmd.data = 0x80; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, enable csa...\n"); + goto _fail_; + } + + /** + * function 0 block size + **/ + if (!sdio_set_func0_block_size(WILC_SDIO_BLOCK_SIZE)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set func 0 block size...\n"); + goto _fail_; + } + g_sdio.block_size = WILC_SDIO_BLOCK_SIZE; + + /** + * enable func1 IO + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = 0x2; + cmd.data = 0x2; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio] Fail cmd 52, set IOE register...\n"); + goto _fail_; + } + + /** + * make sure func 1 is up + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x3; + loop = 3; + do { + cmd.data = 0; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, get IOR register...\n"); + goto _fail_; + } + if (cmd.data == 0x2) + break; + } while (loop--); + + if (loop <= 0) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail func 1 is not ready...\n"); + goto _fail_; + } + + /** + * func 1 is ready, set func 1 block size + **/ + if (!sdio_set_func1_block_size(WILC_SDIO_BLOCK_SIZE)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail set func 1 block size...\n"); + goto _fail_; + } + + /** + * func 1 interrupt enable + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = 0x4; + cmd.data = 0x3; + if (!g_sdio.sdio_cmd52(&cmd)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd 52, set IEN register...\n"); + goto _fail_; + } + + /** + * make sure can read back chip id correctly + **/ + if (!sdio_read_reg(0x1000, &chipid)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Fail cmd read chip id...\n"); + goto _fail_; + } + g_sdio.dPrint(N_ERR, "[wilc sdio]: chipid (%08x)\n", chipid); + if ((chipid & 0xfff) > 0x2a0) + g_sdio.has_thrpt_enh3 = 1; + else + g_sdio.has_thrpt_enh3 = 0; + g_sdio.dPrint(N_ERR, "[wilc sdio]: has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3); + + return 1; + +_fail_: + + return 0; +} + +static void sdio_set_max_speed(void) +{ + g_sdio.sdio_set_max_speed(); +} + +static void sdio_set_default_speed(void) +{ + g_sdio.sdio_set_default_speed(); +} + +static int sdio_read_size(u32 *size) +{ + + u32 tmp; + sdio_cmd52_t cmd; + + /** + * Read DMA count in words + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf2; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + tmp = cmd.data; + + /* cmd.read_write = 0; */ + /* cmd.function = 0; */ + /* cmd.raw = 0; */ + cmd.address = 0xf3; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + tmp |= (cmd.data << 8); + + *size = tmp; + return 1; +} + +static int sdio_read_int(u32 *int_status) +{ + + u32 tmp; + sdio_cmd52_t cmd; + + sdio_read_size(&tmp); + + /** + * Read IRQ flags + **/ +#ifndef WILC_SDIO_IRQ_GPIO + cmd.function = 1; + cmd.address = 0x04; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + + if (cmd.data & BIT(0)) + tmp |= INT_0; + if (cmd.data & BIT(2)) + tmp |= INT_1; + if (cmd.data & BIT(3)) + tmp |= INT_2; + if (cmd.data & BIT(4)) + tmp |= INT_3; + if (cmd.data & BIT(5)) + tmp |= INT_4; + if (cmd.data & BIT(6)) + tmp |= INT_5; + { + int i; + + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { + if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt (1) : tmp=%x, data=%x\n", tmp, cmd.data); + break; + } + } + } +#else + { + u32 irq_flags; + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf7; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + irq_flags = cmd.data & 0x1f; + tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET); + } + +#endif + + *int_status = tmp; + + return 1; +} + +static int sdio_clear_int_ext(u32 val) +{ + int ret; + + if (g_sdio.has_thrpt_enh3) { + u32 reg; + +#ifdef WILC_SDIO_IRQ_GPIO + { + u32 flags; + + flags = val & (BIT(MAX_NUN_INT_THRPT_ENH2) - 1); + reg = flags; + } +#else + reg = 0; +#endif + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + reg |= BIT(5); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + reg |= BIT(6); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + reg |= BIT(7); + if (reg) { + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf8; + cmd.data = reg; + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__); + goto _fail_; + } + + } + } else { +#ifdef WILC_SDIO_IRQ_GPIO + { + /* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */ + /* Cannot clear multiple interrupts. Must clear each interrupt individually */ + u32 flags; + + flags = val & (BIT(MAX_NUM_INT) - 1); + if (flags) { + int i; + + ret = 1; + for (i = 0; i < g_sdio.nint; i++) { + if (flags & 1) { + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf8; + cmd.data = BIT(i); + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf8 data (%d) ...\n", __LINE__); + goto _fail_; + } + + } + if (!ret) + break; + flags >>= 1; + } + if (!ret) + goto _fail_; + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) + g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt cleared %d...\n", i); + flags >>= 1; + } + } + } +#endif /* WILC_SDIO_IRQ_GPIO */ + + { + u32 vmm_ctl; + + vmm_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + vmm_ctl |= BIT(0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + vmm_ctl |= BIT(1); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + vmm_ctl |= BIT(2); + + if (vmm_ctl) { + sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf6; + cmd.data = vmm_ctl; + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd52, set 0xf6 data (%d) ...\n", __LINE__); + goto _fail_; + } + } + } + } + + return 1; +_fail_: + return 0; +} + +static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) +{ + u32 reg; + + if (nint > MAX_NUM_INT) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Too many interupts (%d)...\n", nint); + return 0; + } + if (nint > MAX_NUN_INT_THRPT_ENH2) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Error: Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n"); + return 0; + } + + g_sdio.nint = nint; + + /** + * Disable power sequencer + **/ + if (!sdio_read_reg(WILC_MISC, ®)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read misc reg...\n"); + return 0; + } + + reg &= ~BIT(8); + if (!sdio_write_reg(WILC_MISC, reg)) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write misc reg...\n"); + return 0; + } + +#ifdef WILC_SDIO_IRQ_GPIO + { + u32 reg; + int ret, i; + + /** + * interrupt pin mux select + **/ + ret = sdio_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= BIT(8); + ret = sdio_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = sdio_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) + reg |= BIT((27 + i)); + ret = sdio_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + if (nint) { + ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) + reg |= BIT(i); + + ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + } + } +#endif /* WILC_SDIO_IRQ_GPIO */ + return 1; +} + +/******************************************** + * + * Global sdio HIF function table + * + ********************************************/ + +wilc_hif_func_t hif_sdio = { + sdio_init, + sdio_deinit, + sdio_read_reg, + sdio_write_reg, + sdio_read, + sdio_write, + sdio_sync, + sdio_clear_int, + sdio_read_int, + sdio_clear_int_ext, + sdio_read_size, + sdio_write, + sdio_read, + sdio_sync_ext, + + sdio_set_max_speed, + sdio_set_default_speed, +}; + diff --git a/kernel/drivers/staging/wilc1000/wilc_spi.c b/kernel/drivers/staging/wilc1000/wilc_spi.c new file mode 100644 index 000000000..599508bea --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_spi.c @@ -0,0 +1,1276 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_spi.c */ +/* */ +/* */ +/* //////////////////////////////////////////////////////////////////////////// */ + +#include +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" + +typedef struct { + void *os_context; + int (*spi_tx)(u8 *, u32); + int (*spi_rx)(u8 *, u32); + int (*spi_trx)(u8 *, u8 *, u32); + int (*spi_max_speed)(void); + wilc_debug_func dPrint; + int crc_off; + int nint; + int has_thrpt_enh; +} wilc_spi_t; + +static wilc_spi_t g_spi; + +static int spi_read(u32, u8 *, u32); +static int spi_write(u32, u8 *, u32); + +/******************************************** + * + * Crc7 + * + ********************************************/ + +static const u8 crc7_syndrome_table[256] = { + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, + 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, + 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, + 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, + 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, + 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, + 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, + 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c, + 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, + 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, + 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, + 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, + 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, + 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21, + 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, + 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, + 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, + 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, + 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, + 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f, + 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, + 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, + 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, + 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, + 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52, + 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, + 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, + 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, + 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, + 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, + 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79 +}; + +static u8 crc7_byte(u8 crc, u8 data) +{ + return crc7_syndrome_table[(crc << 1) ^ data]; +} + +static u8 crc7(u8 crc, const u8 *buffer, u32 len) +{ + while (len--) + crc = crc7_byte(crc, *buffer++); + return crc; +} + +/******************************************** + * + * Spi protocol Function + * + ********************************************/ + +#define CMD_DMA_WRITE 0xc1 +#define CMD_DMA_READ 0xc2 +#define CMD_INTERNAL_WRITE 0xc3 +#define CMD_INTERNAL_READ 0xc4 +#define CMD_TERMINATE 0xc5 +#define CMD_REPEAT 0xc6 +#define CMD_DMA_EXT_WRITE 0xc7 +#define CMD_DMA_EXT_READ 0xc8 +#define CMD_SINGLE_WRITE 0xc9 +#define CMD_SINGLE_READ 0xca +#define CMD_RESET 0xcf + +#define N_OK 1 +#define N_FAIL 0 +#define N_RESET -1 +#define N_RETRY -2 + +#define DATA_PKT_SZ_256 256 +#define DATA_PKT_SZ_512 512 +#define DATA_PKT_SZ_1K 1024 +#define DATA_PKT_SZ_4K (4 * 1024) +#define DATA_PKT_SZ_8K (8 * 1024) +#define DATA_PKT_SZ DATA_PKT_SZ_8K + +static int spi_cmd(u8 cmd, u32 adr, u32 data, u32 sz, u8 clockless) +{ + u8 bc[9]; + int len = 5; + int result = N_OK; + + bc[0] = cmd; + switch (cmd) { + case CMD_SINGLE_READ: /* single word (4 bytes) read */ + bc[1] = (u8)(adr >> 16); + bc[2] = (u8)(adr >> 8); + bc[3] = (u8)adr; + len = 5; + break; + + case CMD_INTERNAL_READ: /* internal register read */ + bc[1] = (u8)(adr >> 8); + if (clockless) + bc[1] |= BIT(7); + bc[2] = (u8)adr; + bc[3] = 0x00; + len = 5; + break; + + case CMD_TERMINATE: /* termination */ + bc[1] = 0x00; + bc[2] = 0x00; + bc[3] = 0x00; + len = 5; + break; + + case CMD_REPEAT: /* repeat */ + bc[1] = 0x00; + bc[2] = 0x00; + bc[3] = 0x00; + len = 5; + break; + + case CMD_RESET: /* reset */ + bc[1] = 0xff; + bc[2] = 0xff; + bc[3] = 0xff; + len = 5; + break; + + case CMD_DMA_WRITE: /* dma write */ + case CMD_DMA_READ: /* dma read */ + bc[1] = (u8)(adr >> 16); + bc[2] = (u8)(adr >> 8); + bc[3] = (u8)adr; + bc[4] = (u8)(sz >> 8); + bc[5] = (u8)(sz); + len = 7; + break; + + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + bc[1] = (u8)(adr >> 16); + bc[2] = (u8)(adr >> 8); + bc[3] = (u8)adr; + bc[4] = (u8)(sz >> 16); + bc[5] = (u8)(sz >> 8); + bc[6] = (u8)(sz); + len = 8; + break; + + case CMD_INTERNAL_WRITE: /* internal register write */ + bc[1] = (u8)(adr >> 8); + if (clockless) + bc[1] |= BIT(7); + bc[2] = (u8)(adr); + bc[3] = (u8)(data >> 24); + bc[4] = (u8)(data >> 16); + bc[5] = (u8)(data >> 8); + bc[6] = (u8)(data); + len = 8; + break; + + case CMD_SINGLE_WRITE: /* single word write */ + bc[1] = (u8)(adr >> 16); + bc[2] = (u8)(adr >> 8); + bc[3] = (u8)(adr); + bc[4] = (u8)(data >> 24); + bc[5] = (u8)(data >> 16); + bc[6] = (u8)(data >> 8); + bc[7] = (u8)(data); + len = 9; + break; + + default: + result = N_FAIL; + break; + } + + if (result) { + if (!g_spi.crc_off) + bc[len - 1] = (crc7(0x7f, (const u8 *)&bc[0], len - 1)) << 1; + else + len -= 1; + + if (!g_spi.spi_tx(bc, len)) { + PRINT_ER("[wilc spi]: Failed cmd write, bus error...\n"); + result = N_FAIL; + } + } + + return result; +} + +static int spi_cmd_rsp(u8 cmd) +{ + u8 rsp; + int result = N_OK; + + /** + * Command/Control response + **/ + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + if (!g_spi.spi_rx(&rsp, 1)) { + result = N_FAIL; + goto _fail_; + } + } + + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed cmd response read, bus error...\n"); + result = N_FAIL; + goto _fail_; + } + + if (rsp != cmd) { + PRINT_ER("[wilc spi]: Failed cmd response, cmd (%02x), resp (%02x)\n", cmd, rsp); + result = N_FAIL; + goto _fail_; + } + + /** + * State response + **/ + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed cmd state read, bus error...\n"); + result = N_FAIL; + goto _fail_; + } + + if (rsp != 0x00) { + PRINT_ER("[wilc spi]: Failed cmd state response state (%02x)\n", rsp); + result = N_FAIL; + } + +_fail_: + + return result; +} + +static int spi_cmd_complete(u8 cmd, u32 adr, u8 *b, u32 sz, u8 clockless) +{ + u8 wb[32], rb[32]; + u8 wix, rix; + u32 len2; + u8 rsp; + int len = 0; + int result = N_OK; + + wb[0] = cmd; + switch (cmd) { + case CMD_SINGLE_READ: /* single word (4 bytes) read */ + wb[1] = (u8)(adr >> 16); + wb[2] = (u8)(adr >> 8); + wb[3] = (u8)adr; + len = 5; + break; + + case CMD_INTERNAL_READ: /* internal register read */ + wb[1] = (u8)(adr >> 8); + if (clockless == 1) + wb[1] |= BIT(7); + wb[2] = (u8)adr; + wb[3] = 0x00; + len = 5; + break; + + case CMD_TERMINATE: /* termination */ + wb[1] = 0x00; + wb[2] = 0x00; + wb[3] = 0x00; + len = 5; + break; + + case CMD_REPEAT: /* repeat */ + wb[1] = 0x00; + wb[2] = 0x00; + wb[3] = 0x00; + len = 5; + break; + + case CMD_RESET: /* reset */ + wb[1] = 0xff; + wb[2] = 0xff; + wb[3] = 0xff; + len = 5; + break; + + case CMD_DMA_WRITE: /* dma write */ + case CMD_DMA_READ: /* dma read */ + wb[1] = (u8)(adr >> 16); + wb[2] = (u8)(adr >> 8); + wb[3] = (u8)adr; + wb[4] = (u8)(sz >> 8); + wb[5] = (u8)(sz); + len = 7; + break; + + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + wb[1] = (u8)(adr >> 16); + wb[2] = (u8)(adr >> 8); + wb[3] = (u8)adr; + wb[4] = (u8)(sz >> 16); + wb[5] = (u8)(sz >> 8); + wb[6] = (u8)(sz); + len = 8; + break; + + case CMD_INTERNAL_WRITE: /* internal register write */ + wb[1] = (u8)(adr >> 8); + if (clockless == 1) + wb[1] |= BIT(7); + wb[2] = (u8)(adr); + wb[3] = b[3]; + wb[4] = b[2]; + wb[5] = b[1]; + wb[6] = b[0]; + len = 8; + break; + + case CMD_SINGLE_WRITE: /* single word write */ + wb[1] = (u8)(adr >> 16); + wb[2] = (u8)(adr >> 8); + wb[3] = (u8)(adr); + wb[4] = b[3]; + wb[5] = b[2]; + wb[6] = b[1]; + wb[7] = b[0]; + len = 9; + break; + + default: + result = N_FAIL; + break; + } + + if (result != N_OK) { + return result; + } + + if (!g_spi.crc_off) + wb[len - 1] = (crc7(0x7f, (const u8 *)&wb[0], len - 1)) << 1; + else + len -= 1; + +#define NUM_SKIP_BYTES (1) +#define NUM_RSP_BYTES (2) +#define NUM_DATA_HDR_BYTES (1) +#define NUM_DATA_BYTES (4) +#define NUM_CRC_BYTES (2) +#define NUM_DUMMY_BYTES (3) + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES); + } else if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) { + if (!g_spi.crc_off) { + len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + + NUM_CRC_BYTES + NUM_DUMMY_BYTES); + } else { + len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + + NUM_DUMMY_BYTES); + } + } else { + len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES); + } +#undef NUM_DUMMY_BYTES + + if (len2 > ARRAY_SIZE(wb)) { + PRINT_ER("[wilc spi]: spi buffer size too small (%d) (%zu)\n", + len2, ARRAY_SIZE(wb)); + result = N_FAIL; + return result; + } + /* zero spi write buffers. */ + for (wix = len; wix < len2; wix++) { + wb[wix] = 0; + } + rix = len; + + if (!g_spi.spi_trx(wb, rb, len2)) { + PRINT_ER("[wilc spi]: Failed cmd write, bus error...\n"); + result = N_FAIL; + return result; + } + + /** + * Command/Control response + **/ + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + rix++; /* skip 1 byte */ + } + + /* do { */ + rsp = rb[rix++]; + /* if(rsp == cmd) break; */ + /* } while(&rptr[1] <= &rb[len2]); */ + + if (rsp != cmd) { + PRINT_ER("[wilc spi]: Failed cmd response, cmd (%02x)" + ", resp (%02x)\n", cmd, rsp); + result = N_FAIL; + return result; + } + + /** + * State response + **/ + rsp = rb[rix++]; + if (rsp != 0x00) { + PRINT_ER("[wilc spi]: Failed cmd state response " + "state (%02x)\n", rsp); + result = N_FAIL; + return result; + } + + if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ) + || (cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { + int retry; + /* u16 crc1, crc2; */ + u8 crc[2]; + /** + * Data Respnose header + **/ + retry = 100; + do { + /* ensure there is room in buffer later to read data and crc */ + if (rix < len2) { + rsp = rb[rix++]; + } else { + retry = 0; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (retry <= 0) { + PRINT_ER("[wilc spi]: Error, data read " + "response (%02x)\n", rsp); + result = N_RESET; + return result; + } + + if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) { + /** + * Read bytes + **/ + if ((rix + 3) < len2) { + b[0] = rb[rix++]; + b[1] = rb[rix++]; + b[2] = rb[rix++]; + b[3] = rb[rix++]; + } else { + PRINT_ER("[wilc spi]: buffer overrun when reading data.\n"); + result = N_FAIL; + return result; + } + + if (!g_spi.crc_off) { + /** + * Read Crc + **/ + if ((rix + 1) < len2) { + crc[0] = rb[rix++]; + crc[1] = rb[rix++]; + } else { + PRINT_ER("[wilc spi]: buffer overrun when reading crc.\n"); + result = N_FAIL; + return result; + } + } + } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { + int ix; + + /* some data may be read in response to dummy bytes. */ + for (ix = 0; (rix < len2) && (ix < sz); ) { + b[ix++] = rb[rix++]; + } + + sz -= ix; + + if (sz > 0) { + int nbytes; + + if (sz <= (DATA_PKT_SZ - ix)) + nbytes = sz; + else + nbytes = DATA_PKT_SZ - ix; + + /** + * Read bytes + **/ + if (!g_spi.spi_rx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + goto _error_; + } + + /** + * Read Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + goto _error_; + } + } + + + ix += nbytes; + sz -= nbytes; + } + + /* if any data in left unread, then read the rest using normal DMA code.*/ + while (sz > 0) { + int nbytes; + + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /** + * read data response only on the next DMA cycles not + * the first DMA since data response header is already + * handled above for the first DMA. + **/ + /** + * Data Respnose header + **/ + retry = 10; + do { + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed data response read, bus error...\n"); + result = N_FAIL; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (result == N_FAIL) + break; + + + /** + * Read bytes + **/ + if (!g_spi.spi_rx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Read Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + } + } + } +_error_: + return result; +} + +static int spi_data_read(u8 *b, u32 sz) +{ + int retry, ix, nbytes; + int result = N_OK; + u8 crc[2]; + u8 rsp; + + /** + * Data + **/ + ix = 0; + do { + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /** + * Data Respnose header + **/ + retry = 10; + do { + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("[wilc spi]: Failed data response read, bus error...\n"); + result = N_FAIL; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (result == N_FAIL) + break; + + if (retry <= 0) { + PRINT_ER("[wilc spi]: Failed data response read...(%02x)\n", rsp); + result = N_FAIL; + break; + } + + /** + * Read bytes + **/ + if (!g_spi.spi_rx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Read Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + + } while (sz); + + return result; +} + +static int spi_data_write(u8 *b, u32 sz) +{ + int ix, nbytes; + int result = 1; + u8 cmd, order, crc[2] = {0}; + /* u8 rsp; */ + + /** + * Data + **/ + ix = 0; + do { + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /** + * Write command + **/ + cmd = 0xf0; + if (ix == 0) { + if (sz <= DATA_PKT_SZ) + + order = 0x3; + else + order = 0x1; + } else { + if (sz <= DATA_PKT_SZ) + order = 0x3; + else + order = 0x2; + } + cmd |= order; + if (!g_spi.spi_tx(&cmd, 1)) { + PRINT_ER("[wilc spi]: Failed data block cmd write, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Write data + **/ + if (!g_spi.spi_tx(&b[ix], nbytes)) { + PRINT_ER("[wilc spi]: Failed data block write, bus error...\n"); + result = N_FAIL; + break; + } + + /** + * Write Crc + **/ + if (!g_spi.crc_off) { + if (!g_spi.spi_tx(crc, 2)) { + PRINT_ER("[wilc spi]: Failed data block crc write, bus error...\n"); + result = N_FAIL; + break; + } + } + + /** + * No need to wait for response + **/ + ix += nbytes; + sz -= nbytes; + } while (sz); + + + return result; +} + +/******************************************** + * + * Spi Internal Read/Write Function + * + ********************************************/ + +static int spi_internal_write(u32 adr, u32 dat) +{ + int result; + +#ifdef BIG_ENDIAN + dat = BYTE_SWAP(dat); +#endif + result = spi_cmd_complete(CMD_INTERNAL_WRITE, adr, (u8 *)&dat, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal write cmd...\n"); + } + + return result; +} + +static int spi_internal_read(u32 adr, u32 *data) +{ + int result; + + result = spi_cmd_complete(CMD_INTERNAL_READ, adr, (u8 *)data, 4, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed internal read cmd...\n"); + return 0; + } + +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + + return 1; +} + +/******************************************** + * + * Spi interfaces + * + ********************************************/ + +static int spi_write_reg(u32 addr, u32 data) +{ + int result = N_OK; + u8 cmd = CMD_SINGLE_WRITE; + u8 clockless = 0; + +#ifdef BIG_ENDIAN + data = BYTE_SWAP(data); +#endif + if (addr < 0x30) { + /* Clockless register*/ + cmd = CMD_INTERNAL_WRITE; + clockless = 1; + } + + result = spi_cmd_complete(cmd, addr, (u8 *)&data, 4, clockless); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, write reg (%08x)...\n", addr); + } + + return result; +} + +static int spi_write(u32 addr, u8 *buf, u32 size) +{ + int result; + u8 cmd = CMD_DMA_EXT_WRITE; + + /** + * has to be greated than 4 + **/ + if (size <= 4) + return 0; + + result = spi_cmd_complete(cmd, addr, NULL, size, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, write block (%08x)...\n", addr); + return 0; + } + + /** + * Data + **/ + result = spi_data_write(buf, size); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed block data write...\n"); + } + + return 1; +} + +static int spi_read_reg(u32 addr, u32 *data) +{ + int result = N_OK; + u8 cmd = CMD_SINGLE_READ; + u8 clockless = 0; + + if (addr < 0x30) { + /* PRINT_ER("***** read addr %d\n\n", addr); */ + /* Clockless register*/ + cmd = CMD_INTERNAL_READ; + clockless = 1; + } + + result = spi_cmd_complete(cmd, addr, (u8 *)data, 4, clockless); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, read reg (%08x)...\n", addr); + return 0; + } + +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + + return 1; +} + +static int spi_read(u32 addr, u8 *buf, u32 size) +{ + u8 cmd = CMD_DMA_EXT_READ; + int result; + + if (size <= 4) + return 0; + + result = spi_cmd_complete(cmd, addr, buf, size, 0); + if (result != N_OK) { + PRINT_ER("[wilc spi]: Failed cmd, read block (%08x)...\n", addr); + return 0; + } + + return 1; +} + +/******************************************** + * + * Bus interfaces + * + ********************************************/ + +static int spi_clear_int(void) +{ + u32 reg; + + if (!spi_read_reg(WILC_HOST_RX_CTRL_0, ®)) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0); + return 0; + } + reg &= ~0x1; + spi_write_reg(WILC_HOST_RX_CTRL_0, reg); + return 1; +} + +static int spi_deinit(void *pv) +{ + /** + * TODO: + **/ + return 1; +} + +static int spi_sync(void) +{ + u32 reg; + int ret; + + /** + * interrupt pin mux select + **/ + ret = spi_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= BIT(8); + ret = spi_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = spi_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + reg |= BIT(16); + ret = spi_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + + return 1; +} + +static int spi_init(wilc_wlan_inp_t *inp, wilc_debug_func func) +{ + u32 reg; + u32 chipid; + + static int isinit; + + if (isinit) { + + if (!spi_read_reg(0x1000, &chipid)) { + PRINT_ER("[wilc spi]: Fail cmd read chip id...\n"); + return 0; + } + return 1; + } + + memset(&g_spi, 0, sizeof(wilc_spi_t)); + + g_spi.dPrint = func; + g_spi.os_context = inp->os_context.os_private; + if (inp->io_func.io_init) { + if (!inp->io_func.io_init(g_spi.os_context)) { + PRINT_ER("[wilc spi]: Failed io init bus...\n"); + return 0; + } + } else { + return 0; + } + g_spi.spi_tx = inp->io_func.u.spi.spi_tx; + g_spi.spi_rx = inp->io_func.u.spi.spi_rx; + g_spi.spi_trx = inp->io_func.u.spi.spi_trx; + g_spi.spi_max_speed = inp->io_func.u.spi.spi_max_speed; + + /** + * configure protocol + **/ + g_spi.crc_off = 0; + + /* TODO: We can remove the CRC trials if there is a definite way to reset */ + /* the SPI to it's initial value. */ + if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, ®)) { + /* Read failed. Try with CRC off. This might happen when module + * is removed but chip isn't reset*/ + g_spi.crc_off = 1; + PRINT_ER("[wilc spi]: Failed internal read protocol with CRC on, retyring with CRC off...\n"); + if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, ®)) { + /* Reaad failed with both CRC on and off, something went bad */ + PRINT_ER("[wilc spi]: Failed internal read protocol...\n"); + return 0; + } + } + if (g_spi.crc_off == 0) { + reg &= ~0xc; /* disable crc checking */ + reg &= ~0x70; + reg |= (0x5 << 4); + if (!spi_internal_write(WILC_SPI_PROTOCOL_OFFSET, reg)) { + PRINT_ER("[wilc spi %d]: Failed internal write protocol reg...\n", __LINE__); + return 0; + } + g_spi.crc_off = 1; + } + + + /** + * make sure can read back chip id correctly + **/ + if (!spi_read_reg(0x1000, &chipid)) { + PRINT_ER("[wilc spi]: Fail cmd read chip id...\n"); + return 0; + } + /* PRINT_ER("[wilc spi]: chipid (%08x)\n", chipid); */ + + g_spi.has_thrpt_enh = 1; + + isinit = 1; + + return 1; +} + +static void spi_max_bus_speed(void) +{ + g_spi.spi_max_speed(); +} + +static void spi_default_bus_speed(void) +{ +} + +static int spi_read_size(u32 *size) +{ + int ret; + + if (g_spi.has_thrpt_enh) { + ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, size); + *size = *size & IRQ_DMA_WD_CNT_MASK; + } else { + u32 tmp; + u32 byte_cnt; + + ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read WILC_VMM_TO_HOST_SIZE ...\n"); + goto _fail_; + } + tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; + *size = tmp; + } + + + +_fail_: + return ret; +} + + + +static int spi_read_int(u32 *int_status) +{ + int ret; + + if (g_spi.has_thrpt_enh) { + ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, int_status); + } else { + u32 tmp; + u32 byte_cnt; + + ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read WILC_VMM_TO_HOST_SIZE ...\n"); + goto _fail_; + } + tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; + + { + int happended, j; + + j = 0; + do { + u32 irq_flags; + + happended = 0; + + spi_read_reg(0x1a90, &irq_flags); + tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET); + + if (g_spi.nint > 5) { + spi_read_reg(0x1a94, &irq_flags); + tmp |= (((irq_flags >> 0) & 0x7) << (IRG_FLAGS_OFFSET + 5)); + } + + { + u32 unkmown_mask; + + unkmown_mask = ~((1ul << g_spi.nint) - 1); + + if ((tmp >> IRG_FLAGS_OFFSET) & unkmown_mask) { + PRINT_ER("[wilc spi]: Unexpected interrupt (2): j=%d, tmp=%x, mask=%x\n", j, tmp, unkmown_mask); + happended = 1; + } + } + j++; + } while (happended); + } + + *int_status = tmp; + + } + +_fail_: + return ret; +} + +static int spi_clear_int_ext(u32 val) +{ + int ret; + + if (g_spi.has_thrpt_enh) { + ret = spi_internal_write(0xe844 - WILC_SPI_REG_BASE, val); + } else { + u32 flags; + + flags = val & (BIT(MAX_NUM_INT) - 1); + if (flags) { + int i; + + ret = 1; + for (i = 0; i < g_spi.nint; i++) { + /* No matter what you write 1 or 0, it will clear interrupt. */ + if (flags & 1) + ret = spi_write_reg(0x10c8 + i * 4, 1); + if (!ret) + break; + flags >>= 1; + } + if (!ret) { + PRINT_ER("[wilc spi]: Failed spi_write_reg, set reg %x ...\n", 0x10c8 + i * 4); + goto _fail_; + } + for (i = g_spi.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) + PRINT_ER("[wilc spi]: Unexpected interrupt cleared %d...\n", i); + flags >>= 1; + } + } + + { + u32 tbl_ctl; + + tbl_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + tbl_ctl |= BIT(0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + tbl_ctl |= BIT(1); + + ret = spi_write_reg(WILC_VMM_TBL_CTL, tbl_ctl); + if (!ret) { + PRINT_ER("[wilc spi]: fail write reg vmm_tbl_ctl...\n"); + goto _fail_; + } + + if ((val & EN_VMM) == EN_VMM) { + /** + * enable vmm transfer. + **/ + ret = spi_write_reg(WILC_VMM_CORE_CTL, 1); + if (!ret) { + PRINT_ER("[wilc spi]: fail write reg vmm_core_ctl...\n"); + goto _fail_; + } + } + } + } +_fail_: + return ret; +} + +static int spi_sync_ext(int nint /* how mant interrupts to enable. */) +{ + u32 reg; + int ret, i; + + if (nint > MAX_NUM_INT) { + PRINT_ER("[wilc spi]: Too many interupts (%d)...\n", nint); + return 0; + } + + g_spi.nint = nint; + + /** + * interrupt pin mux select + **/ + ret = spi_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + reg |= BIT(8); + ret = spi_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = spi_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) { + reg |= (BIT((27 + i))); + } + ret = spi_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); + return 0; + } + if (nint) { + ret = spi_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed read reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) { + reg |= BIT(i); + } + + ret = spi_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("[wilc spi]: Failed write reg (%08x)...\n", WILC_INTR2_ENABLE); + return 0; + } + } + + return 1; +} +/******************************************** + * + * Global spi HIF function table + * + ********************************************/ +wilc_hif_func_t hif_spi = { + spi_init, + spi_deinit, + spi_read_reg, + spi_write_reg, + spi_read, + spi_write, + spi_sync, + spi_clear_int, + spi_read_int, + spi_clear_int_ext, + spi_read_size, + spi_write, + spi_read, + spi_sync_ext, + spi_max_bus_speed, + spi_default_bus_speed, +}; diff --git a/kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c new file mode 100644 index 000000000..3e9501727 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -0,0 +1,3535 @@ +/*! + * @file wilc_wfi_cfgopertaions.c + * @brief CFG80211 Function Implementation functionality + * @author aabouzaeid + * mabubakr + * mdaftedar + * zsalah + * @sa wilc_wfi_cfgopertaions.h top level OS wrapper file + * @date 31 Aug 2010 + * @version 1.0 + */ + +#include "wilc_wfi_cfgoperations.h" +#ifdef WILC_SDIO +#include "linux_wlan_sdio.h" +#endif +#include + +#define IS_MANAGMEMENT 0x100 +#define IS_MANAGMEMENT_CALLBACK 0x080 +#define IS_MGMT_STATUS_SUCCES 0x040 +#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff) + +extern int linux_wlan_get_firmware(perInterface_wlan_t *p_nic); + +extern int mac_open(struct net_device *ndev); +extern int mac_close(struct net_device *ndev); + +tstrNetworkInfo astrLastScannedNtwrksShadow[MAX_NUM_SCANNED_NETWORKS_SHADOW]; +u32 u32LastScannedNtwrksCountShadow; +struct timer_list hDuringIpTimer; +struct timer_list hAgingTimer; +static u8 op_ifcs; +extern u8 u8ConnectedSSID[6]; + +u8 g_wilc_initialized = 1; +extern bool g_obtainingIP; + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +/*Frequency range for channels*/ +static struct ieee80211_channel WILC_WFI_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +#define RATETAB_ENT(_rate, _hw_value, _flags) { \ + .bitrate = (_rate), \ + .hw_value = (_hw_value), \ + .flags = (_flags), \ +} + + +/* Table 6 in section 3.2.1.1 */ +static struct ieee80211_rate WILC_WFI_rates[] = { + RATETAB_ENT(10, 0, 0), + RATETAB_ENT(20, 1, 0), + RATETAB_ENT(55, 2, 0), + RATETAB_ENT(110, 3, 0), + RATETAB_ENT(60, 9, 0), + RATETAB_ENT(90, 6, 0), + RATETAB_ENT(120, 7, 0), + RATETAB_ENT(180, 8, 0), + RATETAB_ENT(240, 9, 0), + RATETAB_ENT(360, 10, 0), + RATETAB_ENT(480, 11, 0), + RATETAB_ENT(540, 12, 0), +}; + +struct p2p_mgmt_data { + int size; + u8 *buff; +}; + +/*Global variable used to state the current connected STA channel*/ +u8 u8WLANChannel = INVALID_CHANNEL; + +u8 curr_channel; + +u8 u8P2P_oui[] = {0x50, 0x6f, 0x9A, 0x09}; +u8 u8P2Plocalrandom = 0x01; +u8 u8P2Precvrandom = 0x00; +u8 u8P2P_vendorspec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03}; +bool bWilc_ie; + +static struct ieee80211_supported_band WILC_WFI_band_2ghz = { + .channels = WILC_WFI_2ghz_channels, + .n_channels = ARRAY_SIZE(WILC_WFI_2ghz_channels), + .bitrates = WILC_WFI_rates, + .n_bitrates = ARRAY_SIZE(WILC_WFI_rates), +}; + + +struct add_key_params { + u8 key_idx; + bool pairwise; + u8 *mac_addr; +}; +struct add_key_params g_add_gtk_key_params; +struct wilc_wfi_key g_key_gtk_params; +struct add_key_params g_add_ptk_key_params; +struct wilc_wfi_key g_key_ptk_params; +struct wilc_wfi_wep_key g_key_wep_params; +bool g_ptk_keys_saved; +bool g_gtk_keys_saved; +bool g_wep_keys_saved; + +#define AGING_TIME (9 * 1000) +#define duringIP_TIME 15000 + +void clear_shadow_scan(void *pUserVoid) +{ + int i; + + if (op_ifcs == 0) { + del_timer_sync(&hAgingTimer); + PRINT_INFO(CORECONFIG_DBG, "destroy aging timer\n"); + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (astrLastScannedNtwrksShadow[u32LastScannedNtwrksCountShadow].pu8IEs != NULL) { + kfree(astrLastScannedNtwrksShadow[i].pu8IEs); + astrLastScannedNtwrksShadow[u32LastScannedNtwrksCountShadow].pu8IEs = NULL; + } + + host_int_freeJoinParams(astrLastScannedNtwrksShadow[i].pJoinParams); + astrLastScannedNtwrksShadow[i].pJoinParams = NULL; + } + u32LastScannedNtwrksCountShadow = 0; + } + +} + +u32 get_rssi_avg(tstrNetworkInfo *pstrNetworkInfo) +{ + u8 i; + int rssi_v = 0; + u8 num_rssi = (pstrNetworkInfo->strRssi.u8Full) ? NUM_RSSI : (pstrNetworkInfo->strRssi.u8Index); + + for (i = 0; i < num_rssi; i++) + rssi_v += pstrNetworkInfo->strRssi.as8RSSI[i]; + + rssi_v /= num_rssi; + return rssi_v; +} + +void refresh_scan(void *pUserVoid, u8 all, bool bDirectScan) +{ + struct wilc_priv *priv; + struct wiphy *wiphy; + struct cfg80211_bss *bss = NULL; + int i; + int rssi = 0; + + priv = (struct wilc_priv *)pUserVoid; + wiphy = priv->dev->ieee80211_ptr->wiphy; + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + tstrNetworkInfo *pstrNetworkInfo; + + pstrNetworkInfo = &(astrLastScannedNtwrksShadow[i]); + + + if ((!pstrNetworkInfo->u8Found) || all) { + s32 s32Freq; + struct ieee80211_channel *channel; + + if (pstrNetworkInfo != NULL) { + + s32Freq = ieee80211_channel_to_frequency((s32)pstrNetworkInfo->u8channel, IEEE80211_BAND_2GHZ); + channel = ieee80211_get_channel(wiphy, s32Freq); + + rssi = get_rssi_avg(pstrNetworkInfo); + if (memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7) || bDirectScan) { + bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo, + pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs, + (size_t)pstrNetworkInfo->u16IEsLen, (((s32)rssi) * 100), GFP_KERNEL); + cfg80211_put_bss(wiphy, bss); + } + } + + } + } + +} + +void reset_shadow_found(void *pUserVoid) +{ + int i; + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + astrLastScannedNtwrksShadow[i].u8Found = 0; + + } +} + +void update_scan_time(void *pUserVoid) +{ + int i; + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies; + } +} + +static void remove_network_from_shadow(unsigned long arg) +{ + unsigned long now = jiffies; + int i, j; + + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (time_after(now, astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan + (unsigned long)(SCAN_RESULT_EXPIRE))) { + PRINT_D(CFG80211_DBG, "Network expired in ScanShadow: %s\n", astrLastScannedNtwrksShadow[i].au8ssid); + + kfree(astrLastScannedNtwrksShadow[i].pu8IEs); + astrLastScannedNtwrksShadow[i].pu8IEs = NULL; + + host_int_freeJoinParams(astrLastScannedNtwrksShadow[i].pJoinParams); + + for (j = i; (j < u32LastScannedNtwrksCountShadow - 1); j++) { + astrLastScannedNtwrksShadow[j] = astrLastScannedNtwrksShadow[j + 1]; + } + u32LastScannedNtwrksCountShadow--; + } + } + + PRINT_D(CFG80211_DBG, "Number of cached networks: %d\n", u32LastScannedNtwrksCountShadow); + if (u32LastScannedNtwrksCountShadow != 0) { + hAgingTimer.data = arg; + mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME)); + } else { + PRINT_D(CFG80211_DBG, "No need to restart Aging timer\n"); + } +} + +static void clear_duringIP(unsigned long arg) +{ + PRINT_D(GENERIC_DBG, "GO:IP Obtained , enable scan\n"); + g_obtainingIP = false; +} + +int is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid) +{ + int state = -1; + int i; + + if (u32LastScannedNtwrksCountShadow == 0) { + PRINT_D(CFG80211_DBG, "Starting Aging timer\n"); + hAgingTimer.data = (unsigned long)pUserVoid; + mod_timer(&hAgingTimer, jiffies + msecs_to_jiffies(AGING_TIME)); + state = -1; + } else { + /* Linear search for now */ + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + pstrNetworkInfo->au8bssid, 6) == 0) { + state = i; + break; + } + } + } + return state; +} + +void add_network_to_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid, void *pJoinParams) +{ + int ap_found = is_network_in_shadow(pstrNetworkInfo, pUserVoid); + u32 ap_index = 0; + u8 rssi_index = 0; + + if (u32LastScannedNtwrksCountShadow >= MAX_NUM_SCANNED_NETWORKS_SHADOW) { + PRINT_D(CFG80211_DBG, "Shadow network reached its maximum limit\n"); + return; + } + if (ap_found == -1) { + ap_index = u32LastScannedNtwrksCountShadow; + u32LastScannedNtwrksCountShadow++; + + } else { + ap_index = ap_found; + } + rssi_index = astrLastScannedNtwrksShadow[ap_index].strRssi.u8Index; + astrLastScannedNtwrksShadow[ap_index].strRssi.as8RSSI[rssi_index++] = pstrNetworkInfo->s8rssi; + if (rssi_index == NUM_RSSI) { + rssi_index = 0; + astrLastScannedNtwrksShadow[ap_index].strRssi.u8Full = 1; + } + astrLastScannedNtwrksShadow[ap_index].strRssi.u8Index = rssi_index; + + astrLastScannedNtwrksShadow[ap_index].s8rssi = pstrNetworkInfo->s8rssi; + astrLastScannedNtwrksShadow[ap_index].u16CapInfo = pstrNetworkInfo->u16CapInfo; + + astrLastScannedNtwrksShadow[ap_index].u8SsidLen = pstrNetworkInfo->u8SsidLen; + memcpy(astrLastScannedNtwrksShadow[ap_index].au8ssid, + pstrNetworkInfo->au8ssid, pstrNetworkInfo->u8SsidLen); + + memcpy(astrLastScannedNtwrksShadow[ap_index].au8bssid, + pstrNetworkInfo->au8bssid, ETH_ALEN); + + astrLastScannedNtwrksShadow[ap_index].u16BeaconPeriod = pstrNetworkInfo->u16BeaconPeriod; + astrLastScannedNtwrksShadow[ap_index].u8DtimPeriod = pstrNetworkInfo->u8DtimPeriod; + astrLastScannedNtwrksShadow[ap_index].u8channel = pstrNetworkInfo->u8channel; + + astrLastScannedNtwrksShadow[ap_index].u16IEsLen = pstrNetworkInfo->u16IEsLen; + astrLastScannedNtwrksShadow[ap_index].u64Tsf = pstrNetworkInfo->u64Tsf; + if (ap_found != -1) + kfree(astrLastScannedNtwrksShadow[ap_index].pu8IEs); + astrLastScannedNtwrksShadow[ap_index].pu8IEs = + kmalloc(pstrNetworkInfo->u16IEsLen, GFP_KERNEL); /* will be deallocated by the WILC_WFI_CfgScan() function */ + memcpy(astrLastScannedNtwrksShadow[ap_index].pu8IEs, + pstrNetworkInfo->pu8IEs, pstrNetworkInfo->u16IEsLen); + + astrLastScannedNtwrksShadow[ap_index].u32TimeRcvdInScan = jiffies; + astrLastScannedNtwrksShadow[ap_index].u32TimeRcvdInScanCached = jiffies; + astrLastScannedNtwrksShadow[ap_index].u8Found = 1; + if (ap_found != -1) + host_int_freeJoinParams(astrLastScannedNtwrksShadow[ap_index].pJoinParams); + astrLastScannedNtwrksShadow[ap_index].pJoinParams = pJoinParams; + +} + + +/** + * @brief CfgScanResult + * @details Callback function which returns the scan results found + * + * @param[in] tenuScanEvent enuScanEvent: enum, indicating the scan event triggered, whether that is + * SCAN_EVENT_NETWORK_FOUND or SCAN_EVENT_DONE + * tstrNetworkInfo* pstrNetworkInfo: structure holding the scan results information + * void* pUserVoid: Private structure associated with the wireless interface + * @return NONE + * @author mabubakr + * @date + * @version 1.0 + */ +static void CfgScanResult(enum scan_event enuScanEvent, tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid, void *pJoinParams) +{ + struct wilc_priv *priv; + struct wiphy *wiphy; + s32 s32Freq; + struct ieee80211_channel *channel; + struct cfg80211_bss *bss = NULL; + + priv = (struct wilc_priv *)pUserVoid; + if (priv->bCfgScanning) { + if (enuScanEvent == SCAN_EVENT_NETWORK_FOUND) { + wiphy = priv->dev->ieee80211_ptr->wiphy; + + if (!wiphy) + return; + + if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC + && + ((((s32)pstrNetworkInfo->s8rssi) * 100) < 0 + || + (((s32)pstrNetworkInfo->s8rssi) * 100) > 100) + ) { + PRINT_ER("wiphy signal type fial\n"); + return; + } + + if (pstrNetworkInfo != NULL) { + s32Freq = ieee80211_channel_to_frequency((s32)pstrNetworkInfo->u8channel, IEEE80211_BAND_2GHZ); + channel = ieee80211_get_channel(wiphy, s32Freq); + + if (!channel) + return; + + PRINT_INFO(CFG80211_DBG, "Network Info:: CHANNEL Frequency: %d, RSSI: %d, CapabilityInfo: %d," + "BeaconPeriod: %d\n", channel->center_freq, (((s32)pstrNetworkInfo->s8rssi) * 100), + pstrNetworkInfo->u16CapInfo, pstrNetworkInfo->u16BeaconPeriod); + + if (pstrNetworkInfo->bNewNetwork) { + if (priv->u32RcvdChCount < MAX_NUM_SCANNED_NETWORKS) { /* TODO: mostafa: to be replaced by */ + /* max_scan_ssids */ + PRINT_D(CFG80211_DBG, "Network %s found\n", pstrNetworkInfo->au8ssid); + + + priv->u32RcvdChCount++; + + + + if (pJoinParams == NULL) { + PRINT_INFO(CORECONFIG_DBG, ">> Something really bad happened\n"); + } + add_network_to_shadow(pstrNetworkInfo, priv, pJoinParams); + + /*P2P peers are sent to WPA supplicant and added to shadow table*/ + + if (!(memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7))) { + bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo, + pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs, + (size_t)pstrNetworkInfo->u16IEsLen, (((s32)pstrNetworkInfo->s8rssi) * 100), GFP_KERNEL); + cfg80211_put_bss(wiphy, bss); + } + + + } else { + PRINT_ER("Discovered networks exceeded the max limit\n"); + } + } else { + u32 i; + /* So this network is discovered before, we'll just update its RSSI */ + for (i = 0; i < priv->u32RcvdChCount; i++) { + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) { + PRINT_D(CFG80211_DBG, "Update RSSI of %s\n", astrLastScannedNtwrksShadow[i].au8ssid); + + astrLastScannedNtwrksShadow[i].s8rssi = pstrNetworkInfo->s8rssi; + astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies; + break; + } + } + } + } + } else if (enuScanEvent == SCAN_EVENT_DONE) { + PRINT_D(CFG80211_DBG, "Scan Done[%p]\n", priv->dev); + PRINT_D(CFG80211_DBG, "Refreshing Scan ...\n"); + refresh_scan(priv, 1, false); + + if (priv->u32RcvdChCount > 0) + PRINT_D(CFG80211_DBG, "%d Network(s) found\n", priv->u32RcvdChCount); + else + PRINT_D(CFG80211_DBG, "No networks found\n"); + + down(&(priv->hSemScanReq)); + + if (priv->pstrScanReq != NULL) { + cfg80211_scan_done(priv->pstrScanReq, false); + priv->u32RcvdChCount = 0; + priv->bCfgScanning = false; + priv->pstrScanReq = NULL; + } + up(&(priv->hSemScanReq)); + + } + /*Aborting any scan operation during mac close*/ + else if (enuScanEvent == SCAN_EVENT_ABORTED) { + down(&(priv->hSemScanReq)); + + PRINT_D(CFG80211_DBG, "Scan Aborted\n"); + if (priv->pstrScanReq != NULL) { + + update_scan_time(priv); + refresh_scan(priv, 1, false); + + cfg80211_scan_done(priv->pstrScanReq, false); + priv->bCfgScanning = false; + priv->pstrScanReq = NULL; + } + up(&(priv->hSemScanReq)); + } + } +} + + +/** + * @brief WILC_WFI_Set_PMKSA + * @details Check if pmksa is cached and set it. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_Set_PMKSA(u8 *bssid, struct wilc_priv *priv) +{ + u32 i; + s32 s32Error = 0; + + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + + if (!memcmp(bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + PRINT_D(CFG80211_DBG, "PMKID successful comparison"); + + /*If bssid is found, set the values*/ + s32Error = host_int_set_pmkid_info(priv->hWILCWFIDrv, &priv->pmkid_list); + + if (s32Error != 0) + PRINT_ER("Error in pmkid\n"); + + break; + } + } + + return s32Error; + + +} +int linux_wlan_set_bssid(struct net_device *wilc_netdev, u8 *pBSSID); + + +/** + * @brief CfgConnectResult + * @details + * @param[in] tenuConnDisconnEvent enuConnDisconnEvent: Type of connection response either + * connection response or disconnection notification. + * tstrConnectInfo* pstrConnectInfo: COnnection information. + * u8 u8MacStatus: Mac Status from firmware + * tstrDisconnectNotifInfo* pstrDisconnectNotifInfo: Disconnection Notification + * void* pUserVoid: Private data associated with wireless interface + * @return NONE + * @author mabubakr + * @date 01 MAR 2012 + * @version 1.0 + */ +int connecting; + +static void CfgConnectResult(enum conn_event enuConnDisconnEvent, + tstrConnectInfo *pstrConnectInfo, + u8 u8MacStatus, + tstrDisconnectNotifInfo *pstrDisconnectNotifInfo, + void *pUserVoid) +{ + struct wilc_priv *priv; + struct net_device *dev; + struct host_if_drv *pstrWFIDrv; + u8 NullBssid[ETH_ALEN] = {0}; + struct wilc *wl; + perInterface_wlan_t *nic; + + connecting = 0; + + priv = (struct wilc_priv *)pUserVoid; + dev = priv->dev; + nic = netdev_priv(dev); + wl = nic->wilc; + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + + if (enuConnDisconnEvent == CONN_DISCONN_EVENT_CONN_RESP) { + /*Initialization*/ + u16 u16ConnectStatus; + + u16ConnectStatus = pstrConnectInfo->u16ConnectStatus; + + PRINT_D(CFG80211_DBG, " Connection response received = %d\n", u8MacStatus); + + if ((u8MacStatus == MAC_DISCONNECTED) && + (pstrConnectInfo->u16ConnectStatus == SUCCESSFUL_STATUSCODE)) { + /* The case here is that our station was waiting for association response frame and has just received it containing status code + * = SUCCESSFUL_STATUSCODE, while mac status is MAC_DISCONNECTED (which means something wrong happened) */ + u16ConnectStatus = WLAN_STATUS_UNSPECIFIED_FAILURE; + linux_wlan_set_bssid(priv->dev, NullBssid); + eth_zero_addr(u8ConnectedSSID); + + /*Invalidate u8WLANChannel value on wlan0 disconnect*/ + if (!pstrWFIDrv->u8P2PConnect) + u8WLANChannel = INVALID_CHANNEL; + + PRINT_ER("Unspecified failure: Connection status %d : MAC status = %d\n", u16ConnectStatus, u8MacStatus); + } + + if (u16ConnectStatus == WLAN_STATUS_SUCCESS) { + bool bNeedScanRefresh = false; + u32 i; + + PRINT_INFO(CFG80211_DBG, "Connection Successful:: BSSID: %x%x%x%x%x%x\n", pstrConnectInfo->au8bssid[0], + pstrConnectInfo->au8bssid[1], pstrConnectInfo->au8bssid[2], pstrConnectInfo->au8bssid[3], pstrConnectInfo->au8bssid[4], pstrConnectInfo->au8bssid[5]); + memcpy(priv->au8AssociatedBss, pstrConnectInfo->au8bssid, ETH_ALEN); + + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + pstrConnectInfo->au8bssid, ETH_ALEN) == 0) { + unsigned long now = jiffies; + + if (time_after(now, + astrLastScannedNtwrksShadow[i].u32TimeRcvdInScanCached + (unsigned long)(nl80211_SCAN_RESULT_EXPIRE - (1 * HZ)))) { + bNeedScanRefresh = true; + } + + break; + } + } + + if (bNeedScanRefresh) { + /*Also, refrsh DIRECT- results if */ + refresh_scan(priv, 1, true); + + } + + } + + + PRINT_D(CFG80211_DBG, "Association request info elements length = %zu\n", pstrConnectInfo->ReqIEsLen); + + PRINT_D(CFG80211_DBG, "Association response info elements length = %d\n", pstrConnectInfo->u16RespIEsLen); + + cfg80211_connect_result(dev, pstrConnectInfo->au8bssid, + pstrConnectInfo->pu8ReqIEs, pstrConnectInfo->ReqIEsLen, + pstrConnectInfo->pu8RespIEs, pstrConnectInfo->u16RespIEsLen, + u16ConnectStatus, GFP_KERNEL); /* TODO: mostafa: u16ConnectStatus to */ + /* be replaced by pstrConnectInfo->u16ConnectStatus */ + } else if (enuConnDisconnEvent == CONN_DISCONN_EVENT_DISCONN_NOTIF) { + g_obtainingIP = false; + PRINT_ER("Received MAC_DISCONNECTED from firmware with reason %d on dev [%p]\n", + pstrDisconnectNotifInfo->u16reason, priv->dev); + u8P2Plocalrandom = 0x01; + u8P2Precvrandom = 0x00; + bWilc_ie = false; + eth_zero_addr(priv->au8AssociatedBss); + linux_wlan_set_bssid(priv->dev, NullBssid); + eth_zero_addr(u8ConnectedSSID); + + /*Invalidate u8WLANChannel value on wlan0 disconnect*/ + if (!pstrWFIDrv->u8P2PConnect) + u8WLANChannel = INVALID_CHANNEL; + /*Incase "P2P CLIENT Connected" send deauthentication reason by 3 to force the WPA_SUPPLICANT to directly change + * virtual interface to station*/ + if ((pstrWFIDrv->IFC_UP) && (dev == wl->vif[1].ndev)) { + pstrDisconnectNotifInfo->u16reason = 3; + } + /*Incase "P2P CLIENT during connection(not connected)" send deauthentication reason by 1 to force the WPA_SUPPLICANT + * to scan again and retry the connection*/ + else if ((!pstrWFIDrv->IFC_UP) && (dev == wl->vif[1].ndev)) { + pstrDisconnectNotifInfo->u16reason = 1; + } + cfg80211_disconnected(dev, pstrDisconnectNotifInfo->u16reason, pstrDisconnectNotifInfo->ie, + pstrDisconnectNotifInfo->ie_len, false, + GFP_KERNEL); + + } + +} + + +/** + * @brief set_channel + * @details Set channel for a given wireless interface. Some devices + * may support multi-channel operation (by channel hopping) so cfg80211 + * doesn't verify much. Note, however, that the passed netdev may be + * %NULL as well if the user requested changing the channel for the + * device itself, or for a monitor interface. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int set_channel(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + u32 channelnum = 0; + struct wilc_priv *priv; + int result = 0; + + priv = wiphy_priv(wiphy); + + channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq); + PRINT_D(CFG80211_DBG, "Setting channel %d with frequency %d\n", channelnum, chandef->chan->center_freq); + + curr_channel = channelnum; + result = host_int_set_mac_chnl_num(priv->hWILCWFIDrv, channelnum); + + if (result != 0) + PRINT_ER("Error in setting channel %d\n", channelnum); + + return result; +} + +/** + * @brief scan + * @details Request to do a scan. If returning zero, the scan request is given + * the driver, and will be valid until passed to cfg80211_scan_done(). + * For scan results, call cfg80211_inform_bss(); you can call this outside + * the scan/scan_done bracket too. + * @param[in] + * @return int : Return 0 on Success + * @author mabubakr + * @date 01 MAR 2012 + * @version 1.0 + */ + +static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + struct wilc_priv *priv; + u32 i; + s32 s32Error = 0; + u8 au8ScanChanList[MAX_NUM_SCANNED_NETWORKS]; + struct hidden_network strHiddenNetwork; + + priv = wiphy_priv(wiphy); + + priv->pstrScanReq = request; + + priv->u32RcvdChCount = 0; + + host_int_set_wfi_drv_handler(priv->hWILCWFIDrv); + + + reset_shadow_found(priv); + + priv->bCfgScanning = true; + if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) { /* TODO: mostafa: to be replaced by */ + /* max_scan_ssids */ + for (i = 0; i < request->n_channels; i++) { + au8ScanChanList[i] = (u8)ieee80211_frequency_to_channel(request->channels[i]->center_freq); + PRINT_INFO(CFG80211_DBG, "ScanChannel List[%d] = %d,", i, au8ScanChanList[i]); + } + + PRINT_D(CFG80211_DBG, "Requested num of scan channel %d\n", request->n_channels); + PRINT_D(CFG80211_DBG, "Scan Request IE len = %zu\n", request->ie_len); + + PRINT_D(CFG80211_DBG, "Number of SSIDs %d\n", request->n_ssids); + + if (request->n_ssids >= 1) { + + + strHiddenNetwork.pstrHiddenNetworkInfo = kmalloc(request->n_ssids * sizeof(struct hidden_network), GFP_KERNEL); + strHiddenNetwork.u8ssidnum = request->n_ssids; + + + for (i = 0; i < request->n_ssids; i++) { + + if (request->ssids[i].ssid != NULL && request->ssids[i].ssid_len != 0) { + strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid = kmalloc(request->ssids[i].ssid_len, GFP_KERNEL); + memcpy(strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid, request->ssids[i].ssid, request->ssids[i].ssid_len); + strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen = request->ssids[i].ssid_len; + } else { + PRINT_D(CFG80211_DBG, "Received one NULL SSID\n"); + strHiddenNetwork.u8ssidnum -= 1; + } + } + PRINT_D(CFG80211_DBG, "Trigger Scan Request\n"); + s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN, + au8ScanChanList, request->n_channels, + (const u8 *)request->ie, request->ie_len, + CfgScanResult, (void *)priv, &strHiddenNetwork); + } else { + PRINT_D(CFG80211_DBG, "Trigger Scan Request\n"); + s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN, + au8ScanChanList, request->n_channels, + (const u8 *)request->ie, request->ie_len, + CfgScanResult, (void *)priv, NULL); + } + + } else { + PRINT_ER("Requested num of scanned channels is greater than the max, supported" + " channels\n"); + } + + if (s32Error != 0) { + s32Error = -EBUSY; + PRINT_WRN(CFG80211_DBG, "Device is busy: Error(%d)\n", s32Error); + } + + return s32Error; +} + +/** + * @brief connect + * @details Connect to the ESS with the specified parameters. When connected, + * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. + * If the connection fails for some reason, call cfg80211_connect_result() + * with the status from the AP. + * @param[in] + * @return int : Return 0 on Success + * @author mabubakr + * @date 01 MAR 2012 + * @version 1.0 + */ +static int connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + s32 s32Error = 0; + u32 i; + u8 u8security = NO_ENCRYPT; + enum AUTHTYPE tenuAuth_type = ANY; + char *pcgroup_encrypt_val = NULL; + char *pccipher_group = NULL; + char *pcwpa_version = NULL; + + struct wilc_priv *priv; + struct host_if_drv *pstrWFIDrv; + tstrNetworkInfo *pstrNetworkInfo = NULL; + + + connecting = 1; + priv = wiphy_priv(wiphy); + pstrWFIDrv = (struct host_if_drv *)(priv->hWILCWFIDrv); + + host_int_set_wfi_drv_handler(priv->hWILCWFIDrv); + + PRINT_D(CFG80211_DBG, "Connecting to SSID [%s] on netdev [%p] host if [%p]\n", sme->ssid, dev, priv->hWILCWFIDrv); + if (!(strncmp(sme->ssid, "DIRECT-", 7))) { + PRINT_D(CFG80211_DBG, "Connected to Direct network,OBSS disabled\n"); + pstrWFIDrv->u8P2PConnect = 1; + } else + pstrWFIDrv->u8P2PConnect = 0; + PRINT_INFO(CFG80211_DBG, "Required SSID = %s\n , AuthType = %d\n", sme->ssid, sme->auth_type); + + for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { + if ((sme->ssid_len == astrLastScannedNtwrksShadow[i].u8SsidLen) && + memcmp(astrLastScannedNtwrksShadow[i].au8ssid, + sme->ssid, + sme->ssid_len) == 0) { + PRINT_INFO(CFG80211_DBG, "Network with required SSID is found %s\n", sme->ssid); + if (sme->bssid == NULL) { + /* BSSID is not passed from the user, so decision of matching + * is done by SSID only */ + PRINT_INFO(CFG80211_DBG, "BSSID is not passed from the user\n"); + break; + } else { + /* BSSID is also passed from the user, so decision of matching + * should consider also this passed BSSID */ + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + sme->bssid, + ETH_ALEN) == 0) { + PRINT_INFO(CFG80211_DBG, "BSSID is passed from the user and matched\n"); + break; + } + } + } + } + + if (i < u32LastScannedNtwrksCountShadow) { + PRINT_D(CFG80211_DBG, "Required bss is in scan results\n"); + + pstrNetworkInfo = &(astrLastScannedNtwrksShadow[i]); + + PRINT_INFO(CFG80211_DBG, "network BSSID to be associated: %x%x%x%x%x%x\n", + pstrNetworkInfo->au8bssid[0], pstrNetworkInfo->au8bssid[1], + pstrNetworkInfo->au8bssid[2], pstrNetworkInfo->au8bssid[3], + pstrNetworkInfo->au8bssid[4], pstrNetworkInfo->au8bssid[5]); + } else { + s32Error = -ENOENT; + if (u32LastScannedNtwrksCountShadow == 0) + PRINT_D(CFG80211_DBG, "No Scan results yet\n"); + else + PRINT_D(CFG80211_DBG, "Required bss not in scan results: Error(%d)\n", s32Error); + + goto done; + } + + priv->WILC_WFI_wep_default = 0; + memset(priv->WILC_WFI_wep_key, 0, sizeof(priv->WILC_WFI_wep_key)); + memset(priv->WILC_WFI_wep_key_len, 0, sizeof(priv->WILC_WFI_wep_key_len)); + + PRINT_INFO(CFG80211_DBG, "sme->crypto.wpa_versions=%x\n", sme->crypto.wpa_versions); + PRINT_INFO(CFG80211_DBG, "sme->crypto.cipher_group=%x\n", sme->crypto.cipher_group); + + PRINT_INFO(CFG80211_DBG, "sme->crypto.n_ciphers_pairwise=%d\n", sme->crypto.n_ciphers_pairwise); + + if (INFO) { + for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) + PRINT_D(CORECONFIG_DBG, "sme->crypto.ciphers_pairwise[%d]=%x\n", i, sme->crypto.ciphers_pairwise[i]); + } + + if (sme->crypto.cipher_group != NO_ENCRYPT) { + /* To determine the u8security value, first we check the group cipher suite then {in case of WPA or WPA2} + * we will add to it the pairwise cipher suite(s) */ + pcwpa_version = "Default"; + PRINT_D(CORECONFIG_DBG, ">> sme->crypto.wpa_versions: %x\n", sme->crypto.wpa_versions); + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) { + u8security = ENCRYPT_ENABLED | WEP; + pcgroup_encrypt_val = "WEP40"; + pccipher_group = "WLAN_CIPHER_SUITE_WEP40"; + PRINT_INFO(CFG80211_DBG, "WEP Default Key Idx = %d\n", sme->key_idx); + + if (INFO) { + for (i = 0; i < sme->key_len; i++) + PRINT_D(CORECONFIG_DBG, "WEP Key Value[%d] = %d\n", i, sme->key[i]); + } + priv->WILC_WFI_wep_default = sme->key_idx; + priv->WILC_WFI_wep_key_len[sme->key_idx] = sme->key_len; + memcpy(priv->WILC_WFI_wep_key[sme->key_idx], sme->key, sme->key_len); + + g_key_wep_params.key_len = sme->key_len; + g_key_wep_params.key = kmalloc(sme->key_len, GFP_KERNEL); + memcpy(g_key_wep_params.key, sme->key, sme->key_len); + g_key_wep_params.key_idx = sme->key_idx; + g_wep_keys_saved = true; + + host_int_set_wep_default_key(priv->hWILCWFIDrv, sme->key_idx); + host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, sme->key, sme->key_len, sme->key_idx); + } else if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104) { + u8security = ENCRYPT_ENABLED | WEP | WEP_EXTENDED; + pcgroup_encrypt_val = "WEP104"; + pccipher_group = "WLAN_CIPHER_SUITE_WEP104"; + + priv->WILC_WFI_wep_default = sme->key_idx; + priv->WILC_WFI_wep_key_len[sme->key_idx] = sme->key_len; + memcpy(priv->WILC_WFI_wep_key[sme->key_idx], sme->key, sme->key_len); + + g_key_wep_params.key_len = sme->key_len; + g_key_wep_params.key = kmalloc(sme->key_len, GFP_KERNEL); + memcpy(g_key_wep_params.key, sme->key, sme->key_len); + g_key_wep_params.key_idx = sme->key_idx; + g_wep_keys_saved = true; + + host_int_set_wep_default_key(priv->hWILCWFIDrv, sme->key_idx); + host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, sme->key, sme->key_len, sme->key_idx); + } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) { + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_TKIP) { + u8security = ENCRYPT_ENABLED | WPA2 | TKIP; + pcgroup_encrypt_val = "WPA2_TKIP"; + pccipher_group = "TKIP"; + } else { /* TODO: mostafa: here we assume that any other encryption type is AES */ + /* tenuSecurity_t = WPA2_AES; */ + u8security = ENCRYPT_ENABLED | WPA2 | AES; + pcgroup_encrypt_val = "WPA2_AES"; + pccipher_group = "AES"; + } + pcwpa_version = "WPA_VERSION_2"; + } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) { + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_TKIP) { + u8security = ENCRYPT_ENABLED | WPA | TKIP; + pcgroup_encrypt_val = "WPA_TKIP"; + pccipher_group = "TKIP"; + } else { /* TODO: mostafa: here we assume that any other encryption type is AES */ + /* tenuSecurity_t = WPA_AES; */ + u8security = ENCRYPT_ENABLED | WPA | AES; + pcgroup_encrypt_val = "WPA_AES"; + pccipher_group = "AES"; + + } + pcwpa_version = "WPA_VERSION_1"; + + } else { + s32Error = -ENOTSUPP; + PRINT_ER("Not supported cipher: Error(%d)\n", s32Error); + + goto done; + } + + } + + /* After we set the u8security value from checking the group cipher suite, {in case of WPA or WPA2} we will + * add to it the pairwise cipher suite(s) */ + if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + || (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) { + for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) { + if (sme->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP) { + u8security = u8security | TKIP; + } else { /* TODO: mostafa: here we assume that any other encryption type is AES */ + u8security = u8security | AES; + } + } + } + + PRINT_D(CFG80211_DBG, "Adding key with cipher group = %x\n", sme->crypto.cipher_group); + + PRINT_D(CFG80211_DBG, "Authentication Type = %d\n", sme->auth_type); + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + PRINT_D(CFG80211_DBG, "In OPEN SYSTEM\n"); + tenuAuth_type = OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + tenuAuth_type = SHARED_KEY; + PRINT_D(CFG80211_DBG, "In SHARED KEY\n"); + break; + + default: + PRINT_D(CFG80211_DBG, "Automatic Authentation type = %d\n", sme->auth_type); + } + + + /* ai: key_mgmt: enterprise case */ + if (sme->crypto.n_akm_suites) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + tenuAuth_type = IEEE8021; + break; + + default: + break; + } + } + + + PRINT_INFO(CFG80211_DBG, "Required Channel = %d\n", pstrNetworkInfo->u8channel); + + PRINT_INFO(CFG80211_DBG, "Group encryption value = %s\n Cipher Group = %s\n WPA version = %s\n", + pcgroup_encrypt_val, pccipher_group, pcwpa_version); + + curr_channel = pstrNetworkInfo->u8channel; + + if (!pstrWFIDrv->u8P2PConnect) { + u8WLANChannel = pstrNetworkInfo->u8channel; + } + + linux_wlan_set_bssid(dev, pstrNetworkInfo->au8bssid); + + s32Error = host_int_set_join_req(priv->hWILCWFIDrv, pstrNetworkInfo->au8bssid, sme->ssid, + sme->ssid_len, sme->ie, sme->ie_len, + CfgConnectResult, (void *)priv, u8security, + tenuAuth_type, pstrNetworkInfo->u8channel, + pstrNetworkInfo->pJoinParams); + if (s32Error != 0) { + PRINT_ER("host_int_set_join_req(): Error(%d)\n", s32Error); + s32Error = -ENOENT; + goto done; + } + +done: + + return s32Error; +} + + +/** + * @brief disconnect + * @details Disconnect from the BSS/ESS. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) +{ + s32 s32Error = 0; + struct wilc_priv *priv; + struct host_if_drv *pstrWFIDrv; + u8 NullBssid[ETH_ALEN] = {0}; + + connecting = 0; + priv = wiphy_priv(wiphy); + + /*Invalidate u8WLANChannel value on wlan0 disconnect*/ + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + if (!pstrWFIDrv->u8P2PConnect) + u8WLANChannel = INVALID_CHANNEL; + linux_wlan_set_bssid(priv->dev, NullBssid); + + PRINT_D(CFG80211_DBG, "Disconnecting with reason code(%d)\n", reason_code); + + u8P2Plocalrandom = 0x01; + u8P2Precvrandom = 0x00; + bWilc_ie = false; + pstrWFIDrv->u64P2p_MgmtTimeout = 0; + + s32Error = host_int_disconnect(priv->hWILCWFIDrv, reason_code); + if (s32Error != 0) { + PRINT_ER("Error in disconnecting: Error(%d)\n", s32Error); + s32Error = -EINVAL; + } + + return s32Error; +} + +/** + * @brief add_key + * @details Add a key with the given parameters. @mac_addr will be %NULL + * when adding a group key. + * @param[in] key : key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, + const u8 *mac_addr, struct key_params *params) + +{ + s32 s32Error = 0, KeyLen = params->key_len; + u32 i; + struct wilc_priv *priv; + const u8 *pu8RxMic = NULL; + const u8 *pu8TxMic = NULL; + u8 u8mode = NO_ENCRYPT; + u8 u8gmode = NO_ENCRYPT; + u8 u8pmode = NO_ENCRYPT; + enum AUTHTYPE tenuAuth_type = ANY; + struct wilc *wl; + perInterface_wlan_t *nic; + + priv = wiphy_priv(wiphy); + nic = netdev_priv(netdev); + wl = nic->wilc; + + PRINT_D(CFG80211_DBG, "Adding key with cipher suite = %x\n", params->cipher); + + PRINT_D(CFG80211_DBG, "%p %p %d\n", wiphy, netdev, key_index); + + PRINT_D(CFG80211_DBG, "key %x %x %x\n", params->key[0], + params->key[1], + params->key[2]); + + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if (priv->wdev->iftype == NL80211_IFTYPE_AP) { + + priv->WILC_WFI_wep_default = key_index; + priv->WILC_WFI_wep_key_len[key_index] = params->key_len; + memcpy(priv->WILC_WFI_wep_key[key_index], params->key, params->key_len); + + PRINT_D(CFG80211_DBG, "Adding AP WEP Default key Idx = %d\n", key_index); + PRINT_D(CFG80211_DBG, "Adding AP WEP Key len= %d\n", params->key_len); + + for (i = 0; i < params->key_len; i++) + PRINT_D(CFG80211_DBG, "WEP AP key val[%d] = %x\n", i, params->key[i]); + + tenuAuth_type = OPEN_SYSTEM; + + if (params->cipher == WLAN_CIPHER_SUITE_WEP40) + u8mode = ENCRYPT_ENABLED | WEP; + else + u8mode = ENCRYPT_ENABLED | WEP | WEP_EXTENDED; + + host_int_add_wep_key_bss_ap(priv->hWILCWFIDrv, params->key, params->key_len, key_index, u8mode, tenuAuth_type); + break; + } + if (memcmp(params->key, priv->WILC_WFI_wep_key[key_index], params->key_len)) { + priv->WILC_WFI_wep_default = key_index; + priv->WILC_WFI_wep_key_len[key_index] = params->key_len; + memcpy(priv->WILC_WFI_wep_key[key_index], params->key, params->key_len); + + PRINT_D(CFG80211_DBG, "Adding WEP Default key Idx = %d\n", key_index); + PRINT_D(CFG80211_DBG, "Adding WEP Key length = %d\n", params->key_len); + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "WEP key value[%d] = %d\n", i, params->key[i]); + } + host_int_add_wep_key_bss_sta(priv->hWILCWFIDrv, params->key, params->key_len, key_index); + } + + break; + + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + if (priv->wdev->iftype == NL80211_IFTYPE_AP || priv->wdev->iftype == NL80211_IFTYPE_P2P_GO) { + + if (priv->wilc_gtk[key_index] == NULL) { + priv->wilc_gtk[key_index] = kmalloc(sizeof(struct wilc_wfi_key), GFP_KERNEL); + priv->wilc_gtk[key_index]->key = NULL; + priv->wilc_gtk[key_index]->seq = NULL; + + } + if (priv->wilc_ptk[key_index] == NULL) { + priv->wilc_ptk[key_index] = kmalloc(sizeof(struct wilc_wfi_key), GFP_KERNEL); + priv->wilc_ptk[key_index]->key = NULL; + priv->wilc_ptk[key_index]->seq = NULL; + } + + + + if (!pairwise) { + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) + u8gmode = ENCRYPT_ENABLED | WPA | TKIP; + else + u8gmode = ENCRYPT_ENABLED | WPA2 | AES; + + priv->wilc_groupkey = u8gmode; + + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + + pu8TxMic = params->key + 24; + pu8RxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + /* if there has been previous allocation for the same index through its key, free that memory and allocate again*/ + kfree(priv->wilc_gtk[key_index]->key); + + priv->wilc_gtk[key_index]->key = kmalloc(params->key_len, GFP_KERNEL); + memcpy(priv->wilc_gtk[key_index]->key, params->key, params->key_len); + + /* if there has been previous allocation for the same index through its seq, free that memory and allocate again*/ + kfree(priv->wilc_gtk[key_index]->seq); + + if ((params->seq_len) > 0) { + priv->wilc_gtk[key_index]->seq = kmalloc(params->seq_len, GFP_KERNEL); + memcpy(priv->wilc_gtk[key_index]->seq, params->seq, params->seq_len); + } + + priv->wilc_gtk[key_index]->cipher = params->cipher; + priv->wilc_gtk[key_index]->key_len = params->key_len; + priv->wilc_gtk[key_index]->seq_len = params->seq_len; + + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding group key value[%d] = %x\n", i, params->key[i]); + for (i = 0; i < params->seq_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding group seq value[%d] = %x\n", i, params->seq[i]); + } + + + host_int_add_rx_gtk(priv->hWILCWFIDrv, params->key, KeyLen, + key_index, params->seq_len, params->seq, pu8RxMic, pu8TxMic, AP_MODE, u8gmode); + + } else { + PRINT_INFO(CFG80211_DBG, "STA Address: %x%x%x%x%x\n", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4]); + + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) + u8pmode = ENCRYPT_ENABLED | WPA | TKIP; + else + u8pmode = priv->wilc_groupkey | AES; + + + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + + pu8TxMic = params->key + 24; + pu8RxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + + kfree(priv->wilc_ptk[key_index]->key); + + priv->wilc_ptk[key_index]->key = kmalloc(params->key_len, GFP_KERNEL); + + kfree(priv->wilc_ptk[key_index]->seq); + + if ((params->seq_len) > 0) + priv->wilc_ptk[key_index]->seq = kmalloc(params->seq_len, GFP_KERNEL); + + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding pairwise key value[%d] = %x\n", i, params->key[i]); + + for (i = 0; i < params->seq_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding group seq value[%d] = %x\n", i, params->seq[i]); + } + + memcpy(priv->wilc_ptk[key_index]->key, params->key, params->key_len); + + if ((params->seq_len) > 0) + memcpy(priv->wilc_ptk[key_index]->seq, params->seq, params->seq_len); + + priv->wilc_ptk[key_index]->cipher = params->cipher; + priv->wilc_ptk[key_index]->key_len = params->key_len; + priv->wilc_ptk[key_index]->seq_len = params->seq_len; + + host_int_add_ptk(priv->hWILCWFIDrv, params->key, KeyLen, mac_addr, + pu8RxMic, pu8TxMic, AP_MODE, u8pmode, key_index); + } + break; + } + + { + u8mode = 0; + if (!pairwise) { + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + /* swap the tx mic by rx mic */ + pu8RxMic = params->key + 24; + pu8TxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + + /*save keys only on interface 0 (wifi interface)*/ + if (!g_gtk_keys_saved && netdev == wl->vif[0].ndev) { + g_add_gtk_key_params.key_idx = key_index; + g_add_gtk_key_params.pairwise = pairwise; + if (!mac_addr) { + g_add_gtk_key_params.mac_addr = NULL; + } else { + g_add_gtk_key_params.mac_addr = kmalloc(ETH_ALEN, GFP_KERNEL); + memcpy(g_add_gtk_key_params.mac_addr, mac_addr, ETH_ALEN); + } + g_key_gtk_params.key_len = params->key_len; + g_key_gtk_params.seq_len = params->seq_len; + g_key_gtk_params.key = kmalloc(params->key_len, GFP_KERNEL); + memcpy(g_key_gtk_params.key, params->key, params->key_len); + if (params->seq_len > 0) { + g_key_gtk_params.seq = kmalloc(params->seq_len, GFP_KERNEL); + memcpy(g_key_gtk_params.seq, params->seq, params->seq_len); + } + g_key_gtk_params.cipher = params->cipher; + + PRINT_D(CFG80211_DBG, "key %x %x %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2]); + g_gtk_keys_saved = true; + } + + host_int_add_rx_gtk(priv->hWILCWFIDrv, params->key, KeyLen, + key_index, params->seq_len, params->seq, pu8RxMic, pu8TxMic, STATION_MODE, u8mode); + } else { + if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { + /* swap the tx mic by rx mic */ + pu8RxMic = params->key + 24; + pu8TxMic = params->key + 16; + KeyLen = params->key_len - 16; + } + + /*save keys only on interface 0 (wifi interface)*/ + if (!g_ptk_keys_saved && netdev == wl->vif[0].ndev) { + g_add_ptk_key_params.key_idx = key_index; + g_add_ptk_key_params.pairwise = pairwise; + if (!mac_addr) { + g_add_ptk_key_params.mac_addr = NULL; + } else { + g_add_ptk_key_params.mac_addr = kmalloc(ETH_ALEN, GFP_KERNEL); + memcpy(g_add_ptk_key_params.mac_addr, mac_addr, ETH_ALEN); + } + g_key_ptk_params.key_len = params->key_len; + g_key_ptk_params.seq_len = params->seq_len; + g_key_ptk_params.key = kmalloc(params->key_len, GFP_KERNEL); + memcpy(g_key_ptk_params.key, params->key, params->key_len); + if (params->seq_len > 0) { + g_key_ptk_params.seq = kmalloc(params->seq_len, GFP_KERNEL); + memcpy(g_key_ptk_params.seq, params->seq, params->seq_len); + } + g_key_ptk_params.cipher = params->cipher; + + PRINT_D(CFG80211_DBG, "key %x %x %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2]); + g_ptk_keys_saved = true; + } + + host_int_add_ptk(priv->hWILCWFIDrv, params->key, KeyLen, mac_addr, + pu8RxMic, pu8TxMic, STATION_MODE, u8mode, key_index); + PRINT_D(CFG80211_DBG, "Adding pairwise key\n"); + if (INFO) { + for (i = 0; i < params->key_len; i++) + PRINT_INFO(CFG80211_DBG, "Adding pairwise key value[%d] = %d\n", i, params->key[i]); + } + } + } + break; + + default: + PRINT_ER("Not supported cipher: Error(%d)\n", s32Error); + s32Error = -ENOTSUPP; + + } + + return s32Error; +} + +/** + * @brief del_key + * @details Remove a key given the @mac_addr (%NULL for a group key) + * and @key_index, return -ENOENT if the key doesn't exist. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, + bool pairwise, + const u8 *mac_addr) +{ + struct wilc_priv *priv; + struct wilc *wl; + perInterface_wlan_t *nic; + + priv = wiphy_priv(wiphy); + nic = netdev_priv(netdev); + wl = nic->wilc; + + /*delete saved keys, if any*/ + if (netdev == wl->vif[0].ndev) { + g_ptk_keys_saved = false; + g_gtk_keys_saved = false; + g_wep_keys_saved = false; + + /*Delete saved WEP keys params, if any*/ + kfree(g_key_wep_params.key); + g_key_wep_params.key = NULL; + + /*freeing memory allocated by "wilc_gtk" and "wilc_ptk" in "WILC_WIFI_ADD_KEY"*/ + + if ((priv->wilc_gtk[key_index]) != NULL) { + + kfree(priv->wilc_gtk[key_index]->key); + priv->wilc_gtk[key_index]->key = NULL; + kfree(priv->wilc_gtk[key_index]->seq); + priv->wilc_gtk[key_index]->seq = NULL; + + kfree(priv->wilc_gtk[key_index]); + priv->wilc_gtk[key_index] = NULL; + + } + + if ((priv->wilc_ptk[key_index]) != NULL) { + + kfree(priv->wilc_ptk[key_index]->key); + priv->wilc_ptk[key_index]->key = NULL; + kfree(priv->wilc_ptk[key_index]->seq); + priv->wilc_ptk[key_index]->seq = NULL; + kfree(priv->wilc_ptk[key_index]); + priv->wilc_ptk[key_index] = NULL; + } + + /*Delete saved PTK and GTK keys params, if any*/ + kfree(g_key_ptk_params.key); + g_key_ptk_params.key = NULL; + kfree(g_key_ptk_params.seq); + g_key_ptk_params.seq = NULL; + + kfree(g_key_gtk_params.key); + g_key_gtk_params.key = NULL; + kfree(g_key_gtk_params.seq); + g_key_gtk_params.seq = NULL; + + /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/ + Set_machw_change_vir_if(netdev, false); + } + + if (key_index >= 0 && key_index <= 3) { + memset(priv->WILC_WFI_wep_key[key_index], 0, priv->WILC_WFI_wep_key_len[key_index]); + priv->WILC_WFI_wep_key_len[key_index] = 0; + + PRINT_D(CFG80211_DBG, "Removing WEP key with index = %d\n", key_index); + host_int_remove_wep_key(priv->hWILCWFIDrv, key_index); + } else { + PRINT_D(CFG80211_DBG, "Removing all installed keys\n"); + host_int_remove_key(priv->hWILCWFIDrv, mac_addr); + } + + return 0; +} + +/** + * @brief get_key + * @details Get information about the key with the given parameters. + * @mac_addr will be %NULL when requesting information for a group + * key. All pointers given to the @callback function need not be valid + * after it returns. This function should return an error if it is + * not possible to retrieve the key, -ENOENT if it doesn't exist. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, + const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *)) +{ + struct wilc_priv *priv; + struct key_params key_params; + u32 i; + + priv = wiphy_priv(wiphy); + + + if (!pairwise) { + PRINT_D(CFG80211_DBG, "Getting group key idx: %x\n", key_index); + + key_params.key = priv->wilc_gtk[key_index]->key; + key_params.cipher = priv->wilc_gtk[key_index]->cipher; + key_params.key_len = priv->wilc_gtk[key_index]->key_len; + key_params.seq = priv->wilc_gtk[key_index]->seq; + key_params.seq_len = priv->wilc_gtk[key_index]->seq_len; + if (INFO) { + for (i = 0; i < key_params.key_len; i++) + PRINT_INFO(CFG80211_DBG, "Retrieved key value %x\n", key_params.key[i]); + } + } else { + PRINT_D(CFG80211_DBG, "Getting pairwise key\n"); + + key_params.key = priv->wilc_ptk[key_index]->key; + key_params.cipher = priv->wilc_ptk[key_index]->cipher; + key_params.key_len = priv->wilc_ptk[key_index]->key_len; + key_params.seq = priv->wilc_ptk[key_index]->seq; + key_params.seq_len = priv->wilc_ptk[key_index]->seq_len; + } + + callback(cookie, &key_params); + + return 0; /* priv->wilc_gtk->key_len ?0 : -ENOENT; */ +} + +/** + * @brief set_default_key + * @details Set the default management frame key on an interface + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool unicast, bool multicast) +{ + struct wilc_priv *priv; + + + priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Setting default key with idx = %d\n", key_index); + + if (key_index != priv->WILC_WFI_wep_default) { + + host_int_set_wep_default_key(priv->hWILCWFIDrv, key_index); + } + + return 0; +} + +/** + * @brief get_station + * @details Get station information for the station identified by @mac + * @param[in] NONE + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ + +static int get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +{ + struct wilc_priv *priv; + perInterface_wlan_t *nic; + u32 i = 0; + u32 associatedsta = 0; + u32 inactive_time = 0; + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + PRINT_D(HOSTAPD_DBG, "Getting station parameters\n"); + + PRINT_INFO(HOSTAPD_DBG, ": %x%x%x%x%x\n", mac[0], mac[1], mac[2], mac[3], mac[4]); + + for (i = 0; i < NUM_STA_ASSOCIATED; i++) { + + if (!(memcmp(mac, priv->assoc_stainfo.au8Sta_AssociatedBss[i], ETH_ALEN))) { + associatedsta = i; + break; + } + + } + + if (associatedsta == -1) { + PRINT_ER("Station required is not associated\n"); + return -ENOENT; + } + + sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME); + + host_int_get_inactive_time(priv->hWILCWFIDrv, mac, &(inactive_time)); + sinfo->inactive_time = 1000 * inactive_time; + PRINT_D(CFG80211_DBG, "Inactive time %d\n", sinfo->inactive_time); + + } + + if (nic->iftype == STATION_MODE) { + struct rf_info strStatistics; + + host_int_get_statistics(priv->hWILCWFIDrv, &strStatistics); + + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) | + BIT(NL80211_STA_INFO_RX_PACKETS) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_TX_FAILED) | + BIT(NL80211_STA_INFO_TX_BITRATE); + + sinfo->signal = strStatistics.s8RSSI; + sinfo->rx_packets = strStatistics.u32RxCount; + sinfo->tx_packets = strStatistics.u32TxCount + strStatistics.u32TxFailureCount; + sinfo->tx_failed = strStatistics.u32TxFailureCount; + sinfo->txrate.legacy = strStatistics.u8LinkSpeed * 10; + + if ((strStatistics.u8LinkSpeed > TCP_ACK_FILTER_LINK_SPEED_THRESH) && (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED)) + Enable_TCP_ACK_Filter(true); + else if (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED) + Enable_TCP_ACK_Filter(false); + + PRINT_D(CORECONFIG_DBG, "*** stats[%d][%d][%d][%d][%d]\n", sinfo->signal, sinfo->rx_packets, sinfo->tx_packets, + sinfo->tx_failed, sinfo->txrate.legacy); + } + return 0; +} + + +/** + * @brief change_bss + * @details Modify parameters for a given BSS. + * @param[in] + * -use_cts_prot: Whether to use CTS protection + * (0 = no, 1 = yes, -1 = do not change) + * -use_short_preamble: Whether the use of short preambles is allowed + * (0 = no, 1 = yes, -1 = do not change) + * -use_short_slot_time: Whether the use of short slot time is allowed + * (0 = no, 1 = yes, -1 = do not change) + * -basic_rates: basic rates in IEEE 802.11 format + * (or NULL for no change) + * -basic_rates_len: number of basic rates + * -ap_isolate: do not forward packets between connected stations + * -ht_opmode: HT Operation mode + * (u16 = opmode, -1 = do not change) + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int change_bss(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params) +{ + PRINT_D(CFG80211_DBG, "Changing Bss parametrs\n"); + return 0; +} + +/** + * @brief set_wiphy_params + * @details Notify that wiphy parameters have changed; + * @param[in] Changed bitfield (see &enum wiphy_params_flags) describes which values + * have changed. + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + s32 s32Error = 0; + struct cfg_param_val pstrCfgParamVal; + struct wilc_priv *priv; + + priv = wiphy_priv(wiphy); + + pstrCfgParamVal.flag = 0; + PRINT_D(CFG80211_DBG, "Setting Wiphy params\n"); + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RETRY_SHORT %d\n", + priv->dev->ieee80211_ptr->wiphy->retry_short); + pstrCfgParamVal.flag |= RETRY_SHORT; + pstrCfgParamVal.short_retry_limit = priv->dev->ieee80211_ptr->wiphy->retry_short; + } + if (changed & WIPHY_PARAM_RETRY_LONG) { + + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RETRY_LONG %d\n", priv->dev->ieee80211_ptr->wiphy->retry_long); + pstrCfgParamVal.flag |= RETRY_LONG; + pstrCfgParamVal.long_retry_limit = priv->dev->ieee80211_ptr->wiphy->retry_long; + + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n", priv->dev->ieee80211_ptr->wiphy->frag_threshold); + pstrCfgParamVal.flag |= FRAG_THRESHOLD; + pstrCfgParamVal.frag_threshold = priv->dev->ieee80211_ptr->wiphy->frag_threshold; + + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RTS_THRESHOLD %d\n", priv->dev->ieee80211_ptr->wiphy->rts_threshold); + + pstrCfgParamVal.flag |= RTS_THRESHOLD; + pstrCfgParamVal.rts_threshold = priv->dev->ieee80211_ptr->wiphy->rts_threshold; + + } + + PRINT_D(CFG80211_DBG, "Setting CFG params in the host interface\n"); + s32Error = hif_set_cfg(priv->hWILCWFIDrv, &pstrCfgParamVal); + if (s32Error) + PRINT_ER("Error in setting WIPHY PARAMS\n"); + + + return s32Error; +} + +/** + * @brief set_pmksa + * @details Cache a PMKID for a BSSID. This is mostly useful for fullmac + * devices running firmwares capable of generating the (re) association + * RSN IE. It allows for faster roaming between WPA2 BSSIDs. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + u32 i; + s32 s32Error = 0; + u8 flag = 0; + + struct wilc_priv *priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Setting PMKSA\n"); + + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + /*If bssid already exists and pmkid value needs to reset*/ + flag = PMKID_FOUND; + PRINT_D(CFG80211_DBG, "PMKID already exists\n"); + break; + } + } + if (i < WILC_MAX_NUM_PMKIDS) { + PRINT_D(CFG80211_DBG, "Setting PMKID in private structure\n"); + memcpy(priv->pmkid_list.pmkidlist[i].bssid, pmksa->bssid, + ETH_ALEN); + memcpy(priv->pmkid_list.pmkidlist[i].pmkid, pmksa->pmkid, + PMKID_LEN); + if (!(flag == PMKID_FOUND)) + priv->pmkid_list.numpmkid++; + } else { + PRINT_ER("Invalid PMKID index\n"); + s32Error = -EINVAL; + } + + if (!s32Error) { + PRINT_D(CFG80211_DBG, "Setting pmkid in the host interface\n"); + s32Error = host_int_set_pmkid_info(priv->hWILCWFIDrv, &priv->pmkid_list); + } + return s32Error; +} + +/** + * @brief del_pmksa + * @details Delete a cached PMKID. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + + u32 i; + s32 s32Error = 0; + + struct wilc_priv *priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Deleting PMKSA keys\n"); + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + /*If bssid is found, reset the values*/ + PRINT_D(CFG80211_DBG, "Reseting PMKID values\n"); + memset(&priv->pmkid_list.pmkidlist[i], 0, sizeof(struct host_if_pmkid)); + break; + } + } + + if (i < priv->pmkid_list.numpmkid && priv->pmkid_list.numpmkid > 0) { + for (; i < (priv->pmkid_list.numpmkid - 1); i++) { + memcpy(priv->pmkid_list.pmkidlist[i].bssid, + priv->pmkid_list.pmkidlist[i + 1].bssid, + ETH_ALEN); + memcpy(priv->pmkid_list.pmkidlist[i].pmkid, + priv->pmkid_list.pmkidlist[i].pmkid, + PMKID_LEN); + } + priv->pmkid_list.numpmkid--; + } else { + s32Error = -EINVAL; + } + + return s32Error; +} + +/** + * @brief flush_pmksa + * @details Flush all cached PMKIDs. + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) +{ + struct wilc_priv *priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Flushing PMKID key values\n"); + + /*Get cashed Pmkids and set all with zeros*/ + memset(&priv->pmkid_list, 0, sizeof(struct host_if_pmkid_attr)); + + return 0; +} + + +/** + * @brief WILC_WFI_CfgParseRxAction + * @details Function parses the received frames and modifies the following attributes: + * -GO Intent + * -Channel list + * -Operating Channel + * + * @param[in] u8* Buffer, u32 length + * @return NONE. + * @author mdaftedar + * @date 12 DEC 2012 + * @version + */ + +void WILC_WFI_CfgParseRxAction(u8 *buf, u32 len) +{ + u32 index = 0; + u32 i = 0, j = 0; + + u8 op_channel_attr_index = 0; + u8 channel_list_attr_index = 0; + + while (index < len) { + if (buf[index] == GO_INTENT_ATTR_ID) { + buf[index + 3] = (buf[index + 3] & 0x01) | (0x00 << 1); + } + + if (buf[index] == CHANLIST_ATTR_ID) + channel_list_attr_index = index; + else if (buf[index] == OPERCHAN_ATTR_ID) + op_channel_attr_index = index; + index += buf[index + 1] + 3; /* ID,Length byte */ + } + if (u8WLANChannel != INVALID_CHANNEL) { + + /*Modify channel list attribute*/ + if (channel_list_attr_index) { + PRINT_D(GENERIC_DBG, "Modify channel list attribute\n"); + for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) { + if (buf[i] == 0x51) { + for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) { + buf[j] = u8WLANChannel; + } + break; + } + } + } + /*Modify operating channel attribute*/ + if (op_channel_attr_index) { + PRINT_D(GENERIC_DBG, "Modify operating channel attribute\n"); + buf[op_channel_attr_index + 6] = 0x51; + buf[op_channel_attr_index + 7] = u8WLANChannel; + } + } +} + +/** + * @brief WILC_WFI_CfgParseTxAction + * @details Function parses the transmitted action frames and modifies the + * GO Intent attribute + * @param[in] u8* Buffer, u32 length, bool bOperChan, u8 iftype + * @return NONE. + * @author mdaftedar + * @date 12 DEC 2012 + * @version + */ +void WILC_WFI_CfgParseTxAction(u8 *buf, u32 len, bool bOperChan, u8 iftype) +{ + u32 index = 0; + u32 i = 0, j = 0; + + u8 op_channel_attr_index = 0; + u8 channel_list_attr_index = 0; + + while (index < len) { + if (buf[index] == GO_INTENT_ATTR_ID) { + buf[index + 3] = (buf[index + 3] & 0x01) | (0x0f << 1); + + break; + } + + if (buf[index] == CHANLIST_ATTR_ID) + channel_list_attr_index = index; + else if (buf[index] == OPERCHAN_ATTR_ID) + op_channel_attr_index = index; + index += buf[index + 1] + 3; /* ID,Length byte */ + } + if (u8WLANChannel != INVALID_CHANNEL && bOperChan) { + + /*Modify channel list attribute*/ + if (channel_list_attr_index) { + PRINT_D(GENERIC_DBG, "Modify channel list attribute\n"); + for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) { + if (buf[i] == 0x51) { + for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) { + buf[j] = u8WLANChannel; + } + break; + } + } + } + /*Modify operating channel attribute*/ + if (op_channel_attr_index) { + PRINT_D(GENERIC_DBG, "Modify operating channel attribute\n"); + buf[op_channel_attr_index + 6] = 0x51; + buf[op_channel_attr_index + 7] = u8WLANChannel; + } + } +} + +/* @brief WILC_WFI_p2p_rx + * @details + * @param[in] + * + * @return None + * @author Mai Daftedar + * @date 2 JUN 2013 + * @version 1.0 + */ + +void WILC_WFI_p2p_rx (struct net_device *dev, u8 *buff, u32 size) +{ + + struct wilc_priv *priv; + u32 header, pkt_offset; + struct host_if_drv *pstrWFIDrv; + u32 i = 0; + s32 s32Freq; + + priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + + /* Get WILC header */ + memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET); + + /* The packet offset field conain info about what type of managment frame */ + /* we are dealing with and ack status */ + pkt_offset = GET_PKT_OFFSET(header); + + if (pkt_offset & IS_MANAGMEMENT_CALLBACK) { + if (buff[FRAME_TYPE_ID] == IEEE80211_STYPE_PROBE_RESP) { + PRINT_D(GENERIC_DBG, "Probe response ACK\n"); + cfg80211_mgmt_tx_status(priv->wdev, priv->u64tx_cookie, buff, size, true, GFP_KERNEL); + return; + } else { + if (pkt_offset & IS_MGMT_STATUS_SUCCES) { + PRINT_D(GENERIC_DBG, "Success Ack - Action frame category: %x Action Subtype: %d Dialog T: %x OR %x\n", buff[ACTION_CAT_ID], buff[ACTION_SUBTYPE_ID], + buff[ACTION_SUBTYPE_ID + 1], buff[P2P_PUB_ACTION_SUBTYPE + 1]); + cfg80211_mgmt_tx_status(priv->wdev, priv->u64tx_cookie, buff, size, true, GFP_KERNEL); + } else { + PRINT_D(GENERIC_DBG, "Fail Ack - Action frame category: %x Action Subtype: %d Dialog T: %x OR %x\n", buff[ACTION_CAT_ID], buff[ACTION_SUBTYPE_ID], + buff[ACTION_SUBTYPE_ID + 1], buff[P2P_PUB_ACTION_SUBTYPE + 1]); + cfg80211_mgmt_tx_status(priv->wdev, priv->u64tx_cookie, buff, size, false, GFP_KERNEL); + } + return; + } + } else { + + PRINT_D(GENERIC_DBG, "Rx Frame Type:%x\n", buff[FRAME_TYPE_ID]); + + /*Upper layer is informed that the frame is received on this freq*/ + s32Freq = ieee80211_channel_to_frequency(curr_channel, IEEE80211_BAND_2GHZ); + + if (ieee80211_is_action(buff[FRAME_TYPE_ID])) { + PRINT_D(GENERIC_DBG, "Rx Action Frame Type: %x %x\n", buff[ACTION_SUBTYPE_ID], buff[P2P_PUB_ACTION_SUBTYPE]); + + if (priv->bCfgScanning && time_after_eq(jiffies, (unsigned long)pstrWFIDrv->u64P2p_MgmtTimeout)) { + PRINT_D(GENERIC_DBG, "Receiving action frames from wrong channels\n"); + return; + } + if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) { + + switch (buff[ACTION_SUBTYPE_ID]) { + case GAS_INTIAL_REQ: + PRINT_D(GENERIC_DBG, "GAS INITIAL REQ %x\n", buff[ACTION_SUBTYPE_ID]); + break; + + case GAS_INTIAL_RSP: + PRINT_D(GENERIC_DBG, "GAS INITIAL RSP %x\n", buff[ACTION_SUBTYPE_ID]); + break; + + case PUBLIC_ACT_VENDORSPEC: + /*Now we have a public action vendor specific action frame, check if its a p2p public action frame + * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/ + if (!memcmp(u8P2P_oui, &buff[ACTION_SUBTYPE_ID + 1], 4)) { + if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) { + if (!bWilc_ie) { + for (i = P2P_PUB_ACTION_SUBTYPE; i < size; i++) { + if (!memcmp(u8P2P_vendorspec, &buff[i], 6)) { + u8P2Precvrandom = buff[i + 6]; + bWilc_ie = true; + PRINT_D(GENERIC_DBG, "WILC Vendor specific IE:%02x\n", u8P2Precvrandom); + break; + } + } + } + } + if (u8P2Plocalrandom > u8P2Precvrandom) { + if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP + || buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)) { + for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < size; i++) { + if (buff[i] == P2PELEM_ATTR_ID && !(memcmp(u8P2P_oui, &buff[i + 2], 4))) { + WILC_WFI_CfgParseRxAction(&buff[i + 6], size - (i + 6)); + break; + } + } + } + } else + PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom); + } + + + if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP) && (bWilc_ie)) { + PRINT_D(GENERIC_DBG, "Sending P2P to host without extra elemnt\n"); + /* extra attribute for sig_dbm: signal strength in mBm, or 0 if unknown */ + cfg80211_rx_mgmt(priv->wdev, s32Freq, 0, buff, size - 7, 0); + return; + } + break; + + default: + PRINT_D(GENERIC_DBG, "NOT HANDLED PUBLIC ACTION FRAME TYPE:%x\n", buff[ACTION_SUBTYPE_ID]); + break; + } + } + } + + cfg80211_rx_mgmt(priv->wdev, s32Freq, 0, buff, size - 7, 0); + } +} + +/** + * @brief WILC_WFI_mgmt_tx_complete + * @details Returns result of writing mgmt frame to VMM (Tx buffers are freed here) + * @param[in] priv + * transmitting status + * @return None + * @author Amr Abdelmoghny + * @date 20 MAY 2013 + * @version 1.0 + */ +static void WILC_WFI_mgmt_tx_complete(void *priv, int status) +{ + struct p2p_mgmt_data *pv_data = (struct p2p_mgmt_data *)priv; + + + kfree(pv_data->buff); + kfree(pv_data); +} + +/** + * @brief WILC_WFI_RemainOnChannelReady + * @details Callback function, called from handle_remain_on_channel on being ready on channel + * @param + * @return none + * @author Amr abdelmoghny + * @date 9 JUNE 2013 + * @version + */ + +static void WILC_WFI_RemainOnChannelReady(void *pUserVoid) +{ + struct wilc_priv *priv; + + priv = (struct wilc_priv *)pUserVoid; + + PRINT_D(HOSTINF_DBG, "Remain on channel ready\n"); + + priv->bInP2PlistenState = true; + + cfg80211_ready_on_channel(priv->wdev, + priv->strRemainOnChanParams.u64ListenCookie, + priv->strRemainOnChanParams.pstrListenChan, + priv->strRemainOnChanParams.u32ListenDuration, + GFP_KERNEL); +} + +/** + * @brief WILC_WFI_RemainOnChannelExpired + * @details Callback function, called on expiration of remain-on-channel duration + * @param + * @return none + * @author Amr abdelmoghny + * @date 15 MAY 2013 + * @version + */ + +static void WILC_WFI_RemainOnChannelExpired(void *pUserVoid, u32 u32SessionID) +{ + struct wilc_priv *priv; + + priv = (struct wilc_priv *)pUserVoid; + + if (u32SessionID == priv->strRemainOnChanParams.u32ListenSessionID) { + PRINT_D(GENERIC_DBG, "Remain on channel expired\n"); + + priv->bInP2PlistenState = false; + + /*Inform wpas of remain-on-channel expiration*/ + cfg80211_remain_on_channel_expired(priv->wdev, + priv->strRemainOnChanParams.u64ListenCookie, + priv->strRemainOnChanParams.pstrListenChan, + GFP_KERNEL); + } else { + PRINT_D(GENERIC_DBG, "Received ID 0x%x Expected ID 0x%x (No match)\n", u32SessionID + , priv->strRemainOnChanParams.u32ListenSessionID); + } +} + + +/** + * @brief remain_on_channel + * @details Request the driver to remain awake on the specified + * channel for the specified duration to complete an off-channel + * operation (e.g., public action frame exchange). When the driver is + * ready on the requested channel, it must indicate this with an event + * notification by calling cfg80211_ready_on_channel(). + * @param[in] + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + s32 s32Error = 0; + struct wilc_priv *priv; + + priv = wiphy_priv(wiphy); + + PRINT_D(GENERIC_DBG, "Remaining on channel %d\n", chan->hw_value); + + + if (wdev->iftype == NL80211_IFTYPE_AP) { + PRINT_D(GENERIC_DBG, "Required remain-on-channel while in AP mode"); + return s32Error; + } + + curr_channel = chan->hw_value; + + /*Setting params needed by WILC_WFI_RemainOnChannelExpired()*/ + priv->strRemainOnChanParams.pstrListenChan = chan; + priv->strRemainOnChanParams.u64ListenCookie = *cookie; + priv->strRemainOnChanParams.u32ListenDuration = duration; + priv->strRemainOnChanParams.u32ListenSessionID++; + + s32Error = host_int_remain_on_channel(priv->hWILCWFIDrv + , priv->strRemainOnChanParams.u32ListenSessionID + , duration + , chan->hw_value + , WILC_WFI_RemainOnChannelExpired + , WILC_WFI_RemainOnChannelReady + , (void *)priv); + + return s32Error; +} + +/** + * @brief cancel_remain_on_channel + * @details Cancel an on-going remain-on-channel operation. + * This allows the operation to be terminated prior to timeout based on + * the duration value. + * @param[in] struct wiphy *wiphy, + * @param[in] struct net_device *dev + * @param[in] u64 cookie, + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + s32 s32Error = 0; + struct wilc_priv *priv; + + priv = wiphy_priv(wiphy); + + PRINT_D(CFG80211_DBG, "Cancel remain on channel\n"); + + s32Error = host_int_ListenStateExpired(priv->hWILCWFIDrv, priv->strRemainOnChanParams.u32ListenSessionID); + return s32Error; +} +/** + * @brief WILC_WFI_mgmt_tx_frame + * @details + * + * @param[in] + * @return NONE. + * @author mdaftedar + * @date 01 JUL 2012 + * @version + */ +extern bool bEnablePS; +static int mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + struct ieee80211_channel *chan = params->chan; + unsigned int wait = params->wait; + const u8 *buf = params->buf; + size_t len = params->len; + const struct ieee80211_mgmt *mgmt; + struct p2p_mgmt_data *mgmt_tx; + struct wilc_priv *priv; + struct host_if_drv *pstrWFIDrv; + u32 i; + perInterface_wlan_t *nic; + u32 buf_len = len + sizeof(u8P2P_vendorspec) + sizeof(u8P2Plocalrandom); + + nic = netdev_priv(wdev->netdev); + priv = wiphy_priv(wiphy); + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + + *cookie = (unsigned long)buf; + priv->u64tx_cookie = *cookie; + mgmt = (const struct ieee80211_mgmt *) buf; + + if (ieee80211_is_mgmt(mgmt->frame_control)) { + + /*mgmt frame allocation*/ + mgmt_tx = kmalloc(sizeof(struct p2p_mgmt_data), GFP_KERNEL); + if (mgmt_tx == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx structure\n"); + return -EFAULT; + } + mgmt_tx->buff = kmalloc(buf_len, GFP_KERNEL); + if (mgmt_tx->buff == NULL) { + PRINT_ER("Failed to allocate memory for mgmt_tx buff\n"); + kfree(mgmt_tx); + return -EFAULT; + } + memcpy(mgmt_tx->buff, buf, len); + mgmt_tx->size = len; + + + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + PRINT_D(GENERIC_DBG, "TX: Probe Response\n"); + PRINT_D(GENERIC_DBG, "Setting channel: %d\n", chan->hw_value); + host_int_set_mac_chnl_num(priv->hWILCWFIDrv, chan->hw_value); + /*Save the current channel after we tune to it*/ + curr_channel = chan->hw_value; + } else if (ieee80211_is_action(mgmt->frame_control)) { + PRINT_D(GENERIC_DBG, "ACTION FRAME:%x\n", (u16)mgmt->frame_control); + + + if (buf[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) { + /*Only set the channel, if not a negotiation confirmation frame + * (If Negotiation confirmation frame, force it + * to be transmitted on the same negotiation channel)*/ + + if (buf[ACTION_SUBTYPE_ID] != PUBLIC_ACT_VENDORSPEC || + buf[P2P_PUB_ACTION_SUBTYPE] != GO_NEG_CONF) { + PRINT_D(GENERIC_DBG, "Setting channel: %d\n", chan->hw_value); + host_int_set_mac_chnl_num(priv->hWILCWFIDrv, chan->hw_value); + /*Save the current channel after we tune to it*/ + curr_channel = chan->hw_value; + } + switch (buf[ACTION_SUBTYPE_ID]) { + case GAS_INTIAL_REQ: + { + PRINT_D(GENERIC_DBG, "GAS INITIAL REQ %x\n", buf[ACTION_SUBTYPE_ID]); + break; + } + + case GAS_INTIAL_RSP: + { + PRINT_D(GENERIC_DBG, "GAS INITIAL RSP %x\n", buf[ACTION_SUBTYPE_ID]); + break; + } + + case PUBLIC_ACT_VENDORSPEC: + { + /*Now we have a public action vendor specific action frame, check if its a p2p public action frame + * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/ + if (!memcmp(u8P2P_oui, &buf[ACTION_SUBTYPE_ID + 1], 4)) { + /*For the connection of two WILC's connection generate a rand number to determine who will be a GO*/ + if ((buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) { + if (u8P2Plocalrandom == 1 && u8P2Precvrandom < u8P2Plocalrandom) { + get_random_bytes(&u8P2Plocalrandom, 1); + /*Increment the number to prevent if its 0*/ + u8P2Plocalrandom++; + } + } + + if ((buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP + || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)) { + if (u8P2Plocalrandom > u8P2Precvrandom) { + PRINT_D(GENERIC_DBG, "LOCAL WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom); + + /*Search for the p2p information information element , after the Public action subtype theres a byte for teh dialog token, skip that*/ + for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < len; i++) { + if (buf[i] == P2PELEM_ATTR_ID && !(memcmp(u8P2P_oui, &buf[i + 2], 4))) { + if (buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP) + WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), true, nic->iftype); + + /*If using supplicant go intent, no need at all*/ + /*to parse transmitted negotiation frames*/ + else + WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), false, nic->iftype); + break; + } + } + + if (buf[P2P_PUB_ACTION_SUBTYPE] != P2P_INV_REQ && buf[P2P_PUB_ACTION_SUBTYPE] != P2P_INV_RSP) { + /* + * Adding WILC information element to allow two WILC devices to + * identify each other and connect + */ + memcpy(&mgmt_tx->buff[len], u8P2P_vendorspec, sizeof(u8P2P_vendorspec)); + mgmt_tx->buff[len + sizeof(u8P2P_vendorspec)] = u8P2Plocalrandom; + mgmt_tx->size = buf_len; + } + } else + PRINT_D(GENERIC_DBG, "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n", u8P2Plocalrandom, u8P2Precvrandom); + } + + } else { + PRINT_D(GENERIC_DBG, "Not a P2P public action frame\n"); + } + + break; + } + + default: + { + PRINT_D(GENERIC_DBG, "NOT HANDLED PUBLIC ACTION FRAME TYPE:%x\n", buf[ACTION_SUBTYPE_ID]); + break; + } + } + + } + + PRINT_D(GENERIC_DBG, "TX: ACTION FRAME Type:%x : Chan:%d\n", buf[ACTION_SUBTYPE_ID], chan->hw_value); + pstrWFIDrv->u64P2p_MgmtTimeout = (jiffies + msecs_to_jiffies(wait)); + + PRINT_D(GENERIC_DBG, "Current Jiffies: %lu Timeout:%llu\n", jiffies, pstrWFIDrv->u64P2p_MgmtTimeout); + + } + + wilc_wlan_txq_add_mgmt_pkt(mgmt_tx, mgmt_tx->buff, + mgmt_tx->size, + WILC_WFI_mgmt_tx_complete); + } else { + PRINT_D(GENERIC_DBG, "This function transmits only management frames\n"); + } + return 0; +} + +static int mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct wilc_priv *priv; + struct host_if_drv *pstrWFIDrv; + + priv = wiphy_priv(wiphy); + pstrWFIDrv = (struct host_if_drv *)priv->hWILCWFIDrv; + + + PRINT_D(GENERIC_DBG, "Tx Cancel wait :%lu\n", jiffies); + pstrWFIDrv->u64P2p_MgmtTimeout = jiffies; + + if (!priv->bInP2PlistenState) { + cfg80211_remain_on_channel_expired(priv->wdev, + priv->strRemainOnChanParams.u64ListenCookie, + priv->strRemainOnChanParams.pstrListenChan, + GFP_KERNEL); + } + + return 0; +} + +/** + * @brief wilc_mgmt_frame_register + * @details Notify driver that a management frame type was + * registered. Note that this callback may not sleep, and cannot run + * concurrently with itself. + * @param[in] + * @return NONE. + * @author mdaftedar + * @date 01 JUL 2012 + * @version + */ +void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, + u16 frame_type, bool reg) +{ + + struct wilc_priv *priv; + perInterface_wlan_t *nic; + struct wilc *wl; + + priv = wiphy_priv(wiphy); + nic = netdev_priv(priv->wdev->netdev); + wl = nic->wilc; + + if (!frame_type) + return; + + PRINT_D(GENERIC_DBG, "Frame registering Frame Type: %x: Boolean: %d\n", frame_type, reg); + switch (frame_type) { + case PROBE_REQ: + { + nic->g_struct_frame_reg[0].frame_type = frame_type; + nic->g_struct_frame_reg[0].reg = reg; + } + break; + + case ACTION: + { + nic->g_struct_frame_reg[1].frame_type = frame_type; + nic->g_struct_frame_reg[1].reg = reg; + } + break; + + default: + { + break; + } + + } + /*If mac is closed, then return*/ + if (!wl->initialized) { + PRINT_D(GENERIC_DBG, "Return since mac is closed\n"); + return; + } + host_int_frame_register(priv->hWILCWFIDrv, frame_type, reg); + + +} + +/** + * @brief set_cqm_rssi_config + * @details Configure connection quality monitor RSSI threshold. + * @param[in] struct wiphy *wiphy: + * @param[in] struct net_device *dev: + * @param[in] s32 rssi_thold: + * @param[in] u32 rssi_hyst: + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst) +{ + PRINT_D(CFG80211_DBG, "Setting CQM RSSi Function\n"); + return 0; + +} +/** + * @brief dump_station + * @details Configure connection quality monitor RSSI threshold. + * @param[in] struct wiphy *wiphy: + * @param[in] struct net_device *dev + * @param[in] int idx + * @param[in] u8 *mac + * @param[in] struct station_info *sinfo + * @return int : Return 0 on Success + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct wilc_priv *priv; + + PRINT_D(CFG80211_DBG, "Dumping station information\n"); + + if (idx != 0) + return -ENOENT; + + priv = wiphy_priv(wiphy); + + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + + host_int_get_rssi(priv->hWILCWFIDrv, &(sinfo->signal)); + + return 0; + +} + + +/** + * @brief set_power_mgmt + * @details + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 JUL 2012 + * @version 1.0 + */ +static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) +{ + struct wilc_priv *priv; + + PRINT_D(CFG80211_DBG, " Power save Enabled= %d , TimeOut = %d\n", enabled, timeout); + + if (wiphy == NULL) + return -ENOENT; + + priv = wiphy_priv(wiphy); + if (priv->hWILCWFIDrv == NULL) { + PRINT_ER("Driver is NULL\n"); + return -EIO; + } + + if (bEnablePS) + host_int_set_power_mgmt(priv->hWILCWFIDrv, enabled, timeout); + + + return 0; + +} + +/** + * @brief change_virtual_intf + * @details Change type/configuration of virtual interface, + * keep the struct wireless_dev's iftype updated. + * @param[in] NONE + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic); + +static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, + enum nl80211_iftype type, u32 *flags, struct vif_params *params) +{ + struct wilc_priv *priv; + perInterface_wlan_t *nic; + u8 interface_type; + u16 TID = 0; + u8 i; + struct wilc *wl; + + nic = netdev_priv(dev); + priv = wiphy_priv(wiphy); + wl = nic->wilc; + + PRINT_D(HOSTAPD_DBG, "In Change virtual interface function\n"); + PRINT_D(HOSTAPD_DBG, "Wireless interface name =%s\n", dev->name); + u8P2Plocalrandom = 0x01; + u8P2Precvrandom = 0x00; + + bWilc_ie = false; + + g_obtainingIP = false; + del_timer(&hDuringIpTimer); + PRINT_D(GENERIC_DBG, "Changing virtual interface, enable scan\n"); + /*Set WILC_CHANGING_VIR_IF register to disallow adding futrue keys to CE H/W*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + Set_machw_change_vir_if(dev, true); + } + + switch (type) { + case NL80211_IFTYPE_STATION: + connecting = 0; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_STATION\n"); + + /* send delba over wlan interface */ + + + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + nic->monitor_flag = 0; + nic->iftype = STATION_MODE; + + /*Remove the enteries of the previously connected clients*/ + memset(priv->assoc_stainfo.au8Sta_AssociatedBss, 0, MAX_NUM_STA * ETH_ALEN); + interface_type = nic->iftype; + nic->iftype = STATION_MODE; + + if (wl->initialized) { + host_int_del_All_Rx_BASession(priv->hWILCWFIDrv, + wl->vif[0].bssid, TID); + /* ensure that the message Q is empty */ + host_int_wait_msg_queue_idle(); + + /*Eliminate host interface blocking state*/ + up(&wl->cfg_event); + + wilc1000_wlan_deinit(dev); + wilc1000_wlan_init(dev, nic); + g_wilc_initialized = 1; + nic->iftype = interface_type; + + /*Setting interface 1 drv handler and mac address in newly downloaded FW*/ + host_int_set_wfi_drv_handler(wl->vif[0].hif_drv); + host_int_set_MacAddress(wl->vif[0].hif_drv, + wl->vif[0].src_addr); + host_int_set_operation_mode(priv->hWILCWFIDrv, STATION_MODE); + + /*Add saved WEP keys, if any*/ + if (g_wep_keys_saved) { + host_int_set_wep_default_key(wl->vif[0].hif_drv, + g_key_wep_params.key_idx); + host_int_add_wep_key_bss_sta(wl->vif[0].hif_drv, + g_key_wep_params.key, + g_key_wep_params.key_len, + g_key_wep_params.key_idx); + } + + /*No matter the driver handler passed here, it will be overwriiten*/ + /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/ + host_int_flush_join_req(priv->hWILCWFIDrv); + + /*Add saved PTK and GTK keys, if any*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + PRINT_D(CFG80211_DBG, "ptk %x %x %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2]); + PRINT_D(CFG80211_DBG, "gtk %x %x %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2]); + add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy, + wl->vif[0].ndev, + g_add_ptk_key_params.key_idx, + g_add_ptk_key_params.pairwise, + g_add_ptk_key_params.mac_addr, + (struct key_params *)(&g_key_ptk_params)); + + add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy, + wl->vif[0].ndev, + g_add_gtk_key_params.key_idx, + g_add_gtk_key_params.pairwise, + g_add_gtk_key_params.mac_addr, + (struct key_params *)(&g_key_gtk_params)); + } + + if (wl->initialized) { + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + + bEnablePS = true; + host_int_set_power_mgmt(priv->hWILCWFIDrv, 1, 0); + } + break; + + case NL80211_IFTYPE_P2P_CLIENT: + bEnablePS = false; + host_int_set_power_mgmt(priv->hWILCWFIDrv, 0, 0); + connecting = 0; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_P2P_CLIENT\n"); + + host_int_del_All_Rx_BASession(priv->hWILCWFIDrv, + wl->vif[0].bssid, TID); + + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + nic->monitor_flag = 0; + + PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n"); + nic->iftype = CLIENT_MODE; + + + if (wl->initialized) { + /* ensure that the message Q is empty */ + host_int_wait_msg_queue_idle(); + + wilc1000_wlan_deinit(dev); + wilc1000_wlan_init(dev, nic); + g_wilc_initialized = 1; + + host_int_set_wfi_drv_handler(wl->vif[0].hif_drv); + host_int_set_MacAddress(wl->vif[0].hif_drv, + wl->vif[0].src_addr); + host_int_set_operation_mode(priv->hWILCWFIDrv, STATION_MODE); + + /*Add saved WEP keys, if any*/ + if (g_wep_keys_saved) { + host_int_set_wep_default_key(wl->vif[0].hif_drv, + g_key_wep_params.key_idx); + host_int_add_wep_key_bss_sta(wl->vif[0].hif_drv, + g_key_wep_params.key, + g_key_wep_params.key_len, + g_key_wep_params.key_idx); + } + + /*No matter the driver handler passed here, it will be overwriiten*/ + /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/ + host_int_flush_join_req(priv->hWILCWFIDrv); + + /*Add saved PTK and GTK keys, if any*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + PRINT_D(CFG80211_DBG, "ptk %x %x %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2]); + PRINT_D(CFG80211_DBG, "gtk %x %x %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2]); + add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy, + wl->vif[0].ndev, + g_add_ptk_key_params.key_idx, + g_add_ptk_key_params.pairwise, + g_add_ptk_key_params.mac_addr, + (struct key_params *)(&g_key_ptk_params)); + + add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy, + wl->vif[0].ndev, + g_add_gtk_key_params.key_idx, + g_add_gtk_key_params.pairwise, + g_add_gtk_key_params.mac_addr, + (struct key_params *)(&g_key_gtk_params)); + } + + /*Refresh scan, to refresh the scan results to the wpa_supplicant. Set MachHw to false to enable further key installments*/ + refresh_scan(priv, 1, true); + Set_machw_change_vir_if(dev, false); + + if (wl->initialized) { + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + } + break; + + case NL80211_IFTYPE_AP: + bEnablePS = false; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_AP %d\n", type); + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + nic->iftype = AP_MODE; + PRINT_D(CORECONFIG_DBG, "priv->hWILCWFIDrv[%p]\n", priv->hWILCWFIDrv); + + PRINT_D(HOSTAPD_DBG, "Downloading AP firmware\n"); + linux_wlan_get_firmware(nic); + /*If wilc is running, then close-open to actually get new firmware running (serves P2P)*/ + if (wl->initialized) { + nic->iftype = AP_MODE; + mac_close(dev); + mac_open(dev); + + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + break; + + case NL80211_IFTYPE_P2P_GO: + PRINT_D(GENERIC_DBG, "start duringIP timer\n"); + + g_obtainingIP = true; + mod_timer(&hDuringIpTimer, jiffies + msecs_to_jiffies(duringIP_TIME)); + host_int_set_power_mgmt(priv->hWILCWFIDrv, 0, 0); + /*Delete block ack has to be the latest config packet*/ + /*sent before downloading new FW. This is because it blocks on*/ + /*hWaitResponse semaphore, which allows previous config*/ + /*packets to actually take action on old FW*/ + host_int_del_All_Rx_BASession(priv->hWILCWFIDrv, + wl->vif[0].bssid, TID); + bEnablePS = false; + PRINT_D(HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_GO\n"); + dev->ieee80211_ptr->iftype = type; + priv->wdev->iftype = type; + + PRINT_D(CORECONFIG_DBG, "priv->hWILCWFIDrv[%p]\n", priv->hWILCWFIDrv); + + PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n"); + + + nic->iftype = GO_MODE; + + /* ensure that the message Q is empty */ + host_int_wait_msg_queue_idle(); + wilc1000_wlan_deinit(dev); + wilc1000_wlan_init(dev, nic); + g_wilc_initialized = 1; + + + /*Setting interface 1 drv handler and mac address in newly downloaded FW*/ + host_int_set_wfi_drv_handler(wl->vif[0].hif_drv); + host_int_set_MacAddress(wl->vif[0].hif_drv, + wl->vif[0].src_addr); + host_int_set_operation_mode(priv->hWILCWFIDrv, AP_MODE); + + /*Add saved WEP keys, if any*/ + if (g_wep_keys_saved) { + host_int_set_wep_default_key(wl->vif[0].hif_drv, + g_key_wep_params.key_idx); + host_int_add_wep_key_bss_sta(wl->vif[0].hif_drv, + g_key_wep_params.key, + g_key_wep_params.key_len, + g_key_wep_params.key_idx); + } + + /*No matter the driver handler passed here, it will be overwriiten*/ + /*in Handle_FlushConnect() with gu8FlushedJoinReqDrvHandler*/ + host_int_flush_join_req(priv->hWILCWFIDrv); + + /*Add saved PTK and GTK keys, if any*/ + if (g_ptk_keys_saved && g_gtk_keys_saved) { + PRINT_D(CFG80211_DBG, "ptk %x %x %x cipher %x\n", g_key_ptk_params.key[0], + g_key_ptk_params.key[1], + g_key_ptk_params.key[2], + g_key_ptk_params.cipher); + PRINT_D(CFG80211_DBG, "gtk %x %x %x cipher %x\n", g_key_gtk_params.key[0], + g_key_gtk_params.key[1], + g_key_gtk_params.key[2], + g_key_gtk_params.cipher); + add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy, + wl->vif[0].ndev, + g_add_ptk_key_params.key_idx, + g_add_ptk_key_params.pairwise, + g_add_ptk_key_params.mac_addr, + (struct key_params *)(&g_key_ptk_params)); + + add_key(wl->vif[0].ndev->ieee80211_ptr->wiphy, + wl->vif[0].ndev, + g_add_gtk_key_params.key_idx, + g_add_gtk_key_params.pairwise, + g_add_gtk_key_params.mac_addr, + (struct key_params *)(&g_key_gtk_params)); + } + + if (wl->initialized) { + for (i = 0; i < num_reg_frame; i++) { + PRINT_D(INIT_DBG, "Frame registering Type: %x - Reg: %d\n", nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + host_int_frame_register(priv->hWILCWFIDrv, + nic->g_struct_frame_reg[i].frame_type, + nic->g_struct_frame_reg[i].reg); + } + } + break; + + default: + PRINT_ER("Unknown interface type= %d\n", type); + return -EINVAL; + } + + return 0; +} + +/* (austin.2013-07-23) + * + * To support revised cfg80211_ops + * + * add_beacon --> start_ap + * set_beacon --> change_beacon + * del_beacon --> stop_ap + * + * beacon_parameters --> cfg80211_ap_settings + * cfg80211_beacon_data + * + * applicable for linux kernel 3.4+ + */ + +/** + * @brief start_ap + * @details Add a beacon with given parameters, @head, @interval + * and @dtim_period will be valid, @tail is optional. + * @param[in] wiphy + * @param[in] dev The net device structure + * @param[in] settings cfg80211_ap_settings parameters for the beacon to be added + * @return int : Return 0 on Success. + * @author austin + * @date 23 JUL 2013 + * @version 1.0 + */ +static int start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + struct cfg80211_beacon_data *beacon = &(settings->beacon); + struct wilc_priv *priv; + s32 s32Error = 0; + struct wilc *wl; + perInterface_wlan_t *nic; + + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + wl = nic->wilc; + PRINT_D(HOSTAPD_DBG, "Starting ap\n"); + + PRINT_D(HOSTAPD_DBG, "Interval = %d\n DTIM period = %d\n Head length = %zu Tail length = %zu\n", + settings->beacon_interval, settings->dtim_period, beacon->head_len, beacon->tail_len); + + s32Error = set_channel(wiphy, &settings->chandef); + + if (s32Error != 0) + PRINT_ER("Error in setting channel\n"); + + linux_wlan_set_bssid(dev, wl->vif[0].src_addr); + + s32Error = host_int_add_beacon(priv->hWILCWFIDrv, + settings->beacon_interval, + settings->dtim_period, + beacon->head_len, (u8 *)beacon->head, + beacon->tail_len, (u8 *)beacon->tail); + + return s32Error; +} + +/** + * @brief change_beacon + * @details Add a beacon with given parameters, @head, @interval + * and @dtim_period will be valid, @tail is optional. + * @param[in] wiphy + * @param[in] dev The net device structure + * @param[in] beacon cfg80211_beacon_data for the beacon to be changed + * @return int : Return 0 on Success. + * @author austin + * @date 23 JUL 2013 + * @version 1.0 + */ +static int change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *beacon) +{ + struct wilc_priv *priv; + s32 s32Error = 0; + + priv = wiphy_priv(wiphy); + PRINT_D(HOSTAPD_DBG, "Setting beacon\n"); + + + s32Error = host_int_add_beacon(priv->hWILCWFIDrv, + 0, + 0, + beacon->head_len, (u8 *)beacon->head, + beacon->tail_len, (u8 *)beacon->tail); + + return s32Error; +} + +/** + * @brief stop_ap + * @details Remove beacon configuration and stop sending the beacon. + * @param[in] + * @return int : Return 0 on Success. + * @author austin + * @date 23 JUL 2013 + * @version 1.0 + */ +static int stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + s32 s32Error = 0; + struct wilc_priv *priv; + u8 NullBssid[ETH_ALEN] = {0}; + + if (!wiphy) + return -EFAULT; + + priv = wiphy_priv(wiphy); + + PRINT_D(HOSTAPD_DBG, "Deleting beacon\n"); + + linux_wlan_set_bssid(dev, NullBssid); + + s32Error = host_int_del_beacon(priv->hWILCWFIDrv); + + if (s32Error) + PRINT_ER("Host delete beacon fail\n"); + + return s32Error; +} + +/** + * @brief add_station + * @details Add a new station. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int add_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + s32 s32Error = 0; + struct wilc_priv *priv; + struct add_sta_param strStaParams = { {0} }; + perInterface_wlan_t *nic; + + if (!wiphy) + return -EFAULT; + + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + memcpy(strStaParams.au8BSSID, mac, ETH_ALEN); + memcpy(priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid], mac, ETH_ALEN); + strStaParams.u16AssocID = params->aid; + strStaParams.u8NumRates = params->supported_rates_len; + strStaParams.pu8Rates = params->supported_rates; + + PRINT_D(CFG80211_DBG, "Adding station parameters %d\n", params->aid); + + PRINT_D(CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][0], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][1], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][2], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][3], priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][4], + priv->assoc_stainfo.au8Sta_AssociatedBss[params->aid][5]); + PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.u16AssocID); + PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n", strStaParams.u8NumRates); + + if (params->ht_capa == NULL) { + strStaParams.bIsHTSupported = false; + } else { + strStaParams.bIsHTSupported = true; + strStaParams.u16HTCapInfo = params->ht_capa->cap_info; + strStaParams.u8AmpduParams = params->ht_capa->ampdu_params_info; + memcpy(strStaParams.au8SuppMCsSet, ¶ms->ht_capa->mcs, WILC_SUPP_MCS_SET_SIZE); + strStaParams.u16HTExtParams = params->ht_capa->extended_ht_cap_info; + strStaParams.u32TxBeamformingCap = params->ht_capa->tx_BF_cap_info; + strStaParams.u8ASELCap = params->ht_capa->antenna_selection_info; + } + + strStaParams.u16FlagsMask = params->sta_flags_mask; + strStaParams.u16FlagsSet = params->sta_flags_set; + + PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n", strStaParams.bIsHTSupported); + PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n", strStaParams.u16HTCapInfo); + PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n", strStaParams.u8AmpduParams); + PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n", strStaParams.u16HTExtParams); + PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n", strStaParams.u32TxBeamformingCap); + PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n", strStaParams.u8ASELCap); + PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n", strStaParams.u16FlagsMask); + PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n", strStaParams.u16FlagsSet); + + s32Error = host_int_add_station(priv->hWILCWFIDrv, &strStaParams); + if (s32Error) + PRINT_ER("Host add station fail\n"); + } + + return s32Error; +} + +/** + * @brief del_station + * @details Remove a station; @mac may be NULL to remove all stations. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int del_station(struct wiphy *wiphy, struct net_device *dev, + struct station_del_parameters *params) +{ + const u8 *mac = params->mac; + s32 s32Error = 0; + struct wilc_priv *priv; + perInterface_wlan_t *nic; + + if (!wiphy) + return -EFAULT; + + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + PRINT_D(HOSTAPD_DBG, "Deleting station\n"); + + + if (mac == NULL) { + PRINT_D(HOSTAPD_DBG, "All associated stations\n"); + s32Error = host_int_del_allstation(priv->hWILCWFIDrv, priv->assoc_stainfo.au8Sta_AssociatedBss); + } else { + PRINT_D(HOSTAPD_DBG, "With mac address: %x%x%x%x%x%x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + } + + s32Error = host_int_del_station(priv->hWILCWFIDrv, mac); + + if (s32Error) + PRINT_ER("Host delete station fail\n"); + } + return s32Error; +} + +/** + * @brief change_station + * @details Modify a given station. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +static int change_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + s32 s32Error = 0; + struct wilc_priv *priv; + struct add_sta_param strStaParams = { {0} }; + perInterface_wlan_t *nic; + + + PRINT_D(HOSTAPD_DBG, "Change station paramters\n"); + + if (!wiphy) + return -EFAULT; + + priv = wiphy_priv(wiphy); + nic = netdev_priv(dev); + + if (nic->iftype == AP_MODE || nic->iftype == GO_MODE) { + memcpy(strStaParams.au8BSSID, mac, ETH_ALEN); + strStaParams.u16AssocID = params->aid; + strStaParams.u8NumRates = params->supported_rates_len; + strStaParams.pu8Rates = params->supported_rates; + + PRINT_D(HOSTAPD_DBG, "BSSID = %x%x%x%x%x%x\n", strStaParams.au8BSSID[0], strStaParams.au8BSSID[1], strStaParams.au8BSSID[2], strStaParams.au8BSSID[3], strStaParams.au8BSSID[4], + strStaParams.au8BSSID[5]); + PRINT_D(HOSTAPD_DBG, "ASSOC ID = %d\n", strStaParams.u16AssocID); + PRINT_D(HOSTAPD_DBG, "Number of supported rates = %d\n", strStaParams.u8NumRates); + + if (params->ht_capa == NULL) { + strStaParams.bIsHTSupported = false; + } else { + strStaParams.bIsHTSupported = true; + strStaParams.u16HTCapInfo = params->ht_capa->cap_info; + strStaParams.u8AmpduParams = params->ht_capa->ampdu_params_info; + memcpy(strStaParams.au8SuppMCsSet, ¶ms->ht_capa->mcs, WILC_SUPP_MCS_SET_SIZE); + strStaParams.u16HTExtParams = params->ht_capa->extended_ht_cap_info; + strStaParams.u32TxBeamformingCap = params->ht_capa->tx_BF_cap_info; + strStaParams.u8ASELCap = params->ht_capa->antenna_selection_info; + + } + + strStaParams.u16FlagsMask = params->sta_flags_mask; + strStaParams.u16FlagsSet = params->sta_flags_set; + + PRINT_D(HOSTAPD_DBG, "IS HT supported = %d\n", strStaParams.bIsHTSupported); + PRINT_D(HOSTAPD_DBG, "Capability Info = %d\n", strStaParams.u16HTCapInfo); + PRINT_D(HOSTAPD_DBG, "AMPDU Params = %d\n", strStaParams.u8AmpduParams); + PRINT_D(HOSTAPD_DBG, "HT Extended params = %d\n", strStaParams.u16HTExtParams); + PRINT_D(HOSTAPD_DBG, "Tx Beamforming Cap = %d\n", strStaParams.u32TxBeamformingCap); + PRINT_D(HOSTAPD_DBG, "Antenna selection info = %d\n", strStaParams.u8ASELCap); + PRINT_D(HOSTAPD_DBG, "Flag Mask = %d\n", strStaParams.u16FlagsMask); + PRINT_D(HOSTAPD_DBG, "Flag Set = %d\n", strStaParams.u16FlagsSet); + + s32Error = host_int_edit_station(priv->hWILCWFIDrv, &strStaParams); + if (s32Error) + PRINT_ER("Host edit station fail\n"); + } + return s32Error; +} + + +/** + * @brief add_virtual_intf + * @details + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 JUL 2012 + * @version 1.0 + */ +static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + perInterface_wlan_t *nic; + struct wilc_priv *priv; + struct net_device *new_ifc = NULL; + + priv = wiphy_priv(wiphy); + + + + PRINT_D(HOSTAPD_DBG, "Adding monitor interface[%p]\n", priv->wdev->netdev); + + nic = netdev_priv(priv->wdev->netdev); + + + if (type == NL80211_IFTYPE_MONITOR) { + PRINT_D(HOSTAPD_DBG, "Monitor interface mode: Initializing mon interface virtual device driver\n"); + PRINT_D(HOSTAPD_DBG, "Adding monitor interface[%p]\n", nic->wilc_netdev); + new_ifc = WILC_WFI_init_mon_interface(name, nic->wilc_netdev); + if (new_ifc != NULL) { + PRINT_D(HOSTAPD_DBG, "Setting monitor flag in private structure\n"); + nic = netdev_priv(priv->wdev->netdev); + nic->monitor_flag = 1; + } else + PRINT_ER("Error in initializing monitor interface\n "); + } + return priv->wdev; +} + +/** + * @brief del_virtual_intf + * @details + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 JUL 2012 + * @version 1.0 + */ +static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + PRINT_D(HOSTAPD_DBG, "Deleting virtual interface\n"); + return 0; +} + +static struct cfg80211_ops wilc_cfg80211_ops = { + + .set_monitor_channel = set_channel, + .scan = scan, + .connect = connect, + .disconnect = disconnect, + .add_key = add_key, + .del_key = del_key, + .get_key = get_key, + .set_default_key = set_default_key, + .add_virtual_intf = add_virtual_intf, + .del_virtual_intf = del_virtual_intf, + .change_virtual_intf = change_virtual_intf, + + .start_ap = start_ap, + .change_beacon = change_beacon, + .stop_ap = stop_ap, + .add_station = add_station, + .del_station = del_station, + .change_station = change_station, + .get_station = get_station, + .dump_station = dump_station, + .change_bss = change_bss, + .set_wiphy_params = set_wiphy_params, + + .set_pmksa = set_pmksa, + .del_pmksa = del_pmksa, + .flush_pmksa = flush_pmksa, + .remain_on_channel = remain_on_channel, + .cancel_remain_on_channel = cancel_remain_on_channel, + .mgmt_tx_cancel_wait = mgmt_tx_cancel_wait, + .mgmt_tx = mgmt_tx, + .mgmt_frame_register = wilc_mgmt_frame_register, + .set_power_mgmt = set_power_mgmt, + .set_cqm_rssi_config = set_cqm_rssi_config, + +}; + + + + + +/** + * @brief WILC_WFI_update_stats + * @details Modify parameters for a given BSS. + * @param[in] + * @return int : Return 0 on Success. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int WILC_WFI_update_stats(struct wiphy *wiphy, u32 pktlen, u8 changed) +{ + + struct wilc_priv *priv; + + priv = wiphy_priv(wiphy); + switch (changed) { + + case WILC_WFI_RX_PKT: + { + priv->netstats.rx_packets++; + priv->netstats.rx_bytes += pktlen; + priv->netstats.rx_time = get_jiffies_64(); + } + break; + + case WILC_WFI_TX_PKT: + { + priv->netstats.tx_packets++; + priv->netstats.tx_bytes += pktlen; + priv->netstats.tx_time = get_jiffies_64(); + + } + break; + + default: + break; + } + return 0; +} + +/** + * @brief WILC_WFI_CfgAlloc + * @details Allocation of the wireless device structure and assigning it + * to the cfg80211 operations structure. + * @param[in] NONE + * @return wireless_dev : Returns pointer to wireless_dev structure. + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +struct wireless_dev *WILC_WFI_CfgAlloc(void) +{ + + struct wireless_dev *wdev; + + + PRINT_D(CFG80211_DBG, "Allocating wireless device\n"); + /*Allocating the wireless device structure*/ + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + PRINT_ER("Cannot allocate wireless device\n"); + goto _fail_; + } + + /*Creating a new wiphy, linking wireless structure with the wiphy structure*/ + wdev->wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc_priv)); + if (!wdev->wiphy) { + PRINT_ER("Cannot allocate wiphy\n"); + goto _fail_mem_; + + } + + /* enable 802.11n HT */ + WILC_WFI_band_2ghz.ht_cap.ht_supported = 1; + WILC_WFI_band_2ghz.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + WILC_WFI_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; + WILC_WFI_band_2ghz.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; + WILC_WFI_band_2ghz.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + + /*wiphy bands*/ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &WILC_WFI_band_2ghz; + + return wdev; + +_fail_mem_: + kfree(wdev); +_fail_: + return NULL; + +} +/** + * @brief wilc_create_wiphy + * @details Registering of the wiphy structure and interface modes + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +struct wireless_dev *wilc_create_wiphy(struct net_device *net) +{ + struct wilc_priv *priv; + struct wireless_dev *wdev; + s32 s32Error = 0; + + PRINT_D(CFG80211_DBG, "Registering wifi device\n"); + + wdev = WILC_WFI_CfgAlloc(); + if (wdev == NULL) { + PRINT_ER("CfgAlloc Failed\n"); + return NULL; + } + + + /*Return hardware description structure (wiphy)'s priv*/ + priv = wdev_priv(wdev); + sema_init(&(priv->SemHandleUpdateStats), 1); + + /*Link the wiphy with wireless structure*/ + priv->wdev = wdev; + + /*Maximum number of probed ssid to be added by user for the scan request*/ + wdev->wiphy->max_scan_ssids = MAX_NUM_PROBED_SSID; + /*Maximum number of pmkids to be cashed*/ + wdev->wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS; + PRINT_INFO(CFG80211_DBG, "Max number of PMKIDs = %d\n", wdev->wiphy->max_num_pmkids); + + wdev->wiphy->max_scan_ie_len = 1000; + + /*signal strength in mBm (100*dBm) */ + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /*Set the availaible cipher suites*/ + wdev->wiphy->cipher_suites = cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + /*Setting default managment types: for register action frame: */ + wdev->wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types; + + wdev->wiphy->max_remain_on_channel_duration = 500; + /*Setting the wiphy interfcae mode and type before registering the wiphy*/ + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) | BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); + wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + wdev->iftype = NL80211_IFTYPE_STATION; + + + + PRINT_INFO(CFG80211_DBG, "Max scan ids = %d,Max scan IE len = %d,Signal Type = %d,Interface Modes = %d,Interface Type = %d\n", + wdev->wiphy->max_scan_ssids, wdev->wiphy->max_scan_ie_len, wdev->wiphy->signal_type, + wdev->wiphy->interface_modes, wdev->iftype); + + #ifdef WILC_SDIO + set_wiphy_dev(wdev->wiphy, &local_sdio_func->dev); + #endif + + /*Register wiphy structure*/ + s32Error = wiphy_register(wdev->wiphy); + if (s32Error) { + PRINT_ER("Cannot register wiphy device\n"); + /*should define what action to be taken in such failure*/ + } else { + PRINT_D(CFG80211_DBG, "Successful Registering\n"); + } + + priv->dev = net; + return wdev; + + +} +/** + * @brief WILC_WFI_WiphyFree + * @details Freeing allocation of the wireless device structure + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int wilc_init_host_int(struct net_device *net) +{ + + int s32Error = 0; + + struct wilc_priv *priv; + + PRINT_D(INIT_DBG, "Host[%p][%p]\n", net, net->ieee80211_ptr); + priv = wdev_priv(net->ieee80211_ptr); + if (op_ifcs == 0) { + setup_timer(&hAgingTimer, remove_network_from_shadow, 0); + setup_timer(&hDuringIpTimer, clear_duringIP, 0); + } + op_ifcs++; + if (s32Error < 0) { + PRINT_ER("Failed to creat refresh Timer\n"); + return s32Error; + } + + priv->gbAutoRateAdjusted = false; + + priv->bInP2PlistenState = false; + + sema_init(&(priv->hSemScanReq), 1); + s32Error = host_int_init(net, &priv->hWILCWFIDrv); + if (s32Error) + PRINT_ER("Error while initializing hostinterface\n"); + + return s32Error; +} + +/** + * @brief WILC_WFI_WiphyFree + * @details Freeing allocation of the wireless device structure + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +int wilc_deinit_host_int(struct net_device *net) +{ + int s32Error = 0; + + struct wilc_priv *priv; + + priv = wdev_priv(net->ieee80211_ptr); + + priv->gbAutoRateAdjusted = false; + + priv->bInP2PlistenState = false; + + op_ifcs--; + + s32Error = host_int_deinit(priv->hWILCWFIDrv); + + /* Clear the Shadow scan */ + clear_shadow_scan(priv); + if (op_ifcs == 0) { + PRINT_D(CORECONFIG_DBG, "destroy during ip\n"); + del_timer_sync(&hDuringIpTimer); + } + + if (s32Error) + PRINT_ER("Error while deintializing host interface\n"); + + return s32Error; +} + + +/** + * @brief WILC_WFI_WiphyFree + * @details Freeing allocation of the wireless device structure + * @param[in] NONE + * @return NONE + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +void wilc_free_wiphy(struct net_device *net) +{ + PRINT_D(CFG80211_DBG, "Unregistering wiphy\n"); + + if (!net) { + PRINT_D(INIT_DBG, "net_device is NULL\n"); + return; + } + + if (!net->ieee80211_ptr) { + PRINT_D(INIT_DBG, "ieee80211_ptr is NULL\n"); + return; + } + + if (!net->ieee80211_ptr->wiphy) { + PRINT_D(INIT_DBG, "wiphy is NULL\n"); + return; + } + + wiphy_unregister(net->ieee80211_ptr->wiphy); + + PRINT_D(INIT_DBG, "Freeing wiphy\n"); + wiphy_free(net->ieee80211_ptr->wiphy); + kfree(net->ieee80211_ptr); +} diff --git a/kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h b/kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h new file mode 100644 index 000000000..39cd8e1b5 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h @@ -0,0 +1,109 @@ +/*! + * @file wilc_wfi_cfgoperations.h + * @brief Definitions for the network module + * @author syounan + * @sa wilc_oswrapper.h top level OS wrapper file + * @date 31 Aug 2010 + * @version 1.0 + */ +#ifndef NM_WFI_CFGOPERATIONS +#define NM_WFI_CFGOPERATIONS +#include "wilc_wfi_netdevice.h" + +/* The following macros describe the bitfield map used by the firmware to determine its 11i mode */ +#define NO_ENCRYPT 0 +#define ENCRYPT_ENABLED BIT(0) +#define WEP BIT(1) +#define WEP_EXTENDED BIT(2) +#define WPA BIT(3) +#define WPA2 BIT(4) +#define AES BIT(5) +#define TKIP BIT(6) + +/*Public action frame index IDs*/ +#define FRAME_TYPE_ID 0 +#define ACTION_CAT_ID 24 +#define ACTION_SUBTYPE_ID 25 +#define P2P_PUB_ACTION_SUBTYPE 30 + +/*Public action frame Attribute IDs*/ +#define ACTION_FRAME 0xd0 +#define GO_INTENT_ATTR_ID 0x04 +#define CHANLIST_ATTR_ID 0x0b +#define OPERCHAN_ATTR_ID 0x11 +#define PUB_ACTION_ATTR_ID 0x04 +#define P2PELEM_ATTR_ID 0xdd + +/*Public action subtype values*/ +#define GO_NEG_REQ 0x00 +#define GO_NEG_RSP 0x01 +#define GO_NEG_CONF 0x02 +#define P2P_INV_REQ 0x03 +#define P2P_INV_RSP 0x04 +#define PUBLIC_ACT_VENDORSPEC 0x09 +#define GAS_INTIAL_REQ 0x0a +#define GAS_INTIAL_RSP 0x0b + +#define INVALID_CHANNEL 0 + +#define nl80211_SCAN_RESULT_EXPIRE (3 * HZ) +#define SCAN_RESULT_EXPIRE (40 * HZ) + +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +static const struct ieee80211_txrx_stypes + wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) + } +}; + +/* Time to stay on the channel */ +#define WILC_WFI_DWELL_PASSIVE 100 +#define WILC_WFI_DWELL_ACTIVE 40 + +struct wireless_dev *WILC_WFI_CfgAlloc(void); +struct wireless_dev *wilc_create_wiphy(struct net_device *net); +void wilc_free_wiphy(struct net_device *net); +int WILC_WFI_update_stats(struct wiphy *wiphy, u32 pktlen, u8 changed); +int wilc_deinit_host_int(struct net_device *net); +int wilc_init_host_int(struct net_device *net); +void WILC_WFI_monitor_rx(u8 *buff, u32 size); +int WILC_WFI_deinit_mon_interface(void); +struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev); +void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, + u16 frame_type, bool reg); + +#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54 +#define DEFAULT_LINK_SPEED 72 +void Enable_TCP_ACK_Filter(bool value); + +#endif diff --git a/kernel/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/kernel/drivers/staging/wilc1000/wilc_wfi_netdevice.h new file mode 100644 index 000000000..0bfe7626a --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -0,0 +1,221 @@ +/*! + * @file wilc_wfi_netdevice.h + * @brief Definitions for the network module + * @author mdaftedar + * @date 01 MAR 2012 + * @version 1.0 + */ +#ifndef WILC_WFI_NETDEVICE +#define WILC_WFI_NETDEVICE + +#define WILC_WFI_RX_INTR 0x0001 +#define WILC_WFI_TX_INTR 0x0002 + +#define WILC_WFI_TIMEOUT 5 +#define WILC_MAX_NUM_PMKIDS 16 +#define PMKID_LEN 16 +#define PMKID_FOUND 1 + #define NUM_STA_ASSOCIATED 8 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "host_interface.h" +#include "wilc_wlan.h" +#include + +#define FLOW_CONTROL_LOWER_THRESHOLD 128 +#define FLOW_CONTROL_UPPER_THRESHOLD 256 + +enum stats_flags { + WILC_WFI_RX_PKT = BIT(0), + WILC_WFI_TX_PKT = BIT(1), +}; + +struct WILC_WFI_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + u64 rx_time; + u64 tx_time; + +}; + +/* + * This structure is private to each device. It is used to pass + * packets in and out, so there is place for a packet + */ + +#define num_reg_frame 2 + +struct wilc_wfi_key { + u8 *key; + u8 *seq; + int key_len; + int seq_len; + u32 cipher; +}; + +struct wilc_wfi_wep_key { + u8 *key; + u8 key_len; + u8 key_idx; +}; + +struct sta_info { + u8 au8Sta_AssociatedBss[MAX_NUM_STA][ETH_ALEN]; +}; + +/*Parameters needed for host interface for remaining on channel*/ +struct wilc_wfi_p2pListenParams { + struct ieee80211_channel *pstrListenChan; + enum nl80211_channel_type tenuChannelType; + u32 u32ListenDuration; + u64 u64ListenCookie; + u32 u32ListenSessionID; +}; + +struct wilc_priv { + struct wireless_dev *wdev; + struct cfg80211_scan_request *pstrScanReq; + + struct wilc_wfi_p2pListenParams strRemainOnChanParams; + u64 u64tx_cookie; + + bool bCfgScanning; + u32 u32RcvdChCount; + + u8 au8AssociatedBss[ETH_ALEN]; + struct sta_info assoc_stainfo; + struct net_device_stats stats; + u8 monitor_flag; + int status; + struct WILC_WFI_packet *ppool; + struct WILC_WFI_packet *rx_queue; /* List of incoming packets */ + int rx_int_enabled; + int tx_packetlen; + u8 *tx_packetdata; + struct sk_buff *skb; + spinlock_t lock; + struct net_device *dev; + struct napi_struct napi; + struct host_if_drv *hWILCWFIDrv; + struct host_if_pmkid_attr pmkid_list; + struct WILC_WFI_stats netstats; + u8 WILC_WFI_wep_default; + u8 WILC_WFI_wep_key[4][WLAN_KEY_LEN_WEP104]; + u8 WILC_WFI_wep_key_len[4]; + /* The real interface that the monitor is on */ + struct net_device *real_ndev; + struct wilc_wfi_key *wilc_gtk[MAX_NUM_STA]; + struct wilc_wfi_key *wilc_ptk[MAX_NUM_STA]; + u8 wilc_groupkey; + /* semaphores */ + struct semaphore SemHandleUpdateStats; + struct semaphore hSemScanReq; + /* */ + bool gbAutoRateAdjusted; + + bool bInP2PlistenState; + +}; + +typedef struct { + u16 frame_type; + bool reg; + +} struct_frame_reg; + +struct wilc_vif { + u8 src_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + struct host_if_drv *hif_drv; + struct net_device *ndev; +}; + +struct wilc { + int mac_status; + bool initialized; + #if (!defined WILC_SDIO) || (defined WILC_SDIO_IRQ_GPIO) + unsigned short dev_irq_num; + #endif + int close; + u8 vif_num; + struct wilc_vif vif[NUM_CONCURRENT_IFC]; + u8 open_ifcs; + + struct semaphore txq_add_to_head_cs; + spinlock_t txq_spinlock; + + struct mutex rxq_cs; + struct mutex hif_cs; + + struct semaphore cfg_event; + struct semaphore sync_event; + struct semaphore txq_event; + + struct semaphore txq_thread_started; + + struct task_struct *txq_thread; + + unsigned char eth_src_address[NUM_CONCURRENT_IFC][6]; + + const struct firmware *firmware; + +#ifdef WILC_SDIO + struct sdio_func *wilc_sdio_func; +#else + struct spi_device *wilc_spidev; +#endif +}; + +typedef struct { + u8 u8IfIdx; + u8 iftype; + int monitor_flag; + int mac_opened; + struct_frame_reg g_struct_frame_reg[num_reg_frame]; + struct net_device *wilc_netdev; + struct net_device_stats netstats; + struct wilc *wilc; +} perInterface_wlan_t; + +struct WILC_WFI_mon_priv { + struct net_device *real_ndev; +}; + +extern struct wilc *g_linux_wlan; +extern struct net_device *WILC_WFI_devs[]; +void frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset); +void linux_wlan_mac_indicate(struct wilc *wilc, int flag); +void linux_wlan_rx_complete(void); +void linux_wlan_dbg(u8 *buff); +int linux_wlan_lock_timeout(void *vp, u32 timeout); +void wl_wlan_cleanup(void); +int wilc_netdev_init(struct wilc **wilc); +void wilc1000_wlan_deinit(struct net_device *dev); +void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size); +u16 Set_machw_change_vir_if(struct net_device *dev, bool bValue); +#endif diff --git a/kernel/drivers/staging/wilc1000/wilc_wlan.c b/kernel/drivers/staging/wilc1000/wilc_wlan.c new file mode 100644 index 000000000..c02665747 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wlan.c @@ -0,0 +1,2070 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan.c */ +/* */ +/* */ +/* //////////////////////////////////////////////////////////////////////////// */ + +#include "wilc_wlan_if.h" +#include "wilc_wfi_netdevice.h" +#include "wilc_wlan_cfg.h" + +/******************************************** + * + * Global + * + ********************************************/ +extern wilc_hif_func_t hif_sdio; +extern wilc_hif_func_t hif_spi; +u32 wilc_get_chipid(u8 update); + + + +typedef struct { + int quit; + + /** + * input interface functions + **/ + wilc_wlan_io_func_t io_func; + + /** + * host interface functions + **/ + wilc_hif_func_t hif_func; + + /** + * configuration interface functions + **/ + int cfg_frame_in_use; + wilc_cfg_frame_t cfg_frame; + u32 cfg_frame_offset; + int cfg_seq_no; + + /** + * RX buffer + **/ + #ifdef MEMORY_STATIC + u8 *rx_buffer; + u32 rx_buffer_offset; + #endif + /** + * TX buffer + **/ + u8 *tx_buffer; + u32 tx_buffer_offset; + + /** + * TX queue + **/ + + unsigned long txq_spinlock_flags; + + struct txq_entry_t *txq_head; + struct txq_entry_t *txq_tail; + int txq_entries; + int txq_exit; + + /** + * RX queue + **/ + struct rxq_entry_t *rxq_head; + struct rxq_entry_t *rxq_tail; + int rxq_entries; + int rxq_exit; + + +} wilc_wlan_dev_t; + +static wilc_wlan_dev_t g_wlan; + +static inline void chip_allow_sleep(void); +static inline void chip_wakeup(void); +/******************************************** + * + * Debug + * + ********************************************/ + +static u32 dbgflag = N_INIT | N_ERR | N_INTR | N_TXQ | N_RXQ; + +static void wilc_debug(u32 flag, char *fmt, ...) +{ + char buf[256]; + va_list args; + + if (flag & dbgflag) { + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + linux_wlan_dbg(buf); + } +} + +static CHIP_PS_STATE_T genuChipPSstate = CHIP_WAKEDUP; + +/*acquire_bus() and release_bus() are made static inline functions*/ +/*as a temporary workaround to fix a problem of receiving*/ +/*unknown interrupt from FW*/ +static inline void acquire_bus(BUS_ACQUIRE_T acquire) +{ + + mutex_lock(&g_linux_wlan->hif_cs); + #ifndef WILC_OPTIMIZE_SLEEP_INT + if (genuChipPSstate != CHIP_WAKEDUP) + #endif + { + if (acquire == ACQUIRE_AND_WAKEUP) + chip_wakeup(); + } + +} +static inline void release_bus(BUS_RELEASE_T release) +{ + #ifdef WILC_OPTIMIZE_SLEEP_INT + if (release == RELEASE_ALLOW_SLEEP) + chip_allow_sleep(); + #endif + mutex_unlock(&g_linux_wlan->hif_cs); +} +/******************************************** + * + * Queue + * + ********************************************/ + +static void wilc_wlan_txq_remove(struct txq_entry_t *tqe) +{ + + wilc_wlan_dev_t *p = &g_wlan; + if (tqe == p->txq_head) { + + p->txq_head = tqe->next; + if (p->txq_head) + p->txq_head->prev = NULL; + + + } else if (tqe == p->txq_tail) { + p->txq_tail = (tqe->prev); + if (p->txq_tail) + p->txq_tail->next = NULL; + } else { + tqe->prev->next = tqe->next; + tqe->next->prev = tqe->prev; + } + p->txq_entries -= 1; + +} + +static struct txq_entry_t *wilc_wlan_txq_remove_from_head(void) +{ + struct txq_entry_t *tqe; + wilc_wlan_dev_t *p = &g_wlan; + unsigned long flags; + + spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags); + if (p->txq_head) { + tqe = p->txq_head; + p->txq_head = tqe->next; + if (p->txq_head) + p->txq_head->prev = NULL; + + p->txq_entries -= 1; + + + + + } else { + tqe = NULL; + } + spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags); + return tqe; +} + +static void wilc_wlan_txq_add_to_tail(struct txq_entry_t *tqe) +{ + wilc_wlan_dev_t *p = &g_wlan; + unsigned long flags; + spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags); + + if (p->txq_head == NULL) { + tqe->next = NULL; + tqe->prev = NULL; + p->txq_head = tqe; + p->txq_tail = tqe; + } else { + tqe->next = NULL; + tqe->prev = p->txq_tail; + p->txq_tail->next = tqe; + p->txq_tail = tqe; + } + p->txq_entries += 1; + PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries); + + spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags); + + /** + * wake up TX queue + **/ + PRINT_D(TX_DBG, "Wake the txq_handling\n"); + + up(&g_linux_wlan->txq_event); +} + +static int wilc_wlan_txq_add_to_head(struct txq_entry_t *tqe) +{ + wilc_wlan_dev_t *p = &g_wlan; + unsigned long flags; + if (linux_wlan_lock_timeout(&g_linux_wlan->txq_add_to_head_cs, + CFG_PKTS_TIMEOUT)) + return -1; + + spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags); + + if (p->txq_head == NULL) { + tqe->next = NULL; + tqe->prev = NULL; + p->txq_head = tqe; + p->txq_tail = tqe; + } else { + tqe->next = p->txq_head; + tqe->prev = NULL; + p->txq_head->prev = tqe; + p->txq_head = tqe; + } + p->txq_entries += 1; + PRINT_D(TX_DBG, "Number of entries in TxQ = %d\n", p->txq_entries); + + spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags); + up(&g_linux_wlan->txq_add_to_head_cs); + + + /** + * wake up TX queue + **/ + up(&g_linux_wlan->txq_event); + PRINT_D(TX_DBG, "Wake up the txq_handler\n"); + + return 0; + +} + +u32 Statisitcs_totalAcks = 0, Statisitcs_DroppedAcks = 0; + +#ifdef TCP_ACK_FILTER +struct Ack_session_info; +struct Ack_session_info { + u32 Ack_seq_num; + u32 Bigger_Ack_num; + u16 src_port; + u16 dst_port; + u16 status; +}; + +typedef struct { + u32 ack_num; + u32 Session_index; + struct txq_entry_t *txqe; +} Pending_Acks_info_t /*Ack_info_t*/; + + + + +struct Ack_session_info *Free_head; +struct Ack_session_info *Alloc_head; + +#define NOT_TCP_ACK (-1) + +#define MAX_TCP_SESSION 25 +#define MAX_PENDING_ACKS 256 +struct Ack_session_info Acks_keep_track_info[2 * MAX_TCP_SESSION]; +Pending_Acks_info_t Pending_Acks_info[MAX_PENDING_ACKS]; + +u32 PendingAcks_arrBase; +u32 Opened_TCP_session; +u32 Pending_Acks; + + + +static inline int Init_TCP_tracking(void) +{ + + return 0; + +} +static inline int add_TCP_track_session(u32 src_prt, u32 dst_prt, u32 seq) +{ + Acks_keep_track_info[Opened_TCP_session].Ack_seq_num = seq; + Acks_keep_track_info[Opened_TCP_session].Bigger_Ack_num = 0; + Acks_keep_track_info[Opened_TCP_session].src_port = src_prt; + Acks_keep_track_info[Opened_TCP_session].dst_port = dst_prt; + Opened_TCP_session++; + + PRINT_D(TCP_ENH, "TCP Session %d to Ack %d\n", Opened_TCP_session, seq); + return 0; +} + +static inline int Update_TCP_track_session(u32 index, u32 Ack) +{ + + if (Ack > Acks_keep_track_info[index].Bigger_Ack_num) + Acks_keep_track_info[index].Bigger_Ack_num = Ack; + return 0; + +} +static inline int add_TCP_Pending_Ack(u32 Ack, u32 Session_index, struct txq_entry_t *txqe) +{ + Statisitcs_totalAcks++; + if (Pending_Acks < MAX_PENDING_ACKS) { + Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].ack_num = Ack; + Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].txqe = txqe; + Pending_Acks_info[PendingAcks_arrBase + Pending_Acks].Session_index = Session_index; + txqe->tcp_PendingAck_index = PendingAcks_arrBase + Pending_Acks; + Pending_Acks++; + + } else { + + } + return 0; +} +static inline int remove_TCP_related(void) +{ + wilc_wlan_dev_t *p = &g_wlan; + unsigned long flags; + + spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags); + + spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags); + return 0; +} + +static inline int tcp_process(struct net_device *dev, struct txq_entry_t *tqe) +{ + int ret; + u8 *eth_hdr_ptr; + u8 *buffer = tqe->buffer; + unsigned short h_proto; + int i; + wilc_wlan_dev_t *p = &g_wlan; + unsigned long flags; + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + eth_hdr_ptr = &buffer[0]; + h_proto = ntohs(*((unsigned short *)ð_hdr_ptr[12])); + if (h_proto == 0x0800) { /* IP */ + u8 *ip_hdr_ptr; + u8 protocol; + + ip_hdr_ptr = &buffer[ETHERNET_HDR_LEN]; + protocol = ip_hdr_ptr[9]; + + + if (protocol == 0x06) { + u8 *tcp_hdr_ptr; + u32 IHL, Total_Length, Data_offset; + + tcp_hdr_ptr = &ip_hdr_ptr[IP_HDR_LEN]; + IHL = (ip_hdr_ptr[0] & 0xf) << 2; + Total_Length = (((u32)ip_hdr_ptr[2]) << 8) + ((u32)ip_hdr_ptr[3]); + Data_offset = (((u32)tcp_hdr_ptr[12] & 0xf0) >> 2); + if (Total_Length == (IHL + Data_offset)) { /*we want to recognize the clear Acks(packet only carry Ack infos not with data) so data size must be equal zero*/ + u32 seq_no, Ack_no; + + seq_no = (((u32)tcp_hdr_ptr[4]) << 24) + (((u32)tcp_hdr_ptr[5]) << 16) + (((u32)tcp_hdr_ptr[6]) << 8) + ((u32)tcp_hdr_ptr[7]); + + Ack_no = (((u32)tcp_hdr_ptr[8]) << 24) + (((u32)tcp_hdr_ptr[9]) << 16) + (((u32)tcp_hdr_ptr[10]) << 8) + ((u32)tcp_hdr_ptr[11]); + + + for (i = 0; i < Opened_TCP_session; i++) { + if (Acks_keep_track_info[i].Ack_seq_num == seq_no) { + Update_TCP_track_session(i, Ack_no); + break; + } + } + if (i == Opened_TCP_session) + add_TCP_track_session(0, 0, seq_no); + + add_TCP_Pending_Ack(Ack_no, i, tqe); + + + } + + } else { + ret = 0; + } + } else { + ret = 0; + } + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + return ret; +} + + +static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) +{ + perInterface_wlan_t *nic; + struct wilc *wilc; + u32 i = 0; + u32 Dropped = 0; + wilc_wlan_dev_t *p = &g_wlan; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + spin_lock_irqsave(&wilc->txq_spinlock, p->txq_spinlock_flags); + for (i = PendingAcks_arrBase; i < (PendingAcks_arrBase + Pending_Acks); i++) { + if (Pending_Acks_info[i].ack_num < Acks_keep_track_info[Pending_Acks_info[i].Session_index].Bigger_Ack_num) { + struct txq_entry_t *tqe; + + PRINT_D(TCP_ENH, "DROP ACK: %u\n", Pending_Acks_info[i].ack_num); + tqe = Pending_Acks_info[i].txqe; + if (tqe) { + wilc_wlan_txq_remove(tqe); + Statisitcs_DroppedAcks++; + tqe->status = 1; /* mark the packet send */ + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, tqe->status); + kfree(tqe); + Dropped++; + } + } + } + Pending_Acks = 0; + Opened_TCP_session = 0; + + if (PendingAcks_arrBase == 0) + PendingAcks_arrBase = MAX_TCP_SESSION; + else + PendingAcks_arrBase = 0; + + + spin_unlock_irqrestore(&wilc->txq_spinlock, p->txq_spinlock_flags); + + while (Dropped > 0) { + /*consume the semaphore count of the removed packet*/ + linux_wlan_lock_timeout(&wilc->txq_event, 1); + Dropped--; + } + + return 1; +} +#endif + +bool EnableTCPAckFilter = false; + +void Enable_TCP_ACK_Filter(bool value) +{ + EnableTCPAckFilter = value; +} + +bool is_TCP_ACK_Filter_Enabled(void) +{ + return EnableTCPAckFilter; +} + +static int wilc_wlan_txq_add_cfg_pkt(u8 *buffer, u32 buffer_size) +{ + wilc_wlan_dev_t *p = &g_wlan; + struct txq_entry_t *tqe; + + PRINT_D(TX_DBG, "Adding config packet ...\n"); + if (p->quit) { + PRINT_D(TX_DBG, "Return due to clear function\n"); + up(&g_linux_wlan->cfg_event); + return 0; + } + + tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC); + if (tqe == NULL) { + PRINT_ER("Failed to allocate memory\n"); + return 0; + } + + tqe->type = WILC_CFG_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = NULL; + tqe->priv = NULL; +#ifdef TCP_ACK_FILTER + tqe->tcp_PendingAck_index = NOT_TCP_ACK; +#endif + /** + * Configuration packet always at the front + **/ + PRINT_D(TX_DBG, "Adding the config packet at the Queue tail\n"); + + if (wilc_wlan_txq_add_to_head(tqe)) + return 0; + return 1; +} + +int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, + u32 buffer_size, wilc_tx_complete_func_t func) +{ + wilc_wlan_dev_t *p = &g_wlan; + struct txq_entry_t *tqe; + + if (p->quit) + return 0; + + tqe = kmalloc(sizeof(struct txq_entry_t), GFP_ATOMIC); + + if (tqe == NULL) + return 0; + tqe->type = WILC_NET_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = func; + tqe->priv = priv; + + PRINT_D(TX_DBG, "Adding mgmt packet at the Queue tail\n"); +#ifdef TCP_ACK_FILTER + tqe->tcp_PendingAck_index = NOT_TCP_ACK; + if (is_TCP_ACK_Filter_Enabled()) + tcp_process(dev, tqe); +#endif + wilc_wlan_txq_add_to_tail(tqe); + /*return number of itemes in the queue*/ + return p->txq_entries; +} + +int wilc_wlan_txq_add_mgmt_pkt(void *priv, u8 *buffer, u32 buffer_size, wilc_tx_complete_func_t func) +{ + + wilc_wlan_dev_t *p = &g_wlan; + struct txq_entry_t *tqe; + + if (p->quit) + return 0; + + tqe = kmalloc(sizeof(struct txq_entry_t), GFP_KERNEL); + + if (tqe == NULL) + return 0; + tqe->type = WILC_MGMT_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = func; + tqe->priv = priv; +#ifdef TCP_ACK_FILTER + tqe->tcp_PendingAck_index = NOT_TCP_ACK; +#endif + PRINT_D(TX_DBG, "Adding Network packet at the Queue tail\n"); + wilc_wlan_txq_add_to_tail(tqe); + return 1; +} + +static struct txq_entry_t *wilc_wlan_txq_get_first(void) +{ + wilc_wlan_dev_t *p = &g_wlan; + struct txq_entry_t *tqe; + unsigned long flags; + + spin_lock_irqsave(&g_linux_wlan->txq_spinlock, flags); + + tqe = p->txq_head; + + spin_unlock_irqrestore(&g_linux_wlan->txq_spinlock, flags); + + + return tqe; +} + +static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc, + struct txq_entry_t *tqe) +{ + unsigned long flags; + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + tqe = tqe->next; + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + + + return tqe; +} + +static int wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe) +{ + wilc_wlan_dev_t *p = &g_wlan; + + if (p->quit) + return 0; + + mutex_lock(&wilc->rxq_cs); + if (p->rxq_head == NULL) { + PRINT_D(RX_DBG, "Add to Queue head\n"); + rqe->next = NULL; + p->rxq_head = rqe; + p->rxq_tail = rqe; + } else { + PRINT_D(RX_DBG, "Add to Queue tail\n"); + p->rxq_tail->next = rqe; + rqe->next = NULL; + p->rxq_tail = rqe; + } + p->rxq_entries += 1; + PRINT_D(RX_DBG, "Number of queue entries: %d\n", p->rxq_entries); + mutex_unlock(&wilc->rxq_cs); + return p->rxq_entries; +} + +static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc) +{ + wilc_wlan_dev_t *p = &g_wlan; + + PRINT_D(RX_DBG, "Getting rxQ element\n"); + if (p->rxq_head) { + struct rxq_entry_t *rqe; + + mutex_lock(&wilc->rxq_cs); + rqe = p->rxq_head; + p->rxq_head = p->rxq_head->next; + p->rxq_entries -= 1; + PRINT_D(RX_DBG, "RXQ entries decreased\n"); + mutex_unlock(&wilc->rxq_cs); + return rqe; + } + PRINT_D(RX_DBG, "Nothing to get from Q\n"); + return NULL; +} + + +/******************************************** + * + * Power Save handle functions + * + ********************************************/ + + + +#ifdef WILC_OPTIMIZE_SLEEP_INT + +static inline void chip_allow_sleep(void) +{ + u32 reg = 0; + + /* Clear bit 1 */ + g_wlan.hif_func.hif_read_reg(0xf0, ®); + + g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0)); +} + +static inline void chip_wakeup(void) +{ + u32 reg, clk_status_reg, trials = 0; + u32 sleep_time; + + if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) { + do { + g_wlan.hif_func.hif_read_reg(1, ®); + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(1, reg | BIT(1)); + + /* Clear bit 1*/ + g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1)); + + do { + /* Wait for the chip to stabilize*/ + usleep_range(2 * 1000, 2 * 1000); + /* Make sure chip is awake. This is an extra step that can be removed */ + /* later to avoid the bus access overhead */ + if ((wilc_get_chipid(true) == 0)) + wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n"); + + } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0)); + + } while (wilc_get_chipid(true) == 0); + } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) { + g_wlan.hif_func.hif_read_reg(0xf0, ®); + do { + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0)); + + /* Check the clock status */ + g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg); + + /* in case of clocks off, wait 2ms, and check it again. */ + /* if still off, wait for another 2ms, for a total wait of 6ms. */ + /* If still off, redo the wake up sequence */ + while (((clk_status_reg & 0x1) == 0) && (((++trials) % 3) == 0)) { + /* Wait for the chip to stabilize*/ + usleep_range(2 * 1000, 2 * 1000); + + /* Make sure chip is awake. This is an extra step that can be removed */ + /* later to avoid the bus access overhead */ + g_wlan.hif_func.hif_read_reg(0xf1, &clk_status_reg); + + if ((clk_status_reg & 0x1) == 0) + wilc_debug(N_ERR, "clocks still OFF. Wake up failed\n"); + + } + /* in case of failure, Reset the wakeup bit to introduce a new edge on the next loop */ + if ((clk_status_reg & 0x1) == 0) { + /* Reset bit 0 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg & + (~BIT(0))); + } + } while ((clk_status_reg & 0x1) == 0); + } + + + if (genuChipPSstate == CHIP_SLEEPING_MANUAL) { + g_wlan.hif_func.hif_read_reg(0x1C0C, ®); + reg &= ~BIT(0); + g_wlan.hif_func.hif_write_reg(0x1C0C, reg); + + if (wilc_get_chipid(false) >= 0x1002b0) { + /* Enable PALDO back right after wakeup */ + u32 val32; + + g_wlan.hif_func.hif_read_reg(0x1e1c, &val32); + val32 |= BIT(6); + g_wlan.hif_func.hif_write_reg(0x1e1c, val32); + + g_wlan.hif_func.hif_read_reg(0x1e9c, &val32); + val32 |= BIT(6); + g_wlan.hif_func.hif_write_reg(0x1e9c, val32); + } + } + genuChipPSstate = CHIP_WAKEDUP; +} +#else +static inline void chip_wakeup(void) +{ + u32 reg, trials = 0; + + do { + if ((g_wlan.io_func.io_type & 0x1) == HIF_SPI) { + g_wlan.hif_func.hif_read_reg(1, ®); + /* Make sure bit 1 is 0 before we start. */ + g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1)); + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(1, reg | BIT(1)); + /* Clear bit 1*/ + g_wlan.hif_func.hif_write_reg(1, reg & ~BIT(1)); + } else if ((g_wlan.io_func.io_type & 0x1) == HIF_SDIO) { + /* Make sure bit 0 is 0 before we start. */ + g_wlan.hif_func.hif_read_reg(0xf0, ®); + g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0)); + /* Set bit 1 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg | BIT(0)); + /* Clear bit 1 */ + g_wlan.hif_func.hif_write_reg(0xf0, reg & ~BIT(0)); + } + + do { + /* Wait for the chip to stabilize*/ + mdelay(3); + + /* Make sure chip is awake. This is an extra step that can be removed */ + /* later to avoid the bus access overhead */ + if ((wilc_get_chipid(true) == 0)) + wilc_debug(N_ERR, "Couldn't read chip id. Wake up failed\n"); + + } while ((wilc_get_chipid(true) == 0) && ((++trials % 3) == 0)); + + } while (wilc_get_chipid(true) == 0); + + if (genuChipPSstate == CHIP_SLEEPING_MANUAL) { + g_wlan.hif_func.hif_read_reg(0x1C0C, ®); + reg &= ~BIT(0); + g_wlan.hif_func.hif_write_reg(0x1C0C, reg); + + if (wilc_get_chipid(false) >= 0x1002b0) { + /* Enable PALDO back right after wakeup */ + u32 val32; + + g_wlan.hif_func.hif_read_reg(0x1e1c, &val32); + val32 |= BIT(6); + g_wlan.hif_func.hif_write_reg(0x1e1c, val32); + + g_wlan.hif_func.hif_read_reg(0x1e9c, &val32); + val32 |= BIT(6); + g_wlan.hif_func.hif_write_reg(0x1e9c, val32); + } + } + genuChipPSstate = CHIP_WAKEDUP; +} +#endif +void chip_sleep_manually(u32 u32SleepTime) +{ + if (genuChipPSstate != CHIP_WAKEDUP) { + /* chip is already sleeping. Do nothing */ + return; + } + acquire_bus(ACQUIRE_ONLY); + +#ifdef WILC_OPTIMIZE_SLEEP_INT + chip_allow_sleep(); +#endif + + /* Trigger the manual sleep interrupt */ + g_wlan.hif_func.hif_write_reg(0x10a8, 1); + + genuChipPSstate = CHIP_SLEEPING_MANUAL; + release_bus(RELEASE_ONLY); + +} + + +/******************************************** + * + * Tx, Rx queue handle functions + * + ********************************************/ +int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount) +{ + wilc_wlan_dev_t *p = (wilc_wlan_dev_t *)&g_wlan; + int i, entries = 0; + u32 sum; + u32 reg; + u8 *txb = p->tx_buffer; + u32 offset = 0; + int vmm_sz = 0; + struct txq_entry_t *tqe; + int ret = 0; + int counter; + int timeout; + u32 vmm_table[WILC_VMM_TBL_SIZE]; + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + p->txq_exit = 0; + do { + if (p->quit) + break; + + linux_wlan_lock_timeout(&wilc->txq_add_to_head_cs, + CFG_PKTS_TIMEOUT); +#ifdef TCP_ACK_FILTER + wilc_wlan_txq_filter_dup_tcp_ack(dev); +#endif + /** + * build the vmm list + **/ + PRINT_D(TX_DBG, "Getting the head of the TxQ\n"); + tqe = wilc_wlan_txq_get_first(); + i = 0; + sum = 0; + do { + if ((tqe != NULL) && (i < (WILC_VMM_TBL_SIZE - 1)) /* reserve last entry to 0 */) { + + if (tqe->type == WILC_CFG_PKT) + vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; + + else if (tqe->type == WILC_NET_PKT) + vmm_sz = ETH_ETHERNET_HDR_OFFSET; + + else + vmm_sz = HOST_HDR_OFFSET; + + vmm_sz += tqe->buffer_size; + PRINT_D(TX_DBG, "VMM Size before alignment = %d\n", vmm_sz); + if (vmm_sz & 0x3) { /* has to be word aligned */ + vmm_sz = (vmm_sz + 4) & ~0x3; + } + if ((sum + vmm_sz) > LINUX_TX_SIZE) + break; + + PRINT_D(TX_DBG, "VMM Size AFTER alignment = %d\n", vmm_sz); + vmm_table[i] = vmm_sz / 4; /* table take the word size */ + PRINT_D(TX_DBG, "VMMTable entry size = %d\n", vmm_table[i]); + + if (tqe->type == WILC_CFG_PKT) { + vmm_table[i] |= BIT(10); + PRINT_D(TX_DBG, "VMMTable entry changed for CFG packet = %d\n", vmm_table[i]); + } +#ifdef BIG_ENDIAN + vmm_table[i] = BYTE_SWAP(vmm_table[i]); +#endif + + i++; + sum += vmm_sz; + PRINT_D(TX_DBG, "sum = %d\n", sum); + tqe = wilc_wlan_txq_get_next(wilc, tqe); + } else { + break; + } + } while (1); + + if (i == 0) { /* nothing in the queue */ + PRINT_D(TX_DBG, "Nothing in TX-Q\n"); + break; + } else { + PRINT_D(TX_DBG, "Mark the last entry in VMM table - number of previous entries = %d\n", i); + vmm_table[i] = 0x0; /* mark the last element to 0 */ + } + acquire_bus(ACQUIRE_AND_WAKEUP); + counter = 0; + do { + + ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't read reg vmm_tbl_entry..\n"); + break; + } + + if ((reg & 0x1) == 0) { + /** + * write to vmm table + **/ + PRINT_D(TX_DBG, "Writing VMM table ... with Size = %d\n", ((i + 1) * 4)); + break; + } else { + counter++; + if (counter > 200) { + counter = 0; + PRINT_D(TX_DBG, "Looping in tx ctrl , forcce quit\n"); + ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, 0); + break; + } + /** + * wait for vmm table is ready + **/ + PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n"); + release_bus(RELEASE_ALLOW_SLEEP); + usleep_range(3000, 3000); + acquire_bus(ACQUIRE_AND_WAKEUP); + } + } while (!p->quit); + + if (!ret) + goto _end_; + + timeout = 200; + do { + + /** + * write to vmm table + **/ + ret = p->hif_func.hif_block_tx(WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4)); + if (!ret) { + wilc_debug(N_ERR, "ERR block TX of VMM table.\n"); + break; + } + + + /** + * interrupt firmware + **/ + ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x2); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't write reg host_vmm_ctl..\n"); + break; + } + + /** + * wait for confirm... + **/ + + do { + ret = p->hif_func.hif_read_reg(WILC_HOST_VMM_CTL, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't read reg host_vmm_ctl..\n"); + break; + } + if ((reg >> 2) & 0x1) { + /** + * Get the entries + **/ + entries = ((reg >> 3) & 0x3f); + break; + } else { + release_bus(RELEASE_ALLOW_SLEEP); + usleep_range(3000, 3000); + acquire_bus(ACQUIRE_AND_WAKEUP); + PRINT_WRN(GENERIC_DBG, "Can't get VMM entery - reg = %2x\n", reg); + } + } while (--timeout); + if (timeout <= 0) { + ret = p->hif_func.hif_write_reg(WILC_HOST_VMM_CTL, 0x0); + break; + } + + if (!ret) + break; + + if (entries == 0) { + PRINT_WRN(GENERIC_DBG, "[wilc txq]: no more buffer in the chip (reg: %08x), retry later [[ %d, %x ]]\n", reg, i, vmm_table[i - 1]); + + /* undo the transaction. */ + ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't read reg WILC_HOST_TX_CTRL..\n"); + break; + } + reg &= ~BIT(0); + ret = p->hif_func.hif_write_reg(WILC_HOST_TX_CTRL, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't write reg WILC_HOST_TX_CTRL..\n"); + break; + } + break; + } else { + break; + } + } while (1); + + if (!ret) + goto _end_; + + if (entries == 0) { + ret = WILC_TX_ERR_NO_BUF; + goto _end_; + } + + /* since copying data into txb takes some time, then + * allow the bus lock to be released let the RX task go. */ + release_bus(RELEASE_ALLOW_SLEEP); + + /** + * Copy data to the TX buffer + **/ + offset = 0; + i = 0; + do { + tqe = wilc_wlan_txq_remove_from_head(); + if (tqe != NULL && (vmm_table[i] != 0)) { + u32 header, buffer_offset; + +#ifdef BIG_ENDIAN + vmm_table[i] = BYTE_SWAP(vmm_table[i]); +#endif + vmm_sz = (vmm_table[i] & 0x3ff); /* in word unit */ + vmm_sz *= 4; + header = (tqe->type << 31) | (tqe->buffer_size << 15) | vmm_sz; + if (tqe->type == WILC_MGMT_PKT) + header |= BIT(30); + else + header &= ~BIT(30); + +#ifdef BIG_ENDIAN + header = BYTE_SWAP(header); +#endif + memcpy(&txb[offset], &header, 4); + if (tqe->type == WILC_CFG_PKT) { + buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; + } + else if (tqe->type == WILC_NET_PKT) { + char *pBSSID = ((struct tx_complete_data *)(tqe->priv))->pBssid; + + buffer_offset = ETH_ETHERNET_HDR_OFFSET; + /* copy the bssid at the sart of the buffer */ + memcpy(&txb[offset + 4], pBSSID, 6); + } + else { + buffer_offset = HOST_HDR_OFFSET; + } + + memcpy(&txb[offset + buffer_offset], tqe->buffer, tqe->buffer_size); + offset += vmm_sz; + i++; + tqe->status = 1; /* mark the packet send */ + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, tqe->status); + #ifdef TCP_ACK_FILTER + if (tqe->tcp_PendingAck_index != NOT_TCP_ACK) + Pending_Acks_info[tqe->tcp_PendingAck_index].txqe = NULL; + #endif + kfree(tqe); + } else { + break; + } + } while (--entries); + + /** + * lock the bus + **/ + acquire_bus(ACQUIRE_AND_WAKEUP); + + ret = p->hif_func.hif_clear_int_ext(ENABLE_TX_VMM); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't start tx VMM ...\n"); + goto _end_; + } + + /** + * transfer + **/ + ret = p->hif_func.hif_block_tx_ext(0, txb, offset); + if (!ret) { + wilc_debug(N_ERR, "[wilc txq]: fail can't block tx ext...\n"); + goto _end_; + } + +_end_: + + release_bus(RELEASE_ALLOW_SLEEP); + if (ret != 1) + break; + } while (0); + up(&wilc->txq_add_to_head_cs); + + p->txq_exit = 1; + PRINT_D(TX_DBG, "THREAD: Exiting txq\n"); + /* return tx[]q count */ + *pu32TxqCount = p->txq_entries; + return ret; +} + +static void wilc_wlan_handle_rxq(struct wilc *wilc) +{ + wilc_wlan_dev_t *p = &g_wlan; + int offset = 0, size, has_packet = 0; + u8 *buffer; + struct rxq_entry_t *rqe; + + p->rxq_exit = 0; + + + + + do { + if (p->quit) { + PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n"); + up(&wilc->cfg_event); + break; + } + rqe = wilc_wlan_rxq_remove(wilc); + if (rqe == NULL) { + PRINT_D(RX_DBG, "nothing in the queue - exit 1st do-while\n"); + break; + } + buffer = rqe->buffer; + size = rqe->buffer_size; + PRINT_D(RX_DBG, "rxQ entery Size = %d - Address = %p\n", size, buffer); + offset = 0; + + + + do { + u32 header; + u32 pkt_len, pkt_offset, tp_len; + int is_cfg_packet; + + PRINT_D(RX_DBG, "In the 2nd do-while\n"); + memcpy(&header, &buffer[offset], 4); +#ifdef BIG_ENDIAN + header = BYTE_SWAP(header); +#endif + PRINT_D(RX_DBG, "Header = %04x - Offset = %d\n", header, offset); + + + + is_cfg_packet = (header >> 31) & 0x1; + pkt_offset = (header >> 22) & 0x1ff; + tp_len = (header >> 11) & 0x7ff; + pkt_len = header & 0x7ff; + + if (pkt_len == 0 || tp_len == 0) { + wilc_debug(N_RXQ, "[wilc rxq]: data corrupt, packet len or tp_len is 0 [%d][%d]\n", pkt_len, tp_len); + break; + } + + #define IS_MANAGMEMENT 0x100 + #define IS_MANAGMEMENT_CALLBACK 0x080 + #define IS_MGMT_STATUS_SUCCES 0x040 + + + if (pkt_offset & IS_MANAGMEMENT) { + /* reset mgmt indicator bit, to use pkt_offeset in furthur calculations */ + pkt_offset &= ~(IS_MANAGMEMENT | IS_MANAGMEMENT_CALLBACK | IS_MGMT_STATUS_SUCCES); + + WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len); + } + else + { + + if (!is_cfg_packet) { + if (pkt_len > 0) { + frmw_to_linux(wilc, + &buffer[offset], + pkt_len, + pkt_offset); + has_packet = 1; + } + } else { + wilc_cfg_rsp_t rsp; + + + + wilc_wlan_cfg_indicate_rx(&buffer[pkt_offset + offset], pkt_len, &rsp); + if (rsp.type == WILC_CFG_RSP) { + /** + * wake up the waiting task... + **/ + PRINT_D(RX_DBG, "p->cfg_seq_no = %d - rsp.seq_no = %d\n", p->cfg_seq_no, rsp.seq_no); + if (p->cfg_seq_no == rsp.seq_no) + up(&wilc->cfg_event); + } else if (rsp.type == WILC_CFG_RSP_STATUS) { + /** + * Call back to indicate status... + **/ + linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS); + + } else if (rsp.type == WILC_CFG_RSP_SCAN) { + linux_wlan_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN); + } + } + } + offset += tp_len; + if (offset >= size) + break; + } while (1); + + +#ifndef MEMORY_STATIC + kfree(buffer); +#endif + kfree(rqe); + + if (has_packet) + linux_wlan_rx_complete(); + + } while (1); + + p->rxq_exit = 1; + PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n"); +} + +/******************************************** + * + * Fast DMA Isr + * + ********************************************/ +static void wilc_unknown_isr_ext(void) +{ + g_wlan.hif_func.hif_clear_int_ext(0); +} +static void wilc_pllupdate_isr_ext(u32 int_stats) +{ + + int trials = 10; + + g_wlan.hif_func.hif_clear_int_ext(PLL_INT_CLR); + + /* Waiting for PLL */ + mdelay(WILC_PLL_TO); + + /* poll till read a valid data */ + while (!(ISWILC1000(wilc_get_chipid(true)) && --trials)) { + PRINT_D(TX_DBG, "PLL update retrying\n"); + mdelay(1); + } +} + +static void wilc_sleeptimer_isr_ext(u32 int_stats1) +{ + g_wlan.hif_func.hif_clear_int_ext(SLEEP_INT_CLR); +#ifndef WILC_OPTIMIZE_SLEEP_INT + genuChipPSstate = CHIP_SLEEPING_AUTO; +#endif +} + +static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) +{ + wilc_wlan_dev_t *p = &g_wlan; +#ifdef MEMORY_STATIC + u32 offset = p->rx_buffer_offset; +#endif + u8 *buffer = NULL; + u32 size; + u32 retries = 0; + int ret = 0; + struct rxq_entry_t *rqe; + + + /** + * Get the rx size + **/ + + size = ((int_status & 0x7fff) << 2); + + while (!size && retries < 10) { + u32 time = 0; + /*looping more secure*/ + /*zero size make a crashe because the dma will not happen and that will block the firmware*/ + wilc_debug(N_ERR, "RX Size equal zero ... Trying to read it again for %d time\n", time++); + p->hif_func.hif_read_size(&size); + size = ((size & 0x7fff) << 2); + retries++; + + } + + if (size > 0) { +#ifdef MEMORY_STATIC + if (LINUX_RX_SIZE - offset < size) + offset = 0; + + if (p->rx_buffer) + buffer = &p->rx_buffer[offset]; + else { + wilc_debug(N_ERR, "[wilc isr]: fail Rx Buffer is NULL...drop the packets (%d)\n", size); + goto _end_; + } + +#else + buffer = kmalloc(size, GFP_KERNEL); + if (buffer == NULL) { + wilc_debug(N_ERR, "[wilc isr]: fail alloc host memory...drop the packets (%d)\n", size); + usleep_range(100 * 1000, 100 * 1000); + goto _end_; + } +#endif + + /** + * clear the chip's interrupt after getting size some register getting corrupted after clear the interrupt + **/ + p->hif_func.hif_clear_int_ext(DATA_INT_CLR | ENABLE_RX_VMM); + + + /** + * start transfer + **/ + ret = p->hif_func.hif_block_rx_ext(0, buffer, size); + + if (!ret) { + wilc_debug(N_ERR, "[wilc isr]: fail block rx...\n"); + goto _end_; + } +_end_: + + + if (ret) { +#ifdef MEMORY_STATIC + offset += size; + p->rx_buffer_offset = offset; +#endif + /** + * add to rx queue + **/ + rqe = kmalloc(sizeof(struct rxq_entry_t), GFP_KERNEL); + if (rqe != NULL) { + rqe->buffer = buffer; + rqe->buffer_size = size; + PRINT_D(RX_DBG, "rxq entery Size= %d - Address = %p\n", rqe->buffer_size, rqe->buffer); + wilc_wlan_rxq_add(wilc, rqe); + } + } else { +#ifndef MEMORY_STATIC + kfree(buffer); +#endif + } + } + wilc_wlan_handle_rxq(wilc); +} + +void wilc_handle_isr(void *wilc) +{ + u32 int_status; + + acquire_bus(ACQUIRE_AND_WAKEUP); + g_wlan.hif_func.hif_read_int(&int_status); + + if (int_status & PLL_INT_EXT) + wilc_pllupdate_isr_ext(int_status); + + if (int_status & DATA_INT_EXT) { + wilc_wlan_handle_isr_ext(wilc, int_status); + #ifndef WILC_OPTIMIZE_SLEEP_INT + /* Chip is up and talking*/ + genuChipPSstate = CHIP_WAKEDUP; + #endif + } + if (int_status & SLEEP_INT_EXT) + wilc_sleeptimer_isr_ext(int_status); + + if (!(int_status & (ALL_INT_EXT))) { +#ifdef WILC_SDIO + PRINT_D(TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", int_status); +#endif + wilc_unknown_isr_ext(); + } + release_bus(RELEASE_ALLOW_SLEEP); +} + +/******************************************** + * + * Firmware download + * + ********************************************/ +int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size) +{ + wilc_wlan_dev_t *p = &g_wlan; + u32 offset; + u32 addr, size, size2, blksz; + u8 *dma_buffer; + int ret = 0; + + blksz = BIT(12); + /* Allocate a DMA coherent buffer. */ + + dma_buffer = kmalloc(blksz, GFP_KERNEL); + if (dma_buffer == NULL) { + /*EIO 5*/ + ret = -5; + PRINT_ER("Can't allocate buffer for firmware download IO error\n "); + goto _fail_1; + } + + PRINT_D(INIT_DBG, "Downloading firmware size = %d ...\n", buffer_size); + /** + * load the firmware + **/ + offset = 0; + do { + memcpy(&addr, &buffer[offset], 4); + memcpy(&size, &buffer[offset + 4], 4); +#ifdef BIG_ENDIAN + addr = BYTE_SWAP(addr); + size = BYTE_SWAP(size); +#endif + acquire_bus(ACQUIRE_ONLY); + offset += 8; + while (((int)size) && (offset < buffer_size)) { + if (size <= blksz) + size2 = size; + else + size2 = blksz; + /* Copy firmware into a DMA coherent buffer */ + memcpy(dma_buffer, &buffer[offset], size2); + ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2); + if (!ret) + break; + + addr += size2; + offset += size2; + size -= size2; + } + release_bus(RELEASE_ONLY); + + if (!ret) { + /*EIO 5*/ + ret = -5; + PRINT_ER("Can't download firmware IO error\n "); + goto _fail_; + } + PRINT_D(INIT_DBG, "Offset = %d\n", offset); + } while (offset < buffer_size); + +_fail_: + + kfree(dma_buffer); + +_fail_1: + + return (ret < 0) ? ret : 0; +} + +/******************************************** + * + * Common + * + ********************************************/ +int wilc_wlan_start(void) +{ + wilc_wlan_dev_t *p = &g_wlan; + u32 reg = 0; + int ret; + u32 chipid; + + /** + * Set the host interface + **/ + if (p->io_func.io_type == HIF_SDIO) { + reg = 0; + reg |= BIT(3); /* bug 4456 and 4557 */ + } else if (p->io_func.io_type == HIF_SPI) { + reg = 1; + } + acquire_bus(ACQUIRE_ONLY); + ret = p->hif_func.hif_write_reg(WILC_VMM_CORE_CFG, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write reg vmm_core_cfg...\n"); + release_bus(RELEASE_ONLY); + /* EIO 5*/ + ret = -5; + return ret; + } + reg = 0; +#ifdef WILC_SDIO_IRQ_GPIO + reg |= WILC_HAVE_SDIO_IRQ_GPIO; +#endif + +#ifdef WILC_DISABLE_PMU +#else + reg |= WILC_HAVE_USE_PMU; +#endif + +#ifdef WILC_SLEEP_CLK_SRC_XO + reg |= WILC_HAVE_SLEEP_CLK_SRC_XO; +#elif defined WILC_SLEEP_CLK_SRC_RTC + reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC; +#endif + +#ifdef WILC_EXT_PA_INV_TX_RX + reg |= WILC_HAVE_EXT_PA_INV_TX_RX; +#endif + + reg |= WILC_HAVE_LEGACY_RF_SETTINGS; + + +/*Set oscillator frequency*/ +#ifdef XTAL_24 + reg |= WILC_HAVE_XTAL_24; +#endif + +/*Enable/Disable GPIO configuration for FW logs*/ +#ifdef DISABLE_WILC_UART + reg |= WILC_HAVE_DISABLE_WILC_UART; +#endif + + ret = p->hif_func.hif_write_reg(WILC_GP_REG_1, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write WILC_GP_REG_1 ...\n"); + release_bus(RELEASE_ONLY); + /* EIO 5*/ + ret = -5; + return ret; + } + + /** + * Bus related + **/ + p->hif_func.hif_sync_ext(NUM_INT_EXT); + + ret = p->hif_func.hif_read_reg(0x1000, &chipid); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1000 ...\n"); + release_bus(RELEASE_ONLY); + /* EIO 5*/ + ret = -5; + return ret; + } + + /** + * Go... + **/ + + + p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if ((reg & BIT(10)) == BIT(10)) { + reg &= ~BIT(10); + p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + } + + reg |= BIT(10); + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + release_bus(RELEASE_ONLY); + + return (ret < 0) ? ret : 0; +} + +void wilc_wlan_global_reset(void) +{ + + wilc_wlan_dev_t *p = &g_wlan; + + acquire_bus(ACQUIRE_AND_WAKEUP); + p->hif_func.hif_write_reg(WILC_GLB_RESET_0, 0x0); + release_bus(RELEASE_ONLY); +} +int wilc_wlan_stop(void) +{ + wilc_wlan_dev_t *p = &g_wlan; + u32 reg = 0; + int ret; + u8 timeout = 10; + /** + * TODO: stop the firmware, need a re-download + **/ + acquire_bus(ACQUIRE_AND_WAKEUP); + + ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + + reg &= ~BIT(10); + + + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + if (!ret) { + PRINT_ER("Error while writing reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + + + + do { + ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout); + /*Workaround to ensure that the chip is actually reset*/ + if ((reg & BIT(10))) { + PRINT_D(GENERIC_DBG, "Bit 10 not reset : Retry %d\n", timeout); + reg &= ~BIT(10); + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + timeout--; + } else { + PRINT_D(GENERIC_DBG, "Bit 10 reset after : Retry %d\n", timeout); + ret = p->hif_func.hif_read_reg(WILC_GLB_RESET_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + return ret; + } + PRINT_D(GENERIC_DBG, "Read RESET Reg %x : Retry%d\n", reg, timeout); + break; + } + + } while (timeout); + reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | BIT(26) | + BIT(29) | BIT(30) | BIT(31)); + + p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + reg = (u32)~BIT(10); + + ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); + + release_bus(RELEASE_ALLOW_SLEEP); + + return ret; +} + +void wilc_wlan_cleanup(struct net_device *dev) +{ + wilc_wlan_dev_t *p = &g_wlan; + struct txq_entry_t *tqe; + struct rxq_entry_t *rqe; + u32 reg = 0; + int ret; + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + p->quit = 1; + do { + tqe = wilc_wlan_txq_remove_from_head(); + if (tqe == NULL) + break; + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, 0); + kfree(tqe); + } while (1); + + do { + rqe = wilc_wlan_rxq_remove(wilc); + if (rqe == NULL) + break; +#ifndef MEMORY_STATIC + kfree(rqe->buffer); +#endif + kfree(rqe); + } while (1); + + /** + * clean up buffer + **/ + + #ifdef MEMORY_STATIC + kfree(p->rx_buffer); + p->rx_buffer = NULL; + #endif + kfree(p->tx_buffer); + + acquire_bus(ACQUIRE_AND_WAKEUP); + + + ret = p->hif_func.hif_read_reg(WILC_GP_REG_0, ®); + if (!ret) { + PRINT_ER("Error while reading reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + } + PRINT_ER("Writing ABORT reg\n"); + ret = p->hif_func.hif_write_reg(WILC_GP_REG_0, (reg | ABORT_INT)); + if (!ret) { + PRINT_ER("Error while writing reg\n"); + release_bus(RELEASE_ALLOW_SLEEP); + } + release_bus(RELEASE_ALLOW_SLEEP); + /** + * io clean up + **/ + p->hif_func.hif_deinit(NULL); + +} + +static int wilc_wlan_cfg_commit(int type, u32 drvHandler) +{ + wilc_wlan_dev_t *p = &g_wlan; + wilc_cfg_frame_t *cfg = &p->cfg_frame; + int total_len = p->cfg_frame_offset + 4 + DRIVER_HANDLER_SIZE; + int seq_no = p->cfg_seq_no % 256; + int driver_handler = (u32)drvHandler; + + + /** + * Set up header + **/ + if (type == WILC_CFG_SET) { /* Set */ + cfg->wid_header[0] = 'W'; + } else { /* Query */ + cfg->wid_header[0] = 'Q'; + } + cfg->wid_header[1] = seq_no; /* sequence number */ + cfg->wid_header[2] = (u8)total_len; + cfg->wid_header[3] = (u8)(total_len >> 8); + cfg->wid_header[4] = (u8)driver_handler; + cfg->wid_header[5] = (u8)(driver_handler >> 8); + cfg->wid_header[6] = (u8)(driver_handler >> 16); + cfg->wid_header[7] = (u8)(driver_handler >> 24); + p->cfg_seq_no = seq_no; + + /** + * Add to TX queue + **/ + + if (!wilc_wlan_txq_add_cfg_pkt(&cfg->wid_header[0], total_len)) + return -1; + + return 0; +} + +int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size, + int commit, u32 drvHandler) +{ + wilc_wlan_dev_t *p = &g_wlan; + u32 offset; + int ret_size; + + + if (p->cfg_frame_in_use) + return 0; + + if (start) + p->cfg_frame_offset = 0; + + offset = p->cfg_frame_offset; + ret_size = wilc_wlan_cfg_set_wid(p->cfg_frame.frame, offset, (u16)wid, + buffer, buffer_size); + offset += ret_size; + p->cfg_frame_offset = offset; + + if (commit) { + PRINT_D(TX_DBG, "[WILC]PACKET Commit with sequence number %d\n", p->cfg_seq_no); + PRINT_D(RX_DBG, "Processing cfg_set()\n"); + p->cfg_frame_in_use = 1; + + if (wilc_wlan_cfg_commit(WILC_CFG_SET, drvHandler)) + ret_size = 0; + + if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event, + CFG_PKTS_TIMEOUT)) { + PRINT_D(TX_DBG, "Set Timed Out\n"); + ret_size = 0; + } + p->cfg_frame_in_use = 0; + p->cfg_frame_offset = 0; + p->cfg_seq_no += 1; + + } + + return ret_size; +} +int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler) +{ + wilc_wlan_dev_t *p = &g_wlan; + u32 offset; + int ret_size; + + + if (p->cfg_frame_in_use) + return 0; + + if (start) + p->cfg_frame_offset = 0; + + offset = p->cfg_frame_offset; + ret_size = wilc_wlan_cfg_get_wid(p->cfg_frame.frame, offset, (u16)wid); + offset += ret_size; + p->cfg_frame_offset = offset; + + if (commit) { + p->cfg_frame_in_use = 1; + + if (wilc_wlan_cfg_commit(WILC_CFG_QUERY, drvHandler)) + ret_size = 0; + + + if (linux_wlan_lock_timeout(&g_linux_wlan->cfg_event, + CFG_PKTS_TIMEOUT)) { + PRINT_D(TX_DBG, "Get Timed Out\n"); + ret_size = 0; + } + PRINT_D(GENERIC_DBG, "[WILC]Get Response received\n"); + p->cfg_frame_in_use = 0; + p->cfg_frame_offset = 0; + p->cfg_seq_no += 1; + } + + return ret_size; +} + +int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size) +{ + int ret; + + ret = wilc_wlan_cfg_get_wid_value((u16)wid, buffer, buffer_size); + + return ret; +} + +void wilc_bus_set_max_speed(void) +{ + + /* Increase bus speed to max possible. */ + g_wlan.hif_func.hif_set_max_bus_speed(); +} + +void wilc_bus_set_default_speed(void) +{ + + /* Restore bus speed to default. */ + g_wlan.hif_func.hif_set_default_bus_speed(); +} +u32 init_chip(void) +{ + u32 chipid; + u32 reg, ret = 0; + + acquire_bus(ACQUIRE_ONLY); + + chipid = wilc_get_chipid(true); + + + + if ((chipid & 0xfff) != 0xa0) { + /** + * Avoid booting from boot ROM. Make sure that Drive IRQN [SDIO platform] + * or SD_DAT3 [SPI platform] to ?1? + **/ + /* Set cortus reset register to register control. */ + ret = g_wlan.hif_func.hif_read_reg(0x1118, ®); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail read reg 0x1118 ...\n"); + return ret; + } + reg |= BIT(0); + ret = g_wlan.hif_func.hif_write_reg(0x1118, reg); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write reg 0x1118 ...\n"); + return ret; + } + /** + * Write branch intruction to IRAM (0x71 trap) at location 0xFFFF0000 + * (Cortus map) or C0000 (AHB map). + **/ + ret = g_wlan.hif_func.hif_write_reg(0xc0000, 0x71); + if (!ret) { + wilc_debug(N_ERR, "[wilc start]: fail write reg 0xc0000 ...\n"); + return ret; + } + } + + release_bus(RELEASE_ONLY); + + return ret; + +} + +u32 wilc_get_chipid(u8 update) +{ + static u32 chipid; + /* SDIO can't read into global variables */ + /* Use this variable as a temp, then copy to the global */ + u32 tempchipid = 0; + u32 rfrevid; + + if (chipid == 0 || update != 0) { + g_wlan.hif_func.hif_read_reg(0x1000, &tempchipid); + g_wlan.hif_func.hif_read_reg(0x13f4, &rfrevid); + if (!ISWILC1000(tempchipid)) { + chipid = 0; + goto _fail_; + } + if (tempchipid == 0x1002a0) { + if (rfrevid == 0x1) { /* 1002A0 */ + } else { /* if (rfrevid == 0x2) */ /* 1002A1 */ + tempchipid = 0x1002a1; + } + } else if (tempchipid == 0x1002b0) { + if (rfrevid == 3) { /* 1002B0 */ + } else if (rfrevid == 4) { /* 1002B1 */ + tempchipid = 0x1002b1; + } else { /* if(rfrevid == 5) */ /* 1002B2 */ + tempchipid = 0x1002b2; + } + } else { + } + + chipid = tempchipid; + } +_fail_: + return chipid; +} + +int wilc_wlan_init(wilc_wlan_inp_t *inp) +{ + + int ret = 0; + + PRINT_D(INIT_DBG, "Initializing WILC_Wlan ...\n"); + + memset((void *)&g_wlan, 0, sizeof(wilc_wlan_dev_t)); + + /** + * store the input + **/ + memcpy((void *)&g_wlan.io_func, (void *)&inp->io_func, sizeof(wilc_wlan_io_func_t)); + /*** + * host interface init + **/ + if ((inp->io_func.io_type & 0x1) == HIF_SDIO) { + if (!hif_sdio.hif_init(inp, wilc_debug)) { + /* EIO 5 */ + ret = -5; + goto _fail_; + } + memcpy((void *)&g_wlan.hif_func, &hif_sdio, sizeof(wilc_hif_func_t)); + } else { + if ((inp->io_func.io_type & 0x1) == HIF_SPI) { + /** + * TODO: + **/ + if (!hif_spi.hif_init(inp, wilc_debug)) { + /* EIO 5 */ + ret = -5; + goto _fail_; + } + memcpy((void *)&g_wlan.hif_func, &hif_spi, sizeof(wilc_hif_func_t)); + } else { + /* EIO 5 */ + ret = -5; + goto _fail_; + } + } + + /*** + * mac interface init + **/ + if (!wilc_wlan_cfg_init(wilc_debug)) { + /* ENOBUFS 105 */ + ret = -105; + goto _fail_; + } + + /** + * alloc tx, rx buffer + **/ + if (g_wlan.tx_buffer == NULL) + g_wlan.tx_buffer = kmalloc(LINUX_TX_SIZE, GFP_KERNEL); + PRINT_D(TX_DBG, "g_wlan.tx_buffer = %p\n", g_wlan.tx_buffer); + + if (g_wlan.tx_buffer == NULL) { + /* ENOBUFS 105 */ + ret = -105; + PRINT_ER("Can't allocate Tx Buffer"); + goto _fail_; + } + +/* rx_buffer is not used unless we activate USE_MEM STATIC which is not applicable, allocating such memory is useless*/ +#if defined (MEMORY_STATIC) + if (g_wlan.rx_buffer == NULL) + g_wlan.rx_buffer = kmalloc(LINUX_RX_SIZE, GFP_KERNEL); + PRINT_D(TX_DBG, "g_wlan.rx_buffer =%p\n", g_wlan.rx_buffer); + if (g_wlan.rx_buffer == NULL) { + /* ENOBUFS 105 */ + ret = -105; + PRINT_ER("Can't allocate Rx Buffer"); + goto _fail_; + } +#endif + + if (!init_chip()) { + /* EIO 5 */ + ret = -5; + goto _fail_; + } +#ifdef TCP_ACK_FILTER + Init_TCP_tracking(); +#endif + + return 1; + +_fail_: + + #ifdef MEMORY_STATIC + kfree(g_wlan.rx_buffer); + g_wlan.rx_buffer = NULL; + #endif + kfree(g_wlan.tx_buffer); + g_wlan.tx_buffer = NULL; + + return ret; + +} + +u16 Set_machw_change_vir_if(struct net_device *dev, bool bValue) +{ + u16 ret; + u32 reg; + perInterface_wlan_t *nic; + struct wilc *wilc; + + nic = netdev_priv(dev); + wilc = nic->wilc; + + /*Reset WILC_CHANGING_VIR_IF register to allow adding futrue keys to CE H/W*/ + mutex_lock(&wilc->hif_cs); + ret = (&g_wlan)->hif_func.hif_read_reg(WILC_CHANGING_VIR_IF, ®); + if (!ret) + PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n"); + + if (bValue) + reg |= BIT(31); + else + reg &= ~BIT(31); + + ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg); + + if (!ret) + PRINT_ER("Error while writing reg WILC_CHANGING_VIR_IF\n"); + + mutex_unlock(&wilc->hif_cs); + + return ret; +} diff --git a/kernel/drivers/staging/wilc1000/wilc_wlan.h b/kernel/drivers/staging/wilc1000/wilc_wlan.h new file mode 100644 index 000000000..57e1d5174 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wlan.h @@ -0,0 +1,312 @@ +#ifndef WILC_WLAN_H +#define WILC_WLAN_H + + + +#define ISWILC1000(id) (((id & 0xfffff000) == 0x100000) ? 1 : 0) + + +/******************************************** + * + * Mac eth header length + * + ********************************************/ +#define DRIVER_HANDLER_SIZE 4 +#define MAX_MAC_HDR_LEN 26 /* QOS_MAC_HDR_LEN */ +#define SUB_MSDU_HEADER_LENGTH 14 +#define SNAP_HDR_LEN 8 +#define ETHERNET_HDR_LEN 14 +#define WORD_ALIGNMENT_PAD 0 + +#define ETH_ETHERNET_HDR_OFFSET (MAX_MAC_HDR_LEN + SUB_MSDU_HEADER_LENGTH + \ + SNAP_HDR_LEN - ETHERNET_HDR_LEN + WORD_ALIGNMENT_PAD) + +#define HOST_HDR_OFFSET 4 +#define ETHERNET_HDR_LEN 14 +#define IP_HDR_LEN 20 +#define IP_HDR_OFFSET ETHERNET_HDR_LEN +#define UDP_HDR_OFFSET (IP_HDR_LEN + IP_HDR_OFFSET) +#define UDP_HDR_LEN 8 +#define UDP_DATA_OFFSET (UDP_HDR_OFFSET + UDP_HDR_LEN) +#define ETH_CONFIG_PKT_HDR_LEN UDP_DATA_OFFSET + +#define ETH_CONFIG_PKT_HDR_OFFSET (ETH_ETHERNET_HDR_OFFSET + \ + ETH_CONFIG_PKT_HDR_LEN) + +/******************************************** + * + * Endian Conversion + * + ********************************************/ + +#define BYTE_SWAP(val) ((((val) & 0x000000FF) << 24) + \ + (((val) & 0x0000FF00) << 8) + \ + (((val) & 0x00FF0000) >> 8) + \ + (((val) & 0xFF000000) >> 24)) + +/******************************************** + * + * Register Defines + * + ********************************************/ +#define WILC_PERIPH_REG_BASE 0x1000 +#define WILC_CHANGING_VIR_IF (0x108c) +#define WILC_CHIPID (WILC_PERIPH_REG_BASE) +#define WILC_GLB_RESET_0 (WILC_PERIPH_REG_BASE + 0x400) +#define WILC_PIN_MUX_0 (WILC_PERIPH_REG_BASE + 0x408) +#define WILC_HOST_TX_CTRL (WILC_PERIPH_REG_BASE + 0x6c) +#define WILC_HOST_RX_CTRL_0 (WILC_PERIPH_REG_BASE + 0x70) +#define WILC_HOST_RX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x74) +#define WILC_HOST_VMM_CTL (WILC_PERIPH_REG_BASE + 0x78) +#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80) +#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84) +#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88) +#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428) +#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00) +#define WILC_INTR_ENABLE (WILC_INTR_REG_BASE) +#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4) + +#define WILC_INTR_POLARITY (WILC_INTR_REG_BASE + 0x10) +#define WILC_INTR_TYPE (WILC_INTR_REG_BASE + 0x20) +#define WILC_INTR_CLEAR (WILC_INTR_REG_BASE + 0x30) +#define WILC_INTR_STATUS (WILC_INTR_REG_BASE + 0x40) + +#define WILC_VMM_TBL_SIZE 64 +#define WILC_VMM_TX_TBL_BASE (0x150400) +#define WILC_VMM_RX_TBL_BASE (0x150500) + +#define WILC_VMM_BASE 0x150000 +#define WILC_VMM_CORE_CTL (WILC_VMM_BASE) +#define WILC_VMM_TBL_CTL (WILC_VMM_BASE + 0x4) +#define WILC_VMM_TBL_ENTRY (WILC_VMM_BASE + 0x8) +#define WILC_VMM_TBL0_SIZE (WILC_VMM_BASE + 0xc) +#define WILC_VMM_TO_HOST_SIZE (WILC_VMM_BASE + 0x10) +#define WILC_VMM_CORE_CFG (WILC_VMM_BASE + 0x14) +#define WILC_VMM_TBL_ACTIVE (WILC_VMM_BASE + 040) +#define WILC_VMM_TBL_STATUS (WILC_VMM_BASE + 0x44) + +#define WILC_SPI_REG_BASE 0xe800 +#define WILC_SPI_CTL (WILC_SPI_REG_BASE) +#define WILC_SPI_MASTER_DMA_ADDR (WILC_SPI_REG_BASE + 0x4) +#define WILC_SPI_MASTER_DMA_COUNT (WILC_SPI_REG_BASE + 0x8) +#define WILC_SPI_SLAVE_DMA_ADDR (WILC_SPI_REG_BASE + 0xc) +#define WILC_SPI_SLAVE_DMA_COUNT (WILC_SPI_REG_BASE + 0x10) +#define WILC_SPI_TX_MODE (WILC_SPI_REG_BASE + 0x20) +#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24) +#define WILC_SPI_INTR_CTL (WILC_SPI_REG_BASE + 0x2c) + +#define WILC_SPI_PROTOCOL_OFFSET (WILC_SPI_PROTOCOL_CONFIG - WILC_SPI_REG_BASE) + +#define WILC_AHB_DATA_MEM_BASE 0x30000 +#define WILC_AHB_SHARE_MEM_BASE 0xd0000 + +#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE +#define WILC_VMM_TBL_RX_SHADOW_SIZE (256) + +#define WILC_GP_REG_0 0x149c +#define WILC_GP_REG_1 0x14a0 + +#define rHAVE_SDIO_IRQ_GPIO_BIT (0) +#define rHAVE_USE_PMU_BIT (1) +#define rHAVE_SLEEP_CLK_SRC_RTC_BIT (2) +#define rHAVE_SLEEP_CLK_SRC_XO_BIT (3) +#define rHAVE_EXT_PA_INV_TX_RX_BIT (4) +#define rHAVE_LEGACY_RF_SETTINGS_BIT (5) +#define rHAVE_XTAL_24_BIT (6) +#define rHAVE_DISABLE_WILC_UART_BIT (7) + + +#define WILC_HAVE_SDIO_IRQ_GPIO (1 << rHAVE_SDIO_IRQ_GPIO_BIT) +#define WILC_HAVE_USE_PMU (1 << rHAVE_USE_PMU_BIT) +#define WILC_HAVE_SLEEP_CLK_SRC_RTC (1 << rHAVE_SLEEP_CLK_SRC_RTC_BIT) +#define WILC_HAVE_SLEEP_CLK_SRC_XO (1 << rHAVE_SLEEP_CLK_SRC_XO_BIT) +#define WILC_HAVE_EXT_PA_INV_TX_RX (1 << rHAVE_EXT_PA_INV_TX_RX_BIT) +#define WILC_HAVE_LEGACY_RF_SETTINGS (1 << rHAVE_LEGACY_RF_SETTINGS_BIT) +#define WILC_HAVE_XTAL_24 (1 << rHAVE_XTAL_24_BIT) +#define WILC_HAVE_DISABLE_WILC_UART (1 << rHAVE_DISABLE_WILC_UART_BIT) + + +/******************************************** + * + * Wlan Defines + * + ********************************************/ +#define WILC_CFG_PKT 1 +#define WILC_NET_PKT 0 +#define WILC_MGMT_PKT 2 + +#define WILC_CFG_SET 1 +#define WILC_CFG_QUERY 0 + +#define WILC_CFG_RSP 1 +#define WILC_CFG_RSP_STATUS 2 +#define WILC_CFG_RSP_SCAN 3 + +#ifdef WILC_SDIO +#define WILC_PLL_TO 4 +#else +#define WILC_PLL_TO 2 +#endif + + +#define ABORT_INT BIT(31) + +/*******************************************/ +/* E0 and later Interrupt flags. */ +/*******************************************/ +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Status word */ +/* 15:0 = DMA count in words. */ +/* 16: INT0 flag */ +/* 17: INT1 flag */ +/* 18: INT2 flag */ +/* 19: INT3 flag */ +/* 20: INT4 flag */ +/* 21: INT5 flag */ +/*******************************************/ +#define IRG_FLAGS_OFFSET 16 +#define IRQ_DMA_WD_CNT_MASK ((1ul << IRG_FLAGS_OFFSET) - 1) +#define INT_0 (1 << (IRG_FLAGS_OFFSET)) +#define INT_1 (1 << (IRG_FLAGS_OFFSET + 1)) +#define INT_2 (1 << (IRG_FLAGS_OFFSET + 2)) +#define INT_3 (1 << (IRG_FLAGS_OFFSET + 3)) +#define INT_4 (1 << (IRG_FLAGS_OFFSET + 4)) +#define INT_5 (1 << (IRG_FLAGS_OFFSET + 5)) +#define MAX_NUM_INT (6) + +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Clear word */ +/* 0: Clear INT0 */ +/* 1: Clear INT1 */ +/* 2: Clear INT2 */ +/* 3: Clear INT3 */ +/* 4: Clear INT4 */ +/* 5: Clear INT5 */ +/* 6: Select VMM table 1 */ +/* 7: Select VMM table 2 */ +/* 8: Enable VMM */ +/*******************************************/ +#define CLR_INT0 BIT(0) +#define CLR_INT1 BIT(1) +#define CLR_INT2 BIT(2) +#define CLR_INT3 BIT(3) +#define CLR_INT4 BIT(4) +#define CLR_INT5 BIT(5) +#define SEL_VMM_TBL0 BIT(6) +#define SEL_VMM_TBL1 BIT(7) +#define EN_VMM BIT(8) + +#define DATA_INT_EXT INT_0 +#define PLL_INT_EXT INT_1 +#define SLEEP_INT_EXT INT_2 +#define ALL_INT_EXT (DATA_INT_EXT | PLL_INT_EXT | SLEEP_INT_EXT) +#define NUM_INT_EXT (3) + +#define DATA_INT_CLR CLR_INT0 +#define PLL_INT_CLR CLR_INT1 +#define SLEEP_INT_CLR CLR_INT2 + +#define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM) +#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM) + + +/*time for expiring the semaphores of cfg packets*/ +#define CFG_PKTS_TIMEOUT 2000 +/******************************************** + * + * Debug Type + * + ********************************************/ +typedef void (*wilc_debug_func)(u32, char *, ...); + +/******************************************** + * + * Tx/Rx Queue Structure + * + ********************************************/ + +struct txq_entry_t { + struct txq_entry_t *next; + struct txq_entry_t *prev; + int type; + int tcp_PendingAck_index; + u8 *buffer; + int buffer_size; + void *priv; + int status; + void (*tx_complete_func)(void *, int); +}; + +struct rxq_entry_t { + struct rxq_entry_t *next; + u8 *buffer; + int buffer_size; +}; + +/******************************************** + * + * Host IF Structure + * + ********************************************/ + +typedef struct { + int (*hif_init)(wilc_wlan_inp_t *, wilc_debug_func); + int (*hif_deinit)(void *); + int (*hif_read_reg)(u32, u32 *); + int (*hif_write_reg)(u32, u32); + int (*hif_block_rx)(u32, u8 *, u32); + int (*hif_block_tx)(u32, u8 *, u32); + int (*hif_sync)(void); + int (*hif_clear_int)(void); + int (*hif_read_int)(u32 *); + int (*hif_clear_int_ext)(u32); + int (*hif_read_size)(u32 *); + int (*hif_block_tx_ext)(u32, u8 *, u32); + int (*hif_block_rx_ext)(u32, u8 *, u32); + int (*hif_sync_ext)(int); + void (*hif_set_max_bus_speed)(void); + void (*hif_set_default_bus_speed)(void); +} wilc_hif_func_t; + +/******************************************** + * + * Configuration Structure + * + ********************************************/ + +#define MAX_CFG_FRAME_SIZE 1468 + +typedef struct { + u8 ether_header[14]; + u8 ip_header[20]; + u8 udp_header[8]; + u8 wid_header[8]; + u8 frame[MAX_CFG_FRAME_SIZE]; +} wilc_cfg_frame_t; + +typedef struct { + int (*wlan_tx)(u8 *, u32, wilc_tx_complete_func_t); +} wilc_wlan_cfg_func_t; + +typedef struct { + int type; + u32 seq_no; +} wilc_cfg_rsp_t; + +int wilc_wlan_firmware_download(const u8 *buffer, u32 buffer_size); +int wilc_wlan_start(void); +int wilc_wlan_stop(void); +int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, + u32 buffer_size, wilc_tx_complete_func_t func); +int wilc_wlan_handle_txq(struct net_device *dev, u32 *pu32TxqCount); +void wilc_handle_isr(void *wilc); +void wilc_wlan_cleanup(struct net_device *dev); +int wilc_wlan_cfg_set(int start, u32 wid, u8 *buffer, u32 buffer_size, + int commit, u32 drvHandler); +int wilc_wlan_cfg_get(int start, u32 wid, int commit, u32 drvHandler); +int wilc_wlan_cfg_get_val(u32 wid, u8 *buffer, u32 buffer_size); +int wilc_wlan_txq_add_mgmt_pkt(void *priv, u8 *buffer, u32 buffer_size, + wilc_tx_complete_func_t func); +#endif diff --git a/kernel/drivers/staging/wilc1000/wilc_wlan_cfg.c b/kernel/drivers/staging/wilc1000/wilc_wlan_cfg.c new file mode 100644 index 000000000..a34a81cde --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wlan_cfg.c @@ -0,0 +1,566 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan_cfg.c */ +/* */ +/* */ +/* ///////////////////////////////////////////////////////////////////////// */ + +#include +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" +#include "wilc_wlan_cfg.h" +#include "coreconfigurator.h" + +/******************************************** + * + * Global Data + * + ********************************************/ + +typedef struct { + wilc_debug_func dPrint; + + int mac_status; + u8 mac_address[7]; + u8 ip_address[5]; + u8 bssid[7]; + u8 ssid[34]; + u8 firmware_version[129]; + u8 supp_rate[24]; + u8 wep_key[28]; + u8 i_psk[66]; + u8 hardwareProductVersion[33]; + u8 phyversion[17]; + u8 supp_username[21]; + u8 supp_password[64]; + u8 assoc_req[256]; + u8 assoc_rsp[256]; + u8 firmware_info[8]; + u8 scan_result[256]; + u8 scan_result1[256]; +} wilc_mac_cfg_t; + +static wilc_mac_cfg_t g_mac; + +static wilc_cfg_byte_t g_cfg_byte[] = { + {WID_BSS_TYPE, 0}, + {WID_CURRENT_TX_RATE, 0}, + {WID_CURRENT_CHANNEL, 0}, + {WID_PREAMBLE, 0}, + {WID_11G_OPERATING_MODE, 0}, + {WID_STATUS, 0}, + {WID_SCAN_TYPE, 0}, + {WID_KEY_ID, 0}, + {WID_QOS_ENABLE, 0}, + {WID_POWER_MANAGEMENT, 0}, + {WID_11I_MODE, 0}, + {WID_AUTH_TYPE, 0}, + {WID_SITE_SURVEY, 0}, + {WID_LISTEN_INTERVAL, 0}, + {WID_DTIM_PERIOD, 0}, + {WID_ACK_POLICY, 0}, + {WID_BCAST_SSID, 0}, + {WID_REKEY_POLICY, 0}, + {WID_SHORT_SLOT_ALLOWED, 0}, + {WID_START_SCAN_REQ, 0}, + {WID_RSSI, 0}, + {WID_LINKSPEED, 0}, + {WID_AUTO_RX_SENSITIVITY, 0}, + {WID_DATAFLOW_CONTROL, 0}, + {WID_SCAN_FILTER, 0}, + {WID_11N_PROT_MECH, 0}, + {WID_11N_ERP_PROT_TYPE, 0}, + {WID_11N_ENABLE, 0}, + {WID_11N_OPERATING_MODE, 0}, + {WID_11N_OBSS_NONHT_DETECTION, 0}, + {WID_11N_HT_PROT_TYPE, 0}, + {WID_11N_RIFS_PROT_ENABLE, 0}, + {WID_11N_SMPS_MODE, 0}, + {WID_11N_CURRENT_TX_MCS, 0}, + {WID_11N_SHORT_GI_ENABLE, 0}, + {WID_RIFS_MODE, 0}, + {WID_TX_ABORT_CONFIG, 0}, + {WID_11N_IMMEDIATE_BA_ENABLED, 0}, + {WID_11N_TXOP_PROT_DISABLE, 0}, + {WID_NIL, 0} +}; + +static wilc_cfg_hword_t g_cfg_hword[] = { + {WID_LINK_LOSS_THRESHOLD, 0}, + {WID_RTS_THRESHOLD, 0}, + {WID_FRAG_THRESHOLD, 0}, + {WID_SHORT_RETRY_LIMIT, 0}, + {WID_LONG_RETRY_LIMIT, 0}, + {WID_BEACON_INTERVAL, 0}, + {WID_RX_SENSE, 0}, + {WID_ACTIVE_SCAN_TIME, 0}, + {WID_PASSIVE_SCAN_TIME, 0}, + {WID_SITE_SURVEY_SCAN_TIME, 0}, + {WID_JOIN_START_TIMEOUT, 0}, + {WID_AUTH_TIMEOUT, 0}, + {WID_ASOC_TIMEOUT, 0}, + {WID_11I_PROTOCOL_TIMEOUT, 0}, + {WID_EAPOL_RESPONSE_TIMEOUT, 0}, + {WID_11N_SIG_QUAL_VAL, 0}, + {WID_CCA_THRESHOLD, 0}, + {WID_NIL, 0} +}; + +static wilc_cfg_word_t g_cfg_word[] = { + {WID_FAILED_COUNT, 0}, + {WID_RETRY_COUNT, 0}, + {WID_MULTIPLE_RETRY_COUNT, 0}, + {WID_FRAME_DUPLICATE_COUNT, 0}, + {WID_ACK_FAILURE_COUNT, 0}, + {WID_RECEIVED_FRAGMENT_COUNT, 0}, + {WID_MCAST_RECEIVED_FRAME_COUNT, 0}, + {WID_FCS_ERROR_COUNT, 0}, + {WID_SUCCESS_FRAME_COUNT, 0}, + {WID_TX_FRAGMENT_COUNT, 0}, + {WID_TX_MULTICAST_FRAME_COUNT, 0}, + {WID_RTS_SUCCESS_COUNT, 0}, + {WID_RTS_FAILURE_COUNT, 0}, + {WID_WEP_UNDECRYPTABLE_COUNT, 0}, + {WID_REKEY_PERIOD, 0}, + {WID_REKEY_PACKET_COUNT, 0}, + {WID_HW_RX_COUNT, 0}, + {WID_GET_INACTIVE_TIME, 0}, + {WID_NIL, 0} + +}; + +static wilc_cfg_str_t g_cfg_str[] = { + {WID_SSID, g_mac.ssid}, /* 33 + 1 bytes */ + {WID_FIRMWARE_VERSION, g_mac.firmware_version}, + {WID_OPERATIONAL_RATE_SET, g_mac.supp_rate}, + {WID_BSSID, g_mac.bssid}, /* 6 bytes */ + {WID_WEP_KEY_VALUE, g_mac.wep_key}, /* 27 bytes */ + {WID_11I_PSK, g_mac.i_psk}, /* 65 bytes */ + /* {WID_11E_P_ACTION_REQ, g_mac.action_req}, */ + {WID_HARDWARE_VERSION, g_mac.hardwareProductVersion}, + {WID_MAC_ADDR, g_mac.mac_address}, + {WID_PHY_VERSION, g_mac.phyversion}, + {WID_SUPP_USERNAME, g_mac.supp_username}, + {WID_SUPP_PASSWORD, g_mac.supp_password}, + {WID_SITE_SURVEY_RESULTS, g_mac.scan_result}, + {WID_SITE_SURVEY_RESULTS, g_mac.scan_result1}, + /* {WID_RX_POWER_LEVEL, g_mac.channel_rssi}, */ + {WID_ASSOC_REQ_INFO, g_mac.assoc_req}, + {WID_ASSOC_RES_INFO, g_mac.assoc_rsp}, + /* {WID_11N_P_ACTION_REQ, g_mac.action_req}, */ + {WID_FIRMWARE_INFO, g_mac.firmware_version}, + {WID_IP_ADDRESS, g_mac.ip_address}, + {WID_NIL, NULL} +}; + +/******************************************** + * + * Configuration Functions + * + ********************************************/ + +static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8) +{ + u8 *buf; + + if ((offset + 4) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (u8)id; + buf[1] = (u8)(id >> 8); + buf[2] = 1; + buf[3] = val8; + return 4; +} + +static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16) +{ + u8 *buf; + + if ((offset + 5) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (u8)id; + buf[1] = (u8)(id >> 8); + buf[2] = 2; + buf[3] = (u8)val16; + buf[4] = (u8)(val16 >> 8); + + return 5; +} + +static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32) +{ + u8 *buf; + + if ((offset + 7) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (u8)id; + buf[1] = (u8)(id >> 8); + buf[2] = 4; + buf[3] = (u8)val32; + buf[4] = (u8)(val32 >> 8); + buf[5] = (u8)(val32 >> 16); + buf[6] = (u8)(val32 >> 24); + + return 7; +} + +static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str, u32 size) +{ + u8 *buf; + + if ((offset + size + 3) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (u8)id; + buf[1] = (u8)(id >> 8); + buf[2] = (u8)size; + + if ((str != NULL) && (size != 0)) + memcpy(&buf[3], str, size); + + return (size + 3); +} + +static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size) +{ + u8 *buf; + u32 i; + u8 checksum = 0; + + if ((offset + size + 5) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + buf[0] = (u8)id; + buf[1] = (u8)(id >> 8); + buf[2] = (u8)size; + buf[3] = (u8)(size >> 8); + + if ((b != NULL) && (size != 0)) { + memcpy(&buf[4], b, size); + for (i = 0; i < size; i++) { + checksum += buf[i + 4]; + } + } + + buf[size + 4] = checksum; + + return (size + 5); +} + +/******************************************** + * + * Configuration Response Functions + * + ********************************************/ + +static void wilc_wlan_parse_response_frame(u8 *info, int size) +{ + u32 wid, len = 0, i = 0; + static int seq; + + while (size > 0) { + i = 0; + wid = info[0] | (info[1] << 8); +#ifdef BIG_ENDIAN + wid = BYTE_SWAP(wid); +#endif + PRINT_INFO(GENERIC_DBG, "Processing response for %d seq %d\n", wid, seq++); + switch ((wid >> 12) & 0x7) { + case WID_CHAR: + do { + if (g_cfg_byte[i].id == WID_NIL) + break; + + if (g_cfg_byte[i].id == wid) { + g_cfg_byte[i].val = info[3]; + break; + } + i++; + } while (1); + len = 2; + break; + + case WID_SHORT: + do { + if (g_cfg_hword[i].id == WID_NIL) + break; + + if (g_cfg_hword[i].id == wid) { +#ifdef BIG_ENDIAN + g_cfg_hword[i].val = (info[3] << 8) | (info[4]); +#else + g_cfg_hword[i].val = info[3] | (info[4] << 8); +#endif + break; + } + i++; + } while (1); + len = 3; + break; + + case WID_INT: + do { + if (g_cfg_word[i].id == WID_NIL) + break; + + if (g_cfg_word[i].id == wid) { +#ifdef BIG_ENDIAN + g_cfg_word[i].val = (info[3] << 24) | (info[4] << 16) | (info[5] << 8) | (info[6]); +#else + g_cfg_word[i].val = info[3] | (info[4] << 8) | (info[5] << 16) | (info[6] << 24); +#endif + break; + } + i++; + } while (1); + len = 5; + break; + + case WID_STR: + do { + if (g_cfg_str[i].id == WID_NIL) + break; + + if (g_cfg_str[i].id == wid) { + if (wid == WID_SITE_SURVEY_RESULTS) { + static int toggle; + + PRINT_INFO(GENERIC_DBG, "Site survey results received[%d]\n", + size); + + PRINT_INFO(GENERIC_DBG, "Site survey results value[%d]toggle[%d]\n", size, toggle); + i += toggle; + toggle ^= 1; + } + memcpy(g_cfg_str[i].str, &info[2], (info[2] + 1)); + break; + } + i++; + } while (1); + len = 1 + info[2]; + break; + + default: + break; + } + size -= (2 + len); + info += (2 + len); + } +} + +static int wilc_wlan_parse_info_frame(u8 *info, int size) +{ + wilc_mac_cfg_t *pd = &g_mac; + u32 wid, len; + int type = WILC_CFG_RSP_STATUS; + + wid = info[0] | (info[1] << 8); + + len = info[2]; + PRINT_INFO(GENERIC_DBG, "Status Len = %d Id= %d\n", len, wid); + if ((len == 1) && (wid == WID_STATUS)) { + pd->mac_status = info[3]; + type = WILC_CFG_RSP_STATUS; + } + + return type; +} + +/******************************************** + * + * Configuration Exported Functions + * + ********************************************/ + +int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size) +{ + u8 type = (id >> 12) & 0xf; + int ret = 0; + + if (type == 0) { /* byte command */ + if (size >= 1) + ret = wilc_wlan_cfg_set_byte(frame, offset, id, *buf); + } else if (type == 1) { /* half word command */ + if (size >= 2) + ret = wilc_wlan_cfg_set_hword(frame, offset, id, *((u16 *)buf)); + } else if (type == 2) { /* word command */ + if (size >= 4) + ret = wilc_wlan_cfg_set_word(frame, offset, id, *((u32 *)buf)); + } else if (type == 3) { /* string command */ + ret = wilc_wlan_cfg_set_str(frame, offset, id, buf, size); + } else if (type == 4) { /* binary command */ + ret = wilc_wlan_cfg_set_bin(frame, offset, id, buf, size); + } else { + g_mac.dPrint(N_ERR, "illegal id\n"); + } + + return ret; +} + +int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id) +{ + u8 *buf; + + if ((offset + 2) >= MAX_CFG_FRAME_SIZE) + return 0; + + buf = &frame[offset]; + + buf[0] = (u8)id; + buf[1] = (u8)(id >> 8); + + return 2; +} + +int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size) +{ + u32 type = (wid >> 12) & 0xf; + int i, ret = 0; + + if (wid == WID_STATUS) { + *((u32 *)buffer) = g_mac.mac_status; + return 4; + } + + i = 0; + if (type == 0) { /* byte command */ + do { + if (g_cfg_byte[i].id == WID_NIL) + break; + + if (g_cfg_byte[i].id == wid) { + memcpy(buffer, &g_cfg_byte[i].val, 1); + ret = 1; + break; + } + i++; + } while (1); + } else if (type == 1) { /* half word command */ + do { + if (g_cfg_hword[i].id == WID_NIL) + break; + + if (g_cfg_hword[i].id == wid) { + memcpy(buffer, &g_cfg_hword[i].val, 2); + ret = 2; + break; + } + i++; + } while (1); + } else if (type == 2) { /* word command */ + do { + if (g_cfg_word[i].id == WID_NIL) + break; + + if (g_cfg_word[i].id == wid) { + memcpy(buffer, &g_cfg_word[i].val, 4); + ret = 4; + break; + } + i++; + } while (1); + } else if (type == 3) { /* string command */ + do { + if (g_cfg_str[i].id == WID_NIL) + break; + + if (g_cfg_str[i].id == wid) { + u32 size = g_cfg_str[i].str[0]; + + if (buffer_size >= size) { + if (g_cfg_str[i].id == WID_SITE_SURVEY_RESULTS) { + static int toggle; + + PRINT_INFO(GENERIC_DBG, "Site survey results value[%d]\n", + size); + i += toggle; + toggle ^= 1; + + } + memcpy(buffer, &g_cfg_str[i].str[1], size); + ret = size; + } + break; + } + i++; + } while (1); + } else { + g_mac.dPrint(N_ERR, "[CFG]: illegal type (%08x)\n", wid); + } + + return ret; +} + +int wilc_wlan_cfg_indicate_rx(u8 *frame, int size, wilc_cfg_rsp_t *rsp) +{ + int ret = 1; + u8 msg_type; + u8 msg_id; + + msg_type = frame[0]; + msg_id = frame[1]; /* seq no */ + frame += 4; + size -= 4; + + /** + * The valid types of response messages are 'R' (Response), 'I' (Information), and 'N' (Network Information) + **/ + + switch (msg_type) { + case 'R': + wilc_wlan_parse_response_frame(frame, size); + rsp->type = WILC_CFG_RSP; + rsp->seq_no = msg_id; + break; + + case 'I': + rsp->type = wilc_wlan_parse_info_frame(frame, size); + rsp->seq_no = msg_id; + /*call host interface info parse as well*/ + PRINT_INFO(RX_DBG, "Info message received\n"); + GnrlAsyncInfoReceived(frame - 4, size + 4); + break; + + case 'N': + NetworkInfoReceived(frame - 4, size + 4); + rsp->type = 0; + break; + + case 'S': + PRINT_INFO(RX_DBG, "Scan Notification Received\n"); + host_int_ScanCompleteReceived(frame - 4, size + 4); + break; + + default: + PRINT_INFO(RX_DBG, "Receive unknown message type[%d-%d-%d-%d-%d-%d-%d-%d]\n", + frame[0], frame[1], frame[2], frame[3], frame[4], + frame[5], frame[6], frame[7]); + rsp->type = 0; + rsp->seq_no = msg_id; + ret = 0; + break; + } + + return ret; +} + +int wilc_wlan_cfg_init(wilc_debug_func func) +{ + memset((void *)&g_mac, 0, sizeof(wilc_mac_cfg_t)); + g_mac.dPrint = func; + return 1; +} diff --git a/kernel/drivers/staging/wilc1000/wilc_wlan_cfg.h b/kernel/drivers/staging/wilc1000/wilc_wlan_cfg.h new file mode 100644 index 000000000..30e60ec4d --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wlan_cfg.h @@ -0,0 +1,39 @@ +/* ////////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan_cfg.h */ +/* */ +/* */ +/* ///////////////////////////////////////////////////////////////////////// */ + +#ifndef WILC_WLAN_CFG_H +#define WILC_WLAN_CFG_H + +typedef struct { + u16 id; + u16 val; +} wilc_cfg_byte_t; + +typedef struct { + u16 id; + u16 val; +} wilc_cfg_hword_t; + +typedef struct { + u32 id; + u32 val; +} wilc_cfg_word_t; + +typedef struct { + u32 id; + u8 *str; +} wilc_cfg_str_t; + +int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size); +int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id); +int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size); +int wilc_wlan_cfg_indicate_rx(u8 *frame, int size, wilc_cfg_rsp_t *rsp); +int wilc_wlan_cfg_init(wilc_debug_func func); + +#endif diff --git a/kernel/drivers/staging/wilc1000/wilc_wlan_if.h b/kernel/drivers/staging/wilc1000/wilc_wlan_if.h new file mode 100644 index 000000000..be972afe6 --- /dev/null +++ b/kernel/drivers/staging/wilc1000/wilc_wlan_if.h @@ -0,0 +1,946 @@ +/* ///////////////////////////////////////////////////////////////////////// */ +/* */ +/* Copyright (c) Atmel Corporation. All rights reserved. */ +/* */ +/* Module Name: wilc_wlan_if.h */ +/* */ +/* */ +/* ///////////////////////////////////////////////////////////////////////// */ + +#ifndef WILC_WLAN_IF_H +#define WILC_WLAN_IF_H + +#include +#include "linux_wlan_common.h" + +/******************************************** + * + * Debug Flags + * + ********************************************/ + +#define N_INIT 0x00000001 +#define N_ERR 0x00000002 +#define N_TXQ 0x00000004 +#define N_INTR 0x00000008 +#define N_RXQ 0x00000010 + +/******************************************** + * + * Host Interface Defines + * + ********************************************/ + +#define HIF_SDIO (0) +#define HIF_SPI BIT(0) +#define HIF_SDIO_GPIO_IRQ BIT(2) + +/******************************************** + * + * Tx/Rx Buffer Size Defines + * + ********************************************/ + +#define CE_TX_BUFFER_SIZE (64 * 1024) +#define CE_RX_BUFFER_SIZE (384 * 1024) + +/******************************************** + * + * Wlan Interface Defines + * + ********************************************/ + +typedef struct { + u32 read_write: 1; + u32 function: 3; + u32 raw: 1; + u32 address: 17; + u32 data: 8; +} sdio_cmd52_t; + +typedef struct { + /* struct { */ + u32 read_write: 1; + u32 function: 3; + u32 block_mode: 1; + u32 increment: 1; + u32 address: 17; + u32 count: 9; + /* } bit; */ + u8 *buffer; + u32 block_size; +} sdio_cmd53_t; + +typedef struct { + int io_type; + int (*io_init)(void *); + void (*io_deinit)(void *); + union { + struct { + int (*sdio_cmd52)(sdio_cmd52_t *); + int (*sdio_cmd53)(sdio_cmd53_t *); + int (*sdio_set_max_speed)(void); + int (*sdio_set_default_speed)(void); + } sdio; + struct { + int (*spi_max_speed)(void); + int (*spi_tx)(u8 *, u32); + int (*spi_rx)(u8 *, u32); + int (*spi_trx)(u8 *, u8 *, u32); + } spi; + } u; +} wilc_wlan_io_func_t; + +#define WILC_MAC_INDICATE_STATUS 0x1 +#define WILC_MAC_STATUS_INIT -1 +#define WILC_MAC_STATUS_READY 0 +#define WILC_MAC_STATUS_CONNECT 1 + +#define WILC_MAC_INDICATE_SCAN 0x2 + +typedef struct { + void *os_private; +} wilc_wlan_os_context_t; + +typedef struct { + wilc_wlan_os_context_t os_context; + wilc_wlan_io_func_t io_func; +} wilc_wlan_inp_t; + +struct tx_complete_data { + int size; + void *buff; + u8 *pBssid; + struct sk_buff *skb; +}; + +typedef void (*wilc_tx_complete_func_t)(void *, int); + +#define WILC_TX_ERR_NO_BUF (-2) + +/******************************************** + * + * Wlan Configuration ID + * + ********************************************/ + +#define MAX_SSID_LEN 33 +#define MAX_RATES_SUPPORTED 12 + +#define INFINITE_SLEEP_TIME ((u32)0xFFFFFFFF) + +typedef enum { + SUPP_RATES_IE = 1, + EXT_SUPP_RATES_IE = 50, + HT_CAPABILITY_IE = 45, + RSN_IE = 48, + WPA_IE = 221, + WMM_IE = 221, + P2P_IE = 221, +} BEACON_IE; + +typedef enum { + INFRASTRUCTURE = 0, + INDEPENDENT, + AP, +} BSSTYPE_T; + +typedef enum { + RATE_AUTO = 0, + RATE_1MB = 1, + RATE_2MB = 2, + RATE_5MB = 5, + RATE_6MB = 6, + RATE_9MB = 9, + RATE_11MB = 11, + RATE_12MB = 12, + RATE_18MB = 18, + RATE_24MB = 24, + RATE_26MB = 36, + RATE_48MB = 48, + RATE_54MB = 54 +} TX_RATE_T; + +typedef enum { + B_ONLY_MODE = 0, /* 1, 2 M, otherwise 5, 11 M */ + G_ONLY_MODE, /* 6,12,24 otherwise 9,18,36,48,54 */ + G_MIXED_11B_1_MODE, /* 1,2,5.5,11 otherwise all on */ + G_MIXED_11B_2_MODE, /* 1,2,5,11,6,12,24 otherwise all on */ +} G_OPERATING_MODE_T; + +typedef enum { + G_SHORT_PREAMBLE = 0, /* Short Preamble */ + G_LONG_PREAMBLE = 1, /* Long Preamble */ + G_AUTO_PREAMBLE = 2, /* Auto Preamble Selection */ +} G_PREAMBLE_T; + +#define MAC_CONNECTED 1 +#define MAC_DISCONNECTED 0 + +#define SCAN_DONE TRUE +typedef enum { + PASSIVE_SCAN = 0, + ACTIVE_SCAN = 1, +} SCANTYPE_T; + +typedef enum { + NO_POWERSAVE = 0, + MIN_FAST_PS = 1, + MAX_FAST_PS = 2, + MIN_PSPOLL_PS = 3, + MAX_PSPOLL_PS = 4 +} USER_PS_MODE_T; + +typedef enum { + CHIP_WAKEDUP = 0, + CHIP_SLEEPING_AUTO = 1, + CHIP_SLEEPING_MANUAL = 2 +} CHIP_PS_STATE_T; + +typedef enum { + ACQUIRE_ONLY = 0, + ACQUIRE_AND_WAKEUP = 1, +} BUS_ACQUIRE_T; + +typedef enum { + RELEASE_ONLY = 0, + RELEASE_ALLOW_SLEEP = 1, +} BUS_RELEASE_T; + +typedef enum { + NO_SECURITY = 0, + WEP_40 = 0x3, + WEP_104 = 0x7, + WPA_AES = 0x29, + WPA_TKIP = 0x49, + WPA_AES_TKIP = 0x69, /* Aes or Tkip */ + WPA2_AES = 0x31, + WPA2_TKIP = 0x51, + WPA2_AES_TKIP = 0x71, /* Aes or Tkip */ +} SECURITY_T; + +enum AUTHTYPE { + OPEN_SYSTEM = 1, + SHARED_KEY = 2, + ANY = 3, + IEEE8021 = 5 +}; + +enum SITESURVEY { + SITE_SURVEY_1CH = 0, + SITE_SURVEY_ALL_CH = 1, + SITE_SURVEY_OFF = 2 +}; + +typedef enum { + NORMAL_ACK = 0, + NO_ACK, +} ACK_POLICY_T; + +typedef enum { + DONT_RESET = 0, + DO_RESET = 1, + NO_REQUEST = 2, +} RESET_REQ_T; + +typedef enum { + REKEY_DISABLE = 1, + REKEY_TIME_BASE, + REKEY_PKT_BASE, + REKEY_TIME_PKT_BASE +} RSNA_REKEY_POLICY_T; + +typedef enum { + FILTER_NO = 0x00, + FILTER_AP_ONLY = 0x01, + FILTER_STA_ONLY = 0x02 +} SCAN_CLASS_FITLER_T; + +typedef enum { + PRI_HIGH_RSSI = 0x00, + PRI_LOW_RSSI = 0x04, + PRI_DETECT = 0x08 +} SCAN_PRI_T; + +typedef enum { + CH_FILTER_OFF = 0x00, + CH_FILTER_ON = 0x10 +} CH_FILTER_T; + +typedef enum { + AUTO_PROT = 0, /* Auto */ + NO_PROT, /* Do not use any protection */ + ERP_PROT, /* Protect all ERP frame exchanges */ + HT_PROT, /* Protect all HT frame exchanges */ + GF_PROT, /* Protect all GF frame exchanges */ +} N_PROTECTION_MODE_T; + +typedef enum { + G_SELF_CTS_PROT, + G_RTS_CTS_PROT, +} G_PROTECTION_MODE_T; + +typedef enum { + HT_MIXED_MODE = 1, + HT_ONLY_20MHZ_MODE, + HT_ONLY_20_40MHZ_MODE, +} N_OPERATING_MODE_T; + +typedef enum { + NO_DETECT = 0, + DETECT_ONLY = 1, + DETECT_PROTECT = 2, + DETECT_PROTECT_REPORT = 3, +} N_OBSS_DETECTION_T; + +typedef enum { + RTS_CTS_NONHT_PROT = 0, /* RTS-CTS at non-HT rate */ + FIRST_FRAME_NONHT_PROT, /* First frame at non-HT rate */ + LSIG_TXOP_PROT, /* LSIG TXOP Protection */ + FIRST_FRAME_MIXED_PROT, /* First frame at Mixed format */ +} N_PROTECTION_TYPE_T; + +typedef enum { + STATIC_MODE = 1, + DYNAMIC_MODE = 2, + MIMO_MODE = 3, /* power save disable */ +} N_SMPS_MODE_T; + +typedef enum { + DISABLE_SELF_CTS, + ENABLE_SELF_CTS, + DISABLE_TX_ABORT, + ENABLE_TX_ABORT, + HW_TRIGGER_ABORT, + SW_TRIGGER_ABORT, +} TX_ABORT_OPTION_T; + +enum WID_TYPE { + WID_CHAR = 0, + WID_SHORT = 1, + WID_INT = 2, + WID_STR = 3, + WID_BIN_DATA = 4, + WID_BIN = 5, + WID_IP = 6, + WID_ADR = 7, + WID_UNDEF = 8, + WID_TYPE_FORCE_32BIT = 0xFFFFFFFF +}; + +typedef enum { + WID_NIL = 0xffff, + + /* + * BSS Type + * ----------------------------------------------------------- + * Configuration : Infrastructure Independent Access Point + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_BSS_TYPE = 0x0000, + + /* + * Transmit Rate + * ----------------------------------------------------------- + * Configuration : 1 2 5.5 11 6 9 12 18 24 36 48 54 + * Values to set : 1 2 5 11 6 9 12 18 24 36 48 54 + * ----------------------------------------------------------- + */ + WID_CURRENT_TX_RATE = 0x0001, + + /* + * Channel + * ----------------------------------------------------------- + * Configuration(g) : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + * Values to set : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + * ----------------------------------------------------------- + */ + WID_CURRENT_CHANNEL = 0x0002, + + /* + * Preamble + * ----------------------------------------------------------- + * Configuration : short long Auto + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_PREAMBLE = 0x0003, + + /* + * 11g operating mode (ignored if 11g not present) + * ----------------------------------------------------------- + * Configuration : HighPerf Compat(RSet #1) Compat(RSet #2) + * Values to set : 1 2 3 + * ----------------------------------------------------------- + */ + WID_11G_OPERATING_MODE = 0x0004, + + /* + * Mac status (response only) + * ----------------------------------------------------------- + * Configuration : disconnect connect + * Values to get : 0 1 + * ----------------------------------------------------------- + */ + WID_STATUS = 0x0005, + + /* + * Scan type + * ----------------------------------------------------------- + * Configuration : Passive Scanning Active Scanning + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_SCAN_TYPE = 0x0007, + + /* + * Key Id (WEP default key Id) + * ----------------------------------------------------------- + * Configuration : Any value between 0 to 3 + * Values to set : Same value. Default is 0 + * ----------------------------------------------------------- + */ + WID_KEY_ID = 0x0009, + + /* + * QoS Enable + * ----------------------------------------------------------- + * Configuration : QoS Disable WMM Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_QOS_ENABLE = 0x000A, + + /* + * Power Management + * ----------------------------------------------------------- + * Configuration : NO_POWERSAVE MIN_POWERSAVE MAX_POWERSAVE + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_POWER_MANAGEMENT = 0x000B, + + /* + * WEP/802 11I Configuration + * ----------------------------------------------------------- + * Configuration:Disable WP40 WP104 WPA-AES WPA-TKIP RSN-AES RSN-TKIP + * Values (0x) : 00 03 07 29 49 31 51 + * Configuration:WPA-AES+TKIP RSN-AES+TKIP + * Values (0x) : 69 71 + * ----------------------------------------------------------- + */ + WID_11I_MODE = 0x000C, + + /* + * WEP Configuration: Used in BSS STA mode only when WEP is enabled + * ----------------------------------------------------------- + * Configuration : Open System Shared Key Any Type | 802.1x Auth + * Values (0x) : 01 02 03 | BIT2 + * ----------------------------------------------------------- + */ + WID_AUTH_TYPE = 0x000D, + + /* + * Site Survey Type + * ----------------------------------------------------------- + * Configuration : Values to set + * Survey 1 Channel : 0 + * survey all Channels : 1 + * Disable Site Survey : 2 + * ----------------------------------------------------------- + */ + WID_SITE_SURVEY = 0x000E, + + /* + * Listen Interval + * ----------------------------------------------------------- + * Configuration : Any value between 1 to 255 + * Values to set : Same value. Default is 3 + * ----------------------------------------------------------- + */ + WID_LISTEN_INTERVAL = 0x000F, + + /* + * DTIM Period + * ----------------------------------------------------------- + * Configuration : Any value between 1 to 255 + * Values to set : Same value. Default is 3 + * ----------------------------------------------------------- + */ + WID_DTIM_PERIOD = 0x0010, + + /* + * ACK Policy + * ----------------------------------------------------------- + * Configuration : Normal Ack No Ack + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_ACK_POLICY = 0x0011, + + /* + * Reset MAC (Set only) + * ----------------------------------------------------------- + * Configuration : Don't Reset Reset No Request + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_RESET = 0x0012, + + /* + * Broadcast SSID Option: Setting this will adhere to "" SSID element + * ----------------------------------------------------------- + * Configuration : Enable Disable + * Values to set : 1 0 + * ----------------------------------------------------------- + */ + WID_BCAST_SSID = 0x0015, + + /* + * Disconnect (Station) + * ----------------------------------------------------------- + * Configuration : Association ID + * Values to set : Association ID + * ----------------------------------------------------------- + */ + WID_DISCONNECT = 0x0016, + + /* + * 11a Tx Power Level + * ----------------------------------------------------------- + * Configuration : Sets TX Power (Higher the value greater the power) + * Values to set : Any value between 0 and 63 (inclusive Default 48) + * ----------------------------------------------------------- + */ + WID_TX_POWER_LEVEL_11A = 0x0018, + + /* + * Group Key Update Policy Selection + * ----------------------------------------------------------- + * Configuration : Disabled timeBased packetBased timePacketBased + * Values to set : 1 2 3 4 + * ----------------------------------------------------------- + */ + WID_REKEY_POLICY = 0x0019, + + /* + * Allow Short Slot + * ----------------------------------------------------------- + * Configuration : Disallow Short Slot Allow Short Slot + * (Enable Only Long Slot) (Enable Short Slot if applicable) + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_SHORT_SLOT_ALLOWED = 0x001A, + + WID_PHY_ACTIVE_REG = 0x001B, + + /* + * 11b Tx Power Level + * ----------------------------------------------------------- + * Configuration : Sets TX Power (Higher the value greater the power) + * Values to set : Any value between 0 and 63 (inclusive Default 48) + * ----------------------------------------------------------- + */ + WID_TX_POWER_LEVEL_11B = 0x001D, + + /* + * Scan Request + * ----------------------------------------------------------- + * Configuration : Request default scan + * Values to set : 0 + * ----------------------------------------------------------- + */ + WID_START_SCAN_REQ = 0x001E, + + /* + * Rssi (get only) + * ----------------------------------------------------------- + * Configuration : + * Values to get : Rssi value + * ----------------------------------------------------------- + */ + WID_RSSI = 0x001F, + + /* + * Join Request + * ----------------------------------------------------------- + * Configuration : Request to join + * Values to set : index of scan result + * ----------------------------------------------------------- + */ + WID_JOIN_REQ = 0x0020, + + WID_LINKSPEED = 0x0026, + + /* + * Enable User Control of TX Power + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_USER_CONTROL_ON_TX_POWER = 0x0027, + + WID_MEMORY_ACCESS_8BIT = 0x0029, + + /* + * Enable Auto RX Sensitivity feature + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_AUTO_RX_SENSITIVITY = 0x0032, + + /* + * Receive Buffer Based Ack + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_DATAFLOW_CONTROL = 0x0033, + + /* + * Scan Filter + * ----------------------------------------------------------- + * Configuration : Class No filter AP only Station Only + * Values to set : 0 1 2 + * Configuration : Priority High Rssi Low Rssi Detect + * Values to set : 0 0x4 0x0 + * Configuration : Channel filter off filter on + * Values to set : 0 0x10 + * ----------------------------------------------------------- + */ + WID_SCAN_FILTER = 0x0036, + + /* + * Link Loss Threshold (measure in the beacon period) + * ----------------------------------------------------------- + * Configuration : Any value between 10 and 254(Set to 255 disable) + * Values to set : Same value. Default is 10 + * ----------------------------------------------------------- + */ + WID_LINK_LOSS_THRESHOLD = 0x0037, + + WID_ABORT_RUNNING_SCAN = 0x003E, + + /* NMAC Character WID list */ + WID_WPS_START = 0x0043, + + /* + * Protection mode for MAC + * ----------------------------------------------------------- + * Configuration : Auto No protection ERP HT GF + * Values to set : 0 1 2 3 4 + * ----------------------------------------------------------- + */ + WID_11N_PROT_MECH = 0x0080, + + /* + * ERP Protection type for MAC + * ----------------------------------------------------------- + * Configuration : Self-CTS RTS-CTS + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_ERP_PROT_TYPE = 0x0081, + + /* + * HT Option Enable + * ----------------------------------------------------------- + * Configuration : HT Enable HT Disable + * Values to set : 1 0 + * ----------------------------------------------------------- + */ + WID_11N_ENABLE = 0x0082, + + /* + * 11n Operating mode (Note that 11g operating mode will also be + * used in addition to this, if this is set to HT Mixed mode) + * ----------------------------------------------------------- + * Configuration : HT Mixed HT Only-20MHz HT Only-20/40MHz + * Values to set : 1 2 3 + * ----------------------------------------------------------- + */ + WID_11N_OPERATING_MODE = 0x0083, + + /* + * 11n OBSS non-HT STA Detection flag + * ----------------------------------------------------------- + * Configuration : Do not detect + * Values to set : 0 + * Configuration : Detect, do not protect or report + * Values to set : 1 + * Configuration : Detect, protect and do not report + * Values to set : 2 + * Configuration : Detect, protect and report to other BSS + * Values to set : 3 + * ----------------------------------------------------------- + */ + WID_11N_OBSS_NONHT_DETECTION = 0x0084, + + /* + * 11n HT Protection Type + * ----------------------------------------------------------- + * Configuration : RTS-CTS First Frame Exchange at non-HT-rate + * Values to set : 0 1 + * Configuration : LSIG TXOP First Frame Exchange in Mixed Fmt + * Values to set : 2 3 + * ----------------------------------------------------------- + */ + WID_11N_HT_PROT_TYPE = 0x0085, + + /* + * 11n RIFS Protection Enable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_RIFS_PROT_ENABLE = 0x0086, + + /* + * SMPS Mode + * ----------------------------------------------------------- + * Configuration : Static Dynamic MIMO (Power Save Disabled) + * Values to set : 1 2 3 + * ----------------------------------------------------------- + */ + WID_11N_SMPS_MODE = 0x0087, + + /* + * Current transmit MCS + * ----------------------------------------------------------- + * Configuration : MCS Index for data rate + * Values to set : 0 to 7 + * ----------------------------------------------------------- + */ + WID_11N_CURRENT_TX_MCS = 0x0088, + + WID_11N_PRINT_STATS = 0x0089, + + /* + * 11n Short GI Enable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_SHORT_GI_ENABLE = 0x008D, + + /* + * 11n RIFS Enable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_RIFS_MODE = 0x0094, + + /* + * TX Abort Feature + * ----------------------------------------------------------- + * Configuration : Disable Self CTS Enable Self CTS + * Values to set : 0 1 + * Configuration : Disable TX Abort Enable TX Abort + * Values to set : 2 3 + * Configuration : Enable HW TX Abort Enable SW TX Abort + * Values to set : 4 5 + * ----------------------------------------------------------- + */ + WID_TX_ABORT_CONFIG = 0x00A1, + + WID_REG_TSSI_11B_VALUE = 0x00A6, + WID_REG_TSSI_11G_VALUE = 0x00A7, + WID_REG_TSSI_11N_VALUE = 0x00A8, + WID_TX_CALIBRATION = 0x00A9, + WID_DSCR_TSSI_11B_VALUE = 0x00AA, + WID_DSCR_TSSI_11G_VALUE = 0x00AB, + WID_DSCR_TSSI_11N_VALUE = 0x00AC, + + /* + * Immediate Block-Ack Support + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_IMMEDIATE_BA_ENABLED = 0x00AF, + + /* + * TXOP Disable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 1 0 + * ----------------------------------------------------------- + */ + WID_11N_TXOP_PROT_DISABLE = 0x00B0, + + WID_TX_POWER_LEVEL_11N = 0x00B1, + + /* Custom Character WID list */ + WID_PC_TEST_MODE = 0x00C8, + /* SCAN Complete notification WID*/ + WID_SCAN_COMPLETE = 0x00C9, + + WID_DEL_BEACON = 0x00CA, + + WID_LOGTerminal_Switch = 0x00CD, + /* EMAC Short WID list */ + /* RTS Threshold */ + /* + * ----------------------------------------------------------- + * Configuration : Any value between 256 to 2347 + * Values to set : Same value. Default is 2347 + * ----------------------------------------------------------- + */ + WID_RTS_THRESHOLD = 0x1000, + + /* + * Fragmentation Threshold + * ----------------------------------------------------------- + * Configuration : Any value between 256 to 2346 + * Values to set : Same value. Default is 2346 + * ----------------------------------------------------------- + */ + WID_FRAG_THRESHOLD = 0x1001, + + WID_SHORT_RETRY_LIMIT = 0x1002, + WID_LONG_RETRY_LIMIT = 0x1003, + WID_BEACON_INTERVAL = 0x1006, + WID_MEMORY_ACCESS_16BIT = 0x1008, + WID_RX_SENSE = 0x100B, + WID_ACTIVE_SCAN_TIME = 0x100C, + WID_PASSIVE_SCAN_TIME = 0x100D, + + WID_SITE_SURVEY_SCAN_TIME = 0x100E, + WID_JOIN_START_TIMEOUT = 0x100F, + WID_AUTH_TIMEOUT = 0x1010, + WID_ASOC_TIMEOUT = 0x1011, + WID_11I_PROTOCOL_TIMEOUT = 0x1012, + WID_EAPOL_RESPONSE_TIMEOUT = 0x1013, + + /* NMAC Short WID list */ + WID_11N_SIG_QUAL_VAL = 0x1085, + WID_CCA_THRESHOLD = 0x1087, + + /* Custom Short WID list */ + + /* EMAC Integer WID list */ + WID_FAILED_COUNT = 0x2000, + WID_RETRY_COUNT = 0x2001, + WID_MULTIPLE_RETRY_COUNT = 0x2002, + WID_FRAME_DUPLICATE_COUNT = 0x2003, + WID_ACK_FAILURE_COUNT = 0x2004, + WID_RECEIVED_FRAGMENT_COUNT = 0x2005, + WID_MCAST_RECEIVED_FRAME_COUNT = 0x2006, + WID_FCS_ERROR_COUNT = 0x2007, + WID_SUCCESS_FRAME_COUNT = 0x2008, + WID_HUT_TX_COUNT = 0x200A, + WID_TX_FRAGMENT_COUNT = 0x200B, + WID_TX_MULTICAST_FRAME_COUNT = 0x200C, + WID_RTS_SUCCESS_COUNT = 0x200D, + WID_RTS_FAILURE_COUNT = 0x200E, + WID_WEP_UNDECRYPTABLE_COUNT = 0x200F, + WID_REKEY_PERIOD = 0x2010, + WID_REKEY_PACKET_COUNT = 0x2011, + WID_1X_SERV_ADDR = 0x2012, + WID_STACK_IP_ADDR = 0x2013, + WID_STACK_NETMASK_ADDR = 0x2014, + WID_HW_RX_COUNT = 0x2015, + WID_MEMORY_ADDRESS = 0x201E, + WID_MEMORY_ACCESS_32BIT = 0x201F, + WID_RF_REG_VAL = 0x2021, + + /* NMAC Integer WID list */ + WID_11N_PHY_ACTIVE_REG_VAL = 0x2080, + + /* Custom Integer WID list */ + WID_GET_INACTIVE_TIME = 0x2084, + WID_SET_DRV_HANDLER = 0X2085, + WID_SET_OPERATION_MODE = 0X2086, + /* EMAC String WID list */ + WID_SSID = 0x3000, + WID_FIRMWARE_VERSION = 0x3001, + WID_OPERATIONAL_RATE_SET = 0x3002, + WID_BSSID = 0x3003, + WID_WEP_KEY_VALUE = 0x3004, + WID_11I_PSK = 0x3008, + WID_11E_P_ACTION_REQ = 0x3009, + WID_1X_KEY = 0x300A, + WID_HARDWARE_VERSION = 0x300B, + WID_MAC_ADDR = 0x300C, + WID_HUT_DEST_ADDR = 0x300D, + WID_PHY_VERSION = 0x300F, + WID_SUPP_USERNAME = 0x3010, + WID_SUPP_PASSWORD = 0x3011, + WID_SITE_SURVEY_RESULTS = 0x3012, + WID_RX_POWER_LEVEL = 0x3013, + WID_DEL_ALL_RX_BA = 0x3014, + WID_SET_STA_MAC_INACTIVE_TIME = 0x3017, + WID_ADD_WEP_KEY = 0x3019, + WID_REMOVE_WEP_KEY = 0x301A, + WID_ADD_PTK = 0x301B, + WID_ADD_RX_GTK = 0x301C, + WID_ADD_TX_GTK = 0x301D, + WID_REMOVE_KEY = 0x301E, + WID_ASSOC_REQ_INFO = 0x301F, + WID_ASSOC_RES_INFO = 0x3020, + WID_MANUFACTURER = 0x3026, /*Added for CAPI tool */ + WID_MODEL_NAME = 0x3027, /*Added for CAPI tool */ + WID_MODEL_NUM = 0x3028, /*Added for CAPI tool */ + WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */ + + /* NMAC String WID list */ + WID_11N_P_ACTION_REQ = 0x3080, + WID_HUT_TEST_ID = 0x3081, + WID_PMKID_INFO = 0x3082, + WID_FIRMWARE_INFO = 0x3083, + WID_REGISTER_FRAME = 0x3084, + WID_DEL_ALL_STA = 0x3085, + WID_REMAIN_ON_CHAN = 0x3996, + WID_SSID_PROBE_REQ = 0x3997, + WID_JOIN_REQ_EXTENDED = 0x3998, + + WID_IP_ADDRESS = 0x3999, + + /* Custom String WID list */ + + /* EMAC Binary WID list */ + WID_UAPSD_CONFIG = 0x4001, + WID_UAPSD_STATUS = 0x4002, + WID_WMM_AP_AC_PARAMS = 0x4003, + WID_WMM_STA_AC_PARAMS = 0x4004, + WID_NETWORK_INFO = 0x4005, + WID_STA_JOIN_INFO = 0x4006, + WID_CONNECTED_STA_LIST = 0x4007, + + /* NMAC Binary WID list */ + WID_11N_AUTORATE_TABLE = 0x4080, + + WID_SCAN_CHANNEL_LIST = 0x4084, + + WID_INFO_ELEMENT_PROBE = 0x4085, + WID_INFO_ELEMENT_ASSOCIATE = 0x4086, + WID_ADD_STA = 0X4087, + WID_REMOVE_STA = 0X4088, + WID_EDIT_STA = 0X4089, + WID_ADD_BEACON = 0x408a, + + WID_SETUP_MULTICAST_FILTER = 0x408b, + + /* Miscellaneous WIDs */ + WID_ALL = 0x7FFE, + WID_MAX = 0xFFFF +} WID_T; + +int wilc_wlan_init(wilc_wlan_inp_t *inp); + +void wilc_bus_set_max_speed(void); +void wilc_bus_set_default_speed(void); +u32 wilc_get_chipid(u8 update); + +#endif -- cgit 1.2.3-korg