2009-10-01 02:41:32

by Bing Zhao

[permalink] [raw]
Subject: [PATCH v2] 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 using iwconfig command. 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 | 26 ++++-
drivers/net/wireless/libertas/cmd.c | 72 ++++++++++++-
drivers/net/wireless/libertas/cmdresp.c | 12 ++
drivers/net/wireless/libertas/debugfs.c | 46 ++++++++
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 | 185 ++++++++++++++++++++++++++++++-
15 files changed, 533 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index ab6a2d5..635002d 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,28 @@ 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.

+========================
+IWCONFIG COMMANDS
+========================
+power period
+
+ This command is used to configure the station in deep sleep mode /
+ auto deep sleep mode.
+
+ The timer is implemented to monitor the activities (command, event,
+ 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 deep sleep mode is entered
+ automatically.
+
+ Note: this command is for SDIO interface only.
+
+ Usage:
+ To enable deep sleep mode do:
+ iwconfig wlan0 power period 0
+ To enable auto deep sleep mode with idle time period 5 seconds do:
+ iwconfig wlan0 power period 5
+ To disable deep sleep/auto deep sleep mode do:
+ iwconfig wlan0 power period -1
+
==============================================================================
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..8a7e931 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;
@@ -223,6 +233,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 +288,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 +460,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 +517,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 +558,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 +616,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 +657,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 +715,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;
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..38a451e 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) {
@@ -709,6 +776,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
struct lbs_private *priv = dev->ml_priv;
+ int ret = 0;

lbs_deb_enter(LBS_DEB_WEXT);

@@ -737,8 +805,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
"setting power timeout is not supported\n");
return -EINVAL;
} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- lbs_deb_wext("setting power period not supported\n");
- return -EINVAL;
+ vwrq->value = vwrq->value / 1000;
+ if (!priv->enter_deep_sleep) {
+ lbs_pr_err("deep sleep feature is not implemented "
+ "for this interface driver\n");
+ return -EINVAL;
+ }
+
+ if (priv->connect_status == LBS_CONNECTED) {
+ if ((priv->is_auto_deep_sleep_enabled) &&
+ (vwrq->value == -1000)) {
+ lbs_exit_auto_deep_sleep(priv);
+ return 0;
+ } else {
+ lbs_pr_err("can't use deep sleep cmd in "
+ "connected state\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((vwrq->value < 0) && (vwrq->value != -1000)) {
+ lbs_pr_err("unknown option\n");
+ return -EINVAL;
+ }
+
+ if (vwrq->value > 0) {
+ if (!priv->is_auto_deep_sleep_enabled) {
+ priv->is_activity_detected = 0;
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_enter_auto_deep_sleep(priv);
+ } else {
+ priv->auto_deep_sleep_timeout = vwrq->value;
+ lbs_deb_debugfs("auto deep sleep: "
+ "already enabled\n");
+ }
+ return 0;
+ } else {
+ if (priv->is_auto_deep_sleep_enabled) {
+ lbs_exit_auto_deep_sleep(priv);
+ /* Try to exit deep sleep if auto */
+ /*deep sleep disabled */
+ ret = lbs_set_deep_sleep(priv, 0);
+ }
+ if (vwrq->value == 0)
+ ret = lbs_set_deep_sleep(priv, 1);
+ else if (vwrq->value == -1000)
+ ret = lbs_set_deep_sleep(priv, 0);
+ return ret;
+ }
}

if (priv->psmode != LBS802_11POWERMODECAM) {
@@ -752,6 +866,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
}

lbs_deb_leave(LBS_DEB_WEXT);
+
return 0;
}

@@ -792,6 +907,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 +1010,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 +1124,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 +1188,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 +1219,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 +1465,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 +1654,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 +1872,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 +1980,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 +2028,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 +2152,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 +2285,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-10-01 07:43:08

by Holger Schurig

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

> Tests have been done for USB/CS cards to make sure that the patch
> won't break USB/CS code.


Side question: which firmware are you using on CS cards?

--
http://www.holgerschurig.de

2009-10-05 18:49:04

by Bing Zhao

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

