}
 EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
 
-static int lbs_cmd_802_11_ps_mode(struct cmd_ds_command *cmd,
-                                  u16 cmd_action)
+/**
+ *  @brief Sets the Power Save mode
+ *
+ *  @param priv        A pointer to struct lbs_private structure
+ *  @param cmd_action  The Power Save operation (PS_MODE_ACTION_ENTER_PS or
+ *                         PS_MODE_ACTION_EXIT_PS)
+ *  @param block       Whether to block on a response or not
+ *
+ *  @return            0 on success, error on failure
+ */
+int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
 {
-       struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+       struct cmd_ds_802_11_ps_mode cmd;
+       int ret = 0;
 
        lbs_deb_enter(LBS_DEB_CMD);
 
-       cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
-       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
-                               sizeof(struct cmd_header));
-       psm->action = cpu_to_le16(cmd_action);
-       psm->multipledtim = 0;
-       switch (cmd_action) {
-       case CMD_SUBCMD_ENTER_PS:
-               lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
-
-               psm->locallisteninterval = 0;
-               psm->nullpktinterval = 0;
-               psm->multipledtim =
-                   cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
-               break;
-
-       case CMD_SUBCMD_EXIT_PS:
-               lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
-               break;
-
-       case CMD_SUBCMD_SLEEP_CONFIRMED:
-               lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
-               break;
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       cmd.action = cpu_to_le16(cmd_action);
 
-       default:
-               break;
+       if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
+               lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
+               cmd.multipledtim = cpu_to_le16(1);  /* Default DTIM multiple */
+       } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
+               lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
+       } else {
+               /* We don't handle CONFIRM_SLEEP here because it needs to
+                * be fastpathed to the firmware.
+                */
+               lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
+               ret = -EOPNOTSUPP;
+               goto out;
        }
 
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
+       if (block)
+               ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
+       else
+               lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
+
+out:
+       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+       return ret;
 }
 
 int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
 
        /* Exit_PS command needs to be queued in the header always. */
        if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
-               struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
+               struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
 
-               if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+               if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                        if (priv->psstate != PS_STATE_FULL_POWER)
                                addtail = 0;
                }
        }
 
-       if (le16_to_cpu(cmdnode->cmdbuf->command) ==
-                       CMD_802_11_WAKEUP_CONFIRM)
+       if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
                addtail = 0;
 
        spin_lock_irqsave(&priv->driver_lock, flags);
 {
        int ret = 0;
        struct cmd_ctrl_node *cmdnode;
-       struct cmd_ds_command *cmdptr;
+       struct cmd_header *cmdptr;
        unsigned long flags;
 
        lbs_deb_enter(LBS_DEB_HOST);
        cmdnode->callback = NULL;
        cmdnode->callback_arg = (unsigned long)pdata_buf;
 
-       cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
+       cmdptr = (struct cmd_header *)cmdnode->cmdbuf;
 
        lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
 
        cmdptr->result = 0;
 
        switch (cmd_no) {
-       case CMD_802_11_PS_MODE:
-               ret = lbs_cmd_802_11_ps_mode(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(sizeof(struct cmd_header));
                        /*
                         * 1. Non-PS command:
                         * Queue it. set needtowakeup to TRUE if current state
-                        * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
-                        * 2. PS command but not Exit_PS:
+                        * is SLEEP, otherwise call send EXIT_PS.
+                        * 2. PS command but not EXIT_PS:
                         * Ignore it.
-                        * 3. PS command Exit_PS:
+                        * 3. PS command EXIT_PS:
                         * Set needtowakeup to TRUE if current state is SLEEP,
                         * otherwise send this command down to firmware
                         * immediately.
                                        /* w/ new scheme, it will not reach here.
                                           since it is blocked in main_thread. */
                                        priv->needtowakeup = 1;
-                               } else
-                                       lbs_ps_wakeup(priv, 0);
+                               } else {
+                                       lbs_set_ps_mode(priv,
+                                                       PS_MODE_ACTION_EXIT_PS,
+                                                       false);
+                               }
 
                                ret = 0;
                                goto done;
                                       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
                                       psm->action);
                                if (psm->action !=
-                                   cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+                                   cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
                                        list_del(&cmdnode->list);
                                        lbs_deb_host(
                                               "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
                                               " go back to PS_SLEEP");
-                                       lbs_ps_sleep(priv, 0);
+                                       lbs_set_ps_mode(priv,
+                                                       PS_MODE_ACTION_ENTER_PS,
+                                                       false);
                                }
                        } else {
                                lbs_deb_host(
                                       "EXEC_NEXT_CMD: cmdpendingq empty, "
                                       "go back to PS_SLEEP");
-                               lbs_ps_sleep(priv, 0);
+                               lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
+                                               false);
                        }
                }
 #endif
        lbs_deb_leave(LBS_DEB_HOST);
 }
 
