From 23f4e9ed05abe1145835976966d270b8a9bc5621 Mon Sep 17 00:00:00 2001 From: "Jude.Lee" Date: Thu, 22 Oct 2015 18:29:56 +0900 Subject: [PATCH] Dos to unix text file format convert --- wilc3000/at_pwr_dev_main.c | 2216 +++++++++++----------- wilc3000/atl_error_support.h | 162 +- wilc3000/atl_msg_queue.c | 366 ++-- wilc3000/atl_msg_queue.h | 136 +- wilc3000/core_configurator.c | 3356 +++++++++++++++++----------------- wilc3000/core_configurator.h | 488 ++--- wilc3000/linux_wlan_sdio.c | 640 +++---- wilc3000/linux_wlan_sdio.h | 80 +- wilc3000/linux_wlan_spi.c | 378 ++-- wilc3000/linux_wlan_spi.h | 62 +- wilc3000/wilc_sdio.c | 2268 +++++++++++------------ wilc3000/wilc_spi.c | 2692 +++++++++++++-------------- 12 files changed, 6422 insertions(+), 6422 deletions(-) diff --git a/wilc3000/at_pwr_dev_main.c b/wilc3000/at_pwr_dev_main.c index 18970e8..a9e5ffe 100644 --- a/wilc3000/at_pwr_dev_main.c +++ b/wilc3000/at_pwr_dev_main.c @@ -1,1109 +1,1109 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "at_pwr_dev.h" -#include "linux_wlan_common.h" -#include "host_interface.h" -#include "wilc_wlan.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef WILC_SDIO -#include "linux_wlan_sdio.h" -#include -#include -#else -#include "linux_wlan_spi.h" -#endif /* WILC_SDIO */ -#ifdef WILC_FULLY_HOSTING_AP -#include "wilc_host_ap.h" -#endif /* WILC_FULLY_HOSTING_AP */ - -#define DOWNLOAD_BT_FW_ONCE - -unsigned int int_clrd; - -struct pwr_dev_t { - struct mutex cs; - uint8_t bus_registered[PWR_DEV_SRC_MAX]; - uint8_t power_status[PWR_DEV_SRC_MAX]; - uint8_t keep_awake[PWR_DEV_SRC_MAX]; - struct wilc_hif_func hif_func; - struct mutex hif_cs; -#ifdef DOWNLOAD_BT_FW_ONCE - uint8_t is_bt_fw_ready; -#endif /* DOWNLOAD_BT_FW_ONCE */ -#ifdef WILC_BT_COEXISTENCE - WILCpfChangeCoexMode pfChangeCoexMode; -#endif -}; - -typedef int (cmd_handler)(int); - -struct cmd_handle_entry { - const char *cmd_str; - cmd_handler *handle_cmd; -}; - - -static dev_t chc_dev_no; /* Global variable for the first device number */ -static struct cdev str_chc_dev; /* Global variable for the character - device structure */ -static struct class *chc_dev_class; /* Global variable for the device class */ -struct device *dev; -struct pwr_dev_t pwr_dev; - -#ifdef WILC_SDIO -struct semaphore sdio_probe_sync; -#else -struct semaphore spi_probe_sync; -#endif /* WILC_SDIO */ - -/* Character device operations*/ -static int pwr_dev_open(struct inode *i, struct file *f); -static int pwr_dev_close(struct inode *i, struct file *f); -static ssize_t pwr_dev_read(struct file *f, char __user *buf, size_t len, - loff_t *off); -static ssize_t pwr_dev_write(struct file *f, const char __user *buff, - size_t len, loff_t *off); -/* Command handlers */ -static int cmd_handle_bt_download_fw(int source); -static int cmd_handle_bt_power_up(int source); -static int cmd_handle_bt_power_down(int source); -static int cmd_handle_bt_fw_chip_wake_up(int source); -static int cmd_handle_bt_fw_chip_allow_sleep(int source); - -static int wilc_bt_firmware_download(void); -static int wilc_bt_start(void); -static int linux_wlan_device_power(int on_off); -static int linux_wlan_device_detection(int on_off); -static void prepare_inp(struct wilc_wlan_inp *nwi); - -static const struct cmd_handle_entry cmd_table[] = { - {"BT_DOWNLOAD_FW", cmd_handle_bt_download_fw}, - {"BT_POWER_UP", cmd_handle_bt_power_up}, - {"BT_POWER_DOWN", cmd_handle_bt_power_down}, - {"BT_FW_CHIP_WAKEUP", cmd_handle_bt_fw_chip_wake_up}, - {"BT_FW_CHIP_ALLOW_SLEEP", cmd_handle_bt_fw_chip_allow_sleep}, - /* Keep the NULL handler at the end of the table */ - {(const char *) NULL, NULL}, -}; - -static const struct file_operations pugs_fops = { - .owner = THIS_MODULE, - .open = pwr_dev_open, - .release = pwr_dev_close, - .read = pwr_dev_read, - .write = pwr_dev_write -}; - -enum CHIP_PS_STATE genuChipPSstate = CHIP_WAKEDUP; -EXPORT_SYMBOL(genuChipPSstate); - -enum CHIP_PS_STATE genuChipPSstateFromWifi; - -int at_pwr_dev_init(void) -{ - int ret = 0; - - PRINT_D(PWRDEV_DBG, "at_pwr_dev: registered\n"); - memset(&pwr_dev, 0, sizeof(pwr_dev)); - ret = alloc_chrdev_region(&chc_dev_no, 0, 1, "atmel"); - if (ret < 0) - return ret; - chc_dev_class = class_create(THIS_MODULE, "atmel"); - if (IS_ERR(chc_dev_class)) { - unregister_chrdev_region(chc_dev_no, 1); - return PTR_ERR(chc_dev_class); - } - dev = device_create(chc_dev_class, NULL, chc_dev_no, NULL, - "at_pwr_dev"); - if (IS_ERR(dev)) { - class_destroy(chc_dev_class); - unregister_chrdev_region(chc_dev_no, 1); - return PTR_ERR(dev); - } - - cdev_init(&str_chc_dev, &pugs_fops); - cdev_add(&str_chc_dev, chc_dev_no, 1); - if (ret < 0) { - device_destroy(chc_dev_class, chc_dev_no); - class_destroy(chc_dev_class); - unregister_chrdev_region(chc_dev_no, 1); - return ret; - } - -#ifdef WILC_SDIO - sema_init(&sdio_probe_sync, 0); -#else - sema_init(&spi_probe_sync, 0); -#endif /* WILC_SDIO */ - - mutex_init(&pwr_dev.cs); - mutex_init(&pwr_dev.hif_cs); - - return ret; +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "at_pwr_dev.h" +#include "linux_wlan_common.h" +#include "host_interface.h" +#include "wilc_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WILC_SDIO +#include "linux_wlan_sdio.h" +#include +#include +#else +#include "linux_wlan_spi.h" +#endif /* WILC_SDIO */ +#ifdef WILC_FULLY_HOSTING_AP +#include "wilc_host_ap.h" +#endif /* WILC_FULLY_HOSTING_AP */ + +#define DOWNLOAD_BT_FW_ONCE + +unsigned int int_clrd; + +struct pwr_dev_t { + struct mutex cs; + uint8_t bus_registered[PWR_DEV_SRC_MAX]; + uint8_t power_status[PWR_DEV_SRC_MAX]; + uint8_t keep_awake[PWR_DEV_SRC_MAX]; + struct wilc_hif_func hif_func; + struct mutex hif_cs; +#ifdef DOWNLOAD_BT_FW_ONCE + uint8_t is_bt_fw_ready; +#endif /* DOWNLOAD_BT_FW_ONCE */ +#ifdef WILC_BT_COEXISTENCE + WILCpfChangeCoexMode pfChangeCoexMode; +#endif +}; + +typedef int (cmd_handler)(int); + +struct cmd_handle_entry { + const char *cmd_str; + cmd_handler *handle_cmd; +}; + + +static dev_t chc_dev_no; /* Global variable for the first device number */ +static struct cdev str_chc_dev; /* Global variable for the character + device structure */ +static struct class *chc_dev_class; /* Global variable for the device class */ +struct device *dev; +struct pwr_dev_t pwr_dev; + +#ifdef WILC_SDIO +struct semaphore sdio_probe_sync; +#else +struct semaphore spi_probe_sync; +#endif /* WILC_SDIO */ + +/* Character device operations*/ +static int pwr_dev_open(struct inode *i, struct file *f); +static int pwr_dev_close(struct inode *i, struct file *f); +static ssize_t pwr_dev_read(struct file *f, char __user *buf, size_t len, + loff_t *off); +static ssize_t pwr_dev_write(struct file *f, const char __user *buff, + size_t len, loff_t *off); +/* Command handlers */ +static int cmd_handle_bt_download_fw(int source); +static int cmd_handle_bt_power_up(int source); +static int cmd_handle_bt_power_down(int source); +static int cmd_handle_bt_fw_chip_wake_up(int source); +static int cmd_handle_bt_fw_chip_allow_sleep(int source); + +static int wilc_bt_firmware_download(void); +static int wilc_bt_start(void); +static int linux_wlan_device_power(int on_off); +static int linux_wlan_device_detection(int on_off); +static void prepare_inp(struct wilc_wlan_inp *nwi); + +static const struct cmd_handle_entry cmd_table[] = { + {"BT_DOWNLOAD_FW", cmd_handle_bt_download_fw}, + {"BT_POWER_UP", cmd_handle_bt_power_up}, + {"BT_POWER_DOWN", cmd_handle_bt_power_down}, + {"BT_FW_CHIP_WAKEUP", cmd_handle_bt_fw_chip_wake_up}, + {"BT_FW_CHIP_ALLOW_SLEEP", cmd_handle_bt_fw_chip_allow_sleep}, + /* Keep the NULL handler at the end of the table */ + {(const char *) NULL, NULL}, +}; + +static const struct file_operations pugs_fops = { + .owner = THIS_MODULE, + .open = pwr_dev_open, + .release = pwr_dev_close, + .read = pwr_dev_read, + .write = pwr_dev_write +}; + +enum CHIP_PS_STATE genuChipPSstate = CHIP_WAKEDUP; +EXPORT_SYMBOL(genuChipPSstate); + +enum CHIP_PS_STATE genuChipPSstateFromWifi; + +int at_pwr_dev_init(void) +{ + int ret = 0; + + PRINT_D(PWRDEV_DBG, "at_pwr_dev: registered\n"); + memset(&pwr_dev, 0, sizeof(pwr_dev)); + ret = alloc_chrdev_region(&chc_dev_no, 0, 1, "atmel"); + if (ret < 0) + return ret; + chc_dev_class = class_create(THIS_MODULE, "atmel"); + if (IS_ERR(chc_dev_class)) { + unregister_chrdev_region(chc_dev_no, 1); + return PTR_ERR(chc_dev_class); + } + dev = device_create(chc_dev_class, NULL, chc_dev_no, NULL, + "at_pwr_dev"); + if (IS_ERR(dev)) { + class_destroy(chc_dev_class); + unregister_chrdev_region(chc_dev_no, 1); + return PTR_ERR(dev); + } + + cdev_init(&str_chc_dev, &pugs_fops); + cdev_add(&str_chc_dev, chc_dev_no, 1); + if (ret < 0) { + device_destroy(chc_dev_class, chc_dev_no); + class_destroy(chc_dev_class); + unregister_chrdev_region(chc_dev_no, 1); + return ret; + } + +#ifdef WILC_SDIO + sema_init(&sdio_probe_sync, 0); +#else + sema_init(&spi_probe_sync, 0); +#endif /* WILC_SDIO */ + + mutex_init(&pwr_dev.cs); + mutex_init(&pwr_dev.hif_cs); + + return ret; +} + +int at_pwr_dev_deinit(void) +{ + PRINT_D(PWRDEV_DBG, "at_pwr_dev: deinit\n"); + + if (&pwr_dev.hif_cs != NULL) + mutex_destroy(&pwr_dev.hif_cs); + + if (&pwr_dev.cs != NULL) + mutex_destroy(&pwr_dev.cs); + + cdev_del(&str_chc_dev); + device_destroy(chc_dev_class, chc_dev_no); + class_destroy(chc_dev_class); + unregister_chrdev_region(chc_dev_no, 1); + PRINT_D(PWRDEV_DBG, "at_pwr_dev: unregistered\n"); + return 0; +} + +struct mutex *at_pwr_dev_get_bus_lock() +{ + return &pwr_dev.hif_cs; +} +EXPORT_SYMBOL(at_pwr_dev_get_bus_lock); + +int at_pwr_power_down(int source) +{ + mutex_lock(&pwr_dev.cs); + + PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), + pwr_dev.power_status[PWR_DEV_SRC_WIFI], + pwr_dev.power_status[PWR_DEV_SRC_BT]); + + if (pwr_dev.power_status[source] == false) { + PRINT_ER("power down request for already powered down source %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else if (((source == PWR_DEV_SRC_WIFI) && + (pwr_dev.power_status[PWR_DEV_SRC_BT] == true)) || + ((source == PWR_DEV_SRC_BT) && + (pwr_dev.power_status[PWR_DEV_SRC_WIFI] == true))) { + PRINT_WRN(PWRDEV_DBG, "Another device is preventing power down. request source is %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else { + linux_wlan_device_detection(0); + linux_wlan_device_power(0); +#ifdef DOWNLOAD_BT_FW_ONCE + pwr_dev.is_bt_fw_ready = false; +#endif + } + pwr_dev.power_status[source] = false; + + mutex_unlock(&pwr_dev.cs); + + return 0; +} +EXPORT_SYMBOL(at_pwr_power_down); + +int at_pwr_register_bus(int source) +{ + int ret = 0; + + mutex_lock(&pwr_dev.cs); + + PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), + pwr_dev.bus_registered[PWR_DEV_SRC_WIFI], + pwr_dev.bus_registered[PWR_DEV_SRC_BT]); + + if (pwr_dev.bus_registered[source] == true) { + PRINT_ER("Registering bus request for already registered source %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else { + if ((pwr_dev.bus_registered[PWR_DEV_SRC_WIFI] == true) || + (pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true)) { + pwr_dev.bus_registered[source] = true; + + if (source == PWR_DEV_SRC_BT) { +#ifdef WILC_SDIO + memcpy((void *)&pwr_dev.hif_func, &hif_sdio, + sizeof(struct wilc_hif_func)); +#else + memcpy((void *)&pwr_dev.hif_func, &hif_spi, + sizeof(struct wilc_hif_func)); +#endif /* WILC_SDIO */ + } + } else { + struct wilc_wlan_inp inp; + + prepare_inp(&inp); + linux_wlan_device_detection(1); + +#ifdef WILC_SDIO + ret = sdio_register_driver(&wilc_bus); + if (ret < 0) { + PRINT_D(PWRDEV_DBG, "init_wilc_driver: Failed to register sdio driver\n"); + } else { + PRINT_D(PWRDEV_DBG, "Waiting for sdio probe\n"); + + if (down_timeout(&sdio_probe_sync, msecs_to_jiffies(1000)) < 0) { + PRINT_D(PWRDEV_DBG, "sdio probe TimedOUT\n"); + ret = -1; + } else { + PRINT_D(PWRDEV_DBG, "sdio probe is called\n"); + pwr_dev.bus_registered[source] = true; + if (!hif_sdio.hif_init(&inp)) + ret = -5; + memcpy((void *)&pwr_dev.hif_func, &hif_sdio, sizeof(struct wilc_hif_func)); + } + } +#else + if (!linux_spi_init(NULL)) { + PRINT_ER("Can't initialize SPI\n"); + ret = -1; + } else { + PRINT_D(PWRDEV_DBG, "Waiting for spi probe\n"); + + if (down_timeout(&spi_probe_sync, msecs_to_jiffies(1000)) < 0) { + PRINT_D(PWRDEV_DBG, "spi probe TimedOUT\n"); + ret = -1; + } else { + PRINT_D(PWRDEV_DBG, "spi probe is called\n"); + pwr_dev.bus_registered[source] = true; + if (!hif_spi.hif_init(&inp)) + ret = -5; + memcpy((void *)&pwr_dev.hif_func, &hif_spi, sizeof(struct wilc_hif_func)); + } + } +#endif /* WILC_SDIO */ + } + } + + mutex_unlock(&pwr_dev.cs); + return ret; +} +EXPORT_SYMBOL(at_pwr_register_bus); + +int at_pwr_unregister_bus(int source) +{ + mutex_lock(&pwr_dev.cs); + + PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), + pwr_dev.bus_registered[PWR_DEV_SRC_WIFI], + pwr_dev.bus_registered[PWR_DEV_SRC_BT]); + + if (pwr_dev.bus_registered[source] == false) { + PRINT_ER("Unregistering bus request for already unregistered source %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else if (((source == PWR_DEV_SRC_WIFI) && + (pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true)) || + ((source == PWR_DEV_SRC_BT) && + (pwr_dev.bus_registered[PWR_DEV_SRC_WIFI] == true))) { + PRINT_WRN(PWRDEV_DBG, "Another device is preventing bus unregisteration. request source is %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else { +#ifndef WILC_SDIO + hif_spi.hif_deinit(NULL); + PRINT_D(PWRDEV_DBG, "SPI unregsiter...\n"); + spi_unregister_driver(&wilc_bus); +#else + PRINT_D(PWRDEV_DBG, "SDIO unregsiter...\n"); + hif_sdio.hif_deinit(NULL); + sdio_unregister_driver(&wilc_bus); +#endif /* WILC_SDIO */ + } + + pwr_dev.bus_registered[source] = false; + mutex_unlock(&pwr_dev.cs); + return 0; +} +EXPORT_SYMBOL(at_pwr_unregister_bus); + +/*TicketId883*/ +#ifdef WILC_BT_COEXISTENCE +void wilc_set_pf_change_coex_mode(WILCpfChangeCoexMode pfChangeCoexMode) +{ + pwr_dev.pfChangeCoexMode = pfChangeCoexMode; +} +EXPORT_SYMBOL(wilc_set_pf_change_coex_mode); +#endif + +static int pwr_dev_open(struct inode *i, struct file *f) +{ + PRINT_D(PWRDEV_DBG, "at_pwr_dev: open()\n"); + return 0; +} + +static int pwr_dev_close(struct inode *i, struct file *f) +{ + PRINT_D(PWRDEV_DBG, "at_pwr_dev: close()\n"); + return 0; +} + +static ssize_t pwr_dev_read(struct file *f, char __user *buf, size_t len, + loff_t *off) +{ + PRINT_D(PWRDEV_DBG, "at_pwr_dev: read()\n"); + return 0; +} + +static ssize_t pwr_dev_write(struct file *f, const char __user *buff, + size_t len, loff_t *off) +{ + struct cmd_handle_entry *cmd_entry; + + PRINT_D(PWRDEV_DBG, "at_pwr_dev: dev_write size %d\n", len); + if (len > 0) { + PRINT_D(PWRDEV_DBG, "received %s\n", buff); + + /* call the appropriate command handler */ + cmd_entry = (struct cmd_handle_entry *)cmd_table; + while (cmd_entry->handle_cmd != NULL) { + if (strncmp(cmd_entry->cmd_str, buff, + strlen(cmd_entry->cmd_str)) == 0) { + cmd_entry->handle_cmd(PWR_DEV_SRC_BT); + break; + } + cmd_entry++; + } + } else { + PRINT_D(PWRDEV_DBG, "received invalid size <=0: %d\n", len); + } + return len; +} + + +static int cmd_handle_bt_power_up(int source) +{ + int ret; + unsigned int reg; + + PRINT_D(PWRDEV_DBG, "AT PWR: bt_power_up\n"); + at_pwr_power_up(PWR_DEV_SRC_BT); + at_pwr_register_bus(PWR_DEV_SRC_BT); + + /*TicketId883*/ + /*Set BT bit in global mode reg*/ + if(pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true) + { + acquire_bus(ACQUIRE_AND_WAKEUP,PWR_DEV_SRC_BT); + + ret = pwr_dev.hif_func.hif_read_reg(rGLOBAL_MODE_CONTROL, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", rGLOBAL_MODE_CONTROL); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + reg |= BIT1; + ret = pwr_dev.hif_func.hif_write_reg(rGLOBAL_MODE_CONTROL, reg); + if (!ret) { + PRINT_ER("[wilc start]: fail write reg %x ...\n", rGLOBAL_MODE_CONTROL); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + } + + /*TicketId1092*/ + /*If WiFi is off, force BT*/ + if(pwr_dev.power_status[PWR_DEV_SRC_WIFI] == false) + { + if(pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true) + { + acquire_bus(ACQUIRE_AND_WAKEUP,PWR_DEV_SRC_BT); + + ret = pwr_dev.hif_func.hif_read_reg(rCOEXIST_CTL, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOEXIST_CTL); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + /*Force BT*/ + reg |= BIT0 | BIT9; + reg &= ~BIT11; + ret = pwr_dev.hif_func.hif_write_reg(rCOEXIST_CTL, reg); + if (!ret) { + PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOEXIST_CTL); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + + /*TicketId1115*/ + /*Disable awake coex null frames*/ + ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_ON_NULL_PKT, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + reg &= ~BIT30; + ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_ON_NULL_PKT, reg); + if (!ret) { + PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + + /*TicketId1115*/ + /*Disable doze coex null frames*/ + ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_OFF_NULL_PKT, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + reg &= ~BIT30; + ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_OFF_NULL_PKT, reg); + if (!ret) { + PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + } + } + else + { + /*TicketId883*/ + /*If WiFi is on, send config packet to change coex mode and coex null frames transmission*/ + #ifdef WILC_BT_COEXISTENCE + if(pwr_dev.pfChangeCoexMode) + { + pwr_dev.pfChangeCoexMode(COEX_ON); + } + #endif /*WILC_BT_COEXISTENCE*/ + } + + return 0; +} + + +static int cmd_handle_bt_power_down(int source) +{ + int ret; + uint32_t reg; + + PRINT_D(PWRDEV_DBG, "AT PWR: bt_power_down\n"); + + if ((pwr_dev.bus_registered[PWR_DEV_SRC_BT] == false) + && (pwr_dev.power_status[PWR_DEV_SRC_BT] == true)) { + at_pwr_register_bus(PWR_DEV_SRC_BT); + } + + /* Adjust coexistence module. This should be done from the FW in the future*/ + if (pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true) { + acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); + + ret = pwr_dev.hif_func.hif_read_reg(rGLOBAL_MODE_CONTROL, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", + rGLOBAL_MODE_CONTROL); + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + return ret; + } + /* Clear BT mode*/ + reg &= ~BIT1; + ret = pwr_dev.hif_func.hif_write_reg(rGLOBAL_MODE_CONTROL, reg); + if (!ret) { + PRINT_ER("[wilc start]: fail write reg %x ...\n", + rGLOBAL_MODE_CONTROL); + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + return ret; + } + + ret = pwr_dev.hif_func.hif_read_reg(rCOEXIST_CTL, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", + rCOEXIST_CTL); + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + return ret; + } + /* Stop forcing BT and force Wifi */ + reg &= ~BIT9; + reg |= BIT11; + ret = pwr_dev.hif_func.hif_write_reg(rCOEXIST_CTL, reg); + if (!ret) { + PRINT_ER("[wilc start]: fail write reg %x ...\n", + rCOEXIST_CTL); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + + /*TicketId1115*/ + /*Disable awake coex null frames*/ + ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_ON_NULL_PKT, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + reg &= ~BIT30; + ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_ON_NULL_PKT, reg); + if (!ret) { + PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + + /*TicketId1115*/ + /*Disable doze coex null frames*/ + ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_OFF_NULL_PKT, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + reg &= ~BIT30; + ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_OFF_NULL_PKT, reg); + if (!ret) { + PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + // Disable BT wakeup + ret = pwr_dev.hif_func.hif_read_reg(rPWR_SEQ_MISC_CTRL, ®); + if (!ret) { + PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOEXIST_CTL); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + reg &= ~ BIT29; + ret = pwr_dev.hif_func.hif_write_reg(rPWR_SEQ_MISC_CTRL, reg); + if (!ret) { + PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOEXIST_CTL); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + return ret; + } + + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + } + + at_pwr_unregister_bus(PWR_DEV_SRC_BT); + at_pwr_power_down(PWR_DEV_SRC_BT); + + return 0; +} + +static int cmd_handle_bt_download_fw(int source) +{ + PRINT_D(PWRDEV_DBG, "AT PWR: bt_download_fw\n"); + +#ifdef DOWNLOAD_BT_FW_ONCE + mutex_lock(&pwr_dev.cs); + if (pwr_dev.is_bt_fw_ready == true) { + PRINT_WRN(PWRDEV_DBG, "BT FW already downloaded. Skip!\n"); + mutex_unlock(&pwr_dev.cs); + return 0; + } + mutex_unlock(&pwr_dev.cs); +#endif /* DOWNLOAD_BT_FW_ONCE */ + + if (wilc_bt_firmware_download() != 0) { + PRINT_ER("Failed to download BT FW\n"); + at_pwr_unregister_bus(PWR_DEV_SRC_BT); + return -1; + } + + if (wilc_bt_start() != 0) { + PRINT_ER("Failed to start BT FW\n"); + at_pwr_unregister_bus(PWR_DEV_SRC_BT); + return -1; + } + +#ifdef DOWNLOAD_BT_FW_ONCE + mutex_lock(&pwr_dev.cs); + pwr_dev.is_bt_fw_ready = true; + mutex_unlock(&pwr_dev.cs); +#endif /* DOWNLOAD_BT_FW_ONCE */ + + at_pwr_unregister_bus(PWR_DEV_SRC_BT); + + return 0; +} + + + +static int cmd_handle_bt_fw_chip_wake_up(int source) +{ + chip_wakeup(source); + return 0; +} + + + +static int cmd_handle_bt_fw_chip_allow_sleep(int source) +{ + chip_allow_sleep(source); + return 0; +} + + +void prepare_inp(struct wilc_wlan_inp *nwi) +{ + nwi->os_context.os_private = (void *)&pwr_dev; + +#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; +#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; +#endif /* WILC_SDIO */ +} + + +void chip_allow_sleep(int source) +{ + uint32_t reg = 0; + + if (((source == PWR_DEV_SRC_WIFI) && + (pwr_dev.keep_awake[PWR_DEV_SRC_BT] == true)) || + ((source == PWR_DEV_SRC_BT) && + (pwr_dev.keep_awake[PWR_DEV_SRC_WIFI] == true))) { + PRINT_WRN(PWRDEV_DBG, "Another device is preventing allow sleep operation. request source is %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else { +#ifdef WILC_SDIO + pwr_dev.hif_func.hif_read_reg(0xf0, ®); + pwr_dev.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0)); +#else + pwr_dev.hif_func.hif_read_reg(0x1, ®); + pwr_dev.hif_func.hif_write_reg(0x1, reg & ~(1 << 1)); +#endif /* WILC_SDIO */ + } + if (source == PWR_DEV_SRC_WIFI) + genuChipPSstate = CHIP_SLEEPING_AUTO; + + pwr_dev.keep_awake[source] = false; +} +EXPORT_SYMBOL(chip_allow_sleep); + +void chip_wakeup(int source) +{ + uint32_t wakeup_reg_val, clk_status_reg_val, trials = 0; +#ifdef WILC_SDIO + uint32_t u32WakeupReg = 0xf0; + uint32_t u32ClkStsReg = 0xf0; + uint32_t u32WakepBit = BIT0; + uint32_t u32ClkStsBit = BIT4; +#else + uint32_t u32WakeupReg = 0x1; + uint32_t u32ClkStsReg = 0x13; + uint32_t u32WakepBit = BIT1; + uint32_t u32ClkStsBit = BIT2; +#endif /* WILC_SDIO */ + + int wake_seq_trials = 5; + + pwr_dev.hif_func.hif_read_reg(u32WakeupReg, &wakeup_reg_val); + do { + pwr_dev.hif_func.hif_write_reg(u32WakeupReg, wakeup_reg_val | u32WakepBit); + /* Check the clock status */ + pwr_dev.hif_func.hif_read_reg(u32ClkStsReg, &clk_status_reg_val); + + /* + * 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_val & u32ClkStsBit) == 0) && + (((++trials) % 3) == 0)) { + /* Wait for the chip to stabilize*/ + usleep_range(1000, 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(0xf0, &clk_status_reg_val); + */ + pwr_dev.hif_func.hif_read_reg(u32ClkStsReg, + &clk_status_reg_val); + + if ((clk_status_reg_val & u32ClkStsBit) == 0) + PRINT_ER("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_val & u32ClkStsBit) == 0) + pwr_dev.hif_func.hif_write_reg(u32WakeupReg, + wakeup_reg_val & (~u32WakepBit)); + } while (((clk_status_reg_val & u32ClkStsBit) == 0) + && (wake_seq_trials-- > 0)); + + genuChipPSstate = CHIP_WAKEDUP; + + pwr_dev.keep_awake[source] = true; +} + +void acquire_bus(enum BUS_ACQUIRE acquire, int source) +{ + mutex_lock(&pwr_dev.hif_cs); + + if (genuChipPSstate != CHIP_WAKEDUP) { + if (acquire == ACQUIRE_AND_WAKEUP) + chip_wakeup(source); + } +} +EXPORT_SYMBOL(acquire_bus); + +void release_bus(enum BUS_RELEASE release, int source) +{ + if (release == RELEASE_ALLOW_SLEEP) + chip_allow_sleep(source); + + if (mutex_is_locked(&pwr_dev.hif_cs)) + mutex_unlock(&pwr_dev.hif_cs); +} +EXPORT_SYMBOL(release_bus); + + #if defined(PLAT_SAMA5D4) + extern void atmci_rescan_card(unsigned id,unsigned insert); + #define WILC_SDIO_CARD_ID 0 + #define _linux_wlan_device_detection() {} + #define _linux_wlan_device_removal() {} + #define _linux_wlan_device_power_on() {} + #define _linux_wlan_device_power_off() {} + #elif defined(PANDA_BOARD) + #define _linux_wlan_device_detection() mmc_start_host(mmc_host_backup[2]) + #define _linux_wlan_device_removal() mmc_stop_host(mmc_host_backup[2]) + #define _linux_wlan_device_power_on() {} + #define _linux_wlan_device_power_off() {} + #elif defined(PLAT_ALLWINNER_A31) + extern void sw_mci_rescan_card(unsigned id, unsigned insert); + extern void wifi_pm_power(int on); + #define ATWILC_SDIO_CARD_ID 1 + #define _linux_wlan_device_power_on() wifi_pm_power(1) + #define _linux_wlan_device_power_off() wifi_pm_power(0) + #define _linux_wlan_device_detection() sw_mci_rescan_card(ATWILC_SDIO_CARD_ID,1) + #define _linux_wlan_device_removal() sw_mci_rescan_card(ATWILC_SDIO_CARD_ID,0) +#endif + +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; +} + +int at_pwr_power_up(int source) +{ + mutex_lock(&pwr_dev.cs); + + PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), + pwr_dev.power_status[PWR_DEV_SRC_WIFI], + pwr_dev.power_status[PWR_DEV_SRC_BT]); + + if (pwr_dev.power_status[source] == true) { + PRINT_ER("power up request for already powered up source %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else if ((pwr_dev.power_status[PWR_DEV_SRC_WIFI] == true) || + (pwr_dev.power_status[PWR_DEV_SRC_BT] == true)) { + PRINT_WRN(PWRDEV_DBG, "Device already up. request source is %s\n", + (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); + } else { + printk("PLAT_ALLWINNER_A31 POWER UP\n"); + linux_wlan_device_power(0); + linux_wlan_device_power(1); + msleep(100); + + } + pwr_dev.power_status[source] = true; + mutex_unlock(&pwr_dev.cs); + + return 0; } - -int at_pwr_dev_deinit(void) -{ - PRINT_D(PWRDEV_DBG, "at_pwr_dev: deinit\n"); - - if (&pwr_dev.hif_cs != NULL) - mutex_destroy(&pwr_dev.hif_cs); - - if (&pwr_dev.cs != NULL) - mutex_destroy(&pwr_dev.cs); - - cdev_del(&str_chc_dev); - device_destroy(chc_dev_class, chc_dev_no); - class_destroy(chc_dev_class); - unregister_chrdev_region(chc_dev_no, 1); - PRINT_D(PWRDEV_DBG, "at_pwr_dev: unregistered\n"); - return 0; -} - -struct mutex *at_pwr_dev_get_bus_lock() -{ - return &pwr_dev.hif_cs; -} -EXPORT_SYMBOL(at_pwr_dev_get_bus_lock); - -int at_pwr_power_down(int source) -{ - mutex_lock(&pwr_dev.cs); - - PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), - pwr_dev.power_status[PWR_DEV_SRC_WIFI], - pwr_dev.power_status[PWR_DEV_SRC_BT]); - - if (pwr_dev.power_status[source] == false) { - PRINT_ER("power down request for already powered down source %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else if (((source == PWR_DEV_SRC_WIFI) && - (pwr_dev.power_status[PWR_DEV_SRC_BT] == true)) || - ((source == PWR_DEV_SRC_BT) && - (pwr_dev.power_status[PWR_DEV_SRC_WIFI] == true))) { - PRINT_WRN(PWRDEV_DBG, "Another device is preventing power down. request source is %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else { - linux_wlan_device_detection(0); - linux_wlan_device_power(0); -#ifdef DOWNLOAD_BT_FW_ONCE - pwr_dev.is_bt_fw_ready = false; -#endif - } - pwr_dev.power_status[source] = false; - - mutex_unlock(&pwr_dev.cs); - - return 0; -} -EXPORT_SYMBOL(at_pwr_power_down); - -int at_pwr_register_bus(int source) -{ - int ret = 0; - - mutex_lock(&pwr_dev.cs); - - PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), - pwr_dev.bus_registered[PWR_DEV_SRC_WIFI], - pwr_dev.bus_registered[PWR_DEV_SRC_BT]); - - if (pwr_dev.bus_registered[source] == true) { - PRINT_ER("Registering bus request for already registered source %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else { - if ((pwr_dev.bus_registered[PWR_DEV_SRC_WIFI] == true) || - (pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true)) { - pwr_dev.bus_registered[source] = true; - - if (source == PWR_DEV_SRC_BT) { -#ifdef WILC_SDIO - memcpy((void *)&pwr_dev.hif_func, &hif_sdio, - sizeof(struct wilc_hif_func)); -#else - memcpy((void *)&pwr_dev.hif_func, &hif_spi, - sizeof(struct wilc_hif_func)); -#endif /* WILC_SDIO */ - } - } else { - struct wilc_wlan_inp inp; - - prepare_inp(&inp); - linux_wlan_device_detection(1); - -#ifdef WILC_SDIO - ret = sdio_register_driver(&wilc_bus); - if (ret < 0) { - PRINT_D(PWRDEV_DBG, "init_wilc_driver: Failed to register sdio driver\n"); - } else { - PRINT_D(PWRDEV_DBG, "Waiting for sdio probe\n"); - - if (down_timeout(&sdio_probe_sync, msecs_to_jiffies(1000)) < 0) { - PRINT_D(PWRDEV_DBG, "sdio probe TimedOUT\n"); - ret = -1; - } else { - PRINT_D(PWRDEV_DBG, "sdio probe is called\n"); - pwr_dev.bus_registered[source] = true; - if (!hif_sdio.hif_init(&inp)) - ret = -5; - memcpy((void *)&pwr_dev.hif_func, &hif_sdio, sizeof(struct wilc_hif_func)); - } - } -#else - if (!linux_spi_init(NULL)) { - PRINT_ER("Can't initialize SPI\n"); - ret = -1; - } else { - PRINT_D(PWRDEV_DBG, "Waiting for spi probe\n"); - - if (down_timeout(&spi_probe_sync, msecs_to_jiffies(1000)) < 0) { - PRINT_D(PWRDEV_DBG, "spi probe TimedOUT\n"); - ret = -1; - } else { - PRINT_D(PWRDEV_DBG, "spi probe is called\n"); - pwr_dev.bus_registered[source] = true; - if (!hif_spi.hif_init(&inp)) - ret = -5; - memcpy((void *)&pwr_dev.hif_func, &hif_spi, sizeof(struct wilc_hif_func)); - } - } -#endif /* WILC_SDIO */ - } - } - - mutex_unlock(&pwr_dev.cs); - return ret; -} -EXPORT_SYMBOL(at_pwr_register_bus); - -int at_pwr_unregister_bus(int source) -{ - mutex_lock(&pwr_dev.cs); - - PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), - pwr_dev.bus_registered[PWR_DEV_SRC_WIFI], - pwr_dev.bus_registered[PWR_DEV_SRC_BT]); - - if (pwr_dev.bus_registered[source] == false) { - PRINT_ER("Unregistering bus request for already unregistered source %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else if (((source == PWR_DEV_SRC_WIFI) && - (pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true)) || - ((source == PWR_DEV_SRC_BT) && - (pwr_dev.bus_registered[PWR_DEV_SRC_WIFI] == true))) { - PRINT_WRN(PWRDEV_DBG, "Another device is preventing bus unregisteration. request source is %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else { -#ifndef WILC_SDIO - hif_spi.hif_deinit(NULL); - PRINT_D(PWRDEV_DBG, "SPI unregsiter...\n"); - spi_unregister_driver(&wilc_bus); -#else - PRINT_D(PWRDEV_DBG, "SDIO unregsiter...\n"); - hif_sdio.hif_deinit(NULL); - sdio_unregister_driver(&wilc_bus); -#endif /* WILC_SDIO */ - } - - pwr_dev.bus_registered[source] = false; - mutex_unlock(&pwr_dev.cs); - return 0; -} -EXPORT_SYMBOL(at_pwr_unregister_bus); - -/*TicketId883*/ -#ifdef WILC_BT_COEXISTENCE -void wilc_set_pf_change_coex_mode(WILCpfChangeCoexMode pfChangeCoexMode) -{ - pwr_dev.pfChangeCoexMode = pfChangeCoexMode; -} -EXPORT_SYMBOL(wilc_set_pf_change_coex_mode); -#endif - -static int pwr_dev_open(struct inode *i, struct file *f) -{ - PRINT_D(PWRDEV_DBG, "at_pwr_dev: open()\n"); - return 0; -} - -static int pwr_dev_close(struct inode *i, struct file *f) -{ - PRINT_D(PWRDEV_DBG, "at_pwr_dev: close()\n"); - return 0; -} - -static ssize_t pwr_dev_read(struct file *f, char __user *buf, size_t len, - loff_t *off) -{ - PRINT_D(PWRDEV_DBG, "at_pwr_dev: read()\n"); - return 0; -} - -static ssize_t pwr_dev_write(struct file *f, const char __user *buff, - size_t len, loff_t *off) -{ - struct cmd_handle_entry *cmd_entry; - - PRINT_D(PWRDEV_DBG, "at_pwr_dev: dev_write size %d\n", len); - if (len > 0) { - PRINT_D(PWRDEV_DBG, "received %s\n", buff); - - /* call the appropriate command handler */ - cmd_entry = (struct cmd_handle_entry *)cmd_table; - while (cmd_entry->handle_cmd != NULL) { - if (strncmp(cmd_entry->cmd_str, buff, - strlen(cmd_entry->cmd_str)) == 0) { - cmd_entry->handle_cmd(PWR_DEV_SRC_BT); - break; - } - cmd_entry++; - } - } else { - PRINT_D(PWRDEV_DBG, "received invalid size <=0: %d\n", len); - } - return len; -} - - -static int cmd_handle_bt_power_up(int source) -{ - int ret; - unsigned int reg; - - PRINT_D(PWRDEV_DBG, "AT PWR: bt_power_up\n"); - at_pwr_power_up(PWR_DEV_SRC_BT); - at_pwr_register_bus(PWR_DEV_SRC_BT); - - /*TicketId883*/ - /*Set BT bit in global mode reg*/ - if(pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true) - { - acquire_bus(ACQUIRE_AND_WAKEUP,PWR_DEV_SRC_BT); - - ret = pwr_dev.hif_func.hif_read_reg(rGLOBAL_MODE_CONTROL, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", rGLOBAL_MODE_CONTROL); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - reg |= BIT1; - ret = pwr_dev.hif_func.hif_write_reg(rGLOBAL_MODE_CONTROL, reg); - if (!ret) { - PRINT_ER("[wilc start]: fail write reg %x ...\n", rGLOBAL_MODE_CONTROL); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - } - - /*TicketId1092*/ - /*If WiFi is off, force BT*/ - if(pwr_dev.power_status[PWR_DEV_SRC_WIFI] == false) - { - if(pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true) - { - acquire_bus(ACQUIRE_AND_WAKEUP,PWR_DEV_SRC_BT); - - ret = pwr_dev.hif_func.hif_read_reg(rCOEXIST_CTL, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOEXIST_CTL); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - /*Force BT*/ - reg |= BIT0 | BIT9; - reg &= ~BIT11; - ret = pwr_dev.hif_func.hif_write_reg(rCOEXIST_CTL, reg); - if (!ret) { - PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOEXIST_CTL); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - - /*TicketId1115*/ - /*Disable awake coex null frames*/ - ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_ON_NULL_PKT, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - reg &= ~BIT30; - ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_ON_NULL_PKT, reg); - if (!ret) { - PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - - /*TicketId1115*/ - /*Disable doze coex null frames*/ - ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_OFF_NULL_PKT, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - reg &= ~BIT30; - ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_OFF_NULL_PKT, reg); - if (!ret) { - PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - } - } - else - { - /*TicketId883*/ - /*If WiFi is on, send config packet to change coex mode and coex null frames transmission*/ - #ifdef WILC_BT_COEXISTENCE - if(pwr_dev.pfChangeCoexMode) - { - pwr_dev.pfChangeCoexMode(COEX_ON); - } - #endif /*WILC_BT_COEXISTENCE*/ - } - - return 0; -} - - -static int cmd_handle_bt_power_down(int source) -{ - int ret; - uint32_t reg; - - PRINT_D(PWRDEV_DBG, "AT PWR: bt_power_down\n"); - - if ((pwr_dev.bus_registered[PWR_DEV_SRC_BT] == false) - && (pwr_dev.power_status[PWR_DEV_SRC_BT] == true)) { - at_pwr_register_bus(PWR_DEV_SRC_BT); - } - - /* Adjust coexistence module. This should be done from the FW in the future*/ - if (pwr_dev.bus_registered[PWR_DEV_SRC_BT] == true) { - acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); - - ret = pwr_dev.hif_func.hif_read_reg(rGLOBAL_MODE_CONTROL, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", - rGLOBAL_MODE_CONTROL); - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - return ret; - } - /* Clear BT mode*/ - reg &= ~BIT1; - ret = pwr_dev.hif_func.hif_write_reg(rGLOBAL_MODE_CONTROL, reg); - if (!ret) { - PRINT_ER("[wilc start]: fail write reg %x ...\n", - rGLOBAL_MODE_CONTROL); - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - return ret; - } - - ret = pwr_dev.hif_func.hif_read_reg(rCOEXIST_CTL, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", - rCOEXIST_CTL); - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - return ret; - } - /* Stop forcing BT and force Wifi */ - reg &= ~BIT9; - reg |= BIT11; - ret = pwr_dev.hif_func.hif_write_reg(rCOEXIST_CTL, reg); - if (!ret) { - PRINT_ER("[wilc start]: fail write reg %x ...\n", - rCOEXIST_CTL); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - - /*TicketId1115*/ - /*Disable awake coex null frames*/ - ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_ON_NULL_PKT, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - reg &= ~BIT30; - ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_ON_NULL_PKT, reg); - if (!ret) { - PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_ON_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - - /*TicketId1115*/ - /*Disable doze coex null frames*/ - ret = pwr_dev.hif_func.hif_read_reg(rCOE_AUTO_PS_OFF_NULL_PKT, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - reg &= ~BIT30; - ret = pwr_dev.hif_func.hif_write_reg(rCOE_AUTO_PS_OFF_NULL_PKT, reg); - if (!ret) { - PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOE_AUTO_PS_OFF_NULL_PKT); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - // Disable BT wakeup - ret = pwr_dev.hif_func.hif_read_reg(rPWR_SEQ_MISC_CTRL, ®); - if (!ret) { - PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOEXIST_CTL); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - reg &= ~ BIT29; - ret = pwr_dev.hif_func.hif_write_reg(rPWR_SEQ_MISC_CTRL, reg); - if (!ret) { - PRINT_ER( "[wilc start]: fail write reg %x ...\n", rCOEXIST_CTL); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - return ret; - } - - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - } - - at_pwr_unregister_bus(PWR_DEV_SRC_BT); - at_pwr_power_down(PWR_DEV_SRC_BT); - - return 0; -} - -static int cmd_handle_bt_download_fw(int source) -{ - PRINT_D(PWRDEV_DBG, "AT PWR: bt_download_fw\n"); - -#ifdef DOWNLOAD_BT_FW_ONCE - mutex_lock(&pwr_dev.cs); - if (pwr_dev.is_bt_fw_ready == true) { - PRINT_WRN(PWRDEV_DBG, "BT FW already downloaded. Skip!\n"); - mutex_unlock(&pwr_dev.cs); - return 0; - } - mutex_unlock(&pwr_dev.cs); -#endif /* DOWNLOAD_BT_FW_ONCE */ - - if (wilc_bt_firmware_download() != 0) { - PRINT_ER("Failed to download BT FW\n"); - at_pwr_unregister_bus(PWR_DEV_SRC_BT); - return -1; - } - - if (wilc_bt_start() != 0) { - PRINT_ER("Failed to start BT FW\n"); - at_pwr_unregister_bus(PWR_DEV_SRC_BT); - return -1; - } - -#ifdef DOWNLOAD_BT_FW_ONCE - mutex_lock(&pwr_dev.cs); - pwr_dev.is_bt_fw_ready = true; - mutex_unlock(&pwr_dev.cs); -#endif /* DOWNLOAD_BT_FW_ONCE */ - - at_pwr_unregister_bus(PWR_DEV_SRC_BT); - - return 0; -} - - - -static int cmd_handle_bt_fw_chip_wake_up(int source) -{ - chip_wakeup(source); - return 0; -} - - - -static int cmd_handle_bt_fw_chip_allow_sleep(int source) -{ - chip_allow_sleep(source); - return 0; -} - - -void prepare_inp(struct wilc_wlan_inp *nwi) -{ - nwi->os_context.os_private = (void *)&pwr_dev; - -#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; -#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; -#endif /* WILC_SDIO */ -} - - -void chip_allow_sleep(int source) -{ - uint32_t reg = 0; - - if (((source == PWR_DEV_SRC_WIFI) && - (pwr_dev.keep_awake[PWR_DEV_SRC_BT] == true)) || - ((source == PWR_DEV_SRC_BT) && - (pwr_dev.keep_awake[PWR_DEV_SRC_WIFI] == true))) { - PRINT_WRN(PWRDEV_DBG, "Another device is preventing allow sleep operation. request source is %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else { -#ifdef WILC_SDIO - pwr_dev.hif_func.hif_read_reg(0xf0, ®); - pwr_dev.hif_func.hif_write_reg(0xf0, reg & ~(1 << 0)); -#else - pwr_dev.hif_func.hif_read_reg(0x1, ®); - pwr_dev.hif_func.hif_write_reg(0x1, reg & ~(1 << 1)); -#endif /* WILC_SDIO */ - } - if (source == PWR_DEV_SRC_WIFI) - genuChipPSstate = CHIP_SLEEPING_AUTO; - - pwr_dev.keep_awake[source] = false; -} -EXPORT_SYMBOL(chip_allow_sleep); - -void chip_wakeup(int source) -{ - uint32_t wakeup_reg_val, clk_status_reg_val, trials = 0; -#ifdef WILC_SDIO - uint32_t u32WakeupReg = 0xf0; - uint32_t u32ClkStsReg = 0xf0; - uint32_t u32WakepBit = BIT0; - uint32_t u32ClkStsBit = BIT4; -#else - uint32_t u32WakeupReg = 0x1; - uint32_t u32ClkStsReg = 0x13; - uint32_t u32WakepBit = BIT1; - uint32_t u32ClkStsBit = BIT2; -#endif /* WILC_SDIO */ - - int wake_seq_trials = 5; - - pwr_dev.hif_func.hif_read_reg(u32WakeupReg, &wakeup_reg_val); - do { - pwr_dev.hif_func.hif_write_reg(u32WakeupReg, wakeup_reg_val | u32WakepBit); - /* Check the clock status */ - pwr_dev.hif_func.hif_read_reg(u32ClkStsReg, &clk_status_reg_val); - - /* - * 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_val & u32ClkStsBit) == 0) && - (((++trials) % 3) == 0)) { - /* Wait for the chip to stabilize*/ - usleep_range(1000, 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(0xf0, &clk_status_reg_val); - */ - pwr_dev.hif_func.hif_read_reg(u32ClkStsReg, - &clk_status_reg_val); - - if ((clk_status_reg_val & u32ClkStsBit) == 0) - PRINT_ER("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_val & u32ClkStsBit) == 0) - pwr_dev.hif_func.hif_write_reg(u32WakeupReg, - wakeup_reg_val & (~u32WakepBit)); - } while (((clk_status_reg_val & u32ClkStsBit) == 0) - && (wake_seq_trials-- > 0)); - - genuChipPSstate = CHIP_WAKEDUP; - - pwr_dev.keep_awake[source] = true; -} - -void acquire_bus(enum BUS_ACQUIRE acquire, int source) -{ - mutex_lock(&pwr_dev.hif_cs); - - if (genuChipPSstate != CHIP_WAKEDUP) { - if (acquire == ACQUIRE_AND_WAKEUP) - chip_wakeup(source); - } -} -EXPORT_SYMBOL(acquire_bus); - -void release_bus(enum BUS_RELEASE release, int source) -{ - if (release == RELEASE_ALLOW_SLEEP) - chip_allow_sleep(source); - - if (mutex_is_locked(&pwr_dev.hif_cs)) - mutex_unlock(&pwr_dev.hif_cs); -} -EXPORT_SYMBOL(release_bus); - - #if defined(PLAT_SAMA5D4) - extern void atmci_rescan_card(unsigned id,unsigned insert); - #define WILC_SDIO_CARD_ID 0 - #define _linux_wlan_device_detection() {} - #define _linux_wlan_device_removal() {} - #define _linux_wlan_device_power_on() {} - #define _linux_wlan_device_power_off() {} - #elif defined(PANDA_BOARD) - #define _linux_wlan_device_detection() mmc_start_host(mmc_host_backup[2]) - #define _linux_wlan_device_removal() mmc_stop_host(mmc_host_backup[2]) - #define _linux_wlan_device_power_on() {} - #define _linux_wlan_device_power_off() {} - #elif defined(PLAT_ALLWINNER_A31) - extern void sw_mci_rescan_card(unsigned id, unsigned insert); - extern void wifi_pm_power(int on); - #define ATWILC_SDIO_CARD_ID 1 - #define _linux_wlan_device_power_on() wifi_pm_power(1) - #define _linux_wlan_device_power_off() wifi_pm_power(0) - #define _linux_wlan_device_detection() sw_mci_rescan_card(ATWILC_SDIO_CARD_ID,1) - #define _linux_wlan_device_removal() sw_mci_rescan_card(ATWILC_SDIO_CARD_ID,0) -#endif - -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; -} - -int at_pwr_power_up(int source) -{ - mutex_lock(&pwr_dev.cs); - - PRINT_D(PWRDEV_DBG, "source: %s, current bus status Wifi: %d, BT: %d\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT"), - pwr_dev.power_status[PWR_DEV_SRC_WIFI], - pwr_dev.power_status[PWR_DEV_SRC_BT]); - - if (pwr_dev.power_status[source] == true) { - PRINT_ER("power up request for already powered up source %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else if ((pwr_dev.power_status[PWR_DEV_SRC_WIFI] == true) || - (pwr_dev.power_status[PWR_DEV_SRC_BT] == true)) { - PRINT_WRN(PWRDEV_DBG, "Device already up. request source is %s\n", - (source == PWR_DEV_SRC_WIFI ? "Wifi" : "BT")); - } else { - printk("PLAT_ALLWINNER_A31 POWER UP\n"); - linux_wlan_device_power(0); - linux_wlan_device_power(1); - msleep(100); - - } - pwr_dev.power_status[source] = true; - mutex_unlock(&pwr_dev.cs); - - return 0; -} -EXPORT_SYMBOL(at_pwr_power_up); - -static int wilc_bt_firmware_download(void) -{ - uint32_t offset; - uint32_t addr, size, size2, blksz; - uint8_t *dma_buffer; - int ret = 0; - uint32_t reg; - const struct firmware *wilc_bt_firmware; - const u8 *buffer; - size_t buffer_size; - - PRINT_WRN(PWRDEV_DBG, "Bluetooth firmware: %s\n", BT_FIRMWARE); -#ifdef WILC_SDIO - if (request_firmware(&wilc_bt_firmware, BT_FIRMWARE, dev) != 0) { - PRINT_ER("%s - firmare not available. Skip!\n", BT_FIRMWARE); - ret = -1; - goto _fail_1; - } -#else - if (request_firmware(&wilc_bt_firmware, BT_FIRMWARE, dev) != 0) { - PRINT_ER("%s - firmare not available. Skip!\n", BT_FIRMWARE); - ret = -1; - goto _fail_1; - } -#endif /* WILC_SDIO */ - - buffer = wilc_bt_firmware->data; - buffer_size = (size_t)wilc_bt_firmware->size; - if (buffer_size <= 0) { - PRINT_ER("Firmware size = 0!\n"); - ret = -1; - goto _fail_1; - } - acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); - - ret = pwr_dev.hif_func.hif_write_reg(0x4f0000, 0x71); - if (!ret) { - PRINT_ER("[wilc start]: fail write reg 0x4f0000 ...\n"); - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - - goto _fail_1; - } - - /* - * Avoid booting from BT boot ROM. Make sure that Drive IRQN [SDIO platform] - * or SD_DAT3 [SPI platform] to ?1? - */ - /* Set cortus reset register to register control. */ - ret = pwr_dev.hif_func.hif_read_reg(0x3b0090, ®); - if (!ret) { - PRINT_ER("[wilc start]: fail read reg 0x3b0090 ...\n"); - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - - goto _fail_1; - } - reg |= (1 << 0); - ret = pwr_dev.hif_func.hif_write_reg(0x3b0090, reg); - if (!ret) { - PRINT_ER("[wilc start]: fail write reg 0x3b0090 ...\n"); - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - goto _fail_1; - } - - pwr_dev.hif_func.hif_read_reg(0x3B0400, ®); - - if (reg & (1ul << 2)) { - reg &= ~(1ul << 2); - } else { - reg |= (1ul << 2); - pwr_dev.hif_func.hif_write_reg(0x3B0400, reg); - reg &= ~(1ul << 2); - } - pwr_dev.hif_func.hif_write_reg(0x3B0400, reg); - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - - /* blocks of sizes > 512 causes the wifi to hang! */ - blksz = (1ul << 9); - /* Allocate a DMA coherent buffer. */ - dma_buffer = kmalloc(blksz, GFP_KERNEL); - if (dma_buffer == NULL) { - ret = -5; - PRINT_ER("Can't allocate buffer for BT firmware download IO error\n"); - goto _fail_1; - } - - PRINT_D(PWRDEV_DBG, "Downloading BT firmware size = %d ...\n", buffer_size); - /* load the firmware */ - - offset = 0; - addr = 0x400000; - size = buffer_size; -#ifdef BIG_ENDIAN - addr = BYTE_SWAP(addr); - size = BYTE_SWAP(size); -#endif - offset = 0; - - 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); - - acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); - - ret = pwr_dev.hif_func.hif_block_tx(addr, dma_buffer, size2); - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - if (!ret) - break; - - addr += size2; - offset += size2; - size -= size2; - } - - if (!ret) { - ret = -5; - PRINT_ER("Can't download BT firmware IO error\n"); - goto _fail_; - } - PRINT_D(PWRDEV_DBG, "BT Offset = %d\n", offset); - -_fail_: - kfree(dma_buffer); -_fail_1: - - /* Freeing FW buffer */ - PRINT_D(PWRDEV_DBG, "Freeing BT FW buffer ...\n"); - PRINT_D(PWRDEV_DBG, "Releasing BT firmware\n"); - release_firmware(wilc_bt_firmware); - - if (ret >= 0) - PRINT_D(PWRDEV_DBG, "BT Download Succeeded\n"); - - return (ret < 0) ? ret : 0; -} - -static int wilc_bt_start(void) -{ - uint32_t val32 = 0; - int ret = 0; - - acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); - - PRINT_D(PWRDEV_DBG, "Starting BT firmware\n"); - - /* - * Write the firmware download complete magic value 0x10ADD09E at - * location 0xFFFF000C (Cortus map) or C000C (AHB map). - * This will let the boot-rom code execute from RAM. - */ - pwr_dev.hif_func.hif_write_reg(0x4F000c, 0x10add09e); - - - pwr_dev.hif_func.hif_read_reg(0x3B0400, &val32); - val32 &= ~((1ul << 2) | (1ul << 3)); - pwr_dev.hif_func.hif_write_reg(0x3B0400, val32); - - msleep(100); - - val32 |= ((1ul << 2) | (1ul << 3)); - - pwr_dev.hif_func.hif_write_reg(0x3B0400, val32); - - PRINT_D(PWRDEV_DBG, "BT Start Succeeded\n"); - - - release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); - - return (ret < 0) ? ret : 0; -} - - -void (*pf_chip_sleep_manually)(unsigned int , int )=NULL; -int (*pf_get_num_conn_ifcs)(void)=NULL; -void (*pf_host_wakeup_notify)(int)=NULL; -void (*pf_host_sleep_notify)(int)=NULL; -int (*pf_get_u8SuspendOnEvent_value)(void)=NULL; - -void set_pf_chip_sleep_manually(void (*chip_sleep_manually_address)(unsigned int , int )) -{ - pf_chip_sleep_manually=chip_sleep_manually_address; -} -EXPORT_SYMBOL(set_pf_chip_sleep_manually); - -void set_pf_get_num_conn_ifcs(int (*get_num_conn_ifcs_address)(void)) -{ - pf_get_num_conn_ifcs=get_num_conn_ifcs_address; -} -EXPORT_SYMBOL(set_pf_get_num_conn_ifcs); - -void set_pf_host_wakeup_notify(void (*host_wakeup_notify_address)( int )) -{ - pf_host_wakeup_notify=host_wakeup_notify_address; -} -EXPORT_SYMBOL(set_pf_host_wakeup_notify); - -void set_pf_host_sleep_notify(void (*host_sleep_notify_address)( int )) -{ - pf_host_sleep_notify=host_sleep_notify_address; -} -EXPORT_SYMBOL(set_pf_host_sleep_notify); - -void set_pf_get_u8SuspendOnEvent_value(int (*get_u8SuspendOnEvent_val)(void)) -{ - pf_get_u8SuspendOnEvent_value=get_u8SuspendOnEvent_val; -} -EXPORT_SYMBOL(set_pf_get_u8SuspendOnEvent_value); - -module_init(at_pwr_dev_init); -module_exit(at_pwr_dev_deinit); - -MODULE_LICENSE("GPL"); - +EXPORT_SYMBOL(at_pwr_power_up); + +static int wilc_bt_firmware_download(void) +{ + uint32_t offset; + uint32_t addr, size, size2, blksz; + uint8_t *dma_buffer; + int ret = 0; + uint32_t reg; + const struct firmware *wilc_bt_firmware; + const u8 *buffer; + size_t buffer_size; + + PRINT_WRN(PWRDEV_DBG, "Bluetooth firmware: %s\n", BT_FIRMWARE); +#ifdef WILC_SDIO + if (request_firmware(&wilc_bt_firmware, BT_FIRMWARE, dev) != 0) { + PRINT_ER("%s - firmare not available. Skip!\n", BT_FIRMWARE); + ret = -1; + goto _fail_1; + } +#else + if (request_firmware(&wilc_bt_firmware, BT_FIRMWARE, dev) != 0) { + PRINT_ER("%s - firmare not available. Skip!\n", BT_FIRMWARE); + ret = -1; + goto _fail_1; + } +#endif /* WILC_SDIO */ + + buffer = wilc_bt_firmware->data; + buffer_size = (size_t)wilc_bt_firmware->size; + if (buffer_size <= 0) { + PRINT_ER("Firmware size = 0!\n"); + ret = -1; + goto _fail_1; + } + acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); + + ret = pwr_dev.hif_func.hif_write_reg(0x4f0000, 0x71); + if (!ret) { + PRINT_ER("[wilc start]: fail write reg 0x4f0000 ...\n"); + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + + goto _fail_1; + } + + /* + * Avoid booting from BT boot ROM. Make sure that Drive IRQN [SDIO platform] + * or SD_DAT3 [SPI platform] to ?1? + */ + /* Set cortus reset register to register control. */ + ret = pwr_dev.hif_func.hif_read_reg(0x3b0090, ®); + if (!ret) { + PRINT_ER("[wilc start]: fail read reg 0x3b0090 ...\n"); + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + + goto _fail_1; + } + reg |= (1 << 0); + ret = pwr_dev.hif_func.hif_write_reg(0x3b0090, reg); + if (!ret) { + PRINT_ER("[wilc start]: fail write reg 0x3b0090 ...\n"); + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + goto _fail_1; + } + + pwr_dev.hif_func.hif_read_reg(0x3B0400, ®); + + if (reg & (1ul << 2)) { + reg &= ~(1ul << 2); + } else { + reg |= (1ul << 2); + pwr_dev.hif_func.hif_write_reg(0x3B0400, reg); + reg &= ~(1ul << 2); + } + pwr_dev.hif_func.hif_write_reg(0x3B0400, reg); + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + + /* blocks of sizes > 512 causes the wifi to hang! */ + blksz = (1ul << 9); + /* Allocate a DMA coherent buffer. */ + dma_buffer = kmalloc(blksz, GFP_KERNEL); + if (dma_buffer == NULL) { + ret = -5; + PRINT_ER("Can't allocate buffer for BT firmware download IO error\n"); + goto _fail_1; + } + + PRINT_D(PWRDEV_DBG, "Downloading BT firmware size = %d ...\n", buffer_size); + /* load the firmware */ + + offset = 0; + addr = 0x400000; + size = buffer_size; +#ifdef BIG_ENDIAN + addr = BYTE_SWAP(addr); + size = BYTE_SWAP(size); +#endif + offset = 0; + + 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); + + acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); + + ret = pwr_dev.hif_func.hif_block_tx(addr, dma_buffer, size2); + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + if (!ret) + break; + + addr += size2; + offset += size2; + size -= size2; + } + + if (!ret) { + ret = -5; + PRINT_ER("Can't download BT firmware IO error\n"); + goto _fail_; + } + PRINT_D(PWRDEV_DBG, "BT Offset = %d\n", offset); + +_fail_: + kfree(dma_buffer); +_fail_1: + + /* Freeing FW buffer */ + PRINT_D(PWRDEV_DBG, "Freeing BT FW buffer ...\n"); + PRINT_D(PWRDEV_DBG, "Releasing BT firmware\n"); + release_firmware(wilc_bt_firmware); + + if (ret >= 0) + PRINT_D(PWRDEV_DBG, "BT Download Succeeded\n"); + + return (ret < 0) ? ret : 0; +} + +static int wilc_bt_start(void) +{ + uint32_t val32 = 0; + int ret = 0; + + acquire_bus(ACQUIRE_AND_WAKEUP, PWR_DEV_SRC_WIFI); + + PRINT_D(PWRDEV_DBG, "Starting BT firmware\n"); + + /* + * Write the firmware download complete magic value 0x10ADD09E at + * location 0xFFFF000C (Cortus map) or C000C (AHB map). + * This will let the boot-rom code execute from RAM. + */ + pwr_dev.hif_func.hif_write_reg(0x4F000c, 0x10add09e); + + + pwr_dev.hif_func.hif_read_reg(0x3B0400, &val32); + val32 &= ~((1ul << 2) | (1ul << 3)); + pwr_dev.hif_func.hif_write_reg(0x3B0400, val32); + + msleep(100); + + val32 |= ((1ul << 2) | (1ul << 3)); + + pwr_dev.hif_func.hif_write_reg(0x3B0400, val32); + + PRINT_D(PWRDEV_DBG, "BT Start Succeeded\n"); + + + release_bus(RELEASE_ALLOW_SLEEP, PWR_DEV_SRC_BT); + + return (ret < 0) ? ret : 0; +} + + +void (*pf_chip_sleep_manually)(unsigned int , int )=NULL; +int (*pf_get_num_conn_ifcs)(void)=NULL; +void (*pf_host_wakeup_notify)(int)=NULL; +void (*pf_host_sleep_notify)(int)=NULL; +int (*pf_get_u8SuspendOnEvent_value)(void)=NULL; + +void set_pf_chip_sleep_manually(void (*chip_sleep_manually_address)(unsigned int , int )) +{ + pf_chip_sleep_manually=chip_sleep_manually_address; +} +EXPORT_SYMBOL(set_pf_chip_sleep_manually); + +void set_pf_get_num_conn_ifcs(int (*get_num_conn_ifcs_address)(void)) +{ + pf_get_num_conn_ifcs=get_num_conn_ifcs_address; +} +EXPORT_SYMBOL(set_pf_get_num_conn_ifcs); + +void set_pf_host_wakeup_notify(void (*host_wakeup_notify_address)( int )) +{ + pf_host_wakeup_notify=host_wakeup_notify_address; +} +EXPORT_SYMBOL(set_pf_host_wakeup_notify); + +void set_pf_host_sleep_notify(void (*host_sleep_notify_address)( int )) +{ + pf_host_sleep_notify=host_sleep_notify_address; +} +EXPORT_SYMBOL(set_pf_host_sleep_notify); + +void set_pf_get_u8SuspendOnEvent_value(int (*get_u8SuspendOnEvent_val)(void)) +{ + pf_get_u8SuspendOnEvent_value=get_u8SuspendOnEvent_val; +} +EXPORT_SYMBOL(set_pf_get_u8SuspendOnEvent_value); + +module_init(at_pwr_dev_init); +module_exit(at_pwr_dev_deinit); + +MODULE_LICENSE("GPL"); + diff --git a/wilc3000/atl_error_support.h b/wilc3000/atl_error_support.h index f12f94b..5b4aeba 100644 --- a/wilc3000/atl_error_support.h +++ b/wilc3000/atl_error_support.h @@ -1,81 +1,81 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef __ATL_ERRORSUPPORT_H__ -#define __ATL_ERRORSUPPORT_H__ - -#include "linux_wlan_common.h" - -/* Psitive Numbers to indicate sucess with special status */ -#define ATL_ALREADY_EXSIT (+100) /* The requested object already - exists */ - -/* Generic success will return 0 */ -#define ATL_SUCCESS 0 /* Generic success */ - -/* Negative numbers to indicate failures */ -#define ATL_FAIL -100 /* Generic Fail */ -#define ATL_BUSY -101 /* Busy with another operation*/ -#define ATL_INVALID_ARGUMENT -102 /* A given argument is invalid*/ -#define ATL_INVALID_STATE -103 /* An API request would violate the - Driver state machine (i.e. to start PID while not camped)*/ -#define ATL_BUFFER_OVERFLOW -104 /* In copy operations if the copied - data is larger than the allocated buffer*/ -#define ATL_NULL_PTR -105 /* null pointer is passed or used */ -#define ATL_EMPTY -107 -#define ATL_FULL -108 -#define ATL_TIMEOUT -109 -#define ATL_CANCELED -110 /* The required operation have been - canceled by the user*/ -#define ATL_INVALID_FILE -112 /* The Loaded file is corruped or - having an invalid format */ -#define ATL_NOT_FOUND -113 /* Cant find the file to load */ -#define ATL_NO_MEM -114 -#define ATL_UNSUPPORTED_VERSION -115 -#define ATL_FILE_EOF -116 - - -/* Error type */ -typedef signed int ATL_ErrNo; - -#define ATL_IS_ERR(__status__) (__status__ < ATL_SUCCESS) - -#define ATL_ERRORCHECK(__status__) do {\ - if (ATL_IS_ERR(__status__)) {\ - PRINT_ER("ATL_ERRORCHECK(%d)\n", __status__);\ - goto ERRORHANDLER;\ - } \ -} while (0) - -#define ATL_ERRORREPORT(__status__, __err__) do {\ - PRINT_ER("ATL_ERRORREPORT(%d)\n", __err__);\ - __status__ = __err__;\ - goto ERRORHANDLER;\ -} while (0) - -#define ATL_NULLCHECK(__status__, __ptr__) do {\ - if (__ptr__ == NULL) {\ - ATL_ERRORREPORT(__status__, ATL_NULL_PTR);\ - } \ -} while (0) - -#define ATL_CATCH(__status__) \ -ERRORHANDLER :\ -if(ATL_IS_ERR(__status__)) \ - -#endif +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __ATL_ERRORSUPPORT_H__ +#define __ATL_ERRORSUPPORT_H__ + +#include "linux_wlan_common.h" + +/* Psitive Numbers to indicate sucess with special status */ +#define ATL_ALREADY_EXSIT (+100) /* The requested object already + exists */ + +/* Generic success will return 0 */ +#define ATL_SUCCESS 0 /* Generic success */ + +/* Negative numbers to indicate failures */ +#define ATL_FAIL -100 /* Generic Fail */ +#define ATL_BUSY -101 /* Busy with another operation*/ +#define ATL_INVALID_ARGUMENT -102 /* A given argument is invalid*/ +#define ATL_INVALID_STATE -103 /* An API request would violate the + Driver state machine (i.e. to start PID while not camped)*/ +#define ATL_BUFFER_OVERFLOW -104 /* In copy operations if the copied + data is larger than the allocated buffer*/ +#define ATL_NULL_PTR -105 /* null pointer is passed or used */ +#define ATL_EMPTY -107 +#define ATL_FULL -108 +#define ATL_TIMEOUT -109 +#define ATL_CANCELED -110 /* The required operation have been + canceled by the user*/ +#define ATL_INVALID_FILE -112 /* The Loaded file is corruped or + having an invalid format */ +#define ATL_NOT_FOUND -113 /* Cant find the file to load */ +#define ATL_NO_MEM -114 +#define ATL_UNSUPPORTED_VERSION -115 +#define ATL_FILE_EOF -116 + + +/* Error type */ +typedef signed int ATL_ErrNo; + +#define ATL_IS_ERR(__status__) (__status__ < ATL_SUCCESS) + +#define ATL_ERRORCHECK(__status__) do {\ + if (ATL_IS_ERR(__status__)) {\ + PRINT_ER("ATL_ERRORCHECK(%d)\n", __status__);\ + goto ERRORHANDLER;\ + } \ +} while (0) + +#define ATL_ERRORREPORT(__status__, __err__) do {\ + PRINT_ER("ATL_ERRORREPORT(%d)\n", __err__);\ + __status__ = __err__;\ + goto ERRORHANDLER;\ +} while (0) + +#define ATL_NULLCHECK(__status__, __ptr__) do {\ + if (__ptr__ == NULL) {\ + ATL_ERRORREPORT(__status__, ATL_NULL_PTR);\ + } \ +} while (0) + +#define ATL_CATCH(__status__) \ +ERRORHANDLER :\ +if(ATL_IS_ERR(__status__)) \ + +#endif diff --git a/wilc3000/atl_msg_queue.c b/wilc3000/atl_msg_queue.c index 26ea6f6..93f2ede 100644 --- a/wilc3000/atl_msg_queue.c +++ b/wilc3000/atl_msg_queue.c @@ -1,184 +1,184 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "atl_error_support.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "linux/string.h" -#include "atl_msg_queue.h" - -signed int ATL_MsgQueueCreate(struct MsgQueueHandle *pHandle) -{ - spin_lock_init(&pHandle->strCriticalSection); - sema_init(&pHandle->hSem, 0); - - pHandle->pstrMessageList = NULL; - pHandle->u32ReceiversCount = 0; - pHandle->bExiting = false; - - return ATL_SUCCESS; -} -EXPORT_SYMBOL(ATL_MsgQueueCreate); - -signed int ATL_MsgQueueDestroy(struct MsgQueueHandle *pHandle) -{ - pHandle->bExiting = true; - - /* Release any waiting receiver thread.*/ - while (pHandle->u32ReceiversCount > 0) { - up(&pHandle->hSem); - pHandle->u32ReceiversCount--; - } - - while (NULL != pHandle->pstrMessageList) { - struct Message *pstrMessge = pHandle->pstrMessageList->pstrNext; - - kfree(pHandle->pstrMessageList); - pHandle->pstrMessageList = pstrMessge; - } - - return ATL_SUCCESS; -} -EXPORT_SYMBOL(ATL_MsgQueueDestroy); - -signed int ATL_MsgQueueSend(struct MsgQueueHandle *pHandle, - const void *pvSendBuffer, - unsigned int u32SendBufferSize) -{ - signed int s32RetStatus = ATL_SUCCESS; - unsigned long flags; - struct Message *pstrMessage = NULL; - - if ((NULL == pHandle) - || (u32SendBufferSize == 0) - || (pvSendBuffer == NULL)) - ATL_ERRORREPORT(s32RetStatus, ATL_INVALID_ARGUMENT); - - if (pHandle->bExiting == true) - ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); - - spin_lock_irqsave(&pHandle->strCriticalSection, flags); - - /* construct a new message */ - pstrMessage = kmalloc(sizeof(struct Message), GFP_ATOMIC); - ATL_NULLCHECK(s32RetStatus, pstrMessage); - pstrMessage->u32Length = u32SendBufferSize; - pstrMessage->pstrNext = NULL; - pstrMessage->pvBuffer = kmalloc(u32SendBufferSize, GFP_ATOMIC); - ATL_NULLCHECK(s32RetStatus, pstrMessage->pvBuffer); - memcpy(pstrMessage->pvBuffer, pvSendBuffer, u32SendBufferSize); - - - /* add it to the message queue */ - if (NULL == pHandle->pstrMessageList) { - pHandle->pstrMessageList = pstrMessage; - } else { - struct Message *pstrTailMsg = pHandle->pstrMessageList; - - while (NULL != pstrTailMsg->pstrNext) - pstrTailMsg = pstrTailMsg->pstrNext; - pstrTailMsg->pstrNext = pstrMessage; - } - - spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); - - up(&pHandle->hSem); - - ATL_CATCH(s32RetStatus){ - /* error occured, free any allocations */ - if (NULL != pstrMessage) { - kfree(pstrMessage->pvBuffer); - kfree(pstrMessage); - } - } - - return s32RetStatus; -} -EXPORT_SYMBOL(ATL_MsgQueueSend); - -signed int ATL_MsgQueueRecv(struct MsgQueueHandle *pHandle, - void *pvRecvBuffer, unsigned int u32RecvBufferSize, - unsigned int *pu32ReceivedLength) -{ - - struct Message *pstrMessage; - signed int s32RetStatus = ATL_SUCCESS; - unsigned long flags; - - if ((NULL == pHandle) || (u32RecvBufferSize == 0) - || (NULL == pvRecvBuffer) || (NULL == pu32ReceivedLength)) - ATL_ERRORREPORT(s32RetStatus, ATL_INVALID_ARGUMENT); - - if (pHandle->bExiting == true) - ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); - - spin_lock_irqsave(&pHandle->strCriticalSection, flags); - pHandle->u32ReceiversCount++; - - /* timed out, just exit without consumeing the message */ - spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); - down(&(pHandle->hSem)); - - ATL_ERRORCHECK(s32RetStatus); - - if (pHandle->bExiting) - ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); - - spin_lock_irqsave(&pHandle->strCriticalSection, flags); - - pstrMessage = pHandle->pstrMessageList; - if (NULL == pstrMessage) { - spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); - ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); - } - - /* check buffer size */ - if (u32RecvBufferSize < pstrMessage->u32Length) { - spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); - up(&pHandle->hSem); - ATL_ERRORREPORT(s32RetStatus, ATL_BUFFER_OVERFLOW); - } - - /* 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); - - ATL_CATCH(s32RetStatus) - { - } - return s32RetStatus; -} +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "atl_error_support.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/string.h" +#include "atl_msg_queue.h" + +signed int ATL_MsgQueueCreate(struct MsgQueueHandle *pHandle) +{ + spin_lock_init(&pHandle->strCriticalSection); + sema_init(&pHandle->hSem, 0); + + pHandle->pstrMessageList = NULL; + pHandle->u32ReceiversCount = 0; + pHandle->bExiting = false; + + return ATL_SUCCESS; +} +EXPORT_SYMBOL(ATL_MsgQueueCreate); + +signed int ATL_MsgQueueDestroy(struct MsgQueueHandle *pHandle) +{ + pHandle->bExiting = true; + + /* Release any waiting receiver thread.*/ + while (pHandle->u32ReceiversCount > 0) { + up(&pHandle->hSem); + pHandle->u32ReceiversCount--; + } + + while (NULL != pHandle->pstrMessageList) { + struct Message *pstrMessge = pHandle->pstrMessageList->pstrNext; + + kfree(pHandle->pstrMessageList); + pHandle->pstrMessageList = pstrMessge; + } + + return ATL_SUCCESS; +} +EXPORT_SYMBOL(ATL_MsgQueueDestroy); + +signed int ATL_MsgQueueSend(struct MsgQueueHandle *pHandle, + const void *pvSendBuffer, + unsigned int u32SendBufferSize) +{ + signed int s32RetStatus = ATL_SUCCESS; + unsigned long flags; + struct Message *pstrMessage = NULL; + + if ((NULL == pHandle) + || (u32SendBufferSize == 0) + || (pvSendBuffer == NULL)) + ATL_ERRORREPORT(s32RetStatus, ATL_INVALID_ARGUMENT); + + if (pHandle->bExiting == true) + ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + + /* construct a new message */ + pstrMessage = kmalloc(sizeof(struct Message), GFP_ATOMIC); + ATL_NULLCHECK(s32RetStatus, pstrMessage); + pstrMessage->u32Length = u32SendBufferSize; + pstrMessage->pstrNext = NULL; + pstrMessage->pvBuffer = kmalloc(u32SendBufferSize, GFP_ATOMIC); + ATL_NULLCHECK(s32RetStatus, pstrMessage->pvBuffer); + memcpy(pstrMessage->pvBuffer, pvSendBuffer, u32SendBufferSize); + + + /* add it to the message queue */ + if (NULL == pHandle->pstrMessageList) { + pHandle->pstrMessageList = pstrMessage; + } else { + struct Message *pstrTailMsg = pHandle->pstrMessageList; + + while (NULL != pstrTailMsg->pstrNext) + pstrTailMsg = pstrTailMsg->pstrNext; + pstrTailMsg->pstrNext = pstrMessage; + } + + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + + up(&pHandle->hSem); + + ATL_CATCH(s32RetStatus){ + /* error occured, free any allocations */ + if (NULL != pstrMessage) { + kfree(pstrMessage->pvBuffer); + kfree(pstrMessage); + } + } + + return s32RetStatus; +} +EXPORT_SYMBOL(ATL_MsgQueueSend); + +signed int ATL_MsgQueueRecv(struct MsgQueueHandle *pHandle, + void *pvRecvBuffer, unsigned int u32RecvBufferSize, + unsigned int *pu32ReceivedLength) +{ + + struct Message *pstrMessage; + signed int s32RetStatus = ATL_SUCCESS; + unsigned long flags; + + if ((NULL == pHandle) || (u32RecvBufferSize == 0) + || (NULL == pvRecvBuffer) || (NULL == pu32ReceivedLength)) + ATL_ERRORREPORT(s32RetStatus, ATL_INVALID_ARGUMENT); + + if (pHandle->bExiting == true) + ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + pHandle->u32ReceiversCount++; + + /* timed out, just exit without consumeing the message */ + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + down(&(pHandle->hSem)); + + ATL_ERRORCHECK(s32RetStatus); + + if (pHandle->bExiting) + ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); + + spin_lock_irqsave(&pHandle->strCriticalSection, flags); + + pstrMessage = pHandle->pstrMessageList; + if (NULL == pstrMessage) { + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + ATL_ERRORREPORT(s32RetStatus, ATL_FAIL); + } + + /* check buffer size */ + if (u32RecvBufferSize < pstrMessage->u32Length) { + spin_unlock_irqrestore(&pHandle->strCriticalSection, flags); + up(&pHandle->hSem); + ATL_ERRORREPORT(s32RetStatus, ATL_BUFFER_OVERFLOW); + } + + /* 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); + + ATL_CATCH(s32RetStatus) + { + } + return s32RetStatus; +} EXPORT_SYMBOL(ATL_MsgQueueRecv); \ No newline at end of file diff --git a/wilc3000/atl_msg_queue.h b/wilc3000/atl_msg_queue.h index 9aba6e1..71402f9 100644 --- a/wilc3000/atl_msg_queue.h +++ b/wilc3000/atl_msg_queue.h @@ -1,68 +1,68 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef __ATL_MSG_QUEUE_H__ -#define __ATL_MSG_QUEUE_H__ - -/* Message Queue type is a structure */ -struct Message { - void *pvBuffer; - unsigned int u32Length; - struct Message *pstrNext; -}; - -struct MsgQueueHandle { - struct semaphore hSem; - spinlock_t strCriticalSection; - bool bExiting; - unsigned int u32ReceiversCount; - struct Message *pstrMessageList; -}; - -/* - * Creates a new Message queue, if the feature - * CONFIG_ATL_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 - */ -signed int ATL_MsgQueueCreate(struct MsgQueueHandle *pHandle); - -/* - * Sends a message, this API will block unil the message is - * actually sent or until it is timedout (as long as the feature - * CONFIG_ATL_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout - * is not set to ATL_OS_INFINITY), zero timeout is a valid value - */ -signed int ATL_MsgQueueSend(struct MsgQueueHandle *pHandle, - const void *pvSendBuffer, unsigned int u32SendBufferSize); - -/* - * Receives a message, this API will block unil a message is - * received or until it is timedout (as long as the feature - * CONFIG_ATL_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout - * is not set to ATL_OS_INFINITY), zero timeout is a valid value - */ -signed int ATL_MsgQueueRecv(struct MsgQueueHandle *pHandle, - void *pvRecvBuffer, unsigned int u32RecvBufferSize, - unsigned int *pu32ReceivedLength); - -/* - * Destroys an existing Message queue - */ -signed int ATL_MsgQueueDestroy(struct MsgQueueHandle *pHandle); -#endif +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __ATL_MSG_QUEUE_H__ +#define __ATL_MSG_QUEUE_H__ + +/* Message Queue type is a structure */ +struct Message { + void *pvBuffer; + unsigned int u32Length; + struct Message *pstrNext; +}; + +struct MsgQueueHandle { + struct semaphore hSem; + spinlock_t strCriticalSection; + bool bExiting; + unsigned int u32ReceiversCount; + struct Message *pstrMessageList; +}; + +/* + * Creates a new Message queue, if the feature + * CONFIG_ATL_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 + */ +signed int ATL_MsgQueueCreate(struct MsgQueueHandle *pHandle); + +/* + * Sends a message, this API will block unil the message is + * actually sent or until it is timedout (as long as the feature + * CONFIG_ATL_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout + * is not set to ATL_OS_INFINITY), zero timeout is a valid value + */ +signed int ATL_MsgQueueSend(struct MsgQueueHandle *pHandle, + const void *pvSendBuffer, unsigned int u32SendBufferSize); + +/* + * Receives a message, this API will block unil a message is + * received or until it is timedout (as long as the feature + * CONFIG_ATL_MSG_QUEUE_TIMEOUT is enabled and pstrAttrs->u32Timeout + * is not set to ATL_OS_INFINITY), zero timeout is a valid value + */ +signed int ATL_MsgQueueRecv(struct MsgQueueHandle *pHandle, + void *pvRecvBuffer, unsigned int u32RecvBufferSize, + unsigned int *pu32ReceivedLength); + +/* + * Destroys an existing Message queue + */ +signed int ATL_MsgQueueDestroy(struct MsgQueueHandle *pHandle); +#endif diff --git a/wilc3000/core_configurator.c b/wilc3000/core_configurator.c index 7e925da..ddf868e 100644 --- a/wilc3000/core_configurator.c +++ b/wilc3000/core_configurator.c @@ -1,1678 +1,1678 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "core_configurator.h" -#include "linux_wlan.h" - -#define PHY_802_11n -#define MAX_CFG_PKTLEN 1450 -#define MSG_HEADER_LEN 4 -#define QUERY_MSG_TYPE 'Q' -#define WRITE_MSG_TYPE 'W' -#define RESP_MSG_TYPE 'R' -#define WRITE_RESP_SUCCESS 1 -#define INVALID 255 -#define MAC_ADDR_LEN 6 -#define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \ - BEACON_INTERVAL_LEN + CAP_INFO_LEN) - -/* Basic Frame Type Codes (2-bit) */ -enum tenuBasicFrmType { - FRAME_TYPE_CONTROL = 0x04, - FRAME_TYPE_DATA = 0x08, - FRAME_TYPE_MANAGEMENT = 0x00, - FRAME_TYPE_RESERVED = 0x0C, - FRAME_TYPE_FORCE_32BIT = 0xFFFFFFFF -}; - - -/* Basic Frame Classes */ -enum tenuFrameClass { - CLASS1_FRAME_TYPE = 0x00, - CLASS2_FRAME_TYPE = 0x01, - CLASS3_FRAME_TYPE = 0x02, - FRAME_CLASS_FORCE_32BIT = 0xFFFFFFFF -}; - -/* Element ID of various Information Elements */ -enum tenuInfoElemID { - 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 -}; - -struct tstrConfigPktInfo { - char *pcRespBuffer; - signed int s32MaxRespBuffLen; - signed int s32BytesRead; - bool bRespRequired; -}; - - -static struct semaphore SemHandleSendPkt; -static struct semaphore SemHandlePktResp; -static s8 *gps8ConfigPacket; -static struct tstrConfigPktInfo gstrConfigPktInfo; -static u8 g_seqno; -static s16 g_wid_num = -1; -static u16 Res_Len; -static u8 g_oper_mode = SET_CFG; - -/* WID Switches */ -static struct tstrWID gastrWIDs[] = { - {WID_FIRMWARE_VERSION, WID_STR}, - {WID_PHY_VERSION, WID_STR}, - {WID_HARDWARE_VERSION, WID_STR}, - {WID_BSS_TYPE, WID_CHAR}, - {WID_QOS_ENABLE, WID_CHAR}, - {WID_11I_MODE, WID_CHAR}, - {WID_CURRENT_TX_RATE, WID_CHAR}, - {WID_LINKSPEED, WID_CHAR}, - {WID_RTS_THRESHOLD, WID_SHORT}, - {WID_FRAG_THRESHOLD, WID_SHORT}, - {WID_SSID, WID_STR}, - {WID_BSSID, WID_ADR}, - {WID_BEACON_INTERVAL, WID_SHORT}, - {WID_POWER_MANAGEMENT, WID_CHAR}, - {WID_LISTEN_INTERVAL, WID_CHAR}, - {WID_DTIM_PERIOD, WID_CHAR}, - {WID_CURRENT_CHANNEL, WID_CHAR}, - {WID_TX_POWER_LEVEL_11A, WID_CHAR}, - {WID_TX_POWER_LEVEL_11B, WID_CHAR}, - {WID_PREAMBLE, WID_CHAR}, - {WID_11G_OPERATING_MODE, WID_CHAR}, - {WID_MAC_ADDR, WID_ADR}, - {WID_IP_ADDRESS, WID_ADR}, - {WID_ACK_POLICY, WID_CHAR}, - {WID_PHY_ACTIVE_REG, WID_CHAR}, - {WID_AUTH_TYPE, WID_CHAR}, - {WID_REKEY_POLICY, WID_CHAR}, - {WID_REKEY_PERIOD, WID_INT}, - {WID_REKEY_PACKET_COUNT, WID_INT}, - {WID_11I_PSK, WID_STR}, - {WID_1X_KEY, WID_STR}, - {WID_1X_SERV_ADDR, WID_IP}, - {WID_SUPP_USERNAME, WID_STR}, - {WID_SUPP_PASSWORD, WID_STR}, - {WID_USER_CONTROL_ON_TX_POWER, WID_CHAR}, - {WID_MEMORY_ADDRESS, WID_INT}, - {WID_MEMORY_ACCESS_32BIT, WID_INT}, - {WID_MEMORY_ACCESS_16BIT, WID_SHORT}, - {WID_MEMORY_ACCESS_8BIT, WID_CHAR}, - {WID_SITE_SURVEY_RESULTS, WID_STR}, - {WID_PMKID_INFO, WID_STR}, - {WID_ASSOC_RES_INFO, WID_STR}, - /* 4 Wids added for the CAPI tool*/ - {WID_MANUFACTURER, WID_STR}, - {WID_MODEL_NAME, WID_STR}, - {WID_MODEL_NUM, WID_STR}, - {WID_DEVICE_NAME, WID_STR}, - {WID_SSID_PROBE_REQ, WID_STR}, - -#ifdef MAC_802_11N - {WID_11N_ENABLE, WID_CHAR}, - {WID_11N_CURRENT_TX_MCS, WID_CHAR}, - {WID_TX_POWER_LEVEL_11N, WID_CHAR}, - {WID_11N_OPERATING_MODE, WID_CHAR}, - {WID_11N_SMPS_MODE, WID_CHAR}, - {WID_11N_PROT_MECH, WID_CHAR}, - {WID_11N_ERP_PROT_TYPE, WID_CHAR}, - {WID_11N_HT_PROT_TYPE, WID_CHAR}, - {WID_11N_PRINT_STATS, WID_CHAR}, - {WID_11N_AUTORATE_TABLE, WID_BIN_DATA}, - {WID_HOST_CONFIG_IF_TYPE, WID_CHAR}, - {WID_HOST_DATA_IF_TYPE, WID_CHAR}, - {WID_11N_SIG_QUAL_VAL, WID_SHORT}, - {WID_11N_IMMEDIATE_BA_ENABLED, WID_CHAR}, - {WID_11N_TXOP_PROT_DISABLE, WID_CHAR}, - {WID_11N_SHORT_GI_20MHZ_ENABLE, WID_CHAR}, - {WID_SHORT_SLOT_ALLOWED, WID_CHAR}, - {WID_11W_ENABLE, WID_CHAR}, - {WID_11W_MGMT_PROT_REQ, WID_CHAR}, - {WID_2040_ENABLE, WID_CHAR}, - {WID_2040_COEXISTENCE, WID_CHAR}, - {WID_USER_SEC_CHANNEL_OFFSET, WID_CHAR}, - {WID_2040_CURR_CHANNEL_OFFSET, WID_CHAR}, - {WID_2040_40MHZ_INTOLERANT, WID_CHAR}, - {WID_HUT_RESTART, WID_CHAR}, - {WID_HUT_NUM_TX_PKTS, WID_INT}, - {WID_HUT_FRAME_LEN, WID_SHORT}, - {WID_HUT_TX_FORMAT, WID_CHAR}, - {WID_HUT_BANDWIDTH, WID_CHAR}, - {WID_HUT_OP_BAND, WID_CHAR}, - {WID_HUT_STBC, WID_CHAR}, - {WID_HUT_ESS, WID_CHAR}, - {WID_HUT_ANTSET, WID_CHAR}, - {WID_HUT_HT_OP_MODE, WID_CHAR}, - {WID_HUT_RIFS_MODE, WID_CHAR}, - {WID_HUT_SMOOTHING_REC, WID_CHAR}, - {WID_HUT_SOUNDING_PKT, WID_CHAR}, - {WID_HUT_HT_CODING, WID_CHAR}, - {WID_HUT_TEST_DIR, WID_CHAR}, - {WID_HUT_TXOP_LIMIT, WID_SHORT}, - {WID_HUT_DEST_ADDR, WID_ADR}, - {WID_HUT_TX_PATTERN, WID_BIN_DATA}, - {WID_HUT_TX_TIME_TAKEN, WID_INT}, - {WID_HUT_PHY_TEST_MODE, WID_CHAR}, - {WID_HUT_PHY_TEST_RATE_HI, WID_CHAR}, - {WID_HUT_PHY_TEST_RATE_LO, WID_CHAR}, - {WID_HUT_TX_TEST_TIME, WID_INT}, - {WID_HUT_LOG_INTERVAL, WID_INT}, - {WID_HUT_DISABLE_RXQ_REPLENISH, WID_CHAR}, - {WID_HUT_TEST_ID, WID_STR}, - {WID_HUT_KEY_ORIGIN, WID_CHAR}, - {WID_HUT_BCST_PERCENT, WID_CHAR}, - {WID_HUT_GROUP_CIPHER_TYPE, WID_CHAR}, - {WID_HUT_STATS, WID_BIN_DATA}, - {WID_HUT_TSF_TEST_MODE, WID_CHAR}, - {WID_HUT_SIG_QUAL_AVG, WID_SHORT}, - {WID_HUT_SIG_QUAL_AVG_CNT, WID_SHORT}, - {WID_HUT_TSSI_VALUE, WID_CHAR}, - {WID_HUT_MGMT_PERCENT, WID_CHAR}, - {WID_HUT_MGMT_BCST_PERCENT, WID_CHAR}, - {WID_HUT_MGMT_ALLOW_HT, WID_CHAR}, - {WID_HUT_UC_MGMT_TYPE, WID_CHAR}, - {WID_HUT_BC_MGMT_TYPE, WID_CHAR}, - {WID_HUT_UC_MGMT_FRAME_LEN, WID_SHORT}, - {WID_HUT_BC_MGMT_FRAME_LEN, WID_SHORT}, - {WID_HUT_11W_MFP_REQUIRED_TX, WID_CHAR}, - {WID_HUT_11W_MFP_PEER_CAPABLE, WID_CHAR}, - {WID_HUT_11W_TX_IGTK_ID, WID_CHAR}, - {WID_HUT_FC_TXOP_MOD, WID_CHAR}, - {WID_HUT_FC_PROT_TYPE, WID_CHAR}, - {WID_HUT_SEC_CCA_ASSERT, WID_CHAR}, -#endif /* MAC_802_11N */ -}; - -u16 g_num_total_switches = (sizeof(gastrWIDs) / sizeof(struct tstrWID)); - -static inline u8 ascii_hex_to_dec(u8 num) -{ - if ((num >= '0') && (num <= '9')) - return (num - '0'); - else if ((num >= 'A') && (num <= 'F')) - return (10 + (num - 'A')); - else if ((num >= 'a') && (num <= 'f')) - return (10 + (num - 'a')); - - return INVALID; -} - -static inline u8 get_hex_char(u8 inp) -{ - u8 *d2htab = "0123456789ABCDEF"; - - return d2htab[inp & 0xF]; -} - -/* - * This function extracts the MAC address held in a string in standard format - * into another buffer as integers. - */ -static inline u16 extract_mac_addr(char *str, u8 *buff) -{ - *buff = 0; - while (*str != '\0') { - if ((*str == ':') || (*str == '-')) - *(++buff) = 0; - else - *buff = (*buff << 4) + ascii_hex_to_dec(*str); - - str++; - } - - return MAC_ADDR_LEN; -} - -/* - * This function creates MAC address in standard format from a buffer of - * integers. - */ -static inline void create_mac_addr(u8 *str, u8 *buff) -{ - unsigned int i = 0; - unsigned int j = 0; - - for (i = 0; i < MAC_ADDR_LEN; i++) { - str[j++] = get_hex_char((u8)((buff[i] >> 4) & 0x0F)); - str[j++] = get_hex_char((u8)(buff[i] & 0x0F)); - str[j++] = ':'; - } - str[--j] = '\0'; -} - -/* - * This function converts the IP address string in dotted decimal format to - * unsigned integer. This functionality is similar to the library function - * inet_addr() but is reimplemented here since I could not confirm that - * inet_addr is platform independent. - * ips=>IP Address String in dotted decimal format - * ipn=>Pointer to IP Address in integer format - */ -static inline u8 conv_ip_to_int(u8 *ips, unsigned int *ipn) -{ - u8 i = 0; - u8 ipb = 0; - - *ipn = 0; - /* Integer to string for each component */ - while (ips[i] != '\0') { - if (ips[i] == '.') { - *ipn = ((*ipn) << 8) | ipb; - ipb = 0; - } else { - ipb = ipb * 10 + ascii_hex_to_dec(ips[i]); - } - i++; - } - - /* The last byte of the IP address is read in here */ - *ipn = ((*ipn) << 8) | ipb; - - return 0; -} - -/* - * This function converts the IP address from integer format to dotted - * decimal string format. Alternative to std library fn inet_ntoa(). - * ips=>Buffer to hold IP Address String dotted decimal format (Min 17B) - * ipn=>IP Address in integer format - */ -static inline u8 conv_int_to_ip(u8 *ips, unsigned int ipn) -{ - u8 i = 0; - u8 ipb = 0; - u8 cnt = 0; - u8 ipbsize = 0; - - for (cnt = 4; cnt > 0; cnt--) { - ipb = (ipn >> (8 * (cnt - 1))) & 0xFF; - - if (ipb >= 100) - ipbsize = 2; - else if (ipb >= 10) - ipbsize = 1; - else - ipbsize = 0; - - switch (ipbsize) { - case 2: - ips[i++] = get_hex_char(ipb / 100); - ipb %= 100; - - case 1: - ips[i++] = get_hex_char(ipb / 10); - ipb %= 10; - - default: - ips[i++] = get_hex_char(ipb); - } - - if (cnt > 1) - ips[i++] = '.'; - } - - ips[i] = '\0'; - - return i; -} - -static inline enum WID_TYPE get_wid_type(unsigned int wid_num) -{ - /* Check for iconfig specific WID types first */ - if ((wid_num == WID_BSSID) || - (wid_num == WID_MAC_ADDR) || - (wid_num == WID_IP_ADDRESS) || - (wid_num == WID_HUT_DEST_ADDR)) - return WID_ADR; - - if ((WID_1X_SERV_ADDR == wid_num) || - (WID_STACK_IP_ADDR == wid_num) || - (WID_STACK_NETMASK_ADDR == wid_num)) - return WID_IP; - - /* Next check for standard WID types */ - if (wid_num < 0x1000) - return WID_CHAR; - else if (wid_num < 0x2000) - return WID_SHORT; - else if (wid_num < 0x3000) - return WID_INT; - else if (wid_num < 0x4000) - return WID_STR; - else if (wid_num < 0x5000) - return WID_BIN_DATA; - - return WID_UNDEF; -} - -/* - * 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 = 0; - - bcn_per = data[0]; - bcn_per |= (data[1] << 8); - - return bcn_per; -} - -static inline unsigned int get_beacon_timestamp_lo(u8 *data) -{ - unsigned int time_stamp = 0; - unsigned int 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 unsigned int get_beacon_timestamp_hi(u8 *data) -{ - unsigned int time_stamp = 0; - unsigned int 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' bits from the MAC header of the - * input frame. - * Returns the value in the LSB of the returned value. - */ -static inline enum tenuBasicFrmType get_type(u8 *header) -{ - return ((enum tenuBasicFrmType)(header[0] & 0x0C)); -} - -/* - * 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 tenuFrmSubtype get_sub_type(u8 *header) -{ - return ((enum tenuFrmSubtype)(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 tenuFrmSubtype st = BEACON; - - 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 = 0; - - cap_info = data[0]; - cap_info |= (data[1] << 8); - - return cap_info; -} - -/* - * This funcion 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 = 0; - - 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 = 0; - - asoc_id = data[4]; - asoc_id |= (data[5] << 8); - - return asoc_id; -} - -/* - * initializes the Core Configurator - */ - -signed int CoreConfiguratorInit(void) -{ - signed int s32Error = ATL_SUCCESS; - - PRINT_D(CORECONFIG_DBG,"CoreConfiguratorInit() \n"); - - sema_init(&SemHandleSendPkt, 1); - sema_init(&SemHandlePktResp, 0); - - gps8ConfigPacket = kmalloc(MAX_PACKET_BUFF_SIZE, GFP_ATOMIC); - if (gps8ConfigPacket == NULL) { - s32Error = ATL_NO_MEM; - goto _fail_; - } - - memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); - - memset((void *)(&gstrConfigPktInfo), 0, - sizeof(struct tstrConfigPktInfo)); -_fail_: - return s32Error; -} - -u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset) -{ - u16 u16index = 0; - - /*************************************************************************/ - /* 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 0; -} - -/* - * 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 0; -} - -u8 get_current_channel(u8 *pu8msa, u16 u16RxLen) -{ -#ifdef PHY_802_11n -#ifdef FIVE_GHZ_BAND - /* Get the current channel as its not set in */ - /* 802.11a beacons/probe response */ - return (get_rf_channel() + 1); -#else /* FIVE_GHZ_BAND */ - /* Extract current channel information from */ - /* the beacon/probe response frame */ - return get_current_channel_802_11n(pu8msa, u16RxLen); -#endif /* FIVE_GHZ_BAND */ -#else - return 0; -#endif /* PHY_802_11n */ -} - -/* - * parses the received 'N' message - */ -signed int ParseNetworkInfo(u8 *pu8MsgBuffer, struct tstrNetworkInfo **ppstrNetworkInfo) -{ - signed int s32Error = ATL_SUCCESS; - struct tstrNetworkInfo *pstrNetworkInfo = NULL; - u8 u8MsgType = 0; - u8 u8MsgID = 0; - u16 u16MsgLen = 0; - u16 u16WidID = (u16)WID_NIL; - u16 u16WidLen = 0; - u8 *pu8WidVal = 0; - - u8 *pu8msa = 0; - u16 u16RxLen = 0; - u8 *pu8TimElm = 0; - u8 *pu8IEs = 0; - u16 u16IEsLen = 0; - u8 u8index = 0; - unsigned int u32Tsf_Lo; - unsigned int u32Tsf_Hi; - - u8MsgType = pu8MsgBuffer[0]; - - /* Check whether the received message type is 'N' */ - if ('N' != u8MsgType) { - PRINT_ER("Received Message format incorrect.\n"); - ATL_ERRORREPORT(s32Error, ATL_FAIL); - } - - /* 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" */ - pstrNetworkInfo = kmalloc(sizeof(struct tstrNetworkInfo), GFP_ATOMIC); - memset((void *)(pstrNetworkInfo), 0, sizeof(struct tstrNetworkInfo)); - - 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); -#ifdef WILC_P2P - /* Get time-stamp [Low only 32 bit] */ - pstrNetworkInfo->u32Tsf = get_beacon_timestamp_lo(pu8msa); - PRINT_D(CORECONFIG_DBG,"TSF :%x\n",pstrNetworkInfo->u32Tsf ); -#endif - - /* Get full time-stamp [Low and High 64 bit] */ - u32Tsf_Lo = get_beacon_timestamp_lo(pu8msa); - u32Tsf_Hi = get_beacon_timestamp_hi(pu8msa); - - /*TicketId1023*/ - pstrNetworkInfo->u64Tsf = u32Tsf_Hi; - pstrNetworkInfo->u64Tsf = ((pstrNetworkInfo->u64Tsf) << 32) | u32Tsf_Lo; - - /* Get SSID */ - get_ssid(pu8msa, pstrNetworkInfo->au8ssid, &(pstrNetworkInfo->u8SsidLen)); - - /* Get BSSID */ - get_BSSID(pu8msa, pstrNetworkInfo->au8bssid); - - /* Get the current channel */ - pstrNetworkInfo->u8channel = get_current_channel(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 != 0) - 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 = kmalloc(u16IEsLen, GFP_ATOMIC); - memset((void *)(pstrNetworkInfo->pu8IEs), 0, u16IEsLen); - - memcpy(pstrNetworkInfo->pu8IEs, pu8IEs, u16IEsLen); - } - pstrNetworkInfo->u16IEsLen = u16IEsLen; - - *ppstrNetworkInfo = pstrNetworkInfo; - - ATL_CATCH(s32Error){ - } - return s32Error; -} - -/* - * Deallocates the parsed Network Info - */ -signed int DeallocateNetworkInfo(struct tstrNetworkInfo *pstrNetworkInfo) -{ - signed int s32Error = ATL_SUCCESS; - - if (pstrNetworkInfo != NULL) { - if (pstrNetworkInfo->pu8IEs != NULL) { - kfree(pstrNetworkInfo->pu8IEs); - pstrNetworkInfo->pu8IEs = NULL; - } else { - s32Error = ATL_FAIL; - } - kfree(pstrNetworkInfo); - pstrNetworkInfo = NULL; - } else { - s32Error = ATL_FAIL; - } - return s32Error; -} - -/* - * parses the received Association Response frame - */ -signed int ParseAssocRespInfo(u8 *pu8Buffer, unsigned int u32BufferLen, - struct tstrConnectRespInfo **ppstrConnectRespInfo) -{ - signed int s32Error = ATL_SUCCESS; - struct tstrConnectRespInfo *pstrConnectRespInfo = NULL; - u16 u16AssocRespLen = 0; - u8 *pu8IEs = 0; - u16 u16IEsLen = 0; - - pstrConnectRespInfo = kmalloc(sizeof(*pstrConnectRespInfo), GFP_ATOMIC); - memset((void *)(pstrConnectRespInfo), 0, sizeof(struct tstrConnectRespInfo)); - - 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 = kmalloc(u16IEsLen, GFP_ATOMIC); - memset((void *)(pstrConnectRespInfo->pu8RespIEs), 0, u16IEsLen); - - memcpy(pstrConnectRespInfo->pu8RespIEs, pu8IEs, u16IEsLen); - pstrConnectRespInfo->u16RespIEsLen = u16IEsLen; - } - - *ppstrConnectRespInfo = pstrConnectRespInfo; - - return s32Error; -} - -/* - * Deallocates the parsed Association Response Info - */ -signed int DeallocateAssocRespInfo(struct tstrConnectRespInfo *pstrConnectRespInfo) -{ - signed int s32Error = ATL_SUCCESS; - - if (NULL != pstrConnectRespInfo) { - if (NULL != pstrConnectRespInfo->pu8RespIEs) { - kfree(pstrConnectRespInfo->pu8RespIEs); - pstrConnectRespInfo->pu8RespIEs = NULL; - } else { - s32Error = ATL_FAIL; - } - kfree(pstrConnectRespInfo); - pstrConnectRespInfo = NULL; - } else { - s32Error = ATL_FAIL; - } - return s32Error; -} - -#ifndef CONNECT_DIRECT -signed int ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], - struct wid_site_survey_reslts **ppstrSurveyResults, - unsigned int *pu32SurveyResultsCount) -{ - signed int s32Error = ATL_SUCCESS; - struct wid_site_survey_reslts *pstrSurveyResults = NULL; - unsigned int u32SurveyResultsCount = 0; - unsigned int u32SurveyBytesLength = 0; - u8 *pu8BufferPtr; - unsigned int u32RcvdSurveyResultsNum = 2; - u8 u8ReadSurveyResFragNum; - unsigned int i; - unsigned int j; - - for (i = 0; i < u32RcvdSurveyResultsNum; i++) { - u32SurveyBytesLength = ppu8RcvdSiteSurveyResults[i][0]; - - for (j = 0; j < u32SurveyBytesLength; j += SURVEY_RESULT_LENGTH) - u32SurveyResultsCount++; - } - - pstrSurveyResults = kmalloc_array(u32SurveyResultsCount, - sizeof(struct wid_site_survey_reslts), GFP_ATOMIC); - - if (NULL == pstrSurveyResults) { - u32SurveyResultsCount = 0; - ATL_ERRORREPORT(s32Error, ATL_NO_MEM); - } - - memset((void *)(pstrSurveyResults), 0, - u32SurveyResultsCount * sizeof(struct wid_site_survey_reslts)); - - u32SurveyResultsCount = 0; - - for (i = 0; i < u32RcvdSurveyResultsNum; i++) { - pu8BufferPtr = ppu8RcvdSiteSurveyResults[i]; - - u32SurveyBytesLength = pu8BufferPtr[0]; - - u8ReadSurveyResFragNum = pu8BufferPtr[1]; - - pu8BufferPtr += 2; - - for (j = 0; j < u32SurveyBytesLength; j += SURVEY_RESULT_LENGTH) { - memcpy(&pstrSurveyResults[u32SurveyResultsCount], - pu8BufferPtr, SURVEY_RESULT_LENGTH); - pu8BufferPtr += SURVEY_RESULT_LENGTH; - u32SurveyResultsCount++; - } - } - - ATL_CATCH(s32Error){ - } - *ppstrSurveyResults = pstrSurveyResults; - *pu32SurveyResultsCount = u32SurveyResultsCount; - - return s32Error; -} - -signed int DeallocateSurveyResults(struct wid_site_survey_reslts *pstrSurveyResults) -{ - signed int s32Error = ATL_SUCCESS; - - if (NULL != pstrSurveyResults) - kfree(pstrSurveyResults); - - return s32Error; -} -#endif /* CONNECT_DIRECT */ - -/* - * This function processes a WID of type WID_CHAR and - * updates the cfg packet with the supplied value. - */ -void ProcessCharWid(char *pcPacket, signed int *ps32PktLen, - struct tstrWID *pstrWID, s8 *ps8WidVal) -{ - u8 *pu8val = (u8 *)ps8WidVal; - u8 u8val = 0; - signed int s32PktLen = *ps32PktLen; - - if (NULL == pstrWID) { - PRINT_WRN(CORECONFIG_DBG,"Can't set CHAR val 0x%x ,NULL structure\n",u8val); - return; - } - - /* WID */ - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid >> 8) & 0xFF; - if (g_oper_mode == SET_CFG) { - u8val = *pu8val; - - /* Length */ - pcPacket[s32PktLen++] = sizeof(u8); - - /* Value */ - pcPacket[s32PktLen++] = u8val; - } - *ps32PktLen = s32PktLen; -} - -/* - * This function processes a WID of type WID_SHORT and - * updates the cfg packet with the supplied value. - */ -void ProcessShortWid(char *pcPacket, signed int *ps32PktLen, - struct tstrWID *pstrWID, s8 *ps8WidVal) -{ - u16 *pu16val = (u16 *)ps8WidVal; - u16 u16val = 0; - signed int s32PktLen = *ps32PktLen; - - if (NULL == pstrWID) { - PRINT_WRN(CORECONFIG_DBG,"Can't set SHORT val 0x%x ,NULL structure\n",u16val); - return; - } - - /* WID */ - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); - pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); - - if (g_oper_mode == SET_CFG) { - u16val = *pu16val; - - /* Length */ - pcPacket[s32PktLen++] = sizeof(u16); - - /* Value */ - pcPacket[s32PktLen++] = (u8)(u16val & 0xFF); - pcPacket[s32PktLen++] = (u8)((u16val >> 8) & 0xFF); - } - *ps32PktLen = s32PktLen; -} - -/* - * This function processes a WID of type WID_INT and - * updates the cfg packet with the supplied value. - */ -void ProcessIntWid(char *pcPacket, signed int *ps32PktLen, - struct tstrWID *pstrWID, s8 *ps8WidVal) -{ - unsigned int *pu32val = (unsigned int *)ps8WidVal; - unsigned int u32val = 0; - signed int s32PktLen = *ps32PktLen; - - if (NULL == pstrWID) { - PRINT_WRN(CORECONFIG_DBG,"Can't set INT val 0x%x , NULL structure\n", u32val); - return; - } - - /* WID */ - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); - pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); - - if (g_oper_mode == SET_CFG) { - u32val = *pu32val; - - /* Length */ - pcPacket[s32PktLen++] = sizeof(unsigned int); - - /* Value */ - pcPacket[s32PktLen++] = (u8)(u32val & 0xFF); - pcPacket[s32PktLen++] = (u8)((u32val >> 8) & 0xFF); - pcPacket[s32PktLen++] = (u8)((u32val >> 16) & 0xFF); - pcPacket[s32PktLen++] = (u8)((u32val >> 24) & 0xFF); - } - *ps32PktLen = s32PktLen; -} - -/* - * This function processes a WID of type WID_IP and - * updates the cfg packet with the supplied value. - */ -void ProcessIPwid(char *pcPacket, signed int *ps32PktLen, - struct tstrWID *pstrWID, u8 *pu8ip) -{ - unsigned int u32val = 0; - signed int s32PktLen = *ps32PktLen; - - if (NULL == pstrWID) { - PRINT_WRN(CORECONFIG_DBG,"Can't set IP Addr , NULL structure\n"); - return; - } - - /* WID */ - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); - pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); - - if (g_oper_mode == SET_CFG) { - /* Length */ - pcPacket[s32PktLen++] = sizeof(unsigned int); - - /* Convert the IP Address String to Integer */ - conv_ip_to_int(pu8ip, &u32val); - - /* Value */ - pcPacket[s32PktLen++] = (u8)(u32val & 0xFF); - pcPacket[s32PktLen++] = (u8)((u32val >> 8) & 0xFF); - pcPacket[s32PktLen++] = (u8)((u32val >> 16) & 0xFF); - pcPacket[s32PktLen++] = (u8)((u32val >> 24) & 0xFF); - } - *ps32PktLen = s32PktLen; -} - -/* - * This function processes a WID of type WID_STR and - * updates the cfg packet with the supplied value. - */ -void ProcessStrWid(char *pcPacket, signed int *ps32PktLen, - struct tstrWID *pstrWID, u8 *pu8val, signed int s32ValueSize) -{ - u16 u16MsgLen = 0; - u16 idx = 0; - signed int s32PktLen = *ps32PktLen; - - if (NULL == pstrWID) { - PRINT_WRN(CORECONFIG_DBG,"Can't set STR val, NULL structure\n"); - return; - } - - /* WID */ - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); - pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); - - if (g_oper_mode == SET_CFG) { - /* Message Length */ - u16MsgLen = (u16)s32ValueSize; - - /* Length */ - pcPacket[s32PktLen++] = (u8)u16MsgLen; - - /* Value */ - for (idx = 0; idx < u16MsgLen; idx++) - pcPacket[s32PktLen++] = pu8val[idx]; - } - *ps32PktLen = s32PktLen; -} - -/* - * This function processes a WID of type WID_ADR and - * updates the cfg packet with the supplied value. - */ -void ProcessAdrWid(char *pcPacket, signed int *ps32PktLen, - struct tstrWID *pstrWID, u8 *pu8val) -{ - u16 u16MsgLen = 0; - signed int s32PktLen = *ps32PktLen; - - if (NULL == pstrWID) { - PRINT_WRN(CORECONFIG_DBG,"Can't set Addr WID, NULL structure\n"); - return; - } - - /* WID */ - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); - pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); - - if (g_oper_mode == SET_CFG) { - /* Message Length */ - u16MsgLen = MAC_ADDR_LEN; - - /* Length */ - pcPacket[s32PktLen++] = (u8)u16MsgLen; - - /* Value */ - extract_mac_addr(pu8val, pcPacket + s32PktLen); - s32PktLen += u16MsgLen; - } - *ps32PktLen = s32PktLen; -} - -/* - * This function processes a WID of type WID_BIN_DATA and - * updates the cfg packet with the supplied value. - */ -void ProcessBinWid(char *pcPacket, signed int *ps32PktLen, - struct tstrWID *pstrWID, u8 *pu8val, signed int s32ValueSize) -{ - u16 u16MsgLen = 0; - u16 idx = 0; - signed int s32PktLen = *ps32PktLen; - u8 u8checksum = 0; - - if (NULL == pstrWID) { - PRINT_WRN(CORECONFIG_DBG,"Can't set BIN val, NULL structure\n"); - return; - } - - /* WID */ - pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); - pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); - - if (g_oper_mode == SET_CFG) { - /* Message Length */ - u16MsgLen = (u16)s32ValueSize; - - /* Length */ - pcPacket[s32PktLen++] = (u8)(u16MsgLen & 0xFF); - pcPacket[s32PktLen++] = (u8)((u16MsgLen >> 8) & 0xFF); - - /* Value */ - for (idx = 0; idx < u16MsgLen; idx++) - pcPacket[s32PktLen++] = pu8val[idx]; - - /* checksum */ - for (idx = 0; idx < u16MsgLen; idx++) - u8checksum += pcPacket[MSG_HEADER_LEN + idx + 4]; - - pcPacket[s32PktLen++] = u8checksum; - } - *ps32PktLen = s32PktLen; -} - -/* This function parses the response frame got from the device */ -signed int further_process_response(u8 *resp, - u16 u16WIDid, - u16 cfg_len, - bool process_wid_num, - unsigned int cnt, - struct tstrWID *pstrWIDresult) -{ - unsigned int retval = 0; - unsigned int idx = 0; - u8 cfg_chr = 0; - u16 cfg_sht = 0; - unsigned int cfg_int = 0; - u8 cfg_str[256] = {0}; - enum WID_TYPE enuWIDtype = WID_UNDEF; - - if (process_wid_num) - enuWIDtype = get_wid_type(g_wid_num); - else - enuWIDtype = gastrWIDs[cnt].enuWIDtype; - - switch (enuWIDtype) { - case WID_CHAR: - { - cfg_chr = resp[idx]; - /*Set local copy of WID*/ - *pstrWIDresult->ps8WidVal = cfg_chr; - break; - } - - case WID_SHORT: - { - u16 *pu16val = (u16 *)(pstrWIDresult->ps8WidVal); - - cfg_sht = MAKE_WORD16(resp[idx], resp[idx + 1]); - *pu16val = cfg_sht; - break; - } - - case WID_INT: - { - unsigned int *pu32val = (unsigned int *)(pstrWIDresult->ps8WidVal); - - cfg_int = MAKE_WORD32( - MAKE_WORD16(resp[idx], resp[idx + 1]), - MAKE_WORD16(resp[idx + 2], resp[idx + 3]) - ); - *pu32val = cfg_int; - break; - } - - case WID_STR: - { - memcpy(cfg_str, resp + idx, cfg_len); - - if (pstrWIDresult->s32ValueSize >= cfg_len) { - memcpy(pstrWIDresult->ps8WidVal, cfg_str, cfg_len); - pstrWIDresult->s32ValueSize = cfg_len; - } else { - PRINT_ER("allocated WID buffer length is smaller than the received WID Length \n"); - retval = -2; - } - - break; - } - - case WID_ADR: - create_mac_addr(cfg_str, resp + idx); - - strncpy(pstrWIDresult->ps8WidVal, cfg_str, strlen(cfg_str)); - pstrWIDresult->ps8WidVal[strlen(cfg_str)] = '\0'; - break; - - case WID_IP: - cfg_int = MAKE_WORD32( - MAKE_WORD16(resp[idx], resp[idx + 1]), - MAKE_WORD16(resp[idx + 2], resp[idx + 3]) - ); - conv_int_to_ip(cfg_str, cfg_int); - break; - - case WID_BIN_DATA: - { - if (pstrWIDresult->s32ValueSize >= cfg_len) { - memcpy(pstrWIDresult->ps8WidVal, resp + idx, cfg_len); - pstrWIDresult->s32ValueSize = cfg_len; - } else { - PRINT_ER("Allocated WID buffer length is smaller than the received WID Length Err(%d)\n",retval); - retval = -2; - } - } - break; - - default: - PRINT_ER("ERROR: Check config database: Error(%d)\n",retval); - retval = -2; - } - - return retval; -} - -/* - * This function parses the command-line options and - * creates the config packets which can be sent to the WLAN station - */ -signed int ParseResponse(u8 *resp, struct tstrWID *pstrWIDcfgResult) -{ - u16 u16RespLen = 0; - u16 u16WIDid = 0; - u16 cfg_len = 0; - enum WID_TYPE enuWIDtype = WID_UNDEF; - bool num_wid_processed = false; - unsigned int cnt = 0; - unsigned int idx = 0; - unsigned int ResCnt = 0; - /* Check whether the received frame is a valid response */ - if (RESP_MSG_TYPE != resp[0]) { - PRINT_INFO(CORECONFIG_DBG,"Received Message format incorrect.\n"); - return -1; - } - - /* Extract Response Length */ - u16RespLen = MAKE_WORD16(resp[2], resp[3]); - Res_Len = u16RespLen; - - for (idx = MSG_HEADER_LEN; idx < u16RespLen; ) { - u16WIDid = MAKE_WORD16(resp[idx], resp[idx + 1]); - cfg_len = resp[idx + 2]; - /* Incase of Bin Type Wid, the length is given by two byte field */ - enuWIDtype = get_wid_type(u16WIDid); - if (WID_BIN_DATA == enuWIDtype) { - cfg_len |= ((u16)resp[idx + 3] << 8) & 0xFF00; - idx++; - } - idx += 3; - if ((u16WIDid == g_wid_num) && (!num_wid_processed)) { - num_wid_processed = true; - - if (-2 == further_process_response(&resp[idx], u16WIDid, cfg_len, true, 0, &pstrWIDcfgResult[ResCnt])) - return -2; - ResCnt++; - } else { - for (cnt = 0; cnt < g_num_total_switches; cnt++) { - if (gastrWIDs[cnt].u16WIDid == u16WIDid) { - if (-2 == further_process_response(&resp[idx], u16WIDid, cfg_len, false, cnt, - &pstrWIDcfgResult[ResCnt])) - return -2; - ResCnt++; - } - } - } idx += cfg_len; - /* In case if BIN type Wid, The last byte of the Cfg packet is the */ - /* Checksum. The WID Length field does not accounts for the checksum. */ - /* The Checksum is discarded. */ - if (WID_BIN_DATA == enuWIDtype) - idx++; - } - - return 0; -} - -/* - * parses the write response [just detects its status: success or failure] - */ - -signed int ParseWriteResponse(u8 *pu8RespBuffer) -{ - signed int s32Error = ATL_FAIL; - u16 u16RespLen = 0; - u16 u16WIDtype = (u16)WID_NIL; - - /* Check whether the received frame is a valid response */ - if (RESP_MSG_TYPE != pu8RespBuffer[0]) { - PRINT_ER("Received Message format incorrect.\n"); - return ATL_FAIL; - } - - /* Extract Response Length */ - u16RespLen = MAKE_WORD16(pu8RespBuffer[2], pu8RespBuffer[3]); - - u16WIDtype = MAKE_WORD16(pu8RespBuffer[4], pu8RespBuffer[5]); - - /* Check for WID_STATUS ID and then check the length and status value */ - if ((u16WIDtype == WID_STATUS) && - (pu8RespBuffer[6] == 1) && - (pu8RespBuffer[7] == WRITE_RESP_SUCCESS)) { - s32Error = WRITE_RESP_SUCCESS; - return s32Error; - } - - /* If the length or status are not as expected return failure */ - s32Error = ATL_FAIL; - return s32Error; -} - -/* - * creates the header of the Configuration Packet - */ - -signed int CreatePacketHeader(char *pcpacket, signed int *ps32PacketLength) -{ - signed int s32Error = ATL_SUCCESS; - u16 u16MsgLen = (u16)(*ps32PacketLength); - u16 u16MsgInd = 0; - - /* The format of the message is: */ - /* +-------------------------------------------------------------------+ */ - /* | Message Type | Message ID | Message Length |Message body | */ - /* +-------------------------------------------------------------------+ */ - /* | 1 Byte | 1 Byte | 2 Bytes | Message Length - 4 | */ - /* +-------------------------------------------------------------------+ */ - - /* The format of a message body of a message type 'W' is: */ - /* +-------------------------------------------------------------------+ */ - /* | WID0 | WID0 Length | WID0 Value | ......................... | */ - /* +-------------------------------------------------------------------+ */ - /* | 2 Bytes | 1 Byte | WID0 Length | ......................... | */ - /* +-------------------------------------------------------------------+ */ - /* Message Type */ - if (g_oper_mode == SET_CFG) - pcpacket[u16MsgInd++] = WRITE_MSG_TYPE; - else - pcpacket[u16MsgInd++] = QUERY_MSG_TYPE; - - /* Sequence Number */ - pcpacket[u16MsgInd++] = g_seqno++; - - /* Message Length */ - pcpacket[u16MsgInd++] = (u8)(u16MsgLen & 0xFF); - pcpacket[u16MsgInd++] = (u8)((u16MsgLen >> 8) & 0xFF); - - *ps32PacketLength = u16MsgLen; - - return s32Error; -} - -/* - * creates Configuration packet based on the Input WIDs - * @pstrWIDs WIDs to be sent in the configuration packet - * @u32WIDsCount number of WIDs to be sent in the configuration packet - * @ps8packet The created Configuration Packet - * @ps32PacketLength Length of the created Configuration Packet - */ - -signed int CreateConfigPacket(s8 *ps8packet, signed int *ps32PacketLength, - struct tstrWID *pstrWIDs, unsigned int u32WIDsCount) -{ - signed int s32Error = ATL_SUCCESS; - unsigned int u32idx = 0; - *ps32PacketLength = MSG_HEADER_LEN; - for (u32idx = 0; u32idx < u32WIDsCount; u32idx++) { - switch (pstrWIDs[u32idx].enuWIDtype) { - case WID_CHAR: - ProcessCharWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], - pstrWIDs[u32idx].ps8WidVal); - break; - - case WID_SHORT: - ProcessShortWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], - pstrWIDs[u32idx].ps8WidVal); - break; - - case WID_INT: - ProcessIntWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], - pstrWIDs[u32idx].ps8WidVal); - break; - - case WID_STR: - ProcessStrWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], - pstrWIDs[u32idx].ps8WidVal, pstrWIDs[u32idx].s32ValueSize); - break; - - case WID_IP: - ProcessIPwid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], - pstrWIDs[u32idx].ps8WidVal); - break; - - case WID_BIN_DATA: - ProcessBinWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], - pstrWIDs[u32idx].ps8WidVal, pstrWIDs[u32idx].s32ValueSize); - break; - - default: - PRINT_ER("ERROR: Check Config database\n"); - } - } - - CreatePacketHeader(ps8packet, ps32PacketLength); - - return s32Error; -} - -signed int ConfigWaitResponse(char *pcRespBuffer, signed int s32MaxRespBuffLen, - signed int *ps32BytesRead, bool bRespRequired) -{ - signed int s32Error = ATL_SUCCESS; - - if (gstrConfigPktInfo.bRespRequired) { - down(&SemHandlePktResp); - - *ps32BytesRead = gstrConfigPktInfo.s32BytesRead; - } - - memset((void *)(&gstrConfigPktInfo), 0, sizeof(struct tstrConfigPktInfo)); - - return s32Error; -} - -signed int ConfigProvideResponse(char *pcRespBuffer, signed int s32RespLen) -{ - signed int s32Error = ATL_SUCCESS; - - if (gstrConfigPktInfo.bRespRequired) { - if (s32RespLen <= gstrConfigPktInfo.s32MaxRespBuffLen) { - memcpy(gstrConfigPktInfo.pcRespBuffer, pcRespBuffer, s32RespLen); - gstrConfigPktInfo.s32BytesRead = s32RespLen; - } else { - memcpy(gstrConfigPktInfo.pcRespBuffer, pcRespBuffer, gstrConfigPktInfo.s32MaxRespBuffLen); - gstrConfigPktInfo.s32BytesRead = gstrConfigPktInfo.s32MaxRespBuffLen; - PRINT_ER("BusProvideResponse() Response greater than the prepared Buffer Size \n"); - } - - up(&SemHandlePktResp); - } - - return s32Error; -} - -/* - * writes the received packet pu8RxPacket in the global Rx FIFO buffer - */ - -signed int ConfigPktReceived(u8 *pu8RxPacket, signed int s32RxPacketLen) -{ - signed int s32Error = ATL_SUCCESS; - u8 u8MsgType = 0; - - u8MsgType = pu8RxPacket[0]; - - switch (u8MsgType) { - case 'R': - { - ConfigProvideResponse(pu8RxPacket, s32RxPacketLen); - - break; - } - - case 'N': - { - PRINT_INFO(CORECONFIG_DBG,"NetworkInfo packet received\n"); - NetworkInfoReceived(pu8RxPacket, s32RxPacketLen); - break; - } - - case 'I': - { - GnrlAsyncInfoReceived(pu8RxPacket, s32RxPacketLen); - break; - } - - case 'S': - { - host_int_ScanCompleteReceived(pu8RxPacket, s32RxPacketLen); - break; - } - - default: - { - PRINT_ER("ConfigPktReceived(): invalid received msg type at the Core Configurator \n"); - } - } - - return s32Error; -} - -/* - * Deinitializes the Core Configurator - */ - -signed int CoreConfiguratorDeInit(void) -{ - signed int s32Error = ATL_SUCCESS; - - PRINT_D(CORECONFIG_DBG,"CoreConfiguratorDeInit() \n"); - - if (NULL != gps8ConfigPacket) { - kfree(gps8ConfigPacket); - gps8ConfigPacket = NULL; - } - - return s32Error; -} - -uint32_t cfg_timed_out_cnt = 0; - -/* - * sends certain Configuration Packet based on the input WIDs - * pstrWIDs using driver config layer - * @pstrWIDs WIDs to be sent in the configuration packet - * @u32WIDsCount number of WIDs to be sent in the configuration packet - * @pu8RxResp The received Packet Response - * @ps32RxRespLen Length of the received Packet Response - */ -signed int SendConfigPkt(u8 u8Mode, struct tstrWID *pstrWIDs, - unsigned int u32WIDsCount, bool bRespRequired, - unsigned int drvHandler) -{ - signed int counter = 0, ret = 0; - - if (NULL == gpstrWlanOps) { - PRINT_INFO(CORECONFIG_DBG,"Net Dev is still not initialized\n"); - return 1; - /*TicketId1003*/ - /*Suspend host interface till recovery is done*/ - } else if (g_bWaitForRecovery) { - PRINT_D(CORECONFIG_DBG, "Host interface is suspended\n"); - while (g_bWaitForRecovery) - msleep(300); - PRINT_D(CORECONFIG_DBG, "Host interface is resumed\n"); - } - - if (NULL == gpstrWlanOps->wlan_cfg_set || - NULL == gpstrWlanOps->wlan_cfg_get) { - PRINT_INFO(CORECONFIG_DBG,"Set and Get is still not initialized\n"); - return 1; - } - - if (u8Mode == GET_CFG) { - for (counter = 0; counter < u32WIDsCount; counter++) { - PRINT_INFO(CORECONFIG_DBG,"Sending CFG packet [%d][%d]\n",!counter, - (counter == u32WIDsCount - 1)); - if (!gpstrWlanOps->wlan_cfg_get(!counter, - pstrWIDs[counter].u16WIDid, - (counter == u32WIDsCount - 1), - drvHandler)) { - ret = -1; - PRINT_ER("[Sendconfigpkt]Get Timed out\n"); - break; - } - } - - counter = 0; - for (counter = 0; counter < u32WIDsCount; counter++) { - pstrWIDs[counter].s32ValueSize = gpstrWlanOps->wlan_cfg_get_value( - pstrWIDs[counter].u16WIDid, - pstrWIDs[counter].ps8WidVal, pstrWIDs[counter].s32ValueSize); - } - } else if (u8Mode == SET_CFG) { - for (counter = 0; counter < u32WIDsCount; counter++) { - PRINT_D(CORECONFIG_DBG,"Sending config SET PACKET WID:%x\n",pstrWIDs[counter].u16WIDid); - if (!gpstrWlanOps->wlan_cfg_set(!counter, - pstrWIDs[counter].u16WIDid, pstrWIDs[counter].ps8WidVal, - pstrWIDs[counter].s32ValueSize, - (counter == u32WIDsCount - 1), drvHandler)) { - ret = -1; - PRINT_ER("[Sendconfigpkt]Set Timed out\n"); - break; - } - } - } - /*TicketId1003*/ - cfg_timed_out_cnt = (ret != -1) ? 0 : cfg_timed_out_cnt + 1; - return ret; -} +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core_configurator.h" +#include "linux_wlan.h" + +#define PHY_802_11n +#define MAX_CFG_PKTLEN 1450 +#define MSG_HEADER_LEN 4 +#define QUERY_MSG_TYPE 'Q' +#define WRITE_MSG_TYPE 'W' +#define RESP_MSG_TYPE 'R' +#define WRITE_RESP_SUCCESS 1 +#define INVALID 255 +#define MAC_ADDR_LEN 6 +#define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \ + BEACON_INTERVAL_LEN + CAP_INFO_LEN) + +/* Basic Frame Type Codes (2-bit) */ +enum tenuBasicFrmType { + FRAME_TYPE_CONTROL = 0x04, + FRAME_TYPE_DATA = 0x08, + FRAME_TYPE_MANAGEMENT = 0x00, + FRAME_TYPE_RESERVED = 0x0C, + FRAME_TYPE_FORCE_32BIT = 0xFFFFFFFF +}; + + +/* Basic Frame Classes */ +enum tenuFrameClass { + CLASS1_FRAME_TYPE = 0x00, + CLASS2_FRAME_TYPE = 0x01, + CLASS3_FRAME_TYPE = 0x02, + FRAME_CLASS_FORCE_32BIT = 0xFFFFFFFF +}; + +/* Element ID of various Information Elements */ +enum tenuInfoElemID { + 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 +}; + +struct tstrConfigPktInfo { + char *pcRespBuffer; + signed int s32MaxRespBuffLen; + signed int s32BytesRead; + bool bRespRequired; +}; + + +static struct semaphore SemHandleSendPkt; +static struct semaphore SemHandlePktResp; +static s8 *gps8ConfigPacket; +static struct tstrConfigPktInfo gstrConfigPktInfo; +static u8 g_seqno; +static s16 g_wid_num = -1; +static u16 Res_Len; +static u8 g_oper_mode = SET_CFG; + +/* WID Switches */ +static struct tstrWID gastrWIDs[] = { + {WID_FIRMWARE_VERSION, WID_STR}, + {WID_PHY_VERSION, WID_STR}, + {WID_HARDWARE_VERSION, WID_STR}, + {WID_BSS_TYPE, WID_CHAR}, + {WID_QOS_ENABLE, WID_CHAR}, + {WID_11I_MODE, WID_CHAR}, + {WID_CURRENT_TX_RATE, WID_CHAR}, + {WID_LINKSPEED, WID_CHAR}, + {WID_RTS_THRESHOLD, WID_SHORT}, + {WID_FRAG_THRESHOLD, WID_SHORT}, + {WID_SSID, WID_STR}, + {WID_BSSID, WID_ADR}, + {WID_BEACON_INTERVAL, WID_SHORT}, + {WID_POWER_MANAGEMENT, WID_CHAR}, + {WID_LISTEN_INTERVAL, WID_CHAR}, + {WID_DTIM_PERIOD, WID_CHAR}, + {WID_CURRENT_CHANNEL, WID_CHAR}, + {WID_TX_POWER_LEVEL_11A, WID_CHAR}, + {WID_TX_POWER_LEVEL_11B, WID_CHAR}, + {WID_PREAMBLE, WID_CHAR}, + {WID_11G_OPERATING_MODE, WID_CHAR}, + {WID_MAC_ADDR, WID_ADR}, + {WID_IP_ADDRESS, WID_ADR}, + {WID_ACK_POLICY, WID_CHAR}, + {WID_PHY_ACTIVE_REG, WID_CHAR}, + {WID_AUTH_TYPE, WID_CHAR}, + {WID_REKEY_POLICY, WID_CHAR}, + {WID_REKEY_PERIOD, WID_INT}, + {WID_REKEY_PACKET_COUNT, WID_INT}, + {WID_11I_PSK, WID_STR}, + {WID_1X_KEY, WID_STR}, + {WID_1X_SERV_ADDR, WID_IP}, + {WID_SUPP_USERNAME, WID_STR}, + {WID_SUPP_PASSWORD, WID_STR}, + {WID_USER_CONTROL_ON_TX_POWER, WID_CHAR}, + {WID_MEMORY_ADDRESS, WID_INT}, + {WID_MEMORY_ACCESS_32BIT, WID_INT}, + {WID_MEMORY_ACCESS_16BIT, WID_SHORT}, + {WID_MEMORY_ACCESS_8BIT, WID_CHAR}, + {WID_SITE_SURVEY_RESULTS, WID_STR}, + {WID_PMKID_INFO, WID_STR}, + {WID_ASSOC_RES_INFO, WID_STR}, + /* 4 Wids added for the CAPI tool*/ + {WID_MANUFACTURER, WID_STR}, + {WID_MODEL_NAME, WID_STR}, + {WID_MODEL_NUM, WID_STR}, + {WID_DEVICE_NAME, WID_STR}, + {WID_SSID_PROBE_REQ, WID_STR}, + +#ifdef MAC_802_11N + {WID_11N_ENABLE, WID_CHAR}, + {WID_11N_CURRENT_TX_MCS, WID_CHAR}, + {WID_TX_POWER_LEVEL_11N, WID_CHAR}, + {WID_11N_OPERATING_MODE, WID_CHAR}, + {WID_11N_SMPS_MODE, WID_CHAR}, + {WID_11N_PROT_MECH, WID_CHAR}, + {WID_11N_ERP_PROT_TYPE, WID_CHAR}, + {WID_11N_HT_PROT_TYPE, WID_CHAR}, + {WID_11N_PRINT_STATS, WID_CHAR}, + {WID_11N_AUTORATE_TABLE, WID_BIN_DATA}, + {WID_HOST_CONFIG_IF_TYPE, WID_CHAR}, + {WID_HOST_DATA_IF_TYPE, WID_CHAR}, + {WID_11N_SIG_QUAL_VAL, WID_SHORT}, + {WID_11N_IMMEDIATE_BA_ENABLED, WID_CHAR}, + {WID_11N_TXOP_PROT_DISABLE, WID_CHAR}, + {WID_11N_SHORT_GI_20MHZ_ENABLE, WID_CHAR}, + {WID_SHORT_SLOT_ALLOWED, WID_CHAR}, + {WID_11W_ENABLE, WID_CHAR}, + {WID_11W_MGMT_PROT_REQ, WID_CHAR}, + {WID_2040_ENABLE, WID_CHAR}, + {WID_2040_COEXISTENCE, WID_CHAR}, + {WID_USER_SEC_CHANNEL_OFFSET, WID_CHAR}, + {WID_2040_CURR_CHANNEL_OFFSET, WID_CHAR}, + {WID_2040_40MHZ_INTOLERANT, WID_CHAR}, + {WID_HUT_RESTART, WID_CHAR}, + {WID_HUT_NUM_TX_PKTS, WID_INT}, + {WID_HUT_FRAME_LEN, WID_SHORT}, + {WID_HUT_TX_FORMAT, WID_CHAR}, + {WID_HUT_BANDWIDTH, WID_CHAR}, + {WID_HUT_OP_BAND, WID_CHAR}, + {WID_HUT_STBC, WID_CHAR}, + {WID_HUT_ESS, WID_CHAR}, + {WID_HUT_ANTSET, WID_CHAR}, + {WID_HUT_HT_OP_MODE, WID_CHAR}, + {WID_HUT_RIFS_MODE, WID_CHAR}, + {WID_HUT_SMOOTHING_REC, WID_CHAR}, + {WID_HUT_SOUNDING_PKT, WID_CHAR}, + {WID_HUT_HT_CODING, WID_CHAR}, + {WID_HUT_TEST_DIR, WID_CHAR}, + {WID_HUT_TXOP_LIMIT, WID_SHORT}, + {WID_HUT_DEST_ADDR, WID_ADR}, + {WID_HUT_TX_PATTERN, WID_BIN_DATA}, + {WID_HUT_TX_TIME_TAKEN, WID_INT}, + {WID_HUT_PHY_TEST_MODE, WID_CHAR}, + {WID_HUT_PHY_TEST_RATE_HI, WID_CHAR}, + {WID_HUT_PHY_TEST_RATE_LO, WID_CHAR}, + {WID_HUT_TX_TEST_TIME, WID_INT}, + {WID_HUT_LOG_INTERVAL, WID_INT}, + {WID_HUT_DISABLE_RXQ_REPLENISH, WID_CHAR}, + {WID_HUT_TEST_ID, WID_STR}, + {WID_HUT_KEY_ORIGIN, WID_CHAR}, + {WID_HUT_BCST_PERCENT, WID_CHAR}, + {WID_HUT_GROUP_CIPHER_TYPE, WID_CHAR}, + {WID_HUT_STATS, WID_BIN_DATA}, + {WID_HUT_TSF_TEST_MODE, WID_CHAR}, + {WID_HUT_SIG_QUAL_AVG, WID_SHORT}, + {WID_HUT_SIG_QUAL_AVG_CNT, WID_SHORT}, + {WID_HUT_TSSI_VALUE, WID_CHAR}, + {WID_HUT_MGMT_PERCENT, WID_CHAR}, + {WID_HUT_MGMT_BCST_PERCENT, WID_CHAR}, + {WID_HUT_MGMT_ALLOW_HT, WID_CHAR}, + {WID_HUT_UC_MGMT_TYPE, WID_CHAR}, + {WID_HUT_BC_MGMT_TYPE, WID_CHAR}, + {WID_HUT_UC_MGMT_FRAME_LEN, WID_SHORT}, + {WID_HUT_BC_MGMT_FRAME_LEN, WID_SHORT}, + {WID_HUT_11W_MFP_REQUIRED_TX, WID_CHAR}, + {WID_HUT_11W_MFP_PEER_CAPABLE, WID_CHAR}, + {WID_HUT_11W_TX_IGTK_ID, WID_CHAR}, + {WID_HUT_FC_TXOP_MOD, WID_CHAR}, + {WID_HUT_FC_PROT_TYPE, WID_CHAR}, + {WID_HUT_SEC_CCA_ASSERT, WID_CHAR}, +#endif /* MAC_802_11N */ +}; + +u16 g_num_total_switches = (sizeof(gastrWIDs) / sizeof(struct tstrWID)); + +static inline u8 ascii_hex_to_dec(u8 num) +{ + if ((num >= '0') && (num <= '9')) + return (num - '0'); + else if ((num >= 'A') && (num <= 'F')) + return (10 + (num - 'A')); + else if ((num >= 'a') && (num <= 'f')) + return (10 + (num - 'a')); + + return INVALID; +} + +static inline u8 get_hex_char(u8 inp) +{ + u8 *d2htab = "0123456789ABCDEF"; + + return d2htab[inp & 0xF]; +} + +/* + * This function extracts the MAC address held in a string in standard format + * into another buffer as integers. + */ +static inline u16 extract_mac_addr(char *str, u8 *buff) +{ + *buff = 0; + while (*str != '\0') { + if ((*str == ':') || (*str == '-')) + *(++buff) = 0; + else + *buff = (*buff << 4) + ascii_hex_to_dec(*str); + + str++; + } + + return MAC_ADDR_LEN; +} + +/* + * This function creates MAC address in standard format from a buffer of + * integers. + */ +static inline void create_mac_addr(u8 *str, u8 *buff) +{ + unsigned int i = 0; + unsigned int j = 0; + + for (i = 0; i < MAC_ADDR_LEN; i++) { + str[j++] = get_hex_char((u8)((buff[i] >> 4) & 0x0F)); + str[j++] = get_hex_char((u8)(buff[i] & 0x0F)); + str[j++] = ':'; + } + str[--j] = '\0'; +} + +/* + * This function converts the IP address string in dotted decimal format to + * unsigned integer. This functionality is similar to the library function + * inet_addr() but is reimplemented here since I could not confirm that + * inet_addr is platform independent. + * ips=>IP Address String in dotted decimal format + * ipn=>Pointer to IP Address in integer format + */ +static inline u8 conv_ip_to_int(u8 *ips, unsigned int *ipn) +{ + u8 i = 0; + u8 ipb = 0; + + *ipn = 0; + /* Integer to string for each component */ + while (ips[i] != '\0') { + if (ips[i] == '.') { + *ipn = ((*ipn) << 8) | ipb; + ipb = 0; + } else { + ipb = ipb * 10 + ascii_hex_to_dec(ips[i]); + } + i++; + } + + /* The last byte of the IP address is read in here */ + *ipn = ((*ipn) << 8) | ipb; + + return 0; +} + +/* + * This function converts the IP address from integer format to dotted + * decimal string format. Alternative to std library fn inet_ntoa(). + * ips=>Buffer to hold IP Address String dotted decimal format (Min 17B) + * ipn=>IP Address in integer format + */ +static inline u8 conv_int_to_ip(u8 *ips, unsigned int ipn) +{ + u8 i = 0; + u8 ipb = 0; + u8 cnt = 0; + u8 ipbsize = 0; + + for (cnt = 4; cnt > 0; cnt--) { + ipb = (ipn >> (8 * (cnt - 1))) & 0xFF; + + if (ipb >= 100) + ipbsize = 2; + else if (ipb >= 10) + ipbsize = 1; + else + ipbsize = 0; + + switch (ipbsize) { + case 2: + ips[i++] = get_hex_char(ipb / 100); + ipb %= 100; + + case 1: + ips[i++] = get_hex_char(ipb / 10); + ipb %= 10; + + default: + ips[i++] = get_hex_char(ipb); + } + + if (cnt > 1) + ips[i++] = '.'; + } + + ips[i] = '\0'; + + return i; +} + +static inline enum WID_TYPE get_wid_type(unsigned int wid_num) +{ + /* Check for iconfig specific WID types first */ + if ((wid_num == WID_BSSID) || + (wid_num == WID_MAC_ADDR) || + (wid_num == WID_IP_ADDRESS) || + (wid_num == WID_HUT_DEST_ADDR)) + return WID_ADR; + + if ((WID_1X_SERV_ADDR == wid_num) || + (WID_STACK_IP_ADDR == wid_num) || + (WID_STACK_NETMASK_ADDR == wid_num)) + return WID_IP; + + /* Next check for standard WID types */ + if (wid_num < 0x1000) + return WID_CHAR; + else if (wid_num < 0x2000) + return WID_SHORT; + else if (wid_num < 0x3000) + return WID_INT; + else if (wid_num < 0x4000) + return WID_STR; + else if (wid_num < 0x5000) + return WID_BIN_DATA; + + return WID_UNDEF; +} + +/* + * 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 = 0; + + bcn_per = data[0]; + bcn_per |= (data[1] << 8); + + return bcn_per; +} + +static inline unsigned int get_beacon_timestamp_lo(u8 *data) +{ + unsigned int time_stamp = 0; + unsigned int 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 unsigned int get_beacon_timestamp_hi(u8 *data) +{ + unsigned int time_stamp = 0; + unsigned int 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' bits from the MAC header of the + * input frame. + * Returns the value in the LSB of the returned value. + */ +static inline enum tenuBasicFrmType get_type(u8 *header) +{ + return ((enum tenuBasicFrmType)(header[0] & 0x0C)); +} + +/* + * 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 tenuFrmSubtype get_sub_type(u8 *header) +{ + return ((enum tenuFrmSubtype)(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 tenuFrmSubtype st = BEACON; + + 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 = 0; + + cap_info = data[0]; + cap_info |= (data[1] << 8); + + return cap_info; +} + +/* + * This funcion 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 = 0; + + 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 = 0; + + asoc_id = data[4]; + asoc_id |= (data[5] << 8); + + return asoc_id; +} + +/* + * initializes the Core Configurator + */ + +signed int CoreConfiguratorInit(void) +{ + signed int s32Error = ATL_SUCCESS; + + PRINT_D(CORECONFIG_DBG,"CoreConfiguratorInit() \n"); + + sema_init(&SemHandleSendPkt, 1); + sema_init(&SemHandlePktResp, 0); + + gps8ConfigPacket = kmalloc(MAX_PACKET_BUFF_SIZE, GFP_ATOMIC); + if (gps8ConfigPacket == NULL) { + s32Error = ATL_NO_MEM; + goto _fail_; + } + + memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); + + memset((void *)(&gstrConfigPktInfo), 0, + sizeof(struct tstrConfigPktInfo)); +_fail_: + return s32Error; +} + +u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset) +{ + u16 u16index = 0; + + /*************************************************************************/ + /* 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 0; +} + +/* + * 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 0; +} + +u8 get_current_channel(u8 *pu8msa, u16 u16RxLen) +{ +#ifdef PHY_802_11n +#ifdef FIVE_GHZ_BAND + /* Get the current channel as its not set in */ + /* 802.11a beacons/probe response */ + return (get_rf_channel() + 1); +#else /* FIVE_GHZ_BAND */ + /* Extract current channel information from */ + /* the beacon/probe response frame */ + return get_current_channel_802_11n(pu8msa, u16RxLen); +#endif /* FIVE_GHZ_BAND */ +#else + return 0; +#endif /* PHY_802_11n */ +} + +/* + * parses the received 'N' message + */ +signed int ParseNetworkInfo(u8 *pu8MsgBuffer, struct tstrNetworkInfo **ppstrNetworkInfo) +{ + signed int s32Error = ATL_SUCCESS; + struct tstrNetworkInfo *pstrNetworkInfo = NULL; + u8 u8MsgType = 0; + u8 u8MsgID = 0; + u16 u16MsgLen = 0; + u16 u16WidID = (u16)WID_NIL; + u16 u16WidLen = 0; + u8 *pu8WidVal = 0; + + u8 *pu8msa = 0; + u16 u16RxLen = 0; + u8 *pu8TimElm = 0; + u8 *pu8IEs = 0; + u16 u16IEsLen = 0; + u8 u8index = 0; + unsigned int u32Tsf_Lo; + unsigned int u32Tsf_Hi; + + u8MsgType = pu8MsgBuffer[0]; + + /* Check whether the received message type is 'N' */ + if ('N' != u8MsgType) { + PRINT_ER("Received Message format incorrect.\n"); + ATL_ERRORREPORT(s32Error, ATL_FAIL); + } + + /* 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" */ + pstrNetworkInfo = kmalloc(sizeof(struct tstrNetworkInfo), GFP_ATOMIC); + memset((void *)(pstrNetworkInfo), 0, sizeof(struct tstrNetworkInfo)); + + 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); +#ifdef WILC_P2P + /* Get time-stamp [Low only 32 bit] */ + pstrNetworkInfo->u32Tsf = get_beacon_timestamp_lo(pu8msa); + PRINT_D(CORECONFIG_DBG,"TSF :%x\n",pstrNetworkInfo->u32Tsf ); +#endif + + /* Get full time-stamp [Low and High 64 bit] */ + u32Tsf_Lo = get_beacon_timestamp_lo(pu8msa); + u32Tsf_Hi = get_beacon_timestamp_hi(pu8msa); + + /*TicketId1023*/ + pstrNetworkInfo->u64Tsf = u32Tsf_Hi; + pstrNetworkInfo->u64Tsf = ((pstrNetworkInfo->u64Tsf) << 32) | u32Tsf_Lo; + + /* Get SSID */ + get_ssid(pu8msa, pstrNetworkInfo->au8ssid, &(pstrNetworkInfo->u8SsidLen)); + + /* Get BSSID */ + get_BSSID(pu8msa, pstrNetworkInfo->au8bssid); + + /* Get the current channel */ + pstrNetworkInfo->u8channel = get_current_channel(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 != 0) + 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 = kmalloc(u16IEsLen, GFP_ATOMIC); + memset((void *)(pstrNetworkInfo->pu8IEs), 0, u16IEsLen); + + memcpy(pstrNetworkInfo->pu8IEs, pu8IEs, u16IEsLen); + } + pstrNetworkInfo->u16IEsLen = u16IEsLen; + + *ppstrNetworkInfo = pstrNetworkInfo; + + ATL_CATCH(s32Error){ + } + return s32Error; +} + +/* + * Deallocates the parsed Network Info + */ +signed int DeallocateNetworkInfo(struct tstrNetworkInfo *pstrNetworkInfo) +{ + signed int s32Error = ATL_SUCCESS; + + if (pstrNetworkInfo != NULL) { + if (pstrNetworkInfo->pu8IEs != NULL) { + kfree(pstrNetworkInfo->pu8IEs); + pstrNetworkInfo->pu8IEs = NULL; + } else { + s32Error = ATL_FAIL; + } + kfree(pstrNetworkInfo); + pstrNetworkInfo = NULL; + } else { + s32Error = ATL_FAIL; + } + return s32Error; +} + +/* + * parses the received Association Response frame + */ +signed int ParseAssocRespInfo(u8 *pu8Buffer, unsigned int u32BufferLen, + struct tstrConnectRespInfo **ppstrConnectRespInfo) +{ + signed int s32Error = ATL_SUCCESS; + struct tstrConnectRespInfo *pstrConnectRespInfo = NULL; + u16 u16AssocRespLen = 0; + u8 *pu8IEs = 0; + u16 u16IEsLen = 0; + + pstrConnectRespInfo = kmalloc(sizeof(*pstrConnectRespInfo), GFP_ATOMIC); + memset((void *)(pstrConnectRespInfo), 0, sizeof(struct tstrConnectRespInfo)); + + 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 = kmalloc(u16IEsLen, GFP_ATOMIC); + memset((void *)(pstrConnectRespInfo->pu8RespIEs), 0, u16IEsLen); + + memcpy(pstrConnectRespInfo->pu8RespIEs, pu8IEs, u16IEsLen); + pstrConnectRespInfo->u16RespIEsLen = u16IEsLen; + } + + *ppstrConnectRespInfo = pstrConnectRespInfo; + + return s32Error; +} + +/* + * Deallocates the parsed Association Response Info + */ +signed int DeallocateAssocRespInfo(struct tstrConnectRespInfo *pstrConnectRespInfo) +{ + signed int s32Error = ATL_SUCCESS; + + if (NULL != pstrConnectRespInfo) { + if (NULL != pstrConnectRespInfo->pu8RespIEs) { + kfree(pstrConnectRespInfo->pu8RespIEs); + pstrConnectRespInfo->pu8RespIEs = NULL; + } else { + s32Error = ATL_FAIL; + } + kfree(pstrConnectRespInfo); + pstrConnectRespInfo = NULL; + } else { + s32Error = ATL_FAIL; + } + return s32Error; +} + +#ifndef CONNECT_DIRECT +signed int ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], + struct wid_site_survey_reslts **ppstrSurveyResults, + unsigned int *pu32SurveyResultsCount) +{ + signed int s32Error = ATL_SUCCESS; + struct wid_site_survey_reslts *pstrSurveyResults = NULL; + unsigned int u32SurveyResultsCount = 0; + unsigned int u32SurveyBytesLength = 0; + u8 *pu8BufferPtr; + unsigned int u32RcvdSurveyResultsNum = 2; + u8 u8ReadSurveyResFragNum; + unsigned int i; + unsigned int j; + + for (i = 0; i < u32RcvdSurveyResultsNum; i++) { + u32SurveyBytesLength = ppu8RcvdSiteSurveyResults[i][0]; + + for (j = 0; j < u32SurveyBytesLength; j += SURVEY_RESULT_LENGTH) + u32SurveyResultsCount++; + } + + pstrSurveyResults = kmalloc_array(u32SurveyResultsCount, + sizeof(struct wid_site_survey_reslts), GFP_ATOMIC); + + if (NULL == pstrSurveyResults) { + u32SurveyResultsCount = 0; + ATL_ERRORREPORT(s32Error, ATL_NO_MEM); + } + + memset((void *)(pstrSurveyResults), 0, + u32SurveyResultsCount * sizeof(struct wid_site_survey_reslts)); + + u32SurveyResultsCount = 0; + + for (i = 0; i < u32RcvdSurveyResultsNum; i++) { + pu8BufferPtr = ppu8RcvdSiteSurveyResults[i]; + + u32SurveyBytesLength = pu8BufferPtr[0]; + + u8ReadSurveyResFragNum = pu8BufferPtr[1]; + + pu8BufferPtr += 2; + + for (j = 0; j < u32SurveyBytesLength; j += SURVEY_RESULT_LENGTH) { + memcpy(&pstrSurveyResults[u32SurveyResultsCount], + pu8BufferPtr, SURVEY_RESULT_LENGTH); + pu8BufferPtr += SURVEY_RESULT_LENGTH; + u32SurveyResultsCount++; + } + } + + ATL_CATCH(s32Error){ + } + *ppstrSurveyResults = pstrSurveyResults; + *pu32SurveyResultsCount = u32SurveyResultsCount; + + return s32Error; +} + +signed int DeallocateSurveyResults(struct wid_site_survey_reslts *pstrSurveyResults) +{ + signed int s32Error = ATL_SUCCESS; + + if (NULL != pstrSurveyResults) + kfree(pstrSurveyResults); + + return s32Error; +} +#endif /* CONNECT_DIRECT */ + +/* + * This function processes a WID of type WID_CHAR and + * updates the cfg packet with the supplied value. + */ +void ProcessCharWid(char *pcPacket, signed int *ps32PktLen, + struct tstrWID *pstrWID, s8 *ps8WidVal) +{ + u8 *pu8val = (u8 *)ps8WidVal; + u8 u8val = 0; + signed int s32PktLen = *ps32PktLen; + + if (NULL == pstrWID) { + PRINT_WRN(CORECONFIG_DBG,"Can't set CHAR val 0x%x ,NULL structure\n",u8val); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid >> 8) & 0xFF; + if (g_oper_mode == SET_CFG) { + u8val = *pu8val; + + /* Length */ + pcPacket[s32PktLen++] = sizeof(u8); + + /* Value */ + pcPacket[s32PktLen++] = u8val; + } + *ps32PktLen = s32PktLen; +} + +/* + * This function processes a WID of type WID_SHORT and + * updates the cfg packet with the supplied value. + */ +void ProcessShortWid(char *pcPacket, signed int *ps32PktLen, + struct tstrWID *pstrWID, s8 *ps8WidVal) +{ + u16 *pu16val = (u16 *)ps8WidVal; + u16 u16val = 0; + signed int s32PktLen = *ps32PktLen; + + if (NULL == pstrWID) { + PRINT_WRN(CORECONFIG_DBG,"Can't set SHORT val 0x%x ,NULL structure\n",u16val); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + u16val = *pu16val; + + /* Length */ + pcPacket[s32PktLen++] = sizeof(u16); + + /* Value */ + pcPacket[s32PktLen++] = (u8)(u16val & 0xFF); + pcPacket[s32PktLen++] = (u8)((u16val >> 8) & 0xFF); + } + *ps32PktLen = s32PktLen; +} + +/* + * This function processes a WID of type WID_INT and + * updates the cfg packet with the supplied value. + */ +void ProcessIntWid(char *pcPacket, signed int *ps32PktLen, + struct tstrWID *pstrWID, s8 *ps8WidVal) +{ + unsigned int *pu32val = (unsigned int *)ps8WidVal; + unsigned int u32val = 0; + signed int s32PktLen = *ps32PktLen; + + if (NULL == pstrWID) { + PRINT_WRN(CORECONFIG_DBG,"Can't set INT val 0x%x , NULL structure\n", u32val); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + u32val = *pu32val; + + /* Length */ + pcPacket[s32PktLen++] = sizeof(unsigned int); + + /* Value */ + pcPacket[s32PktLen++] = (u8)(u32val & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 8) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 16) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 24) & 0xFF); + } + *ps32PktLen = s32PktLen; +} + +/* + * This function processes a WID of type WID_IP and + * updates the cfg packet with the supplied value. + */ +void ProcessIPwid(char *pcPacket, signed int *ps32PktLen, + struct tstrWID *pstrWID, u8 *pu8ip) +{ + unsigned int u32val = 0; + signed int s32PktLen = *ps32PktLen; + + if (NULL == pstrWID) { + PRINT_WRN(CORECONFIG_DBG,"Can't set IP Addr , NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Length */ + pcPacket[s32PktLen++] = sizeof(unsigned int); + + /* Convert the IP Address String to Integer */ + conv_ip_to_int(pu8ip, &u32val); + + /* Value */ + pcPacket[s32PktLen++] = (u8)(u32val & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 8) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 16) & 0xFF); + pcPacket[s32PktLen++] = (u8)((u32val >> 24) & 0xFF); + } + *ps32PktLen = s32PktLen; +} + +/* + * This function processes a WID of type WID_STR and + * updates the cfg packet with the supplied value. + */ +void ProcessStrWid(char *pcPacket, signed int *ps32PktLen, + struct tstrWID *pstrWID, u8 *pu8val, signed int s32ValueSize) +{ + u16 u16MsgLen = 0; + u16 idx = 0; + signed int s32PktLen = *ps32PktLen; + + if (NULL == pstrWID) { + PRINT_WRN(CORECONFIG_DBG,"Can't set STR val, NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Message Length */ + u16MsgLen = (u16)s32ValueSize; + + /* Length */ + pcPacket[s32PktLen++] = (u8)u16MsgLen; + + /* Value */ + for (idx = 0; idx < u16MsgLen; idx++) + pcPacket[s32PktLen++] = pu8val[idx]; + } + *ps32PktLen = s32PktLen; +} + +/* + * This function processes a WID of type WID_ADR and + * updates the cfg packet with the supplied value. + */ +void ProcessAdrWid(char *pcPacket, signed int *ps32PktLen, + struct tstrWID *pstrWID, u8 *pu8val) +{ + u16 u16MsgLen = 0; + signed int s32PktLen = *ps32PktLen; + + if (NULL == pstrWID) { + PRINT_WRN(CORECONFIG_DBG,"Can't set Addr WID, NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Message Length */ + u16MsgLen = MAC_ADDR_LEN; + + /* Length */ + pcPacket[s32PktLen++] = (u8)u16MsgLen; + + /* Value */ + extract_mac_addr(pu8val, pcPacket + s32PktLen); + s32PktLen += u16MsgLen; + } + *ps32PktLen = s32PktLen; +} + +/* + * This function processes a WID of type WID_BIN_DATA and + * updates the cfg packet with the supplied value. + */ +void ProcessBinWid(char *pcPacket, signed int *ps32PktLen, + struct tstrWID *pstrWID, u8 *pu8val, signed int s32ValueSize) +{ + u16 u16MsgLen = 0; + u16 idx = 0; + signed int s32PktLen = *ps32PktLen; + u8 u8checksum = 0; + + if (NULL == pstrWID) { + PRINT_WRN(CORECONFIG_DBG,"Can't set BIN val, NULL structure\n"); + return; + } + + /* WID */ + pcPacket[s32PktLen++] = (u8)(pstrWID->u16WIDid & 0xFF); + pcPacket[s32PktLen++] = (u8)((pstrWID->u16WIDid >> 8) & 0xFF); + + if (g_oper_mode == SET_CFG) { + /* Message Length */ + u16MsgLen = (u16)s32ValueSize; + + /* Length */ + pcPacket[s32PktLen++] = (u8)(u16MsgLen & 0xFF); + pcPacket[s32PktLen++] = (u8)((u16MsgLen >> 8) & 0xFF); + + /* Value */ + for (idx = 0; idx < u16MsgLen; idx++) + pcPacket[s32PktLen++] = pu8val[idx]; + + /* checksum */ + for (idx = 0; idx < u16MsgLen; idx++) + u8checksum += pcPacket[MSG_HEADER_LEN + idx + 4]; + + pcPacket[s32PktLen++] = u8checksum; + } + *ps32PktLen = s32PktLen; +} + +/* This function parses the response frame got from the device */ +signed int further_process_response(u8 *resp, + u16 u16WIDid, + u16 cfg_len, + bool process_wid_num, + unsigned int cnt, + struct tstrWID *pstrWIDresult) +{ + unsigned int retval = 0; + unsigned int idx = 0; + u8 cfg_chr = 0; + u16 cfg_sht = 0; + unsigned int cfg_int = 0; + u8 cfg_str[256] = {0}; + enum WID_TYPE enuWIDtype = WID_UNDEF; + + if (process_wid_num) + enuWIDtype = get_wid_type(g_wid_num); + else + enuWIDtype = gastrWIDs[cnt].enuWIDtype; + + switch (enuWIDtype) { + case WID_CHAR: + { + cfg_chr = resp[idx]; + /*Set local copy of WID*/ + *pstrWIDresult->ps8WidVal = cfg_chr; + break; + } + + case WID_SHORT: + { + u16 *pu16val = (u16 *)(pstrWIDresult->ps8WidVal); + + cfg_sht = MAKE_WORD16(resp[idx], resp[idx + 1]); + *pu16val = cfg_sht; + break; + } + + case WID_INT: + { + unsigned int *pu32val = (unsigned int *)(pstrWIDresult->ps8WidVal); + + cfg_int = MAKE_WORD32( + MAKE_WORD16(resp[idx], resp[idx + 1]), + MAKE_WORD16(resp[idx + 2], resp[idx + 3]) + ); + *pu32val = cfg_int; + break; + } + + case WID_STR: + { + memcpy(cfg_str, resp + idx, cfg_len); + + if (pstrWIDresult->s32ValueSize >= cfg_len) { + memcpy(pstrWIDresult->ps8WidVal, cfg_str, cfg_len); + pstrWIDresult->s32ValueSize = cfg_len; + } else { + PRINT_ER("allocated WID buffer length is smaller than the received WID Length \n"); + retval = -2; + } + + break; + } + + case WID_ADR: + create_mac_addr(cfg_str, resp + idx); + + strncpy(pstrWIDresult->ps8WidVal, cfg_str, strlen(cfg_str)); + pstrWIDresult->ps8WidVal[strlen(cfg_str)] = '\0'; + break; + + case WID_IP: + cfg_int = MAKE_WORD32( + MAKE_WORD16(resp[idx], resp[idx + 1]), + MAKE_WORD16(resp[idx + 2], resp[idx + 3]) + ); + conv_int_to_ip(cfg_str, cfg_int); + break; + + case WID_BIN_DATA: + { + if (pstrWIDresult->s32ValueSize >= cfg_len) { + memcpy(pstrWIDresult->ps8WidVal, resp + idx, cfg_len); + pstrWIDresult->s32ValueSize = cfg_len; + } else { + PRINT_ER("Allocated WID buffer length is smaller than the received WID Length Err(%d)\n",retval); + retval = -2; + } + } + break; + + default: + PRINT_ER("ERROR: Check config database: Error(%d)\n",retval); + retval = -2; + } + + return retval; +} + +/* + * This function parses the command-line options and + * creates the config packets which can be sent to the WLAN station + */ +signed int ParseResponse(u8 *resp, struct tstrWID *pstrWIDcfgResult) +{ + u16 u16RespLen = 0; + u16 u16WIDid = 0; + u16 cfg_len = 0; + enum WID_TYPE enuWIDtype = WID_UNDEF; + bool num_wid_processed = false; + unsigned int cnt = 0; + unsigned int idx = 0; + unsigned int ResCnt = 0; + /* Check whether the received frame is a valid response */ + if (RESP_MSG_TYPE != resp[0]) { + PRINT_INFO(CORECONFIG_DBG,"Received Message format incorrect.\n"); + return -1; + } + + /* Extract Response Length */ + u16RespLen = MAKE_WORD16(resp[2], resp[3]); + Res_Len = u16RespLen; + + for (idx = MSG_HEADER_LEN; idx < u16RespLen; ) { + u16WIDid = MAKE_WORD16(resp[idx], resp[idx + 1]); + cfg_len = resp[idx + 2]; + /* Incase of Bin Type Wid, the length is given by two byte field */ + enuWIDtype = get_wid_type(u16WIDid); + if (WID_BIN_DATA == enuWIDtype) { + cfg_len |= ((u16)resp[idx + 3] << 8) & 0xFF00; + idx++; + } + idx += 3; + if ((u16WIDid == g_wid_num) && (!num_wid_processed)) { + num_wid_processed = true; + + if (-2 == further_process_response(&resp[idx], u16WIDid, cfg_len, true, 0, &pstrWIDcfgResult[ResCnt])) + return -2; + ResCnt++; + } else { + for (cnt = 0; cnt < g_num_total_switches; cnt++) { + if (gastrWIDs[cnt].u16WIDid == u16WIDid) { + if (-2 == further_process_response(&resp[idx], u16WIDid, cfg_len, false, cnt, + &pstrWIDcfgResult[ResCnt])) + return -2; + ResCnt++; + } + } + } idx += cfg_len; + /* In case if BIN type Wid, The last byte of the Cfg packet is the */ + /* Checksum. The WID Length field does not accounts for the checksum. */ + /* The Checksum is discarded. */ + if (WID_BIN_DATA == enuWIDtype) + idx++; + } + + return 0; +} + +/* + * parses the write response [just detects its status: success or failure] + */ + +signed int ParseWriteResponse(u8 *pu8RespBuffer) +{ + signed int s32Error = ATL_FAIL; + u16 u16RespLen = 0; + u16 u16WIDtype = (u16)WID_NIL; + + /* Check whether the received frame is a valid response */ + if (RESP_MSG_TYPE != pu8RespBuffer[0]) { + PRINT_ER("Received Message format incorrect.\n"); + return ATL_FAIL; + } + + /* Extract Response Length */ + u16RespLen = MAKE_WORD16(pu8RespBuffer[2], pu8RespBuffer[3]); + + u16WIDtype = MAKE_WORD16(pu8RespBuffer[4], pu8RespBuffer[5]); + + /* Check for WID_STATUS ID and then check the length and status value */ + if ((u16WIDtype == WID_STATUS) && + (pu8RespBuffer[6] == 1) && + (pu8RespBuffer[7] == WRITE_RESP_SUCCESS)) { + s32Error = WRITE_RESP_SUCCESS; + return s32Error; + } + + /* If the length or status are not as expected return failure */ + s32Error = ATL_FAIL; + return s32Error; +} + +/* + * creates the header of the Configuration Packet + */ + +signed int CreatePacketHeader(char *pcpacket, signed int *ps32PacketLength) +{ + signed int s32Error = ATL_SUCCESS; + u16 u16MsgLen = (u16)(*ps32PacketLength); + u16 u16MsgInd = 0; + + /* The format of the message is: */ + /* +-------------------------------------------------------------------+ */ + /* | Message Type | Message ID | Message Length |Message body | */ + /* +-------------------------------------------------------------------+ */ + /* | 1 Byte | 1 Byte | 2 Bytes | Message Length - 4 | */ + /* +-------------------------------------------------------------------+ */ + + /* The format of a message body of a message type 'W' is: */ + /* +-------------------------------------------------------------------+ */ + /* | WID0 | WID0 Length | WID0 Value | ......................... | */ + /* +-------------------------------------------------------------------+ */ + /* | 2 Bytes | 1 Byte | WID0 Length | ......................... | */ + /* +-------------------------------------------------------------------+ */ + /* Message Type */ + if (g_oper_mode == SET_CFG) + pcpacket[u16MsgInd++] = WRITE_MSG_TYPE; + else + pcpacket[u16MsgInd++] = QUERY_MSG_TYPE; + + /* Sequence Number */ + pcpacket[u16MsgInd++] = g_seqno++; + + /* Message Length */ + pcpacket[u16MsgInd++] = (u8)(u16MsgLen & 0xFF); + pcpacket[u16MsgInd++] = (u8)((u16MsgLen >> 8) & 0xFF); + + *ps32PacketLength = u16MsgLen; + + return s32Error; +} + +/* + * creates Configuration packet based on the Input WIDs + * @pstrWIDs WIDs to be sent in the configuration packet + * @u32WIDsCount number of WIDs to be sent in the configuration packet + * @ps8packet The created Configuration Packet + * @ps32PacketLength Length of the created Configuration Packet + */ + +signed int CreateConfigPacket(s8 *ps8packet, signed int *ps32PacketLength, + struct tstrWID *pstrWIDs, unsigned int u32WIDsCount) +{ + signed int s32Error = ATL_SUCCESS; + unsigned int u32idx = 0; + *ps32PacketLength = MSG_HEADER_LEN; + for (u32idx = 0; u32idx < u32WIDsCount; u32idx++) { + switch (pstrWIDs[u32idx].enuWIDtype) { + case WID_CHAR: + ProcessCharWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_SHORT: + ProcessShortWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_INT: + ProcessIntWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_STR: + ProcessStrWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal, pstrWIDs[u32idx].s32ValueSize); + break; + + case WID_IP: + ProcessIPwid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal); + break; + + case WID_BIN_DATA: + ProcessBinWid(ps8packet, ps32PacketLength, &pstrWIDs[u32idx], + pstrWIDs[u32idx].ps8WidVal, pstrWIDs[u32idx].s32ValueSize); + break; + + default: + PRINT_ER("ERROR: Check Config database\n"); + } + } + + CreatePacketHeader(ps8packet, ps32PacketLength); + + return s32Error; +} + +signed int ConfigWaitResponse(char *pcRespBuffer, signed int s32MaxRespBuffLen, + signed int *ps32BytesRead, bool bRespRequired) +{ + signed int s32Error = ATL_SUCCESS; + + if (gstrConfigPktInfo.bRespRequired) { + down(&SemHandlePktResp); + + *ps32BytesRead = gstrConfigPktInfo.s32BytesRead; + } + + memset((void *)(&gstrConfigPktInfo), 0, sizeof(struct tstrConfigPktInfo)); + + return s32Error; +} + +signed int ConfigProvideResponse(char *pcRespBuffer, signed int s32RespLen) +{ + signed int s32Error = ATL_SUCCESS; + + if (gstrConfigPktInfo.bRespRequired) { + if (s32RespLen <= gstrConfigPktInfo.s32MaxRespBuffLen) { + memcpy(gstrConfigPktInfo.pcRespBuffer, pcRespBuffer, s32RespLen); + gstrConfigPktInfo.s32BytesRead = s32RespLen; + } else { + memcpy(gstrConfigPktInfo.pcRespBuffer, pcRespBuffer, gstrConfigPktInfo.s32MaxRespBuffLen); + gstrConfigPktInfo.s32BytesRead = gstrConfigPktInfo.s32MaxRespBuffLen; + PRINT_ER("BusProvideResponse() Response greater than the prepared Buffer Size \n"); + } + + up(&SemHandlePktResp); + } + + return s32Error; +} + +/* + * writes the received packet pu8RxPacket in the global Rx FIFO buffer + */ + +signed int ConfigPktReceived(u8 *pu8RxPacket, signed int s32RxPacketLen) +{ + signed int s32Error = ATL_SUCCESS; + u8 u8MsgType = 0; + + u8MsgType = pu8RxPacket[0]; + + switch (u8MsgType) { + case 'R': + { + ConfigProvideResponse(pu8RxPacket, s32RxPacketLen); + + break; + } + + case 'N': + { + PRINT_INFO(CORECONFIG_DBG,"NetworkInfo packet received\n"); + NetworkInfoReceived(pu8RxPacket, s32RxPacketLen); + break; + } + + case 'I': + { + GnrlAsyncInfoReceived(pu8RxPacket, s32RxPacketLen); + break; + } + + case 'S': + { + host_int_ScanCompleteReceived(pu8RxPacket, s32RxPacketLen); + break; + } + + default: + { + PRINT_ER("ConfigPktReceived(): invalid received msg type at the Core Configurator \n"); + } + } + + return s32Error; +} + +/* + * Deinitializes the Core Configurator + */ + +signed int CoreConfiguratorDeInit(void) +{ + signed int s32Error = ATL_SUCCESS; + + PRINT_D(CORECONFIG_DBG,"CoreConfiguratorDeInit() \n"); + + if (NULL != gps8ConfigPacket) { + kfree(gps8ConfigPacket); + gps8ConfigPacket = NULL; + } + + return s32Error; +} + +uint32_t cfg_timed_out_cnt = 0; + +/* + * sends certain Configuration Packet based on the input WIDs + * pstrWIDs using driver config layer + * @pstrWIDs WIDs to be sent in the configuration packet + * @u32WIDsCount number of WIDs to be sent in the configuration packet + * @pu8RxResp The received Packet Response + * @ps32RxRespLen Length of the received Packet Response + */ +signed int SendConfigPkt(u8 u8Mode, struct tstrWID *pstrWIDs, + unsigned int u32WIDsCount, bool bRespRequired, + unsigned int drvHandler) +{ + signed int counter = 0, ret = 0; + + if (NULL == gpstrWlanOps) { + PRINT_INFO(CORECONFIG_DBG,"Net Dev is still not initialized\n"); + return 1; + /*TicketId1003*/ + /*Suspend host interface till recovery is done*/ + } else if (g_bWaitForRecovery) { + PRINT_D(CORECONFIG_DBG, "Host interface is suspended\n"); + while (g_bWaitForRecovery) + msleep(300); + PRINT_D(CORECONFIG_DBG, "Host interface is resumed\n"); + } + + if (NULL == gpstrWlanOps->wlan_cfg_set || + NULL == gpstrWlanOps->wlan_cfg_get) { + PRINT_INFO(CORECONFIG_DBG,"Set and Get is still not initialized\n"); + return 1; + } + + if (u8Mode == GET_CFG) { + for (counter = 0; counter < u32WIDsCount; counter++) { + PRINT_INFO(CORECONFIG_DBG,"Sending CFG packet [%d][%d]\n",!counter, + (counter == u32WIDsCount - 1)); + if (!gpstrWlanOps->wlan_cfg_get(!counter, + pstrWIDs[counter].u16WIDid, + (counter == u32WIDsCount - 1), + drvHandler)) { + ret = -1; + PRINT_ER("[Sendconfigpkt]Get Timed out\n"); + break; + } + } + + counter = 0; + for (counter = 0; counter < u32WIDsCount; counter++) { + pstrWIDs[counter].s32ValueSize = gpstrWlanOps->wlan_cfg_get_value( + pstrWIDs[counter].u16WIDid, + pstrWIDs[counter].ps8WidVal, pstrWIDs[counter].s32ValueSize); + } + } else if (u8Mode == SET_CFG) { + for (counter = 0; counter < u32WIDsCount; counter++) { + PRINT_D(CORECONFIG_DBG,"Sending config SET PACKET WID:%x\n",pstrWIDs[counter].u16WIDid); + if (!gpstrWlanOps->wlan_cfg_set(!counter, + pstrWIDs[counter].u16WIDid, pstrWIDs[counter].ps8WidVal, + pstrWIDs[counter].s32ValueSize, + (counter == u32WIDsCount - 1), drvHandler)) { + ret = -1; + PRINT_ER("[Sendconfigpkt]Set Timed out\n"); + break; + } + } + } + /*TicketId1003*/ + cfg_timed_out_cnt = (ret != -1) ? 0 : cfg_timed_out_cnt + 1; + return ret; +} diff --git a/wilc3000/core_configurator.h b/wilc3000/core_configurator.h index 28e0d6e..49292b1 100644 --- a/wilc3000/core_configurator.h +++ b/wilc3000/core_configurator.h @@ -1,244 +1,244 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef CORECONFIGURATOR_H -#define CORECONFIGURATOR_H - -#include "atl_error_support.h" -#include "wilc_wlan_if.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "linux/string.h" - -/* Number of WID Options Supported */ -#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 /* MAC_802_11N */ -#define NUM_11N_BASIC_SWITCHES 0 -#define NUM_11N_HUT_SWITCHES 0 -#endif /* MAC_802_11N */ - -/* No Address4 - non-ESS*/ -#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 -/* Operating Mode: SET */ -#define SET_CFG 0 -/* Operating Mode: GET */ -#define GET_CFG 1 - -#define MAX_PACKET_BUFF_SIZE 1596 - -#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 STATUS_MSG_LEN 12 -#define MAC_CONNECTED 1 -#define MAC_DISCONNECTED 0 -#define MAKE_WORD16(lsb, msb) ((((u16)(msb) << 8) & 0xFF00) | (lsb)) -#define MAKE_WORD32(lsw, msw) ((((unsigned int)(msw) << 16) & 0xFFFF0000) \ - | (lsw)) - -extern u16 g_num_total_switches; -extern uint32_t cfg_timed_out_cnt; - -/* Frame Type and Subtype Codes (6-bit) */ -enum tenuFrmSubtype { - 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 -}; - - -/* Status Codes for Authentication and Association Frames */ -enum tenuConnectSts { - 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 -}; - -struct tstrWID { - u16 u16WIDid; - enum WID_TYPE enuWIDtype; - signed int s32ValueSize; - s8 *ps8WidVal; -}; -struct tstrRSSI { - u8 u8Full; - u8 u8Index; - s8 as8RSSI[NUM_RSSI]; -}; - -/* This structure is used to support parsing of the received 'N' message */ -struct tstrNetworkInfo { - s8 s8rssi; - u16 u16CapInfo; - u8 au8ssid[MAX_SSID_LEN]; - u8 u8SsidLen; - u8 au8bssid[6]; - u16 u16BeaconPeriod; - u8 u8DtimPeriod; - u8 u8channel; - /* - * of type unsigned long to be accepted by the linux kernel - *macro time_after() - */ - unsigned long u32TimeRcvdInScanCached; - unsigned long u32TimeRcvdInScan; - bool bNewNetwork; -#ifdef AGING_ALG - u8 u8Found; -#endif -#ifdef WILC_P2P - unsigned int u32Tsf; /* time-stamp [Low only 32 bit] */ -#endif - u8 *pu8IEs; - u16 u16IEsLen; - void *pJoinParams; - struct tstrRSSI strRssi; - unsigned long long u64Tsf; /* time-stamp [Low and High 64 bit] */ -}; - -/* - * This structure is used to support parsing of the received Association - * Response frame - */ -struct tstrConnectRespInfo { - u16 u16capability; - u16 u16ConnectStatus; - u16 u16AssocID; - u8 *pu8RespIEs; - u16 u16RespIEsLen; -}; - -struct tstrConnectInfo { - u8 au8bssid[6]; - u8 *pu8ReqIEs; - size_t ReqIEsLen; - u8 *pu8RespIEs; - u16 u16RespIEsLen; - u16 u16ConnectStatus; -}; - -struct tstrDisconnectNotifInfo { - u16 u16reason; - u8 *ie; - size_t ie_len; -}; - -#ifndef CONNECT_DIRECT -struct wid_site_survey_reslts { - char SSID[MAX_SSID_LEN]; - u8 BssType; - u8 Channel; - u8 SecurityStatus; - u8 BSSID[6]; - char RxPower; - u8 Reserved; -}; -#endif /* CONNECT_DIRECT */ - -signed int CoreConfiguratorInit(void); -signed int CoreConfiguratorDeInit(void); -signed int SendConfigPkt(u8 u8Mode, struct tstrWID *pstrWIDs, - unsigned int u32WIDsCount, - bool bRespRequired, - unsigned int drvHandler); -signed int ParseNetworkInfo(u8 *pu8MsgBuffer, struct tstrNetworkInfo **ppstrNetworkInfo); -signed int DeallocateNetworkInfo(struct tstrNetworkInfo *pstrNetworkInfo); -signed int ParseAssocRespInfo(u8 *pu8Buffer, unsigned int u32BufferLen, - struct tstrConnectRespInfo **ppstrConnectRespInfo); -signed int DeallocateAssocRespInfo(struct tstrConnectRespInfo *pstrConnectRespInfo); -#ifndef CONNECT_DIRECT -signed int ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], - struct wid_site_survey_reslts **ppstrSurveyResults, - unsigned int *pu32SurveyResultsCount); -signed int DeallocateSurveyResults(struct wid_site_survey_reslts *pstrSurveyResults); -#endif /* CONNECT_DIRECT */ -signed int SendRawPacket(s8 *pspacket, signed int s32PacketLen); -void NetworkInfoReceived(u8 *pu8Buffer, unsigned int u32Length); -void GnrlAsyncInfoReceived(u8 *pu8Buffer, unsigned int u32Length); -void host_int_ScanCompleteReceived(u8 *pu8Buffer, unsigned int u32Length); -#endif /* CORECONFIGURATOR_H */ +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CORECONFIGURATOR_H +#define CORECONFIGURATOR_H + +#include "atl_error_support.h" +#include "wilc_wlan_if.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/string.h" + +/* Number of WID Options Supported */ +#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 /* MAC_802_11N */ +#define NUM_11N_BASIC_SWITCHES 0 +#define NUM_11N_HUT_SWITCHES 0 +#endif /* MAC_802_11N */ + +/* No Address4 - non-ESS*/ +#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 +/* Operating Mode: SET */ +#define SET_CFG 0 +/* Operating Mode: GET */ +#define GET_CFG 1 + +#define MAX_PACKET_BUFF_SIZE 1596 + +#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 STATUS_MSG_LEN 12 +#define MAC_CONNECTED 1 +#define MAC_DISCONNECTED 0 +#define MAKE_WORD16(lsb, msb) ((((u16)(msb) << 8) & 0xFF00) | (lsb)) +#define MAKE_WORD32(lsw, msw) ((((unsigned int)(msw) << 16) & 0xFFFF0000) \ + | (lsw)) + +extern u16 g_num_total_switches; +extern uint32_t cfg_timed_out_cnt; + +/* Frame Type and Subtype Codes (6-bit) */ +enum tenuFrmSubtype { + 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 +}; + + +/* Status Codes for Authentication and Association Frames */ +enum tenuConnectSts { + 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 +}; + +struct tstrWID { + u16 u16WIDid; + enum WID_TYPE enuWIDtype; + signed int s32ValueSize; + s8 *ps8WidVal; +}; +struct tstrRSSI { + u8 u8Full; + u8 u8Index; + s8 as8RSSI[NUM_RSSI]; +}; + +/* This structure is used to support parsing of the received 'N' message */ +struct tstrNetworkInfo { + s8 s8rssi; + u16 u16CapInfo; + u8 au8ssid[MAX_SSID_LEN]; + u8 u8SsidLen; + u8 au8bssid[6]; + u16 u16BeaconPeriod; + u8 u8DtimPeriod; + u8 u8channel; + /* + * of type unsigned long to be accepted by the linux kernel + *macro time_after() + */ + unsigned long u32TimeRcvdInScanCached; + unsigned long u32TimeRcvdInScan; + bool bNewNetwork; +#ifdef AGING_ALG + u8 u8Found; +#endif +#ifdef WILC_P2P + unsigned int u32Tsf; /* time-stamp [Low only 32 bit] */ +#endif + u8 *pu8IEs; + u16 u16IEsLen; + void *pJoinParams; + struct tstrRSSI strRssi; + unsigned long long u64Tsf; /* time-stamp [Low and High 64 bit] */ +}; + +/* + * This structure is used to support parsing of the received Association + * Response frame + */ +struct tstrConnectRespInfo { + u16 u16capability; + u16 u16ConnectStatus; + u16 u16AssocID; + u8 *pu8RespIEs; + u16 u16RespIEsLen; +}; + +struct tstrConnectInfo { + u8 au8bssid[6]; + u8 *pu8ReqIEs; + size_t ReqIEsLen; + u8 *pu8RespIEs; + u16 u16RespIEsLen; + u16 u16ConnectStatus; +}; + +struct tstrDisconnectNotifInfo { + u16 u16reason; + u8 *ie; + size_t ie_len; +}; + +#ifndef CONNECT_DIRECT +struct wid_site_survey_reslts { + char SSID[MAX_SSID_LEN]; + u8 BssType; + u8 Channel; + u8 SecurityStatus; + u8 BSSID[6]; + char RxPower; + u8 Reserved; +}; +#endif /* CONNECT_DIRECT */ + +signed int CoreConfiguratorInit(void); +signed int CoreConfiguratorDeInit(void); +signed int SendConfigPkt(u8 u8Mode, struct tstrWID *pstrWIDs, + unsigned int u32WIDsCount, + bool bRespRequired, + unsigned int drvHandler); +signed int ParseNetworkInfo(u8 *pu8MsgBuffer, struct tstrNetworkInfo **ppstrNetworkInfo); +signed int DeallocateNetworkInfo(struct tstrNetworkInfo *pstrNetworkInfo); +signed int ParseAssocRespInfo(u8 *pu8Buffer, unsigned int u32BufferLen, + struct tstrConnectRespInfo **ppstrConnectRespInfo); +signed int DeallocateAssocRespInfo(struct tstrConnectRespInfo *pstrConnectRespInfo); +#ifndef CONNECT_DIRECT +signed int ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], + struct wid_site_survey_reslts **ppstrSurveyResults, + unsigned int *pu32SurveyResultsCount); +signed int DeallocateSurveyResults(struct wid_site_survey_reslts *pstrSurveyResults); +#endif /* CONNECT_DIRECT */ +signed int SendRawPacket(s8 *pspacket, signed int s32PacketLen); +void NetworkInfoReceived(u8 *pu8Buffer, unsigned int u32Length); +void GnrlAsyncInfoReceived(u8 *pu8Buffer, unsigned int u32Length); +void host_int_ScanCompleteReceived(u8 *pu8Buffer, unsigned int u32Length); +#endif /* CORECONFIGURATOR_H */ diff --git a/wilc3000/linux_wlan_sdio.c b/wilc3000/linux_wlan_sdio.c index 0575b81..5c63d55 100644 --- a/wilc3000/linux_wlan_sdio.c +++ b/wilc3000/linux_wlan_sdio.c @@ -1,320 +1,320 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include "linux_wlan_sdio.h" -#include "linux_wlan_common.h" -#include "at_pwr_dev.h" - -#define SDIO_MODALIAS "wilc_sdio" - -#if defined (PLAT_SAMA5D4) -#define MAX_SPEED 40000000 // 6000000 -#else -#define MAX_SPEED 50000000 -#endif - -struct sdio_func *local_sdio_func = NULL; -EXPORT_SYMBOL(local_sdio_func); - -static isr_handler_t isr_handler; - -#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) }, - - { } -}; - -#ifndef WILC_SDIO_IRQ_GPIO -enum sdio_host_lock { - WILC_SDIO_HOST_NO_TAKEN = 0, - WILC_SDIO_HOST_IRQ_TAKEN = 1, - WILC_SDIO_HOST_DIS_TAKEN = 2, -}; - -static enum sdio_host_lock sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; -static wait_queue_head_t sdio_intr_waitqueue; -#endif /* WILC_SDIO_IRQ_GPIO */ - -static void wilc_sdio_interrupt(struct sdio_func *func) -{ -#ifndef WILC_SDIO_IRQ_GPIO - if (sdio_intr_lock == WILC_SDIO_HOST_DIS_TAKEN) - return; - sdio_intr_lock = WILC_SDIO_HOST_IRQ_TAKEN; - - sdio_release_host(func); - if (NULL != isr_handler) - isr_handler(); - sdio_claim_host(func); - - sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; - wake_up_interruptible(&sdio_intr_waitqueue); -#endif /* WILC_SDIO_IRQ_GPIO */ -} - -int linux_sdio_cmd52(struct sdio_cmd52_t *cmd) -{ - struct sdio_func *func = local_sdio_func; - int ret; - u8 data; - - sdio_claim_host(func); - - func->num = cmd->function; - if (cmd->read_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 { - 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(struct sdio_cmd53_t *cmd) -{ - struct sdio_func *func = local_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) { - ret = sdio_memcpy_toio(func, - cmd->address, - (void *)cmd->buffer, - size); - } else { - 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; -} - -volatile int probe = 0; -static int linux_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - PRINT_D(BUS_DBG, "probe function\n"); - - if (NULL != local_sdio_func) { - local_sdio_func = func; - probe = 1; - - up(&sdio_probe_sync); - - return 0; - } - local_sdio_func = func; - - up(&sdio_probe_sync); - - return 0; -} - -static void linux_sdio_remove(struct sdio_func *func) -{ -} - -int sdio_init(struct wilc_wlan_inp *inp, wilc_debug_func func); -int sdio_deinit(void *pv); -void chip_wakeup(int source); -void chip_allow_sleep(int source); -extern void (*pf_chip_sleep_manually)(unsigned int , int ); -extern int (*pf_get_num_conn_ifcs)(void); -extern void (*pf_host_wakeup_notify)(int); -extern void (*pf_host_sleep_notify)(int); -extern int (*pf_get_u8SuspendOnEvent_value)(void); - -static int wilc_sdio_suspend(struct device *dev) -{ - printk("\n\n << SUSPEND >>\n\n"); - chip_wakeup(0); - /*if there is no events , put the chip in low power mode */ - if(pf_get_u8SuspendOnEvent_value()== 0) - - { - /*BugID_5213*/ - /*Allow chip sleep, only if both interfaces are not connected*/ - if(!pf_get_num_conn_ifcs()) - { - pf_chip_sleep_manually(0xFFFFFFFF,0); - } - } - else - { - /*notify the chip that host will sleep*/ - pf_host_sleep_notify(0); - chip_allow_sleep(0); - } - /*reset SDIO to allow kerenl reintilaization at wake up*/ - sdio_deinit(NULL); - /*claim the host to prevent driver SDIO access before resume is called*/ - sdio_claim_host(local_sdio_func); - return 0 ; -} - -static int wilc_sdio_resume(struct device *dev) -{ - sdio_release_host(local_sdio_func); - /*wake the chip to compelete the re-intialization*/ - chip_wakeup(0); - printk("\n\n <> \n\n"); - /*Init SDIO block mode*/ - sdio_init(NULL,NULL); - /*if there is an event , notify the chip that the host is awake now*/ - if(pf_get_u8SuspendOnEvent_value()== 1) - pf_host_wakeup_notify(0); - - chip_allow_sleep(0); - return 0; - -} - -static const struct dev_pm_ops wilc_sdio_pm_ops = { - .suspend = wilc_sdio_suspend, - .resume = wilc_sdio_resume, - }; - -struct sdio_driver wilc_bus = { - .name = SDIO_MODALIAS, - .id_table = wilc_sdio_ids, - .probe = linux_sdio_probe, - .remove = linux_sdio_remove, - - .drv = { - .pm = &wilc_sdio_pm_ops, - } -}; - - -int enable_sdio_interrupt(isr_handler_t p_isr_handler) -{ - int ret = 0; - -#ifndef WILC_SDIO_IRQ_GPIO - sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; - - isr_handler = p_isr_handler; - - 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 /* WILC_SDIO_IRQ_GPIO */ - return ret; -} -EXPORT_SYMBOL(enable_sdio_interrupt); - -void disable_sdio_interrupt(void) -{ -#ifndef WILC_SDIO_IRQ_GPIO - int ret; - - if (sdio_intr_lock == WILC_SDIO_HOST_IRQ_TAKEN) - wait_event_interruptible(sdio_intr_waitqueue, - sdio_intr_lock == WILC_SDIO_HOST_NO_TAKEN); - sdio_intr_lock = WILC_SDIO_HOST_DIS_TAKEN; - - 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); - - sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; -#endif /* WILC_SDIO_IRQ_GPIO */ -} -EXPORT_SYMBOL(disable_sdio_interrupt); - -static int linux_sdio_set_speed(int speed) -{ -#if 0 - 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_D(INIT_DBG,"@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed); -#endif - return 1; -} - -int linux_sdio_init(void *pv) -{ -#ifndef WILC_SDIO_IRQ_GPIO - init_waitqueue_head(&sdio_intr_waitqueue); -#endif /* WILC_SDIO_IRQ_GPIO */ - return 1; -} - -void linux_sdio_deinit(void *pv) -{ - sdio_unregister_driver(&wilc_bus); -} - -int linux_sdio_set_max_speed(void) -{ - return linux_sdio_set_speed(MAX_SPEED); -} - +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "linux_wlan_sdio.h" +#include "linux_wlan_common.h" +#include "at_pwr_dev.h" + +#define SDIO_MODALIAS "wilc_sdio" + +#if defined (PLAT_SAMA5D4) +#define MAX_SPEED 40000000 // 6000000 +#else +#define MAX_SPEED 50000000 +#endif + +struct sdio_func *local_sdio_func = NULL; +EXPORT_SYMBOL(local_sdio_func); + +static isr_handler_t isr_handler; + +#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) }, + + { } +}; + +#ifndef WILC_SDIO_IRQ_GPIO +enum sdio_host_lock { + WILC_SDIO_HOST_NO_TAKEN = 0, + WILC_SDIO_HOST_IRQ_TAKEN = 1, + WILC_SDIO_HOST_DIS_TAKEN = 2, +}; + +static enum sdio_host_lock sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; +static wait_queue_head_t sdio_intr_waitqueue; +#endif /* WILC_SDIO_IRQ_GPIO */ + +static void wilc_sdio_interrupt(struct sdio_func *func) +{ +#ifndef WILC_SDIO_IRQ_GPIO + if (sdio_intr_lock == WILC_SDIO_HOST_DIS_TAKEN) + return; + sdio_intr_lock = WILC_SDIO_HOST_IRQ_TAKEN; + + sdio_release_host(func); + if (NULL != isr_handler) + isr_handler(); + sdio_claim_host(func); + + sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; + wake_up_interruptible(&sdio_intr_waitqueue); +#endif /* WILC_SDIO_IRQ_GPIO */ +} + +int linux_sdio_cmd52(struct sdio_cmd52_t *cmd) +{ + struct sdio_func *func = local_sdio_func; + int ret; + u8 data; + + sdio_claim_host(func); + + func->num = cmd->function; + if (cmd->read_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 { + 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(struct sdio_cmd53_t *cmd) +{ + struct sdio_func *func = local_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) { + ret = sdio_memcpy_toio(func, + cmd->address, + (void *)cmd->buffer, + size); + } else { + 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; +} + +volatile int probe = 0; +static int linux_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + PRINT_D(BUS_DBG, "probe function\n"); + + if (NULL != local_sdio_func) { + local_sdio_func = func; + probe = 1; + + up(&sdio_probe_sync); + + return 0; + } + local_sdio_func = func; + + up(&sdio_probe_sync); + + return 0; +} + +static void linux_sdio_remove(struct sdio_func *func) +{ +} + +int sdio_init(struct wilc_wlan_inp *inp, wilc_debug_func func); +int sdio_deinit(void *pv); +void chip_wakeup(int source); +void chip_allow_sleep(int source); +extern void (*pf_chip_sleep_manually)(unsigned int , int ); +extern int (*pf_get_num_conn_ifcs)(void); +extern void (*pf_host_wakeup_notify)(int); +extern void (*pf_host_sleep_notify)(int); +extern int (*pf_get_u8SuspendOnEvent_value)(void); + +static int wilc_sdio_suspend(struct device *dev) +{ + printk("\n\n << SUSPEND >>\n\n"); + chip_wakeup(0); + /*if there is no events , put the chip in low power mode */ + if(pf_get_u8SuspendOnEvent_value()== 0) + + { + /*BugID_5213*/ + /*Allow chip sleep, only if both interfaces are not connected*/ + if(!pf_get_num_conn_ifcs()) + { + pf_chip_sleep_manually(0xFFFFFFFF,0); + } + } + else + { + /*notify the chip that host will sleep*/ + pf_host_sleep_notify(0); + chip_allow_sleep(0); + } + /*reset SDIO to allow kerenl reintilaization at wake up*/ + sdio_deinit(NULL); + /*claim the host to prevent driver SDIO access before resume is called*/ + sdio_claim_host(local_sdio_func); + return 0 ; +} + +static int wilc_sdio_resume(struct device *dev) +{ + sdio_release_host(local_sdio_func); + /*wake the chip to compelete the re-intialization*/ + chip_wakeup(0); + printk("\n\n <> \n\n"); + /*Init SDIO block mode*/ + sdio_init(NULL,NULL); + /*if there is an event , notify the chip that the host is awake now*/ + if(pf_get_u8SuspendOnEvent_value()== 1) + pf_host_wakeup_notify(0); + + chip_allow_sleep(0); + return 0; + +} + +static const struct dev_pm_ops wilc_sdio_pm_ops = { + .suspend = wilc_sdio_suspend, + .resume = wilc_sdio_resume, + }; + +struct sdio_driver wilc_bus = { + .name = SDIO_MODALIAS, + .id_table = wilc_sdio_ids, + .probe = linux_sdio_probe, + .remove = linux_sdio_remove, + + .drv = { + .pm = &wilc_sdio_pm_ops, + } +}; + + +int enable_sdio_interrupt(isr_handler_t p_isr_handler) +{ + int ret = 0; + +#ifndef WILC_SDIO_IRQ_GPIO + sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; + + isr_handler = p_isr_handler; + + 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 /* WILC_SDIO_IRQ_GPIO */ + return ret; +} +EXPORT_SYMBOL(enable_sdio_interrupt); + +void disable_sdio_interrupt(void) +{ +#ifndef WILC_SDIO_IRQ_GPIO + int ret; + + if (sdio_intr_lock == WILC_SDIO_HOST_IRQ_TAKEN) + wait_event_interruptible(sdio_intr_waitqueue, + sdio_intr_lock == WILC_SDIO_HOST_NO_TAKEN); + sdio_intr_lock = WILC_SDIO_HOST_DIS_TAKEN; + + 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); + + sdio_intr_lock = WILC_SDIO_HOST_NO_TAKEN; +#endif /* WILC_SDIO_IRQ_GPIO */ +} +EXPORT_SYMBOL(disable_sdio_interrupt); + +static int linux_sdio_set_speed(int speed) +{ +#if 0 + 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_D(INIT_DBG,"@@@@@@@@@@@@ change SDIO speed to %d @@@@@@@@@\n", speed); +#endif + return 1; +} + +int linux_sdio_init(void *pv) +{ +#ifndef WILC_SDIO_IRQ_GPIO + init_waitqueue_head(&sdio_intr_waitqueue); +#endif /* WILC_SDIO_IRQ_GPIO */ + return 1; +} + +void linux_sdio_deinit(void *pv) +{ + sdio_unregister_driver(&wilc_bus); +} + +int linux_sdio_set_max_speed(void) +{ + return linux_sdio_set_speed(MAX_SPEED); +} + diff --git a/wilc3000/linux_wlan_sdio.h b/wilc3000/linux_wlan_sdio.h index e9b8ed9..4725114 100644 --- a/wilc3000/linux_wlan_sdio.h +++ b/wilc3000/linux_wlan_sdio.h @@ -1,32 +1,32 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef LINUX_WLAN_SDIO_H -#define LINUX_WLAN_SDIO_H - -#include -#include "wilc_type.h" - -#ifdef WILC_SDIO -extern struct sdio_func *local_sdio_func; -extern struct sdio_driver wilc_bus; -#endif /* WILC_SDIO */ -extern volatile int probe; +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef LINUX_WLAN_SDIO_H +#define LINUX_WLAN_SDIO_H + +#include +#include "wilc_type.h" + +#ifdef WILC_SDIO +extern struct sdio_func *local_sdio_func; +extern struct sdio_driver wilc_bus; +#endif /* WILC_SDIO */ +extern volatile int probe; struct sdio_cmd52_t { uint32_t read_write : 1; @@ -46,14 +46,14 @@ struct sdio_cmd53_t { uint8_t *buffer; uint32_t block_size; }; -typedef void (*wilc_debug_func)(uint32_t, char *, ...); -typedef void (*isr_handler_t)(void); -int linux_sdio_init(void *); -void linux_sdio_deinit(void *); -int linux_sdio_cmd52(struct sdio_cmd52_t *cmd); -int linux_sdio_cmd53(struct sdio_cmd53_t *cmd); -int enable_sdio_interrupt(isr_handler_t isr_handler); -void disable_sdio_interrupt(void); -int linux_sdio_set_max_speed(void); - -#endif /* LINUX_WLAN_SDIO_H */ +typedef void (*wilc_debug_func)(uint32_t, char *, ...); +typedef void (*isr_handler_t)(void); +int linux_sdio_init(void *); +void linux_sdio_deinit(void *); +int linux_sdio_cmd52(struct sdio_cmd52_t *cmd); +int linux_sdio_cmd53(struct sdio_cmd53_t *cmd); +int enable_sdio_interrupt(isr_handler_t isr_handler); +void disable_sdio_interrupt(void); +int linux_sdio_set_max_speed(void); + +#endif /* LINUX_WLAN_SDIO_H */ diff --git a/wilc3000/linux_wlan_spi.c b/wilc3000/linux_wlan_spi.c index c404f69..863cd63 100644 --- a/wilc3000/linux_wlan_spi.c +++ b/wilc3000/linux_wlan_spi.c @@ -1,189 +1,189 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "linux_wlan_common.h" -#include "at_pwr_dev.h" - -static uint32_t SPEED = MIN_SPEED; - -struct spi_device *wilc_spi_dev; -EXPORT_SYMBOL(wilc_spi_dev); - -static int 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; - - up(&spi_probe_sync); - return 0; -} - -static int wilc_bus_remove(struct spi_device *spi) -{ - return 0; -} - -struct spi_driver wilc_bus __refdata = { - .driver = { - .name = MODALIAS, - }, - .probe = wilc_bus_probe, - .remove = __devexit_p(wilc_bus_remove), -}; - -void linux_spi_deinit(void *vp) -{ - spi_unregister_driver(&wilc_bus); -} - -int linux_spi_init(void *vp) -{ - int ret = 1; - static int called; - - if (called == 0) { - called++; - if (NULL == &wilc_bus) { - PRINT_ER("wilc_bus address is NULL\n"); - return 0; /* TODO */ - } - - ret = spi_register_driver(&wilc_bus); - } - - (ret < 0) ? (ret = 0) : (ret = 1); - - return ret; -} - -int linux_spi_write(uint8_t *b, uint32_t len) -{ - int ret; - struct spi_message msg; - - if (len > 0 && NULL != b) { - 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 0; /* TODO: it should be return -ENOMEM */ - - tr.rx_buf = r_buffer; - PRINT_D(BUS_DBG, "Request writing %d bytes\n", len); - - spi_message_init(&msg); - 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 due to NULL buffer or zero length\n"); - ret = -1; - } - - (ret < 0) ? (ret = 0) : (ret = 1); - - return ret; -} - -int linux_spi_read(u8 *rb, unsigned long rlen) -{ - int ret; - - if (rlen > 0) { - char *t_buffer; - struct spi_message msg; - struct spi_transfer tr = { - .rx_buf = rb, - .len = rlen, - .speed_hz = SPEED, - .delay_usecs = 0, - - }; - t_buffer = kzalloc(rlen, GFP_KERNEL); - - if (!t_buffer) - return 0; /* TODO: it should be return -ENOMEM */ - - tr.tx_buf = t_buffer; - - spi_message_init(&msg); - 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 due to zero length\n"); - ret = -1; - } - - (ret < 0) ? (ret = 0) : (ret = 1); - - return ret; -} - -int linux_spi_write_read(u8 *wb, u8 *rb, unsigned int 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, - .delay_usecs = 0, - - }; - - spi_message_init(&msg); - 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 due to zero length\n"); - ret = -1; - } - - (ret < 0) ? (ret = 0) : (ret = 1); - - return ret; -} +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux_wlan_common.h" +#include "at_pwr_dev.h" + +static uint32_t SPEED = MIN_SPEED; + +struct spi_device *wilc_spi_dev; +EXPORT_SYMBOL(wilc_spi_dev); + +static int 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; + + up(&spi_probe_sync); + return 0; +} + +static int wilc_bus_remove(struct spi_device *spi) +{ + return 0; +} + +struct spi_driver wilc_bus __refdata = { + .driver = { + .name = MODALIAS, + }, + .probe = wilc_bus_probe, + .remove = __devexit_p(wilc_bus_remove), +}; + +void linux_spi_deinit(void *vp) +{ + spi_unregister_driver(&wilc_bus); +} + +int linux_spi_init(void *vp) +{ + int ret = 1; + static int called; + + if (called == 0) { + called++; + if (NULL == &wilc_bus) { + PRINT_ER("wilc_bus address is NULL\n"); + return 0; /* TODO */ + } + + ret = spi_register_driver(&wilc_bus); + } + + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +int linux_spi_write(uint8_t *b, uint32_t len) +{ + int ret; + struct spi_message msg; + + if (len > 0 && NULL != b) { + 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 0; /* TODO: it should be return -ENOMEM */ + + tr.rx_buf = r_buffer; + PRINT_D(BUS_DBG, "Request writing %d bytes\n", len); + + spi_message_init(&msg); + 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 due to NULL buffer or zero length\n"); + ret = -1; + } + + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +int linux_spi_read(u8 *rb, unsigned long rlen) +{ + int ret; + + if (rlen > 0) { + char *t_buffer; + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .len = rlen, + .speed_hz = SPEED, + .delay_usecs = 0, + + }; + t_buffer = kzalloc(rlen, GFP_KERNEL); + + if (!t_buffer) + return 0; /* TODO: it should be return -ENOMEM */ + + tr.tx_buf = t_buffer; + + spi_message_init(&msg); + 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 due to zero length\n"); + ret = -1; + } + + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} + +int linux_spi_write_read(u8 *wb, u8 *rb, unsigned int 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, + .delay_usecs = 0, + + }; + + spi_message_init(&msg); + 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 due to zero length\n"); + ret = -1; + } + + (ret < 0) ? (ret = 0) : (ret = 1); + + return ret; +} diff --git a/wilc3000/linux_wlan_spi.h b/wilc3000/linux_wlan_spi.h index 261a67a..bc77d6b 100644 --- a/wilc3000/linux_wlan_spi.h +++ b/wilc3000/linux_wlan_spi.h @@ -1,31 +1,31 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#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(uint8_t *b, uint32_t len); -int linux_spi_read(uint8_t *rb, uint32_t rlen); -int linux_spi_write_read(u8 *wb, u8 *rb, unsigned int rlen); -#endif +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#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(uint8_t *b, uint32_t len); +int linux_spi_read(uint8_t *rb, uint32_t rlen); +int linux_spi_write_read(u8 *wb, u8 *rb, unsigned int rlen); +#endif diff --git a/wilc3000/wilc_sdio.c b/wilc3000/wilc_sdio.c index 81c181d..d6b1804 100644 --- a/wilc3000/wilc_sdio.c +++ b/wilc3000/wilc_sdio.c @@ -1,1134 +1,1134 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "at_pwr_dev.h" -#include "wilc_wlan_if.h" -#include "wilc_wlan.h" - - -#define WILC_SDIO_BLOCK_SIZE 512 - -struct wilc_sdio { - void *os_context; - uint32_t block_size; - int (*sdio_cmd52)(struct sdio_cmd52_t *); - int (*sdio_cmd53)(struct sdio_cmd53_t *); - int (*sdio_set_max_speed)(void); - int nint; - /* Max num interrupts allowed in registers 0xf7, 0xf8 */ - #define MAX_NUN_INT_THRPT_ENH2 (5) - int has_thrpt_enh3; -}; - -static struct wilc_sdio g_sdio; - -#ifdef WILC_SDIO_IRQ_GPIO -static int sdio_write_reg(uint32_t addr, uint32_t data); -static int sdio_read_reg(uint32_t addr, uint32_t *data); -#endif /* WILC_SDIO_IRQ_GPIO */ - -static int sdio_set_func0_csa_address(uint32_t adr) -{ - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0x10c; - cmd.data = (uint8_t)adr; - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x10c data\n"); - goto _fail_; - } - - cmd.address = 0x10d; - cmd.data = (uint8_t)(adr >> 8); - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x10d data\n"); - goto _fail_; - } - - cmd.address = 0x10e; - cmd.data = (uint8_t)(adr >> 16); - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x10e data\n"); - goto _fail_; - } - - return 1; -_fail_: - return 0; -} - -static int sdio_set_func0_csa_address_byte0(uint32_t adr) -{ - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0x10c; - cmd.data = (uint8_t)adr; - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x10c data\n"); - goto _fail_; - } - - return 1; -_fail_: - return 0; -} - -static int sdio_set_func0_block_size(uint32_t block_size) -{ - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0x10; - cmd.data = (uint8_t)block_size; - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x10 data\n"); - goto _fail_; - } - - cmd.address = 0x11; - cmd.data = (uint8_t)(block_size >> 8); - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x11 data\n"); - goto _fail_; - } - - return 1; -_fail_: - return 0; -} - -static int sdio_set_func1_block_size(uint32_t block_size) -{ - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0x110; - cmd.data = (uint8_t)block_size; - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x110 data\n"); - goto _fail_; - } - cmd.address = 0x111; - cmd.data = (uint8_t)(block_size >> 8); - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd52, set 0x111 data\n"); - goto _fail_; - } - - return 1; -_fail_: - return 0; -} - -#ifdef WILC_SDIO_IRQ_GPIO -static int sdio_clear_int(void) -{ - uint32_t reg; - - if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, ®)) { - PRINT_ER("Failed read reg %08x\n", WILC_HOST_RX_CTRL_0); - return 0; - } - - reg &= ~0x1; - sdio_write_reg(WILC_HOST_RX_CTRL_0, reg); - - int_clrd++; - - return 1; -} -#else -static int sdio_clear_int(void) -{ - struct 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); - - int_clrd++; - - return cmd.data; -} -#endif /* WILC_SDIO_IRQ_GPIO */ - -uint32_t sdio_xfer_cnt(void) -{ - uint32_t cnt = 0; - struct 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; -} - -int sdio_check_bs(void) -{ - struct sdio_cmd52_t cmd; - - cmd.read_write = 0; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xc; - cmd.data = 0; - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Fail cmd 52, get BS register\n"); - goto _fail_; - } - - return 1; -_fail_: - return 0; -} - -static int sdio_write_reg(uint32_t addr, uint32_t data) -{ -#ifdef BIG_ENDIAN - data = BYTE_SWAP(data); -#endif - if ((addr >= 0xf0) && (addr <= 0xff)) { - struct 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)) { - PRINT_ER("Failed cmd 52, write reg %08x\n", addr); - goto _fail_; - } - } else { - struct 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 = (uint8_t *)&data; - cmd.block_size = g_sdio.block_size; - - if (!g_sdio.sdio_cmd53(&cmd)) { - PRINT_ER("Failed cmd53, write reg %08x\n", addr); - goto _fail_; - } - } - - return 1; -_fail_: - return 0; -} - -static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) -{ - uint32_t block_size = g_sdio.block_size; - struct 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)) { - PRINT_ER("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; - - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - PRINT_ER("Failed cmd53 [%x], bytes send\n", addr); - goto _fail_; - } - } - - return 1; -_fail_: - return 0; -} - -static int sdio_read_reg(uint32_t addr, uint32_t *data) -{ - if ((addr >= 0xf0) && (addr <= 0xff)) { - struct sdio_cmd52_t cmd; - - cmd.read_write = 0; - cmd.function = 0; - cmd.raw = 0; - cmd.address = addr; - if (!g_sdio.sdio_cmd52(&cmd)) { - PRINT_ER("Failed cmd 52, read reg %08x\n", addr); - goto _fail_; - } - *data = cmd.data; - } else { - struct 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 = (uint8_t *)data; - - cmd.block_size = g_sdio.block_size; - - if (!g_sdio.sdio_cmd53(&cmd)) { - PRINT_ER("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(uint32_t addr, uint8_t *buf, uint32_t size) -{ - uint32_t block_size = g_sdio.block_size; - struct 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)) { - PRINT_ER("Failed cmd53 [%x], block read\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; - - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - PRINT_ER("Failed cmd53 [%x], bytes read\n", addr); - goto _fail_; - } - } - - return 1; -_fail_: - return 0; -} - -int sdio_deinit(void *pv) -{ - - struct sdio_cmd52_t cmd; - - PRINT_INFO(BUS_DBG, "De Init SDIO\n"); - /* - * func 1 interrupt enable - */ - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 1; - cmd.address = 0x6; - cmd.data = 0x8; - if (!g_sdio.sdio_cmd52(&cmd)) - PRINT_ER("Fail cmd 52, reset cmd\n"); - return 1; -} - -#ifdef WILC_SDIO_IRQ_GPIO -static int sdio_sync(void) -{ - uint32_t reg; - int ret; - - /* - * Disable power sequencer - */ - if (!sdio_read_reg(WILC_MISC, ®)) { - PRINT_ER("Failed read misc reg\n"); - return 0; - } - - reg &= ~(1 << 8); - if (!sdio_write_reg(WILC_MISC, reg)) { - PRINT_ER("Failed write misc reg\n"); - return 0; - } - - /* - * interrupt pin mux select - */ - ret = sdio_read_reg(WILC_PIN_MUX_0, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - reg |= (1 << 8); - ret = sdio_write_reg(WILC_PIN_MUX_0, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - - /** - * interrupt enable - **/ - ret = sdio_read_reg(WILC_INTR_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - reg |= (1 << 16); - ret = sdio_write_reg(WILC_INTR_ENABLE, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - - return 1; -} -#else -static int sdio_sync(void) -{ - uint32_t reg; - - /* - * Disable power sequencer - */ - if (!sdio_read_reg(WILC_MISC, ®)) { - PRINT_ER("Failed read misc reg\n"); - return 0; - } - - reg &= ~(1 << 8); - if (!sdio_write_reg(WILC_MISC, reg)) { - PRINT_ER("Failed write misc reg\n"); - return 0; - } - - return 1; -} -#endif - -int sdio_init(struct wilc_wlan_inp *inp, wilc_debug_func func) -{ - struct sdio_cmd52_t cmd; - int loop; - uint32_t chipid; - if(inp != NULL) - { - memset(&g_sdio, 0, sizeof(struct wilc_sdio)); - - 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)) { - PRINT_ER("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; - } - /* - * 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)) { - PRINT_ER("Fail cmd 52, enable csa\n"); - goto _fail_; - } - - /* - * function 0 block size - */ - if (!sdio_set_func0_block_size(WILC_SDIO_BLOCK_SIZE)) { - PRINT_ER("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)) { - PRINT_ER("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)) { - PRINT_ER("Fail cmd 52, get IOR register\n"); - goto _fail_; - } - if (cmd.data == 0x2) - break; - } while (loop--); - - if (loop <= 0) { - PRINT_ER("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)) { - PRINT_ER("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)) { - PRINT_ER("Fail cmd 52, set IEN register\n"); - goto _fail_; - } - - /* - * make sure can read back chip id correctly - */ - if(inp != NULL) - { - if (!sdio_read_reg(0x3b0000, &chipid)) { - PRINT_ER("Fail cmd read chip id\n"); - goto _fail_; - } - - PRINT_D(BUS_DBG, "chipid %08x\n", chipid); - g_sdio.has_thrpt_enh3 = 1; - PRINT_D(BUS_DBG, "has_thrpt_enh3 = %d\n", g_sdio.has_thrpt_enh3); - } - int_clrd = 0; - - g_sdio.sdio_set_max_speed(); - - return 1; -_fail_: - return 0; -} - -static int sdio_read_size(uint32_t *size) -{ - uint32_t tmp; - struct 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.address = 0xf3; - cmd.data = 0; - g_sdio.sdio_cmd52(&cmd); - tmp |= (cmd.data << 8); - - *size = tmp; - - return 1; -} - -#ifdef WILC_SDIO_IRQ_GPIO -static int sdio_read_int(uint32_t *int_status) -{ - uint32_t tmp = 0; - struct sdio_cmd52_t cmd; - uint32_t irq_flags; - - sdio_read_size(&tmp); - - cmd.read_write = 0; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xfe; - cmd.data = 0; - g_sdio.sdio_cmd52(&cmd); - irq_flags = cmd.data & 0x0f; - tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET); - - *int_status = tmp; - - return 1; -} -#else -static int sdio_read_int(uint32_t *int_status) -{ - uint32_t tmp = 0; - struct sdio_cmd52_t cmd; - int i; - - sdio_read_size(&tmp); - - cmd.function = 1; - cmd.address = 0x04; - cmd.data = 0; - g_sdio.sdio_cmd52(&cmd); - if (cmd.data & (1 << 0)) - tmp |= INT_0; - - if (cmd.data & (1 << 2)) - tmp |= INT_1; - - if (cmd.data & (1 << 3)) - tmp |= INT_2; - - if (cmd.data & (1 << 4)) - tmp |= INT_3; - - if (cmd.data & (1 << 5)) - tmp |= INT_4; - - if (cmd.data & (1 << 6)) - tmp |= INT_5; - - for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { - if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) { - PRINT_ER("Unexpected int\n"); - break; - } - } - - *int_status = tmp; - - return 1; -} -#endif - -#ifdef WILC_SDIO_IRQ_GPIO -static int sdio_clear_int_ext(uint32_t val) -{ - int ret; - - if (g_sdio.has_thrpt_enh3) { - uint32_t reg; - - reg = val & ((1 << MAX_NUN_INT_THRPT_ENH2) - 1); - if (reg) { - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xfe; - cmd.data = reg; - - ret = g_sdio.sdio_cmd52(&cmd); - if (!ret) { - PRINT_ER("Failed cmd52\n"); - goto _fail_; - } - } - - reg = 0; - /* select VMM table 0 */ - if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) - reg |= (1 << 0); - /* select VMM table 1 */ - if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) - reg |= (1 << 1); - /* enable VMM */ - if ((val & EN_VMM) == EN_VMM) - reg |= (1 << 2); - if (reg) { - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf1; - cmd.data = reg; - - ret = g_sdio.sdio_cmd52(&cmd); - if (!ret) { - PRINT_ER("Failed cmd52\n"); - goto _fail_; - } - } - } else { - /* - * see below. has_thrpt_enh2 uses register 0xf8 to clear - * interrupts. - * We Cannot clear multiple interrupts. - * we must clear each interrupt individually - */ - uint32_t flags; - uint32_t vmm_ctl; - - flags = val & ((1 << MAX_NUM_INT) - 1); - - if (flags) { - int i; - - ret = 1; - for (i = 0; i < g_sdio.nint; i++) { - if (flags & 1) { - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf8; - cmd.data = (1 << i); - - ret = g_sdio.sdio_cmd52(&cmd); - if (!ret) { - PRINT_ER("Failed cmd52\n"); - goto _fail_; - } - } - - if (!ret) - break; - flags >>= 1; - } - if (!ret) - goto _fail_; - - for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { - if (flags & 1) - PRINT_ER("Unexpected int cleared\n"); - - flags >>= 1; - } - } - - vmm_ctl = 0; - /* select VMM table 0 */ - if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) - vmm_ctl |= (1 << 0); - /* select VMM table 1 */ - if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) - vmm_ctl |= (1 << 1); - /* enable VMM */ - if ((val & EN_VMM) == EN_VMM) - vmm_ctl |= (1 << 2); - - if (vmm_ctl) { - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf1; - cmd.data = vmm_ctl; - ret = g_sdio.sdio_cmd52(&cmd); - if (!ret) { - PRINT_ER("Failed cmd52\n"); - goto _fail_; - } - } - } - - return 1; -_fail_: - return 0; -} -#else -static int sdio_clear_int_ext(uint32_t val) -{ - int ret; - - if (g_sdio.has_thrpt_enh3) { - uint32_t reg = 0; - - /* select VMM table 0 */ - if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) - reg |= (1 << 0); - /* select VMM table 1 */ - if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) - reg |= (1 << 1); - /* enable VMM */ - if ((val & EN_VMM) == EN_VMM) - reg |= (1 << 2); - if (reg) { - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf1; - cmd.data = reg; - - ret = g_sdio.sdio_cmd52(&cmd); - if (!ret) { - PRINT_ER("Failed cmd52\n"); - goto _fail_; - } - } - } else { - uint32_t vmm_ctl = 0; - - /* select VMM table 0 */ - if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) - vmm_ctl |= (1 << 0); - /* select VMM table 1 */ - if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) - vmm_ctl |= (1 << 1); - /* enable VMM */ - if ((val & EN_VMM) == EN_VMM) - vmm_ctl |= (1 << 2); - - if (vmm_ctl) { - struct sdio_cmd52_t cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf1; - cmd.data = vmm_ctl; - ret = g_sdio.sdio_cmd52(&cmd); - if (!ret) { - PRINT_ER("Failed cmd52\n"); - goto _fail_; - } - } - } - - return 1; -_fail_: - return 0; -} -#endif - -#ifdef WILC_SDIO_IRQ_GPIO -static int sdio_sync_ext(int nint) -{ - uint32_t reg; - int ret, i; - - if (nint > MAX_NUM_INT) { - PRINT_ER("too many interupts %d\n", nint); - return 0; - } - if (nint > MAX_NUN_INT_THRPT_ENH2) { - PRINT_ER("not support more than 5 ints when has_thrpt_enh2=1\n"); - return 0; - } - - g_sdio.nint = nint; - - /* - * Disable power sequencer - */ - if (!sdio_read_reg(WILC_MISC, ®)) { - PRINT_ER("Failed read misc reg\n"); - return 0; - } - - reg &= ~(1 << 8); - if (!sdio_write_reg(WILC_MISC, reg)) { - PRINT_ER("Failed write misc reg\n"); - return 0; - } - - /* - * interrupt pin mux select - */ - ret = sdio_read_reg(WILC_PIN_MUX_0, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - reg |= (1 << 8); - ret = sdio_write_reg(WILC_PIN_MUX_0, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - - /** - * interrupt enable - **/ - ret = sdio_read_reg(WILC_INTR_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - - for (i = 0; (i < 5) && (nint > 0); i++, nint--) - reg |= (1 << (27 + i)); - - ret = sdio_write_reg(WILC_INTR_ENABLE, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - if (nint) { - ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_INTR2_ENABLE); - return 0; - } - - for (i = 0; (i < 3) && (nint > 0); i++, nint--) - reg |= (1 << i); - - ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_INTR2_ENABLE); - return 0; - } - } - - return 1; -} -#else -static int sdio_sync_ext(int nint) -{ - uint32_t reg; - - if (nint > MAX_NUM_INT) { - PRINT_ER("too many interupts %d\n", nint); - return 0; - } - if (nint > MAX_NUN_INT_THRPT_ENH2) { - PRINT_ER("not support more than 5 int when has_thrpt_enh2=1\n"); - return 0; - } - - g_sdio.nint = nint; - - /* - * Disable power sequencer - */ - if (!sdio_read_reg(WILC_MISC, ®)) { - PRINT_ER("Failed read misc reg\n"); - return 0; - } - - reg &= ~(1 << 8); - if (!sdio_write_reg(WILC_MISC, reg)) { - PRINT_ER("Failed write misc reg\n"); - return 0; - } - - return 1; -} -#endif - -/* - * Global sdio HIF function table - */ -struct wilc_hif_func 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, -}; -EXPORT_SYMBOL(hif_sdio); - +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "at_pwr_dev.h" +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" + + +#define WILC_SDIO_BLOCK_SIZE 512 + +struct wilc_sdio { + void *os_context; + uint32_t block_size; + int (*sdio_cmd52)(struct sdio_cmd52_t *); + int (*sdio_cmd53)(struct sdio_cmd53_t *); + int (*sdio_set_max_speed)(void); + int nint; + /* Max num interrupts allowed in registers 0xf7, 0xf8 */ + #define MAX_NUN_INT_THRPT_ENH2 (5) + int has_thrpt_enh3; +}; + +static struct wilc_sdio g_sdio; + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_write_reg(uint32_t addr, uint32_t data); +static int sdio_read_reg(uint32_t addr, uint32_t *data); +#endif /* WILC_SDIO_IRQ_GPIO */ + +static int sdio_set_func0_csa_address(uint32_t adr) +{ + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10c; + cmd.data = (uint8_t)adr; + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x10c data\n"); + goto _fail_; + } + + cmd.address = 0x10d; + cmd.data = (uint8_t)(adr >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x10d data\n"); + goto _fail_; + } + + cmd.address = 0x10e; + cmd.data = (uint8_t)(adr >> 16); + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x10e data\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_set_func0_csa_address_byte0(uint32_t adr) +{ + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10c; + cmd.data = (uint8_t)adr; + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x10c data\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_set_func0_block_size(uint32_t block_size) +{ + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x10; + cmd.data = (uint8_t)block_size; + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x10 data\n"); + goto _fail_; + } + + cmd.address = 0x11; + cmd.data = (uint8_t)(block_size >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x11 data\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_set_func1_block_size(uint32_t block_size) +{ + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0x110; + cmd.data = (uint8_t)block_size; + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x110 data\n"); + goto _fail_; + } + cmd.address = 0x111; + cmd.data = (uint8_t)(block_size >> 8); + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd52, set 0x111 data\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_clear_int(void) +{ + uint32_t reg; + + if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, ®)) { + PRINT_ER("Failed read reg %08x\n", WILC_HOST_RX_CTRL_0); + return 0; + } + + reg &= ~0x1; + sdio_write_reg(WILC_HOST_RX_CTRL_0, reg); + + int_clrd++; + + return 1; +} +#else +static int sdio_clear_int(void) +{ + struct 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); + + int_clrd++; + + return cmd.data; +} +#endif /* WILC_SDIO_IRQ_GPIO */ + +uint32_t sdio_xfer_cnt(void) +{ + uint32_t cnt = 0; + struct 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; +} + +int sdio_check_bs(void) +{ + struct sdio_cmd52_t cmd; + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xc; + cmd.data = 0; + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Fail cmd 52, get BS register\n"); + goto _fail_; + } + + return 1; +_fail_: + return 0; +} + +static int sdio_write_reg(uint32_t addr, uint32_t data) +{ +#ifdef BIG_ENDIAN + data = BYTE_SWAP(data); +#endif + if ((addr >= 0xf0) && (addr <= 0xff)) { + struct 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)) { + PRINT_ER("Failed cmd 52, write reg %08x\n", addr); + goto _fail_; + } + } else { + struct 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 = (uint8_t *)&data; + cmd.block_size = g_sdio.block_size; + + if (!g_sdio.sdio_cmd53(&cmd)) { + PRINT_ER("Failed cmd53, write reg %08x\n", addr); + goto _fail_; + } + } + + return 1; +_fail_: + return 0; +} + +static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) +{ + uint32_t block_size = g_sdio.block_size; + struct 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)) { + PRINT_ER("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; + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + PRINT_ER("Failed cmd53 [%x], bytes send\n", addr); + goto _fail_; + } + } + + return 1; +_fail_: + return 0; +} + +static int sdio_read_reg(uint32_t addr, uint32_t *data) +{ + if ((addr >= 0xf0) && (addr <= 0xff)) { + struct sdio_cmd52_t cmd; + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + if (!g_sdio.sdio_cmd52(&cmd)) { + PRINT_ER("Failed cmd 52, read reg %08x\n", addr); + goto _fail_; + } + *data = cmd.data; + } else { + struct 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 = (uint8_t *)data; + + cmd.block_size = g_sdio.block_size; + + if (!g_sdio.sdio_cmd53(&cmd)) { + PRINT_ER("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(uint32_t addr, uint8_t *buf, uint32_t size) +{ + uint32_t block_size = g_sdio.block_size; + struct 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)) { + PRINT_ER("Failed cmd53 [%x], block read\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; + + if (addr > 0) { + if (!sdio_set_func0_csa_address(addr)) + goto _fail_; + } + if (!g_sdio.sdio_cmd53(&cmd)) { + PRINT_ER("Failed cmd53 [%x], bytes read\n", addr); + goto _fail_; + } + } + + return 1; +_fail_: + return 0; +} + +int sdio_deinit(void *pv) +{ + + struct sdio_cmd52_t cmd; + + PRINT_INFO(BUS_DBG, "De Init SDIO\n"); + /* + * func 1 interrupt enable + */ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = 0x6; + cmd.data = 0x8; + if (!g_sdio.sdio_cmd52(&cmd)) + PRINT_ER("Fail cmd 52, reset cmd\n"); + return 1; +} + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_sync(void) +{ + uint32_t reg; + int ret; + + /* + * Disable power sequencer + */ + if (!sdio_read_reg(WILC_MISC, ®)) { + PRINT_ER("Failed read misc reg\n"); + return 0; + } + + reg &= ~(1 << 8); + if (!sdio_write_reg(WILC_MISC, reg)) { + PRINT_ER("Failed write misc reg\n"); + return 0; + } + + /* + * interrupt pin mux select + */ + ret = sdio_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = sdio_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = sdio_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + reg |= (1 << 16); + ret = sdio_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + + return 1; +} +#else +static int sdio_sync(void) +{ + uint32_t reg; + + /* + * Disable power sequencer + */ + if (!sdio_read_reg(WILC_MISC, ®)) { + PRINT_ER("Failed read misc reg\n"); + return 0; + } + + reg &= ~(1 << 8); + if (!sdio_write_reg(WILC_MISC, reg)) { + PRINT_ER("Failed write misc reg\n"); + return 0; + } + + return 1; +} +#endif + +int sdio_init(struct wilc_wlan_inp *inp, wilc_debug_func func) +{ + struct sdio_cmd52_t cmd; + int loop; + uint32_t chipid; + if(inp != NULL) + { + memset(&g_sdio, 0, sizeof(struct wilc_sdio)); + + 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)) { + PRINT_ER("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; + } + /* + * 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)) { + PRINT_ER("Fail cmd 52, enable csa\n"); + goto _fail_; + } + + /* + * function 0 block size + */ + if (!sdio_set_func0_block_size(WILC_SDIO_BLOCK_SIZE)) { + PRINT_ER("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)) { + PRINT_ER("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)) { + PRINT_ER("Fail cmd 52, get IOR register\n"); + goto _fail_; + } + if (cmd.data == 0x2) + break; + } while (loop--); + + if (loop <= 0) { + PRINT_ER("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)) { + PRINT_ER("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)) { + PRINT_ER("Fail cmd 52, set IEN register\n"); + goto _fail_; + } + + /* + * make sure can read back chip id correctly + */ + if(inp != NULL) + { + if (!sdio_read_reg(0x3b0000, &chipid)) { + PRINT_ER("Fail cmd read chip id\n"); + goto _fail_; + } + + PRINT_D(BUS_DBG, "chipid %08x\n", chipid); + g_sdio.has_thrpt_enh3 = 1; + PRINT_D(BUS_DBG, "has_thrpt_enh3 = %d\n", g_sdio.has_thrpt_enh3); + } + int_clrd = 0; + + g_sdio.sdio_set_max_speed(); + + return 1; +_fail_: + return 0; +} + +static int sdio_read_size(uint32_t *size) +{ + uint32_t tmp; + struct 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.address = 0xf3; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + tmp |= (cmd.data << 8); + + *size = tmp; + + return 1; +} + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_read_int(uint32_t *int_status) +{ + uint32_t tmp = 0; + struct sdio_cmd52_t cmd; + uint32_t irq_flags; + + sdio_read_size(&tmp); + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xfe; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + irq_flags = cmd.data & 0x0f; + tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET); + + *int_status = tmp; + + return 1; +} +#else +static int sdio_read_int(uint32_t *int_status) +{ + uint32_t tmp = 0; + struct sdio_cmd52_t cmd; + int i; + + sdio_read_size(&tmp); + + cmd.function = 1; + cmd.address = 0x04; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + if (cmd.data & (1 << 0)) + tmp |= INT_0; + + if (cmd.data & (1 << 2)) + tmp |= INT_1; + + if (cmd.data & (1 << 3)) + tmp |= INT_2; + + if (cmd.data & (1 << 4)) + tmp |= INT_3; + + if (cmd.data & (1 << 5)) + tmp |= INT_4; + + if (cmd.data & (1 << 6)) + tmp |= INT_5; + + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { + if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) { + PRINT_ER("Unexpected int\n"); + break; + } + } + + *int_status = tmp; + + return 1; +} +#endif + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_clear_int_ext(uint32_t val) +{ + int ret; + + if (g_sdio.has_thrpt_enh3) { + uint32_t reg; + + reg = val & ((1 << MAX_NUN_INT_THRPT_ENH2) - 1); + if (reg) { + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xfe; + cmd.data = reg; + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + PRINT_ER("Failed cmd52\n"); + goto _fail_; + } + } + + reg = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + reg |= (1 << 0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + reg |= (1 << 1); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + reg |= (1 << 2); + if (reg) { + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf1; + cmd.data = reg; + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + PRINT_ER("Failed cmd52\n"); + goto _fail_; + } + } + } else { + /* + * see below. has_thrpt_enh2 uses register 0xf8 to clear + * interrupts. + * We Cannot clear multiple interrupts. + * we must clear each interrupt individually + */ + uint32_t flags; + uint32_t vmm_ctl; + + flags = val & ((1 << MAX_NUM_INT) - 1); + + if (flags) { + int i; + + ret = 1; + for (i = 0; i < g_sdio.nint; i++) { + if (flags & 1) { + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf8; + cmd.data = (1 << i); + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + PRINT_ER("Failed cmd52\n"); + goto _fail_; + } + } + + if (!ret) + break; + flags >>= 1; + } + if (!ret) + goto _fail_; + + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) + PRINT_ER("Unexpected int cleared\n"); + + flags >>= 1; + } + } + + vmm_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + vmm_ctl |= (1 << 0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + vmm_ctl |= (1 << 1); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + vmm_ctl |= (1 << 2); + + if (vmm_ctl) { + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf1; + cmd.data = vmm_ctl; + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + PRINT_ER("Failed cmd52\n"); + goto _fail_; + } + } + } + + return 1; +_fail_: + return 0; +} +#else +static int sdio_clear_int_ext(uint32_t val) +{ + int ret; + + if (g_sdio.has_thrpt_enh3) { + uint32_t reg = 0; + + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + reg |= (1 << 0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + reg |= (1 << 1); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + reg |= (1 << 2); + if (reg) { + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf1; + cmd.data = reg; + + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + PRINT_ER("Failed cmd52\n"); + goto _fail_; + } + } + } else { + uint32_t vmm_ctl = 0; + + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + vmm_ctl |= (1 << 0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + vmm_ctl |= (1 << 1); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + vmm_ctl |= (1 << 2); + + if (vmm_ctl) { + struct sdio_cmd52_t cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf1; + cmd.data = vmm_ctl; + ret = g_sdio.sdio_cmd52(&cmd); + if (!ret) { + PRINT_ER("Failed cmd52\n"); + goto _fail_; + } + } + } + + return 1; +_fail_: + return 0; +} +#endif + +#ifdef WILC_SDIO_IRQ_GPIO +static int sdio_sync_ext(int nint) +{ + uint32_t reg; + int ret, i; + + if (nint > MAX_NUM_INT) { + PRINT_ER("too many interupts %d\n", nint); + return 0; + } + if (nint > MAX_NUN_INT_THRPT_ENH2) { + PRINT_ER("not support more than 5 ints when has_thrpt_enh2=1\n"); + return 0; + } + + g_sdio.nint = nint; + + /* + * Disable power sequencer + */ + if (!sdio_read_reg(WILC_MISC, ®)) { + PRINT_ER("Failed read misc reg\n"); + return 0; + } + + reg &= ~(1 << 8); + if (!sdio_write_reg(WILC_MISC, reg)) { + PRINT_ER("Failed write misc reg\n"); + return 0; + } + + /* + * interrupt pin mux select + */ + ret = sdio_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = sdio_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + + /** + * interrupt enable + **/ + ret = sdio_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) + reg |= (1 << (27 + i)); + + ret = sdio_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + if (nint) { + ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_INTR2_ENABLE); + return 0; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) + reg |= (1 << i); + + ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_INTR2_ENABLE); + return 0; + } + } + + return 1; +} +#else +static int sdio_sync_ext(int nint) +{ + uint32_t reg; + + if (nint > MAX_NUM_INT) { + PRINT_ER("too many interupts %d\n", nint); + return 0; + } + if (nint > MAX_NUN_INT_THRPT_ENH2) { + PRINT_ER("not support more than 5 int when has_thrpt_enh2=1\n"); + return 0; + } + + g_sdio.nint = nint; + + /* + * Disable power sequencer + */ + if (!sdio_read_reg(WILC_MISC, ®)) { + PRINT_ER("Failed read misc reg\n"); + return 0; + } + + reg &= ~(1 << 8); + if (!sdio_write_reg(WILC_MISC, reg)) { + PRINT_ER("Failed write misc reg\n"); + return 0; + } + + return 1; +} +#endif + +/* + * Global sdio HIF function table + */ +struct wilc_hif_func 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, +}; +EXPORT_SYMBOL(hif_sdio); + diff --git a/wilc3000/wilc_spi.c b/wilc3000/wilc_spi.c index c57882b..ec73724 100644 --- a/wilc3000/wilc_spi.c +++ b/wilc3000/wilc_spi.c @@ -1,1346 +1,1346 @@ -/* - * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver - * - * Copyright (c) 2015 Atmel Corportation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "wilc_wlan_if.h" -#include "wilc_wlan.h" - -struct wilc_spi { - void *os_context; - int (*spi_tx)(uint8_t *, uint32_t); - int (*spi_rx)(uint8_t *, uint32_t); - int (*spi_trx)(uint8_t *, uint8_t *, uint32_t); - int crc_off; - int nint; - int has_thrpt_enh; -}; - -static struct wilc_spi g_spi; - -static int spi_read(uint32_t, uint8_t *, uint32_t); -static int spi_write(uint32_t, uint8_t *, uint32_t); - -/* - * Crc7 - */ -static const uint8_t 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 uint8_t crc7_byte(uint8_t crc, uint8_t data) -{ - return crc7_syndrome_table[(crc << 1) ^ data]; -} - -static uint8_t crc7(uint8_t crc, const uint8_t *buffer, uint32_t len) -{ - while (len--) - crc = crc7_byte(crc, *buffer++); - return crc; -} - -#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(uint8_t cmd, uint32_t adr, - uint32_t data, uint32_t sz, uint8_t clockless) -{ - uint8_t 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] = (uint8_t)(adr >> 16); - bc[2] = (uint8_t)(adr >> 8); - bc[3] = (uint8_t)adr; - len = 5; - break; - - case CMD_INTERNAL_READ: /* internal register read */ - bc[1] = (uint8_t)(adr >> 8); - if (clockless) - bc[1] |= (1 << 7); - bc[2] = (uint8_t)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] = (uint8_t)(adr >> 16); - bc[2] = (uint8_t)(adr >> 8); - bc[3] = (uint8_t)adr; - bc[4] = (uint8_t)(sz >> 8); - bc[5] = (uint8_t)(sz); - len = 7; - break; - - case CMD_DMA_EXT_WRITE: /* dma extended write */ - case CMD_DMA_EXT_READ: /* dma extended read */ - bc[1] = (uint8_t)(adr >> 16); - bc[2] = (uint8_t)(adr >> 8); - bc[3] = (uint8_t)adr; - bc[4] = (uint8_t)(sz >> 16); - bc[5] = (uint8_t)(sz >> 8); - bc[6] = (uint8_t)(sz); - len = 8; - break; - - case CMD_INTERNAL_WRITE:/* internal register write */ - bc[1] = (uint8_t)(adr >> 8); - if (clockless) - bc[1] |= (1 << 7); - bc[2] = (uint8_t)(adr); - bc[3] = (uint8_t)(data >> 24); - bc[4] = (uint8_t)(data >> 16); - bc[5] = (uint8_t)(data >> 8); - bc[6] = (uint8_t)(data); - len = 8; - break; - - case CMD_SINGLE_WRITE: /* single word write */ - bc[1] = (uint8_t)(adr >> 16); - bc[2] = (uint8_t)(adr >> 8); - bc[3] = (uint8_t)(adr); - bc[4] = (uint8_t)(data >> 24); - bc[5] = (uint8_t)(data >> 16); - bc[6] = (uint8_t)(data >> 8); - bc[7] = (uint8_t)(data); - len = 9; - break; - - default: - result = N_FAIL; - break; - } - - if (result) { - if (!g_spi.crc_off) - bc[len - 1] = (crc7(0x7f, &bc[0], len - 1)) << 1; - else - len -= 1; - - if (!g_spi.spi_tx(bc, len)) { - PRINT_ER("Failed cmd write, bus error\n"); - result = N_FAIL; - } - } - - return result; -} - -static int spi_cmd_rsp(uint8_t cmd) -{ - uint8_t 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("Failed cmd response read, bus error\n"); - result = N_FAIL; - goto _fail_; - } - - if (rsp != cmd) { - PRINT_ER("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("Failed cmd state read, bus error\n"); - result = N_FAIL; - goto _fail_; - } - - if (rsp != 0x00) { - PRINT_ER("Failed cmd state response state %02x\n", rsp); - result = N_FAIL; - } - -_fail_: - return result; -} - -static int spi_cmd_complete(uint8_t cmd, uint32_t adr, - uint8_t *b, uint32_t sz, uint8_t clockless) -{ - uint8_t wb[32], rb[32]; - uint8_t wix, rix; - uint32_t len2; - uint8_t rsp; - int len = 0; - int result = N_OK; - - wb[0] = cmd; - switch (cmd) { - case CMD_SINGLE_READ: /* single word (4 bytes) read */ - wb[1] = (uint8_t)(adr >> 16); - wb[2] = (uint8_t)(adr >> 8); - wb[3] = (uint8_t)adr; - len = 5; - break; - - case CMD_INTERNAL_READ: /* internal register read */ - wb[1] = (uint8_t)(adr >> 8); - if (clockless == 1) - wb[1] |= (1 << 7); - wb[2] = (uint8_t)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] = (uint8_t)(adr >> 16); - wb[2] = (uint8_t)(adr >> 8); - wb[3] = (uint8_t)adr; - wb[4] = (uint8_t)(sz >> 8); - wb[5] = (uint8_t)(sz); - len = 7; - break; - - case CMD_DMA_EXT_WRITE: /* dma extended write */ - case CMD_DMA_EXT_READ: /* dma extended read */ - wb[1] = (uint8_t)(adr >> 16); - wb[2] = (uint8_t)(adr >> 8); - wb[3] = (uint8_t)adr; - wb[4] = (uint8_t)(sz >> 16); - wb[5] = (uint8_t)(sz >> 8); - wb[6] = (uint8_t)(sz); - len = 8; - break; - - case CMD_INTERNAL_WRITE: /* internal register write */ - wb[1] = (uint8_t)(adr >> 8); - if (clockless == 1) - wb[1] |= (1 << 7); - wb[2] = (uint8_t)(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] = (uint8_t)(adr >> 16); - wb[2] = (uint8_t)(adr >> 8); - wb[3] = (uint8_t)(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, &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("spi buf size too small %d,%d\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("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 */ - - rsp = rb[rix++]; - - if (rsp != cmd) { - PRINT_ER("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("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; - uint8_t 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("Err, data read resp %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("buf 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("buf 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("data read error\n"); - result = N_FAIL; - goto _error_; - } - - /* - * Read Crc - */ - if (!g_spi.crc_off) { - if (!g_spi.spi_rx(crc, 2)) { - PRINT_ER("crc read err\n"); - result = N_FAIL; - goto _error_; - } - } - - ix += nbytes; - sz -= nbytes; - } - - /* - * if any data is 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. - */ - retry = 10; - do { - if (!g_spi.spi_rx(&rsp, 1)) { - PRINT_ER("resp rx 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("data rx error\n"); - result = N_FAIL; - break; - } - - /* - * Read Crc - */ - if (!g_spi.crc_off) { - if (!g_spi.spi_rx(crc, 2)) { - PRINT_ER("crc rx error\n"); - result = N_FAIL; - break; - } - } - - ix += nbytes; - sz -= nbytes; - } - } - } - -_error_: - return result; -} - -static int spi_data_read(uint8_t *b, uint32_t sz) -{ - int retry, ix, nbytes; - int result = N_OK; - uint8_t crc[2]; - uint8_t 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("resp rx error\n"); - result = N_FAIL; - break; - } - if (((rsp >> 4) & 0xf) == 0xf) - break; - } while (retry--); - - if (result == N_FAIL) - break; - - if (retry <= 0) { - PRINT_ER("resp rx error (%02x)\n", rsp); - result = N_FAIL; - break; - } - - /* - * Read bytes - */ - if (!g_spi.spi_rx(&b[ix], nbytes)) { - PRINT_ER("data rx error\n"); - result = N_FAIL; - break; - } - - /* - * Read Crc - */ - if (!g_spi.crc_off) { - if (!g_spi.spi_rx(crc, 2)) { - PRINT_ER("crc rx error\n"); - result = N_FAIL; - break; - } - } - - ix += nbytes; - sz -= nbytes; - - } while (sz); - - return result; -} - -static int spi_data_write(uint8_t *b, uint32_t sz) -{ - int ix, nbytes; - int result = 1; - uint8_t cmd, order, crc[2] = {0}; - - /* - * 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("data block cmd write error\n"); - result = N_FAIL; - break; - } - - /* - * Write data - */ - if (!g_spi.spi_tx(&b[ix], nbytes)) { - PRINT_ER("data block write error\n"); - result = N_FAIL; - break; - } - - /* - * Write Crc - */ - if (!g_spi.crc_off) { - if (!g_spi.spi_tx(crc, 2)) { - PRINT_ER("crc write error\n"); - result = N_FAIL; - break; - } - } - - ix += nbytes; - sz -= nbytes; - } while (sz); - - return result; -} - -/* - * Spi Internal Read/Write Function - */ -static int spi_internal_write(uint32_t adr, uint32_t dat) -{ - int result; - -#if defined USE_OLD_SPI_SW - /* - * Command - */ - result = spi_cmd(CMD_INTERNAL_WRITE, adr, dat, 4, 0); - if (result != N_OK) { - PRINT_ER("Failed internal write cmd\n"); - return 0; - } - - result = spi_cmd_rsp(CMD_INTERNAL_WRITE, 0); - if (result != N_OK) - PRINT_ER("Failed internal write cmd response\n"); -#else -#ifdef BIG_ENDIAN - dat = BYTE_SWAP(dat); -#endif - result = spi_cmd_complete(CMD_INTERNAL_WRITE, adr, - (uint8_t *)&dat, 4, - 0); - if (result != N_OK) - PRINT_ER("Failed internal write cmd\n"); -#endif - return result; -} - -static int spi_internal_read(uint32_t adr, uint32_t *data) -{ - int result; - -#if defined USE_OLD_SPI_SW - result = spi_cmd(CMD_INTERNAL_READ, adr, 0, 4, 0); - if (result != N_OK) { - PRINT_ER("Failed internal read cmd\n"); - return 0; - } - - result = spi_cmd_rsp(CMD_INTERNAL_READ, 0); - if (result != N_OK) { - PRINT_ER("Failed internal read cmd response\n"); - return 0; - } - - /* - * Data - */ - result = spi_data_read((uint8_t *)data, 4); - if (result != N_OK) { - PRINT_ER("Failed internal read data\n"); - return 0; - } -#else - result = spi_cmd_complete(CMD_INTERNAL_READ, adr, - (uint8_t *)data, 4, - 0); - if (result != N_OK) { - PRINT_ER("Failed internal read cmd\n"); - return 0; - } -#endif -#ifdef BIG_ENDIAN - *data = BYTE_SWAP(*data); -#endif - return 1; -} - -/* - * Spi interfaces - */ -static int spi_write_reg(uint32_t addr, uint32_t data) -{ - int result = N_OK; - uint8_t cmd = CMD_SINGLE_WRITE; - uint8_t clockless = 0; - -#if defined USE_OLD_SPI_SW - result = spi_cmd(cmd, addr, data, 4, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd, write reg %08x\n", addr); - return 0; - } - - result = spi_cmd_rsp(cmd, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd resp, write reg %08x\n", addr); - return 0; - } - return 1; -#else -#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, (uint8_t *)&data, 4, clockless); - if (result != N_OK) - PRINT_ER("Failed cmd, write reg %08x\n", addr); - - return result; -#endif -} - -static int spi_write(uint32_t addr, uint8_t *buf, uint32_t size) -{ - int result; - uint8_t cmd = CMD_DMA_EXT_WRITE; - - /* - * has to be greated than 4 - */ - if (size <= 4) - return 0; - -#if defined USE_OLD_SPI_SW - /* - * Command - */ - result = spi_cmd(cmd, addr, 0, size, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd, write block %08x\n", addr); - return 0; - } - - result = spi_cmd_rsp(cmd, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd resp, write block %08x\n", addr); - return 0; - } -#else - result = spi_cmd_complete(cmd, addr, NULL, size, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd, write block %08x\n", addr); - return 0; - } -#endif - - /* - * Data - */ - result = spi_data_write(buf, size); - if (result != N_OK) - PRINT_ER("Failed block data write\n"); - - return 1; -} - -static int spi_read_reg(uint32_t addr, uint32_t *data) -{ - int result = N_OK; - uint8_t cmd = CMD_SINGLE_READ; - uint8_t clockless = 0; - -#if defined USE_OLD_SPI_SW - result = spi_cmd(cmd, addr, 0, 4, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd, read reg %08x\n", addr); - return 0; - } - result = spi_cmd_rsp(cmd, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd response, read reg %08x\n", addr); - return 0; - } - - result = spi_data_read((uint8_t *)data, 4); - if (result != N_OK) { - PRINT_ER("Failed data read\n"); - return 0; - } -#else - if (addr < 0x30) { - /* Clockless register */ - cmd = CMD_INTERNAL_READ; - clockless = 1; - } - - result = spi_cmd_complete(cmd, addr, (uint8_t *)data, 4, clockless); - if (result != N_OK) { - PRINT_ER("Failed cmd, read reg %08x\n", addr); - return 0; - } -#endif -#ifdef BIG_ENDIAN - *data = BYTE_SWAP(*data); -#endif - return 1; -} - -static int spi_read(uint32_t addr, uint8_t *buf, uint32_t size) -{ - uint8_t cmd = CMD_DMA_EXT_READ; - int result; - - if (size <= 4) - return 0; - -#if defined USE_OLD_SPI_SW - /* - * Command - */ - result = spi_cmd(cmd, addr, 0, size, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd, read block %08x\n", addr); - return 0; - } - - result = spi_cmd_rsp(cmd, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd response, read block %08x\n", addr); - return 0; - } - - /* - * Data - */ - result = spi_data_read(buf, size); - if (result != N_OK) { - PRINT_ER("Failed block data read\n"); - return 0; - } -#else - result = spi_cmd_complete(cmd, addr, buf, size, 0); - if (result != N_OK) { - PRINT_ER("Failed cmd, read block %08x\n", addr); - return 0; - } -#endif - return 1; -} - -/* - * Bus interfaces - */ -static int spi_clear_int(void) -{ - uint32_t reg; - - if (!spi_read_reg(WILC_HOST_RX_CTRL_0, ®)) { - PRINT_ER("Failed read reg %08x\n", WILC_HOST_RX_CTRL_0); - return 0; - } - - reg &= ~0x1; - spi_write_reg(WILC_HOST_RX_CTRL_0, reg); - int_clrd++; - - return 1; -} - -static int spi_deinit(void *pv) -{ - return 1; -} - -static int spi_sync(void) -{ - uint32_t reg; - int ret; - - /* - * interrupt pin mux select - */ - ret = spi_read_reg(WILC_PIN_MUX_0, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - reg |= (1 << 8); - ret = spi_write_reg(WILC_PIN_MUX_0, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - - /* - * interrupt enable - */ - ret = spi_read_reg(WILC_INTR_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - reg |= (1 << 16); - ret = spi_write_reg(WILC_INTR_ENABLE, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - - return 1; -} - -static int spi_init(struct wilc_wlan_inp *inp) -{ - uint32_t reg; - uint32_t chipid; - - static int isinit; - - if (isinit) { - if (!spi_read_reg(0x3b0000, &chipid)) { - PRINT_ER("Fail cmd read chip id\n"); - return 0; - } - return 1; - } - - memset(&g_spi, 0, sizeof(struct wilc_spi)); - - 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("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; - - /* - * 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("internal read err with CRC on,retyring with CRC off\n"); - if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, ®)) { - /* - * Read failed with both CRC on and off, - * something went bad - */ - PRINT_ER("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("Failed internal write reg\n"); - return 0; - } - g_spi.crc_off = 1; - } - - /* - * make sure can read back chip id correctly - */ - if (!spi_read_reg(0x3b0000, &chipid)) { - PRINT_ER("Fail cmd read chip id\n"); - return 0; - } - - g_spi.has_thrpt_enh = 1; - - isinit = 1; - int_clrd = 0; - - return 1; -} - -static int spi_read_size(uint32_t *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 { - uint32_t tmp; - uint32_t byte_cnt; - - ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); - - if (!ret) { - PRINT_ER("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(uint32_t *int_status) -{ - int ret; - int happended, unknown_mask, j; - - if (g_spi.has_thrpt_enh) { - ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, int_status); - } else { - uint32_t tmp; - uint32_t byte_cnt; - - ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); - - if (!ret) { - PRINT_ER("Failed read WILC_VMM_TO_HOST_SIZE\n"); - goto _fail_; - } - - tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; - - j = 0; - do { - uint32_t 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)); - } - - unknown_mask = ~((1ul << g_spi.nint) - 1); - if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) { - PRINT_ER("Unexpected int:j=%d, tmp=%x, mask=%x\n" - , j, tmp, unknown_mask); - happended = 1; - } - j++; - } while (happended); - - *int_status = tmp; - } -_fail_: - return ret; -} - -static int spi_clear_int_ext(uint32_t val) -{ - int ret; - uint32_t tbl_ctl; - - if (g_spi.has_thrpt_enh) { - ret = spi_internal_write(0xe844 - WILC_SPI_REG_BASE, val); - } else { - uint32_t flags; - - flags = val & ((1 << 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("Failed spi_write_reg\n"); - goto _fail_; - } - for (i = g_spi.nint; i < MAX_NUM_INT; i++) { - if (flags & 1) - PRINT_ER("Unexpected int cleared\n"); - flags >>= 1; - } - } - - tbl_ctl = 0; - /* select VMM table 0 */ - if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) - tbl_ctl |= (1 << 0); - /* select VMM table 1 */ - if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) - tbl_ctl |= (1 << 1); - - ret = spi_write_reg(WILC_VMM_TBL_CTL, tbl_ctl); - if (!ret) { - PRINT_ER("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("fail write reg vmm_core_ctl\n"); - goto _fail_; - } - } - } -_fail_: - return ret; -} - -static int spi_sync_ext(int nint) -{ - uint32_t reg; - int ret, i; - - if (nint > MAX_NUM_INT) { - PRINT_ER("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("Failed read reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - reg |= (1 << 8); - ret = spi_write_reg(WILC_PIN_MUX_0, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); - return 0; - } - - /* - * interrupt enable - */ - ret = spi_read_reg(WILC_INTR_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - - for (i = 0; (i < 5) && (nint > 0); i++, nint--) - reg |= (1 << (27 + i)); - - ret = spi_write_reg(WILC_INTR_ENABLE, reg); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); - return 0; - } - if (nint) { - ret = spi_read_reg(WILC_INTR2_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed read reg %08x\n", WILC_INTR2_ENABLE); - return 0; - } - - for (i = 0; (i < 3) && (nint > 0); i++, nint--) - reg |= (1 << i); - - ret = spi_read_reg(WILC_INTR2_ENABLE, ®); - if (!ret) { - PRINT_ER("Failed write reg %08x\n", WILC_INTR2_ENABLE); - return 0; - } - } - - return 1; -} - -/* - * Global spi HIF function table - */ -struct wilc_hif_func 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, -}; -EXPORT_SYMBOL(hif_spi); +/* + * Atmel WILC3000 802.11 b/g/n and Bluetooth Combo driver + * + * Copyright (c) 2015 Atmel Corportation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wilc_wlan_if.h" +#include "wilc_wlan.h" + +struct wilc_spi { + void *os_context; + int (*spi_tx)(uint8_t *, uint32_t); + int (*spi_rx)(uint8_t *, uint32_t); + int (*spi_trx)(uint8_t *, uint8_t *, uint32_t); + int crc_off; + int nint; + int has_thrpt_enh; +}; + +static struct wilc_spi g_spi; + +static int spi_read(uint32_t, uint8_t *, uint32_t); +static int spi_write(uint32_t, uint8_t *, uint32_t); + +/* + * Crc7 + */ +static const uint8_t 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 uint8_t crc7_byte(uint8_t crc, uint8_t data) +{ + return crc7_syndrome_table[(crc << 1) ^ data]; +} + +static uint8_t crc7(uint8_t crc, const uint8_t *buffer, uint32_t len) +{ + while (len--) + crc = crc7_byte(crc, *buffer++); + return crc; +} + +#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(uint8_t cmd, uint32_t adr, + uint32_t data, uint32_t sz, uint8_t clockless) +{ + uint8_t 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] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)adr; + len = 5; + break; + + case CMD_INTERNAL_READ: /* internal register read */ + bc[1] = (uint8_t)(adr >> 8); + if (clockless) + bc[1] |= (1 << 7); + bc[2] = (uint8_t)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] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)adr; + bc[4] = (uint8_t)(sz >> 8); + bc[5] = (uint8_t)(sz); + len = 7; + break; + + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + bc[1] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)adr; + bc[4] = (uint8_t)(sz >> 16); + bc[5] = (uint8_t)(sz >> 8); + bc[6] = (uint8_t)(sz); + len = 8; + break; + + case CMD_INTERNAL_WRITE:/* internal register write */ + bc[1] = (uint8_t)(adr >> 8); + if (clockless) + bc[1] |= (1 << 7); + bc[2] = (uint8_t)(adr); + bc[3] = (uint8_t)(data >> 24); + bc[4] = (uint8_t)(data >> 16); + bc[5] = (uint8_t)(data >> 8); + bc[6] = (uint8_t)(data); + len = 8; + break; + + case CMD_SINGLE_WRITE: /* single word write */ + bc[1] = (uint8_t)(adr >> 16); + bc[2] = (uint8_t)(adr >> 8); + bc[3] = (uint8_t)(adr); + bc[4] = (uint8_t)(data >> 24); + bc[5] = (uint8_t)(data >> 16); + bc[6] = (uint8_t)(data >> 8); + bc[7] = (uint8_t)(data); + len = 9; + break; + + default: + result = N_FAIL; + break; + } + + if (result) { + if (!g_spi.crc_off) + bc[len - 1] = (crc7(0x7f, &bc[0], len - 1)) << 1; + else + len -= 1; + + if (!g_spi.spi_tx(bc, len)) { + PRINT_ER("Failed cmd write, bus error\n"); + result = N_FAIL; + } + } + + return result; +} + +static int spi_cmd_rsp(uint8_t cmd) +{ + uint8_t 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("Failed cmd response read, bus error\n"); + result = N_FAIL; + goto _fail_; + } + + if (rsp != cmd) { + PRINT_ER("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("Failed cmd state read, bus error\n"); + result = N_FAIL; + goto _fail_; + } + + if (rsp != 0x00) { + PRINT_ER("Failed cmd state response state %02x\n", rsp); + result = N_FAIL; + } + +_fail_: + return result; +} + +static int spi_cmd_complete(uint8_t cmd, uint32_t adr, + uint8_t *b, uint32_t sz, uint8_t clockless) +{ + uint8_t wb[32], rb[32]; + uint8_t wix, rix; + uint32_t len2; + uint8_t rsp; + int len = 0; + int result = N_OK; + + wb[0] = cmd; + switch (cmd) { + case CMD_SINGLE_READ: /* single word (4 bytes) read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + len = 5; + break; + + case CMD_INTERNAL_READ: /* internal register read */ + wb[1] = (uint8_t)(adr >> 8); + if (clockless == 1) + wb[1] |= (1 << 7); + wb[2] = (uint8_t)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] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + wb[4] = (uint8_t)(sz >> 8); + wb[5] = (uint8_t)(sz); + len = 7; + break; + + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + wb[4] = (uint8_t)(sz >> 16); + wb[5] = (uint8_t)(sz >> 8); + wb[6] = (uint8_t)(sz); + len = 8; + break; + + case CMD_INTERNAL_WRITE: /* internal register write */ + wb[1] = (uint8_t)(adr >> 8); + if (clockless == 1) + wb[1] |= (1 << 7); + wb[2] = (uint8_t)(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] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)(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, &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("spi buf size too small %d,%d\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("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 */ + + rsp = rb[rix++]; + + if (rsp != cmd) { + PRINT_ER("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("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; + uint8_t 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("Err, data read resp %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("buf 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("buf 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("data read error\n"); + result = N_FAIL; + goto _error_; + } + + /* + * Read Crc + */ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("crc read err\n"); + result = N_FAIL; + goto _error_; + } + } + + ix += nbytes; + sz -= nbytes; + } + + /* + * if any data is 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. + */ + retry = 10; + do { + if (!g_spi.spi_rx(&rsp, 1)) { + PRINT_ER("resp rx 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("data rx error\n"); + result = N_FAIL; + break; + } + + /* + * Read Crc + */ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("crc rx error\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + } + } + } + +_error_: + return result; +} + +static int spi_data_read(uint8_t *b, uint32_t sz) +{ + int retry, ix, nbytes; + int result = N_OK; + uint8_t crc[2]; + uint8_t 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("resp rx error\n"); + result = N_FAIL; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (result == N_FAIL) + break; + + if (retry <= 0) { + PRINT_ER("resp rx error (%02x)\n", rsp); + result = N_FAIL; + break; + } + + /* + * Read bytes + */ + if (!g_spi.spi_rx(&b[ix], nbytes)) { + PRINT_ER("data rx error\n"); + result = N_FAIL; + break; + } + + /* + * Read Crc + */ + if (!g_spi.crc_off) { + if (!g_spi.spi_rx(crc, 2)) { + PRINT_ER("crc rx error\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + + } while (sz); + + return result; +} + +static int spi_data_write(uint8_t *b, uint32_t sz) +{ + int ix, nbytes; + int result = 1; + uint8_t cmd, order, crc[2] = {0}; + + /* + * 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("data block cmd write error\n"); + result = N_FAIL; + break; + } + + /* + * Write data + */ + if (!g_spi.spi_tx(&b[ix], nbytes)) { + PRINT_ER("data block write error\n"); + result = N_FAIL; + break; + } + + /* + * Write Crc + */ + if (!g_spi.crc_off) { + if (!g_spi.spi_tx(crc, 2)) { + PRINT_ER("crc write error\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + } while (sz); + + return result; +} + +/* + * Spi Internal Read/Write Function + */ +static int spi_internal_write(uint32_t adr, uint32_t dat) +{ + int result; + +#if defined USE_OLD_SPI_SW + /* + * Command + */ + result = spi_cmd(CMD_INTERNAL_WRITE, adr, dat, 4, 0); + if (result != N_OK) { + PRINT_ER("Failed internal write cmd\n"); + return 0; + } + + result = spi_cmd_rsp(CMD_INTERNAL_WRITE, 0); + if (result != N_OK) + PRINT_ER("Failed internal write cmd response\n"); +#else +#ifdef BIG_ENDIAN + dat = BYTE_SWAP(dat); +#endif + result = spi_cmd_complete(CMD_INTERNAL_WRITE, adr, + (uint8_t *)&dat, 4, + 0); + if (result != N_OK) + PRINT_ER("Failed internal write cmd\n"); +#endif + return result; +} + +static int spi_internal_read(uint32_t adr, uint32_t *data) +{ + int result; + +#if defined USE_OLD_SPI_SW + result = spi_cmd(CMD_INTERNAL_READ, adr, 0, 4, 0); + if (result != N_OK) { + PRINT_ER("Failed internal read cmd\n"); + return 0; + } + + result = spi_cmd_rsp(CMD_INTERNAL_READ, 0); + if (result != N_OK) { + PRINT_ER("Failed internal read cmd response\n"); + return 0; + } + + /* + * Data + */ + result = spi_data_read((uint8_t *)data, 4); + if (result != N_OK) { + PRINT_ER("Failed internal read data\n"); + return 0; + } +#else + result = spi_cmd_complete(CMD_INTERNAL_READ, adr, + (uint8_t *)data, 4, + 0); + if (result != N_OK) { + PRINT_ER("Failed internal read cmd\n"); + return 0; + } +#endif +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + return 1; +} + +/* + * Spi interfaces + */ +static int spi_write_reg(uint32_t addr, uint32_t data) +{ + int result = N_OK; + uint8_t cmd = CMD_SINGLE_WRITE; + uint8_t clockless = 0; + +#if defined USE_OLD_SPI_SW + result = spi_cmd(cmd, addr, data, 4, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd, write reg %08x\n", addr); + return 0; + } + + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd resp, write reg %08x\n", addr); + return 0; + } + return 1; +#else +#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, (uint8_t *)&data, 4, clockless); + if (result != N_OK) + PRINT_ER("Failed cmd, write reg %08x\n", addr); + + return result; +#endif +} + +static int spi_write(uint32_t addr, uint8_t *buf, uint32_t size) +{ + int result; + uint8_t cmd = CMD_DMA_EXT_WRITE; + + /* + * has to be greated than 4 + */ + if (size <= 4) + return 0; + +#if defined USE_OLD_SPI_SW + /* + * Command + */ + result = spi_cmd(cmd, addr, 0, size, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd, write block %08x\n", addr); + return 0; + } + + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd resp, write block %08x\n", addr); + return 0; + } +#else + result = spi_cmd_complete(cmd, addr, NULL, size, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd, write block %08x\n", addr); + return 0; + } +#endif + + /* + * Data + */ + result = spi_data_write(buf, size); + if (result != N_OK) + PRINT_ER("Failed block data write\n"); + + return 1; +} + +static int spi_read_reg(uint32_t addr, uint32_t *data) +{ + int result = N_OK; + uint8_t cmd = CMD_SINGLE_READ; + uint8_t clockless = 0; + +#if defined USE_OLD_SPI_SW + result = spi_cmd(cmd, addr, 0, 4, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd, read reg %08x\n", addr); + return 0; + } + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd response, read reg %08x\n", addr); + return 0; + } + + result = spi_data_read((uint8_t *)data, 4); + if (result != N_OK) { + PRINT_ER("Failed data read\n"); + return 0; + } +#else + if (addr < 0x30) { + /* Clockless register */ + cmd = CMD_INTERNAL_READ; + clockless = 1; + } + + result = spi_cmd_complete(cmd, addr, (uint8_t *)data, 4, clockless); + if (result != N_OK) { + PRINT_ER("Failed cmd, read reg %08x\n", addr); + return 0; + } +#endif +#ifdef BIG_ENDIAN + *data = BYTE_SWAP(*data); +#endif + return 1; +} + +static int spi_read(uint32_t addr, uint8_t *buf, uint32_t size) +{ + uint8_t cmd = CMD_DMA_EXT_READ; + int result; + + if (size <= 4) + return 0; + +#if defined USE_OLD_SPI_SW + /* + * Command + */ + result = spi_cmd(cmd, addr, 0, size, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd, read block %08x\n", addr); + return 0; + } + + result = spi_cmd_rsp(cmd, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd response, read block %08x\n", addr); + return 0; + } + + /* + * Data + */ + result = spi_data_read(buf, size); + if (result != N_OK) { + PRINT_ER("Failed block data read\n"); + return 0; + } +#else + result = spi_cmd_complete(cmd, addr, buf, size, 0); + if (result != N_OK) { + PRINT_ER("Failed cmd, read block %08x\n", addr); + return 0; + } +#endif + return 1; +} + +/* + * Bus interfaces + */ +static int spi_clear_int(void) +{ + uint32_t reg; + + if (!spi_read_reg(WILC_HOST_RX_CTRL_0, ®)) { + PRINT_ER("Failed read reg %08x\n", WILC_HOST_RX_CTRL_0); + return 0; + } + + reg &= ~0x1; + spi_write_reg(WILC_HOST_RX_CTRL_0, reg); + int_clrd++; + + return 1; +} + +static int spi_deinit(void *pv) +{ + return 1; +} + +static int spi_sync(void) +{ + uint32_t reg; + int ret; + + /* + * interrupt pin mux select + */ + ret = spi_read_reg(WILC_PIN_MUX_0, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = spi_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + + /* + * interrupt enable + */ + ret = spi_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + reg |= (1 << 16); + ret = spi_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + + return 1; +} + +static int spi_init(struct wilc_wlan_inp *inp) +{ + uint32_t reg; + uint32_t chipid; + + static int isinit; + + if (isinit) { + if (!spi_read_reg(0x3b0000, &chipid)) { + PRINT_ER("Fail cmd read chip id\n"); + return 0; + } + return 1; + } + + memset(&g_spi, 0, sizeof(struct wilc_spi)); + + 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("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; + + /* + * 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("internal read err with CRC on,retyring with CRC off\n"); + if (!spi_internal_read(WILC_SPI_PROTOCOL_OFFSET, ®)) { + /* + * Read failed with both CRC on and off, + * something went bad + */ + PRINT_ER("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("Failed internal write reg\n"); + return 0; + } + g_spi.crc_off = 1; + } + + /* + * make sure can read back chip id correctly + */ + if (!spi_read_reg(0x3b0000, &chipid)) { + PRINT_ER("Fail cmd read chip id\n"); + return 0; + } + + g_spi.has_thrpt_enh = 1; + + isinit = 1; + int_clrd = 0; + + return 1; +} + +static int spi_read_size(uint32_t *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 { + uint32_t tmp; + uint32_t byte_cnt; + + ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); + + if (!ret) { + PRINT_ER("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(uint32_t *int_status) +{ + int ret; + int happended, unknown_mask, j; + + if (g_spi.has_thrpt_enh) { + ret = spi_internal_read(0xe840 - WILC_SPI_REG_BASE, int_status); + } else { + uint32_t tmp; + uint32_t byte_cnt; + + ret = spi_read_reg(WILC_VMM_TO_HOST_SIZE, &byte_cnt); + + if (!ret) { + PRINT_ER("Failed read WILC_VMM_TO_HOST_SIZE\n"); + goto _fail_; + } + + tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; + + j = 0; + do { + uint32_t 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)); + } + + unknown_mask = ~((1ul << g_spi.nint) - 1); + if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) { + PRINT_ER("Unexpected int:j=%d, tmp=%x, mask=%x\n" + , j, tmp, unknown_mask); + happended = 1; + } + j++; + } while (happended); + + *int_status = tmp; + } +_fail_: + return ret; +} + +static int spi_clear_int_ext(uint32_t val) +{ + int ret; + uint32_t tbl_ctl; + + if (g_spi.has_thrpt_enh) { + ret = spi_internal_write(0xe844 - WILC_SPI_REG_BASE, val); + } else { + uint32_t flags; + + flags = val & ((1 << 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("Failed spi_write_reg\n"); + goto _fail_; + } + for (i = g_spi.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) + PRINT_ER("Unexpected int cleared\n"); + flags >>= 1; + } + } + + tbl_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + tbl_ctl |= (1 << 0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + tbl_ctl |= (1 << 1); + + ret = spi_write_reg(WILC_VMM_TBL_CTL, tbl_ctl); + if (!ret) { + PRINT_ER("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("fail write reg vmm_core_ctl\n"); + goto _fail_; + } + } + } +_fail_: + return ret; +} + +static int spi_sync_ext(int nint) +{ + uint32_t reg; + int ret, i; + + if (nint > MAX_NUM_INT) { + PRINT_ER("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("Failed read reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + reg |= (1 << 8); + ret = spi_write_reg(WILC_PIN_MUX_0, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_PIN_MUX_0); + return 0; + } + + /* + * interrupt enable + */ + ret = spi_read_reg(WILC_INTR_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) + reg |= (1 << (27 + i)); + + ret = spi_write_reg(WILC_INTR_ENABLE, reg); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_INTR_ENABLE); + return 0; + } + if (nint) { + ret = spi_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed read reg %08x\n", WILC_INTR2_ENABLE); + return 0; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) + reg |= (1 << i); + + ret = spi_read_reg(WILC_INTR2_ENABLE, ®); + if (!ret) { + PRINT_ER("Failed write reg %08x\n", WILC_INTR2_ENABLE); + return 0; + } + } + + return 1; +} + +/* + * Global spi HIF function table + */ +struct wilc_hif_func 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, +}; +EXPORT_SYMBOL(hif_spi);