SGkgRGFuLA0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IERhbiBXaWxs
aWFtcyBbbWFpbHRvOmRjYndAcmVkaGF0LmNvbV0NCj4gU2VudDogVGh1cnNkYXksIE9jdG9iZXIg
MDEsIDIwMDkgMTE6MjcgQU0NCj4gVG86IEJpbmcgWmhhbw0KPiBDYzogbGliZXJ0YXMtZGV2QGxp
c3RzLmluZnJhZGVhZC5vcmc7IEFtaXRrdW1hciBLYXJ3YXI7IGxpbnV4LXdpcmVsZXNzQHZnZXIu
a2VybmVsLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BBVENIIHYyXSBsaWJlcnRhczogQWRkIGF1dG8g
ZGVlcCBzbGVlcCBzdXBwb3J0IGZvciBTRDgzODUvU0Q4Njg2L1NEODY4OA0KPg0KPiBPbiBXZWQs
IDIwMDktMDktMzAgYXQgMjA6MDQgLTA3MDAsIEJpbmcgWmhhbyB3cm90ZToNCj4gPiBGcm9tOiBB
bWl0a3VtYXIgS2Fyd2FyIDxha2Fyd2FyQG1hcnZlbGwuY29tPg0KPiA+DQo+ID4gQWRkIHRpbWVy
IGJhc2VkIGF1dG8gZGVlcCBzbGVlcCBmZWF0dXJlIGluIGxpYmVydGFzIGRyaXZlciB3aGljaCBj
YW4gYmUNCj4gPiBjb25maWd1cmVkIHVzaW5nIGl3Y29uZmlnIGNvbW1hbmQuIFRoaXMgaXMgdGVz
dGVkIG9uIFNEODY4OCwgU0Q4Njg2IGNhcmRzDQo+ID4gd2l0aCBmaXJtd2FyZSB2ZXJzaW9ucyAx
MC4zOC4xLnAyNSwgOS43MC40LnAwIHJlc3BlY3RpdmVseSBvbiAzMi1iaXQgYW5kIDY0LWJpdA0K
PiA+IHBsYXRmb3Jtcy4gVGVzdHMgaGF2ZSBiZWVuIGRvbmUgZm9yIFVTQi9DUyBjYXJkcyB0byBt
YWtlIHN1cmUgdGhhdCB0aGUgcGF0Y2gNCj4gPiB3b24ndCBicmVhayBVU0IvQ1MgY29kZS4gV2Ug
ZGlkbid0IHRlc3QgdGhlIGlmX3NwaSBkcml2ZXIuDQo+ID4NCj4gPiBTaWduZWQtb2ZmLWJ5OiBB
bWl0a3VtYXIgS2Fyd2FyIDxha2Fyd2FyQG1hcnZlbGwuY29tPg0KPiA+IFNpZ25lZC1vZmYtYnk6
IEJpbmcgWmhhbyA8YnpoYW9AbWFydmVsbC5jb20+DQo+DQo+IEFja2VkLWJ5OiBEYW4gV2lsbGlh
bXMgPGRjYndAcmVkaGF0LmNvbT4NCj4NCj4gVGhvdWdoIEkgd29uZGVyIGlmIHdlIGNvdWxkIGp1
c3QgcHV0IHRoZSBsYnNfaXNfY21kX2FsbG93ZWQoKSBjaGVjayBpbnRvDQo+IHRoZSBhY3R1YWwg
Y29tbWFuZCBoYW5kbGluZyByb3V0aW5lcyBpbnN0ZWFkIG9mIHNwcmlua2xpbmcgaXQgYXJvdW5k
Lg0KDQpZZXMsIHdlIGNhbiBkbyB0aGF0Lg0KDQo+IFdlIGRpZCBtb3ZlIGF3YXkgZnJvbSB0aGUg
J29uZS1odWdlLXN3aXRjaCcgY29tbWFuZCBzdWJtaXNzaW9uIG1vZGVsLA0KPiB3aGljaCBtYWtl
cyBpdCBhIGJpdCBoYXJkZXIgdG8gZ2F0ZSBjb21tYW5kcyBiYXNlZCBvbiBkZXZpY2Ugc3RhdGUs
IGJ1dA0KPiBJIGNhbid0IHRoaW5rIG9mIGFueXRoaW5nIG9mZiB0aGUgdG9wIG9mIG15IGhlYWQg
dGhhdCB3b3VsZCBodXJ0IGJ5DQo+IGRvaW5nIGl0IGxpa2UgdGhhdC4NCj4NCj4gaS5lLiB3b3Vs
ZCBwdXR0aW5nIHRoZSBjaGVjayBpbiBib3RoIF9fbGJzX2NtZF9hc3luYygpIGFuZA0KPiBsYnNf
cHJlcGFyZV9hbmRfc2VuZF9jb21tYW5kKCkgYXJvdW5kIHdoZXJlIHRoZSBwcml2LT5zdXJwcmlz
ZV9yZW1vdmVkDQo+IGNoZWNrIGlzIHdvcmsgdG9vPw0KDQpXZSB3aWxsIHN1Ym1pdCBhIG5ldyBw
YXRjaCBmb3IgdGhpcy4NCg0KUmVnYXJkcywNCg0KQmluZw0KDQo+DQo+IERhbg0KPg0KPiA+IC0t
LQ0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9SRUFETUUgICAgfCAgIDI2ICsr
KystDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2NtZC5jICAgICB8ICAgNzIg
KysrKysrKysrKysrLQ0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWRyZXNw
LmMgfCAgIDEyICsrDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2RlYnVnZnMu
YyB8ICAgNDYgKysrKysrKysNCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGVj
bC5oICAgIHwgICAgNCArDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2Rldi5o
ICAgICB8ICAgMTggKysrDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2hvc3Qu
aCAgICB8ICAgIDEgKw0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9jcy5j
ICAgfCAgICAzICsNCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc2Rpby5j
IHwgICA1NiArKysrKysrKysNCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZf
c2Rpby5oIHwgICAgMyArLQ0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9z
cGkuYyAgfCAgICAzICsNCj4gPiAgZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfdXNi
LmMgIHwgICAgMyArDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL21haW4uYyAg
ICB8ICAxMTEgKysrKysrKysrKysrKysrKy0tLQ0KPiA+ICBkcml2ZXJzL25ldC93aXJlbGVzcy9s
aWJlcnRhcy9zY2FuLmMgICAgfCAgIDExICsrDQo+ID4gIGRyaXZlcnMvbmV0L3dpcmVsZXNzL2xp
YmVydGFzL3dleHQuYyAgICB8ICAxODUgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrLQ0K
PiA+ICAxNSBmaWxlcyBjaGFuZ2VkLCA1MzMgaW5zZXJ0aW9ucygrKSwgMjEgZGVsZXRpb25zKC0p
DQo+ID4NCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvUkVB
RE1FIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvUkVBRE1FDQo+ID4gaW5kZXggYWI2
YTJkNS4uNjM1MDAyZCAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJl
cnRhcy9SRUFETUUNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9SRUFE
TUUNCj4gPiBAQCAtMSw1ICsxLDUgQEANCj4gPiAgPT09PT09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCj4g
PiAtICAgICAgICAgICAgICAgICAgIFJFQURNRSBmb3IgVVNCODM4OA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgUkVBRE1FIGZvciBMaWJlcnRhcw0KPiA+DQo+ID4gICAoYykgQ29weXJpZ2h0IMKp
IDIwMDMtMjAwNiwgTWFydmVsbCBJbnRlcm5hdGlvbmFsIEx0ZC4NCj4gPiAgIEFsbCBSaWdodHMg
UmVzZXJ2ZWQNCj4gPiBAQCAtMjI2LDQgKzIyNiwyOCBAQCBzZXR1c2Vyc2Nhbg0KPiA+ICAgICAg
QWxsIGVudHJpZXMgaW4gdGhlIHNjYW4gdGFibGUgKG5vdCBqdXN0IHRoZSBuZXcgc2NhbiBkYXRh
IHdoZW4ga2VlcD0xKQ0KPiA+ICAgICAgd2lsbCBiZSBkaXNwbGF5ZWQgdXBvbiBjb21wbGV0aW9u
IGJ5IHVzZSBvZiB0aGUgZ2V0c2NhbnRhYmxlIGlvY3RsLg0KPiA+DQo+ID4gKz09PT09PT09PT09
PT09PT09PT09PT09PQ0KPiA+ICtJV0NPTkZJRyBDT01NQU5EUw0KPiA+ICs9PT09PT09PT09PT09
PT09PT09PT09PT0NCj4gPiArcG93ZXIgcGVyaW9kDQo+ID4gKw0KPiA+ICsgICBUaGlzIGNvbW1h
bmQgaXMgdXNlZCB0byBjb25maWd1cmUgdGhlIHN0YXRpb24gaW4gZGVlcCBzbGVlcCBtb2RlIC8N
Cj4gPiArICAgYXV0byBkZWVwIHNsZWVwIG1vZGUuDQo+ID4gKw0KPiA+ICsgICBUaGUgdGltZXIg
aXMgaW1wbGVtZW50ZWQgdG8gbW9uaXRvciB0aGUgYWN0aXZpdGllcyAoY29tbWFuZCwgZXZlbnQs
DQo+ID4gKyAgIGV0Yy4pLiBXaGVuIGFuIGFjdGl2aXR5IGlzIGRldGVjdGVkIHN0YXRpb24gd2ls
bCBleGl0IGZyb20gZGVlcA0KPiA+ICsgICBzbGVlcCBtb2RlIGF1dG9tYXRpY2FsbHkgYW5kIHJl
c3RhcnQgdGhlIHRpbWVyLiBBdCB0aW1lciBleHBpcnkNCj4gPiArICAgKG5vIGFjdGl2aXR5IGZv
ciBkZWZpbmVkIHRpbWUgcGVyaW9kKSB0aGUgZGVlcCBzbGVlcCBtb2RlIGlzIGVudGVyZWQNCj4g
PiArICAgYXV0b21hdGljYWxseS4NCj4gPiArDQo+ID4gKyAgIE5vdGU6IHRoaXMgY29tbWFuZCBp
cyBmb3IgU0RJTyBpbnRlcmZhY2Ugb25seS4NCj4gPiArDQo+ID4gKyAgIFVzYWdlOg0KPiA+ICsg
ICBUbyBlbmFibGUgZGVlcCBzbGVlcCBtb2RlIGRvOg0KPiA+ICsgICAgICAgICAgIGl3Y29uZmln
IHdsYW4wIHBvd2VyIHBlcmlvZCAwDQo+ID4gKyAgIFRvIGVuYWJsZSBhdXRvIGRlZXAgc2xlZXAg
bW9kZSB3aXRoIGlkbGUgdGltZSBwZXJpb2QgNSBzZWNvbmRzIGRvOg0KPiA+ICsgICAgICAgICAg
IGl3Y29uZmlnIHdsYW4wIHBvd2VyIHBlcmlvZCA1DQo+ID4gKyAgIFRvIGRpc2FibGUgZGVlcCBz
bGVlcC9hdXRvIGRlZXAgc2xlZXAgbW9kZSBkbzoNCj4gPiArICAgICAgICAgICBpd2NvbmZpZyB3
bGFuMCBwb3dlciBwZXJpb2QgLTENCj4gPiArDQo+ID4gID09PT09PT09PT09PT09PT09PT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0K
PiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWQuYyBiL2Ry
aXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2NtZC5jDQo+ID4gaW5kZXggNjg1MDk4MS4uM2Ez
ZTg5NCAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWQu
Yw0KPiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2NtZC5jDQo+ID4gQEAg
LTE3LDcgKzE3LDYgQEANCj4gPg0KPiA+ICBzdGF0aWMgc3RydWN0IGNtZF9jdHJsX25vZGUgKmxi
c19nZXRfY21kX2N0cmxfbm9kZShzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYpOw0KPiA+DQo+ID4g
LQ0KPiA+ICAvKioNCj4gPiAgICogIEBicmllZiBTaW1wbGUgY2FsbGJhY2sgdGhhdCBjb3BpZXMg
cmVzcG9uc2UgYmFjayBpbnRvIGNvbW1hbmQNCj4gPiAgICoNCj4gPiBAQCAtMzE5LDYgKzMxOCw2
MCBAQCBpbnQgbGJzX2NtZF84MDJfMTFfc2xlZXBfcGFyYW1zKHN0cnVjdCBsYnNfcHJpdmF0ZSAq
cHJpdiwgdWludDE2X3QgY21kX2FjdGlvbiwNCj4gPiAgICAgcmV0dXJuIDA7DQo+ID4gIH0NCj4g
Pg0KPiA+ICtzdGF0aWMgaW50IGxic193YWl0X2Zvcl9kc19hd2FrZShzdHJ1Y3QgbGJzX3ByaXZh
dGUgKnByaXYpDQo+ID4gK3sNCj4gPiArICAgaW50IHJldCA9IDA7DQo+ID4gKw0KPiA+ICsgICBs
YnNfZGViX2VudGVyKExCU19ERUJfQ01EKTsNCj4gPiArDQo+ID4gKyAgIGlmIChwcml2LT5pc19k
ZWVwX3NsZWVwKSB7DQo+ID4gKyAgICAgICAgICAgaWYgKCF3YWl0X2V2ZW50X2ludGVycnVwdGli
bGVfdGltZW91dChwcml2LT5kc19hd2FrZV9xLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICFwcml2LT5pc19kZWVwX3NsZWVwLCAoMTAgKiBIWikpKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICBsYnNfcHJfZXJyKCJkc19hd2FrZV9xOiB0aW1lciBleHBpcmVkXG4i
KTsNCj4gPiArICAgICAgICAgICAgICAgICAgIHJldCA9IC0xOw0KPiA+ICsgICAgICAgICAgIH0N
Cj4gPiArICAgfQ0KPiA+ICsNCj4gPiArICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfQ01E
LCAicmV0ICVkIiwgcmV0KTsNCj4gPiArICAgcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsNCj4g
PiAraW50IGxic19zZXRfZGVlcF9zbGVlcChzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYsIGludCBk
ZWVwX3NsZWVwKQ0KPiA+ICt7DQo+ID4gKyAgIGludCByZXQgPSAgMDsNCj4gPiArDQo+ID4gKyAg
IGxic19kZWJfZW50ZXIoTEJTX0RFQl9DTUQpOw0KPiA+ICsNCj4gPiArICAgaWYgKGRlZXBfc2xl
ZXApIHsNCj4gPiArICAgICAgICAgICBpZiAocHJpdi0+aXNfZGVlcF9zbGVlcCAhPSAxKSB7DQo+
ID4gKyAgICAgICAgICAgICAgICAgICBsYnNfZGViX2NtZCgiZGVlcCBzbGVlcDogc2xlZXBcbiIp
Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgQlVHX09OKCFwcml2LT5lbnRlcl9kZWVwX3NsZWVw
KTsNCj4gPiArICAgICAgICAgICAgICAgICAgIHJldCA9IHByaXYtPmVudGVyX2RlZXBfc2xlZXAo
cHJpdik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBpZiAoIXJldCkgew0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICBuZXRpZl9zdG9wX3F1ZXVlKHByaXYtPmRldik7DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgIG5ldGlmX2NhcnJpZXJfb2ZmKHByaXYtPmRldik7DQo+
ID4gKyAgICAgICAgICAgICAgICAgICB9DQo+ID4gKyAgICAgICAgICAgfSBlbHNlIHsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgIGxic19wcl9lcnIoImRlZXAgc2xlZXA6IGFscmVhZHkgZW5hYmxl
ZFxuIik7DQo+ID4gKyAgICAgICAgICAgfQ0KPiA+ICsgICB9IGVsc2Ugew0KPiA+ICsgICAgICAg
ICAgIGlmIChwcml2LT5pc19kZWVwX3NsZWVwKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBs
YnNfZGViX2NtZCgiZGVlcCBzbGVlcDogd2FrZXVwXG4iKTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgIEJVR19PTighcHJpdi0+ZXhpdF9kZWVwX3NsZWVwKTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgIHJldCA9IHByaXYtPmV4aXRfZGVlcF9zbGVlcChwcml2KTsNCj4gPiArICAgICAgICAgICAg
ICAgICAgIGlmICghcmV0KSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldCA9
IGxic193YWl0X2Zvcl9kc19hd2FrZShwcml2KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgaWYgKHJldCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBs
YnNfcHJfZXJyKCJkZWVwIHNsZWVwOiB3YWtldXAiDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmYWlsZWRcbiIpOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAgIH0NCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAr
ICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfQ01ELCAicmV0ICVkIiwgcmV0KTsNCj4gPiAr
ICAgcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsNCj4gPiAgaW50IGxic19jbWRfODAyXzExX3Nl
dF93ZXAoc3RydWN0IGxic19wcml2YXRlICpwcml2LCB1aW50MTZfdCBjbWRfYWN0aW9uLA0KPiA+
ICAgICAgICAgICAgICAgICAgICAgICAgc3RydWN0IGFzc29jX3JlcXVlc3QgKmFzc29jKQ0KPiA+
ICB7DQo+ID4gQEAgLTEyNDIsOCArMTI5NSwxNyBAQCBzdGF0aWMgdm9pZCBsYnNfc3VibWl0X2Nv
bW1hbmQoc3RydWN0IGxic19wcml2YXRlICpwcml2LA0KPiA+ICAgICAgICAgICAgIHRpbWVvID0g
SFovNDsNCj4gPiAgICAgfQ0KPiA+DQo+ID4gLSAgIC8qIFNldHVwIHRoZSB0aW1lciBhZnRlciB0
cmFuc21pdCBjb21tYW5kICovDQo+ID4gLSAgIG1vZF90aW1lcigmcHJpdi0+Y29tbWFuZF90aW1l
ciwgamlmZmllcyArIHRpbWVvKTsNCj4gPiArICAgaWYgKGNvbW1hbmQgPT0gQ01EXzgwMl8xMV9E
RUVQX1NMRUVQKSB7DQo+ID4gKyAgICAgICAgICAgaWYgKHByaXYtPmlzX2F1dG9fZGVlcF9zbGVl
cF9lbmFibGVkKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBwcml2LT53YWtldXBfZGV2X3Jl
cXVpcmVkID0gMTsNCj4gPiArICAgICAgICAgICAgICAgICAgIHByaXYtPmRubGRfc2VudCA9IDA7
DQo+ID4gKyAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAgIHByaXYtPmlzX2RlZXBfc2xlZXAg
PSAxOw0KPiA+ICsgICAgICAgICAgIGxic19jb21wbGV0ZV9jb21tYW5kKHByaXYsIGNtZG5vZGUs
IDApOw0KPiA+ICsgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgIC8qIFNldHVwIHRoZSB0aW1l
ciBhZnRlciB0cmFuc21pdCBjb21tYW5kICovDQo+ID4gKyAgICAgICAgICAgbW9kX3RpbWVyKCZw
cml2LT5jb21tYW5kX3RpbWVyLCBqaWZmaWVzICsgdGltZW8pOw0KPiA+ICsgICB9DQo+ID4NCj4g
PiAgICAgbGJzX2RlYl9sZWF2ZShMQlNfREVCX0hPU1QpOw0KPiA+ICB9DQo+ID4gQEAgLTE1MDUs
NiArMTU2NywxMCBAQCBpbnQgbGJzX3ByZXBhcmVfYW5kX3NlbmRfY29tbWFuZChzdHJ1Y3QgbGJz
X3ByaXZhdGUgKnByaXYsDQo+ID4gICAgIGNhc2UgQ01EXzgwMl8xMV9CRUFDT05fQ1RSTDoNCj4g
PiAgICAgICAgICAgICByZXQgPSBsYnNfY21kX2Jjbl9jdHJsKHByaXYsIGNtZHB0ciwgY21kX2Fj
dGlvbik7DQo+ID4gICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgIGNhc2UgQ01EXzgwMl8xMV9E
RUVQX1NMRUVQOg0KPiA+ICsgICAgICAgICAgIGNtZHB0ci0+Y29tbWFuZCA9IGNwdV90b19sZTE2
KENNRF84MDJfMTFfREVFUF9TTEVFUCk7DQo+ID4gKyAgICAgICAgICAgY21kcHRyLT5zaXplID0g
Y3B1X3RvX2xlMTYoU19EU19HRU4pOw0KPiA+ICsgICAgICAgICAgIGJyZWFrOw0KPiA+ICAgICBk
ZWZhdWx0Og0KPiA+ICAgICAgICAgICAgIGxic19wcl9lcnIoIlBSRVBfQ01EOiB1bmtub3duIGNv
bW1hbmQgMHglMDR4XG4iLCBjbWRfbm8pOw0KPiA+ICAgICAgICAgICAgIHJldCA9IC0xOw0KPiA+
IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWRyZXNwLmMgYi9k
cml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9jbWRyZXNwLmMNCj4gPiBpbmRleCBjNDJkM2Zh
Li40N2QyYjE5IDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFz
L2NtZHJlc3AuYw0KPiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2NtZHJl
c3AuYw0KPiA+IEBAIC01MDQsOSArNTA0LDIxIEBAIGludCBsYnNfcHJvY2Vzc19ldmVudChzdHJ1
Y3QgbGJzX3ByaXZhdGUgKnByaXYsIHUzMiBldmVudCkNCj4gPg0KPiA+ICAgICBjYXNlIE1BQ1JF
R19JTlRfQ09ERV9IT1NUX0FXQUtFOg0KPiA+ICAgICAgICAgICAgIGxic19kZWJfY21kKCJFVkVO
VDogaG9zdCBhd2FrZVxuIik7DQo+ID4gKyAgICAgICAgICAgaWYgKHByaXYtPnJlc2V0X2RlZXBf
c2xlZXBfd2FrZXVwKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgcHJpdi0+cmVzZXRfZGVlcF9z
bGVlcF93YWtldXAocHJpdik7DQo+ID4gKyAgICAgICAgICAgcHJpdi0+aXNfZGVlcF9zbGVlcCA9
IDA7DQo+ID4gICAgICAgICAgICAgbGJzX3NlbmRfY29uZmlybXdha2UocHJpdik7DQo+ID4gICAg
ICAgICAgICAgYnJlYWs7DQo+ID4NCj4gPiArICAgY2FzZSBNQUNSRUdfSU5UX0NPREVfREVFUF9T
TEVFUF9BV0FLRToNCj4gPiArICAgICAgICAgICBpZiAocHJpdi0+cmVzZXRfZGVlcF9zbGVlcF93
YWtldXApDQo+ID4gKyAgICAgICAgICAgICAgICAgICBwcml2LT5yZXNldF9kZWVwX3NsZWVwX3dh
a2V1cChwcml2KTsNCj4gPiArICAgICAgICAgICBsYnNfZGViX2NtZCgiRVZFTlQ6IGRzIGF3YWtl
XG4iKTsNCj4gPiArICAgICAgICAgICBwcml2LT5pc19kZWVwX3NsZWVwID0gMDsNCj4gPiArICAg
ICAgICAgICBwcml2LT53YWtldXBfZGV2X3JlcXVpcmVkID0gMDsNCj4gPiArICAgICAgICAgICB3
YWtlX3VwX2ludGVycnVwdGlibGUoJnByaXYtPmRzX2F3YWtlX3EpOw0KPiA+ICsgICAgICAgICAg
IGJyZWFrOw0KPiA+ICsNCj4gPiAgICAgY2FzZSBNQUNSRUdfSU5UX0NPREVfUFNfQVdBS0U6DQo+
ID4gICAgICAgICAgICAgbGJzX2RlYl9jbWQoIkVWRU5UOiBwcyBhd2FrZVxuIik7DQo+ID4gICAg
ICAgICAgICAgLyogaGFuZGxlIHVuZXhwZWN0ZWQgUFMgQVdBS0UgZXZlbnQgKi8NCj4gPiBkaWZm
IC0tZ2l0IGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGVidWdmcy5jIGIvZHJpdmVy
cy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGVidWdmcy5jDQo+ID4gaW5kZXggODkzYTU1Yy4uOGE3
ZTkzMSAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9kZWJ1
Z2ZzLmMNCj4gPiArKysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9kZWJ1Z2ZzLmMN
Cj4gPiBAQCAtMTE3LDYgKzExNywxMSBAQCBzdGF0aWMgc3NpemVfdCBsYnNfc2xlZXBwYXJhbXNf
d3JpdGUoc3RydWN0IGZpbGUgKmZpbGUsDQo+ID4gICAgIGlmICghYnVmKQ0KPiA+ICAgICAgICAg
ICAgIHJldHVybiAtRU5PTUVNOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2Vk
KHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAg
IGdvdG8gb3V0X3VubG9jazsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgYnVmX3NpemUgPSBt
aW4oY291bnQsIGxlbiAtIDEpOw0KPiA+ICAgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2Vy
X2J1ZiwgYnVmX3NpemUpKSB7DQo+ID4gICAgICAgICAgICAgcmV0ID0gLUVGQVVMVDsNCj4gPiBA
QCAtMTU3LDYgKzE2MiwxMSBAQCBzdGF0aWMgc3NpemVfdCBsYnNfc2xlZXBwYXJhbXNfcmVhZChz
dHJ1Y3QgZmlsZSAqZmlsZSwgY2hhciBfX3VzZXIgKnVzZXJidWYsDQo+ID4gICAgIGlmICghYnVm
KQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRU5PTUVNOw0KPiA+DQo+ID4gKyAgIGlmICghbGJz
X2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0K
PiA+ICsgICAgICAgICAgIGdvdG8gb3V0X3VubG9jazsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAg
ICAgcmV0ID0gbGJzX2NtZF84MDJfMTFfc2xlZXBfcGFyYW1zKHByaXYsIENNRF9BQ1RfR0VULCAm
c3ApOw0KPiA+ICAgICBpZiAocmV0KQ0KPiA+ICAgICAgICAgICAgIGdvdG8gb3V0X3VubG9jazsN
Cj4gPiBAQCAtMjIzLDYgKzIzMyw5IEBAIHN0YXRpYyBzc2l6ZV90IGxic190aHJlc2hvbGRfcmVh
ZCh1aW50MTZfdCB0bHZfdHlwZSwgdWludDE2X3QgZXZlbnRfbWFzaywNCj4gPiAgICAgdTggZnJl
cTsNCj4gPiAgICAgaW50IGV2ZW50cyA9IDA7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21k
X2FsbG93ZWQocHJpdikpDQo+ID4gKyAgICAgICAgICAgcmV0dXJuIC1FQlVTWTsNCj4gPiArDQo+
ID4gICAgIGJ1ZiA9IChjaGFyICopZ2V0X3plcm9lZF9wYWdlKEdGUF9LRVJORUwpOw0KPiA+ICAg
ICBpZiAoIWJ1ZikNCj4gPiAgICAgICAgICAgICByZXR1cm4gLUVOT01FTTsNCj4gPiBAQCAtMjc1
LDYgKzI4OCw5IEBAIHN0YXRpYyBzc2l6ZV90IGxic190aHJlc2hvbGRfd3JpdGUodWludDE2X3Qg
dGx2X3R5cGUsIHVpbnQxNl90IGV2ZW50X21hc2ssDQo+ID4gICAgIGNoYXIgKmJ1ZjsNCj4gPiAg
ICAgaW50IHJldDsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkN
Cj4gPiArICAgICAgICAgICByZXR1cm4gLUVCVVNZOw0KPiA+ICsNCj4gPiAgICAgYnVmID0gKGNo
YXIgKilnZXRfemVyb2VkX3BhZ2UoR0ZQX0tFUk5FTCk7DQo+ID4gICAgIGlmICghYnVmKQ0KPiA+
ICAgICAgICAgICAgIHJldHVybiAtRU5PTUVNOw0KPiA+IEBAIC00NDQsNiArNDYwLDExIEBAIHN0
YXRpYyBzc2l6ZV90IGxic19yZG1hY19yZWFkKHN0cnVjdCBmaWxlICpmaWxlLCBjaGFyIF9fdXNl
ciAqdXNlcmJ1ZiwNCj4gPiAgICAgaWYgKCFidWYpDQo+ID4gICAgICAgICAgICAgcmV0dXJuIC1F
Tk9NRU07DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4g
PiArICAgICAgICAgICBmcmVlX3BhZ2UoYWRkcik7DQo+ID4gKyAgICAgICAgICAgcmV0dXJuIC1F
QlVTWTsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgb2ZmdmFsLm9mZnNldCA9IHByaXYtPm1h
Y19vZmZzZXQ7DQo+ID4gICAgIG9mZnZhbC52YWx1ZSA9IDA7DQo+ID4NCj4gPiBAQCAtNDk2LDYg
KzUxNywxMSBAQCBzdGF0aWMgc3NpemVfdCBsYnNfd3JtYWNfd3JpdGUoc3RydWN0IGZpbGUgKmZp
bGUsDQo+ID4gICAgIGlmICghYnVmKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRU5PTUVNOw0K
PiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAg
ICAgICAgcmVzID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0X3VubG9jazsNCj4g
PiArICAgfQ0KPiA+ICsNCj4gPiAgICAgYnVmX3NpemUgPSBtaW4oY291bnQsIGxlbiAtIDEpOw0K
PiA+ICAgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2VyYnVmLCBidWZfc2l6ZSkpIHsNCj4g
PiAgICAgICAgICAgICByZXMgPSAtRUZBVUxUOw0KPiA+IEBAIC01MzIsNiArNTU4LDExIEBAIHN0
YXRpYyBzc2l6ZV90IGxic19yZGJicF9yZWFkKHN0cnVjdCBmaWxlICpmaWxlLCBjaGFyIF9fdXNl
ciAqdXNlcmJ1ZiwNCj4gPiAgICAgaWYgKCFidWYpDQo+ID4gICAgICAgICAgICAgcmV0dXJuIC1F
Tk9NRU07DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4g
PiArICAgICAgICAgICBmcmVlX3BhZ2UoYWRkcik7DQo+ID4gKyAgICAgICAgICAgcmV0dXJuIC1F
QlVTWTsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgb2ZmdmFsLm9mZnNldCA9IHByaXYtPmJi
cF9vZmZzZXQ7DQo+ID4gICAgIG9mZnZhbC52YWx1ZSA9IDA7DQo+ID4NCj4gPiBAQCAtNTg1LDYg
KzYxNiwxMSBAQCBzdGF0aWMgc3NpemVfdCBsYnNfd3JiYnBfd3JpdGUoc3RydWN0IGZpbGUgKmZp
bGUsDQo+ID4gICAgIGlmICghYnVmKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRU5PTUVNOw0K
PiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAg
ICAgICAgcmVzID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0X3VubG9jazsNCj4g
PiArICAgfQ0KPiA+ICsNCj4gPiAgICAgYnVmX3NpemUgPSBtaW4oY291bnQsIGxlbiAtIDEpOw0K
PiA+ICAgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2VyYnVmLCBidWZfc2l6ZSkpIHsNCj4g
PiAgICAgICAgICAgICByZXMgPSAtRUZBVUxUOw0KPiA+IEBAIC02MjEsNiArNjU3LDExIEBAIHN0
YXRpYyBzc2l6ZV90IGxic19yZHJmX3JlYWQoc3RydWN0IGZpbGUgKmZpbGUsIGNoYXIgX191c2Vy
ICp1c2VyYnVmLA0KPiA+ICAgICBpZiAoIWJ1ZikNCj4gPiAgICAgICAgICAgICByZXR1cm4gLUVO
T01FTTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+
ICsgICAgICAgICAgIGZyZWVfcGFnZShhZGRyKTsNCj4gPiArICAgICAgICAgICByZXR1cm4gLUVC
VVNZOw0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBvZmZ2YWwub2Zmc2V0ID0gcHJpdi0+cmZf
b2Zmc2V0Ow0KPiA+ICAgICBvZmZ2YWwudmFsdWUgPSAwOw0KPiA+DQo+ID4gQEAgLTY3NCw2ICs3
MTUsMTEgQEAgc3RhdGljIHNzaXplX3QgbGJzX3dycmZfd3JpdGUoc3RydWN0IGZpbGUgKmZpbGUs
DQo+ID4gICAgIGlmICghYnVmKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRU5PTUVNOw0KPiA+
DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAg
ICAgcmVzID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0X3VubG9jazsNCj4gPiAr
ICAgfQ0KPiA+ICsNCj4gPiAgICAgYnVmX3NpemUgPSBtaW4oY291bnQsIGxlbiAtIDEpOw0KPiA+
ICAgICBpZiAoY29weV9mcm9tX3VzZXIoYnVmLCB1c2VyYnVmLCBidWZfc2l6ZSkpIHsNCj4gPiAg
ICAgICAgICAgICByZXMgPSAtRUZBVUxUOw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93
aXJlbGVzcy9saWJlcnRhcy9kZWNsLmggYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9k
ZWNsLmgNCj4gPiBpbmRleCAwYjg0YmRjLi4zNGI0NzVmIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZl
cnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2RlY2wuaA0KPiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dp
cmVsZXNzL2xpYmVydGFzL2RlY2wuaA0KPiA+IEBAIC0zMyw2ICszMywxMCBAQCBpbnQgbGJzX2V4
ZWN1dGVfbmV4dF9jb21tYW5kKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdik7DQo+ID4gIGludCBs
YnNfcHJvY2Vzc19ldmVudChzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYsIHUzMiBldmVudCk7DQo+
ID4gIHZvaWQgbGJzX3F1ZXVlX2V2ZW50KHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdiwgdTMyIGV2
ZW50KTsNCj4gPiAgdm9pZCBsYnNfbm90aWZ5X2NvbW1hbmRfcmVzcG9uc2Uoc3RydWN0IGxic19w
cml2YXRlICpwcml2LCB1OCByZXNwX2lkeCk7DQo+ID4gK2ludCBsYnNfc2V0X2RlZXBfc2xlZXAo
c3RydWN0IGxic19wcml2YXRlICpwcml2LCBpbnQgZGVlcF9zbGVlcCk7DQo+ID4gK2ludCBsYnNf
aXNfY21kX2FsbG93ZWQoc3RydWN0IGxic19wcml2YXRlICpwcml2KTsNCj4gPiAraW50IGxic19l
bnRlcl9hdXRvX2RlZXBfc2xlZXAoc3RydWN0IGxic19wcml2YXRlICpwcml2KTsNCj4gPiAraW50
IGxic19leGl0X2F1dG9fZGVlcF9zbGVlcChzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYpOw0KPiA+
DQo+ID4gIHUzMiBsYnNfZndfaW5kZXhfdG9fZGF0YV9yYXRlKHU4IGluZGV4KTsNCj4gPiAgdTgg
bGJzX2RhdGFfcmF0ZV90b19md19pbmRleCh1MzIgcmF0ZSk7DQo+ID4gZGlmZiAtLWdpdCBhL2Ry
aXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2Rldi5oIGIvZHJpdmVycy9uZXQvd2lyZWxlc3Mv
bGliZXJ0YXMvZGV2LmgNCj4gPiBpbmRleCA1NzhjNjk3Li5lMmI0ZWYyIDEwMDY0NA0KPiA+IC0t
LSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2Rldi5oDQo+ID4gKysrIGIvZHJpdmVy
cy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvZGV2LmgNCj4gPiBAQCAtMTI5LDYgKzEyOSwyMCBAQCBz
dHJ1Y3QgbGJzX3ByaXZhdGUgew0KPiA+ICAgICB1MzIgYmJwX29mZnNldDsNCj4gPiAgICAgdTMy
IHJmX29mZnNldDsNCj4gPg0KPiA+ICsgICAvKiogRGVlcCBzbGVlcCBmbGFnICovDQo+ID4gKyAg
IGludCBpc19kZWVwX3NsZWVwOw0KPiA+ICsgICAvKiogQXV0byBkZWVwIHNsZWVwIGVuYWJsZWQg
ZmxhZyAqLw0KPiA+ICsgICBpbnQgaXNfYXV0b19kZWVwX3NsZWVwX2VuYWJsZWQ7DQo+ID4gKyAg
IC8qKiBEZXZpY2Ugd2FrZXVwIHJlcXVpcmVkIGZsYWcgKi8NCj4gPiArICAgaW50IHdha2V1cF9k
ZXZfcmVxdWlyZWQ7DQo+ID4gKyAgIC8qKiBBdXRvIGRlZXAgc2xlZXAgZmxhZyovDQo+ID4gKyAg
IGludCBpc19hY3Rpdml0eV9kZXRlY3RlZDsNCj4gPiArICAgLyoqIEF1dG8gZGVlcCBzbGVlcCB0
aW1lb3V0IChpbiBtaWxpc2Vjb25kcykgKi8NCj4gPiArICAgaW50IGF1dG9fZGVlcF9zbGVlcF90
aW1lb3V0Ow0KPiA+ICsNCj4gPiArICAgLyoqIERlZXAgc2xlZXAgd2FpdCBxdWV1ZSAqLw0KPiA+
ICsgICB3YWl0X3F1ZXVlX2hlYWRfdCAgICAgICBkc19hd2FrZV9xOw0KPiA+ICsNCj4gPiAgICAg
LyogRG93bmxvYWQgc2VudDoNCj4gPiAgICAgICAgYml0MCAxLzA9ZGF0YV9zZW50L2RhdGFfdHhf
ZG9uZSwNCj4gPiAgICAgICAgYml0MSAxLzA9Y21kX3NlbnQvY21kX3R4X2RvbmUsDQo+ID4gQEAg
LTE1NCw2ICsxNjgsOSBAQCBzdHJ1Y3QgbGJzX3ByaXZhdGUgew0KPiA+ICAgICAvKiogSGFyZHdh
cmUgYWNjZXNzICovDQo+ID4gICAgIGludCAoKmh3X2hvc3RfdG9fY2FyZCkgKHN0cnVjdCBsYnNf
cHJpdmF0ZSAqcHJpdiwgdTggdHlwZSwgdTggKnBheWxvYWQsIHUxNiBuYik7DQo+ID4gICAgIHZv
aWQgKCpyZXNldF9jYXJkKSAoc3RydWN0IGxic19wcml2YXRlICpwcml2KTsNCj4gPiArICAgaW50
ICgqZW50ZXJfZGVlcF9zbGVlcCkgKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdik7DQo+ID4gKyAg
IGludCAoKmV4aXRfZGVlcF9zbGVlcCkgKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdik7DQo+ID4g
KyAgIGludCAoKnJlc2V0X2RlZXBfc2xlZXBfd2FrZXVwKSAoc3RydWN0IGxic19wcml2YXRlICpw
cml2KTsNCj4gPg0KPiA+ICAgICAvKiBXYWtlIE9uIExBTiAqLw0KPiA+ICAgICB1aW50MzJfdCB3
b2xfY3JpdGVyaWE7DQo+ID4gQEAgLTIwNCw2ICsyMjEsNyBAQCBzdHJ1Y3QgbGJzX3ByaXZhdGUg
ew0KPiA+DQo+ID4gICAgIC8qKiBUaW1lcnMgKi8NCj4gPiAgICAgc3RydWN0IHRpbWVyX2xpc3Qg
Y29tbWFuZF90aW1lcjsNCj4gPiArICAgc3RydWN0IHRpbWVyX2xpc3QgYXV0b19kZWVwc2xlZXBf
dGltZXI7DQo+ID4gICAgIGludCBucl9yZXRyaWVzOw0KPiA+ICAgICBpbnQgY21kX3RpbWVkX291
dDsNCj4gPg0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9o
b3N0LmggYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9ob3N0LmgNCj4gPiBpbmRleCBm
ZThmMGNiLi5jMDU1ZGFhIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xp
YmVydGFzL2hvc3QuaA0KPiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2hv
c3QuaA0KPiA+IEBAIC01Nyw2ICs1Nyw3IEBADQo+ID4gICNkZWZpbmUgQ01EXzgwMl8xMV9FTkFC
TEVfUlNOICAgICAgICAgICAgICAgICAgICAgIDB4MDAyZg0KPiA+ICAjZGVmaW5lIENNRF84MDJf
MTFfU0VUX0FGQyAgICAgICAgICAgICAgICAgMHgwMDNjDQo+ID4gICNkZWZpbmUgQ01EXzgwMl8x
MV9HRVRfQUZDICAgICAgICAgICAgICAgICAweDAwM2QNCj4gPiArI2RlZmluZSBDTURfODAyXzEx
X0RFRVBfU0xFRVAgICAgICAgICAgICAgICAgICAweDAwM2UNCj4gPiAgI2RlZmluZSBDTURfODAy
XzExX0FEX0hPQ19TVE9QICAgICAgICAgICAgICAgICAgICAgMHgwMDQwDQo+ID4gICNkZWZpbmUg
Q01EXzgwMl8xMV9IT1NUX1NMRUVQX0NGRyAgICAgICAgICAweDAwNDMNCj4gPiAgI2RlZmluZSBD
TURfODAyXzExX1dBS0VVUF9DT05GSVJNICAgICAgICAgIDB4MDA0NA0KPiA+IGRpZmYgLS1naXQg
YS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9jcy5jIGIvZHJpdmVycy9uZXQvd2ly
ZWxlc3MvbGliZXJ0YXMvaWZfY3MuYw0KPiA+IGluZGV4IDYyMzgxNzYuLjQ2NTc0MmYgMTAwNjQ0
DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfY3MuYw0KPiA+ICsr
KyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX2NzLmMNCj4gPiBAQCAtOTQ2LDYg
Kzk0Niw5IEBAIHN0YXRpYyBpbnQgaWZfY3NfcHJvYmUoc3RydWN0IHBjbWNpYV9kZXZpY2UgKnBf
ZGV2KQ0KPiA+ICAgICBjYXJkLT5wcml2ID0gcHJpdjsNCj4gPiAgICAgcHJpdi0+Y2FyZCA9IGNh
cmQ7DQo+ID4gICAgIHByaXYtPmh3X2hvc3RfdG9fY2FyZCA9IGlmX2NzX2hvc3RfdG9fY2FyZDsN
Cj4gPiArICAgcHJpdi0+ZW50ZXJfZGVlcF9zbGVlcCA9IE5VTEw7DQo+ID4gKyAgIHByaXYtPmV4
aXRfZGVlcF9zbGVlcCA9IE5VTEw7DQo+ID4gKyAgIHByaXYtPnJlc2V0X2RlZXBfc2xlZXBfd2Fr
ZXVwID0gTlVMTDsNCj4gPiAgICAgcHJpdi0+ZndfcmVhZHkgPSAxOw0KPiA+DQo+ID4gICAgIC8q
IE5vdyBhY3R1YWxseSBnZXQgdGhlIElSUSAqLw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25l
dC93aXJlbGVzcy9saWJlcnRhcy9pZl9zZGlvLmMgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJl
cnRhcy9pZl9zZGlvLmMNCj4gPiBpbmRleCA0ODVhOGQ0Li45NzE2NzI4IDEwMDY0NA0KPiA+IC0t
LSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3NkaW8uYw0KPiA+ICsrKyBiL2Ry
aXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3NkaW8uYw0KPiA+IEBAIC04MzEsNiArODMx
LDU4IEBAIG91dDoNCj4gPiAgICAgcmV0dXJuIHJldDsNCj4gPiAgfQ0KPiA+DQo+ID4gK3N0YXRp
YyBpbnQgaWZfc2Rpb19lbnRlcl9kZWVwX3NsZWVwKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdikN
Cj4gPiArew0KPiA+ICsgICBpbnQgcmV0ID0gLTE7DQo+ID4gKyAgIHN0cnVjdCBjbWRfaGVhZGVy
IGNtZDsNCj4gPiArDQo+ID4gKyAgIG1lbXNldCgmY21kLCAwLCBzaXplb2YoY21kKSk7DQo+ID4g
Kw0KPiA+ICsgICBsYnNfZGViX3NkaW8oInNlbmQgREVFUF9TTEVFUCBjb21tYW5kXG4iKTsNCj4g
PiArICAgcmV0ID0gX19sYnNfY21kKHByaXYsIENNRF84MDJfMTFfREVFUF9TTEVFUCwgJmNtZCwg
c2l6ZW9mKGNtZCksDQo+ID4gKyAgICAgICAgICAgICAgICAgICBsYnNfY21kX2NvcHliYWNrLCAo
dW5zaWduZWQgbG9uZykgJmNtZCk7DQo+ID4gKyAgIGlmIChyZXQpDQo+ID4gKyAgICAgICAgICAg
bGJzX3ByX2VycigiREVFUF9TTEVFUCBjbWQgZmFpbGVkXG4iKTsNCj4gPiArDQo+ID4gKyAgIG1k
ZWxheSgyMDApOw0KPiA+ICsgICByZXR1cm4gcmV0Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0
aWMgaW50IGlmX3NkaW9fZXhpdF9kZWVwX3NsZWVwKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdikN
Cj4gPiArew0KPiA+ICsgICBzdHJ1Y3QgaWZfc2Rpb19jYXJkICpjYXJkID0gcHJpdi0+Y2FyZDsN
Cj4gPiArICAgaW50IHJldCA9IC0xOw0KPiA+ICsNCj4gPiArICAgbGJzX2RlYl9lbnRlcihMQlNf
REVCX1NESU8pOw0KPiA+ICsgICBzZGlvX2NsYWltX2hvc3QoY2FyZC0+ZnVuYyk7DQo+ID4gKw0K
PiA+ICsgICBzZGlvX3dyaXRlYihjYXJkLT5mdW5jLCBIT1NUX1BPV0VSX1VQLCBDT05GSUdVUkFU
SU9OX1JFRywgJnJldCk7DQo+ID4gKyAgIGlmIChyZXQpDQo+ID4gKyAgICAgICAgICAgbGJzX3By
X2Vycigic2Rpb193cml0ZWIgZmFpbGVkIVxuIik7DQo+ID4gKw0KPiA+ICsgICBzZGlvX3JlbGVh
c2VfaG9zdChjYXJkLT5mdW5jKTsNCj4gPiArICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJf
U0RJTywgInJldCAlZCIsIHJldCk7DQo+ID4gKyAgIHJldHVybiByZXQ7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK3N0YXRpYyBpbnQgaWZfc2Rpb19yZXNldF9kZWVwX3NsZWVwX3dha2V1cChzdHJ1Y3Qg
bGJzX3ByaXZhdGUgKnByaXYpDQo+ID4gK3sNCj4gPiArICAgc3RydWN0IGlmX3NkaW9fY2FyZCAq
Y2FyZCA9IHByaXYtPmNhcmQ7DQo+ID4gKyAgIGludCByZXQgPSAtMTsNCj4gPiArDQo+ID4gKyAg
IGxic19kZWJfZW50ZXIoTEJTX0RFQl9TRElPKTsNCj4gPiArICAgc2Rpb19jbGFpbV9ob3N0KGNh
cmQtPmZ1bmMpOw0KPiA+ICsNCj4gPiArICAgc2Rpb193cml0ZWIoY2FyZC0+ZnVuYywgMCwgQ09O
RklHVVJBVElPTl9SRUcsICZyZXQpOw0KPiA+ICsgICBpZiAocmV0KQ0KPiA+ICsgICAgICAgICAg
IGxic19wcl9lcnIoInNkaW9fd3JpdGViIGZhaWxlZCFcbiIpOw0KPiA+ICsNCj4gPiArICAgc2Rp
b19yZWxlYXNlX2hvc3QoY2FyZC0+ZnVuYyk7DQo+ID4gKyAgIGxic19kZWJfbGVhdmVfYXJncyhM
QlNfREVCX1NESU8sICJyZXQgJWQiLCByZXQpOw0KPiA+ICsgICByZXR1cm4gcmV0Ow0KPiA+ICsN
Cj4gPiArfQ0KPiA+ICsNCj4gPiAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovDQo+ID4gIC8qIFNESU8gY2FsbGJhY2tz
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqLw0KPiA+
ICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
KioqKioqKioqKioqKi8NCj4gPiBAQCAtODU5LDYgKzkxMSw3IEBAIHN0YXRpYyB2b2lkIGlmX3Nk
aW9faW50ZXJydXB0KHN0cnVjdCBzZGlvX2Z1bmMgKmZ1bmMpDQo+ID4gICAgICAqIElnbm9yZSB0
aGUgZGVmaW5lIG5hbWUsIHRoaXMgcmVhbGx5IG1lYW5zIHRoZSBjYXJkIGhhcw0KPiA+ICAgICAg
KiBzdWNjZXNzZnVsbHkgcmVjZWl2ZWQgdGhlIGNvbW1hbmQuDQo+ID4gICAgICAqLw0KPiA+ICsg
ICBjYXJkLT5wcml2LT5pc19hY3Rpdml0eV9kZXRlY3RlZCA9IDE7DQo+ID4gICAgIGlmIChjYXVz
ZSAmIElGX1NESU9fSF9JTlRfRE5MRCkNCj4gPiAgICAgICAgICAgICBsYnNfaG9zdF90b19jYXJk
X2RvbmUoY2FyZC0+cHJpdik7DQo+ID4NCj4gPiBAQCAtOTk4LDYgKzEwNTEsOSBAQCBzdGF0aWMg
aW50IGlmX3NkaW9fcHJvYmUoc3RydWN0IHNkaW9fZnVuYyAqZnVuYywNCj4gPg0KPiA+ICAgICBw
cml2LT5jYXJkID0gY2FyZDsNCj4gPiAgICAgcHJpdi0+aHdfaG9zdF90b19jYXJkID0gaWZfc2Rp
b19ob3N0X3RvX2NhcmQ7DQo+ID4gKyAgIHByaXYtPmVudGVyX2RlZXBfc2xlZXAgPSBpZl9zZGlv
X2VudGVyX2RlZXBfc2xlZXA7DQo+ID4gKyAgIHByaXYtPmV4aXRfZGVlcF9zbGVlcCA9IGlmX3Nk
aW9fZXhpdF9kZWVwX3NsZWVwOw0KPiA+ICsgICBwcml2LT5yZXNldF9kZWVwX3NsZWVwX3dha2V1
cCA9IGlmX3NkaW9fcmVzZXRfZGVlcF9zbGVlcF93YWtldXA7DQo+ID4NCj4gPiAgICAgcHJpdi0+
ZndfcmVhZHkgPSAxOw0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbmV0L3dpcmVsZXNz
L2xpYmVydGFzL2lmX3NkaW8uaCBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3Nk
aW8uaA0KPiA+IGluZGV4IDYwYzliMmYuLjEyMTc5YzEgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVy
cy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc2Rpby5oDQo+ID4gKysrIGIvZHJpdmVycy9uZXQv
d2lyZWxlc3MvbGliZXJ0YXMvaWZfc2Rpby5oDQo+ID4gQEAgLTUxLDUgKzUxLDYgQEANCj4gPiAg
I2RlZmluZSBJRl9TRElPX0VWRU5UICAgICAgICAgICAweDgwZmMNCj4gPg0KPiA+ICAjZGVmaW5l
IElGX1NESU9fQkxPQ0tfU0laRSAyNTYNCj4gPiAtDQo+ID4gKyNkZWZpbmUgQ09ORklHVVJBVElP
Tl9SRUcgICAgICAgICAgICAgICAweDAzDQo+ID4gKyNkZWZpbmUgSE9TVF9QT1dFUl9VUCAgICAg
ICAgICAgICAgICAgICAoMHgxVSA8PCAxKQ0KPiA+ICAjZW5kaWYNCj4gPiBkaWZmIC0tZ2l0IGEv
ZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc3BpLmMgYi9kcml2ZXJzL25ldC93aXJl
bGVzcy9saWJlcnRhcy9pZl9zcGkuYw0KPiA+IGluZGV4IDQ0NmUzMjcuLmUyZmE2NTcgMTAwNjQ0
DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfc3BpLmMNCj4gPiAr
KysgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9pZl9zcGkuYw0KPiA+IEBAIC0xMTE3
LDYgKzExMTcsOSBAQCBzdGF0aWMgaW50IF9fZGV2aW5pdCBpZl9zcGlfcHJvYmUoc3RydWN0IHNw
aV9kZXZpY2UgKnNwaSkNCj4gPiAgICAgY2FyZC0+cHJpdiA9IHByaXY7DQo+ID4gICAgIHByaXYt
PmNhcmQgPSBjYXJkOw0KPiA+ICAgICBwcml2LT5od19ob3N0X3RvX2NhcmQgPSBpZl9zcGlfaG9z
dF90b19jYXJkOw0KPiA+ICsgICBwcml2LT5lbnRlcl9kZWVwX3NsZWVwID0gTlVMTDsNCj4gPiAr
ICAgcHJpdi0+ZXhpdF9kZWVwX3NsZWVwID0gTlVMTDsNCj4gPiArICAgcHJpdi0+cmVzZXRfZGVl
cF9zbGVlcF93YWtldXAgPSBOVUxMOw0KPiA+ICAgICBwcml2LT5md19yZWFkeSA9IDE7DQo+ID4N
Cj4gPiAgICAgLyogSW5pdGlhbGl6ZSBpbnRlcnJ1cHQgaGFuZGxpbmcgc3R1ZmYuICovDQo+ID4g
ZGlmZiAtLWdpdCBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lmX3VzYi5jIGIvZHJp
dmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfdXNiLmMNCj4gPiBpbmRleCA5MmJjOGM1Li5h
ODI2MmRlIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL2lm
X3VzYi5jDQo+ID4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGliZXJ0YXMvaWZfdXNiLmMN
Cj4gPiBAQCAtMzAwLDYgKzMwMCw5IEBAIHN0YXRpYyBpbnQgaWZfdXNiX3Byb2JlKHN0cnVjdCB1
c2JfaW50ZXJmYWNlICppbnRmLA0KPiA+ICAgICBjYXJkcC0+cHJpdi0+ZndfcmVhZHkgPSAxOw0K
PiA+DQo+ID4gICAgIHByaXYtPmh3X2hvc3RfdG9fY2FyZCA9IGlmX3VzYl9ob3N0X3RvX2NhcmQ7
DQo+ID4gKyAgIHByaXYtPmVudGVyX2RlZXBfc2xlZXAgPSBOVUxMOw0KPiA+ICsgICBwcml2LT5l
eGl0X2RlZXBfc2xlZXAgPSBOVUxMOw0KPiA+ICsgICBwcml2LT5yZXNldF9kZWVwX3NsZWVwX3dh
a2V1cCA9IE5VTEw7DQo+ID4gICNpZmRlZiBDT05GSUdfT0xQQw0KPiA+ICAgICBpZiAobWFjaGlu
ZV9pc19vbHBjKCkpDQo+ID4gICAgICAgICAgICAgcHJpdi0+cmVzZXRfY2FyZCA9IGlmX3VzYl9y
ZXNldF9vbHBjX2NhcmQ7DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xp
YmVydGFzL21haW4uYyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL21haW4uYw0KPiA+
IGluZGV4IDhkZjFjZmQuLjNiMTRmY2MgMTAwNjQ0DQo+ID4gLS0tIGEvZHJpdmVycy9uZXQvd2ly
ZWxlc3MvbGliZXJ0YXMvbWFpbi5jDQo+ID4gKysrIGIvZHJpdmVycy9uZXQvd2lyZWxlc3MvbGli
ZXJ0YXMvbWFpbi5jDQo+ID4gQEAgLTU3NCw4ICs1NzQsMTAgQEAgdm9pZCBsYnNfaG9zdF90b19j
YXJkX2RvbmUoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0KPiA+ICAgICBwcml2LT5kbmxkX3Nl
bnQgPSBETkxEX1JFU19SRUNFSVZFRDsNCj4gPg0KPiA+ICAgICAvKiBXYWtlIG1haW4gdGhyZWFk
IGlmIGNvbW1hbmRzIGFyZSBwZW5kaW5nICovDQo+ID4gLSAgIGlmICghcHJpdi0+Y3VyX2NtZCB8
fCBwcml2LT50eF9wZW5kaW5nX2xlbiA+IDApDQo+ID4gLSAgICAgICAgICAgd2FrZV91cF9pbnRl
cnJ1cHRpYmxlKCZwcml2LT53YWl0cSk7DQo+ID4gKyAgIGlmICghcHJpdi0+Y3VyX2NtZCB8fCBw
cml2LT50eF9wZW5kaW5nX2xlbiA+IDApIHsNCj4gPiArICAgICAgICAgICBpZiAoIXByaXYtPndh
a2V1cF9kZXZfcmVxdWlyZWQpDQo+ID4gKyAgICAgICAgICAgICAgICAgICB3YWtlX3VwX2ludGVy
cnVwdGlibGUoJnByaXYtPndhaXRxKTsNCj4gPiArICAgfQ0KPiA+DQo+ID4gICAgIHNwaW5fdW5s
b2NrX2lycXJlc3RvcmUoJnByaXYtPmRyaXZlcl9sb2NrLCBmbGFncyk7DQo+ID4gICAgIGxic19k
ZWJfbGVhdmUoTEJTX0RFQl9USFJFQUQpOw0KPiA+IEBAIC03NzAsNyArNzcyLDggQEAgc3RhdGlj
IGludCBsYnNfdGhyZWFkKHZvaWQgKmRhdGEpDQo+ID4gICAgICAgICAgICAgICAgICAgICBzaG91
bGRzbGVlcCA9IDA7ICAgICAgICAvKiBXZSBoYXZlIGEgY29tbWFuZCByZXNwb25zZSAqLw0KPiA+
ICAgICAgICAgICAgIGVsc2UgaWYgKHByaXYtPmN1cl9jbWQpDQo+ID4gICAgICAgICAgICAgICAg
ICAgICBzaG91bGRzbGVlcCA9IDE7ICAgICAgICAvKiBDYW4ndCBzZW5kIGEgY29tbWFuZDsgb25l
IGFscmVhZHkgcnVubmluZyAqLw0KPiA+IC0gICAgICAgICAgIGVsc2UgaWYgKCFsaXN0X2VtcHR5
KCZwcml2LT5jbWRwZW5kaW5ncSkpDQo+ID4gKyAgICAgICAgICAgZWxzZSBpZiAoIWxpc3RfZW1w
dHkoJnByaXYtPmNtZHBlbmRpbmdxKSAmJg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICEocHJpdi0+d2FrZXVwX2Rldl9yZXF1aXJlZCkpDQo+ID4gICAgICAgICAgICAg
ICAgICAgICBzaG91bGRzbGVlcCA9IDA7ICAgICAgICAvKiBXZSBoYXZlIGEgY29tbWFuZCB0byBz
ZW5kICovDQo+ID4gICAgICAgICAgICAgZWxzZSBpZiAoX19rZmlmb19sZW4ocHJpdi0+ZXZlbnRf
ZmlmbykpDQo+ID4gICAgICAgICAgICAgICAgICAgICBzaG91bGRzbGVlcCA9IDA7ICAgICAgICAv
KiBXZSBoYXZlIGFuIGV2ZW50IHRvIHByb2Nlc3MgKi8NCj4gPiBAQCAtODIyLDYgKzgyNSwyNiBA
QCBzdGF0aWMgaW50IGxic190aHJlYWQodm9pZCAqZGF0YSkNCj4gPiAgICAgICAgICAgICB9DQo+
ID4gICAgICAgICAgICAgc3Bpbl91bmxvY2tfaXJxKCZwcml2LT5kcml2ZXJfbG9jayk7DQo+ID4N
Cj4gPiArICAgICAgICAgICAvKiBQcm9jZXNzIGhhcmR3YXJlIGV2ZW50cywgZS5nLiBjYXJkIHJl
bW92ZWQsIGxpbmsgbG9zdCAqLw0KPiA+ICsgICAgICAgICAgIHNwaW5fbG9ja19pcnEoJnByaXYt
PmRyaXZlcl9sb2NrKTsNCj4gPiArICAgICAgICAgICB3aGlsZSAoX19rZmlmb19sZW4ocHJpdi0+
ZXZlbnRfZmlmbykpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgIHUzMiBldmVudDsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgIF9fa2ZpZm9fZ2V0KHByaXYtPmV2ZW50X2ZpZm8sICh1bnNpZ25l
ZCBjaGFyICopICZldmVudCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZW9m
KGV2ZW50KSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBzcGluX3VubG9ja19pcnEoJnByaXYt
PmRyaXZlcl9sb2NrKTsNCj4gPiArICAgICAgICAgICAgICAgICAgIGxic19wcm9jZXNzX2V2ZW50
KHByaXYsIGV2ZW50KTsNCj4gPiArICAgICAgICAgICAgICAgICAgIHNwaW5fbG9ja19pcnEoJnBy
aXYtPmRyaXZlcl9sb2NrKTsNCj4gPiArICAgICAgICAgICB9DQo+ID4gKyAgICAgICAgICAgc3Bp
bl91bmxvY2tfaXJxKCZwcml2LT5kcml2ZXJfbG9jayk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
IGlmIChwcml2LT53YWtldXBfZGV2X3JlcXVpcmVkKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICBsYnNfZGViX3RocmVhZCgiV2FraW5nIHVwIGRldmljZS4uLlxuIik7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAvKiBXYWtlIHVwIGRldmljZSAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAg
aWYgKHByaXYtPmV4aXRfZGVlcF9zbGVlcChwcml2KSkNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgbGJzX2RlYl90aHJlYWQoIldha2V1cCBkZXZpY2UgZmFpbGVkXG4iKTsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOw0KPiA+ICsgICAgICAgICAgIH0NCj4gPiArDQo+
ID4gICAgICAgICAgICAgLyogY29tbWFuZCB0aW1lb3V0IHN0dWZmICovDQo+ID4gICAgICAgICAg
ICAgaWYgKHByaXYtPmNtZF90aW1lZF9vdXQgJiYgcHJpdi0+Y3VyX2NtZCkgew0KPiA+ICAgICAg
ICAgICAgICAgICAgICAgc3RydWN0IGNtZF9jdHJsX25vZGUgKmNtZG5vZGUgPSBwcml2LT5jdXJf
Y21kOw0KPiA+IEBAIC04NDksMTggKzg3Miw3IEBAIHN0YXRpYyBpbnQgbGJzX3RocmVhZCh2b2lk
ICpkYXRhKQ0KPiA+ICAgICAgICAgICAgIH0NCj4gPiAgICAgICAgICAgICBwcml2LT5jbWRfdGlt
ZWRfb3V0ID0gMDsNCj4gPg0KPiA+IC0gICAgICAgICAgIC8qIFByb2Nlc3MgaGFyZHdhcmUgZXZl
bnRzLCBlLmcuIGNhcmQgcmVtb3ZlZCwgbGluayBsb3N0ICovDQo+ID4gLSAgICAgICAgICAgc3Bp
bl9sb2NrX2lycSgmcHJpdi0+ZHJpdmVyX2xvY2spOw0KPiA+IC0gICAgICAgICAgIHdoaWxlIChf
X2tmaWZvX2xlbihwcml2LT5ldmVudF9maWZvKSkgew0KPiA+IC0gICAgICAgICAgICAgICAgICAg
dTMyIGV2ZW50Ow0KPiA+DQo+ID4gLSAgICAgICAgICAgICAgICAgICBfX2tmaWZvX2dldChwcml2
LT5ldmVudF9maWZvLCAodW5zaWduZWQgY2hhciAqKSAmZXZlbnQsDQo+ID4gLSAgICAgICAgICAg
ICAgICAgICAgICAgICAgIHNpemVvZihldmVudCkpOw0KPiA+IC0gICAgICAgICAgICAgICAgICAg
c3Bpbl91bmxvY2tfaXJxKCZwcml2LT5kcml2ZXJfbG9jayk7DQo+ID4gLSAgICAgICAgICAgICAg
ICAgICBsYnNfcHJvY2Vzc19ldmVudChwcml2LCBldmVudCk7DQo+ID4gLSAgICAgICAgICAgICAg
ICAgICBzcGluX2xvY2tfaXJxKCZwcml2LT5kcml2ZXJfbG9jayk7DQo+ID4gLSAgICAgICAgICAg
fQ0KPiA+IC0gICAgICAgICAgIHNwaW5fdW5sb2NrX2lycSgmcHJpdi0+ZHJpdmVyX2xvY2spOw0K
PiA+DQo+ID4gICAgICAgICAgICAgaWYgKCFwcml2LT5md19yZWFkeSkNCj4gPiAgICAgICAgICAg
ICAgICAgICAgIGNvbnRpbnVlOw0KPiA+IEBAIC04OTQsNiArOTA2LDkgQEAgc3RhdGljIGludCBs
YnNfdGhyZWFkKHZvaWQgKmRhdGEpDQo+ID4gICAgICAgICAgICAgICAgIChwcml2LT5wc3N0YXRl
ID09IFBTX1NUQVRFX1BSRV9TTEVFUCkpDQo+ID4gICAgICAgICAgICAgICAgICAgICBjb250aW51
ZTsNCj4gPg0KPiA+ICsgICAgICAgICAgIGlmIChwcml2LT5pc19kZWVwX3NsZWVwKQ0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgY29udGludWU7DQo+ID4gKw0KPiA+ICAgICAgICAgICAgIC8qIEV4
ZWN1dGUgdGhlIG5leHQgY29tbWFuZCAqLw0KPiA+ICAgICAgICAgICAgIGlmICghcHJpdi0+ZG5s
ZF9zZW50ICYmICFwcml2LT5jdXJfY21kKQ0KPiA+ICAgICAgICAgICAgICAgICAgICAgbGJzX2V4
ZWN1dGVfbmV4dF9jb21tYW5kKHByaXYpOw0KPiA+IEBAIC05MjgsNiArOTQzLDcgQEAgc3RhdGlj
IGludCBsYnNfdGhyZWFkKHZvaWQgKmRhdGEpDQo+ID4gICAgIH0NCj4gPg0KPiA+ICAgICBkZWxf
dGltZXIoJnByaXYtPmNvbW1hbmRfdGltZXIpOw0KPiA+ICsgICBkZWxfdGltZXIoJnByaXYtPmF1
dG9fZGVlcHNsZWVwX3RpbWVyKTsNCj4gPiAgICAgd2FrZV91cF9hbGwoJnByaXYtPmNtZF9wZW5k
aW5nKTsNCj4gPg0KPiA+ICAgICBsYnNfZGViX2xlYXZlKExCU19ERUJfVEhSRUFEKTsNCj4gPiBA
QCAtMTA1MCw2ICsxMDY2LDYwIEBAIG91dDoNCj4gPiAgICAgbGJzX2RlYl9sZWF2ZShMQlNfREVC
X0NNRCk7DQo+ID4gIH0NCj4gPg0KPiA+ICsvKioNCj4gPiArICogIFRoaXMgZnVuY3Rpb24gcHV0
IHRoZSBkZXZpY2UgYmFjayB0byBkZWVwIHNsZWVwIG1vZGUgd2hlbiB0aW1lciBleHBpcmVzDQo+
ID4gKyAqICBhbmQgbm8gYWN0aXZpdHkgKGNvbW1hbmQsIGV2ZW50LCBkYXRhIGV0Yy4pIGlzIGRl
dGVjdGVkLg0KPiA+ICsgKi8NCj4gPiArc3RhdGljIHZvaWQgYXV0b19kZWVwc2xlZXBfdGltZXJf
Zm4odW5zaWduZWQgbG9uZyBkYXRhKQ0KPiA+ICt7DQo+ID4gKyAgIHN0cnVjdCBsYnNfcHJpdmF0
ZSAqcHJpdiA9IChzdHJ1Y3QgbGJzX3ByaXZhdGUgKilkYXRhOw0KPiA+ICsgICBpbnQgcmV0Ow0K
PiA+ICsNCj4gPiArICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX0NNRCk7DQo+ID4gKw0KPiA+ICsg
ICBpZiAocHJpdi0+aXNfYWN0aXZpdHlfZGV0ZWN0ZWQpIHsNCj4gPiArICAgICAgICAgICBwcml2
LT5pc19hY3Rpdml0eV9kZXRlY3RlZCA9IDA7DQo+ID4gKyAgIH0gZWxzZSB7DQo+ID4gKyAgICAg
ICAgICAgaWYgKHByaXYtPmlzX2F1dG9fZGVlcF9zbGVlcF9lbmFibGVkICYmDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICghcHJpdi0+d2FrZXVwX2Rldl9yZXF1aXJlZCkgJiYNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgKHByaXYtPmNvbm5lY3Rfc3RhdHVzICE9IExC
U19DT05ORUNURUQpKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBsYnNfZGViX21haW4oIkVu
dGVyaW5nIGF1dG8gZGVlcCBzbGVlcCBtb2RlLi4uXG4iKTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgIHJldCA9IGxic19wcmVwYXJlX2FuZF9zZW5kX2NvbW1hbmQocHJpdiwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDTURfODAyXzExX0RFRVBfU0xFRVAsIDAsDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMCwgMCwgTlVMTCk7DQo+ID4g
KyAgICAgICAgICAgfQ0KPiA+ICsgICB9DQo+ID4gKyAgIG1vZF90aW1lcigmcHJpdi0+YXV0b19k
ZWVwc2xlZXBfdGltZXIgLCBqaWZmaWVzICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgKHByaXYtPmF1dG9fZGVlcF9zbGVlcF90aW1lb3V0ICogSFopLzEwMDApOw0KPiA+ICsgICBs
YnNfZGViX2xlYXZlKExCU19ERUJfQ01EKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiAraW50IGxic19l
bnRlcl9hdXRvX2RlZXBfc2xlZXAoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0KPiA+ICt7DQo+
ID4gKyAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9TRElPKTsNCj4gPiArDQo+ID4gKyAgIHByaXYt
PmlzX2F1dG9fZGVlcF9zbGVlcF9lbmFibGVkID0gMTsNCj4gPiArICAgaWYgKHByaXYtPmlzX2Rl
ZXBfc2xlZXApDQo+ID4gKyAgICAgICAgICAgcHJpdi0+d2FrZXVwX2Rldl9yZXF1aXJlZCA9IDE7
DQo+ID4gKyAgIG1vZF90aW1lcigmcHJpdi0+YXV0b19kZWVwc2xlZXBfdGltZXIgLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgamlmZmllcyArIChwcml2LT5hdXRvX2RlZXBfc2xlZXBfdGltZW91
dCAqIEhaKS8xMDAwKTsNCj4gPiArDQo+ID4gKyAgIGxic19kZWJfbGVhdmUoTEJTX0RFQl9TRElP
KTsNCj4gPiArICAgcmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4gK2ludCBsYnNfZXhpdF9h
dXRvX2RlZXBfc2xlZXAoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0KPiA+ICt7DQo+ID4gKyAg
IGxic19kZWJfZW50ZXIoTEJTX0RFQl9TRElPKTsNCj4gPiArDQo+ID4gKyAgIHByaXYtPmlzX2F1
dG9fZGVlcF9zbGVlcF9lbmFibGVkID0gMDsNCj4gPiArICAgcHJpdi0+YXV0b19kZWVwX3NsZWVw
X3RpbWVvdXQgPSAwOw0KPiA+ICsgICBkZWxfdGltZXIoJnByaXYtPmF1dG9fZGVlcHNsZWVwX3Rp
bWVyKTsNCj4gPiArDQo+ID4gKyAgIGxic19kZWJfbGVhdmUoTEJTX0RFQl9TRElPKTsNCj4gPiAr
ICAgcmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4gIHN0YXRpYyB2b2lkIGxic19zeW5jX2No
YW5uZWxfd29ya2VyKHN0cnVjdCB3b3JrX3N0cnVjdCAqd29yaykNCj4gPiAgew0KPiA+ICAgICBz
dHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYgPSBjb250YWluZXJfb2Yod29yaywgc3RydWN0IGxic19w
cml2YXRlLA0KPiA+IEBAIC0xMDk5LDExICsxMTY5LDE3IEBAIHN0YXRpYyBpbnQgbGJzX2luaXRf
YWRhcHRlcihzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYpDQo+ID4gICAgIHByaXYtPmNhcGFiaWxp
dHkgPSBXTEFOX0NBUEFCSUxJVFlfU0hPUlRfUFJFQU1CTEU7DQo+ID4gICAgIHByaXYtPnBzbW9k
ZSA9IExCUzgwMl8xMVBPV0VSTU9ERUNBTTsNCj4gPiAgICAgcHJpdi0+cHNzdGF0ZSA9IFBTX1NU
QVRFX0ZVTExfUE9XRVI7DQo+ID4gKyAgIHByaXYtPmlzX2RlZXBfc2xlZXAgPSAwOw0KPiA+ICsg
ICBwcml2LT5pc19hdXRvX2RlZXBfc2xlZXBfZW5hYmxlZCA9IDA7DQo+ID4gKyAgIHByaXYtPndh
a2V1cF9kZXZfcmVxdWlyZWQgPSAwOw0KPiA+ICsgICBpbml0X3dhaXRxdWV1ZV9oZWFkKCZwcml2
LT5kc19hd2FrZV9xKTsNCj4gPg0KPiA+ICAgICBtdXRleF9pbml0KCZwcml2LT5sb2NrKTsNCj4g
Pg0KPiA+ICAgICBzZXR1cF90aW1lcigmcHJpdi0+Y29tbWFuZF90aW1lciwgY29tbWFuZF90aW1l
cl9mbiwNCj4gPiAgICAgICAgICAgICAodW5zaWduZWQgbG9uZylwcml2KTsNCj4gPiArICAgc2V0
dXBfdGltZXIoJnByaXYtPmF1dG9fZGVlcHNsZWVwX3RpbWVyLCBhdXRvX2RlZXBzbGVlcF90aW1l
cl9mbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICh1bnNpZ25lZCBsb25nKXByaXYpOw0KPiA+
DQo+ID4gICAgIElOSVRfTElTVF9IRUFEKCZwcml2LT5jbWRmcmVlcSk7DQo+ID4gICAgIElOSVRf
TElTVF9IRUFEKCZwcml2LT5jbWRwZW5kaW5ncSk7DQo+ID4gQEAgLTExNDIsNiArMTIxOCw3IEBA
IHN0YXRpYyB2b2lkIGxic19mcmVlX2FkYXB0ZXIoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0K
PiA+ICAgICBpZiAocHJpdi0+ZXZlbnRfZmlmbykNCj4gPiAgICAgICAgICAgICBrZmlmb19mcmVl
KHByaXYtPmV2ZW50X2ZpZm8pOw0KPiA+ICAgICBkZWxfdGltZXIoJnByaXYtPmNvbW1hbmRfdGlt
ZXIpOw0KPiA+ICsgICBkZWxfdGltZXIoJnByaXYtPmF1dG9fZGVlcHNsZWVwX3RpbWVyKTsNCj4g
PiAgICAga2ZyZWUocHJpdi0+bmV0d29ya3MpOw0KPiA+ICAgICBwcml2LT5uZXR3b3JrcyA9IE5V
TEw7DQo+ID4NCj4gPiBAQCAtMTI3Miw2ICsxMzQ5LDExIEBAIHZvaWQgbGJzX3JlbW92ZV9jYXJk
KHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdikNCj4gPiAgICAgd3JxdS5hcF9hZGRyLnNhX2ZhbWls
eSA9IEFSUEhSRF9FVEhFUjsNCj4gPiAgICAgd2lyZWxlc3Nfc2VuZF9ldmVudChwcml2LT5kZXYs
IFNJT0NHSVdBUCwgJndycXUsIE5VTEwpOw0KPiA+DQo+ID4gKyAgIGlmIChwcml2LT5pc19kZWVw
X3NsZWVwKSB7DQo+ID4gKyAgICAgICAgICAgcHJpdi0+aXNfZGVlcF9zbGVlcCA9IDA7DQo+ID4g
KyAgICAgICAgICAgd2FrZV91cF9pbnRlcnJ1cHRpYmxlKCZwcml2LT5kc19hd2FrZV9xKTsNCj4g
PiArICAgfQ0KPiA+ICsNCj4gPiAgICAgLyogU3RvcCB0aGUgdGhyZWFkIHNlcnZpY2luZyB0aGUg
aW50ZXJydXB0cyAqLw0KPiA+ICAgICBwcml2LT5zdXJwcmlzZXJlbW92ZWQgPSAxOw0KPiA+ICAg
ICBrdGhyZWFkX3N0b3AocHJpdi0+bWFpbl90aHJlYWQpOw0KPiA+IEBAIC0xMzkyLDYgKzE0NzQs
NyBAQCB2b2lkIGxic19zdG9wX2NhcmQoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0KPiA+DQo+
ID4gICAgIC8qIERlbGV0ZSB0aGUgdGltZW91dCBvZiB0aGUgY3VycmVudGx5IHByb2Nlc3Npbmcg
Y29tbWFuZCAqLw0KPiA+ICAgICBkZWxfdGltZXJfc3luYygmcHJpdi0+Y29tbWFuZF90aW1lcik7
DQo+ID4gKyAgIGRlbF90aW1lcl9zeW5jKCZwcml2LT5hdXRvX2RlZXBzbGVlcF90aW1lcik7DQo+
ID4NCj4gPiAgICAgLyogRmx1c2ggcGVuZGluZyBjb21tYW5kIG5vZGVzICovDQo+ID4gICAgIHNw
aW5fbG9ja19pcnFzYXZlKCZwcml2LT5kcml2ZXJfbG9jaywgZmxhZ3MpOw0KPiA+IGRpZmYgLS1n
aXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy9zY2FuLmMgYi9kcml2ZXJzL25ldC93
aXJlbGVzcy9saWJlcnRhcy9zY2FuLmMNCj4gPiBpbmRleCA2Yzk1YWYzLi5lNDY4ZTE1IDEwMDY0
NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL3NjYW4uYw0KPiA+ICsr
KyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL3NjYW4uYw0KPiA+IEBAIC05NTAsNiAr
OTUwLDExIEBAIGludCBsYnNfc2V0X3NjYW4oc3RydWN0IG5ldF9kZXZpY2UgKmRldiwgc3RydWN0
IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4gPg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19E
RUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsN
Cj4gPiArICAgICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4gKyAgICAgICAgICAgZ290byBvdXQ7
DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIGlmICghcHJpdi0+cmFkaW9fb24pIHsNCj4gPiAg
ICAgICAgICAgICByZXQgPSAtRUlOVkFMOw0KPiA+ICAgICAgICAgICAgIGdvdG8gb3V0Ow0KPiA+
IEBAIC0xMDE3LDYgKzEwMjIsMTIgQEAgaW50IGxic19nZXRfc2NhbihzdHJ1Y3QgbmV0X2Rldmlj
ZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZvLA0KPiA+DQo+ID4gICAgIGxic19k
ZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxs
b3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIGVyciA9IC1FQlVTWTsNCj4gPiArICAgICAg
ICAgICBsYnNfZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9XRVhULCAicmV0ICVkIiwgZXJyKTsNCj4g
PiArICAgICAgICAgICByZXR1cm4gZXJyOw0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICAvKiBp
d2xpc3Qgc2hvdWxkIHdhaXQgdW50aWwgdGhlIGN1cnJlbnQgc2NhbiBpcyBmaW5pc2hlZCAqLw0K
PiA+ICAgICBpZiAocHJpdi0+c2Nhbl9jaGFubmVsKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAt
RUFHQUlOOw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy93
ZXh0LmMgYi9kcml2ZXJzL25ldC93aXJlbGVzcy9saWJlcnRhcy93ZXh0LmMNCj4gPiBpbmRleCBi
ZTgzN2EwLi4zOGE0NTFlIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xp
YmVydGFzL3dleHQuYw0KPiA+ICsrKyBiL2RyaXZlcnMvbmV0L3dpcmVsZXNzL2xpYmVydGFzL3dl
eHQuYw0KPiA+IEBAIC00NSw2ICs0NSwzMSBAQCBzdGF0aWMgaW5saW5lIHZvaWQgbGJzX2NhbmNl
bF9hc3NvY2lhdGlvbl93b3JrKHN0cnVjdCBsYnNfcHJpdmF0ZSAqcHJpdikNCj4gPiAgICAgcHJp
di0+cGVuZGluZ19hc3NvY19yZXEgPSBOVUxMOw0KPiA+ICB9DQo+ID4NCj4gPiArLyoqDQo+ID4g
KyAqICBAYnJpZWYgVGhpcyBmdW5jdGlvbiBjaGVja3MgaWYgdGhlIGNvbW1hbmQgaXMgYWxsb3dl
ZC4NCj4gPiArICoNCj4gPiArICogIEBwYXJhbSBwcml2ICAgICAgICAgQSBwb2ludGVyIHRvIGxi
c19wcml2YXRlIHN0cnVjdHVyZQ0KPiA+ICsgKiAgQHJldHVybiAgICAgICAgICAgICBhbGxvd2Vk
IG9yIG5vdCBhbGxvd2VkLg0KPiA+ICsgKi8NCj4gPiArDQo+ID4gK2ludCBsYnNfaXNfY21kX2Fs
bG93ZWQoc3RydWN0IGxic19wcml2YXRlICpwcml2KQ0KPiA+ICt7DQo+ID4gKyAgIGludCAgICAg
ICAgIHJldCA9IDE7DQo+ID4gKw0KPiA+ICsgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7
DQo+ID4gKw0KPiA+ICsgICBpZiAoIXByaXYtPmlzX2F1dG9fZGVlcF9zbGVlcF9lbmFibGVkKSB7
DQo+ID4gKyAgICAgICAgICAgaWYgKHByaXYtPmlzX2RlZXBfc2xlZXApIHsNCj4gPiArICAgICAg
ICAgICAgICAgICAgIGxic19kZWJfd2V4dCgiSU9DVExTIGNhbGxlZCB3aGVuIHN0YXRpb24iDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlzIGluIGRlZXAgc2xlZXBc
biIpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgcmV0ID0gMDsNCj4gPiArICAgICAgICAgICB9
DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gKyAgIGxic19kZWJfbGVhdmUoTEJTX0RFQl9XRVhUKTsN
Cj4gPiArICAgcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsNCj4gPg0KPiA+ICAvKioNCj4gPiAg
ICogIEBicmllZiBGaW5kIHRoZSBjaGFubmVsIGZyZXF1ZW5jeSBwb3dlciBpbmZvIHdpdGggc3Bl
Y2lmaWMgY2hhbm5lbA0KPiA+IEBAIC0xNjgsNiArMTkzLDExIEBAIHN0YXRpYyBpbnQgbGJzX2dl
dF9mcmVxKHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1ZXN0X2luZm8gKmlu
Zm8sDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4g
KyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgbGJz
X2RlYl9sZWF2ZShMQlNfREVCX1dFWFQpOw0KPiA+ICsgICAgICAgICAgIHJldHVybiAtRUJVU1k7
DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIGNmcCA9IGxic19maW5kX2NmcF9ieV9iYW5kX2Fu
ZF9jaGFubmVsKHByaXYsIDAsDQo+ID4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgcHJpdi0+Y3VyYnNzcGFyYW1zLmNoYW5uZWwpOw0KPiA+DQo+ID4gQEAgLTI3OCw2ICsz
MDgsMTIgQEAgc3RhdGljIGludCBsYnNfc2V0X3J0cyhzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBz
dHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZvLA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIo
TEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2
KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBsYnNf
ZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9XRVhULCAicmV0ICVkIiwgcmV0KTsNCj4gPiArICAgICAg
ICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAodndycS0+ZGlz
YWJsZWQpDQo+ID4gICAgICAgICAgICAgdmFsID0gTVJWRFJWX1JUU19NQVhfVkFMVUU7DQo+ID4N
Cj4gPiBAQCAtMjk5LDYgKzMzNSwxMSBAQCBzdGF0aWMgaW50IGxic19nZXRfcnRzKHN0cnVjdCBu
ZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1ZXN0X2luZm8gKmluZm8sDQo+ID4NCj4gPiAg
ICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lz
X2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+
ICsgICAgICAgICAgIGdvdG8gb3V0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICByZXQgPSBs
YnNfZ2V0X3NubXBfbWliKHByaXYsIFNOTVBfTUlCX09JRF9SVFNfVEhSRVNIT0xELCAmdmFsKTsN
Cj4gPiAgICAgaWYgKHJldCkNCj4gPiAgICAgICAgICAgICBnb3RvIG91dDsNCj4gPiBAQCAtMzIx
LDYgKzM2MiwxMiBAQCBzdGF0aWMgaW50IGxic19zZXRfZnJhZyhzdHJ1Y3QgbmV0X2RldmljZSAq
ZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZvLA0KPiA+DQo+ID4gICAgIGxic19kZWJf
ZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dl
ZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAg
ICBsYnNfZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9XRVhULCAicmV0ICVkIiwgcmV0KTsNCj4gPiAr
ICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAodndy
cS0+ZGlzYWJsZWQpDQo+ID4gICAgICAgICAgICAgdmFsID0gTVJWRFJWX0ZSQUdfTUFYX1ZBTFVF
Ow0KPiA+DQo+ID4gQEAgLTM0Miw2ICszODksMTEgQEAgc3RhdGljIGludCBsYnNfZ2V0X2ZyYWco
c3RydWN0IG5ldF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4g
Pg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYg
KCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJV
U1k7DQo+ID4gKyAgICAgICAgICAgZ290byBvdXQ7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAg
IHJldCA9IGxic19nZXRfc25tcF9taWIocHJpdiwgU05NUF9NSUJfT0lEX0ZSQUdfVEhSRVNIT0xE
LCAmdmFsKTsNCj4gPiAgICAgaWYgKHJldCkNCj4gPiAgICAgICAgICAgICBnb3RvIG91dDsNCj4g
PiBAQCAtMzkxLDYgKzQ0MywxMSBAQCBzdGF0aWMgaW50IGxic19nZXRfdHhwb3coc3RydWN0IG5l
dF9kZXZpY2UgKmRldiwNCj4gPg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7
DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAg
ICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4gKyAgICAgICAgICAgZ290byBvdXQ7DQo+ID4gKyAg
IH0NCj4gPiArDQo+ID4gICAgIGlmICghcHJpdi0+cmFkaW9fb24pIHsNCj4gPiAgICAgICAgICAg
ICBsYnNfZGViX3dleHQoInR4IHBvd2VyIG9mZlxuIik7DQo+ID4gICAgICAgICAgICAgdndycS0+
dmFsdWUgPSAwOw0KPiA+IEBAIC00MjQsNiArNDgxLDExIEBAIHN0YXRpYyBpbnQgbGJzX3NldF9y
ZXRyeShzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZv
LA0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsg
ICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9
IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBnb3RvIG91dDsNCj4gPiArICAgfQ0KPiA+ICsNCj4g
PiAgICAgICAgICBpZiAoKHZ3cnEtPmZsYWdzICYgSVdfUkVUUllfVFlQRSkgIT0gSVdfUkVUUllf
TElNSVQpDQo+ID4gICAgICAgICAgICAgICAgICByZXR1cm4gLUVPUE5PVFNVUFA7DQo+ID4NCj4g
PiBAQCAtNDcyLDYgKzUzNCwxMSBAQCBzdGF0aWMgaW50IGxic19nZXRfcmV0cnkoc3RydWN0IG5l
dF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4gPg0KPiA+ICAg
ICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNf
Y21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4g
KyAgICAgICAgICAgZ290byBvdXQ7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIHZ3cnEtPmRp
c2FibGVkID0gMDsNCj4gPg0KPiA+ICAgICBpZiAodndycS0+ZmxhZ3MgJiBJV19SRVRSWV9MT05H
KSB7DQo+ID4gQEAgLTcwOSw2ICs3NzYsNyBAQCBzdGF0aWMgaW50IGxic19zZXRfcG93ZXIoc3Ry
dWN0IG5ldF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3JlcXVlc3RfaW5mbyAqaW5mbywNCj4gPiAg
ICAgICAgICAgICAgICAgICAgICAgc3RydWN0IGl3X3BhcmFtICp2d3JxLCBjaGFyICpleHRyYSkN
Cj4gPiAgew0KPiA+ICAgICBzdHJ1Y3QgbGJzX3ByaXZhdGUgKnByaXYgPSBkZXYtPm1sX3ByaXY7
DQo+ID4gKyAgIGludCByZXQgPSAwOw0KPiA+DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RF
Ql9XRVhUKTsNCj4gPg0KPiA+IEBAIC03MzcsOCArODA1LDU0IEBAIHN0YXRpYyBpbnQgbGJzX3Nl
dF9wb3dlcihzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICpp
bmZvLA0KPiA+ICAgICAgICAgICAgICAgICAgICAic2V0dGluZyBwb3dlciB0aW1lb3V0IGlzIG5v
dCBzdXBwb3J0ZWRcbiIpOw0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRUlOVkFMOw0KPiA+ICAg
ICB9IGVsc2UgaWYgKCh2d3JxLT5mbGFncyAmIElXX1BPV0VSX1RZUEUpID09IElXX1BPV0VSX1BF
UklPRCkgew0KPiA+IC0gICAgICAgICAgIGxic19kZWJfd2V4dCgic2V0dGluZyBwb3dlciBwZXJp
b2Qgbm90IHN1cHBvcnRlZFxuIik7DQo+ID4gLSAgICAgICAgICAgcmV0dXJuIC1FSU5WQUw7DQo+
ID4gKyAgICAgICAgICAgdndycS0+dmFsdWUgPSB2d3JxLT52YWx1ZSAvIDEwMDA7DQo+ID4gKyAg
ICAgICAgICAgaWYgKCFwcml2LT5lbnRlcl9kZWVwX3NsZWVwKSB7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICBsYnNfcHJfZXJyKCJkZWVwIHNsZWVwIGZlYXR1cmUgaXMgbm90IGltcGxlbWVudGVk
ICINCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZm9yIHRoaXMgaW50
ZXJmYWNlIGRyaXZlclxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICByZXR1cm4gLUVJTlZB
TDsNCj4gPiArICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgIGlmIChwcml2LT5j
b25uZWN0X3N0YXR1cyA9PSBMQlNfQ09OTkVDVEVEKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICBpZiAoKHByaXYtPmlzX2F1dG9fZGVlcF9zbGVlcF9lbmFibGVkKSAmJg0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHZ3cnEtPnZhbHVlID09IC0xMDAw
KSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICBsYnNfZXhpdF9hdXRvX2RlZXBf
c2xlZXAocHJpdik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAwOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgbGJzX3ByX2VycigiY2FuJ3QgdXNlIGRlZXAgc2xlZXAgY21kIGluICINCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb25uZWN0ZWQgc3Rh
dGVcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gLUVJTlZBTDsN
Cj4gPiArICAgICAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgICAgICB9DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgIGlmICgodndycS0+dmFsdWUgPCAwKSAmJiAodndycS0+dmFsdWUgIT0gLTEw
MDApKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICBsYnNfcHJfZXJyKCJ1bmtub3duIG9wdGlv
blxuIik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICByZXR1cm4gLUVJTlZBTDsNCj4gPiArICAg
ICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgIGlmICh2d3JxLT52YWx1ZSA+IDApIHsN
Cj4gPiArICAgICAgICAgICAgICAgICAgIGlmICghcHJpdi0+aXNfYXV0b19kZWVwX3NsZWVwX2Vu
YWJsZWQpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpdi0+aXNfYWN0aXZp
dHlfZGV0ZWN0ZWQgPSAwOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICBwcml2LT5h
dXRvX2RlZXBfc2xlZXBfdGltZW91dCA9IHZ3cnEtPnZhbHVlOw0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICBsYnNfZW50ZXJfYXV0b19kZWVwX3NsZWVwKHByaXYpOw0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
cHJpdi0+YXV0b19kZWVwX3NsZWVwX3RpbWVvdXQgPSB2d3JxLT52YWx1ZTsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgbGJzX2RlYl9kZWJ1Z2ZzKCJhdXRvIGRlZXAgc2xlZXA6ICIN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhbHJlYWR5
IGVuYWJsZWRcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgcmV0dXJuIDA7DQo+ID4gKyAgICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAg
ICAgICAgICAgICAgIGlmIChwcml2LT5pc19hdXRvX2RlZXBfc2xlZXBfZW5hYmxlZCkgew0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICBsYnNfZXhpdF9hdXRvX2RlZXBfc2xlZXAocHJp
dik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qIFRyeSB0byBleGl0IGRlZXAg
c2xlZXAgaWYgYXV0byAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAvKmRlZXAg
c2xlZXAgZGlzYWJsZWQgKi8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0ID0g
bGJzX3NldF9kZWVwX3NsZWVwKHByaXYsIDApOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgfQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgaWYgKHZ3cnEtPnZhbHVlID09IDApDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgIHJldCA9IGxic19zZXRfZGVlcF9zbGVlcChwcml2LCAxKTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKHZ3cnEtPnZhbHVlID09IC0xMDAwKQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICByZXQgPSBsYnNfc2V0X2RlZXBfc2xlZXAo
cHJpdiwgMCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICAg
ICAgICAgIH0NCj4gPiAgICAgfQ0KPiA+DQo+ID4gICAgIGlmIChwcml2LT5wc21vZGUgIT0gTEJT
ODAyXzExUE9XRVJNT0RFQ0FNKSB7DQo+ID4gQEAgLTc1Miw2ICs4NjYsNyBAQCBzdGF0aWMgaW50
IGxic19zZXRfcG93ZXIoc3RydWN0IG5ldF9kZXZpY2UgKmRldiwgc3RydWN0IGl3X3JlcXVlc3Rf
aW5mbyAqaW5mbywNCj4gPiAgICAgfQ0KPiA+DQo+ID4gICAgIGxic19kZWJfbGVhdmUoTEJTX0RF
Ql9XRVhUKTsNCj4gPiArDQo+ID4gICAgIHJldHVybiAwOw0KPiA+ICB9DQo+ID4NCj4gPiBAQCAt
NzkyLDYgKzkwNyw5IEBAIHN0YXRpYyBzdHJ1Y3QgaXdfc3RhdGlzdGljcyAqbGJzX2dldF93aXJl
bGVzc19zdGF0cyhzdHJ1Y3QgbmV0X2RldmljZSAqZGV2KQ0KPiA+DQo+ID4gICAgIGxic19kZWJf
ZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dl
ZChwcml2KSkNCj4gPiArICAgICAgICAgICByZXR1cm4gTlVMTDsNCj4gPiArDQo+ID4gICAgIHBy
aXYtPndzdGF0cy5zdGF0dXMgPSBwcml2LT5tb2RlOw0KPiA+DQo+ID4gICAgIC8qIElmIHdlJ3Jl
IG5vdCBhc3NvY2lhdGVkLCBhbGwgcXVhbGl0eSB2YWx1ZXMgYXJlIG1lYW5pbmdsZXNzICovDQo+
ID4gQEAgLTg5Miw2ICsxMDEwLDEyIEBAIHN0YXRpYyBpbnQgbGJzX3NldF9mcmVxKHN0cnVjdCBu
ZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1ZXN0X2luZm8gKmluZm8sDQo+ID4NCj4gPiAg
ICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lz
X2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+
ICsgICAgICAgICAgIGxic19kZWJfbGVhdmVfYXJncyhMQlNfREVCX1dFWFQsICJyZXQgJWQiLCBy
ZXQpOw0KPiA+ICsgICAgICAgICAgIHJldHVybiByZXQ7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4g
ICAgIG11dGV4X2xvY2soJnByaXYtPmxvY2spOw0KPiA+ICAgICBhc3NvY19yZXEgPSBsYnNfZ2V0
X2Fzc29jaWF0aW9uX3JlcXVlc3QocHJpdik7DQo+ID4gICAgIGlmICghYXNzb2NfcmVxKSB7DQo+
ID4gQEAgLTEwMDAsNiArMTEyNCwxMiBAQCBzdGF0aWMgaW50IGxic19zZXRfcmF0ZShzdHJ1Y3Qg
bmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZvLA0KPiA+ICAgICB1
OCByYXRlc1tNQVhfUkFURVMgKyAxXTsNCj4gPg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19E
RUJfV0VYVCk7DQo+ID4gKw0KPiA+ICsgICBpZiAoIWxic19pc19jbWRfYWxsb3dlZChwcml2KSkg
ew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVTWTsNCj4gPiArICAgICAgICAgICBnb3RvIG91
dDsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgbGJzX2RlYl93ZXh0KCJ2d3JxLT52YWx1ZSAl
ZFxuIiwgdndycS0+dmFsdWUpOw0KPiA+ICAgICBsYnNfZGViX3dleHQoInZ3cnEtPmZpeGVkICVk
XG4iLCB2d3JxLT5maXhlZCk7DQo+ID4NCj4gPiBAQCAtMTA1OCw2ICsxMTg4LDExIEBAIHN0YXRp
YyBpbnQgbGJzX2dldF9yYXRlKHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1
ZXN0X2luZm8gKmluZm8sDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQp
Ow0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAg
ICAgICAgICAgbGJzX2RlYl9sZWF2ZShMQlNfREVCX1dFWFQpOw0KPiA+ICsgICAgICAgICAgIHJl
dHVybiAtRUJVU1k7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIGlmIChwcml2LT5jb25uZWN0
X3N0YXR1cyA9PSBMQlNfQ09OTkVDVEVEKSB7DQo+ID4gICAgICAgICAgICAgdndycS0+dmFsdWUg
PSBwcml2LT5jdXJfcmF0ZSAqIDUwMDAwMDsNCj4gPg0KPiA+IEBAIC0xMDg0LDYgKzEyMTksMTEg
QEAgc3RhdGljIGludCBsYnNfc2V0X21vZGUoc3RydWN0IG5ldF9kZXZpY2UgKmRldiwNCj4gPg0K
PiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFs
YnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJVU1k7
DQo+ID4gKyAgICAgICAgICAgZ290byBvdXQ7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIGlm
ICggICAoKnV3cnEgIT0gSVdfTU9ERV9BREhPQykNCj4gPiAgICAgICAgICYmICgqdXdycSAhPSBJ
V19NT0RFX0lORlJBKQ0KPiA+ICAgICAgICAgJiYgKCp1d3JxICE9IElXX01PREVfQVVUTykpIHsN
Cj4gPiBAQCAtMTMyNSw2ICsxNDY1LDEyIEBAIHN0YXRpYyBpbnQgbGJzX3NldF9lbmNvZGUoc3Ry
dWN0IG5ldF9kZXZpY2UgKmRldiwNCj4gPg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJf
V0VYVCk7DQo+ID4NCj4gPiArICAgaWYgKCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4g
PiArICAgICAgICAgICByZXQgPSAtRUJVU1k7DQo+ID4gKyAgICAgICAgICAgbGJzX2RlYl9sZWF2
ZV9hcmdzKExCU19ERUJfV0VYVCwgInJldCAlZCIsIHJldCk7DQo+ID4gKyAgICAgICAgICAgcmV0
dXJuIHJldDsNCj4gPiArICAgfQ0KPiA+ICsNCj4gPiAgICAgbXV0ZXhfbG9jaygmcHJpdi0+bG9j
ayk7DQo+ID4gICAgIGFzc29jX3JlcSA9IGxic19nZXRfYXNzb2NpYXRpb25fcmVxdWVzdChwcml2
KTsNCj4gPiAgICAgaWYgKCFhc3NvY19yZXEpIHsNCj4gPiBAQCAtMTUwOCw2ICsxNjU0LDEyIEBA
IHN0YXRpYyBpbnQgbGJzX3NldF9lbmNvZGVleHQoc3RydWN0IG5ldF9kZXZpY2UgKmRldiwNCj4g
Pg0KPiA+ICAgICBsYnNfZGViX2VudGVyKExCU19ERUJfV0VYVCk7DQo+ID4NCj4gPiArICAgaWYg
KCFsYnNfaXNfY21kX2FsbG93ZWQocHJpdikpIHsNCj4gPiArICAgICAgICAgICByZXQgPSAtRUJV
U1k7DQo+ID4gKyAgICAgICAgICAgbGJzX2RlYl9sZWF2ZV9hcmdzKExCU19ERUJfV0VYVCwgInJl
dCAlZCIsIHJldCk7DQo+ID4gKyAgICAgICAgICAgcmV0dXJuIHJldDsNCj4gPiArICAgfQ0KPiA+
ICsNCj4gPiAgICAgbXV0ZXhfbG9jaygmcHJpdi0+bG9jayk7DQo+ID4gICAgIGFzc29jX3JlcSA9
IGxic19nZXRfYXNzb2NpYXRpb25fcmVxdWVzdChwcml2KTsNCj4gPiAgICAgaWYgKCFhc3NvY19y
ZXEpIHsNCj4gPiBAQCAtMTcyMCw2ICsxODcyLDEyIEBAIHN0YXRpYyBpbnQgbGJzX3NldF9hdXRo
KHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNf
REVCX1dFWFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7
DQo+ID4gKyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGxic19kZWJf
bGVhdmVfYXJncyhMQlNfREVCX1dFWFQsICJyZXQgJWQiLCByZXQpOw0KPiA+ICsgICAgICAgICAg
IHJldHVybiByZXQ7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIG11dGV4X2xvY2soJnByaXYt
PmxvY2spOw0KPiA+ICAgICBhc3NvY19yZXEgPSBsYnNfZ2V0X2Fzc29jaWF0aW9uX3JlcXVlc3Qo
cHJpdik7DQo+ID4gICAgIGlmICghYXNzb2NfcmVxKSB7DQo+ID4gQEAgLTE4MjIsNiArMTk4MCwx
MiBAQCBzdGF0aWMgaW50IGxic19nZXRfYXV0aChzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LA0KPiA+
DQo+ID4gICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsgICBpZiAo
IWxic19pc19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVT
WTsNCj4gPiArICAgICAgICAgICBsYnNfZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9XRVhULCAicmV0
ICVkIiwgcmV0KTsNCj4gPiArICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICB9DQo+ID4g
Kw0KPiA+ICAgICBzd2l0Y2ggKGR3cnEtPmZsYWdzICYgSVdfQVVUSF9JTkRFWCkgew0KPiA+ICAg
ICBjYXNlIElXX0FVVEhfS0VZX01HTVQ6DQo+ID4gICAgICAgICAgICAgZHdycS0+dmFsdWUgPSBw
cml2LT5zZWNpbmZvLmtleV9tZ210Ow0KPiA+IEBAIC0xODY0LDYgKzIwMjgsMTEgQEAgc3RhdGlj
IGludCBsYnNfc2V0X3R4cG93KHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1
ZXN0X2luZm8NCj4gKmluZm8sDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dF
WFQpOw0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4g
KyAgICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGdvdG8gb3V0Ow0KPiA+
ICsgICB9DQo+ID4gKw0KPiA+ICAgICBpZiAodndycS0+ZGlzYWJsZWQpIHsNCj4gPiAgICAgICAg
ICAgICBsYnNfc2V0X3JhZGlvKHByaXYsIFJBRElPX1BSRUFNQkxFX0FVVE8sIDApOw0KPiA+ICAg
ICAgICAgICAgIGdvdG8gb3V0Ow0KPiA+IEBAIC0xOTgzLDYgKzIxNTIsMTIgQEAgc3RhdGljIGlu
dCBsYnNfc2V0X2Vzc2lkKHN0cnVjdCBuZXRfZGV2aWNlICpkZXYsIHN0cnVjdCBpd19yZXF1ZXN0
X2luZm8NCj4gKmluZm8sDQo+ID4NCj4gPiAgICAgbGJzX2RlYl9lbnRlcihMQlNfREVCX1dFWFQp
Ow0KPiA+DQo+ID4gKyAgIGlmICghbGJzX2lzX2NtZF9hbGxvd2VkKHByaXYpKSB7DQo+ID4gKyAg
ICAgICAgICAgcmV0ID0gLUVCVVNZOw0KPiA+ICsgICAgICAgICAgIGxic19kZWJfbGVhdmVfYXJn
cyhMQlNfREVCX1dFWFQsICJyZXQgJWQiLCByZXQpOw0KPiA+ICsgICAgICAgICAgIHJldHVybiBy
ZXQ7DQo+ID4gKyAgIH0NCj4gPiArDQo+ID4gICAgIGlmICghcHJpdi0+cmFkaW9fb24pIHsNCj4g
PiAgICAgICAgICAgICByZXQgPSAtRUlOVkFMOw0KPiA+ICAgICAgICAgICAgIGdvdG8gb3V0Ow0K
PiA+IEBAIC0yMTEwLDYgKzIyODUsMTIgQEAgc3RhdGljIGludCBsYnNfc2V0X3dhcChzdHJ1Y3Qg
bmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QgaXdfcmVxdWVzdF9pbmZvICppbmZvLA0KPiA+DQo+ID4g
ICAgIGxic19kZWJfZW50ZXIoTEJTX0RFQl9XRVhUKTsNCj4gPg0KPiA+ICsgICBpZiAoIWxic19p
c19jbWRfYWxsb3dlZChwcml2KSkgew0KPiA+ICsgICAgICAgICAgIHJldCA9IC1FQlVTWTsNCj4g
PiArICAgICAgICAgICBsYnNfZGViX2xlYXZlX2FyZ3MoTEJTX0RFQl9XRVhULCAicmV0ICVkIiwg
cmV0KTsNCj4gPiArICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICB9DQo+ID4gKw0KPiA+
ICAgICBpZiAoIXByaXYtPnJhZGlvX29uKQ0KPiA+ICAgICAgICAgICAgIHJldHVybiAtRUlOVkFM
Ow0KPiA+DQo+ID4gX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X18NCj4gPiBsaWJlcnRhcy1kZXYgbWFpbGluZyBsaXN0DQo+ID4gbGliZXJ0YXMtZGV2QGxpc3Rz
LmluZnJhZGVhZC5vcmcNCj4gPiBodHRwOi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xp
c3RpbmZvL2xpYmVydGFzLWRldg0KDQo=

