2009-09-15 23:22:51

by Bing Zhao

[permalink] [raw]
Subject: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

From: Amitkumar Karwar <[email protected]>

Add timer based auto deep sleep feature in libertas driver which can be
configured through debugfs interface. This is tested on SD8688, SD8686 cards
with firmware versions 10.38.1.p25, 9.70.4.p0 respectively on 32-bit and 64-bit
platforms. Tests have been done for USB/CS cards to make sure that the patch
won't break USB/CS code. We didn't test the if_spi driver.

Signed-off-by: Amitkumar Karwar <[email protected]>
Signed-off-by: Bing Zhao <[email protected]>
---
drivers/net/wireless/libertas/README | 28 +++++-
drivers/net/wireless/libertas/cmd.c | 72 +++++++++++++-
drivers/net/wireless/libertas/cmdresp.c | 12 +++
drivers/net/wireless/libertas/debugfs.c | 160 +++++++++++++++++++++++++++++++
drivers/net/wireless/libertas/decl.h | 4 +
drivers/net/wireless/libertas/dev.h | 18 ++++
drivers/net/wireless/libertas/host.h | 1 +
drivers/net/wireless/libertas/if_cs.c | 3 +
drivers/net/wireless/libertas/if_sdio.c | 56 +++++++++++
drivers/net/wireless/libertas/if_sdio.h | 3 +-
drivers/net/wireless/libertas/if_spi.c | 3 +
drivers/net/wireless/libertas/if_usb.c | 3 +
drivers/net/wireless/libertas/main.c | 111 +++++++++++++++++++---
drivers/net/wireless/libertas/scan.c | 11 ++
drivers/net/wireless/libertas/wext.c | 138 ++++++++++++++++++++++++++
15 files changed, 604 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index ab6a2d5..059ce8c 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -1,5 +1,5 @@
================================================================================
- README for USB8388
+ README for Libertas

(c) Copyright © 2003-2006, Marvell International Ltd.
All Rights Reserved
@@ -226,4 +226,30 @@ setuserscan
All entries in the scan table (not just the new scan data when keep=1)
will be displayed upon completion by use of the getscantable ioctl.

+deepsleep
+
+ This command is used to configure the station in deep sleep mode/auto
+ deep sleep mode. Command expects two parameters:
+ 'state' 'idle time period'
+
+ The timer is implemented to monitor the activities (command, event,
+ data, etc.). When an activity is detected station will exit from deep
+ sleep mode automatically and restart the timer. At timer expiry (no
+ activity for defined time period) the deepsleep mode is entered
+ automatically.
+
+ Note: this command is for SDIO interface only.
+
+ Path: /sys/kernel/debug/libertas_wireless/ethX/
+
+ Usage:
+ To read the current status of deep sleep do:
+ cat deepsleep
+ To enable deep sleep mode do:
+ echo '1 0' > deepsleep
+ To enable auto deep sleep mode with idle time period 5 seconds do:
+ echo '1 5000' > deepsleep
+ To disable deep sleep/auto deep sleep mode do:
+ echo '0 0' > deepsleep
+
==============================================================================
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 6850981..3a3e894 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -17,7 +17,6 @@

static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);

-
/**
* @brief Simple callback that copies response back into command
*
@@ -319,6 +318,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
return 0;
}

+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (priv->is_deep_sleep) {
+ if (!wait_event_interruptible_timeout(priv->ds_awake_q,
+ !priv->is_deep_sleep, (10 * HZ))) {
+ lbs_pr_err("ds_awake_q: timer expired\n");
+ ret = -1;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (deep_sleep) {
+ if (priv->is_deep_sleep != 1) {
+ lbs_deb_cmd("deep sleep: sleep\n");
+ BUG_ON(!priv->enter_deep_sleep);
+ ret = priv->enter_deep_sleep(priv);
+ if (!ret) {
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+ }
+ } else {
+ lbs_pr_err("deep sleep: already enabled\n");
+ }
+ } else {
+ if (priv->is_deep_sleep) {
+ lbs_deb_cmd("deep sleep: wakeup\n");
+ BUG_ON(!priv->exit_deep_sleep);
+ ret = priv->exit_deep_sleep(priv);
+ if (!ret) {
+ ret = lbs_wait_for_ds_awake(priv);
+ if (ret)
+ lbs_pr_err("deep sleep: wakeup"
+ "failed\n");
+ }
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc)
{
@@ -1242,8 +1295,17 @@ static void lbs_submit_command(struct lbs_private *priv,
timeo = HZ/4;
}

- /* Setup the timer after transmit command */
- mod_timer(&priv->command_timer, jiffies + timeo);
+ if (command == CMD_802_11_DEEP_SLEEP) {
+ if (priv->is_auto_deep_sleep_enabled) {
+ priv->wakeup_dev_required = 1;
+ priv->dnld_sent = 0;
+ }
+ priv->is_deep_sleep = 1;
+ lbs_complete_command(priv, cmdnode, 0);
+ } else {
+ /* Setup the timer after transmit command */
+ mod_timer(&priv->command_timer, jiffies + timeo);
+ }

lbs_deb_leave(LBS_DEB_HOST);
}
@@ -1505,6 +1567,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
case CMD_802_11_BEACON_CTRL:
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
+ case CMD_802_11_DEEP_SLEEP:
+ cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
+ cmdptr->size = cpu_to_le16(S_DS_GEN);
+ break;
default:
lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index c42d3fa..47d2b19 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -504,9 +504,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)

case MACREG_INT_CODE_HOST_AWAKE:
lbs_deb_cmd("EVENT: host awake\n");
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ priv->is_deep_sleep = 0;
lbs_send_confirmwake(priv);
break;

+ case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
+ if (priv->reset_deep_sleep_wakeup)
+ priv->reset_deep_sleep_wakeup(priv);
+ lbs_deb_cmd("EVENT: ds awake\n");
+ priv->is_deep_sleep = 0;
+ priv->wakeup_dev_required = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ break;
+
case MACREG_INT_CODE_PS_AWAKE:
lbs_deb_cmd("EVENT: ps awake\n");
/* handle unexpected PS AWAKE event */
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 893a55c..624a438 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -117,6 +117,11 @@ static ssize_t lbs_sleepparams_write(struct file *file,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, user_buf, buf_size)) {
ret = -EFAULT;
@@ -157,6 +162,11 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
if (ret)
goto out_unlock;
@@ -173,6 +183,118 @@ out_unlock:
return ret;
}

+static ssize_t lbs_deepsleep_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct lbs_private *priv = file->private_data;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (!priv->enter_deep_sleep) {
+ lbs_pr_err("deep sleep feature is not implemented "
+ "for this interface driver\n");
+ ret = -EINVAL;
+ goto out_ds;
+ }
+
+ if (priv->is_auto_deep_sleep_enabled)
+ pos += snprintf(buf, len, "%d %d\n",
+ priv->is_auto_deep_sleep_enabled,
+ priv->auto_deep_sleep_timeout);
+ else if (priv->is_deep_sleep)
+ pos += snprintf(buf, len, "%d %d\n",
+ priv->is_deep_sleep,
+ priv->auto_deep_sleep_timeout);
+ else
+ pos += snprintf(buf, len, "%d %d\n",
+ priv->is_deep_sleep,
+ priv->auto_deep_sleep_timeout);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+out_ds:
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t lbs_deepsleep_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct lbs_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ int is_deep_sleep, auto_deep_sleep_timeout;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (!priv->enter_deep_sleep) {
+ lbs_pr_err("deep sleep feature is not implemented "
+ "for this interface driver\n");
+ res = -EINVAL;
+ goto out_ds;
+ }
+
+ if (priv->connect_status == LBS_CONNECTED) {
+ lbs_pr_err("can't use deep sleep cmd in connected "
+ "state\n");
+ res = -EINVAL;
+ goto out_ds;
+ }
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_ds;
+ }
+
+ res = sscanf(buf, "%d %d", &is_deep_sleep, &auto_deep_sleep_timeout);
+ if ((res != 2) || (!is_deep_sleep && auto_deep_sleep_timeout) ||
+ !((is_deep_sleep == 1) ||
+ (is_deep_sleep == 0))) {
+ lbs_pr_err("unknown option\n");
+ res = -EINVAL;
+ goto out_ds;
+ }
+
+ if (auto_deep_sleep_timeout) {
+ if (!priv->is_auto_deep_sleep_enabled) {
+ priv->is_activity_detected = 0;
+ priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
+ lbs_enter_auto_deep_sleep(priv);
+ } else {
+ priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
+ lbs_deb_debugfs("auto deep sleep: already enabled\n");
+ }
+ } else {
+ if (priv->is_auto_deep_sleep_enabled) {
+ lbs_exit_auto_deep_sleep(priv);
+ /* Try to exit deep sleep if auto deep sleep disabled */
+ res = lbs_set_deep_sleep(priv, 0);
+ if (res)
+ goto out_ds;
+ }
+ if ((is_deep_sleep == 0) || (is_deep_sleep == 1)) {
+ res = lbs_set_deep_sleep(priv, is_deep_sleep);
+ if (res)
+ goto out_ds;
+ }
+ }
+
+ res = count;
+
+out_ds:
+ free_page(addr);
+ return res;
+}
+
/*
* When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
* get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
@@ -223,6 +345,9 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
u8 freq;
int events = 0;

+ if (!lbs_is_cmd_allowed(priv))
+ return -EBUSY;
+
buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -275,6 +400,9 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
char *buf;
int ret;

+ if (!lbs_is_cmd_allowed(priv))
+ return -EBUSY;
+
buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -444,6 +572,11 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ free_page(addr);
+ return -EBUSY;
+ }
+
offval.offset = priv->mac_offset;
offval.value = 0;

@@ -496,6 +629,11 @@ static ssize_t lbs_wrmac_write(struct file *file,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ res = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
@@ -532,6 +670,11 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ free_page(addr);
+ return -EBUSY;
+ }
+
offval.offset = priv->bbp_offset;
offval.value = 0;

@@ -585,6 +728,11 @@ static ssize_t lbs_wrbbp_write(struct file *file,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ res = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
@@ -621,6 +769,11 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ free_page(addr);
+ return -EBUSY;
+ }
+
offval.offset = priv->rf_offset;
offval.value = 0;

@@ -674,6 +827,11 @@ static ssize_t lbs_wrrf_write(struct file *file,
if (!buf)
return -ENOMEM;

+ if (!lbs_is_cmd_allowed(priv)) {
+ res = -EBUSY;
+ goto out_unlock;
+ }
+
buf_size = min(count, len - 1);
if (copy_from_user(buf, userbuf, buf_size)) {
res = -EFAULT;
@@ -717,6 +875,8 @@ static const struct lbs_debugfs_files debugfs_files[] = {
write_file_dummy), },
{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
lbs_sleepparams_write), },
+ { "deepsleep", 0644, FOPS(lbs_deepsleep_read,
+ lbs_deepsleep_write), },
};

static const struct lbs_debugfs_files debugfs_events_files[] = {
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 0b84bdc..34b475f 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -33,6 +33,10 @@ int lbs_execute_next_command(struct lbs_private *priv);
int lbs_process_event(struct lbs_private *priv, u32 event);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+int lbs_is_cmd_allowed(struct lbs_private *priv);
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv);

u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 578c697..e2b4ef2 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -129,6 +129,20 @@ struct lbs_private {
u32 bbp_offset;
u32 rf_offset;

+ /** Deep sleep flag */
+ int is_deep_sleep;
+ /** Auto deep sleep enabled flag */
+ int is_auto_deep_sleep_enabled;
+ /** Device wakeup required flag */
+ int wakeup_dev_required;
+ /** Auto deep sleep flag*/
+ int is_activity_detected;
+ /** Auto deep sleep timeout (in miliseconds) */
+ int auto_deep_sleep_timeout;
+
+ /** Deep sleep wait queue */
+ wait_queue_head_t ds_awake_q;
+
/* Download sent:
bit0 1/0=data_sent/data_tx_done,
bit1 1/0=cmd_sent/cmd_tx_done,
@@ -154,6 +168,9 @@ struct lbs_private {
/** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
void (*reset_card) (struct lbs_private *priv);
+ int (*enter_deep_sleep) (struct lbs_private *priv);
+ int (*exit_deep_sleep) (struct lbs_private *priv);
+ int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);

/* Wake On LAN */
uint32_t wol_criteria;
@@ -204,6 +221,7 @@ struct lbs_private {

/** Timers */
struct timer_list command_timer;
+ struct timer_list auto_deepsleep_timer;
int nr_retries;
int cmd_timed_out;

diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index fe8f0cb..c055daa 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -57,6 +57,7 @@
#define CMD_802_11_ENABLE_RSN 0x002f
#define CMD_802_11_SET_AFC 0x003c
#define CMD_802_11_GET_AFC 0x003d
+#define CMD_802_11_DEEP_SLEEP 0x003e
#define CMD_802_11_AD_HOC_STOP 0x0040
#define CMD_802_11_HOST_SLEEP_CFG 0x0043
#define CMD_802_11_WAKEUP_CONFIRM 0x0044
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 6238176..465742f 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -946,6 +946,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_cs_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;

/* Now actually get the IRQ */
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 485a8d4..9716728 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -831,6 +831,58 @@ out:
return ret;
}

+static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
+{
+ int ret = -1;
+ struct cmd_header cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ lbs_deb_sdio("send DEEP_SLEEP command\n");
+ ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
+ lbs_cmd_copyback, (unsigned long) &cmd);
+ if (ret)
+ lbs_pr_err("DEEP_SLEEP cmd failed\n");
+
+ mdelay(200);
+ return ret;
+}
+
+static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+}
+
+static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
+{
+ struct if_sdio_card *card = priv->card;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+ sdio_claim_host(card->func);
+
+ sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
+ if (ret)
+ lbs_pr_err("sdio_writeb failed!\n");
+
+ sdio_release_host(card->func);
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+ return ret;
+
+}
+
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
@@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
* Ignore the define name, this really means the card has
* successfully received the command.
*/
+ card->priv->is_activity_detected = 1;
if (cause & IF_SDIO_H_INT_DNLD)
lbs_host_to_card_done(card->priv);

@@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func,

priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card;
+ priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
+ priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
+ priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;

priv->fw_ready = 1;

diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index 60c9b2f..12179c1 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -51,5 +51,6 @@
#define IF_SDIO_EVENT 0x80fc

#define IF_SDIO_BLOCK_SIZE 256
-
+#define CONFIGURATION_REG 0x03
+#define HOST_POWER_UP (0x1U << 1)
#endif
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 446e327..e2fa657 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
card->priv = priv;
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
priv->fw_ready = 1;

/* Initialize interrupt handling stuff. */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 92bc8c5..a8262de 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf,
cardp->priv->fw_ready = 1;

priv->hw_host_to_card = if_usb_host_to_card;
+ priv->enter_deep_sleep = NULL;
+ priv->exit_deep_sleep = NULL;
+ priv->reset_deep_sleep_wakeup = NULL;
#ifdef CONFIG_OLPC
if (machine_is_olpc())
priv->reset_card = if_usb_reset_olpc_card;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 8df1cfd..3b14fcc 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -574,8 +574,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
priv->dnld_sent = DNLD_RES_RECEIVED;

/* Wake main thread if commands are pending */
- if (!priv->cur_cmd || priv->tx_pending_len > 0)
- wake_up_interruptible(&priv->waitq);
+ if (!priv->cur_cmd || priv->tx_pending_len > 0) {
+ if (!priv->wakeup_dev_required)
+ wake_up_interruptible(&priv->waitq);
+ }

spin_unlock_irqrestore(&priv->driver_lock, flags);
lbs_deb_leave(LBS_DEB_THREAD);
@@ -770,7 +772,8 @@ static int lbs_thread(void *data)
shouldsleep = 0; /* We have a command response */
else if (priv->cur_cmd)
shouldsleep = 1; /* Can't send a command; one already running */
- else if (!list_empty(&priv->cmdpendingq))
+ else if (!list_empty(&priv->cmdpendingq) &&
+ !(priv->wakeup_dev_required))
shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
@@ -822,6 +825,26 @@ static int lbs_thread(void *data)
}
spin_unlock_irq(&priv->driver_lock);

+ /* Process hardware events, e.g. card removed, link lost */
+ spin_lock_irq(&priv->driver_lock);
+ while (__kfifo_len(priv->event_fifo)) {
+ u32 event;
+ __kfifo_get(priv->event_fifo, (unsigned char *) &event,
+ sizeof(event));
+ spin_unlock_irq(&priv->driver_lock);
+ lbs_process_event(priv, event);
+ spin_lock_irq(&priv->driver_lock);
+ }
+ spin_unlock_irq(&priv->driver_lock);
+
+ if (priv->wakeup_dev_required) {
+ lbs_deb_thread("Waking up device...\n");
+ /* Wake up device */
+ if (priv->exit_deep_sleep(priv))
+ lbs_deb_thread("Wakeup device failed\n");
+ continue;
+ }
+
/* command timeout stuff */
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
@@ -849,18 +872,7 @@ static int lbs_thread(void *data)
}
priv->cmd_timed_out = 0;

- /* Process hardware events, e.g. card removed, link lost */
- spin_lock_irq(&priv->driver_lock);
- while (__kfifo_len(priv->event_fifo)) {
- u32 event;

- __kfifo_get(priv->event_fifo, (unsigned char *) &event,
- sizeof(event));
- spin_unlock_irq(&priv->driver_lock);
- lbs_process_event(priv, event);
- spin_lock_irq(&priv->driver_lock);
- }
- spin_unlock_irq(&priv->driver_lock);

if (!priv->fw_ready)
continue;
@@ -894,6 +906,9 @@ static int lbs_thread(void *data)
(priv->psstate == PS_STATE_PRE_SLEEP))
continue;

+ if (priv->is_deep_sleep)
+ continue;
+
/* Execute the next command */
if (!priv->dnld_sent && !priv->cur_cmd)
lbs_execute_next_command(priv);
@@ -928,6 +943,7 @@ static int lbs_thread(void *data)
}

del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
wake_up_all(&priv->cmd_pending);

lbs_deb_leave(LBS_DEB_THREAD);
@@ -1050,6 +1066,60 @@ out:
lbs_deb_leave(LBS_DEB_CMD);
}

+/**
+ * This function put the device back to deep sleep mode when timer expires
+ * and no activity (command, event, data etc.) is detected.
+ */
+static void auto_deepsleep_timer_fn(unsigned long data)
+{
+ struct lbs_private *priv = (struct lbs_private *)data;
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ if (priv->is_activity_detected) {
+ priv->is_activity_detected = 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled &&
+ (!priv->wakeup_dev_required) &&
+ (priv->connect_status != LBS_CONNECTED)) {
+ lbs_deb_main("Entering auto deep sleep mode...\n");
+ ret = lbs_prepare_and_send_command(priv,
+ CMD_802_11_DEEP_SLEEP, 0,
+ 0, 0, NULL);
+ }
+ }
+ mod_timer(&priv->auto_deepsleep_timer , jiffies +
+ (priv->auto_deep_sleep_timeout * HZ)/1000);
+ lbs_deb_leave(LBS_DEB_CMD);
+}
+
+int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 1;
+ if (priv->is_deep_sleep)
+ priv->wakeup_dev_required = 1;
+ mod_timer(&priv->auto_deepsleep_timer ,
+ jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
+int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->auto_deep_sleep_timeout = 0;
+ del_timer(&priv->auto_deepsleep_timer);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+ return 0;
+}
+
static void lbs_sync_channel_worker(struct work_struct *work)
{
struct lbs_private *priv = container_of(work, struct lbs_private,
@@ -1099,11 +1169,17 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
+ priv->is_deep_sleep = 0;
+ priv->is_auto_deep_sleep_enabled = 0;
+ priv->wakeup_dev_required = 0;
+ init_waitqueue_head(&priv->ds_awake_q);

mutex_init(&priv->lock);

setup_timer(&priv->command_timer, command_timer_fn,
(unsigned long)priv);
+ setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
+ (unsigned long)priv);

INIT_LIST_HEAD(&priv->cmdfreeq);
INIT_LIST_HEAD(&priv->cmdpendingq);
@@ -1142,6 +1218,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
if (priv->event_fifo)
kfifo_free(priv->event_fifo);
del_timer(&priv->command_timer);
+ del_timer(&priv->auto_deepsleep_timer);
kfree(priv->networks);
priv->networks = NULL;

@@ -1272,6 +1349,11 @@ void lbs_remove_card(struct lbs_private *priv)
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);

+ if (priv->is_deep_sleep) {
+ priv->is_deep_sleep = 0;
+ wake_up_interruptible(&priv->ds_awake_q);
+ }
+
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);
@@ -1392,6 +1474,7 @@ void lbs_stop_card(struct lbs_private *priv)

/* Delete the timeout of the currently processing command */
del_timer_sync(&priv->command_timer);
+ del_timer_sync(&priv->auto_deepsleep_timer);

/* Flush pending command nodes */
spin_lock_irqsave(&priv->driver_lock, flags);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 6c95af3..e468e15 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -950,6 +950,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
@@ -1017,6 +1022,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ err = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
+ return err;
+ }
+
/* iwlist should wait until the current scan is finished */
if (priv->scan_channel)
return -EAGAIN;
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index be837a0..ef2b986 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -45,6 +45,31 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
priv->pending_assoc_req = NULL;
}

+/**
+ * @brief This function checks if the command is allowed.
+ *
+ * @param priv A pointer to lbs_private structure
+ * @return allowed or not allowed.
+ */
+
+int lbs_is_cmd_allowed(struct lbs_private *priv)
+{
+ int ret = 1;
+
+ lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (!priv->is_auto_deep_sleep_enabled) {
+ if (priv->is_deep_sleep) {
+ lbs_deb_wext("IOCTLS called when station"
+ "is in deep sleep\n");
+ ret = 0;
+ }
+ }
+
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return ret;
+}
+

/**
* @brief Find the channel frequency power info with specific channel
@@ -168,6 +193,11 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return -EBUSY;
+ }
+
cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
priv->curbssparams.channel);

@@ -278,6 +308,12 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (vwrq->disabled)
val = MRVDRV_RTS_MAX_VALUE;

@@ -299,6 +335,11 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
if (ret)
goto out;
@@ -321,6 +362,12 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (vwrq->disabled)
val = MRVDRV_FRAG_MAX_VALUE;

@@ -342,6 +389,11 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
if (ret)
goto out;
@@ -391,6 +443,11 @@ static int lbs_get_txpow(struct net_device *dev,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if (!priv->radio_on) {
lbs_deb_wext("tx power off\n");
vwrq->value = 0;
@@ -424,6 +481,11 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
return -EOPNOTSUPP;

@@ -472,6 +534,11 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
vwrq->disabled = 0;

if (vwrq->flags & IW_RETRY_LONG) {
@@ -712,6 +779,11 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return -EBUSY;
+ }
+
if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
if (vwrq->disabled)
return 0;
@@ -792,6 +864,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv))
+ return NULL;
+
priv->wstats.status = priv->mode;

/* If we're not associated, all quality values are meaningless */
@@ -892,6 +967,12 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1000,6 +1081,12 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
u8 rates[MAX_RATES + 1];

lbs_deb_enter(LBS_DEB_WEXT);
+
+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);