-void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
-{
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       /*
-        * PS is currently supported only in Infrastructure mode
-        * Remove this check if it is to be supported in IBSS mode also
-        */
-
-       lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
-                             CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
-
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
-/**
- *  @brief This function sends Exit_PS command to firmware.
- *
- *  @param priv        A pointer to struct lbs_private structure
- *  @param wait_option wait response or not
- *  @return            n/a
- */
-void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
-{
-       __le32 Localpsmode;
-
-       lbs_deb_enter(LBS_DEB_HOST);
-
-       Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
-
-       lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
-                             CMD_SUBCMD_EXIT_PS,
-                             wait_option, 0, &Localpsmode);
-
-       lbs_deb_leave(LBS_DEB_HOST);
-}
-
 /**
  *  @brief This function checks condition and prepares to
  *  send sleep confirm command to firmware if ok.
 
        if (priv->psstate != PS_STATE_FULL_POWER) {
                /* make firmware to exit PS mode */
                lbs_deb_cmd("disconnected, so exit PS mode\n");
-               lbs_ps_wakeup(priv, 0);
+               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
        }
        lbs_deb_leave(LBS_DEB_ASSOC);
 }
                         * lbs_execute_next_command().
                         */
                        if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
-                           action == CMD_SUBCMD_ENTER_PS)
+                           action == PS_MODE_ACTION_ENTER_PS)
                                priv->psmode = LBS802_11POWERMODECAM;
-               } else if (action == CMD_SUBCMD_ENTER_PS) {
+               } else if (action == PS_MODE_ACTION_ENTER_PS) {
                        priv->needtowakeup = 0;
                        priv->psstate = PS_STATE_AWAKE;
 
 
                                spin_unlock_irqrestore(&priv->driver_lock, flags);
                                mutex_unlock(&priv->lock);
-                               lbs_ps_wakeup(priv, 0);
+                               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS,
+                                               false);
                                mutex_lock(&priv->lock);
                                spin_lock_irqsave(&priv->driver_lock, flags);
                        }
-               } else if (action == CMD_SUBCMD_EXIT_PS) {
+               } else if (action == PS_MODE_ACTION_EXIT_PS) {
                        priv->needtowakeup = 0;
                        priv->psstate = PS_STATE_FULL_POWER;
                        lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
                         * in lbs_ps_wakeup()
                         */
                        lbs_deb_cmd("waking up ...\n");
-                       lbs_ps_wakeup(priv, 0);
+                       lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
                }
                break;
 
 
 #define CMD_802_11_BEACON_CTRL                  0x00b0
 
 /* For the IEEE Power Save */
-#define CMD_SUBCMD_ENTER_PS                     0x0030
-#define CMD_SUBCMD_EXIT_PS                      0x0031
-#define CMD_SUBCMD_SLEEP_CONFIRMED              0x0034
-#define CMD_SUBCMD_FULL_POWERDOWN               0x0035
-#define CMD_SUBCMD_FULL_POWERUP                 0x0036
+#define PS_MODE_ACTION_ENTER_PS                 0x0030
+#define PS_MODE_ACTION_EXIT_PS                  0x0031
+#define PS_MODE_ACTION_SLEEP_CONFIRMED          0x0034
 
 #define CMD_ENABLE_RSN                          0x0001
 #define CMD_DISABLE_RSN                         0x0000
 #define CMD_ACT_SET_TX_FIX_RATE                 0x0001
 #define CMD_ACT_GET_TX_RATE                     0x0002
 
-/* Define action or option for CMD_802_11_PS_MODE */
-#define CMD_TYPE_CAM                            0x0000
-#define CMD_TYPE_MAX_PSP                        0x0001
-#define CMD_TYPE_FAST_PSP                       0x0002
-
 /* Options for CMD_802_11_FW_WAKE_METHOD */
 #define CMD_WAKE_METHOD_UNCHANGED               0x0000
 #define CMD_WAKE_METHOD_COMMAND_INT             0x0001
 } __packed;
 
 struct cmd_ds_802_11_ps_mode {
+       struct cmd_header hdr;
+
        __le16 action;
+
+       /* Interval for keepalive in PS mode:
+        * 0x0000 = don't change
+        * 0x001E = firmware default
+        * 0xFFFF = disable
+        */
        __le16 nullpktinterval;
+
+       /* Number of DTIM intervals to wake up for:
+        * 0 = don't change
+        * 1 = firmware default
+        * 5 = max
+        */
        __le16 multipledtim;
+
        __le16 reserved;
        __le16 locallisteninterval;
+
+       /* AdHoc awake period (FW v9+ only):
+        * 0 = don't change
+        * 1 = always awake (IEEE standard behavior)
+        * 2 - 31 = sleep for (n - 1) periods and awake for 1 period
+        * 32 - 254 = invalid
+        * 255 = sleep at each ATIM
+        */
+       __le16 adhoc_awake_period;
 } __packed;
 
 struct cmd_confirm_sleep {
 
 /* Number of stats counters returned by the firmware */
 #define MESH_STATS_NUM 8
-
-struct cmd_ds_command {
-       /* command header */
-       __le16 command;
-       __le16 size;
-       __le16 seqnum;
-       __le16 result;
-
-       /* command Body */
-       union {
-               struct cmd_ds_802_11_ps_mode psmode;
-       } params;
-} __packed;
 #endif