2009-10-01 18:27:38

by Dan Williams

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

On Wed, 2009-09-30 at 20:04 -0700, Bing Zhao wrote:
> From: Amitkumar Karwar <[email protected]>
>
> Add timer based auto deep sleep feature in libertas driver which can be
> configured using iwconfig command. 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]>

Acked-by: Dan Williams <[email protected]>

Though I wonder if we could just put the lbs_is_cmd_allowed() check into
the actual command handling routines instead of sprinkling it around.
We did move away from the 'one-huge-switch' command submission model,
which makes it a bit harder to gate commands based on device state, but
I can't think of anything off the top of my head that would hurt by
doing it like that.

i.e. would putting the check in both __lbs_cmd_async() and
lbs_prepare_and_send_command() around where the priv->surprise_removed
check is work too?

Dan

> ---
> drivers/net/wireless/libertas/README | 26 ++++-
> drivers/net/wireless/libertas/cmd.c | 72 ++++++++++++-
> drivers/net/wireless/libertas/cmdresp.c | 12 ++
> drivers/net/wireless/libertas/debugfs.c | 46 ++++++++
> 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 | 185 ++++++++++++++++++++++++++++++-
> 15 files changed, 533 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
> index ab6a2d5..635002d 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,28 @@ 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.
>
> +========================
> +IWCONFIG COMMANDS
> +========================
> +power period
> +
> + This command is used to configure the station in deep sleep mode /
> + auto deep sleep mode.
> +
> + The timer is implemented to monitor the activities (command, event,
> + 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 deep sleep mode is entered
> + automatically.
> +
> + Note: this command is for SDIO interface only.
> +
> + Usage:
> + To enable deep sleep mode do:
> + iwconfig wlan0 power period 0
> + To enable auto deep sleep mode with idle time period 5 seconds do:
> + iwconfig wlan0 power period 5
> + To disable deep sleep/auto deep sleep mode do:
> + iwconfig wlan0 power period -1
> +
> ==============================================================================
> 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..8a7e931 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;
> @@ -223,6 +233,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 +288,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 +460,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 +517,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 +558,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 +616,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 +657,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 +715,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;
> 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..38a451e 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) {
> @@ -709,6 +776,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
> struct iw_param *vwrq, char *extra)
> {
> struct lbs_private *priv = dev->ml_priv;
> + int ret = 0;
>
> lbs_deb_enter(LBS_DEB_WEXT);
>
> @@ -737,8 +805,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
> "setting power timeout is not supported\n");
> return -EINVAL;
> } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
> - lbs_deb_wext("setting power period not supported\n");
> - return -EINVAL;
> + vwrq->value = vwrq->value / 1000;
> + if (!priv->enter_deep_sleep) {
> + lbs_pr_err("deep sleep feature is not implemented "
> + "for this interface driver\n");
> + return -EINVAL;
> + }
> +
> + if (priv->connect_status == LBS_CONNECTED) {
> + if ((priv->is_auto_deep_sleep_enabled) &&
> + (vwrq->value == -1000)) {
> + lbs_exit_auto_deep_sleep(priv);
> + return 0;
> + } else {
> + lbs_pr_err("can't use deep sleep cmd in "
> + "connected state\n");
> + return -EINVAL;
> + }
> + }
> +
> + if ((vwrq->value < 0) && (vwrq->value != -1000)) {
> + lbs_pr_err("unknown option\n");
> + return -EINVAL;
> + }
> +
> + if (vwrq->value > 0) {
> + if (!priv->is_auto_deep_sleep_enabled) {
> + priv->is_activity_detected = 0;
> + priv->auto_deep_sleep_timeout = vwrq->value;
> + lbs_enter_auto_deep_sleep(priv);
> + } else {
> + priv->auto_deep_sleep_timeout = vwrq->value;
> + lbs_deb_debugfs("auto deep sleep: "
> + "already enabled\n");
> + }
> + return 0;
> + } else {
> + if (priv->is_auto_deep_sleep_enabled) {
> + lbs_exit_auto_deep_sleep(priv);
> + /* Try to exit deep sleep if auto */
> + /*deep sleep disabled */
> + ret = lbs_set_deep_sleep(priv, 0);
> + }
> + if (vwrq->value == 0)
> + ret = lbs_set_deep_sleep(priv, 1);
> + else if (vwrq->value == -1000)
> + ret = lbs_set_deep_sleep(priv, 0);
> + return ret;
> + }
> }
>
> if (priv->psmode != LBS802_11POWERMODECAM) {
> @@ -752,6 +866,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
> }
>
> lbs_deb_leave(LBS_DEB_WEXT);
> +
> return 0;
> }
>
> @@ -792,6 +907,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 +1010,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 +1124,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 +1188,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 +1219,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 +1465,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 +1654,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 +1872,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 +1980,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 +2028,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 +2152,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 +2285,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;
>
> _______________________________________________
> libertas-dev mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/libertas-dev