@@ -1058,6 +1145,11 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ lbs_deb_leave(LBS_DEB_WEXT);
+ return -EBUSY;
+ }
+
if (priv->connect_status == LBS_CONNECTED) {
vwrq->value = priv->cur_rate * 500000;

@@ -1084,6 +1176,11 @@ static int lbs_set_mode(struct net_device *dev,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if ( (*uwrq != IW_MODE_ADHOC)
&& (*uwrq != IW_MODE_INFRA)
&& (*uwrq != IW_MODE_AUTO)) {
@@ -1325,6 +1422,12 @@ static int lbs_set_encode(struct net_device *dev,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1508,6 +1611,12 @@ static int lbs_set_encodeext(struct net_device *dev,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1720,6 +1829,12 @@ static int lbs_set_auth(struct net_device *dev,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
mutex_lock(&priv->lock);
assoc_req = lbs_get_association_request(priv);
if (!assoc_req) {
@@ -1822,6 +1937,12 @@ static int lbs_get_auth(struct net_device *dev,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
switch (dwrq->flags & IW_AUTH_INDEX) {
case IW_AUTH_KEY_MGMT:
dwrq->value = priv->secinfo.key_mgmt;
@@ -1864,6 +1985,11 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
if (vwrq->disabled) {
lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
goto out;
@@ -1983,6 +2109,12 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (!priv->radio_on) {
ret = -EINVAL;
goto out;
@@ -2110,6 +2242,12 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,

lbs_deb_enter(LBS_DEB_WEXT);

+ if (!lbs_is_cmd_allowed(priv)) {
+ ret = -EBUSY;
+ lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+ return ret;
+ }
+
if (!priv->radio_on)
return -EINVAL;

--
1.5.4.3



2009-09-18 07:38:26

by Holger Schurig

[permalink] [raw]
Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

> I agree on this. Debugfs is for debug only and should stay
> that way. What do other driver in regard to this?

I see this now as an example where a Manufacturer (Marvell)
starts to work with the community, has a nice feature (probably
bacause of customer-request) and cannot get this into the kernel
because of this issue :-)


Debugfs isn't suitable for anything except debugging. It is, per
definition, an interface for developers that want to debug it.
The idea is that a kernel for end-user devices won't even have
debugfs compiled in.

If libertas currently does use debugfs for something !=
debugging? I don't know, but than that has been a lapse, an
oversight. Let's not do that oversight again.


So you can use

* iwpriv
* sysfs
* kernel module parameters
* nl80211/cfg80211
* Maybe the new "stable debugfs" proposed by Rostedt (see the
Article "A stable debugfs" on http://lwn.net/Articles/350463/,
but here it's not even clear that this will come).

For me, iwpriv seems the best candidate as long as libertas
doesn't have a cfg80211/nl80211 interface.



> I hardly belive that the libertas driver is the only "deep
> sleep" user.

I think that ATH6K WLAN devices might be candidates for this,
too. If the interface is "iwpriv XXX deepsleep 0" / "iwpriv XXX
deepsleep 1" I don't see a reason they could do it similar.


> iwconfig has an interface for this I think:
> |interface power {period N|timeout N|saving N|off}

That's something very differently.


--
http://www.holgerschurig.de

2009-09-16 20:26:12

by Bing Zhao

[permalink] [raw]
Subject: RE: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

Hi Andrey,

> -----Original Message-----
> From: Andrey Yurovsky [mailto:[email protected]]
> Sent: Tuesday, September 15, 2009 4:41 PM
> To: Bing Zhao
> Cc: [email protected]; [email protected]; Amitkumar Karwar; Dan Williams
> Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
>
> Hi Bing. This is not specific to the actual implementation of the
> deep sleep commands in your patch but,
>
> On Tue, Sep 15, 2009 at 4:45 PM, Bing Zhao <[email protected]> wrote:
> > + ? ? ? Path: /sys/kernel/debug/libertas_wireless/ethX/
>
> Is the sysfs interface really necessary? It seems like yet another
> non-standard configuration option to keep track of.

Actually the debugfs interface is used in the patch.

Some information (such as the interface name and path) in README file is out of date. We just copy-and-paste it for the new deepsleep command. We need a separate patch to clean up the REAME file and keep it up to date.

>
> Deep sleep seems to pretty much "turn off" the wifi card (as far as
> the user is concerned) so how about a simpler approach: enter deep
> sleep when the interface is brought down (ifconfig wlanN down) and
> exit deep sleep when it's brought up. Do this only when deep sleep is
> supported/possible. Alternately, maybe this belongs as an rfkill
> feature?

Entering/exiting deep sleep doesn't have to depend on wlanN interface's up and down. User can still put the chip into sleep when wlanN is up. And, with auto deep sleep feature, the driver automatically wakes the chip up for sending user commands (for example, scan) and put the chip back to sleep after certain time period of inactivity. The deepsleep command through debugfs interface provides the flexibility of deep sleep options.

The rfkill shuts down the RF transmitter of the device but most of other modules may be still functioning. The deep sleep shuts down most of the modules (including the RF) on the chip to save as much power as possible.


Regards,

Bing

>
> -Andrey

2009-09-29 07:24:16

by Holger Schurig

[permalink] [raw]
Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

> iwconfig wlan0 power period 0 -> enable deep sleep (enter
> deep sleep immediately)

> iwconfig wlan0 power period 5 -> enable auto deep sleep
> (enter deep sleep automatically after 5s idle time)

> iwconfig wlan0 power period -1 -> disable deep sleep / auto
> deep sleep

ACK from my side (not that I'm the maintainer ...)

--
http://www.holgerschurig.de

2009-09-29 07:04:12

by Holger Schurig

[permalink] [raw]
Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

Hi Bing !

Please note that I just sent an experimental patch to enable
cfg80211 for libertas.

Once this is polished, you can immediately start using
nl80211/cfg80211 to configure such things, there's no need to
have the full thingy (e.g. wpa_supplicant via -Dnl80211 working
with WEP/WPA/WPA2) working, those things are not interrelated.


--
http://www.holgerschurig.de

2009-09-18 17:36:34

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

On Fri, 2009-09-18 at 09:37 +0200, Holger Schurig wrote:
> > I agree on this. Debugfs is for debug only and should stay
> > that way. What do other driver in regard to this?
>
> I see this now as an example where a Manufacturer (Marvell)
> starts to work with the community, has a nice feature (probably
> bacause of customer-request) and cannot get this into the kernel
> because of this issue :-)

We've been over this for a long time actually. I'm the one that removed
all the private vendor ioctls in the first place back in 2006 from the
vendor driver. The reasons were known then, and are still the same.

But Bing probably wasn't involved then, and he doesn't need to bear the
brunt of that :) I'm very happy to be getting more active contributions
from Marvell and we should work this sort of thing out.

The major issue then was that iwpriv is a "quick fix" that is not
standardized and *is* kernel API that cannot/should not change. Thus,
unless it's well-designed and generic, it probably shouldn't even go in
in the first place.

We (Woodhouse, I, and Marcelo Tosatti) pushed back on Michail and
Marvell at the time and nobody (Michail in particular) was not willing
to spend the time to _do it right_ and help out with nl80211. Getting
attributes Marvell wanted into nl80211 would have been fine, and still
would be fine, but there's a process to follow and it will take longer
than a single iwpriv patch.

> Debugfs isn't suitable for anything except debugging. It is, per
> definition, an interface for developers that want to debug it.
> The idea is that a kernel for end-user devices won't even have
> debugfs compiled in.

Correct; that's the point: if we can't find a generic API to put this
into, it probably shouldn't go in, because the interface hasn't been
thought out well enough. Yes, that means a little more work, but it's
much more maintainable in the long run.

> If libertas currently does use debugfs for something !=
> debugging? I don't know, but than that has been a lapse, an
> oversight. Let's not do that oversight again.
>
>
> So you can use
>
> * iwpriv

No.

> * sysfs

No, it's basically the same thing as iwpriv just in a file. Slightly
better (since there's the rule of one-value-per-file) but not much.

> * kernel module parameters

No, because they usually cannot be changed at runtime.

> * nl80211/cfg80211

Yes.

> * Maybe the new "stable debugfs" proposed by Rostedt (see the
> Article "A stable debugfs" on http://lwn.net/Articles/350463/,
> but here it's not even clear that this will come).

No, if the value isn't for debugging.

> For me, iwpriv seems the best candidate as long as libertas
> doesn't have a cfg80211/nl80211 interface.

Then maybe we should convert it to cfg80211/nl80211. We should anyway.

>
>
> > I hardly belive that the libertas driver is the only "deep
> > sleep" user.
>
> I think that ATH6K WLAN devices might be candidates for this,
> too. If the interface is "iwpriv XXX deepsleep 0" / "iwpriv XXX
> deepsleep 1" I don't see a reason they could do it similar.

So if libertas isn't the only user, then we can make a more generic
interface for this that uses 'iw' and cfg80211.

Dan

>
> > iwconfig has an interface for this I think:
> > |interface power {period N|timeout N|saving N|off}
>
> That's something very differently.
>
>


2009-09-18 01:48:01

by Bing Zhao

[permalink] [raw]
Subject: RE: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

Hi Sebastian,

> -----Original Message-----
> From: Sebastian Andrzej Siewior [mailto:[email protected]]
> Sent: Thursday, September 17, 2009 9:12 AM
> To: Andrey Yurovsky
> Cc: Bing Zhao; Dan Williams; Amitkumar Karwar; [email protected]; libertas-
> [email protected]
> Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
>
> * Andrey Yurovsky | 2009-09-16 13:47:48 [-0700]:
>
> >> Some information (such as the interface name and path) in README file is out of date. We just
> copy-and-paste it for the new deepsleep command. We need a separate patch to clean up the REAME file
> and keep it up to date.
> >
> >Ok. Either way, this is another out-of-band interface (regardless of
> >if it's debugfs or sysfs). That said, I believe that debugfs should
> >be used for debugging, not for configuring driver/device features like
> >these.
> I agree on this. Debugfs is for debug only and should stay that way.
> What do other driver in regard to this? I hardly belive that the
> libertas driver is the only "deep sleep" user.

The debugfs interface has already been used for configuring some other parameters in libertas driver.
Choosing a different way for deep sleep configuration doesn't make sense to me.

>
> >>> Deep sleep seems to pretty much "turn off" the wifi card (as far as
> >>> the user is concerned) so how about a simpler approach: enter deep
> >>> sleep when the interface is brought down (ifconfig wlanN down) and
> >>> exit deep sleep when it's brought up. ?Do this only when deep sleep is
> >>> supported/possible. ?Alternately, maybe this belongs as an rfkill
> >>> feature?
> >>
> >> Entering/exiting deep sleep doesn't have to depend on wlanN interface's up and down. User can
> still put the chip into sleep when wlanN is up. And, with auto deep sleep feature, the driver
> automatically wakes the chip up for sending user commands (for example, scan) and put the chip back
> to sleep after certain time period of inactivity. The deepsleep command through debugfs interface
> provides the flexibility of deep sleep options.
> >>
> >> The rfkill shuts down the RF transmitter of the device but most of other modules may be still
> functioning. The deep sleep shuts down most of the modules (including the RF) on the chip to save as
> much power as possible.
> >
> >It seems that when the device is in deep sleep, it's effectively
> >"turned off" as far as the user is concerned. That seems really
> >similar to "ifconfig down" or rfkill, does the user really care about
> >anything beyond that? I understand that it's possible to control this
> >feature independently of either of those functions, but is it ever
> >necessary? If not, it would be great to just integrate it into one
> >(or both) of these already standard network interface semantics and
> >not introduce a whole new configuration parameter.
>
> iwconfig has an interface for this I think:
> |interface power {period N|timeout N|saving N|off}
>
> From what I see in the man page it covers pretty much what you wrote in
> the Readme file. So it looks like like there is your flexible interface
> you've been looking for :)

Unfortunately, the "iwconfig wlanN power" command is used for ieee power saving mode in the driver.

Regards,

Bing

>
> > -Andrey
> >
> >> Regards,
> >>
> >> Bing
>
> Sebastian

2009-09-16 20:47:44

by Andrey Yurovsky

[permalink] [raw]
Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

On Wed, Sep 16, 2009 at 1:20 PM, Bing Zhao <[email protected]> wrote:
> Hi Andrey,
>
>> -----Original Message-----
>> From: Andrey Yurovsky [mailto:[email protected]]
>> Sent: Tuesday, September 15, 2009 4:41 PM
>> To: Bing Zhao
>> Cc: [email protected]; [email protected]; Amitkumar Karwar; Dan Williams
>> Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
>>
>> Hi Bing. ?This is not specific to the actual implementation of the
>> deep sleep commands in your patch but,
>>
>> On Tue, Sep 15, 2009 at 4:45 PM, Bing Zhao <[email protected]> wrote:
>> > + ? ? ? Path: /sys/kernel/debug/libertas_wireless/ethX/
>>
>> Is the sysfs interface really necessary? ?It seems like yet another
>> non-standard configuration option to keep track of.
>
> Actually the debugfs interface is used in the patch.
>
> Some information (such as the interface name and path) in README file is out of date. We just copy-and-paste it for the new deepsleep command. We need a separate patch to clean up the REAME file and keep it up to date.

Ok. Either way, this is another out-of-band interface (regardless of
if it's debugfs or sysfs). That said, I believe that debugfs should
be used for debugging, not for configuring driver/device features like
these.

>> Deep sleep seems to pretty much "turn off" the wifi card (as far as
>> the user is concerned) so how about a simpler approach: enter deep
>> sleep when the interface is brought down (ifconfig wlanN down) and
>> exit deep sleep when it's brought up. ?Do this only when deep sleep is
>> supported/possible. ?Alternately, maybe this belongs as an rfkill
>> feature?
>
> Entering/exiting deep sleep doesn't have to depend on wlanN interface's up and down. User can still put the chip into sleep when wlanN is up. And, with auto deep sleep feature, the driver automatically wakes the chip up for sending user commands (for example, scan) and put the chip back to sleep after certain time period of inactivity. The deepsleep command through debugfs interface provides the flexibility of deep sleep options.
>
> The rfkill shuts down the RF transmitter of the device but most of other modules may be still functioning. The deep sleep shuts down most of the modules (including the RF) on the chip to save as much power as possible.

It seems that when the device is in deep sleep, it's effectively
"turned off" as far as the user is concerned. That seems really
similar to "ifconfig down" or rfkill, does the user really care about
anything beyond that? I understand that it's possible to control this
feature independently of either of those functions, but is it ever
necessary? If not, it would be great to just integrate it into one
(or both) of these already standard network interface semantics and
not introduce a whole new configuration parameter.

-Andrey

> Regards,
>
> Bing
>
>>
>> ? -Andrey
>

2009-09-29 18:38:58

by Bing Zhao

[permalink] [raw]
Subject: RE: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

Hi Holger,

> From: Holger Schurig [[email protected]]
> Sent: Tuesday, September 29, 2009 12:04 AM
> To: Bing Zhao
> Cc: Dan Williams; [email protected]; [email protected]; Amitkumar Karwar
> Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
>
> Hi Bing !
>
> Please note that I just sent an experimental patch to enable
> cfg80211 for libertas.
>
> Once this is polished, you can immediately start using
> nl80211/cfg80211 to configure such things, there's no need to
> have the full thingy (e.g. wpa_supplicant via -Dnl80211 working
> with WEP/WPA/WPA2) working, those things are not interrelated.

Thanks for the info.

I will start to use nl80211/cfg80211 to configure my parameters as soon as your patch is in libertas driver.

Best regards,

Bing

>
>
> --
> http://www.holgerschurig.de

Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

* Andrey Yurovsky | 2009-09-16 13:47:48 [-0700]:

>> Some information (such as the interface name and path) in README file is out of date. We just copy-and-paste it for the new deepsleep command. We need a separate patch to clean up the REAME file and keep it up to date.
>
>Ok. Either way, this is another out-of-band interface (regardless of
>if it's debugfs or sysfs). That said, I believe that debugfs should
>be used for debugging, not for configuring driver/device features like
>these.
I agree on this. Debugfs is for debug only and should stay that way.
What do other driver in regard to this? I hardly belive that the
libertas driver is the only "deep sleep" user.

>>> Deep sleep seems to pretty much "turn off" the wifi card (as far as
>>> the user is concerned) so how about a simpler approach: enter deep
>>> sleep when the interface is brought down (ifconfig wlanN down) and
>>> exit deep sleep when it's brought up. ?Do this only when deep sleep is
>>> supported/possible. ?Alternately, maybe this belongs as an rfkill
>>> feature?
>>
>> Entering/exiting deep sleep doesn't have to depend on wlanN interface's up and down. User can still put the chip into sleep when wlanN is up. And, with auto deep sleep feature, the driver automatically wakes the chip up for sending user commands (for example, scan) and put the chip back to sleep after certain time period of inactivity. The deepsleep command through debugfs interface provides the flexibility of deep sleep options.
>>
>> The rfkill shuts down the RF transmitter of the device but most of other modules may be still functioning. The deep sleep shuts down most of the modules (including the RF) on the chip to save as much power as possible.
>
>It seems that when the device is in deep sleep, it's effectively
>"turned off" as far as the user is concerned. That seems really
>similar to "ifconfig down" or rfkill, does the user really care about
>anything beyond that? I understand that it's possible to control this
>feature independently of either of those functions, but is it ever
>necessary? If not, it would be great to just integrate it into one
>(or both) of these already standard network interface semantics and
>not introduce a whole new configuration parameter.

iwconfig has an interface for this I think:
|interface power {period N|timeout N|saving N|off}

>From what I see in the man page it covers pretty much what you wrote in
the Readme file. So it looks like like there is your flexible interface
you've been looking for :)

> -Andrey
>
>> Regards,
>>
>> Bing

Sebastian

2009-09-15 23:47:24

by Andrey Yurovsky

[permalink] [raw]
Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

Hi Bing. This is not specific to the actual implementation of the
deep sleep commands in your patch but,

On Tue, Sep 15, 2009 at 4:45 PM, Bing Zhao <[email protected]> wrote:
> + ? ? ? Path: /sys/kernel/debug/libertas_wireless/ethX/

Is the sysfs interface really necessary? It seems like yet another
non-standard configuration option to keep track of.

Deep sleep seems to pretty much "turn off" the wifi card (as far as
the user is concerned) so how about a simpler approach: enter deep
sleep when the interface is brought down (ifconfig wlanN down) and
exit deep sleep when it's brought up. Do this only when deep sleep is
supported/possible. Alternately, maybe this belongs as an rfkill
feature?

-Andrey

2009-09-20 14:58:17

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

On Tue, 2009-09-15 at 16:45 -0700, Bing Zhao wrote:
> From: Amitkumar Karwar <[email protected]>
>
> Add timer based auto deep sleep feature in libertas driver which can be
> configured through debugfs interface. This is tested on SD8688, SD8686 cards
> with firmware versions 10.38.1.p25, 9.70.4.p0 respectively on 32-bit and 64-bit
> platforms. Tests have been done for USB/CS cards to make sure that the patch
> won't break USB/CS code. We didn't test the if_spi driver.

So there's always:

#define IW_POWER_SAVING 0x4000 /* Value is relative (how aggressive)*/

iwconfig wlan0 power saving 10

That seems quite a bit better than a new debugfs parameter, until we can
conver the driver over cfg80211 and do this properly. If the power
saving mode is higher than some number X, the chip gets put into deep
sleep mode, or it can be automatically placed in deep sleep mode by the
driver when there is no association like you have done with the timer
above. I think you should pick reasonable defaults, and perhaps if the
'saving' value is larger, the timer value in the driver gets smaller.

Does that sound like an OK approach? We really should be using debugfs
only for debugging stuff (obviously), and the real fix for this sort of
thing is to switch over to cfg80211 where we can actually extend the
configuration API instead of hacking it into debugfs/WEXT/etc.

Dan

> Signed-off-by: Amitkumar Karwar <[email protected]>
> Signed-off-by: Bing Zhao <[email protected]>
> ---
> drivers/net/wireless/libertas/README | 28 +++++-
> drivers/net/wireless/libertas/cmd.c | 72 +++++++++++++-
> drivers/net/wireless/libertas/cmdresp.c | 12 +++
> drivers/net/wireless/libertas/debugfs.c | 160 +++++++++++++++++++++++++++++++
> drivers/net/wireless/libertas/decl.h | 4 +
> drivers/net/wireless/libertas/dev.h | 18 ++++
> drivers/net/wireless/libertas/host.h | 1 +
> drivers/net/wireless/libertas/if_cs.c | 3 +
> drivers/net/wireless/libertas/if_sdio.c | 56 +++++++++++
> drivers/net/wireless/libertas/if_sdio.h | 3 +-
> drivers/net/wireless/libertas/if_spi.c | 3 +
> drivers/net/wireless/libertas/if_usb.c | 3 +
> drivers/net/wireless/libertas/main.c | 111 +++++++++++++++++++---
> drivers/net/wireless/libertas/scan.c | 11 ++
> drivers/net/wireless/libertas/wext.c | 138 ++++++++++++++++++++++++++
> 15 files changed, 604 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
> index ab6a2d5..059ce8c 100644
> --- a/drivers/net/wireless/libertas/README
> +++ b/drivers/net/wireless/libertas/README
> @@ -1,5 +1,5 @@
> ================================================================================
> - README for USB8388
> + README for Libertas
>
> (c) Copyright © 2003-2006, Marvell International Ltd.
> All Rights Reserved
> @@ -226,4 +226,30 @@ setuserscan
> All entries in the scan table (not just the new scan data when keep=1)
> will be displayed upon completion by use of the getscantable ioctl.
>
> +deepsleep
> +
> + This command is used to configure the station in deep sleep mode/auto
> + deep sleep mode. Command expects two parameters:
> + 'state' 'idle time period'
> +
> + The timer is implemented to monitor the activities (command, event,
> + data, etc.). When an activity is detected station will exit from deep
> + sleep mode automatically and restart the timer. At timer expiry (no
> + activity for defined time period) the deepsleep mode is entered
> + automatically.
> +
> + Note: this command is for SDIO interface only.
> +
> + Path: /sys/kernel/debug/libertas_wireless/ethX/
> +
> + Usage:
> + To read the current status of deep sleep do:
> + cat deepsleep
> + To enable deep sleep mode do:
> + echo '1 0' > deepsleep
> + To enable auto deep sleep mode with idle time period 5 seconds do:
> + echo '1 5000' > deepsleep
> + To disable deep sleep/auto deep sleep mode do:
> + echo '0 0' > deepsleep
> +
> ==============================================================================
> diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
> index 6850981..3a3e894 100644
> --- a/drivers/net/wireless/libertas/cmd.c
> +++ b/drivers/net/wireless/libertas/cmd.c
> @@ -17,7 +17,6 @@
>
> static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
>
> -
> /**
> * @brief Simple callback that copies response back into command
> *
> @@ -319,6 +318,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
> return 0;
> }
>
> +static int lbs_wait_for_ds_awake(struct lbs_private *priv)
> +{
> + int ret = 0;
> +
> + lbs_deb_enter(LBS_DEB_CMD);
> +
> + if (priv->is_deep_sleep) {
> + if (!wait_event_interruptible_timeout(priv->ds_awake_q,
> + !priv->is_deep_sleep, (10 * HZ))) {
> + lbs_pr_err("ds_awake_q: timer expired\n");
> + ret = -1;
> + }
> + }
> +
> + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
> + return ret;
> +}
> +
> +int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
> +{
> + int ret = 0;
> +
> + lbs_deb_enter(LBS_DEB_CMD);
> +
> + if (deep_sleep) {
> + if (priv->is_deep_sleep != 1) {
> + lbs_deb_cmd("deep sleep: sleep\n");
> + BUG_ON(!priv->enter_deep_sleep);
> + ret = priv->enter_deep_sleep(priv);
> + if (!ret) {
> + netif_stop_queue(priv->dev);
> + netif_carrier_off(priv->dev);
> + }
> + } else {
> + lbs_pr_err("deep sleep: already enabled\n");
> + }
> + } else {
> + if (priv->is_deep_sleep) {
> + lbs_deb_cmd("deep sleep: wakeup\n");
> + BUG_ON(!priv->exit_deep_sleep);
> + ret = priv->exit_deep_sleep(priv);
> + if (!ret) {
> + ret = lbs_wait_for_ds_awake(priv);
> + if (ret)
> + lbs_pr_err("deep sleep: wakeup"
> + "failed\n");
> + }
> + }
> + }
> +
> + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
> + return ret;
> +}
> +
> int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
> struct assoc_request *assoc)
> {
> @@ -1242,8 +1295,17 @@ static void lbs_submit_command(struct lbs_private *priv,
> timeo = HZ/4;
> }
>
> - /* Setup the timer after transmit command */
> - mod_timer(&priv->command_timer, jiffies + timeo);
> + if (command == CMD_802_11_DEEP_SLEEP) {
> + if (priv->is_auto_deep_sleep_enabled) {
> + priv->wakeup_dev_required = 1;
> + priv->dnld_sent = 0;
> + }
> + priv->is_deep_sleep = 1;
> + lbs_complete_command(priv, cmdnode, 0);
> + } else {
> + /* Setup the timer after transmit command */
> + mod_timer(&priv->command_timer, jiffies + timeo);
> + }
>
> lbs_deb_leave(LBS_DEB_HOST);
> }
> @@ -1505,6 +1567,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
> case CMD_802_11_BEACON_CTRL:
> ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
> break;
> + case CMD_802_11_DEEP_SLEEP:
> + cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
> + cmdptr->size = cpu_to_le16(S_DS_GEN);
> + break;
> default:
> lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
> ret = -1;
> diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
> index c42d3fa..47d2b19 100644
> --- a/drivers/net/wireless/libertas/cmdresp.c
> +++ b/drivers/net/wireless/libertas/cmdresp.c
> @@ -504,9 +504,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
>
> case MACREG_INT_CODE_HOST_AWAKE:
> lbs_deb_cmd("EVENT: host awake\n");
> + if (priv->reset_deep_sleep_wakeup)
> + priv->reset_deep_sleep_wakeup(priv);
> + priv->is_deep_sleep = 0;
> lbs_send_confirmwake(priv);
> break;
>
> + case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
> + if (priv->reset_deep_sleep_wakeup)
> + priv->reset_deep_sleep_wakeup(priv);
> + lbs_deb_cmd("EVENT: ds awake\n");
> + priv->is_deep_sleep = 0;
> + priv->wakeup_dev_required = 0;
> + wake_up_interruptible(&priv->ds_awake_q);
> + break;
> +
> case MACREG_INT_CODE_PS_AWAKE:
> lbs_deb_cmd("EVENT: ps awake\n");
> /* handle unexpected PS AWAKE event */
> diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
> index 893a55c..624a438 100644
> --- a/drivers/net/wireless/libertas/debugfs.c
> +++ b/drivers/net/wireless/libertas/debugfs.c
> @@ -117,6 +117,11 @@ static ssize_t lbs_sleepparams_write(struct file *file,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out_unlock;
> + }
> +
> buf_size = min(count, len - 1);
> if (copy_from_user(buf, user_buf, buf_size)) {
> ret = -EFAULT;
> @@ -157,6 +162,11 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out_unlock;
> + }
> +
> ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
> if (ret)
> goto out_unlock;
> @@ -173,6 +183,118 @@ out_unlock:
> return ret;
> }
>
> +static ssize_t lbs_deepsleep_read(struct file *file, char __user *userbuf,
> + size_t count, loff_t *ppos)
> +{
> + struct lbs_private *priv = file->private_data;
> + ssize_t pos = 0;
> + int ret;
> + unsigned long addr = get_zeroed_page(GFP_KERNEL);
> + char *buf = (char *)addr;
> +
> + if (!buf)
> + return -ENOMEM;
> +
> + if (!priv->enter_deep_sleep) {
> + lbs_pr_err("deep sleep feature is not implemented "
> + "for this interface driver\n");
> + ret = -EINVAL;
> + goto out_ds;
> + }
> +
> + if (priv->is_auto_deep_sleep_enabled)
> + pos += snprintf(buf, len, "%d %d\n",
> + priv->is_auto_deep_sleep_enabled,
> + priv->auto_deep_sleep_timeout);
> + else if (priv->is_deep_sleep)
> + pos += snprintf(buf, len, "%d %d\n",
> + priv->is_deep_sleep,
> + priv->auto_deep_sleep_timeout);
> + else
> + pos += snprintf(buf, len, "%d %d\n",
> + priv->is_deep_sleep,
> + priv->auto_deep_sleep_timeout);
> +
> + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> +
> +out_ds:
> + free_page(addr);
> + return ret;
> +}
> +
> +static ssize_t lbs_deepsleep_write(struct file *file,
> + const char __user *userbuf,
> + size_t count, loff_t *ppos)
> +{
> + struct lbs_private *priv = file->private_data;
> + ssize_t res, buf_size;
> + int is_deep_sleep, auto_deep_sleep_timeout;
> + unsigned long addr = get_zeroed_page(GFP_KERNEL);
> + char *buf = (char *)addr;
> +
> + if (!buf)
> + return -ENOMEM;
> +
> + if (!priv->enter_deep_sleep) {
> + lbs_pr_err("deep sleep feature is not implemented "
> + "for this interface driver\n");
> + res = -EINVAL;
> + goto out_ds;
> + }
> +
> + if (priv->connect_status == LBS_CONNECTED) {
> + lbs_pr_err("can't use deep sleep cmd in connected "
> + "state\n");
> + res = -EINVAL;
> + goto out_ds;
> + }
> +
> + buf_size = min(count, len - 1);
> + if (copy_from_user(buf, userbuf, buf_size)) {
> + res = -EFAULT;
> + goto out_ds;
> + }
> +
> + res = sscanf(buf, "%d %d", &is_deep_sleep, &auto_deep_sleep_timeout);
> + if ((res != 2) || (!is_deep_sleep && auto_deep_sleep_timeout) ||
> + !((is_deep_sleep == 1) ||
> + (is_deep_sleep == 0))) {
> + lbs_pr_err("unknown option\n");
> + res = -EINVAL;
> + goto out_ds;
> + }
> +
> + if (auto_deep_sleep_timeout) {
> + if (!priv->is_auto_deep_sleep_enabled) {
> + priv->is_activity_detected = 0;
> + priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
> + lbs_enter_auto_deep_sleep(priv);
> + } else {
> + priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
> + lbs_deb_debugfs("auto deep sleep: already enabled\n");
> + }
> + } else {
> + if (priv->is_auto_deep_sleep_enabled) {
> + lbs_exit_auto_deep_sleep(priv);
> + /* Try to exit deep sleep if auto deep sleep disabled */
> + res = lbs_set_deep_sleep(priv, 0);
> + if (res)
> + goto out_ds;
> + }
> + if ((is_deep_sleep == 0) || (is_deep_sleep == 1)) {
> + res = lbs_set_deep_sleep(priv, is_deep_sleep);
> + if (res)
> + goto out_ds;
> + }
> + }
> +
> + res = count;
> +
> +out_ds:
> + free_page(addr);
> + return res;
> +}
> +
> /*
> * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
> * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
> @@ -223,6 +345,9 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
> u8 freq;
> int events = 0;
>
> + if (!lbs_is_cmd_allowed(priv))
> + return -EBUSY;
> +
> buf = (char *)get_zeroed_page(GFP_KERNEL);
> if (!buf)
> return -ENOMEM;
> @@ -275,6 +400,9 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
> char *buf;
> int ret;
>
> + if (!lbs_is_cmd_allowed(priv))
> + return -EBUSY;
> +
> buf = (char *)get_zeroed_page(GFP_KERNEL);
> if (!buf)
> return -ENOMEM;
> @@ -444,6 +572,11 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + free_page(addr);
> + return -EBUSY;
> + }
> +
> offval.offset = priv->mac_offset;
> offval.value = 0;
>
> @@ -496,6 +629,11 @@ static ssize_t lbs_wrmac_write(struct file *file,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + res = -EBUSY;
> + goto out_unlock;
> + }
> +
> buf_size = min(count, len - 1);
> if (copy_from_user(buf, userbuf, buf_size)) {
> res = -EFAULT;
> @@ -532,6 +670,11 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + free_page(addr);
> + return -EBUSY;
> + }
> +
> offval.offset = priv->bbp_offset;
> offval.value = 0;
>
> @@ -585,6 +728,11 @@ static ssize_t lbs_wrbbp_write(struct file *file,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + res = -EBUSY;
> + goto out_unlock;
> + }
> +
> buf_size = min(count, len - 1);
> if (copy_from_user(buf, userbuf, buf_size)) {
> res = -EFAULT;
> @@ -621,6 +769,11 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + free_page(addr);
> + return -EBUSY;
> + }
> +
> offval.offset = priv->rf_offset;
> offval.value = 0;
>
> @@ -674,6 +827,11 @@ static ssize_t lbs_wrrf_write(struct file *file,
> if (!buf)
> return -ENOMEM;
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + res = -EBUSY;
> + goto out_unlock;
> + }
> +
> buf_size = min(count, len - 1);
> if (copy_from_user(buf, userbuf, buf_size)) {
> res = -EFAULT;
> @@ -717,6 +875,8 @@ static const struct lbs_debugfs_files debugfs_files[] = {
> write_file_dummy), },
> { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
> lbs_sleepparams_write), },
> + { "deepsleep", 0644, FOPS(lbs_deepsleep_read,
> + lbs_deepsleep_write), },
> };
>
> static const struct lbs_debugfs_files debugfs_events_files[] = {
> diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
> index 0b84bdc..34b475f 100644
> --- a/drivers/net/wireless/libertas/decl.h
> +++ b/drivers/net/wireless/libertas/decl.h
> @@ -33,6 +33,10 @@ int lbs_execute_next_command(struct lbs_private *priv);
> int lbs_process_event(struct lbs_private *priv, u32 event);
> void lbs_queue_event(struct lbs_private *priv, u32 event);
> void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
> +int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
> +int lbs_is_cmd_allowed(struct lbs_private *priv);
> +int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
> +int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
>
> u32 lbs_fw_index_to_data_rate(u8 index);
> u8 lbs_data_rate_to_fw_index(u32 rate);
> diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
> index 578c697..e2b4ef2 100644
> --- a/drivers/net/wireless/libertas/dev.h
> +++ b/drivers/net/wireless/libertas/dev.h
> @@ -129,6 +129,20 @@ struct lbs_private {
> u32 bbp_offset;
> u32 rf_offset;
>
> + /** Deep sleep flag */
> + int is_deep_sleep;
> + /** Auto deep sleep enabled flag */
> + int is_auto_deep_sleep_enabled;
> + /** Device wakeup required flag */
> + int wakeup_dev_required;
> + /** Auto deep sleep flag*/
> + int is_activity_detected;
> + /** Auto deep sleep timeout (in miliseconds) */
> + int auto_deep_sleep_timeout;
> +
> + /** Deep sleep wait queue */
> + wait_queue_head_t ds_awake_q;
> +
> /* Download sent:
> bit0 1/0=data_sent/data_tx_done,
> bit1 1/0=cmd_sent/cmd_tx_done,
> @@ -154,6 +168,9 @@ struct lbs_private {
> /** Hardware access */
> int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
> void (*reset_card) (struct lbs_private *priv);
> + int (*enter_deep_sleep) (struct lbs_private *priv);
> + int (*exit_deep_sleep) (struct lbs_private *priv);
> + int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
>
> /* Wake On LAN */
> uint32_t wol_criteria;
> @@ -204,6 +221,7 @@ struct lbs_private {
>
> /** Timers */
> struct timer_list command_timer;
> + struct timer_list auto_deepsleep_timer;
> int nr_retries;
> int cmd_timed_out;
>
> diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
> index fe8f0cb..c055daa 100644
> --- a/drivers/net/wireless/libertas/host.h
> +++ b/drivers/net/wireless/libertas/host.h
> @@ -57,6 +57,7 @@
> #define CMD_802_11_ENABLE_RSN 0x002f
> #define CMD_802_11_SET_AFC 0x003c
> #define CMD_802_11_GET_AFC 0x003d
> +#define CMD_802_11_DEEP_SLEEP 0x003e
> #define CMD_802_11_AD_HOC_STOP 0x0040
> #define CMD_802_11_HOST_SLEEP_CFG 0x0043
> #define CMD_802_11_WAKEUP_CONFIRM 0x0044
> diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
> index 6238176..465742f 100644
> --- a/drivers/net/wireless/libertas/if_cs.c
> +++ b/drivers/net/wireless/libertas/if_cs.c
> @@ -946,6 +946,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
> card->priv = priv;
> priv->card = card;
> priv->hw_host_to_card = if_cs_host_to_card;
> + priv->enter_deep_sleep = NULL;
> + priv->exit_deep_sleep = NULL;
> + priv->reset_deep_sleep_wakeup = NULL;
> priv->fw_ready = 1;
>
> /* Now actually get the IRQ */
> diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
> index 485a8d4..9716728 100644
> --- a/drivers/net/wireless/libertas/if_sdio.c
> +++ b/drivers/net/wireless/libertas/if_sdio.c
> @@ -831,6 +831,58 @@ out:
> return ret;
> }
>
> +static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
> +{
> + int ret = -1;
> + struct cmd_header cmd;
> +
> + memset(&cmd, 0, sizeof(cmd));
> +
> + lbs_deb_sdio("send DEEP_SLEEP command\n");
> + ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
> + lbs_cmd_copyback, (unsigned long) &cmd);
> + if (ret)
> + lbs_pr_err("DEEP_SLEEP cmd failed\n");
> +
> + mdelay(200);
> + return ret;
> +}
> +
> +static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
> +{
> + struct if_sdio_card *card = priv->card;
> + int ret = -1;
> +
> + lbs_deb_enter(LBS_DEB_SDIO);
> + sdio_claim_host(card->func);
> +
> + sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
> + if (ret)
> + lbs_pr_err("sdio_writeb failed!\n");
> +
> + sdio_release_host(card->func);
> + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
> + return ret;
> +}
> +
> +static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
> +{
> + struct if_sdio_card *card = priv->card;
> + int ret = -1;
> +
> + lbs_deb_enter(LBS_DEB_SDIO);
> + sdio_claim_host(card->func);
> +
> + sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
> + if (ret)
> + lbs_pr_err("sdio_writeb failed!\n");
> +
> + sdio_release_host(card->func);
> + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
> + return ret;
> +
> +}
> +
> /*******************************************************************/
> /* SDIO callbacks */
> /*******************************************************************/
> @@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
> * Ignore the define name, this really means the card has
> * successfully received the command.
> */
> + card->priv->is_activity_detected = 1;
> if (cause & IF_SDIO_H_INT_DNLD)
> lbs_host_to_card_done(card->priv);
>
> @@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func,
>
> priv->card = card;
> priv->hw_host_to_card = if_sdio_host_to_card;
> + priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
> + priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
> + priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
>
> priv->fw_ready = 1;
>
> diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
> index 60c9b2f..12179c1 100644
> --- a/drivers/net/wireless/libertas/if_sdio.h
> +++ b/drivers/net/wireless/libertas/if_sdio.h
> @@ -51,5 +51,6 @@
> #define IF_SDIO_EVENT 0x80fc
>
> #define IF_SDIO_BLOCK_SIZE 256
> -
> +#define CONFIGURATION_REG 0x03
> +#define HOST_POWER_UP (0x1U << 1)
> #endif
> diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
> index 446e327..e2fa657 100644
> --- a/drivers/net/wireless/libertas/if_spi.c
> +++ b/drivers/net/wireless/libertas/if_spi.c
> @@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
> card->priv = priv;
> priv->card = card;
> priv->hw_host_to_card = if_spi_host_to_card;
> + priv->enter_deep_sleep = NULL;
> + priv->exit_deep_sleep = NULL;
> + priv->reset_deep_sleep_wakeup = NULL;
> priv->fw_ready = 1;
>
> /* Initialize interrupt handling stuff. */
> diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
> index 92bc8c5..a8262de 100644
> --- a/drivers/net/wireless/libertas/if_usb.c
> +++ b/drivers/net/wireless/libertas/if_usb.c
> @@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf,
> cardp->priv->fw_ready = 1;
>
> priv->hw_host_to_card = if_usb_host_to_card;
> + priv->enter_deep_sleep = NULL;
> + priv->exit_deep_sleep = NULL;
> + priv->reset_deep_sleep_wakeup = NULL;
> #ifdef CONFIG_OLPC
> if (machine_is_olpc())
> priv->reset_card = if_usb_reset_olpc_card;
> diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
> index 8df1cfd..3b14fcc 100644
> --- a/drivers/net/wireless/libertas/main.c
> +++ b/drivers/net/wireless/libertas/main.c
> @@ -574,8 +574,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
> priv->dnld_sent = DNLD_RES_RECEIVED;
>
> /* Wake main thread if commands are pending */
> - if (!priv->cur_cmd || priv->tx_pending_len > 0)
> - wake_up_interruptible(&priv->waitq);
> + if (!priv->cur_cmd || priv->tx_pending_len > 0) {
> + if (!priv->wakeup_dev_required)
> + wake_up_interruptible(&priv->waitq);
> + }
>
> spin_unlock_irqrestore(&priv->driver_lock, flags);
> lbs_deb_leave(LBS_DEB_THREAD);
> @@ -770,7 +772,8 @@ static int lbs_thread(void *data)
> shouldsleep = 0; /* We have a command response */
> else if (priv->cur_cmd)
> shouldsleep = 1; /* Can't send a command; one already running */
> - else if (!list_empty(&priv->cmdpendingq))
> + else if (!list_empty(&priv->cmdpendingq) &&
> + !(priv->wakeup_dev_required))
> shouldsleep = 0; /* We have a command to send */
> else if (__kfifo_len(priv->event_fifo))
> shouldsleep = 0; /* We have an event to process */
> @@ -822,6 +825,26 @@ static int lbs_thread(void *data)
> }
> spin_unlock_irq(&priv->driver_lock);
>
> + /* Process hardware events, e.g. card removed, link lost */
> + spin_lock_irq(&priv->driver_lock);
> + while (__kfifo_len(priv->event_fifo)) {
> + u32 event;
> + __kfifo_get(priv->event_fifo, (unsigned char *) &event,
> + sizeof(event));
> + spin_unlock_irq(&priv->driver_lock);
> + lbs_process_event(priv, event);
> + spin_lock_irq(&priv->driver_lock);
> + }
> + spin_unlock_irq(&priv->driver_lock);
> +
> + if (priv->wakeup_dev_required) {
> + lbs_deb_thread("Waking up device...\n");
> + /* Wake up device */
> + if (priv->exit_deep_sleep(priv))
> + lbs_deb_thread("Wakeup device failed\n");
> + continue;
> + }
> +
> /* command timeout stuff */
> if (priv->cmd_timed_out && priv->cur_cmd) {
> struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
> @@ -849,18 +872,7 @@ static int lbs_thread(void *data)
> }
> priv->cmd_timed_out = 0;
>
> - /* Process hardware events, e.g. card removed, link lost */
> - spin_lock_irq(&priv->driver_lock);
> - while (__kfifo_len(priv->event_fifo)) {
> - u32 event;
>
> - __kfifo_get(priv->event_fifo, (unsigned char *) &event,
> - sizeof(event));
> - spin_unlock_irq(&priv->driver_lock);
> - lbs_process_event(priv, event);
> - spin_lock_irq(&priv->driver_lock);
> - }
> - spin_unlock_irq(&priv->driver_lock);
>
> if (!priv->fw_ready)
> continue;
> @@ -894,6 +906,9 @@ static int lbs_thread(void *data)
> (priv->psstate == PS_STATE_PRE_SLEEP))
> continue;
>
> + if (priv->is_deep_sleep)
> + continue;
> +
> /* Execute the next command */
> if (!priv->dnld_sent && !priv->cur_cmd)
> lbs_execute_next_command(priv);
> @@ -928,6 +943,7 @@ static int lbs_thread(void *data)
> }
>
> del_timer(&priv->command_timer);
> + del_timer(&priv->auto_deepsleep_timer);
> wake_up_all(&priv->cmd_pending);
>
> lbs_deb_leave(LBS_DEB_THREAD);
> @@ -1050,6 +1066,60 @@ out:
> lbs_deb_leave(LBS_DEB_CMD);
> }
>
> +/**
> + * This function put the device back to deep sleep mode when timer expires
> + * and no activity (command, event, data etc.) is detected.
> + */
> +static void auto_deepsleep_timer_fn(unsigned long data)
> +{
> + struct lbs_private *priv = (struct lbs_private *)data;
> + int ret;
> +
> + lbs_deb_enter(LBS_DEB_CMD);
> +
> + if (priv->is_activity_detected) {
> + priv->is_activity_detected = 0;
> + } else {
> + if (priv->is_auto_deep_sleep_enabled &&
> + (!priv->wakeup_dev_required) &&
> + (priv->connect_status != LBS_CONNECTED)) {
> + lbs_deb_main("Entering auto deep sleep mode...\n");
> + ret = lbs_prepare_and_send_command(priv,
> + CMD_802_11_DEEP_SLEEP, 0,
> + 0, 0, NULL);
> + }
> + }
> + mod_timer(&priv->auto_deepsleep_timer , jiffies +
> + (priv->auto_deep_sleep_timeout * HZ)/1000);
> + lbs_deb_leave(LBS_DEB_CMD);
> +}
> +
> +int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
> +{
> + lbs_deb_enter(LBS_DEB_SDIO);
> +
> + priv->is_auto_deep_sleep_enabled = 1;
> + if (priv->is_deep_sleep)
> + priv->wakeup_dev_required = 1;
> + mod_timer(&priv->auto_deepsleep_timer ,
> + jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
> +
> + lbs_deb_leave(LBS_DEB_SDIO);
> + return 0;
> +}
> +
> +int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
> +{
> + lbs_deb_enter(LBS_DEB_SDIO);
> +
> + priv->is_auto_deep_sleep_enabled = 0;
> + priv->auto_deep_sleep_timeout = 0;
> + del_timer(&priv->auto_deepsleep_timer);
> +
> + lbs_deb_leave(LBS_DEB_SDIO);
> + return 0;
> +}
> +
> static void lbs_sync_channel_worker(struct work_struct *work)
> {
> struct lbs_private *priv = container_of(work, struct lbs_private,
> @@ -1099,11 +1169,17 @@ static int lbs_init_adapter(struct lbs_private *priv)
> priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
> priv->psmode = LBS802_11POWERMODECAM;
> priv->psstate = PS_STATE_FULL_POWER;
> + priv->is_deep_sleep = 0;
> + priv->is_auto_deep_sleep_enabled = 0;
> + priv->wakeup_dev_required = 0;
> + init_waitqueue_head(&priv->ds_awake_q);
>
> mutex_init(&priv->lock);
>
> setup_timer(&priv->command_timer, command_timer_fn,
> (unsigned long)priv);
> + setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
> + (unsigned long)priv);
>
> INIT_LIST_HEAD(&priv->cmdfreeq);
> INIT_LIST_HEAD(&priv->cmdpendingq);
> @@ -1142,6 +1218,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
> if (priv->event_fifo)
> kfifo_free(priv->event_fifo);
> del_timer(&priv->command_timer);
> + del_timer(&priv->auto_deepsleep_timer);
> kfree(priv->networks);
> priv->networks = NULL;
>
> @@ -1272,6 +1349,11 @@ void lbs_remove_card(struct lbs_private *priv)
> wrqu.ap_addr.sa_family = ARPHRD_ETHER;
> wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
>
> + if (priv->is_deep_sleep) {
> + priv->is_deep_sleep = 0;
> + wake_up_interruptible(&priv->ds_awake_q);
> + }
> +
> /* Stop the thread servicing the interrupts */
> priv->surpriseremoved = 1;
> kthread_stop(priv->main_thread);
> @@ -1392,6 +1474,7 @@ void lbs_stop_card(struct lbs_private *priv)
>
> /* Delete the timeout of the currently processing command */
> del_timer_sync(&priv->command_timer);
> + del_timer_sync(&priv->auto_deepsleep_timer);
>
> /* Flush pending command nodes */
> spin_lock_irqsave(&priv->driver_lock, flags);
> diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
> index 6c95af3..e468e15 100644
> --- a/drivers/net/wireless/libertas/scan.c
> +++ b/drivers/net/wireless/libertas/scan.c
> @@ -950,6 +950,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> if (!priv->radio_on) {
> ret = -EINVAL;
> goto out;
> @@ -1017,6 +1022,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + err = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
> + return err;
> + }
> +
> /* iwlist should wait until the current scan is finished */
> if (priv->scan_channel)
> return -EAGAIN;
> diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
> index be837a0..ef2b986 100644
> --- a/drivers/net/wireless/libertas/wext.c
> +++ b/drivers/net/wireless/libertas/wext.c
> @@ -45,6 +45,31 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
> priv->pending_assoc_req = NULL;
> }
>
> +/**
> + * @brief This function checks if the command is allowed.
> + *
> + * @param priv A pointer to lbs_private structure
> + * @return allowed or not allowed.
> + */
> +
> +int lbs_is_cmd_allowed(struct lbs_private *priv)
> +{
> + int ret = 1;
> +
> + lbs_deb_enter(LBS_DEB_WEXT);
> +
> + if (!priv->is_auto_deep_sleep_enabled) {
> + if (priv->is_deep_sleep) {
> + lbs_deb_wext("IOCTLS called when station"
> + "is in deep sleep\n");
> + ret = 0;
> + }
> + }
> +
> + lbs_deb_leave(LBS_DEB_WEXT);
> + return ret;
> +}
> +
>
> /**
> * @brief Find the channel frequency power info with specific channel
> @@ -168,6 +193,11 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + lbs_deb_leave(LBS_DEB_WEXT);
> + return -EBUSY;
> + }
> +
> cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
> priv->curbssparams.channel);
>
> @@ -278,6 +308,12 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> if (vwrq->disabled)
> val = MRVDRV_RTS_MAX_VALUE;
>
> @@ -299,6 +335,11 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
> if (ret)
> goto out;
> @@ -321,6 +362,12 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> if (vwrq->disabled)
> val = MRVDRV_FRAG_MAX_VALUE;
>
> @@ -342,6 +389,11 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
> if (ret)
> goto out;
> @@ -391,6 +443,11 @@ static int lbs_get_txpow(struct net_device *dev,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> if (!priv->radio_on) {
> lbs_deb_wext("tx power off\n");
> vwrq->value = 0;
> @@ -424,6 +481,11 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
> return -EOPNOTSUPP;
>
> @@ -472,6 +534,11 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> vwrq->disabled = 0;
>
> if (vwrq->flags & IW_RETRY_LONG) {
> @@ -712,6 +779,11 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + lbs_deb_leave(LBS_DEB_WEXT);
> + return -EBUSY;
> + }
> +
> if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
> if (vwrq->disabled)
> return 0;
> @@ -792,6 +864,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv))
> + return NULL;
> +
> priv->wstats.status = priv->mode;
>
> /* If we're not associated, all quality values are meaningless */
> @@ -892,6 +967,12 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> mutex_lock(&priv->lock);
> assoc_req = lbs_get_association_request(priv);
> if (!assoc_req) {
> @@ -1000,6 +1081,12 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
> u8 rates[MAX_RATES + 1];
>
> lbs_deb_enter(LBS_DEB_WEXT);
> +
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> lbs_deb_wext("vwrq->value %d\n", vwrq->value);
> lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
>
> @@ -1058,6 +1145,11 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + lbs_deb_leave(LBS_DEB_WEXT);
> + return -EBUSY;
> + }
> +
> if (priv->connect_status == LBS_CONNECTED) {
> vwrq->value = priv->cur_rate * 500000;
>
> @@ -1084,6 +1176,11 @@ static int lbs_set_mode(struct net_device *dev,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> if ( (*uwrq != IW_MODE_ADHOC)
> && (*uwrq != IW_MODE_INFRA)
> && (*uwrq != IW_MODE_AUTO)) {
> @@ -1325,6 +1422,12 @@ static int lbs_set_encode(struct net_device *dev,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> mutex_lock(&priv->lock);
> assoc_req = lbs_get_association_request(priv);
> if (!assoc_req) {
> @@ -1508,6 +1611,12 @@ static int lbs_set_encodeext(struct net_device *dev,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> mutex_lock(&priv->lock);
> assoc_req = lbs_get_association_request(priv);
> if (!assoc_req) {
> @@ -1720,6 +1829,12 @@ static int lbs_set_auth(struct net_device *dev,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> mutex_lock(&priv->lock);
> assoc_req = lbs_get_association_request(priv);
> if (!assoc_req) {
> @@ -1822,6 +1937,12 @@ static int lbs_get_auth(struct net_device *dev,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> switch (dwrq->flags & IW_AUTH_INDEX) {
> case IW_AUTH_KEY_MGMT:
> dwrq->value = priv->secinfo.key_mgmt;
> @@ -1864,6 +1985,11 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + goto out;
> + }
> +
> if (vwrq->disabled) {
> lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
> goto out;
> @@ -1983,6 +2109,12 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> if (!priv->radio_on) {
> ret = -EINVAL;
> goto out;
> @@ -2110,6 +2242,12 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> + if (!lbs_is_cmd_allowed(priv)) {
> + ret = -EBUSY;
> + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> + return ret;
> + }
> +
> if (!priv->radio_on)
> return -EINVAL;
>


2009-09-28 22:42:49

by Bing Zhao

[permalink] [raw]
Subject: RE: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

SGkgRGFuLA0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IERhbiBXaWxs
aWFtcyBbbWFpbHRvOmRjYndAcmVkaGF0LmNvbV0NCj4gU2VudDogU3VuZGF5LCBTZXB0ZW1iZXIg
MjAsIDIwMDkgNzo1OCBBTQ0KPiBUbzogQmluZyBaaGFvDQo+IENjOiBsaWJlcnRhcy1kZXZAbGlz
dHMuaW5mcmFkZWFkLm9yZzsgbGludXgtd2lyZWxlc3NAdmdlci5rZXJuZWwub3JnOyBBbWl0a3Vt
YXIgS2Fyd2FyDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0hdIGxpYmVydGFzOiBBZGQgYXV0byBkZWVw
IHNsZWVwIHN1cHBvcnQgZm9yIFNEODM4NS9TRDg2ODYvU0Q4Njg4DQo+DQo+IE9uIFR1ZSwgMjAw
OS0wOS0xNSBhdCAxNjo0NSAtMDcwMCwgQmluZyBaaGFvIHdyb3RlOg0KPiA+IEZyb206IEFtaXRr
dW1hciBLYXJ3YXIgPGFrYXJ3YXJAbWFydmVsbC5jb20+DQo+ID4NCj4gPiBBZGQgdGltZXIgYmFz
ZWQgYXV0byBkZWVwIHNsZWVwIGZlYXR1cmUgaW4gbGliZXJ0YXMgZHJpdmVyIHdoaWNoIGNhbiBi
ZQ0KPiA+IGNvbmZpZ3VyZWQgdGhyb3VnaCBkZWJ1Z2ZzIGludGVyZmFjZS4gVGhpcyBpcyB0ZXN0
ZWQgb24gU0Q4Njg4LCBTRDg2ODYgY2FyZHMNCj4gPiB3aXRoIGZpcm13YXJlIHZlcnNpb25zIDEw
LjM4LjEucDI1LCA5LjcwLjQucDAgcmVzcGVjdGl2ZWx5IG9uIDMyLWJpdCBhbmQgNjQtYml0DQo+
ID4gcGxhdGZvcm1zLiBUZXN0cyBoYXZlIGJlZW4gZG9uZSBmb3IgVVNCL0NTIGNhcmRzIHRvIG1h
a2Ugc3VyZSB0aGF0IHRoZSBwYXRjaA0KPiA+IHdvbid0IGJyZWFrIFVTQi9DUyBjb2RlLiBXZSBk
aWRuJ3QgdGVzdCB0aGUgaWZfc3BpIGRyaXZlci4NCj4NCj4gU28gdGhlcmUncyBhbHdheXM6DQo+
DQo+ICNkZWZpbmUgSVdfUE9XRVJfU0FWSU5HICAgICAgICAgICAgICAgMHg0MDAwICAvKiBWYWx1
ZSBpcyByZWxhdGl2ZSAoaG93IGFnZ3Jlc3NpdmUpKi8NCj4NCj4gaXdjb25maWcgd2xhbjAgcG93
ZXIgc2F2aW5nIDEwDQo+DQo+IFRoYXQgc2VlbXMgcXVpdGUgYSBiaXQgYmV0dGVyIHRoYW4gYSBu
ZXcgZGVidWdmcyBwYXJhbWV0ZXIsIHVudGlsIHdlIGNhbg0KPiBjb252ZXIgdGhlIGRyaXZlciBv
dmVyIGNmZzgwMjExIGFuZCBkbyB0aGlzIHByb3Blcmx5LiAgSWYgdGhlIHBvd2VyDQo+IHNhdmlu
ZyBtb2RlIGlzIGhpZ2hlciB0aGFuIHNvbWUgbnVtYmVyIFgsIHRoZSBjaGlwIGdldHMgcHV0IGlu
dG8gZGVlcA0KPiBzbGVlcCBtb2RlLCBvciBpdCBjYW4gYmUgYXV0b21hdGljYWxseSBwbGFjZWQg
aW4gZGVlcCBzbGVlcCBtb2RlIGJ5IHRoZQ0KPiBkcml2ZXIgd2hlbiB0aGVyZSBpcyBubyBhc3Nv
Y2lhdGlvbiBsaWtlIHlvdSBoYXZlIGRvbmUgd2l0aCB0aGUgdGltZXINCj4gYWJvdmUuICBJIHRo
aW5rIHlvdSBzaG91bGQgcGljayByZWFzb25hYmxlIGRlZmF1bHRzLCBhbmQgcGVyaGFwcyBpZiB0
aGUNCj4gJ3NhdmluZycgdmFsdWUgaXMgbGFyZ2VyLCB0aGUgdGltZXIgdmFsdWUgaW4gdGhlIGRy
aXZlciBnZXRzIHNtYWxsZXIuDQo+DQo+IERvZXMgdGhhdCBzb3VuZCBsaWtlIGFuIE9LIGFwcHJv
YWNoPyAgV2UgcmVhbGx5IHNob3VsZCBiZSB1c2luZyBkZWJ1Z2ZzDQo+IG9ubHkgZm9yIGRlYnVn
Z2luZyBzdHVmZiAob2J2aW91c2x5KSwgYW5kIHRoZSByZWFsIGZpeCBmb3IgdGhpcyBzb3J0IG9m
DQo+IHRoaW5nIGlzIHRvIHN3aXRjaCBvdmVyIHRvIGNmZzgwMjExIHdoZXJlIHdlIGNhbiBhY3R1
YWxseSBleHRlbmQgdGhlDQo+IGNvbmZpZ3VyYXRpb24gQVBJIGluc3RlYWQgb2YgaGFja2luZyBp
dCBpbnRvIGRlYnVnZnMvV0VYVC9ldGMuDQo+DQo+IERhbg0KDQpUaGFua3MgZm9yIHlvdXIgc3Vn
Z2VzdGlvbi4NCg0KSW4gbGF0ZXN0IGtlcm5lbCwgSVdfUE9XRVJfU0FWSU5HIGlzIG5vdCBkZWZp
bmVkIGluIGluY2x1ZGUvbGludXgvd2lyZWxlc3MuaC4NCklXX1BPV0VSX1BFUklPRCBhbmQgSVdf
UE9XRVJfVElNRU9VVCBhcmUgZGVmaW5lZCB0aG91Z2guDQoNCldlIGFyZSBwbGFubmluZyB0byBy
ZW1vdmUgZGVidWdmcyBmb3IgY29uZmlndXJhdGlvbnMgYW5kIHVzZSB0aGUgZm9sbG93aW5nIGNv
bW1hbmRzIGluc3RlYWQuDQpQbGVhc2UgbGV0IHVzIGtub3cgaWYgdGhlcmUgaXMgYW55IGNvbmNl
cm4uDQoNCml3Y29uZmlnIHdsYW4wIHBvd2VyIHBlcmlvZCAwICAgLT4gZW5hYmxlIGRlZXAgc2xl
ZXAgKGVudGVyIGRlZXAgc2xlZXAgaW1tZWRpYXRlbHkpDQppd2NvbmZpZyB3bGFuMCBwb3dlciBw
ZXJpb2QgNSAgIC0+IGVuYWJsZSBhdXRvIGRlZXAgc2xlZXAgKGVudGVyIGRlZXAgc2xlZXAgYXV0
b21hdGljYWxseSBhZnRlciA1cyBpZGxlIHRpbWUpDQppd2NvbmZpZyB3bGFuMCBwb3dlciBwZXJp
b2QgLTEgIC0+IGRpc2FibGUgZGVlcCBzbGVlcCAvIGF1dG8gZGVlcCBzbGVlcA0KDQpCeSB0aGUg
d2F5LCB0aGVyZSBpcyBhIGJ1ZyBpbiBpd2NvbmZpZyB0b29sIHYyOS4gSXQgZG9lc27igJl0IHRh
a2UgYW55IHZhbHVlcyByaWdodCBhZnRlciAicGVyaW9kIiBvciAidGltZW91dCIuIFRoZSBuZXcg
dmVyc2lvbiBvZiBXaXJlbGVzcyBUb29scyB2MzAtcHJlOCAobGluayBiZWxvdykgZml4ZWQgdGhl
IGJ1ZzoNCg0KaHR0cDovL3d3dy5ocGwuaHAuY29tL3BlcnNvbmFsL0plYW5fVG91cnJpbGhlcy9M
aW51eC93aXJlbGVzc190b29scy4zMC5wcmU4LnRhci5neg0KDQpUaGFua3MsDQoNCkJpbmcNCg0K
Pg0KPiA+IFNpZ25lZC1vZmYtYnk6IEFtaXRrdW1hciBLYXJ3YXIgPGFrYXJ3YXJAbWFydmVsbC5j
b20+DQo+ID4gU2lnbmVkLW9mZi1ieTogQmluZyBaaGFvIDxiemhhb0BtYXJ2ZWxsLmNvbT4NCj4g
PiAtLS0NCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvUkVBRE1FICAgIHwgICAy
OCArKysrKy0NCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvY21kLmMgICAgIHwg
ICA3MiArKysrKysrKysrKysrLQ0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9j
bWRyZXNwLmMgfCAgIDEyICsrKw0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9k
ZWJ1Z2ZzLmMgfCAgMTYwICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysNCj4gPiAgZHJp
dmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGVjbC5oICAgIHwgICAgNCArDQo+ID4gIGRyaXZl
cnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2Rldi5oICAgICB8ICAgMTggKysrKw0KPiA+ICBkcml2
ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9ob3N0LmggICAgfCAgICAxICsNCj4gPiAgZHJpdmVy
cy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfY3MuYyAgIHwgICAgMyArDQo+ID4gIGRyaXZlcnMv
bmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3NkaW8uYyB8ICAgNTYgKysrKysrKysrKysNCj4gPiAg
ZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc2Rpby5oIHwgICAgMyArLQ0KPiA+ICBk
cml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9zcGkuYyAgfCAgICAzICsNCj4gPiAgZHJp
dmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfdXNiLmMgIHwgICAgMyArDQo+ID4gIGRyaXZl
cnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL21haW4uYyAgICB8ICAxMTEgKysrKysrKysrKysrKysr
KysrKy0tLQ0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9zY2FuLmMgICAgfCAg
IDExICsrDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL3dleHQuYyAgICB8ICAx
MzggKysrKysrKysrKysrKysrKysrKysrKysrKysNCj4gPiAgMTUgZmlsZXMgY2hhbmdlZCwgNjA0
IGluc2VydGlvbnMoKyksIDE5IGRlbGV0aW9ucygtKQ0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2Ry
aXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL1JFQURNRSBiL2RyaXZlcnMvbmV0L3dpcmVsZXNz
L2xpYmVydGFzL1JFQURNRQ0KPiA+IGluZGV4IGFiNmEyZDUuLjA1OWNlOGMgMTAwNjQ0DQo+ID4g
LS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvUkVBRE1FDQo+ID4gKysrIGIvZHJp
dmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvUkVBRE1FDQo+ID4gQEAgLTEsNSArMSw1IEBADQo+
ID4gID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09DQo+ID4gLSAgICAgICAgICAgICAgICAgICBSRUFE
TUUgZm9yIFVTQjgzODgNCj4gPiArICAgICAgICAgICAgICAgICAgIFJFQURNRSBmb3IgTGliZXJ0
YXMNCj4gPg0KPiA+ICAgKGMpIENvcHlyaWdodCDCqSAyMDAzLTIwMDYsIE1hcnZlbGwgSW50ZXJu
YXRpb25hbCBMdGQuDQo+ID4gICBBbGwgUmlnaHRzIFJlc2VydmVkDQo+ID4gQEAgLTIyNiw0ICsy
MjYsMzAgQEAgc2V0dXNlcnNjYW4NCj4gPiAgICAgIEFsbCBlbnRyaWVzIGluIHRoZSBzY2FuIHRh
YmxlIChub3QganVzdCB0aGUgbmV3IHNjYW4gZGF0YSB3aGVuIGtlZXA9MSkNCj4gPiAgICAgIHdp
bGwgYmUgZGlzcGxheWVkIHVwb24gY29tcGxldGlvbiBieSB1c2Ugb2YgdGhlIGdldHNjYW50YWJs
ZSBpb2N0bC4NCj4gPg0KPiA+ICtkZWVwc2xlZXANCj4gPiArDQo+ID4gKyAgIFRoaXMgY29tbWFu
ZCBpcyB1c2VkIHRvIGNvbmZpZ3VyZSB0aGUgc3RhdGlvbiBpbiBkZWVwIHNsZWVwIG1vZGUvYXV0
bw0KPiA+ICsgICBkZWVwIHNsZWVwIG1vZGUuIENvbW1hbmQgZXhwZWN0cyB0d28gcGFyYW1ldGVy
czoNCj4gPiArICAgJ3N0YXRlJyAnaWRsZSB0aW1lIHBlcmlvZCcNCj4gPiArDQo+ID4gKyAgIFRo
ZSB0aW1lciBpcyBpbXBsZW1lbnRlZCB0byBtb25pdG9yIHRoZSBhY3Rpdml0aWVzIChjb21tYW5k
LCBldmVudCwNCj4gPiArICAgICAgICBkYXRhLCBldGMuKS4gV2hlbiBhbiBhY3Rpdml0eSBpcyBk
ZXRlY3RlZCBzdGF0aW9uIHdpbGwgZXhpdCBmcm9tIGRlZXANCj4gPiArICAgICAgICBzbGVlcCBt
b2RlIGF1dG9tYXRpY2FsbHkgYW5kIHJlc3RhcnQgdGhlIHRpbWVyLiBBdCB0aW1lciBleHBpcnkg
KG5vDQo+ID4gKyAgICAgICAgYWN0aXZpdHkgZm9yIGRlZmluZWQgdGltZSBwZXJpb2QpIHRoZSBk
ZWVwc2xlZXAgbW9kZSBpcyBlbnRlcmVkDQo+ID4gKyAgICAgICAgYXV0b21hdGljYWxseS4NCj4g
PiArDQo+ID4gKyAgIE5vdGU6IHRoaXMgY29tbWFuZCBpcyBmb3IgU0RJTyBpbnRlcmZhY2Ugb25s
eS4NCj4gPiArDQo+ID4gKyAgIFBhdGg6IC9zeXMva2VybmVsL2RlYnVnL2xpYmVydGFzX3dpcmVs
ZXNzL2V0aFgvDQo+ID4gKw0KPiA+ICsgICBVc2FnZToNCj4gPiArICAgVG8gcmVhZCB0aGUgY3Vy
cmVudCBzdGF0dXMgb2YgZGVlcCBzbGVlcCBkbzoNCj4gPiArICAgICAgICAgICBjYXQgZGVlcHNs
ZWVwDQo+ID4gKyAgIFRvIGVuYWJsZSBkZWVwIHNsZWVwIG1vZGUgZG86DQo+ID4gKyAgICAgICAg
ICAgZWNobyAnMSAwJyA+IGRlZXBzbGVlcA0KPiA+ICsgICBUbyBlbmFibGUgYXV0byBkZWVwIHNs
ZWVwIG1vZGUgd2l0aCBpZGxlIHRpbWUgcGVyaW9kIDUgc2Vjb25kcyBkbzoNCj4gPiArICAgICAg
ICAgICBlY2hvICcxIDUwMDAnID4gZGVlcHNsZWVwDQo+ID4gKyAgIFRvIGRpc2FibGUgZGVlcCBz
bGVlcC9hdXRvIGRlZXAgc2xlZXAgbW9kZSBkbzoNCj4gPiArICAgICAgICAgICBlY2hvICcwIDAn
ID4gZGVlcHNsZWVwDQo+ID4gKw0KPiA+ICA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCj4gPiBkaWZm
IC0tZ2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvY21kLmMgYi9kcml2ZXJzL25l
dC93aXJlbGVzcy9saWJlcnRhcy9jbWQuYw0KPiA+IGluZGV4IDY4NTA5ODEuLjNhM2U4OTQgMTAw
NjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvY21kLmMNCj4gPiAr
KysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWQuYw0KPiA+IEBAIC0xNyw3ICsx
Nyw2IEBADQo+ID4NCj4gPiAgc3RhdGljIHN0cnVjdCBjbWRfY3RybF9ub2RlICpsYnNfZ2V0X2Nt
ZF9jdHJsX25vZGUoc3RydWN0IGxic19wcml2YXRlICpwcml2KTsNCj4gPg0KPiA+IC0NCj4gPiAg
LyoqDQo+ID4gICAqICBAYnJpZWYgU2ltcGxlIGNhbGxiYWNrIHRoYXQgY29waWVzIHJlc3BvbnNl
IGJhY2sgaW50byBjb21tYW5kDQo+ID4gICAqDQo+ID4gQEAgLTMxOSw2ICszMTgsNjAgQEAgaW50
IGxic19jbWRfODAyXzExX3NsZWVwX3BhcmFtcyhzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYsIHVp
bnQxNl90IGNtZF9hY3Rpb24sDQo+ID4gICAgIHJldHVybiAwOw0KPiA+ICB9DQo+ID4NCj4gPiAr
c3RhdGljIGludCBsYnNfd2FpdF9mb3JfZHNfYXdha2Uoc3RydWN0IGxic19wcml2YXRlICpwcml2
KQ0KPiA+ICt7DQo+ID4gKyAgIGludCByZXQgPSAwOw0KPiA+ICsNCj4gPiArICAgbGJzX2RlYl9l
bnRlcihMQlNfREVCX0NNRCk7DQo+ID4gKw0KPiA+ICsgICBpZiAocHJpdi0+aXNfZGVlcF9zbGVl
cCkgew0KPiA+ICsgICAgICAgICAgIGlmICghd2FpdF9ldmVudF9pbnRlcnJ1cHRpYmxlX3RpbWVv
dXQocHJpdi0+ZHNfYXdha2VfcSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAhcHJpdi0+aXNfZGVlcF9zbGVlcCwgKDEwICogSFopKSkgew0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgbGJzX3ByX2VycigiZHNfYXdha2VfcTogdGltZXIgZXhwaXJlZFxuIik7DQo+ID4g
KyAgICAgICAgICAgICAgICAgICByZXQgPSAtMTsNCj4gPiArICAgICAgICAgICB9DQo+ID4gKyAg
IH0NCj4gPiArDQo+ID4gKyAgIGxic19kZWJfbGVhdmVfYXJncyhMQlNfREVCX0NNRCwgInJldCAl
ZCIsIHJldCk7DQo+ID4gKyAgIHJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK2ludCBs
YnNfc2V0X2RlZXBfc2xlZXAoc3RydWN0IGxic19wcml2YXRlICpwcml2LCBpbnQgZGVlcF9zbGVl
cCkNCj4gPiArew0KPiA+ICsgICBpbnQgcmV0ID0gIDA7DQo+ID4gKw0KPiA+ICsgICBsYnNfZGVi
X2VudGVyKExCU19ERUJfQ01EKTsNCj4gPiArDQo+ID4gKyAgIGlmIChkZWVwX3NsZWVwKSB7DQo+
ID4gKyAgICAgICAgICAgaWYgKHByaXYtPmlzX2RlZXBfc2xlZXAgIT0gMSkgew0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgbGJzX2RlYl9jbWQoImRlZXAgc2xlZXA6IHNsZWVwXG4iKTsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgIEJVR19PTighcHJpdi0+ZW50ZXJfZGVlcF9zbGVlcCk7DQo+ID4g
KyAgICAgICAgICAgICAgICAgICByZXQgPSBwcml2LT5lbnRlcl9kZWVwX3NsZWVwKHByaXYpOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgaWYgKCFyZXQpIHsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgbmV0aWZfc3RvcF9xdWV1ZShwcml2LT5kZXYpOw0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICBuZXRpZl9jYXJyaWVyX29mZihwcml2LT5kZXYpOw0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICBsYnNfcHJfZXJyKCJkZWVwIHNsZWVwOiBhbHJlYWR5IGVuYWJsZWRcbiIpOw0K
PiA+ICsgICAgICAgICAgIH0NCj4gPiArICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICBpZiAo
cHJpdi0+aXNfZGVlcF9zbGVlcCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgbGJzX2RlYl9j
bWQoImRlZXAgc2xlZXA6IHdha2V1cFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBCVUdf
T04oIXByaXYtPmV4aXRfZGVlcF9zbGVlcCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICByZXQg
PSBwcml2LT5leGl0X2RlZXBfc2xlZXAocHJpdik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBp
ZiAoIXJldCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICByZXQgPSBsYnNfd2Fp
dF9mb3JfZHNfYXdha2UocHJpdik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIGlm
IChyZXQpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGJzX3ByX2Vy
cigiZGVlcCBzbGVlcDogd2FrZXVwIg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAiZmFpbGVkXG4iKTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgIH0NCj4gPiArICAgICAgICAgICB9DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gKyAgIGxic19k
ZWJfbGVhdmVfYXJncyhMQlNfREVCX0NNRCwgInJldCAlZCIsIHJldCk7DQo+ID4gKyAgIHJldHVy
biByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gIGludCBsYnNfY21kXzgwMl8xMV9zZXRfd2VwKHN0
cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdiwgdWludDE2X3QgY21kX2FjdGlvbiwNCj4gPiAgICAgICAg
ICAgICAgICAgICAgICAgIHN0cnVjdCBhc3NvY19yZXF1ZXN0ICphc3NvYykNCj4gPiAgew0KPiA+
IEBAIC0xMjQyLDggKzEyOTUsMTcgQEAgc3RhdGljIHZvaWQgbGJzX3N1Ym1pdF9jb21tYW5kKHN0
cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdiwNCj4gPiAgICAgICAgICAgICB0aW1lbyA9IEhaLzQ7DQo+
ID4gICAgIH0NCj4gPg0KPiA+IC0gICAvKiBTZXR1cCB0aGUgdGltZXIgYWZ0ZXIgdHJhbnNtaXQg
Y29tbWFuZCAqLw0KPiA+IC0gICBtb2RfdGltZXIoJnByaXYtPmNvbW1hbmRfdGltZXIsIGppZmZp
ZXMgKyB0aW1lbyk7DQo+ID4gKyAgIGlmIChjb21tYW5kID09IENNRF84MDJfMTFfREVFUF9TTEVF
UCkgew0KPiA+ICsgICAgICAgICAgIGlmIChwcml2LT5pc19hdXRvX2RlZXBfc2xlZXBfZW5hYmxl
ZCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgcHJpdi0+d2FrZXVwX2Rldl9yZXF1aXJlZCA9
IDE7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBwcml2LT5kbmxkX3NlbnQgPSAwOw0KPiA+ICsg
ICAgICAgICAgIH0NCj4gPiArICAgICAgICAgICBwcml2LT5pc19kZWVwX3NsZWVwID0gMTsNCj4g
PiArICAgICAgICAgICBsYnNfY29tcGxldGVfY29tbWFuZChwcml2LCBjbWRub2RlLCAwKTsNCj4g
PiArICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAvKiBTZXR1cCB0aGUgdGltZXIgYWZ0ZXIg
dHJhbnNtaXQgY29tbWFuZCAqLw0KPiA+ICsgICAgICAgICAgIG1vZF90aW1lcigmcHJpdi0+Y29t
bWFuZF90aW1lciwgamlmZmllcyArIHRpbWVvKTsNCj4gPiArICAgfQ0KPiA+DQo+ID4gICAgIGxi
c19kZWJfbGVhdmUoTEJTX0RFQl9IT1NUKTsNCj4gPiAgfQ0KPiA+IEBAIC0xNTA1LDYgKzE1Njcs
MTAgQEAgaW50IGxic19wcmVwYXJlX2FuZF9zZW5kX2NvbW1hbmQoc3RydWN0IGxic19wcml2YXRl
ICpwcml2LA0KPiA+ICAgICBjYXNlIENNRF84MDJfMTFfQkVBQ09OX0NUUkw6DQo+ID4gICAgICAg
ICAgICAgcmV0ID0gbGJzX2NtZF9iY25fY3RybChwcml2LCBjbWRwdHIsIGNtZF9hY3Rpb24pOw0K
PiA+ICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICBjYXNlIENNRF84MDJfMTFfREVFUF9TTEVF
UDoNCj4gPiArICAgICAgICAgICBjbWRwdHItPmNvbW1hbmQgPSBjcHVfdG9fbGUxNihDTURfODAy
XzExX0RFRVBfU0xFRVApOw0KPiA+ICsgICAgICAgICAgIGNtZHB0ci0+c2l6ZSA9IGNwdV90b19s
ZTE2KFNfRFNfR0VOKTsNCj4gPiArICAgICAgICAgICBicmVhazsNCj4gPiAgICAgZGVmYXVsdDoN
Cj4gPiAgICAgICAgICAgICBsYnNfcHJfZXJyKCJQUkVQX0NNRDogdW5rbm93biBjb21tYW5kIDB4
JTA0eFxuIiwgY21kX25vKTsNCj4gPiAgICAgICAgICAgICByZXQgPSAtMTsNCj4gPiBkaWZmIC0t
Z2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvY21kcmVzcC5jIGIvZHJpdmVycy9u
ZXQvd2lyZWxlc3MvbGliZXJ0YXMvY21kcmVzcC5jDQo+ID4gaW5kZXggYzQyZDNmYS4uNDdkMmIx
OSAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWRyZXNw
LmMNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWRyZXNwLmMNCj4g
PiBAQCAtNTA0LDkgKzUwNCwyMSBAQCBpbnQgbGJzX3Byb2Nlc3NfZXZlbnQoc3RydWN0IGxic19w
cml2YXRlICpwcml2LCB1MzIgZXZlbnQpDQo+ID4NCj4gPiAgICAgY2FzZSBNQUNSRUdfSU5UX0NP
REVfSE9TVF9BV0FLRToNCj4gPiAgICAgICAgICAgICBsYnNfZGViX2NtZCgiRVZFTlQ6IGhvc3Qg
YXdha2VcbiIpOw0KPiA+ICsgICAgICAgICAgIGlmIChwcml2LT5yZXNldF9kZWVwX3NsZWVwX3dh
a2V1cCkNCj4gPiArICAgICAgICAgICAgICAgICAgIHByaXYtPnJlc2V0X2RlZXBfc2xlZXBfd2Fr
ZXVwKHByaXYpOw0KPiA+ICsgICAgICAgICAgIHByaXYtPmlzX2RlZXBfc2xlZXAgPSAwOw0KPiA+
ICAgICAgICAgICAgIGxic19zZW5kX2NvbmZpcm13YWtlKHByaXYpOw0KPiA+ICAgICAgICAgICAg
IGJyZWFrOw0KPiA+DQo+ID4gKyAgIGNhc2UgTUFDUkVHX0lOVF9DT0RFX0RFRVBfU0xFRVBfQVdB
S0U6DQo+ID4gKyAgICAgICAgICAgaWYgKHByaXYtPnJlc2V0X2RlZXBfc2xlZXBfd2FrZXVwKQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgcHJpdi0+cmVzZXRfZGVlcF9zbGVlcF93YWtldXAocHJp
dik7DQo+ID4gKyAgICAgICAgICAgbGJzX2RlYl9jbWQoIkVWRU5UOiBkcyBhd2FrZVxuIik7DQo+
ID4gKyAgICAgICAgICAgcHJpdi0+aXNfZGVlcF9zbGVlcCA9IDA7DQo+ID4gKyAgICAgICAgICAg
cHJpdi0+d2FrZXVwX2Rldl9yZXF1aXJlZCA9IDA7DQo+ID4gKyAgICAgICAgICAgd2FrZV91cF9p
bnRlcnJ1cHRpYmxlKCZwcml2LT5kc19hd2FrZV9xKTsNCj4gPiArICAgICAgICAgICBicmVhazsN
Cj4gPiArDQo+ID4gICAgIGNhc2UgTUFDUkVHX0lOVF9DT0RFX1BTX0FXQUtFOg0KPiA+ICAgICAg
ICAgICAgIGxic19kZWJfY21kKCJFVkVOVDogcHMgYXdha2VcbiIpOw0KPiA+ICAgICAgICAgICAg
IC8qIGhhbmRsZSB1bmV4cGVjdGVkIFBTIEFXQUtFIGV2ZW50ICovDQo+ID4gZGlmZiAtLWdpdCBh
L2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2RlYnVnZnMuYyBiL2RyaXZlcnMvbmV0L3dp
cmVsZXNzL2xpYmVydGFzL2RlYnVnZnMuYw0KPiA+IGluZGV4IDg5M2E1NWMuLjYyNGE0MzggMTAw
NjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGVidWdmcy5jDQo+
ID4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGVidWdmcy5jDQo+ID4gQEAg
LTExNyw2ICsxMTcsMTEgQEAgc3RhdGljIHNzaXplX3QgbGJzX3NsZWVwcGFyYW1zX3dyaXRlKHN0
cnVjdCBmaWxlICpmaWxlLA0KPiA+ICAgICBpZiAoIWJ1ZikNCj4gPiAgICAgICAgICAgICByZXR1
cm4gLUVOT01FTTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkg
ew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBnb3RvIG91
dF91bmxvY2s7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIGJ1Zl9zaXplID0gbWluKGNvdW50
LCBsZW4gLSAxKTsNCj4gPiAgICAgaWYgKGNvcHlfZnJvbV91c2VyKGJ1ZiwgdXNlcl9idWYsIGJ1
Zl9zaXplKSkgew0KPiA+ICAgICAgICAgICAgIHJldCA9IC1FRkFVTFQ7DQo+ID4gQEAgLTE1Nyw2
ICsxNjIsMTEgQEAgc3RhdGljIHNzaXplX3QgbGJzX3NsZWVwcGFyYW1zX3JlYWQoc3RydWN0IGZp
bGUgKmZpbGUsIGNoYXIgX191c2VyICp1c2VyYnVmLA0KPiA+ICAgICBpZiAoIWJ1ZikNCj4gPiAg
ICAgICAgICAgICByZXR1cm4gLUVOT01FTTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRf
YWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVTWTsNCj4gPiArICAg
ICAgICAgICBnb3RvIG91dF91bmxvY2s7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIHJldCA9
IGxic19jbWRfODAyXzExX3NsZWVwX3BhcmFtcyhwcml2LCBDTURfQUNUX0dFVCwgJnNwKTsNCj4g
PiAgICAgaWYgKHJldCkNCj4gPiAgICAgICAgICAgICBnb3RvIG91dF91bmxvY2s7DQo+ID4gQEAg
LTE3Myw2ICsxODMsMTE4IEBAIG91dF91bmxvY2s6DQo+ID4gICAgIHJldHVybiByZXQ7DQo+ID4g
IH0NCj4gPg0KPiA+ICtzdGF0aWMgc3NpemVfdCBsYnNfZGVlcHNsZWVwX3JlYWQoc3RydWN0IGZp
bGUgKmZpbGUsIGNoYXIgX191c2VyICp1c2VyYnVmLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIHNpemVfdCBjb3VudCwgbG9mZl90ICpwcG9zKQ0KPiA+ICt7DQo+ID4gKyAgIHN0
cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdiA9IGZpbGUtPnByaXZhdGVfZGF0YTsNCj4gPiArICAgc3Np
emVfdCBwb3MgPSAwOw0KPiA+ICsgICBpbnQgcmV0Ow0KPiA+ICsgICB1bnNpZ25lZCBsb25nIGFk
ZHIgPSBnZXRfemVyb2VkX3BhZ2UoR0ZQX0tFUk5FTCk7DQo+ID4gKyAgIGNoYXIgKmJ1ZiA9IChj
aGFyICopYWRkcjsNCj4gPiArDQo+ID4gKyAgIGlmICghYnVmKQ0KPiA+ICsgICAgICAgICAgIHJl
dHVybiAtRU5PTUVNOw0KPiA+ICsNCj4gPiArICAgaWYgKCFwcml2LT5lbnRlcl9kZWVwX3NsZWVw
KSB7DQo+ID4gKyAgICAgICAgICAgbGJzX3ByX2VycigiZGVlcCBzbGVlcCBmZWF0dXJlIGlzIG5v
dCBpbXBsZW1lbnRlZCAiDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICJmb3IgdGhp
cyBpbnRlcmZhY2UgZHJpdmVyXG4iKTsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUlOVkFMOw0K
PiA+ICsgICAgICAgICAgIGdvdG8gb3V0X2RzOw0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICsgICBp
ZiAocHJpdi0+aXNfYXV0b19kZWVwX3NsZWVwX2VuYWJsZWQpDQo+ID4gKyAgICAgICAgICAgcG9z
ICs9IHNucHJpbnRmKGJ1ZiwgbGVuLCAiJWQgJWRcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgIHByaXYtPmlzX2F1dG9fZGVlcF9zbGVlcF9lbmFibGVkLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICBwcml2LT5hdXRvX2RlZXBfc2xlZXBfdGltZW91dCk7DQo+ID4g
KyAgIGVsc2UgaWYgKHByaXYtPmlzX2RlZXBfc2xlZXApDQo+ID4gKyAgICAgICAgICAgcG9zICs9
IHNucHJpbnRmKGJ1ZiwgbGVuLCAiJWQgJWRcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgIHByaXYtPmlzX2RlZXBfc2xlZXAsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgIHByaXYtPmF1dG9fZGVlcF9zbGVlcF90aW1lb3V0KTsNCj4gPiArICAgZWxzZQ0KPiA+ICsg
ICAgICAgICAgIHBvcyArPSBzbnByaW50ZihidWYsIGxlbiwgIiVkICVkXG4iLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICBwcml2LT5pc19kZWVwX3NsZWVwLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICBwcml2LT5hdXRvX2RlZXBfc2xlZXBfdGltZW91dCk7DQo+ID4g
Kw0KPiA+ICsgICByZXQgPSBzaW1wbGVfcmVhZF9mcm9tX2J1ZmZlcih1c2VyYnVmLCBjb3VudCwg
cHBvcywgYnVmLCBwb3MpOw0KPiA+ICsNCj4gPiArb3V0X2RzOg0KPiA+ICsgICBmcmVlX3BhZ2Uo
YWRkcik7DQo+ID4gKyAgIHJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBz
c2l6ZV90IGxic19kZWVwc2xlZXBfd3JpdGUoc3RydWN0IGZpbGUgKmZpbGUsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBjaGFyIF9fdXNlciAqdXNlcmJ1ZiwNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVfdCBjb3VudCwgbG9mZl90ICpw
cG9zKQ0KPiA+ICt7DQo+ID4gKyAgIHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdiA9IGZpbGUtPnBy
aXZhdGVfZGF0YTsNCj4gPiArICAgc3NpemVfdCByZXMsIGJ1Zl9zaXplOw0KPiA+ICsgICBpbnQg
aXNfZGVlcF9zbGVlcCwgYXV0b19kZWVwX3NsZWVwX3RpbWVvdXQ7DQo+ID4gKyAgIHVuc2lnbmVk
IGxvbmcgYWRkciA9IGdldF96ZXJvZWRfcGFnZShHRlBfS0VSTkVMKTsNCj4gPiArICAgY2hhciAq
YnVmID0gKGNoYXIgKilhZGRyOw0KPiA+ICsNCj4gPiArICAgaWYgKCFidWYpDQo+ID4gKyAgICAg
ICAgICAgcmV0dXJuIC1FTk9NRU07DQo+ID4gKw0KPiA+ICsgICBpZiAoIXByaXYtPmVudGVyX2Rl
ZXBfc2xlZXApIHsNCj4gPiArICAgICAgICAgICBsYnNfcHJfZXJyKCJkZWVwIHNsZWVwIGZlYXR1
cmUgaXMgbm90IGltcGxlbWVudGVkICINCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ImZvciB0aGlzIGludGVyZmFjZSBkcml2ZXJcbiIpOw0KPiA+ICsgICAgICAgICAgIHJlcyA9IC1F
SU5WQUw7DQo+ID4gKyAgICAgICAgICAgZ290byBvdXRfZHM7DQo+ID4gKyAgIH0NCj4gPiArDQo+
ID4gKyAgIGlmIChwcml2LT5jb25uZWN0X3N0YXR1cyA9PSBMQlNfQ09OTkVDVEVEKSB7DQo+ID4g
KyAgICAgICAgICAgbGJzX3ByX2VycigiY2FuJ3QgdXNlIGRlZXAgc2xlZXAgY21kIGluIGNvbm5l
Y3RlZCAiDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICJzdGF0ZVxuIik7DQo+ID4g
KyAgICAgICAgICAgcmVzID0gLUVJTlZBTDsNCj4gPiArICAgICAgICAgICBnb3RvIG91dF9kczsN
Cj4gPiArICAgfQ0KPiA+ICsNCj4gPiArICAgYnVmX3NpemUgPSBtaW4oY291bnQsIGxlbiAtIDEp
Ow0KPiA+ICsgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2VyYnVmLCBidWZfc2l6ZSkpIHsN
Cj4gPiArICAgICAgICAgICByZXMgPSAtRUZBVUxUOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0
X2RzOw0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICsgICByZXMgPSBzc2NhbmYoYnVmLCAiJWQgJWQi
LCAmaXNfZGVlcF9zbGVlcCwgJmF1dG9fZGVlcF9zbGVlcF90aW1lb3V0KTsNCj4gPiArICAgaWYg
KChyZXMgIT0gMikgfHwgKCFpc19kZWVwX3NsZWVwICYmIGF1dG9fZGVlcF9zbGVlcF90aW1lb3V0
KSB8fA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICEoKGlzX2RlZXBf
c2xlZXAgPT0gMSkgfHwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAo
aXNfZGVlcF9zbGVlcCA9PSAwKSkpIHsNCj4gPiArICAgICAgICAgICBsYnNfcHJfZXJyKCJ1bmtu
b3duIG9wdGlvblxuIik7DQo+ID4gKyAgICAgICAgICAgcmVzID0gLUVJTlZBTDsNCj4gPiArICAg
ICAgICAgICBnb3RvIG91dF9kczsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiArICAgaWYgKGF1dG9f
ZGVlcF9zbGVlcF90aW1lb3V0KSB7DQo+ID4gKyAgICAgICAgICAgaWYgKCFwcml2LT5pc19hdXRv
X2RlZXBfc2xlZXBfZW5hYmxlZCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgcHJpdi0+aXNf
YWN0aXZpdHlfZGV0ZWN0ZWQgPSAwOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgcHJpdi0+YXV0
b19kZWVwX3NsZWVwX3RpbWVvdXQgPSBhdXRvX2RlZXBfc2xlZXBfdGltZW91dDsNCj4gPiArICAg
ICAgICAgICAgICAgICAgIGxic19lbnRlcl9hdXRvX2RlZXBfc2xlZXAocHJpdik7DQo+ID4gKyAg
ICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgICAgIHByaXYtPmF1dG9fZGVl
cF9zbGVlcF90aW1lb3V0ID0gYXV0b19kZWVwX3NsZWVwX3RpbWVvdXQ7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICBsYnNfZGViX2RlYnVnZnMoImF1dG8gZGVlcCBzbGVlcDogYWxyZWFkeSBlbmFi
bGVkXG4iKTsNCj4gPiArICAgICAgICAgICB9DQo+ID4gKyAgIH0gZWxzZSB7DQo+ID4gKyAgICAg
ICAgICAgaWYgKHByaXYtPmlzX2F1dG9fZGVlcF9zbGVlcF9lbmFibGVkKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICBsYnNfZXhpdF9hdXRvX2RlZXBfc2xlZXAocHJpdik7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAvKiBUcnkgdG8gZXhpdCBkZWVwIHNsZWVwIGlmIGF1dG8gZGVlcCBzbGVl
cCBkaXNhYmxlZCAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgcmVzID0gbGJzX3NldF9kZWVw
X3NsZWVwKHByaXYsIDApOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgaWYgKHJlcykNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgZ290byBvdXRfZHM7DQo+ID4gKyAgICAgICAgICAg
fQ0KPiA+ICsgICAgICAgICAgIGlmICgoaXNfZGVlcF9zbGVlcCA9PSAwKSB8fCAoaXNfZGVlcF9z
bGVlcCA9PSAxKSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgcmVzID0gbGJzX3NldF9kZWVw
X3NsZWVwKHByaXYsIGlzX2RlZXBfc2xlZXApOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgaWYg
KHJlcykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgZ290byBvdXRfZHM7DQo+ID4g
KyAgICAgICAgICAgfQ0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICsgICByZXMgPSBjb3VudDsNCj4g
PiArDQo+ID4gK291dF9kczoNCj4gPiArICAgZnJlZV9wYWdlKGFkZHIpOw0KPiA+ICsgICByZXR1
cm4gcmVzOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICAvKg0KPiA+ICAgKiBXaGVuIGNhbGxpbmcgQ01E
XzgwMl8xMV9TVUJTQ1JJQkVfRVZFTlQgd2l0aCBDTURfQUNUX0dFVCwgbWUgbWlnaHQNCj4gPiAg
ICogZ2V0IGEgYnVuY2ggb2YgdmVuZG9yLXNwZWNpZmljIFRMVnMgKGEuay5hLiBJRXMpIGJhY2sg
ZnJvbSB0aGUNCj4gPiBAQCAtMjIzLDYgKzM0NSw5IEBAIHN0YXRpYyBzc2l6ZV90IGxic190aHJl
c2hvbGRfcmVhZCh1aW50MTZfdCB0bHZfdHlwZSwgdWludDE2X3QgZXZlbnRfbWFzaywNCj4gPiAg
ICAgdTggZnJlcTsNCj4gPiAgICAgaW50IGV2ZW50cyA9IDA7DQo+ID4NCj4gPiArICAgaWYgKCFs
YnNfaXNfY21kX2FsbG93ZWQocHJpdikpDQo+ID4gKyAgICAgICAgICAgcmV0dXJuIC1FQlVTWTsN
Cj4gPiArDQo+ID4gICAgIGJ1ZiA9IChjaGFyICopZ2V0X3plcm9lZF9wYWdlKEdGUF9LRVJORUwp
Ow0KPiA+ICAgICBpZiAoIWJ1ZikNCj4gPiAgICAgICAgICAgICByZXR1cm4gLUVOT01FTTsNCj4g
PiBAQCAtMjc1LDYgKzQwMCw5IEBAIHN0YXRpYyBzc2l6ZV90IGxic190aHJlc2hvbGRfd3JpdGUo
dWludDE2X3QgdGx2X3R5cGUsIHVpbnQxNl90IGV2ZW50X21hc2ssDQo+ID4gICAgIGNoYXIgKmJ1
ZjsNCj4gPiAgICAgaW50IHJldDsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dl
ZChwcml2KSkNCj4gPiArICAgICAgICAgICByZXR1cm4gLUVCVVNZOw0KPiA+ICsNCj4gPiAgICAg
YnVmID0gKGNoYXIgKilnZXRfemVyb2VkX3BhZ2UoR0ZQX0tFUk5FTCk7DQo+ID4gICAgIGlmICgh
YnVmKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRU5PTUVNOw0KPiA+IEBAIC00NDQsNiArNTcy
LDExIEBAIHN0YXRpYyBzc2l6ZV90IGxic19yZG1hY19yZWFkKHN0cnVjdCBmaWxlICpmaWxlLCBj
aGFyIF9fdXNlciAqdXNlcmJ1ZiwNCj4gPiAgICAgaWYgKCFidWYpDQo+ID4gICAgICAgICAgICAg
cmV0dXJuIC1FTk9NRU07DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJp
dikpIHsNCj4gPiArICAgICAgICAgICBmcmVlX3BhZ2UoYWRkcik7DQo+ID4gKyAgICAgICAgICAg
cmV0dXJuIC1FQlVTWTsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgb2ZmdmFsLm9mZnNldCA9
IHByaXYtPm1hY19vZmZzZXQ7DQo+ID4gICAgIG9mZnZhbC52YWx1ZSA9IDA7DQo+ID4NCj4gPiBA
QCAtNDk2LDYgKzYyOSwxMSBAQCBzdGF0aWMgc3NpemVfdCBsYnNfd3JtYWNfd3JpdGUoc3RydWN0
IGZpbGUgKmZpbGUsDQo+ID4gICAgIGlmICghYnVmKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAt
RU5PTUVNOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+
ID4gKyAgICAgICAgICAgcmVzID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0X3Vu
bG9jazsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgYnVmX3NpemUgPSBtaW4oY291bnQsIGxl
biAtIDEpOw0KPiA+ICAgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2VyYnVmLCBidWZfc2l6
ZSkpIHsNCj4gPiAgICAgICAgICAgICByZXMgPSAtRUZBVUxUOw0KPiA+IEBAIC01MzIsNiArNjcw
LDExIEBAIHN0YXRpYyBzc2l6ZV90IGxic19yZGJicF9yZWFkKHN0cnVjdCBmaWxlICpmaWxlLCBj
aGFyIF9fdXNlciAqdXNlcmJ1ZiwNCj4gPiAgICAgaWYgKCFidWYpDQo+ID4gICAgICAgICAgICAg
cmV0dXJuIC1FTk9NRU07DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJp
dikpIHsNCj4gPiArICAgICAgICAgICBmcmVlX3BhZ2UoYWRkcik7DQo+ID4gKyAgICAgICAgICAg
cmV0dXJuIC1FQlVTWTsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgb2ZmdmFsLm9mZnNldCA9
IHByaXYtPmJicF9vZmZzZXQ7DQo+ID4gICAgIG9mZnZhbC52YWx1ZSA9IDA7DQo+ID4NCj4gPiBA
QCAtNTg1LDYgKzcyOCwxMSBAQCBzdGF0aWMgc3NpemVfdCBsYnNfd3JiYnBfd3JpdGUoc3RydWN0
IGZpbGUgKmZpbGUsDQo+ID4gICAgIGlmICghYnVmKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAt
RU5PTUVNOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+
ID4gKyAgICAgICAgICAgcmVzID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0X3Vu
bG9jazsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgYnVmX3NpemUgPSBtaW4oY291bnQsIGxl
biAtIDEpOw0KPiA+ICAgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2VyYnVmLCBidWZfc2l6
ZSkpIHsNCj4gPiAgICAgICAgICAgICByZXMgPSAtRUZBVUxUOw0KPiA+IEBAIC02MjEsNiArNzY5
LDExIEBAIHN0YXRpYyBzc2l6ZV90IGxic19yZHJmX3JlYWQoc3RydWN0IGZpbGUgKmZpbGUsIGNo
YXIgX191c2VyICp1c2VyYnVmLA0KPiA+ICAgICBpZiAoIWJ1ZikNCj4gPiAgICAgICAgICAgICBy
ZXR1cm4gLUVOT01FTTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2
KSkgew0KPiA+ICsgICAgICAgICAgIGZyZWVfcGFnZShhZGRyKTsNCj4gPiArICAgICAgICAgICBy
ZXR1cm4gLUVCVVNZOw0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBvZmZ2YWwub2Zmc2V0ID0g
cHJpdi0+cmZfb2Zmc2V0Ow0KPiA+ICAgICBvZmZ2YWwudmFsdWUgPSAwOw0KPiA+DQo+ID4gQEAg
LTY3NCw2ICs4MjcsMTEgQEAgc3RhdGljIHNzaXplX3QgbGJzX3dycmZfd3JpdGUoc3RydWN0IGZp
bGUgKmZpbGUsDQo+ID4gICAgIGlmICghYnVmKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRU5P
TUVNOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4g
KyAgICAgICAgICAgcmVzID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0X3VubG9j
azsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgYnVmX3NpemUgPSBtaW4oY291bnQsIGxlbiAt
IDEpOw0KPiA+ICAgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2VyYnVmLCBidWZfc2l6ZSkp
IHsNCj4gPiAgICAgICAgICAgICByZXMgPSAtRUZBVUxUOw0KPiA+IEBAIC03MTcsNiArODc1LDgg
QEAgc3RhdGljIGNvbnN0IHN0cnVjdCBsYnNfZGVidWdmc19maWxlcyBkZWJ1Z2ZzX2ZpbGVzW10g
PSB7DQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd3JpdGVfZmlsZV9k
dW1teSksIH0sDQo+ID4gICAgIHsgInNsZWVwcGFyYW1zIiwgMDY0NCwgRk9QUyhsYnNfc2xlZXBw
YXJhbXNfcmVhZCwNCj4gPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGJzX3NsZWVwcGFy
YW1zX3dyaXRlKSwgfSwNCj4gPiArICAgeyAiZGVlcHNsZWVwIiwgMDY0NCwgRk9QUyhsYnNfZGVl
cHNsZWVwX3JlYWQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIGxic19kZWVwc2xl
ZXBfd3JpdGUpLCB9LA0KPiA+ICB9Ow0KPiA+DQo+ID4gIHN0YXRpYyBjb25zdCBzdHJ1Y3QgbGJz
X2RlYnVnZnNfZmlsZXMgZGVidWdmc19ldmVudHNfZmlsZXNbXSA9IHsNCj4gPiBkaWZmIC0tZ2l0
IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGVjbC5oIGIvZHJpdmVycy9uZXQvd2ly
ZWxlc3MvbGliZXJ0YXMvZGVjbC5oDQo+ID4gaW5kZXggMGI4NGJkYy4uMzRiNDc1ZiAxMDA2NDQN
Cj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9kZWNsLmgNCj4gPiArKysg
Yi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9kZWNsLmgNCj4gPiBAQCAtMzMsNiArMzMs
MTAgQEAgaW50IGxic19leGVjdXRlX25leHRfY29tbWFuZChzdHJ1Y3QgbGJzX3ByaXZhdGUgKnBy
aXYpOw0KPiA+ICBpbnQgbGJzX3Byb2Nlc3NfZXZlbnQoc3RydWN0IGxic19wcml2YXRlICpwcml2
LCB1MzIgZXZlbnQpOw0KPiA+ICB2b2lkIGxic19xdWV1ZV9ldmVudChzdHJ1Y3QgbGJzX3ByaXZh
dGUgKnByaXYsIHUzMiBldmVudCk7DQo+ID4gIHZvaWQgbGJzX25vdGlmeV9jb21tYW5kX3Jlc3Bv
bnNlKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdiwgdTggcmVzcF9pZHgpOw0KPiA+ICtpbnQgbGJz
X3NldF9kZWVwX3NsZWVwKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdiwgaW50IGRlZXBfc2xlZXAp
Ow0KPiA+ICtpbnQgbGJzX2lzX2NtZF9hbGxvd2VkKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdik7
DQo+ID4gK2ludCBsYnNfZW50ZXJfYXV0b19kZWVwX3NsZWVwKHN0cnVjdCBsYnNfcHJpdmF0ZSAq
cHJpdik7DQo+ID4gK2ludCBsYnNfZXhpdF9hdXRvX2RlZXBfc2xlZXAoc3RydWN0IGxic19wcml2
YXRlICpwcml2KTsNCj4gPg0KPiA+ICB1MzIgbGJzX2Z3X2luZGV4X3RvX2RhdGFfcmF0ZSh1OCBp
bmRleCk7DQo+ID4gIHU4IGxic19kYXRhX3JhdGVfdG9fZndfaW5kZXgodTMyIHJhdGUpOw0KPiA+
IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9kZXYuaCBiL2RyaXZl
cnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2Rldi5oDQo+ID4gaW5kZXggNTc4YzY5Ny4uZTJiNGVm
MiAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9kZXYuaA0K
PiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2Rldi5oDQo+ID4gQEAgLTEy
OSw2ICsxMjksMjAgQEAgc3RydWN0IGxic19wcml2YXRlIHsNCj4gPiAgICAgdTMyIGJicF9vZmZz
ZXQ7DQo+ID4gICAgIHUzMiByZl9vZmZzZXQ7DQo+ID4NCj4gPiArICAgLyoqIERlZXAgc2xlZXAg
ZmxhZyAqLw0KPiA+ICsgICBpbnQgaXNfZGVlcF9zbGVlcDsNCj4gPiArICAgLyoqIEF1dG8gZGVl
cCBzbGVlcCBlbmFibGVkIGZsYWcgKi8NCj4gPiArICAgaW50IGlzX2F1dG9fZGVlcF9zbGVlcF9l
bmFibGVkOw0KPiA+ICsgICAvKiogRGV2aWNlIHdha2V1cCByZXF1aXJlZCBmbGFnICovDQo+ID4g
KyAgIGludCB3YWtldXBfZGV2X3JlcXVpcmVkOw0KPiA+ICsgICAvKiogQXV0byBkZWVwIHNsZWVw
IGZsYWcqLw0KPiA+ICsgICBpbnQgaXNfYWN0aXZpdHlfZGV0ZWN0ZWQ7DQo+ID4gKyAgIC8qKiBB
dXRvIGRlZXAgc2xlZXAgdGltZW91dCAoaW4gbWlsaXNlY29uZHMpICovDQo+ID4gKyAgIGludCBh
dXRvX2RlZXBfc2xlZXBfdGltZW91dDsNCj4gPiArDQo+ID4gKyAgIC8qKiBEZWVwIHNsZWVwIHdh
aXQgcXVldWUgKi8NCj4gPiArICAgd2FpdF9xdWV1ZV9oZWFkX3QgICAgICAgZHNfYXdha2VfcTsN
Cj4gPiArDQo+ID4gICAgIC8qIERvd25sb2FkIHNlbnQ6DQo+ID4gICAgICAgIGJpdDAgMS8wPWRh
dGFfc2VudC9kYXRhX3R4X2RvbmUsDQo+ID4gICAgICAgIGJpdDEgMS8wPWNtZF9zZW50L2NtZF90
eF9kb25lLA0KPiA+IEBAIC0xNTQsNiArMTY4LDkgQEAgc3RydWN0IGxic19wcml2YXRlIHsNCj4g
PiAgICAgLyoqIEhhcmR3YXJlIGFjY2VzcyAqLw0KPiA+ICAgICBpbnQgKCpod19ob3N0X3RvX2Nh
cmQpIChzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYsIHU4IHR5cGUsIHU4ICpwYXlsb2FkLCB1MTYg
bmIpOw0KPiA+ICAgICB2b2lkICgqcmVzZXRfY2FyZCkgKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJp
dik7DQo+ID4gKyAgIGludCAoKmVudGVyX2RlZXBfc2xlZXApIChzdHJ1Y3QgbGJzX3ByaXZhdGUg
KnByaXYpOw0KPiA+ICsgICBpbnQgKCpleGl0X2RlZXBfc2xlZXApIChzdHJ1Y3QgbGJzX3ByaXZh
dGUgKnByaXYpOw0KPiA+ICsgICBpbnQgKCpyZXNldF9kZWVwX3NsZWVwX3dha2V1cCkgKHN0cnVj
dCBsYnNfcHJpdmF0ZSAqcHJpdik7DQo+ID4NCj4gPiAgICAgLyogV2FrZSBPbiBMQU4gKi8NCj4g
PiAgICAgdWludDMyX3Qgd29sX2NyaXRlcmlhOw0KPiA+IEBAIC0yMDQsNiArMjIxLDcgQEAgc3Ry
dWN0IGxic19wcml2YXRlIHsNCj4gPg0KPiA+ICAgICAvKiogVGltZXJzICovDQo+ID4gICAgIHN0
cnVjdCB0aW1lcl9saXN0IGNvbW1hbmRfdGltZXI7DQo+ID4gKyAgIHN0cnVjdCB0aW1lcl9saXN0
IGF1dG9fZGVlcHNsZWVwX3RpbWVyOw0KPiA+ICAgICBpbnQgbnJfcmV0cmllczsNCj4gPiAgICAg
aW50IGNtZF90aW1lZF9vdXQ7DQo+ID4NCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9uZXQvd2ly
ZWxlc3MvbGliZXJ0YXMvaG9zdC5oIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaG9z
dC5oDQo+ID4gaW5kZXggZmU4ZjBjYi4uYzA1NWRhYSAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJz
L25ldC93aXJlbGVzcy9saWJlcnRhcy9ob3N0LmgNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJl
bGVzcy9saWJlcnRhcy9ob3N0LmgNCj4gPiBAQCAtNTcsNiArNTcsNyBAQA0KPiA+ICAjZGVmaW5l
IENNRF84MDJfMTFfRU5BQkxFX1JTTiAgICAgICAgICAgICAgICAgICAgICAweDAwMmYNCj4gPiAg
I2RlZmluZSBDTURfODAyXzExX1NFVF9BRkMgICAgICAgICAgICAgICAgIDB4MDAzYw0KPiA+ICAj
ZGVmaW5lIENNRF84MDJfMTFfR0VUX0FGQyAgICAgICAgICAgICAgICAgMHgwMDNkDQo+ID4gKyNk
ZWZpbmUgQ01EXzgwMl8xMV9ERUVQX1NMRUVQICAgICAgICAgICAgICAgICAgMHgwMDNlDQo+ID4g
ICNkZWZpbmUgQ01EXzgwMl8xMV9BRF9IT0NfU1RPUCAgICAgICAgICAgICAgICAgICAgIDB4MDA0
MA0KPiA+ICAjZGVmaW5lIENNRF84MDJfMTFfSE9TVF9TTEVFUF9DRkcgICAgICAgICAgMHgwMDQz
DQo+ID4gICNkZWZpbmUgQ01EXzgwMl8xMV9XQUtFVVBfQ09ORklSTSAgICAgICAgICAweDAwNDQN
Cj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfY3MuYyBi
L2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX2NzLmMNCj4gPiBpbmRleCA2MjM4MTc2
Li40NjU3NDJmIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFz
L2lmX2NzLmMNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9jcy5j
DQo+ID4gQEAgLTk0Niw2ICs5NDYsOSBAQCBzdGF0aWMgaW50IGlmX2NzX3Byb2JlKHN0cnVjdCBw
Y21jaWFfZGV2aWNlICpwX2RldikNCj4gPiAgICAgY2FyZC0+cHJpdiA9IHByaXY7DQo+ID4gICAg
IHByaXYtPmNhcmQgPSBjYXJkOw0KPiA+ICAgICBwcml2LT5od19ob3N0X3RvX2NhcmQgPSBpZl9j
c19ob3N0X3RvX2NhcmQ7DQo+ID4gKyAgIHByaXYtPmVudGVyX2RlZXBfc2xlZXAgPSBOVUxMOw0K
PiA+ICsgICBwcml2LT5leGl0X2RlZXBfc2xlZXAgPSBOVUxMOw0KPiA+ICsgICBwcml2LT5yZXNl
dF9kZWVwX3NsZWVwX3dha2V1cCA9IE5VTEw7DQo+ID4gICAgIHByaXYtPmZ3X3JlYWR5ID0gMTsN
Cj4gPg0KPiA+ICAgICAvKiBOb3cgYWN0dWFsbHkgZ2V0IHRoZSBJUlEgKi8NCj4gPiBkaWZmIC0t
Z2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc2Rpby5jIGIvZHJpdmVycy9u
ZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc2Rpby5jDQo+ID4gaW5kZXggNDg1YThkNC4uOTcxNjcy
OCAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9zZGlv
LmMNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9zZGlvLmMNCj4g
PiBAQCAtODMxLDYgKzgzMSw1OCBAQCBvdXQ6DQo+ID4gICAgIHJldHVybiByZXQ7DQo+ID4gIH0N
Cj4gPg0KPiA+ICtzdGF0aWMgaW50IGlmX3NkaW9fZW50ZXJfZGVlcF9zbGVlcChzdHJ1Y3QgbGJz
X3ByaXZhdGUgKnByaXYpDQo+ID4gK3sNCj4gPiArICAgaW50IHJldCA9IC0xOw0KPiA+ICsgICBz
dHJ1Y3QgY21kX2hlYWRlciBjbWQ7DQo+ID4gKw0KPiA+ICsgICBtZW1zZXQoJmNtZCwgMCwgc2l6
ZW9mKGNtZCkpOw0KPiA+ICsNCj4gPiArICAgbGJzX2RlYl9zZGlvKCJzZW5kIERFRVBfU0xFRVAg
Y29tbWFuZFxuIik7DQo+ID4gKyAgIHJldCA9IF9fbGJzX2NtZChwcml2LCBDTURfODAyXzExX0RF
RVBfU0xFRVAsICZjbWQsIHNpemVvZihjbWQpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgbGJz
X2NtZF9jb3B5YmFjaywgKHVuc2lnbmVkIGxvbmcpICZjbWQpOw0KPiA+ICsgICBpZiAocmV0KQ0K
PiA+ICsgICAgICAgICAgIGxic19wcl9lcnIoIkRFRVBfU0xFRVAgY21kIGZhaWxlZFxuIik7DQo+
ID4gKw0KPiA+ICsgICBtZGVsYXkoMjAwKTsNCj4gPiArICAgcmV0dXJuIHJldDsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArc3RhdGljIGludCBpZl9zZGlvX2V4aXRfZGVlcF9zbGVlcChzdHJ1Y3QgbGJz
X3ByaXZhdGUgKnByaXYpDQo+ID4gK3sNCj4gPiArICAgc3RydWN0IGlmX3NkaW9fY2FyZCAqY2Fy
ZCA9IHByaXYtPmNhcmQ7DQo+ID4gKyAgIGludCByZXQgPSAtMTsNCj4gPiArDQo+ID4gKyAgIGxi
c19kZWJfZW50ZXIoTEJTX0RFQl9TRElPKTsNCj4gPiArICAgc2Rpb19jbGFpbV9ob3N0KGNhcmQt
PmZ1bmMpOw0KPiA+ICsNCj4gPiArICAgc2Rpb193cml0ZWIoY2FyZC0+ZnVuYywgSE9TVF9QT1dF
Ul9VUCwgQ09ORklHVVJBVElPTl9SRUcsICZyZXQpOw0KPiA+ICsgICBpZiAocmV0KQ0KPiA+ICsg
ICAgICAgICAgIGxic19wcl9lcnIoInNkaW9fd3JpdGViIGZhaWxlZCFcbiIpOw0KPiA+ICsNCj4g
PiArICAgc2Rpb19yZWxlYXNlX2hvc3QoY2FyZC0+ZnVuYyk7DQo+ID4gKyAgIGxic19kZWJfbGVh
dmVfYXJncyhMQlNfREVCX1NESU8sICJyZXQgJWQiLCByZXQpOw0KPiA+ICsgICByZXR1cm4gcmV0
Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGlmX3NkaW9fcmVzZXRfZGVlcF9zbGVl
cF93YWtldXAoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0KPiA+ICt7DQo+ID4gKyAgIHN0cnVj
dCBpZl9zZGlvX2NhcmQgKmNhcmQgPSBwcml2LT5jYXJkOw0KPiA+ICsgICBpbnQgcmV0ID0gLTE7
DQo+ID4gKw0KPiA+ICsgICBsYnNfZGViX2VudGVyKExCU19ERUJfU0RJTyk7DQo+ID4gKyAgIHNk
aW9fY2xhaW1faG9zdChjYXJkLT5mdW5jKTsNCj4gPiArDQo+ID4gKyAgIHNkaW9fd3JpdGViKGNh
cmQtPmZ1bmMsIDAsIENPTkZJR1VSQVRJT05fUkVHLCAmcmV0KTsNCj4gPiArICAgaWYgKHJldCkN
Cj4gPiArICAgICAgICAgICBsYnNfcHJfZXJyKCJzZGlvX3dyaXRlYiBmYWlsZWQhXG4iKTsNCj4g
PiArDQo+ID4gKyAgIHNkaW9fcmVsZWFzZV9ob3N0KGNhcmQtPmZ1bmMpOw0KPiA+ICsgICBsYnNf
ZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9TRElPLCAicmV0ICVkIiwgcmV0KTsNCj4gPiArICAgcmV0
dXJuIHJldDsNCj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4gIC8qKioqKioqKioqKioqKioqKioq
KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLw0KPiA+ICAv
KiBTRElPIGNhbGxiYWNrcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgKi8NCj4gPiAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
KioqKioqKioqKioqKioqKioqKioqKioqKioqKiovDQo+ID4gQEAgLTg1OSw2ICs5MTEsNyBAQCBz
dGF0aWMgdm9pZCBpZl9zZGlvX2ludGVycnVwdChzdHJ1Y3Qgc2Rpb19mdW5jICpmdW5jKQ0KPiA+
ICAgICAgKiBJZ25vcmUgdGhlIGRlZmluZSBuYW1lLCB0aGlzIHJlYWxseSBtZWFucyB0aGUgY2Fy
ZCBoYXMNCj4gPiAgICAgICogc3VjY2Vzc2Z1bGx5IHJlY2VpdmVkIHRoZSBjb21tYW5kLg0KPiA+
ICAgICAgKi8NCj4gPiArICAgY2FyZC0+cHJpdi0+aXNfYWN0aXZpdHlfZGV0ZWN0ZWQgPSAxOw0K
PiA+ICAgICBpZiAoY2F1c2UgJiBJRl9TRElPX0hfSU5UX0ROTEQpDQo+ID4gICAgICAgICAgICAg
bGJzX2hvc3RfdG9fY2FyZF9kb25lKGNhcmQtPnByaXYpOw0KPiA+DQo+ID4gQEAgLTk5OCw2ICsx
MDUxLDkgQEAgc3RhdGljIGludCBpZl9zZGlvX3Byb2JlKHN0cnVjdCBzZGlvX2Z1bmMgKmZ1bmMs
DQo+ID4NCj4gPiAgICAgcHJpdi0+Y2FyZCA9IGNhcmQ7DQo+ID4gICAgIHByaXYtPmh3X2hvc3Rf
dG9fY2FyZCA9IGlmX3NkaW9faG9zdF90b19jYXJkOw0KPiA+ICsgICBwcml2LT5lbnRlcl9kZWVw
X3NsZWVwID0gaWZfc2Rpb19lbnRlcl9kZWVwX3NsZWVwOw0KPiA+ICsgICBwcml2LT5leGl0X2Rl
ZXBfc2xlZXAgPSBpZl9zZGlvX2V4aXRfZGVlcF9zbGVlcDsNCj4gPiArICAgcHJpdi0+cmVzZXRf
ZGVlcF9zbGVlcF93YWtldXAgPSBpZl9zZGlvX3Jlc2V0X2RlZXBfc2xlZXBfd2FrZXVwOw0KPiA+
DQo+ID4gICAgIHByaXYtPmZ3X3JlYWR5ID0gMTsNCj4gPg0KPiA+IGRpZmYgLS1naXQgYS9kcml2
ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9zZGlvLmggYi9kcml2ZXJzL25ldC93aXJlbGVz
cy9saWJlcnRhcy9pZl9zZGlvLmgNCj4gPiBpbmRleCA2MGM5YjJmLi4xMjE3OWMxIDEwMDY0NA0K
PiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3NkaW8uaA0KPiA+ICsr
KyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3NkaW8uaA0KPiA+IEBAIC01MSw1
ICs1MSw2IEBADQo+ID4gICNkZWZpbmUgSUZfU0RJT19FVkVOVCAgICAgICAgICAgMHg4MGZjDQo+
ID4NCj4gPiAgI2RlZmluZSBJRl9TRElPX0JMT0NLX1NJWkUgMjU2DQo+ID4gLQ0KPiA+ICsjZGVm
aW5lIENPTkZJR1VSQVRJT05fUkVHICAgICAgICAgICAgICAgMHgwMw0KPiA+ICsjZGVmaW5lIEhP
U1RfUE9XRVJfVVAgICAgICAgICAgICAgICAgICAgKDB4MVUgPDwgMSkNCj4gPiAgI2VuZGlmDQo+
ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3NwaS5jIGIv
ZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc3BpLmMNCj4gPiBpbmRleCA0NDZlMzI3
Li5lMmZhNjU3IDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFz
L2lmX3NwaS5jDQo+ID4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc3Bp
LmMNCj4gPiBAQCAtMTExNyw2ICsxMTE3LDkgQEAgc3RhdGljIGludCBfX2RldmluaXQgaWZfc3Bp
X3Byb2JlKHN0cnVjdCBzcGlfZGV2aWNlICpzcGkpDQo+ID4gICAgIGNhcmQtPnByaXYgPSBwcml2
Ow0KPiA+ICAgICBwcml2LT5jYXJkID0gY2FyZDsNCj4gPiAgICAgcHJpdi0+aHdfaG9zdF90b19j
YXJkID0gaWZfc3BpX2hvc3RfdG9fY2FyZDsNCj4gPiArICAgcHJpdi0+ZW50ZXJfZGVlcF9zbGVl
cCA9IE5VTEw7DQo+ID4gKyAgIHByaXYtPmV4aXRfZGVlcF9zbGVlcCA9IE5VTEw7DQo+ID4gKyAg
IHByaXYtPnJlc2V0X2RlZXBfc2xlZXBfd2FrZXVwID0gTlVMTDsNCj4gPiAgICAgcHJpdi0+Zndf
cmVhZHkgPSAxOw0KPiA+DQo+ID4gICAgIC8qIEluaXRpYWxpemUgaW50ZXJydXB0IGhhbmRsaW5n
IHN0dWZmLiAqLw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRh
cy9pZl91c2IuYyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3VzYi5jDQo+ID4g
aW5kZXggOTJiYzhjNS4uYTgyNjJkZSAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJl
bGVzcy9saWJlcnRhcy9pZl91c2IuYw0KPiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xp
YmVydGFzL2lmX3VzYi5jDQo+ID4gQEAgLTMwMCw2ICszMDAsOSBAQCBzdGF0aWMgaW50IGlmX3Vz
Yl9wcm9iZShzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZiwNCj4gPiAgICAgY2FyZHAtPnByaXYt
PmZ3X3JlYWR5ID0gMTsNCj4gPg0KPiA+ICAgICBwcml2LT5od19ob3N0X3RvX2NhcmQgPSBpZl91
c2JfaG9zdF90b19jYXJkOw0KPiA+ICsgICBwcml2LT5lbnRlcl9kZWVwX3NsZWVwID0gTlVMTDsN
Cj4gPiArICAgcHJpdi0+ZXhpdF9kZWVwX3NsZWVwID0gTlVMTDsNCj4gPiArICAgcHJpdi0+cmVz
ZXRfZGVlcF9zbGVlcF93YWtldXAgPSBOVUxMOw0KPiA+ICAjaWZkZWYgQ09ORklHX09MUEMNCj4g
PiAgICAgaWYgKG1hY2hpbmVfaXNfb2xwYygpKQ0KPiA+ICAgICAgICAgICAgIHByaXYtPnJlc2V0
X2NhcmQgPSBpZl91c2JfcmVzZXRfb2xwY19jYXJkOw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJz
L25ldC93aXJlbGVzcy9saWJlcnRhcy9tYWluLmMgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJl
cnRhcy9tYWluLmMNCj4gPiBpbmRleCA4ZGYxY2ZkLi4zYjE0ZmNjIDEwMDY0NA0KPiA+IC0tLSBh
L2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL21haW4uYw0KPiA+ICsrKyBiL2RyaXZlcnMv
bmV0L3dpcmVsZXNzL2xpYmVydGFzL21haW4uYw0KPiA+IEBAIC01NzQsOCArNTc0LDEwIEBAIHZv
aWQgbGJzX2hvc3RfdG9fY2FyZF9kb25lKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdikNCj4gPiAg
ICAgcHJpdi0+ZG5sZF9zZW50ID0gRE5MRF9SRVNfUkVDRUlWRUQ7DQo+ID4NCj4gPiAgICAgLyog
V2FrZSBtYWluIHRocmVhZCBpZiBjb21tYW5kcyBhcmUgcGVuZGluZyAqLw0KPiA+IC0gICBpZiAo
IXByaXYtPmN1cl9jbWQgfHwgcHJpdi0+dHhfcGVuZGluZ19sZW4gPiAwKQ0KPiA+IC0gICAgICAg
ICAgIHdha2VfdXBfaW50ZXJydXB0aWJsZSgmcHJpdi0+d2FpdHEpOw0KPiA+ICsgICBpZiAoIXBy
aXYtPmN1cl9jbWQgfHwgcHJpdi0+dHhfcGVuZGluZ19sZW4gPiAwKSB7DQo+ID4gKyAgICAgICAg
ICAgaWYgKCFwcml2LT53YWtldXBfZGV2X3JlcXVpcmVkKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgd2FrZV91cF9pbnRlcnJ1cHRpYmxlKCZwcml2LT53YWl0cSk7DQo+ID4gKyAgIH0NCj4gPg0K
PiA+ICAgICBzcGluX3VubG9ja19pcnFyZXN0b3JlKCZwcml2LT5kcml2ZXJfbG9jaywgZmxhZ3Mp
Ow0KPiA+ICAgICBsYnNfZGViX2xlYXZlKExCU19ERUJfVEhSRUFEKTsNCj4gPiBAQCAtNzcwLDcg
Kzc3Miw4IEBAIHN0YXRpYyBpbnQgbGJzX3RocmVhZCh2b2lkICpkYXRhKQ0KPiA+ICAgICAgICAg
ICAgICAgICAgICAgc2hvdWxkc2xlZXAgPSAwOyAgICAgICAgLyogV2UgaGF2ZSBhIGNvbW1hbmQg
cmVzcG9uc2UgKi8NCj4gPiAgICAgICAgICAgICBlbHNlIGlmIChwcml2LT5jdXJfY21kKQ0KPiA+
ICAgICAgICAgICAgICAgICAgICAgc2hvdWxkc2xlZXAgPSAxOyAgICAgICAgLyogQ2FuJ3Qgc2Vu
ZCBhIGNvbW1hbmQ7IG9uZSBhbHJlYWR5IHJ1bm5pbmcgKi8NCj4gPiAtICAgICAgICAgICBlbHNl
IGlmICghbGlzdF9lbXB0eSgmcHJpdi0+Y21kcGVuZGluZ3EpKQ0KPiA+ICsgICAgICAgICAgIGVs
c2UgaWYgKCFsaXN0X2VtcHR5KCZwcml2LT5jbWRwZW5kaW5ncSkgJiYNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAhKHByaXYtPndha2V1cF9kZXZfcmVxdWlyZWQpKQ0K
PiA+ICAgICAgICAgICAgICAgICAgICAgc2hvdWxkc2xlZXAgPSAwOyAgICAgICAgLyogV2UgaGF2
ZSBhIGNvbW1hbmQgdG8gc2VuZCAqLw0KPiA+ICAgICAgICAgICAgIGVsc2UgaWYgKF9fa2ZpZm9f
bGVuKHByaXYtPmV2ZW50X2ZpZm8pKQ0KPiA+ICAgICAgICAgICAgICAgICAgICAgc2hvdWxkc2xl
ZXAgPSAwOyAgICAgICAgLyogV2UgaGF2ZSBhbiBldmVudCB0byBwcm9jZXNzICovDQo+ID4gQEAg
LTgyMiw2ICs4MjUsMjYgQEAgc3RhdGljIGludCBsYnNfdGhyZWFkKHZvaWQgKmRhdGEpDQo+ID4g
ICAgICAgICAgICAgfQ0KPiA+ICAgICAgICAgICAgIHNwaW5fdW5sb2NrX2lycSgmcHJpdi0+ZHJp
dmVyX2xvY2spOw0KPiA+DQo+ID4gKyAgICAgICAgICAgLyogUHJvY2VzcyBoYXJkd2FyZSBldmVu
dHMsIGUuZy4gY2FyZCByZW1vdmVkLCBsaW5rIGxvc3QgKi8NCj4gPiArICAgICAgICAgICBzcGlu
X2xvY2tfaXJxKCZwcml2LT5kcml2ZXJfbG9jayk7DQo+ID4gKyAgICAgICAgICAgd2hpbGUgKF9f
a2ZpZm9fbGVuKHByaXYtPmV2ZW50X2ZpZm8pKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICB1
MzIgZXZlbnQ7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBfX2tmaWZvX2dldChwcml2LT5ldmVu
dF9maWZvLCAodW5zaWduZWQgY2hhciAqKSAmZXZlbnQsDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgIHNpemVvZihldmVudCkpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgc3Bpbl91
bmxvY2tfaXJxKCZwcml2LT5kcml2ZXJfbG9jayk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBs
YnNfcHJvY2Vzc19ldmVudChwcml2LCBldmVudCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBz
cGluX2xvY2tfaXJxKCZwcml2LT5kcml2ZXJfbG9jayk7DQo+ID4gKyAgICAgICAgICAgfQ0KPiA+
ICsgICAgICAgICAgIHNwaW5fdW5sb2NrX2lycSgmcHJpdi0+ZHJpdmVyX2xvY2spOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICBpZiAocHJpdi0+d2FrZXVwX2Rldl9yZXF1aXJlZCkgew0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgbGJzX2RlYl90aHJlYWQoIldha2luZyB1cCBkZXZpY2UuLi5cbiIp
Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgLyogV2FrZSB1cCBkZXZpY2UgKi8NCj4gPiArICAg
ICAgICAgICAgICAgICAgIGlmIChwcml2LT5leGl0X2RlZXBfc2xlZXAocHJpdikpDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgIGxic19kZWJfdGhyZWFkKCJXYWtldXAgZGV2aWNlIGZh
aWxlZFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBjb250aW51ZTsNCj4gPiArICAgICAg
ICAgICB9DQo+ID4gKw0KPiA+ICAgICAgICAgICAgIC8qIGNvbW1hbmQgdGltZW91dCBzdHVmZiAq
Lw0KPiA+ICAgICAgICAgICAgIGlmIChwcml2LT5jbWRfdGltZWRfb3V0ICYmIHByaXYtPmN1cl9j
bWQpIHsNCj4gPiAgICAgICAgICAgICAgICAgICAgIHN0cnVjdCBjbWRfY3RybF9ub2RlICpjbWRu
b2RlID0gcHJpdi0+Y3VyX2NtZDsNCj4gPiBAQCAtODQ5LDE4ICs4NzIsNyBAQCBzdGF0aWMgaW50
IGxic190aHJlYWQodm9pZCAqZGF0YSkNCj4gPiAgICAgICAgICAgICB9DQo+ID4gICAgICAgICAg
ICAgcHJpdi0+Y21kX3RpbWVkX291dCA9IDA7DQo+ID4NCj4gPiAtICAgICAgICAgICAvKiBQcm9j
ZXNzIGhhcmR3YXJlIGV2ZW50cywgZS5nLiBjYXJkIHJlbW92ZWQsIGxpbmsgbG9zdCAqLw0KPiA+
IC0gICAgICAgICAgIHNwaW5fbG9ja19pcnEoJnByaXYtPmRyaXZlcl9sb2NrKTsNCj4gPiAtICAg
ICAgICAgICB3aGlsZSAoX19rZmlmb19sZW4ocHJpdi0+ZXZlbnRfZmlmbykpIHsNCj4gPiAtICAg
ICAgICAgICAgICAgICAgIHUzMiBldmVudDsNCj4gPg0KPiA+IC0gICAgICAgICAgICAgICAgICAg
X19rZmlmb19nZXQocHJpdi0+ZXZlbnRfZmlmbywgKHVuc2lnbmVkIGNoYXIgKikgJmV2ZW50LA0K
PiA+IC0gICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplb2YoZXZlbnQpKTsNCj4gPiAtICAg
ICAgICAgICAgICAgICAgIHNwaW5fdW5sb2NrX2lycSgmcHJpdi0+ZHJpdmVyX2xvY2spOw0KPiA+
IC0gICAgICAgICAgICAgICAgICAgbGJzX3Byb2Nlc3NfZXZlbnQocHJpdiwgZXZlbnQpOw0KPiA+
IC0gICAgICAgICAgICAgICAgICAgc3Bpbl9sb2NrX2lycSgmcHJpdi0+ZHJpdmVyX2xvY2spOw0K
PiA+IC0gICAgICAgICAgIH0NCj4gPiAtICAgICAgICAgICBzcGluX3VubG9ja19pcnEoJnByaXYt
PmRyaXZlcl9sb2NrKTsNCj4gPg0KPiA+ICAgICAgICAgICAgIGlmICghcHJpdi0+ZndfcmVhZHkp
DQo+ID4gICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsNCj4gPiBAQCAtODk0LDYgKzkwNiw5
IEBAIHN0YXRpYyBpbnQgbGJzX3RocmVhZCh2b2lkICpkYXRhKQ0KPiA+ICAgICAgICAgICAgICAg
ICAocHJpdi0+cHNzdGF0ZSA9PSBQU19TVEFURV9QUkVfU0xFRVApKQ0KPiA+ICAgICAgICAgICAg
ICAgICAgICAgY29udGludWU7DQo+ID4NCj4gPiArICAgICAgICAgICBpZiAocHJpdi0+aXNfZGVl
cF9zbGVlcCkNCj4gPiArICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOw0KPiA+ICsNCj4gPiAg
ICAgICAgICAgICAvKiBFeGVjdXRlIHRoZSBuZXh0IGNvbW1hbmQgKi8NCj4gPiAgICAgICAgICAg
ICBpZiAoIXByaXYtPmRubGRfc2VudCAmJiAhcHJpdi0+Y3VyX2NtZCkNCj4gPiAgICAgICAgICAg
ICAgICAgICAgIGxic19leGVjdXRlX25leHRfY29tbWFuZChwcml2KTsNCj4gPiBAQCAtOTI4LDYg
Kzk0Myw3IEBAIHN0YXRpYyBpbnQgbGJzX3RocmVhZCh2b2lkICpkYXRhKQ0KPiA+ICAgICB9DQo+
ID4NCj4gPiAgICAgZGVsX3RpbWVyKCZwcml2LT5jb21tYW5kX3RpbWVyKTsNCj4gPiArICAgZGVs
X3RpbWVyKCZwcml2LT5hdXRvX2RlZXBzbGVlcF90aW1lcik7DQo+ID4gICAgIHdha2VfdXBfYWxs
KCZwcml2LT5jbWRfcGVuZGluZyk7DQo+ID4NCj4gPiAgICAgbGJzX2RlYl9sZWF2ZShMQlNfREVC
X1RIUkVBRCk7DQo+ID4gQEAgLTEwNTAsNiArMTA2Niw2MCBAQCBvdXQ6DQo+ID4gICAgIGxic19k
ZWJfbGVhdmUoTEJTX0RFQl9DTUQpOw0KPiA+ICB9DQo+ID4NCj4gPiArLyoqDQo+ID4gKyAqICBU
aGlzIGZ1bmN0aW9uIHB1dCB0aGUgZGV2aWNlIGJhY2sgdG8gZGVlcCBzbGVlcCBtb2RlIHdoZW4g
dGltZXIgZXhwaXJlcw0KPiA+ICsgKiAgYW5kIG5vIGFjdGl2aXR5IChjb21tYW5kLCBldmVudCwg
ZGF0YSBldGMuKSBpcyBkZXRlY3RlZC4NCj4gPiArICovDQo+ID4gK3N0YXRpYyB2b2lkIGF1dG9f
ZGVlcHNsZWVwX3RpbWVyX2ZuKHVuc2lnbmVkIGxvbmcgZGF0YSkNCj4gPiArew0KPiA+ICsgICBz
dHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYgPSAoc3RydWN0IGxic19wcml2YXRlICopZGF0YTsNCj4g
PiArICAgaW50IHJldDsNCj4gPiArDQo+ID4gKyAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9DTUQp
Ow0KPiA+ICsNCj4gPiArICAgaWYgKHByaXYtPmlzX2FjdGl2aXR5X2RldGVjdGVkKSB7DQo+ID4g
KyAgICAgICAgICAgcHJpdi0+aXNfYWN0aXZpdHlfZGV0ZWN0ZWQgPSAwOw0KPiA+ICsgICB9IGVs
c2Ugew0KPiA+ICsgICAgICAgICAgIGlmIChwcml2LT5pc19hdXRvX2RlZXBfc2xlZXBfZW5hYmxl
ZCAmJg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAoIXByaXYtPndha2V1cF9kZXZf
cmVxdWlyZWQpICYmDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIChwcml2LT5jb25u
ZWN0X3N0YXR1cyAhPSBMQlNfQ09OTkVDVEVEKSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAg
bGJzX2RlYl9tYWluKCJFbnRlcmluZyBhdXRvIGRlZXAgc2xlZXAgbW9kZS4uLlxuIik7DQo+ID4g
KyAgICAgICAgICAgICAgICAgICByZXQgPSBsYnNfcHJlcGFyZV9hbmRfc2VuZF9jb21tYW5kKHBy
aXYsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ01EXzgwMl8xMV9E
RUVQX1NMRUVQLCAwLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAs
IDAsIE5VTEwpOw0KPiA+ICsgICAgICAgICAgIH0NCj4gPiArICAgfQ0KPiA+ICsgICBtb2RfdGlt
ZXIoJnByaXYtPmF1dG9fZGVlcHNsZWVwX3RpbWVyICwgamlmZmllcyArDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgIChwcml2LT5hdXRvX2RlZXBfc2xlZXBfdGltZW91dCAqIEhaKS8x
MDAwKTsNCj4gPiArICAgbGJzX2RlYl9sZWF2ZShMQlNfREVCX0NNRCk7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK2ludCBsYnNfZW50ZXJfYXV0b19kZWVwX3NsZWVwKHN0cnVjdCBsYnNfcHJpdmF0ZSAq
cHJpdikNCj4gPiArew0KPiA+ICsgICBsYnNfZGViX2VudGVyKExCU19ERUJfU0RJTyk7DQo+ID4g
Kw0KPiA+ICsgICBwcml2LT5pc19hdXRvX2RlZXBfc2xlZXBfZW5hYmxlZCA9IDE7DQo+ID4gKyAg
IGlmIChwcml2LT5pc19kZWVwX3NsZWVwKQ0KPiA+ICsgICAgICAgICAgIHByaXYtPndha2V1cF9k
ZXZfcmVxdWlyZWQgPSAxOw0KPiA+ICsgICBtb2RfdGltZXIoJnByaXYtPmF1dG9fZGVlcHNsZWVw
X3RpbWVyICwNCj4gPiArICAgICAgICAgICAgICAgICAgIGppZmZpZXMgKyAocHJpdi0+YXV0b19k
ZWVwX3NsZWVwX3RpbWVvdXQgKiBIWikvMTAwMCk7DQo+ID4gKw0KPiA+ICsgICBsYnNfZGViX2xl
YXZlKExCU19ERUJfU0RJTyk7DQo+ID4gKyAgIHJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+
ICtpbnQgbGJzX2V4aXRfYXV0b19kZWVwX3NsZWVwKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdikN
Cj4gPiArew0KPiA+ICsgICBsYnNfZGViX2VudGVyKExCU19ERUJfU0RJTyk7DQo+ID4gKw0KPiA+
ICsgICBwcml2LT5pc19hdXRvX2RlZXBfc2xlZXBfZW5hYmxlZCA9IDA7DQo+ID4gKyAgIHByaXYt
PmF1dG9fZGVlcF9zbGVlcF90aW1lb3V0ID0gMDsNCj4gPiArICAgZGVsX3RpbWVyKCZwcml2LT5h
dXRvX2RlZXBzbGVlcF90aW1lcik7DQo+ID4gKw0KPiA+ICsgICBsYnNfZGViX2xlYXZlKExCU19E
RUJfU0RJTyk7DQo+ID4gKyAgIHJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICBzdGF0aWMg
dm9pZCBsYnNfc3luY19jaGFubmVsX3dvcmtlcihzdHJ1Y3Qgd29ya19zdHJ1Y3QgKndvcmspDQo+
ID4gIHsNCj4gPiAgICAgc3RydWN0IGxic19wcml2YXRlICpwcml2ID0gY29udGFpbmVyX29mKHdv
cmssIHN0cnVjdCBsYnNfcHJpdmF0ZSwNCj4gPiBAQCAtMTA5OSwxMSArMTE2OSwxNyBAQCBzdGF0
aWMgaW50IGxic19pbml0X2FkYXB0ZXIoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0KPiA+ICAg
ICBwcml2LT5jYXBhYmlsaXR5ID0gV0xBTl9DQVBBQklMSVRZX1NIT1JUX1BSRUFNQkxFOw0KPiA+
ICAgICBwcml2LT5wc21vZGUgPSBMQlM4MDJfMTFQT1dFUk1PREVDQU07DQo+ID4gICAgIHByaXYt
PnBzc3RhdGUgPSBQU19TVEFURV9GVUxMX1BPV0VSOw0KPiA+ICsgICBwcml2LT5pc19kZWVwX3Ns
ZWVwID0gMDsNCj4gPiArICAgcHJpdi0+aXNfYXV0b19kZWVwX3NsZWVwX2VuYWJsZWQgPSAwOw0K
PiA+ICsgICBwcml2LT53YWtldXBfZGV2X3JlcXVpcmVkID0gMDsNCj4gPiArICAgaW5pdF93YWl0
cXVldWVfaGVhZCgmcHJpdi0+ZHNfYXdha2VfcSk7DQo+ID4NCj4gPiAgICAgbXV0ZXhfaW5pdCgm
cHJpdi0+bG9jayk7DQo+ID4NCj4gPiAgICAgc2V0dXBfdGltZXIoJnByaXYtPmNvbW1hbmRfdGlt
ZXIsIGNvbW1hbmRfdGltZXJfZm4sDQo+ID4gICAgICAgICAgICAgKHVuc2lnbmVkIGxvbmcpcHJp
dik7DQo+ID4gKyAgIHNldHVwX3RpbWVyKCZwcml2LT5hdXRvX2RlZXBzbGVlcF90aW1lciwgYXV0
b19kZWVwc2xlZXBfdGltZXJfZm4sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAodW5zaWduZWQg
bG9uZylwcml2KTsNCj4gPg0KPiA+ICAgICBJTklUX0xJU1RfSEVBRCgmcHJpdi0+Y21kZnJlZXEp
Ow0KPiA+ICAgICBJTklUX0xJU1RfSEVBRCgmcHJpdi0+Y21kcGVuZGluZ3EpOw0KPiA+IEBAIC0x
MTQyLDYgKzEyMTgsNyBAQCBzdGF0aWMgdm9pZCBsYnNfZnJlZV9hZGFwdGVyKHN0cnVjdCBsYnNf
cHJpdmF0ZSAqcHJpdikNCj4gPiAgICAgaWYgKHByaXYtPmV2ZW50X2ZpZm8pDQo+ID4gICAgICAg
ICAgICAga2ZpZm9fZnJlZShwcml2LT5ldmVudF9maWZvKTsNCj4gPiAgICAgZGVsX3RpbWVyKCZw
cml2LT5jb21tYW5kX3RpbWVyKTsNCj4gPiArICAgZGVsX3RpbWVyKCZwcml2LT5hdXRvX2RlZXBz
bGVlcF90aW1lcik7DQo+ID4gICAgIGtmcmVlKHByaXYtPm5ldHdvcmtzKTsNCj4gPiAgICAgcHJp
di0+bmV0d29ya3MgPSBOVUxMOw0KPiA+DQo+ID4gQEAgLTEyNzIsNiArMTM0OSwxMSBAQCB2b2lk
IGxic19yZW1vdmVfY2FyZChzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYpDQo+ID4gICAgIHdycXUu
YXBfYWRkci5zYV9mYW1pbHkgPSBBUlBIUkRfRVRIRVI7DQo+ID4gICAgIHdpcmVsZXNzX3NlbmRf
ZXZlbnQocHJpdi0+ZGV2LCBTSU9DR0lXQVAsICZ3cnF1LCBOVUxMKTsNCj4gPg0KPiA+ICsgICBp
ZiAocHJpdi0+aXNfZGVlcF9zbGVlcCkgew0KPiA+ICsgICAgICAgICAgIHByaXYtPmlzX2RlZXBf
c2xlZXAgPSAwOw0KPiA+ICsgICAgICAgICAgIHdha2VfdXBfaW50ZXJydXB0aWJsZSgmcHJpdi0+
ZHNfYXdha2VfcSk7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIC8qIFN0b3AgdGhlIHRocmVh
ZCBzZXJ2aWNpbmcgdGhlIGludGVycnVwdHMgKi8NCj4gPiAgICAgcHJpdi0+c3VycHJpc2VyZW1v
dmVkID0gMTsNCj4gPiAgICAga3RocmVhZF9zdG9wKHByaXYtPm1haW5fdGhyZWFkKTsNCj4gPiBA
QCAtMTM5Miw2ICsxNDc0LDcgQEAgdm9pZCBsYnNfc3RvcF9jYXJkKHN0cnVjdCBsYnNfcHJpdmF0
ZSAqcHJpdikNCj4gPg0KPiA+ICAgICAvKiBEZWxldGUgdGhlIHRpbWVvdXQgb2YgdGhlIGN1cnJl
bnRseSBwcm9jZXNzaW5nIGNvbW1hbmQgKi8NCj4gPiAgICAgZGVsX3RpbWVyX3N5bmMoJnByaXYt
PmNvbW1hbmRfdGltZXIpOw0KPiA+ICsgICBkZWxfdGltZXJfc3luYygmcHJpdi0+YXV0b19kZWVw
c2xlZXBfdGltZXIpOw0KPiA+DQo+ID4gICAgIC8qIEZsdXNoIHBlbmRpbmcgY29tbWFuZCBub2Rl
cyAqLw0KPiA+ICAgICBzcGluX2xvY2tfaXJxc2F2ZSgmcHJpdi0+ZHJpdmVyX2xvY2ssIGZsYWdz
KTsNCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvc2Nhbi5j
IGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvc2Nhbi5jDQo+ID4gaW5kZXggNmM5NWFm
My4uZTQ2OGUxNSAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRh
cy9zY2FuLmMNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9zY2FuLmMN
Cj4gPiBAQCAtOTUwLDYgKzk1MCwxMSBAQCBpbnQgbGJzX3NldF9zY2FuKHN0cnVjdCBuZXRfZGV2
aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1ZXN0X2luZm8gKmluZm8sDQo+ID4NCj4gPiAgICAgbGJz
X2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9h
bGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAg
ICAgICAgIGdvdG8gb3V0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAoIXByaXYtPnJh
ZGlvX29uKSB7DQo+ID4gICAgICAgICAgICAgcmV0ID0gLUVJTlZBTDsNCj4gPiAgICAgICAgICAg
ICBnb3RvIG91dDsNCj4gPiBAQCAtMTAxNyw2ICsxMDIyLDEyIEBAIGludCBsYnNfZ2V0X3NjYW4o
c3RydWN0IG5ldF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4g
Pg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYg
KCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICBlcnIgPSAtRUJV
U1k7DQo+ID4gKyAgICAgICAgICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfV0VYVCwgInJl
dCAlZCIsIGVycik7DQo+ID4gKyAgICAgICAgICAgcmV0dXJuIGVycjsNCj4gPiArICAgfQ0KPiA+
ICsNCj4gPiAgICAgLyogaXdsaXN0IHNob3VsZCB3YWl0IHVudGlsIHRoZSBjdXJyZW50IHNjYW4g
aXMgZmluaXNoZWQgKi8NCj4gPiAgICAgaWYgKHByaXYtPnNjYW5fY2hhbm5lbCkNCj4gPiAgICAg
ICAgICAgICByZXR1cm4gLUVBR0FJTjsNCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9uZXQvd2ly
ZWxlc3MvbGliZXJ0YXMvd2V4dC5jIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvd2V4
dC5jDQo+ID4gaW5kZXggYmU4MzdhMC4uZWYyYjk4NiAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJz
L25ldC93aXJlbGVzcy9saWJlcnRhcy93ZXh0LmMNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJl
bGVzcy9saWJlcnRhcy93ZXh0LmMNCj4gPiBAQCAtNDUsNiArNDUsMzEgQEAgc3RhdGljIGlubGlu
ZSB2b2lkIGxic19jYW5jZWxfYXNzb2NpYXRpb25fd29yayhzdHJ1Y3QgbGJzX3ByaXZhdGUgKnBy
aXYpDQo+ID4gICAgIHByaXYtPnBlbmRpbmdfYXNzb2NfcmVxID0gTlVMTDsNCj4gPiAgfQ0KPiA+
DQo+ID4gKy8qKg0KPiA+ICsgKiAgQGJyaWVmIFRoaXMgZnVuY3Rpb24gY2hlY2tzIGlmIHRoZSBj
b21tYW5kIGlzIGFsbG93ZWQuDQo+ID4gKyAqDQo+ID4gKyAqICBAcGFyYW0gcHJpdiAgICAgICAg
IEEgcG9pbnRlciB0byBsYnNfcHJpdmF0ZSBzdHJ1Y3R1cmUNCj4gPiArICogIEByZXR1cm4gICAg
ICAgICAgICAgYWxsb3dlZCBvciBub3QgYWxsb3dlZC4NCj4gPiArICovDQo+ID4gKw0KPiA+ICtp
bnQgbGJzX2lzX2NtZF9hbGxvd2VkKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdikNCj4gPiArew0K
PiA+ICsgICBpbnQgICAgICAgICByZXQgPSAxOw0KPiA+ICsNCj4gPiArICAgbGJzX2RlYl9lbnRl
cihMQlNfREVCX1dFWFQpOw0KPiA+ICsNCj4gPiArICAgaWYgKCFwcml2LT5pc19hdXRvX2RlZXBf
c2xlZXBfZW5hYmxlZCkgew0KPiA+ICsgICAgICAgICAgIGlmIChwcml2LT5pc19kZWVwX3NsZWVw
KSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBsYnNfZGViX3dleHQoIklPQ1RMUyBjYWxsZWQg
d2hlbiBzdGF0aW9uIg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJp
cyBpbiBkZWVwIHNsZWVwXG4iKTsNCj4gPiArICAgICAgICAgICAgICAgICAgIHJldCA9IDA7DQo+
ID4gKyAgICAgICAgICAgfQ0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICsgICBsYnNfZGViX2xlYXZl
KExCU19ERUJfV0VYVCk7DQo+ID4gKyAgIHJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4N
Cj4gPiAgLyoqDQo+ID4gICAqICBAYnJpZWYgRmluZCB0aGUgY2hhbm5lbCBmcmVxdWVuY3kgcG93
ZXIgaW5mbyB3aXRoIHNwZWNpZmljIGNoYW5uZWwNCj4gPiBAQCAtMTY4LDYgKzE5MywxMSBAQCBz
dGF0aWMgaW50IGxic19nZXRfZnJlcShzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdf
cmVxdWVzdF9pbmZvICppbmZvLA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9X
RVhUKTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+
ICsgICAgICAgICAgIGxic19kZWJfbGVhdmUoTEJTX0RFQl9XRVhUKTsNCj4gPiArICAgICAgICAg
ICByZXR1cm4gLUVCVVNZOw0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBjZnAgPSBsYnNfZmlu
ZF9jZnBfYnlfYmFuZF9hbmRfY2hhbm5lbChwcml2LCAwLA0KPiA+ICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIHByaXYtPmN1cmJzc3BhcmFtcy5jaGFubmVsKTsNCj4gPg0K
PiA+IEBAIC0yNzgsNiArMzA4LDEyIEBAIHN0YXRpYyBpbnQgbGJzX3NldF9ydHMoc3RydWN0IG5l
dF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4gPg0KPiA+ICAg
ICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNf
Y21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4g
KyAgICAgICAgICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfV0VYVCwgInJldCAlZCIsIHJl
dCk7DQo+ID4gKyAgICAgICAgICAgcmV0dXJuIHJldDsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAg
ICAgaWYgKHZ3cnEtPmRpc2FibGVkKQ0KPiA+ICAgICAgICAgICAgIHZhbCA9IE1SVkRSVl9SVFNf
TUFYX1ZBTFVFOw0KPiA+DQo+ID4gQEAgLTI5OSw2ICszMzUsMTEgQEAgc3RhdGljIGludCBsYnNf
Z2V0X3J0cyhzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICpp
bmZvLA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+
ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJl
dCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBnb3RvIG91dDsNCj4gPiArICAgfQ0KPiA+ICsN
Cj4gPiAgICAgcmV0ID0gbGJzX2dldF9zbm1wX21pYihwcml2LCBTTk1QX01JQl9PSURfUlRTX1RI
UkVTSE9MRCwgJnZhbCk7DQo+ID4gICAgIGlmIChyZXQpDQo+ID4gICAgICAgICAgICAgZ290byBv
dXQ7DQo+ID4gQEAgLTMyMSw2ICszNjIsMTIgQEAgc3RhdGljIGludCBsYnNfc2V0X2ZyYWcoc3Ry
dWN0IG5ldF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4gPg0K
PiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFs
YnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJVU1k7
DQo+ID4gKyAgICAgICAgICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfV0VYVCwgInJldCAl
ZCIsIHJldCk7DQo+ID4gKyAgICAgICAgICAgcmV0dXJuIHJldDsNCj4gPiArICAgfQ0KPiA+ICsN
Cj4gPiAgICAgaWYgKHZ3cnEtPmRpc2FibGVkKQ0KPiA+ICAgICAgICAgICAgIHZhbCA9IE1SVkRS
Vl9GUkFHX01BWF9WQUxVRTsNCj4gPg0KPiA+IEBAIC0zNDIsNiArMzg5LDExIEBAIHN0YXRpYyBp
bnQgbGJzX2dldF9mcmFnKHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1ZXN0
X2luZm8gKmluZm8sDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0K
PiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAg
ICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0Ow0KPiA+ICsgICB9
DQo+ID4gKw0KPiA+ICAgICByZXQgPSBsYnNfZ2V0X3NubXBfbWliKHByaXYsIFNOTVBfTUlCX09J
RF9GUkFHX1RIUkVTSE9MRCwgJnZhbCk7DQo+ID4gICAgIGlmIChyZXQpDQo+ID4gICAgICAgICAg
ICAgZ290byBvdXQ7DQo+ID4gQEAgLTM5MSw2ICs0NDMsMTEgQEAgc3RhdGljIGludCBsYnNfZ2V0
X3R4cG93KHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRl
cihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHBy
aXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdv
dG8gb3V0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAoIXByaXYtPnJhZGlvX29uKSB7
DQo+ID4gICAgICAgICAgICAgbGJzX2RlYl93ZXh0KCJ0eCBwb3dlciBvZmZcbiIpOw0KPiA+ICAg
ICAgICAgICAgIHZ3cnEtPnZhbHVlID0gMDsNCj4gPiBAQCAtNDI0LDYgKzQ4MSwxMSBAQCBzdGF0
aWMgaW50IGxic19zZXRfcmV0cnkoc3RydWN0IG5ldF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3Jl
cXVlc3RfaW5mbyAqaW5mbywNCj4gPg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VY
VCk7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiAr
ICAgICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4gKyAgICAgICAgICAgZ290byBvdXQ7DQo+ID4g
KyAgIH0NCj4gPiArDQo+ID4gICAgICAgICAgaWYgKCh2d3JxLT5mbGFncyAmIElXX1JFVFJZX1RZ
UEUpICE9IElXX1JFVFJZX0xJTUlUKQ0KPiA+ICAgICAgICAgICAgICAgICAgcmV0dXJuIC1FT1BO
T1RTVVBQOw0KPiA+DQo+ID4gQEAgLTQ3Miw2ICs1MzQsMTEgQEAgc3RhdGljIGludCBsYnNfZ2V0
X3JldHJ5KHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1ZXN0X2luZm8gKmlu
Zm8sDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4g
KyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0
ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0Ow0KPiA+ICsgICB9DQo+ID4gKw0K
PiA+ICAgICB2d3JxLT5kaXNhYmxlZCA9IDA7DQo+ID4NCj4gPiAgICAgaWYgKHZ3cnEtPmZsYWdz
ICYgSVdfUkVUUllfTE9ORykgew0KPiA+IEBAIC03MTIsNiArNzc5LDExIEBAIHN0YXRpYyBpbnQg
bGJzX3NldF9wb3dlcihzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9p
bmZvICppbmZvLA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4g
Pg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAg
ICAgIGxic19kZWJfbGVhdmUoTEJTX0RFQl9XRVhUKTsNCj4gPiArICAgICAgICAgICByZXR1cm4g
LUVCVVNZOw0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAoIShwcml2LT5md2NhcGluZm8g
JiBGV19DQVBJTkZPX1BTKSkgew0KPiA+ICAgICAgICAgICAgIGlmICh2d3JxLT5kaXNhYmxlZCkN
Cj4gPiAgICAgICAgICAgICAgICAgICAgIHJldHVybiAwOw0KPiA+IEBAIC03OTIsNiArODY0LDkg
QEAgc3RhdGljIHN0cnVjdCBpd19zdGF0aXN0aWNzICpsYnNfZ2V0X3dpcmVsZXNzX3N0YXRzKHN0
cnVjdCBuZXRfZGV2aWNlICpkZXYpDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVC
X1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKQ0KPiA+
ICsgICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiAgICAgcHJpdi0+d3N0YXRzLnN0
YXR1cyA9IHByaXYtPm1vZGU7DQo+ID4NCj4gPiAgICAgLyogSWYgd2UncmUgbm90IGFzc29jaWF0
ZWQsIGFsbCBxdWFsaXR5IHZhbHVlcyBhcmUgbWVhbmluZ2xlc3MgKi8NCj4gPiBAQCAtODkyLDYg
Kzk2NywxMiBAQCBzdGF0aWMgaW50IGxic19zZXRfZnJlcShzdHJ1Y3QgbmV0X2RldmljZSAqZGV2
LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZvLA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50
ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChw
cml2KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBs
YnNfZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9XRVhULCAicmV0ICVkIiwgcmV0KTsNCj4gPiArICAg
ICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBtdXRleF9sb2Nr
KCZwcml2LT5sb2NrKTsNCj4gPiAgICAgYXNzb2NfcmVxID0gbGJzX2dldF9hc3NvY2lhdGlvbl9y
ZXF1ZXN0KHByaXYpOw0KPiA+ICAgICBpZiAoIWFzc29jX3JlcSkgew0KPiA+IEBAIC0xMDAwLDYg
KzEwODEsMTIgQEAgc3RhdGljIGludCBsYnNfc2V0X3JhdGUoc3RydWN0IG5ldF9kZXZpY2UgKmRl
diwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4gPiAgICAgdTggcmF0ZXNbTUFYX1JB
VEVTICsgMV07DQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+
ICsNCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAg
ICAgICByZXQgPSAtRUJVU1k7DQo+ID4gKyAgICAgICAgICAgZ290byBvdXQ7DQo+ID4gKyAgIH0N
Cj4gPiArDQo+ID4gICAgIGxic19kZWJfd2V4dCgidndycS0+dmFsdWUgJWRcbiIsIHZ3cnEtPnZh
bHVlKTsNCj4gPiAgICAgbGJzX2RlYl93ZXh0KCJ2d3JxLT5maXhlZCAlZFxuIiwgdndycS0+Zml4
ZWQpOw0KPiA+DQo+ID4gQEAgLTEwNTgsNiArMTE0NSwxMSBAQCBzdGF0aWMgaW50IGxic19nZXRf
cmF0ZShzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZv
LA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsg
ICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIGxic19k
ZWJfbGVhdmUoTEJTX0RFQl9XRVhUKTsNCj4gPiArICAgICAgICAgICByZXR1cm4gLUVCVVNZOw0K
PiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAocHJpdi0+Y29ubmVjdF9zdGF0dXMgPT0gTEJT
X0NPTk5FQ1RFRCkgew0KPiA+ICAgICAgICAgICAgIHZ3cnEtPnZhbHVlID0gcHJpdi0+Y3VyX3Jh
dGUgKiA1MDAwMDA7DQo+ID4NCj4gPiBAQCAtMTA4NCw2ICsxMTc2LDExIEBAIHN0YXRpYyBpbnQg
bGJzX3NldF9tb2RlKHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsDQo+ID4NCj4gPiAgICAgbGJzX2Rl
Yl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxv
d2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAg
ICAgIGdvdG8gb3V0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAoICAgKCp1d3JxICE9
IElXX01PREVfQURIT0MpDQo+ID4gICAgICAgICAmJiAoKnV3cnEgIT0gSVdfTU9ERV9JTkZSQSkN
Cj4gPiAgICAgICAgICYmICgqdXdycSAhPSBJV19NT0RFX0FVVE8pKSB7DQo+ID4gQEAgLTEzMjUs
NiArMTQyMiwxMiBAQCBzdGF0aWMgaW50IGxic19zZXRfZW5jb2RlKHN0cnVjdCBuZXRfZGV2aWNl
ICpkZXYsDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+
ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAg
cmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGxic19kZWJfbGVhdmVfYXJncyhMQlNfREVC
X1dFWFQsICJyZXQgJWQiLCByZXQpOw0KPiA+ICsgICAgICAgICAgIHJldHVybiByZXQ7DQo+ID4g
KyAgIH0NCj4gPiArDQo+ID4gICAgIG11dGV4X2xvY2soJnByaXYtPmxvY2spOw0KPiA+ICAgICBh
c3NvY19yZXEgPSBsYnNfZ2V0X2Fzc29jaWF0aW9uX3JlcXVlc3QocHJpdik7DQo+ID4gICAgIGlm
ICghYXNzb2NfcmVxKSB7DQo+ID4gQEAgLTE1MDgsNiArMTYxMSwxMiBAQCBzdGF0aWMgaW50IGxi
c19zZXRfZW5jb2RlZXh0KHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsDQo+ID4NCj4gPiAgICAgbGJz
X2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9h
bGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAg
ICAgICAgIGxic19kZWJfbGVhdmVfYXJncyhMQlNfREVCX1dFWFQsICJyZXQgJWQiLCByZXQpOw0K
PiA+ICsgICAgICAgICAgIHJldHVybiByZXQ7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIG11
dGV4X2xvY2soJnByaXYtPmxvY2spOw0KPiA+ICAgICBhc3NvY19yZXEgPSBsYnNfZ2V0X2Fzc29j
aWF0aW9uX3JlcXVlc3QocHJpdik7DQo+ID4gICAgIGlmICghYXNzb2NfcmVxKSB7DQo+ID4gQEAg
LTE3MjAsNiArMTgyOSwxMiBAQCBzdGF0aWMgaW50IGxic19zZXRfYXV0aChzdHJ1Y3QgbmV0X2Rl
dmljZSAqZGV2LA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4g
Pg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAg
ICAgIHJldCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBsYnNfZGViX2xlYXZlX2FyZ3MoTEJT
X0RFQl9XRVhULCAicmV0ICVkIiwgcmV0KTsNCj4gPiArICAgICAgICAgICByZXR1cm4gcmV0Ow0K
PiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBtdXRleF9sb2NrKCZwcml2LT5sb2NrKTsNCj4gPiAg
ICAgYXNzb2NfcmVxID0gbGJzX2dldF9hc3NvY2lhdGlvbl9yZXF1ZXN0KHByaXYpOw0KPiA+ICAg
ICBpZiAoIWFzc29jX3JlcSkgew0KPiA+IEBAIC0xODIyLDYgKzE5MzcsMTIgQEAgc3RhdGljIGlu
dCBsYnNfZ2V0X2F1dGgoc3RydWN0IG5ldF9kZXZpY2UgKmRldiwNCj4gPg0KPiA+ICAgICBsYnNf
ZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2Fs
bG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4gKyAgICAg
ICAgICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfV0VYVCwgInJldCAlZCIsIHJldCk7DQo+
ID4gKyAgICAgICAgICAgcmV0dXJuIHJldDsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgc3dp
dGNoIChkd3JxLT5mbGFncyAmIElXX0FVVEhfSU5ERVgpIHsNCj4gPiAgICAgY2FzZSBJV19BVVRI
X0tFWV9NR01UOg0KPiA+ICAgICAgICAgICAgIGR3cnEtPnZhbHVlID0gcHJpdi0+c2VjaW5mby5r
ZXlfbWdtdDsNCj4gPiBAQCAtMTg2NCw2ICsxOTg1LDExIEBAIHN0YXRpYyBpbnQgbGJzX3NldF90
eHBvdyhzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvDQo+ICpp
bmZvLA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+
ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJl
dCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBnb3RvIG91dDsNCj4gPiArICAgfQ0KPiA+ICsN
Cj4gPiAgICAgaWYgKHZ3cnEtPmRpc2FibGVkKSB7DQo+ID4gICAgICAgICAgICAgbGJzX3NldF9y
YWRpbyhwcml2LCBSQURJT19QUkVBTUJMRV9BVVRPLCAwKTsNCj4gPiAgICAgICAgICAgICBnb3Rv
IG91dDsNCj4gPiBAQCAtMTk4Myw2ICsyMTA5LDEyIEBAIHN0YXRpYyBpbnQgbGJzX3NldF9lc3Np
ZChzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvDQo+ICppbmZv
LA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsg
ICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9
IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBsYnNfZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9XRVhU
LCAicmV0ICVkIiwgcmV0KTsNCj4gPiArICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICB9
DQo+ID4gKw0KPiA+ICAgICBpZiAoIXByaXYtPnJhZGlvX29uKSB7DQo+ID4gICAgICAgICAgICAg
cmV0ID0gLUVJTlZBTDsNCj4gPiAgICAgICAgICAgICBnb3RvIG91dDsNCj4gPiBAQCAtMjExMCw2
ICsyMjQyLDEyIEBAIHN0YXRpYyBpbnQgbGJzX3NldF93YXAoc3RydWN0IG5ldF9kZXZpY2UgKmRl
diwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4gPg0KPiA+ICAgICBsYnNfZGViX2Vu
dGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQo
cHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4gKyAgICAgICAgICAg
bGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfV0VYVCwgInJldCAlZCIsIHJldCk7DQo+ID4gKyAg
ICAgICAgICAgcmV0dXJuIHJldDsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgaWYgKCFwcml2
LT5yYWRpb19vbikNCj4gPiAgICAgICAgICAgICByZXR1cm4gLUVJTlZBTDsNCj4gPg0KDQo=

2009-10-01 18:00:30

by Dan Williams

[permalink] [raw]
Subject: RE: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688

On Mon, 2009-09-28 at 15:42 -0700, Bing Zhao wrote:
> Hi Dan,
>
> > -----Original Message-----
> > From: Dan Williams [mailto:[email protected]]
> > Sent: Sunday, September 20, 2009 7:58 AM
> > To: Bing Zhao
> > Cc: [email protected]; [email protected]; Amitkumar Karwar
> > Subject: Re: [PATCH] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
> >
> > On Tue, 2009-09-15 at 16:45 -0700, Bing Zhao wrote:
> > > From: Amitkumar Karwar <[email protected]>
> > >
> > > Add timer based auto deep sleep feature in libertas driver which can be
> > > configured through debugfs interface. This is tested on SD8688, SD8686 cards
> > > with firmware versions 10.38.1.p25, 9.70.4.p0 respectively on 32-bit and 64-bit
> > > platforms. Tests have been done for USB/CS cards to make sure that the patch
> > > won't break USB/CS code. We didn't test the if_spi driver.
> >
> > So there's always:
> >
> > #define IW_POWER_SAVING 0x4000 /* Value is relative (how aggressive)*/
> >
> > iwconfig wlan0 power saving 10
> >
> > That seems quite a bit better than a new debugfs parameter, until we can
> > conver the driver over cfg80211 and do this properly. If the power
> > saving mode is higher than some number X, the chip gets put into deep
> > sleep mode, or it can be automatically placed in deep sleep mode by the
> > driver when there is no association like you have done with the timer
> > above. I think you should pick reasonable defaults, and perhaps if the
> > 'saving' value is larger, the timer value in the driver gets smaller.
> >
> > Does that sound like an OK approach? We really should be using debugfs
> > only for debugging stuff (obviously), and the real fix for this sort of
> > thing is to switch over to cfg80211 where we can actually extend the
> > configuration API instead of hacking it into debugfs/WEXT/etc.
> >
> > Dan
>
> Thanks for your suggestion.
>
> In latest kernel, IW_POWER_SAVING is not defined in include/linux/wireless.h.
> IW_POWER_PERIOD and IW_POWER_TIMEOUT are defined though.

You're right. wireless-tools apparently had it, but since WEXT is on
life-support, John removed most of the additions before WE-21 got
committed to the kernel. So it's not there.

> We are planning to remove debugfs for configurations and use the following commands instead.
> Please let us know if there is any concern.
>
> iwconfig wlan0 power period 0 -> enable deep sleep (enter deep sleep immediately)
> iwconfig wlan0 power period 5 -> enable auto deep sleep (enter deep sleep automatically after 5s idle time)
> iwconfig wlan0 power period -1 -> disable deep sleep / auto deep sleep

Sure, that seems fine to me.

dan

> By the way, there is a bug in iwconfig tool v29. It doesn’t take any values right after "period" or "timeout". The new version of Wireless Tools v30-pre8 (link below) fixed the bug:
>
> http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/wireless_tools.30.pre8.tar.gz
>
> Thanks,
>
> Bing
>
> >
> > > Signed-off-by: Amitkumar Karwar <[email protected]>
> > > Signed-off-by: Bing Zhao <[email protected]>
> > > ---
> > > drivers/net/wireless/libertas/README | 28 +++++-
> > > drivers/net/wireless/libertas/cmd.c | 72 +++++++++++++-
> > > drivers/net/wireless/libertas/cmdresp.c | 12 +++
> > > drivers/net/wireless/libertas/debugfs.c | 160 +++++++++++++++++++++++++++++++
> > > drivers/net/wireless/libertas/decl.h | 4 +
> > > drivers/net/wireless/libertas/dev.h | 18 ++++
> > > drivers/net/wireless/libertas/host.h | 1 +
> > > drivers/net/wireless/libertas/if_cs.c | 3 +
> > > drivers/net/wireless/libertas/if_sdio.c | 56 +++++++++++
> > > drivers/net/wireless/libertas/if_sdio.h | 3 +-
> > > drivers/net/wireless/libertas/if_spi.c | 3 +
> > > drivers/net/wireless/libertas/if_usb.c | 3 +
> > > drivers/net/wireless/libertas/main.c | 111 +++++++++++++++++++---
> > > drivers/net/wireless/libertas/scan.c | 11 ++
> > > drivers/net/wireless/libertas/wext.c | 138 ++++++++++++++++++++++++++
> > > 15 files changed, 604 insertions(+), 19 deletions(-)
> > >
> > > diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
> > > index ab6a2d5..059ce8c 100644
> > > --- a/drivers/net/wireless/libertas/README
> > > +++ b/drivers/net/wireless/libertas/README
> > > @@ -1,5 +1,5 @@
> > > ================================================================================
> > > - README for USB8388
> > > + README for Libertas
> > >
> > > (c) Copyright © 2003-2006, Marvell International Ltd.
> > > All Rights Reserved
> > > @@ -226,4 +226,30 @@ setuserscan
> > > All entries in the scan table (not just the new scan data when keep=1)
> > > will be displayed upon completion by use of the getscantable ioctl.
> > >
> > > +deepsleep
> > > +
> > > + This command is used to configure the station in deep sleep mode/auto
> > > + deep sleep mode. Command expects two parameters:
> > > + 'state' 'idle time period'
> > > +
> > > + The timer is implemented to monitor the activities (command, event,
> > > + data, etc.). When an activity is detected station will exit from deep
> > > + sleep mode automatically and restart the timer. At timer expiry (no
> > > + activity for defined time period) the deepsleep mode is entered
> > > + automatically.
> > > +
> > > + Note: this command is for SDIO interface only.
> > > +
> > > + Path: /sys/kernel/debug/libertas_wireless/ethX/
> > > +
> > > + Usage:
> > > + To read the current status of deep sleep do:
> > > + cat deepsleep
> > > + To enable deep sleep mode do:
> > > + echo '1 0' > deepsleep
> > > + To enable auto deep sleep mode with idle time period 5 seconds do:
> > > + echo '1 5000' > deepsleep
> > > + To disable deep sleep/auto deep sleep mode do:
> > > + echo '0 0' > deepsleep
> > > +
> > > ==============================================================================
> > > diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
> > > index 6850981..3a3e894 100644
> > > --- a/drivers/net/wireless/libertas/cmd.c
> > > +++ b/drivers/net/wireless/libertas/cmd.c
> > > @@ -17,7 +17,6 @@
> > >
> > > static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
> > >
> > > -
> > > /**
> > > * @brief Simple callback that copies response back into command
> > > *
> > > @@ -319,6 +318,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
> > > return 0;
> > > }
> > >
> > > +static int lbs_wait_for_ds_awake(struct lbs_private *priv)
> > > +{
> > > + int ret = 0;
> > > +
> > > + lbs_deb_enter(LBS_DEB_CMD);
> > > +
> > > + if (priv->is_deep_sleep) {
> > > + if (!wait_event_interruptible_timeout(priv->ds_awake_q,
> > > + !priv->is_deep_sleep, (10 * HZ))) {
> > > + lbs_pr_err("ds_awake_q: timer expired\n");
> > > + ret = -1;
> > > + }
> > > + }
> > > +
> > > + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
> > > + return ret;
> > > +}
> > > +
> > > +int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
> > > +{
> > > + int ret = 0;
> > > +
> > > + lbs_deb_enter(LBS_DEB_CMD);
> > > +
> > > + if (deep_sleep) {
> > > + if (priv->is_deep_sleep != 1) {
> > > + lbs_deb_cmd("deep sleep: sleep\n");
> > > + BUG_ON(!priv->enter_deep_sleep);
> > > + ret = priv->enter_deep_sleep(priv);
> > > + if (!ret) {
> > > + netif_stop_queue(priv->dev);
> > > + netif_carrier_off(priv->dev);
> > > + }
> > > + } else {
> > > + lbs_pr_err("deep sleep: already enabled\n");
> > > + }
> > > + } else {
> > > + if (priv->is_deep_sleep) {
> > > + lbs_deb_cmd("deep sleep: wakeup\n");
> > > + BUG_ON(!priv->exit_deep_sleep);
> > > + ret = priv->exit_deep_sleep(priv);
> > > + if (!ret) {
> > > + ret = lbs_wait_for_ds_awake(priv);
> > > + if (ret)
> > > + lbs_pr_err("deep sleep: wakeup"
> > > + "failed\n");
> > > + }
> > > + }
> > > + }
> > > +
> > > + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
> > > + return ret;
> > > +}
> > > +
> > > int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
> > > struct assoc_request *assoc)
> > > {
> > > @@ -1242,8 +1295,17 @@ static void lbs_submit_command(struct lbs_private *priv,
> > > timeo = HZ/4;
> > > }
> > >
> > > - /* Setup the timer after transmit command */
> > > - mod_timer(&priv->command_timer, jiffies + timeo);
> > > + if (command == CMD_802_11_DEEP_SLEEP) {
> > > + if (priv->is_auto_deep_sleep_enabled) {
> > > + priv->wakeup_dev_required = 1;
> > > + priv->dnld_sent = 0;
> > > + }
> > > + priv->is_deep_sleep = 1;
> > > + lbs_complete_command(priv, cmdnode, 0);
> > > + } else {
> > > + /* Setup the timer after transmit command */
> > > + mod_timer(&priv->command_timer, jiffies + timeo);
> > > + }
> > >
> > > lbs_deb_leave(LBS_DEB_HOST);
> > > }
> > > @@ -1505,6 +1567,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
> > > case CMD_802_11_BEACON_CTRL:
> > > ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
> > > break;
> > > + case CMD_802_11_DEEP_SLEEP:
> > > + cmdptr->command = cpu_to_le16(CMD_802_11_DEEP_SLEEP);
> > > + cmdptr->size = cpu_to_le16(S_DS_GEN);
> > > + break;
> > > default:
> > > lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
> > > ret = -1;
> > > diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
> > > index c42d3fa..47d2b19 100644
> > > --- a/drivers/net/wireless/libertas/cmdresp.c
> > > +++ b/drivers/net/wireless/libertas/cmdresp.c
> > > @@ -504,9 +504,21 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
> > >
> > > case MACREG_INT_CODE_HOST_AWAKE:
> > > lbs_deb_cmd("EVENT: host awake\n");
> > > + if (priv->reset_deep_sleep_wakeup)
> > > + priv->reset_deep_sleep_wakeup(priv);
> > > + priv->is_deep_sleep = 0;
> > > lbs_send_confirmwake(priv);
> > > break;
> > >
> > > + case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
> > > + if (priv->reset_deep_sleep_wakeup)
> > > + priv->reset_deep_sleep_wakeup(priv);
> > > + lbs_deb_cmd("EVENT: ds awake\n");
> > > + priv->is_deep_sleep = 0;
> > > + priv->wakeup_dev_required = 0;
> > > + wake_up_interruptible(&priv->ds_awake_q);
> > > + break;
> > > +
> > > case MACREG_INT_CODE_PS_AWAKE:
> > > lbs_deb_cmd("EVENT: ps awake\n");
> > > /* handle unexpected PS AWAKE event */
> > > diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
> > > index 893a55c..624a438 100644
> > > --- a/drivers/net/wireless/libertas/debugfs.c
> > > +++ b/drivers/net/wireless/libertas/debugfs.c
> > > @@ -117,6 +117,11 @@ static ssize_t lbs_sleepparams_write(struct file *file,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out_unlock;
> > > + }
> > > +
> > > buf_size = min(count, len - 1);
> > > if (copy_from_user(buf, user_buf, buf_size)) {
> > > ret = -EFAULT;
> > > @@ -157,6 +162,11 @@ static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out_unlock;
> > > + }
> > > +
> > > ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
> > > if (ret)
> > > goto out_unlock;
> > > @@ -173,6 +183,118 @@ out_unlock:
> > > return ret;
> > > }
> > >
> > > +static ssize_t lbs_deepsleep_read(struct file *file, char __user *userbuf,
> > > + size_t count, loff_t *ppos)
> > > +{
> > > + struct lbs_private *priv = file->private_data;
> > > + ssize_t pos = 0;
> > > + int ret;
> > > + unsigned long addr = get_zeroed_page(GFP_KERNEL);
> > > + char *buf = (char *)addr;
> > > +
> > > + if (!buf)
> > > + return -ENOMEM;
> > > +
> > > + if (!priv->enter_deep_sleep) {
> > > + lbs_pr_err("deep sleep feature is not implemented "
> > > + "for this interface driver\n");
> > > + ret = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + if (priv->is_auto_deep_sleep_enabled)
> > > + pos += snprintf(buf, len, "%d %d\n",
> > > + priv->is_auto_deep_sleep_enabled,
> > > + priv->auto_deep_sleep_timeout);
> > > + else if (priv->is_deep_sleep)
> > > + pos += snprintf(buf, len, "%d %d\n",
> > > + priv->is_deep_sleep,
> > > + priv->auto_deep_sleep_timeout);
> > > + else
> > > + pos += snprintf(buf, len, "%d %d\n",
> > > + priv->is_deep_sleep,
> > > + priv->auto_deep_sleep_timeout);
> > > +
> > > + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
> > > +
> > > +out_ds:
> > > + free_page(addr);
> > > + return ret;
> > > +}
> > > +
> > > +static ssize_t lbs_deepsleep_write(struct file *file,
> > > + const char __user *userbuf,
> > > + size_t count, loff_t *ppos)
> > > +{
> > > + struct lbs_private *priv = file->private_data;
> > > + ssize_t res, buf_size;
> > > + int is_deep_sleep, auto_deep_sleep_timeout;
> > > + unsigned long addr = get_zeroed_page(GFP_KERNEL);
> > > + char *buf = (char *)addr;
> > > +
> > > + if (!buf)
> > > + return -ENOMEM;
> > > +
> > > + if (!priv->enter_deep_sleep) {
> > > + lbs_pr_err("deep sleep feature is not implemented "
> > > + "for this interface driver\n");
> > > + res = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + if (priv->connect_status == LBS_CONNECTED) {
> > > + lbs_pr_err("can't use deep sleep cmd in connected "
> > > + "state\n");
> > > + res = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + buf_size = min(count, len - 1);
> > > + if (copy_from_user(buf, userbuf, buf_size)) {
> > > + res = -EFAULT;
> > > + goto out_ds;
> > > + }
> > > +
> > > + res = sscanf(buf, "%d %d", &is_deep_sleep, &auto_deep_sleep_timeout);
> > > + if ((res != 2) || (!is_deep_sleep && auto_deep_sleep_timeout) ||
> > > + !((is_deep_sleep == 1) ||
> > > + (is_deep_sleep == 0))) {
> > > + lbs_pr_err("unknown option\n");
> > > + res = -EINVAL;
> > > + goto out_ds;
> > > + }
> > > +
> > > + if (auto_deep_sleep_timeout) {
> > > + if (!priv->is_auto_deep_sleep_enabled) {
> > > + priv->is_activity_detected = 0;
> > > + priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
> > > + lbs_enter_auto_deep_sleep(priv);
> > > + } else {
> > > + priv->auto_deep_sleep_timeout = auto_deep_sleep_timeout;
> > > + lbs_deb_debugfs("auto deep sleep: already enabled\n");
> > > + }
> > > + } else {
> > > + if (priv->is_auto_deep_sleep_enabled) {
> > > + lbs_exit_auto_deep_sleep(priv);
> > > + /* Try to exit deep sleep if auto deep sleep disabled */
> > > + res = lbs_set_deep_sleep(priv, 0);
> > > + if (res)
> > > + goto out_ds;
> > > + }
> > > + if ((is_deep_sleep == 0) || (is_deep_sleep == 1)) {
> > > + res = lbs_set_deep_sleep(priv, is_deep_sleep);
> > > + if (res)
> > > + goto out_ds;
> > > + }
> > > + }
> > > +
> > > + res = count;
> > > +
> > > +out_ds:
> > > + free_page(addr);
> > > + return res;
> > > +}
> > > +
> > > /*
> > > * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
> > > * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
> > > @@ -223,6 +345,9 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
> > > u8 freq;
> > > int events = 0;
> > >
> > > + if (!lbs_is_cmd_allowed(priv))
> > > + return -EBUSY;
> > > +
> > > buf = (char *)get_zeroed_page(GFP_KERNEL);
> > > if (!buf)
> > > return -ENOMEM;
> > > @@ -275,6 +400,9 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
> > > char *buf;
> > > int ret;
> > >
> > > + if (!lbs_is_cmd_allowed(priv))
> > > + return -EBUSY;
> > > +
> > > buf = (char *)get_zeroed_page(GFP_KERNEL);
> > > if (!buf)
> > > return -ENOMEM;
> > > @@ -444,6 +572,11 @@ static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + free_page(addr);
> > > + return -EBUSY;
> > > + }
> > > +
> > > offval.offset = priv->mac_offset;
> > > offval.value = 0;
> > >
> > > @@ -496,6 +629,11 @@ static ssize_t lbs_wrmac_write(struct file *file,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + res = -EBUSY;
> > > + goto out_unlock;
> > > + }
> > > +
> > > buf_size = min(count, len - 1);
> > > if (copy_from_user(buf, userbuf, buf_size)) {
> > > res = -EFAULT;
> > > @@ -532,6 +670,11 @@ static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + free_page(addr);
> > > + return -EBUSY;
> > > + }
> > > +
> > > offval.offset = priv->bbp_offset;
> > > offval.value = 0;
> > >
> > > @@ -585,6 +728,11 @@ static ssize_t lbs_wrbbp_write(struct file *file,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + res = -EBUSY;
> > > + goto out_unlock;
> > > + }
> > > +
> > > buf_size = min(count, len - 1);
> > > if (copy_from_user(buf, userbuf, buf_size)) {
> > > res = -EFAULT;
> > > @@ -621,6 +769,11 @@ static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + free_page(addr);
> > > + return -EBUSY;
> > > + }
> > > +
> > > offval.offset = priv->rf_offset;
> > > offval.value = 0;
> > >
> > > @@ -674,6 +827,11 @@ static ssize_t lbs_wrrf_write(struct file *file,
> > > if (!buf)
> > > return -ENOMEM;
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + res = -EBUSY;
> > > + goto out_unlock;
> > > + }
> > > +
> > > buf_size = min(count, len - 1);
> > > if (copy_from_user(buf, userbuf, buf_size)) {
> > > res = -EFAULT;
> > > @@ -717,6 +875,8 @@ static const struct lbs_debugfs_files debugfs_files[] = {
> > > write_file_dummy), },
> > > { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
> > > lbs_sleepparams_write), },
> > > + { "deepsleep", 0644, FOPS(lbs_deepsleep_read,
> > > + lbs_deepsleep_write), },
> > > };
> > >
> > > static const struct lbs_debugfs_files debugfs_events_files[] = {
> > > diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
> > > index 0b84bdc..34b475f 100644
> > > --- a/drivers/net/wireless/libertas/decl.h
> > > +++ b/drivers/net/wireless/libertas/decl.h
> > > @@ -33,6 +33,10 @@ int lbs_execute_next_command(struct lbs_private *priv);
> > > int lbs_process_event(struct lbs_private *priv, u32 event);
> > > void lbs_queue_event(struct lbs_private *priv, u32 event);
> > > void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
> > > +int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
> > > +int lbs_is_cmd_allowed(struct lbs_private *priv);
> > > +int lbs_enter_auto_deep_sleep(struct lbs_private *priv);
> > > +int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
> > >
> > > u32 lbs_fw_index_to_data_rate(u8 index);
> > > u8 lbs_data_rate_to_fw_index(u32 rate);
> > > diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
> > > index 578c697..e2b4ef2 100644
> > > --- a/drivers/net/wireless/libertas/dev.h
> > > +++ b/drivers/net/wireless/libertas/dev.h
> > > @@ -129,6 +129,20 @@ struct lbs_private {
> > > u32 bbp_offset;
> > > u32 rf_offset;
> > >
> > > + /** Deep sleep flag */
> > > + int is_deep_sleep;
> > > + /** Auto deep sleep enabled flag */
> > > + int is_auto_deep_sleep_enabled;
> > > + /** Device wakeup required flag */
> > > + int wakeup_dev_required;
> > > + /** Auto deep sleep flag*/
> > > + int is_activity_detected;
> > > + /** Auto deep sleep timeout (in miliseconds) */
> > > + int auto_deep_sleep_timeout;
> > > +
> > > + /** Deep sleep wait queue */
> > > + wait_queue_head_t ds_awake_q;
> > > +
> > > /* Download sent:
> > > bit0 1/0=data_sent/data_tx_done,
> > > bit1 1/0=cmd_sent/cmd_tx_done,
> > > @@ -154,6 +168,9 @@ struct lbs_private {
> > > /** Hardware access */
> > > int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
> > > void (*reset_card) (struct lbs_private *priv);
> > > + int (*enter_deep_sleep) (struct lbs_private *priv);
> > > + int (*exit_deep_sleep) (struct lbs_private *priv);
> > > + int (*reset_deep_sleep_wakeup) (struct lbs_private *priv);
> > >
> > > /* Wake On LAN */
> > > uint32_t wol_criteria;
> > > @@ -204,6 +221,7 @@ struct lbs_private {
> > >
> > > /** Timers */
> > > struct timer_list command_timer;
> > > + struct timer_list auto_deepsleep_timer;
> > > int nr_retries;
> > > int cmd_timed_out;
> > >
> > > diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
> > > index fe8f0cb..c055daa 100644
> > > --- a/drivers/net/wireless/libertas/host.h
> > > +++ b/drivers/net/wireless/libertas/host.h
> > > @@ -57,6 +57,7 @@
> > > #define CMD_802_11_ENABLE_RSN 0x002f
> > > #define CMD_802_11_SET_AFC 0x003c
> > > #define CMD_802_11_GET_AFC 0x003d
> > > +#define CMD_802_11_DEEP_SLEEP 0x003e
> > > #define CMD_802_11_AD_HOC_STOP 0x0040
> > > #define CMD_802_11_HOST_SLEEP_CFG 0x0043
> > > #define CMD_802_11_WAKEUP_CONFIRM 0x0044
> > > diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
> > > index 6238176..465742f 100644
> > > --- a/drivers/net/wireless/libertas/if_cs.c
> > > +++ b/drivers/net/wireless/libertas/if_cs.c
> > > @@ -946,6 +946,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
> > > card->priv = priv;
> > > priv->card = card;
> > > priv->hw_host_to_card = if_cs_host_to_card;
> > > + priv->enter_deep_sleep = NULL;
> > > + priv->exit_deep_sleep = NULL;
> > > + priv->reset_deep_sleep_wakeup = NULL;
> > > priv->fw_ready = 1;
> > >
> > > /* Now actually get the IRQ */
> > > diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
> > > index 485a8d4..9716728 100644
> > > --- a/drivers/net/wireless/libertas/if_sdio.c
> > > +++ b/drivers/net/wireless/libertas/if_sdio.c
> > > @@ -831,6 +831,58 @@ out:
> > > return ret;
> > > }
> > >
> > > +static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
> > > +{
> > > + int ret = -1;
> > > + struct cmd_header cmd;
> > > +
> > > + memset(&cmd, 0, sizeof(cmd));
> > > +
> > > + lbs_deb_sdio("send DEEP_SLEEP command\n");
> > > + ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
> > > + lbs_cmd_copyback, (unsigned long) &cmd);
> > > + if (ret)
> > > + lbs_pr_err("DEEP_SLEEP cmd failed\n");
> > > +
> > > + mdelay(200);
> > > + return ret;
> > > +}
> > > +
> > > +static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
> > > +{
> > > + struct if_sdio_card *card = priv->card;
> > > + int ret = -1;
> > > +
> > > + lbs_deb_enter(LBS_DEB_SDIO);
> > > + sdio_claim_host(card->func);
> > > +
> > > + sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
> > > + if (ret)
> > > + lbs_pr_err("sdio_writeb failed!\n");
> > > +
> > > + sdio_release_host(card->func);
> > > + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
> > > + return ret;
> > > +}
> > > +
> > > +static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
> > > +{
> > > + struct if_sdio_card *card = priv->card;
> > > + int ret = -1;
> > > +
> > > + lbs_deb_enter(LBS_DEB_SDIO);
> > > + sdio_claim_host(card->func);
> > > +
> > > + sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
> > > + if (ret)
> > > + lbs_pr_err("sdio_writeb failed!\n");
> > > +
> > > + sdio_release_host(card->func);
> > > + lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
> > > + return ret;
> > > +
> > > +}
> > > +
> > > /*******************************************************************/
> > > /* SDIO callbacks */
> > > /*******************************************************************/
> > > @@ -859,6 +911,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
> > > * Ignore the define name, this really means the card has
> > > * successfully received the command.
> > > */
> > > + card->priv->is_activity_detected = 1;
> > > if (cause & IF_SDIO_H_INT_DNLD)
> > > lbs_host_to_card_done(card->priv);
> > >
> > > @@ -998,6 +1051,9 @@ static int if_sdio_probe(struct sdio_func *func,
> > >
> > > priv->card = card;
> > > priv->hw_host_to_card = if_sdio_host_to_card;
> > > + priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
> > > + priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
> > > + priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
> > >
> > > priv->fw_ready = 1;
> > >
> > > diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
> > > index 60c9b2f..12179c1 100644
> > > --- a/drivers/net/wireless/libertas/if_sdio.h
> > > +++ b/drivers/net/wireless/libertas/if_sdio.h
> > > @@ -51,5 +51,6 @@
> > > #define IF_SDIO_EVENT 0x80fc
> > >
> > > #define IF_SDIO_BLOCK_SIZE 256
> > > -
> > > +#define CONFIGURATION_REG 0x03
> > > +#define HOST_POWER_UP (0x1U << 1)
> > > #endif
> > > diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
> > > index 446e327..e2fa657 100644
> > > --- a/drivers/net/wireless/libertas/if_spi.c
> > > +++ b/drivers/net/wireless/libertas/if_spi.c
> > > @@ -1117,6 +1117,9 @@ static int __devinit if_spi_probe(struct spi_device *spi)
> > > card->priv = priv;
> > > priv->card = card;
> > > priv->hw_host_to_card = if_spi_host_to_card;
> > > + priv->enter_deep_sleep = NULL;
> > > + priv->exit_deep_sleep = NULL;
> > > + priv->reset_deep_sleep_wakeup = NULL;
> > > priv->fw_ready = 1;
> > >
> > > /* Initialize interrupt handling stuff. */
> > > diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
> > > index 92bc8c5..a8262de 100644
> > > --- a/drivers/net/wireless/libertas/if_usb.c
> > > +++ b/drivers/net/wireless/libertas/if_usb.c
> > > @@ -300,6 +300,9 @@ static int if_usb_probe(struct usb_interface *intf,
> > > cardp->priv->fw_ready = 1;
> > >
> > > priv->hw_host_to_card = if_usb_host_to_card;
> > > + priv->enter_deep_sleep = NULL;
> > > + priv->exit_deep_sleep = NULL;
> > > + priv->reset_deep_sleep_wakeup = NULL;
> > > #ifdef CONFIG_OLPC
> > > if (machine_is_olpc())
> > > priv->reset_card = if_usb_reset_olpc_card;
> > > diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
> > > index 8df1cfd..3b14fcc 100644
> > > --- a/drivers/net/wireless/libertas/main.c
> > > +++ b/drivers/net/wireless/libertas/main.c
> > > @@ -574,8 +574,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
> > > priv->dnld_sent = DNLD_RES_RECEIVED;
> > >
> > > /* Wake main thread if commands are pending */
> > > - if (!priv->cur_cmd || priv->tx_pending_len > 0)
> > > - wake_up_interruptible(&priv->waitq);
> > > + if (!priv->cur_cmd || priv->tx_pending_len > 0) {
> > > + if (!priv->wakeup_dev_required)
> > > + wake_up_interruptible(&priv->waitq);
> > > + }
> > >
> > > spin_unlock_irqrestore(&priv->driver_lock, flags);
> > > lbs_deb_leave(LBS_DEB_THREAD);
> > > @@ -770,7 +772,8 @@ static int lbs_thread(void *data)
> > > shouldsleep = 0; /* We have a command response */
> > > else if (priv->cur_cmd)
> > > shouldsleep = 1; /* Can't send a command; one already running */
> > > - else if (!list_empty(&priv->cmdpendingq))
> > > + else if (!list_empty(&priv->cmdpendingq) &&
> > > + !(priv->wakeup_dev_required))
> > > shouldsleep = 0; /* We have a command to send */
> > > else if (__kfifo_len(priv->event_fifo))
> > > shouldsleep = 0; /* We have an event to process */
> > > @@ -822,6 +825,26 @@ static int lbs_thread(void *data)
> > > }
> > > spin_unlock_irq(&priv->driver_lock);
> > >
> > > + /* Process hardware events, e.g. card removed, link lost */
> > > + spin_lock_irq(&priv->driver_lock);
> > > + while (__kfifo_len(priv->event_fifo)) {
> > > + u32 event;
> > > + __kfifo_get(priv->event_fifo, (unsigned char *) &event,
> > > + sizeof(event));
> > > + spin_unlock_irq(&priv->driver_lock);
> > > + lbs_process_event(priv, event);
> > > + spin_lock_irq(&priv->driver_lock);
> > > + }
> > > + spin_unlock_irq(&priv->driver_lock);
> > > +
> > > + if (priv->wakeup_dev_required) {
> > > + lbs_deb_thread("Waking up device...\n");
> > > + /* Wake up device */
> > > + if (priv->exit_deep_sleep(priv))
> > > + lbs_deb_thread("Wakeup device failed\n");
> > > + continue;
> > > + }
> > > +
> > > /* command timeout stuff */
> > > if (priv->cmd_timed_out && priv->cur_cmd) {
> > > struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
> > > @@ -849,18 +872,7 @@ static int lbs_thread(void *data)
> > > }
> > > priv->cmd_timed_out = 0;
> > >
> > > - /* Process hardware events, e.g. card removed, link lost */
> > > - spin_lock_irq(&priv->driver_lock);
> > > - while (__kfifo_len(priv->event_fifo)) {
> > > - u32 event;
> > >
> > > - __kfifo_get(priv->event_fifo, (unsigned char *) &event,
> > > - sizeof(event));
> > > - spin_unlock_irq(&priv->driver_lock);
> > > - lbs_process_event(priv, event);
> > > - spin_lock_irq(&priv->driver_lock);
> > > - }
> > > - spin_unlock_irq(&priv->driver_lock);
> > >
> > > if (!priv->fw_ready)
> > > continue;
> > > @@ -894,6 +906,9 @@ static int lbs_thread(void *data)
> > > (priv->psstate == PS_STATE_PRE_SLEEP))
> > > continue;
> > >
> > > + if (priv->is_deep_sleep)
> > > + continue;
> > > +
> > > /* Execute the next command */
> > > if (!priv->dnld_sent && !priv->cur_cmd)
> > > lbs_execute_next_command(priv);
> > > @@ -928,6 +943,7 @@ static int lbs_thread(void *data)
> > > }
> > >
> > > del_timer(&priv->command_timer);
> > > + del_timer(&priv->auto_deepsleep_timer);
> > > wake_up_all(&priv->cmd_pending);
> > >
> > > lbs_deb_leave(LBS_DEB_THREAD);
> > > @@ -1050,6 +1066,60 @@ out:
> > > lbs_deb_leave(LBS_DEB_CMD);
> > > }
> > >
> > > +/**
> > > + * This function put the device back to deep sleep mode when timer expires
> > > + * and no activity (command, event, data etc.) is detected.
> > > + */
> > > +static void auto_deepsleep_timer_fn(unsigned long data)
> > > +{
> > > + struct lbs_private *priv = (struct lbs_private *)data;
> > > + int ret;
> > > +
> > > + lbs_deb_enter(LBS_DEB_CMD);
> > > +
> > > + if (priv->is_activity_detected) {
> > > + priv->is_activity_detected = 0;
> > > + } else {
> > > + if (priv->is_auto_deep_sleep_enabled &&
> > > + (!priv->wakeup_dev_required) &&
> > > + (priv->connect_status != LBS_CONNECTED)) {
> > > + lbs_deb_main("Entering auto deep sleep mode...\n");
> > > + ret = lbs_prepare_and_send_command(priv,
> > > + CMD_802_11_DEEP_SLEEP, 0,
> > > + 0, 0, NULL);
> > > + }
> > > + }
> > > + mod_timer(&priv->auto_deepsleep_timer , jiffies +
> > > + (priv->auto_deep_sleep_timeout * HZ)/1000);
> > > + lbs_deb_leave(LBS_DEB_CMD);
> > > +}
> > > +
> > > +int lbs_enter_auto_deep_sleep(struct lbs_private *priv)
> > > +{
> > > + lbs_deb_enter(LBS_DEB_SDIO);
> > > +
> > > + priv->is_auto_deep_sleep_enabled = 1;
> > > + if (priv->is_deep_sleep)
> > > + priv->wakeup_dev_required = 1;
> > > + mod_timer(&priv->auto_deepsleep_timer ,
> > > + jiffies + (priv->auto_deep_sleep_timeout * HZ)/1000);
> > > +
> > > + lbs_deb_leave(LBS_DEB_SDIO);
> > > + return 0;
> > > +}
> > > +
> > > +int lbs_exit_auto_deep_sleep(struct lbs_private *priv)
> > > +{
> > > + lbs_deb_enter(LBS_DEB_SDIO);
> > > +
> > > + priv->is_auto_deep_sleep_enabled = 0;
> > > + priv->auto_deep_sleep_timeout = 0;
> > > + del_timer(&priv->auto_deepsleep_timer);
> > > +
> > > + lbs_deb_leave(LBS_DEB_SDIO);
> > > + return 0;
> > > +}
> > > +
> > > static void lbs_sync_channel_worker(struct work_struct *work)
> > > {
> > > struct lbs_private *priv = container_of(work, struct lbs_private,
> > > @@ -1099,11 +1169,17 @@ static int lbs_init_adapter(struct lbs_private *priv)
> > > priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
> > > priv->psmode = LBS802_11POWERMODECAM;
> > > priv->psstate = PS_STATE_FULL_POWER;
> > > + priv->is_deep_sleep = 0;
> > > + priv->is_auto_deep_sleep_enabled = 0;
> > > + priv->wakeup_dev_required = 0;
> > > + init_waitqueue_head(&priv->ds_awake_q);
> > >
> > > mutex_init(&priv->lock);
> > >
> > > setup_timer(&priv->command_timer, command_timer_fn,
> > > (unsigned long)priv);
> > > + setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn,
> > > + (unsigned long)priv);
> > >
> > > INIT_LIST_HEAD(&priv->cmdfreeq);
> > > INIT_LIST_HEAD(&priv->cmdpendingq);
> > > @@ -1142,6 +1218,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
> > > if (priv->event_fifo)
> > > kfifo_free(priv->event_fifo);
> > > del_timer(&priv->command_timer);
> > > + del_timer(&priv->auto_deepsleep_timer);
> > > kfree(priv->networks);
> > > priv->networks = NULL;
> > >
> > > @@ -1272,6 +1349,11 @@ void lbs_remove_card(struct lbs_private *priv)
> > > wrqu.ap_addr.sa_family = ARPHRD_ETHER;
> > > wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
> > >
> > > + if (priv->is_deep_sleep) {
> > > + priv->is_deep_sleep = 0;
> > > + wake_up_interruptible(&priv->ds_awake_q);
> > > + }
> > > +
> > > /* Stop the thread servicing the interrupts */
> > > priv->surpriseremoved = 1;
> > > kthread_stop(priv->main_thread);
> > > @@ -1392,6 +1474,7 @@ void lbs_stop_card(struct lbs_private *priv)
> > >
> > > /* Delete the timeout of the currently processing command */
> > > del_timer_sync(&priv->command_timer);
> > > + del_timer_sync(&priv->auto_deepsleep_timer);
> > >
> > > /* Flush pending command nodes */
> > > spin_lock_irqsave(&priv->driver_lock, flags);
> > > diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
> > > index 6c95af3..e468e15 100644
> > > --- a/drivers/net/wireless/libertas/scan.c
> > > +++ b/drivers/net/wireless/libertas/scan.c
> > > @@ -950,6 +950,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > if (!priv->radio_on) {
> > > ret = -EINVAL;
> > > goto out;
> > > @@ -1017,6 +1022,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + err = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);
> > > + return err;
> > > + }
> > > +
> > > /* iwlist should wait until the current scan is finished */
> > > if (priv->scan_channel)
> > > return -EAGAIN;
> > > diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
> > > index be837a0..ef2b986 100644
> > > --- a/drivers/net/wireless/libertas/wext.c
> > > +++ b/drivers/net/wireless/libertas/wext.c
> > > @@ -45,6 +45,31 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
> > > priv->pending_assoc_req = NULL;
> > > }
> > >
> > > +/**
> > > + * @brief This function checks if the command is allowed.
> > > + *
> > > + * @param priv A pointer to lbs_private structure
> > > + * @return allowed or not allowed.
> > > + */
> > > +
> > > +int lbs_is_cmd_allowed(struct lbs_private *priv)
> > > +{
> > > + int ret = 1;
> > > +
> > > + lbs_deb_enter(LBS_DEB_WEXT);
> > > +
> > > + if (!priv->is_auto_deep_sleep_enabled) {
> > > + if (priv->is_deep_sleep) {
> > > + lbs_deb_wext("IOCTLS called when station"
> > > + "is in deep sleep\n");
> > > + ret = 0;
> > > + }
> > > + }
> > > +
> > > + lbs_deb_leave(LBS_DEB_WEXT);
> > > + return ret;
> > > +}
> > > +
> > >
> > > /**
> > > * @brief Find the channel frequency power info with specific channel
> > > @@ -168,6 +193,11 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + lbs_deb_leave(LBS_DEB_WEXT);
> > > + return -EBUSY;
> > > + }
> > > +
> > > cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
> > > priv->curbssparams.channel);
> > >
> > > @@ -278,6 +308,12 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > if (vwrq->disabled)
> > > val = MRVDRV_RTS_MAX_VALUE;
> > >
> > > @@ -299,6 +335,11 @@ static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);
> > > if (ret)
> > > goto out;
> > > @@ -321,6 +362,12 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > if (vwrq->disabled)
> > > val = MRVDRV_FRAG_MAX_VALUE;
> > >
> > > @@ -342,6 +389,11 @@ static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);
> > > if (ret)
> > > goto out;
> > > @@ -391,6 +443,11 @@ static int lbs_get_txpow(struct net_device *dev,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > if (!priv->radio_on) {
> > > lbs_deb_wext("tx power off\n");
> > > vwrq->value = 0;
> > > @@ -424,6 +481,11 @@ static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
> > > return -EOPNOTSUPP;
> > >
> > > @@ -472,6 +534,11 @@ static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > vwrq->disabled = 0;
> > >
> > > if (vwrq->flags & IW_RETRY_LONG) {
> > > @@ -712,6 +779,11 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + lbs_deb_leave(LBS_DEB_WEXT);
> > > + return -EBUSY;
> > > + }
> > > +
> > > if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
> > > if (vwrq->disabled)
> > > return 0;
> > > @@ -792,6 +864,9 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv))
> > > + return NULL;
> > > +
> > > priv->wstats.status = priv->mode;
> > >
> > > /* If we're not associated, all quality values are meaningless */
> > > @@ -892,6 +967,12 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > mutex_lock(&priv->lock);
> > > assoc_req = lbs_get_association_request(priv);
> > > if (!assoc_req) {
> > > @@ -1000,6 +1081,12 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
> > > u8 rates[MAX_RATES + 1];
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > > +
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > lbs_deb_wext("vwrq->value %d\n", vwrq->value);
> > > lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
> > >
> > > @@ -1058,6 +1145,11 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + lbs_deb_leave(LBS_DEB_WEXT);
> > > + return -EBUSY;
> > > + }
> > > +
> > > if (priv->connect_status == LBS_CONNECTED) {
> > > vwrq->value = priv->cur_rate * 500000;
> > >
> > > @@ -1084,6 +1176,11 @@ static int lbs_set_mode(struct net_device *dev,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > if ( (*uwrq != IW_MODE_ADHOC)
> > > && (*uwrq != IW_MODE_INFRA)
> > > && (*uwrq != IW_MODE_AUTO)) {
> > > @@ -1325,6 +1422,12 @@ static int lbs_set_encode(struct net_device *dev,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > mutex_lock(&priv->lock);
> > > assoc_req = lbs_get_association_request(priv);
> > > if (!assoc_req) {
> > > @@ -1508,6 +1611,12 @@ static int lbs_set_encodeext(struct net_device *dev,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > mutex_lock(&priv->lock);
> > > assoc_req = lbs_get_association_request(priv);
> > > if (!assoc_req) {
> > > @@ -1720,6 +1829,12 @@ static int lbs_set_auth(struct net_device *dev,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > mutex_lock(&priv->lock);
> > > assoc_req = lbs_get_association_request(priv);
> > > if (!assoc_req) {
> > > @@ -1822,6 +1937,12 @@ static int lbs_get_auth(struct net_device *dev,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > switch (dwrq->flags & IW_AUTH_INDEX) {
> > > case IW_AUTH_KEY_MGMT:
> > > dwrq->value = priv->secinfo.key_mgmt;
> > > @@ -1864,6 +1985,11 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info
> > *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + goto out;
> > > + }
> > > +
> > > if (vwrq->disabled) {
> > > lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);
> > > goto out;
> > > @@ -1983,6 +2109,12 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info
> > *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > if (!priv->radio_on) {
> > > ret = -EINVAL;
> > > goto out;
> > > @@ -2110,6 +2242,12 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > + if (!lbs_is_cmd_allowed(priv)) {
> > > + ret = -EBUSY;
> > > + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
> > > + return ret;
> > > + }
> > > +
> > > if (!priv->radio_on)
> > > return -EINVAL;
> > >
>