2009-10-05 19:00:27

by Dan Williams

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

On Mon, 2009-10-05 at 11:47 -0700, Bing Zhao wrote:
> Hi Dan,
>
> > -----Original Message-----
> > From: Dan Williams [mailto:[email protected]]
> > Sent: Thursday, October 01, 2009 11:27 AM
> > To: Bing Zhao
> > Cc: [email protected]; Amitkumar Karwar; [email protected]
> > Subject: Re: [PATCH v2] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
> >
> > On Wed, 2009-09-30 at 20:04 -0700, Bing Zhao wrote:
> > > From: Amitkumar Karwar <[email protected]>
> > >
> > > Add timer based auto deep sleep feature in libertas driver which can be
> > > configured using iwconfig command. 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]>
> >
> > Acked-by: Dan Williams <[email protected]>
> >
> > Though I wonder if we could just put the lbs_is_cmd_allowed() check into
> > the actual command handling routines instead of sprinkling it around.
>
> Yes, we can do that.
>
> > We did move away from the 'one-huge-switch' command submission model,
> > which makes it a bit harder to gate commands based on device state, but
> > I can't think of anything off the top of my head that would hurt by
> > doing it like that.
> >
> > i.e. would putting the check in both __lbs_cmd_async() and
> > lbs_prepare_and_send_command() around where the priv->surprise_removed
> > check is work too?
>
> We will submit a new patch for this.

John may have already applied, so I think it's OK to base the new patch
on top of this one.

Dan

> Regards,
>
> Bing
>
> >
> > Dan
> >
> > > ---
> > > drivers/net/wireless/libertas/README | 26 ++++-
> > > drivers/net/wireless/libertas/cmd.c | 72 ++++++++++++-
> > > drivers/net/wireless/libertas/cmdresp.c | 12 ++
> > > drivers/net/wireless/libertas/debugfs.c | 46 ++++++++
> > > 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 | 185 ++++++++++++++++++++++++++++++-
> > > 15 files changed, 533 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
> > > index ab6a2d5..635002d 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,28 @@ 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.
> > >
> > > +========================
> > > +IWCONFIG COMMANDS
> > > +========================
> > > +power period
> > > +
> > > + This command is used to configure the station in deep sleep mode /
> > > + auto deep sleep mode.
> > > +
> > > + The timer is implemented to monitor the activities (command, event,
> > > + 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 deep sleep mode is entered
> > > + automatically.
> > > +
> > > + Note: this command is for SDIO interface only.
> > > +
> > > + Usage:
> > > + To enable deep sleep mode do:
> > > + iwconfig wlan0 power period 0
> > > + To enable auto deep sleep mode with idle time period 5 seconds do:
> > > + iwconfig wlan0 power period 5
> > > + To disable deep sleep/auto deep sleep mode do:
> > > + iwconfig wlan0 power period -1
> > > +
> > > ==============================================================================
> > > 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..8a7e931 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;
> > > @@ -223,6 +233,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 +288,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 +460,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 +517,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 +558,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 +616,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 +657,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 +715,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;
> > > 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..38a451e 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) {
> > > @@ -709,6 +776,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
> > > struct iw_param *vwrq, char *extra)
> > > {
> > > struct lbs_private *priv = dev->ml_priv;
> > > + int ret = 0;
> > >
> > > lbs_deb_enter(LBS_DEB_WEXT);
> > >
> > > @@ -737,8 +805,54 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
> > > "setting power timeout is not supported\n");
> > > return -EINVAL;
> > > } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
> > > - lbs_deb_wext("setting power period not supported\n");
> > > - return -EINVAL;
> > > + vwrq->value = vwrq->value / 1000;
> > > + if (!priv->enter_deep_sleep) {
> > > + lbs_pr_err("deep sleep feature is not implemented "
> > > + "for this interface driver\n");
> > > + return -EINVAL;
> > > + }
> > > +
> > > + if (priv->connect_status == LBS_CONNECTED) {
> > > + if ((priv->is_auto_deep_sleep_enabled) &&
> > > + (vwrq->value == -1000)) {
> > > + lbs_exit_auto_deep_sleep(priv);
> > > + return 0;
> > > + } else {
> > > + lbs_pr_err("can't use deep sleep cmd in "
> > > + "connected state\n");
> > > + return -EINVAL;
> > > + }
> > > + }
> > > +
> > > + if ((vwrq->value < 0) && (vwrq->value != -1000)) {
> > > + lbs_pr_err("unknown option\n");
> > > + return -EINVAL;
> > > + }
> > > +
> > > + if (vwrq->value > 0) {
> > > + if (!priv->is_auto_deep_sleep_enabled) {
> > > + priv->is_activity_detected = 0;
> > > + priv->auto_deep_sleep_timeout = vwrq->value;
> > > + lbs_enter_auto_deep_sleep(priv);
> > > + } else {
> > > + priv->auto_deep_sleep_timeout = vwrq->value;
> > > + lbs_deb_debugfs("auto deep sleep: "
> > > + "already enabled\n");
> > > + }
> > > + return 0;
> > > + } else {
> > > + if (priv->is_auto_deep_sleep_enabled) {
> > > + lbs_exit_auto_deep_sleep(priv);
> > > + /* Try to exit deep sleep if auto */
> > > + /*deep sleep disabled */
> > > + ret = lbs_set_deep_sleep(priv, 0);
> > > + }
> > > + if (vwrq->value == 0)
> > > + ret = lbs_set_deep_sleep(priv, 1);
> > > + else if (vwrq->value == -1000)
> > > + ret = lbs_set_deep_sleep(priv, 0);
> > > + return ret;
> > > + }
> > > }
> > >
> > > if (priv->psmode != LBS802_11POWERMODECAM) {
> > > @@ -752,6 +866,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
> > > }
> > >
> > > lbs_deb_leave(LBS_DEB_WEXT);
> > > +
> > > return 0;
> > > }
> > >
> > > @@ -792,6 +907,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 +1010,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 +1124,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 +1188,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 +1219,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 +1465,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 +1654,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 +1872,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 +1980,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 +2028,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 +2152,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 +2285,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;
> > >
> > > _______________________________________________
> > > libertas-dev mailing list
> > > [email protected]
> > > http://lists.infradead.org/mailman/listinfo/libertas-dev
>
> NrybXǧv^)޺{.n+{*ޕ,{ayʇڙ,jfhzw j:+vwjmzZ+ݢj"!


2009-10-20 06:43:37

by Holger Schurig

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

> > Side question: which firmware are you using on CS cards?
>
> firmware version for Marvell CF8385 card: 5.101.13p1

Can you provide this firmware to me? Or can you say me where I
can download it?

I still have 5.0.16p0, which seems to not understand
CMD_802_11_MONITOR_MODE and CMD_802_11_TX_RATE_QUERY.

--
http://www.holgerschurig.de

2009-10-06 21:45:09

by Bing Zhao

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

Hi Holger,

Sorry for the late response.

> -----Original Message-----
> From: Holger Schurig [mailto:[email protected]]
> Sent: Thursday, October 01, 2009 12:43 AM
> To: Bing Zhao
> Cc: [email protected]; [email protected]; Amitkumar Karwar
> Subject: Re: [PATCH v2] libertas: Add auto deep sleep support for SD8385/SD8686/SD8688
>
> > Tests have been done for USB/CS cards to make sure that the patch
> > won't break USB/CS code.
>
>
> Side question: which firmware are you using on CS cards?

firmware version for Marvell CF8385 card: 5.101.13p1

Regards,

Bing

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