diff -Naur backports-4.4.2-1/defconfigs/ath9k-debug backports-4.4.2-1-modwifi/defconfigs/ath9k-debug
--- backports-4.4.2-1/defconfigs/ath9k-debug 2016-02-18 22:41:34.000000000 +0100
+++ backports-4.4.2-1-modwifi/defconfigs/ath9k-debug 2016-04-03 13:28:53.000000000 +0200
@@ -17,3 +17,4 @@
CPTCFG_ATH9K_HTC=m
CPTCFG_ATH_DEBUG=y
CPTCFG_ATH9K_DEBUGFS=y
+CPTCFG_ATH9K_HTC_DEBUGFS=y
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_debug.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_debug.c 2016-02-18 22:41:35.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_debug.c 2016-04-03 13:28:54.000000000 +0200
@@ -15,6 +15,61 @@
*/
#include "htc.h"
+#include "hw.h"
+
+typedef u32 (*GetTimeFunc)(struct ath_hw *ah);
+typedef void (*SetTimeFunc)(struct ath_hw *ah, u32 us);
+
+struct time_func {
+ const char *name;
+ GetTimeFunc getter;
+ SetTimeFunc setter;
+ const char *comments;
+};
+
+struct time_func_context {
+ struct time_func *timefunc;
+ struct ath9k_htc_priv *htcpriv;
+};
+
+struct time_func timefunctions[] =
+{
+ {"time_sifs", ath9k_hw_get_sifs_time, ath9k_hw_set_sifs_time,
+ "SIFS time in microseconds (us) = Rx/Tx time = required time to wait after Rx."},
+ {"time_slottime", ath9k_hw_getslottime, ath9k_hw_setslottime,
+ "Slot time (aSlotTime) in microseconds (us) = slot time as used in backoff algo."},
+ {"time_ack_timeout", ath9k_hw_get_ack_timeout, ath9k_hw_set_ack_timeout,
+ "ACK timeout in microseconds (us)"},
+ {"time_cts_timeout", ath9k_hw_get_cts_timeout, ath9k_hw_set_cts_timeout,
+ "CTS timeout in microseconds (us)"},
+ {"time_eifs", ath9k_hw_get_eifs_timeout, ath9k_hw_set_eifs_timeout,
+ "EIFS time in microseconds (us)"}
+};
+
+struct reg_ops registers[] = {
+ // Backoff parameters
+ {"ifs_cwmin_queue0", AR_DLCL_IFS(0), AR_D_LCL_IFS_CWMIN,
+ "Backoff behaviour (queue 0): CW_MIN is the minimum number of time slots to wait."},
+ {"ifs_cwmax_queue0", AR_DLCL_IFS(0), AR_D_LCL_IFS_CWMAX,
+ "Backoff behaviour (queue 0): CW_MAX is the maximum number of time slots to wait."},
+ {"ifs_aifs_queue0", AR_DLCL_IFS(0), AR_D_LCL_IFS_AIFS,
+ "AIFS (in number of aSlotTime's) for queue 0."},
+ // Disable backoff
+ {"ifs_ignore_backoff", AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF,
+ "Ignore backoff (perhaps you also want to disable waiting for ACKs - see inject_noack)."},
+ // Virtual and physical carrier sense
+ {"ignore_virt_cs", AR_DIAG_SW, AR_DIAG_IGNORE_VIRT_CS,
+ "Disables virtual carrier (cts/rts) sense when set."},
+ {"force_channel_idle", AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH,
+ "Disables physical carrier sense (air clear) when set."},
+ {"diag_rx_disable", AR_DIAG_SW, AR_DIAG_RX_DIS,
+ "Block incoming frames from being sent to the firmware."},
+ // Other
+ {"diag_corrupt_fcs", AR_DIAG_SW, AR_DIAG_CORR_FCS,
+ "If set, every transmitted packet is given an incorrect FCS."},
+ {"cpu_freq_pll", 0x00056000, -1,
+ "Value = frequency * 4 + 5 (Setting of the Phase Locked Loop)."},
+};
static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -398,6 +453,633 @@
.llseek = default_llseek,
};
+static ssize_t read_file_reg_ops(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct reg_ops_instance *instance = file->private_data;
+ struct ath9k_htc_priv *priv = instance->owner;
+ struct reg_ops *regops = instance->regops;
+ char buf[512];
+ unsigned int len;
+ unsigned int regval, mask;
+
+ ath9k_htc_ps_wakeup(priv);
+ regval = REG_READ(priv->ah, regops->address);
+ ath9k_htc_ps_restore(priv);
+
+ // apply mask, and shift according to mask
+ regval &= regops->mask;
+ mask = regops->mask;
+ while ( (mask & 1) == 0) {
+ mask >>= 1;
+ regval >>= 1;
+ }
+
+ len = snprintf(buf, sizeof(buf), "%s: %s\nValue: 0x%08X = %d (forced: %d)\n",
+ regops->name, regops->description, regval, regval,
+ !!(instance->valueset));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_reg_ops(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct reg_ops_instance *instance = file->private_data;
+ struct ath9k_htc_priv *priv = instance->owner;
+ struct reg_ops *regops = instance->regops;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+ unsigned int mask, regval;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EINVAL;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ // shift according to mask
+ mask = regops->mask;
+ while ( (mask & 1) == 0) {
+ mask >>= 1;
+ val <<= 1;
+ }
+
+ // apply mask to assure we're not overwriting anything else
+ val &= regops->mask;
+
+ ath9k_htc_ps_wakeup(priv);
+ regval = REG_READ(priv->ah, regops->address);
+ regval = (regval & ~regops->mask) | val;
+ REG_WRITE(priv->ah, regops->address, regval);
+ ath9k_htc_ps_restore(priv);
+
+ instance->valueset = 1;
+ instance->value = val;
+
+ return count;
+}
+
+static const struct file_operations fops_reg_ops = {
+ .read = read_file_reg_ops,
+ .write = write_file_reg_ops,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_dmesg(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct wmi_debugmsg_cmd cmd;
+ struct wmi_debugmsg_resp cmd_rsp;
+ /** ppos is the amount of data already read (maintained by caller) */
+ int offset = *ppos;
+ int ret;
+
+ /** Note: don't need to wake the WiFi MAC chip to get debug messages! */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.offset = cpu_to_be16(offset);
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+ ret = ath9k_wmi_cmd(priv->wmi, WMI_DEBUGMSG_CMDID,
+ (u8*)&cmd, sizeof(cmd),
+ (u8*)&cmd_rsp, sizeof(cmd_rsp),
+ HZ*2);
+ if (ret) {
+ printk("ath9k_htc %s: Something went wrong reading firmware dmesg (ret: %d, len: %d)\n",
+ __FUNCTION__, ret, cmd_rsp.length);
+ return -EIO;
+ }
+
+ // Don't overflow user_buf
+ if (count < cmd_rsp.length)
+ cmd_rsp.length = count;
+
+ // Length of zero signifies EOF
+ if (cmd_rsp.length != 0) {
+ // Returns number of bytes that could not be copied
+ if (copy_to_user(user_buf, cmd_rsp.buffer, cmd_rsp.length) != 0)
+ return -EFAULT;
+ }
+
+ *ppos += cmd_rsp.length;
+ return cmd_rsp.length;
+}
+
+static const struct file_operations fops_dmesg = {
+ .read = read_file_dmesg,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_reactivejam(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char output[] = "Jam beacons and probe responses by writing the bssid and"
+ "duration (in msecs) to this file as 'XX:XX:XX:XX:XX:XX,10000'.\n"
+ "Duration of 0 means an infinite jam (device becomes unresponsive).\n";
+ return simple_read_from_buffer(user_buf, count, ppos, output, sizeof(output));
+}
+
+static ssize_t write_file_reactivejam(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct wmi_reactivejam_cmd cmd;
+ char buf[32] = {0}, reply[128] = {0};
+ unsigned int intmac[6];
+ unsigned int duration;
+ int rval, len, i;
+
+ if (*ppos != 0) return 0;
+
+ // copy over input
+ len = min(count, sizeof(buf) - 1);
+ if (unlikely(copy_from_user(buf, user_buf, len))) {
+ printk("ath9k_htc %s: copy_from_user failed\n", __FUNCTION__);
+ return -EFAULT;
+ }
+ buf[sizeof(buf) - 1] = 0;
+
+ // parse input
+ if ( 7 != sscanf(buf, "%x:%x:%x:%x:%x:%x,%u", &intmac[0], &intmac[1], &intmac[2],
+ &intmac[3], &intmac[4], &intmac[5], &duration) ) {
+ printk("ath9k_htc %s: invalid format\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ // save input to command
+ for (i = 0; i < 6; ++i)
+ cmd.bssid[i] = intmac[i];
+ cmd.mduration = cpu_to_be32(duration);
+
+ printk("ath9k_htc: Reactively jamming %x:%x:%x:%x:%x:%x ", cmd.bssid[0], cmd.bssid[1],
+ cmd.bssid[2], cmd.bssid[3], cmd.bssid[4], cmd.bssid[5]);
+ if (cmd.mduration == 0)
+ printk("indefinitely (device will be unresponsive)\n");
+ else
+ printk("for %u miliseconds\n", duration);
+
+ // Blocking call! Wait for duration + 4 seconds. Response is an ASCII string. If the duration
+ // is zero, firmware instantly replies, but will then become unresponsive (infinite jam).
+ ath9k_htc_ps_wakeup(priv);
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_REACTIVEJAM_CMDID,
+ (u8*)&cmd, sizeof(cmd),
+ (u8*)reply, sizeof(reply),
+ HZ * (duration / 1000 + 4));
+ ath9k_htc_ps_restore(priv);
+
+ if (unlikely(rval) && cmd.mduration != 0) {
+ printk("ath9k_htc %s: WMI_REACTIVEJAM_CMD failed with %d\n", __FUNCTION__, rval);
+ return -EBUSY;
+ }
+
+ // Reset radio settings
+ ath9k_hw_init_global_settings(priv->ah);
+
+ return count;
+}
+
+static const struct file_operations fops_reactivejam = {
+ .read = read_file_reactivejam,
+ .write = write_file_reactivejam,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_constantjam(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct wmi_constantjam_resp cmd_rsp;
+ struct wmi_constantjam_cmd cmd;
+ char buf[128];
+ unsigned int len;
+ int rval;
+
+ if (*ppos != 0) return 0;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.request = CONSTJAM_STATUS;
+
+ // Send command to firmware
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_CONSTANTJAM_CMDID,
+ (u8 *)&cmd, sizeof(cmd),
+ (u8 *)&cmd_rsp, sizeof(cmd_rsp),
+ HZ*2);
+
+ if (unlikely(rval)) {
+ printk(">>>> WMI_CONSTANTJAM_CMD failed: %d\n", rval);
+ return -EIO;
+ }
+
+ len = snprintf(buf, sizeof(buf), "Constant jammer running: %d\n", cmd_rsp.status);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_constantjam(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct wmi_constantjam_resp cmd_rsp;
+ struct wmi_constantjam_cmd cmd;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+ int rval = 0;
+
+ if (*ppos != 0) return 0;
+
+ // parse input
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EINVAL;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(cmd));
+ // should we start or stop
+ cmd.request = val == 0 ? CONSTJAM_STOP : CONSTJAM_START;
+ // full continuous jamming (disable carrier sense, no timeouts between packets)
+ cmd.conf_radio = 1;
+ // length of packet used for jamming (pick a small one to avoid memory issues)
+ cmd.len = cpu_to_be16(50);
+
+ // Send command to firmware
+ ath9k_htc_ps_wakeup(priv);
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_CONSTANTJAM_CMDID,
+ (u8 *)&cmd, sizeof(cmd),
+ (u8 *)&cmd_rsp, sizeof(cmd_rsp),
+ HZ*2);
+
+ if (unlikely(rval)) {
+ printk(">>>> WMI_CONSTANTJAM_CMD failed: %d\n", rval);
+ return -EIO;
+ }
+
+ if (cmd.request == CONSTJAM_STOP)
+ ath9k_htc_ps_restore(priv);
+
+ return count;
+}
+
+static const struct file_operations fops_constantjam = {
+ .read = read_file_constantjam,
+ .write = write_file_constantjam,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_macaddr(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len;
+ unsigned int low, upper;
+
+ ath9k_htc_ps_wakeup(priv);
+ low = REG_READ(priv->ah, AR_STA_ID0);
+ upper = REG_READ(priv->ah, AR_STA_ID1) & AR_STA_ID1_SADH_MASK;
+ ath9k_htc_ps_restore(priv);
+
+ len = snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X\n",
+ low & 0xFF, (low >> 8) & 0xFF, (low >> 16) & 0xFF,
+ (low >> 24) & 0xFF, upper & 0xFF, (upper >> 8) & 0xFF);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_macaddr(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[32];
+ unsigned int mac[6];
+ unsigned int low, upper;
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[sizeof(buf) - 1] = 0;
+
+ if ( 6 != sscanf(buf, "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) )
+ return -EINVAL;
+
+ low = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+ upper = mac[4] | (mac[5] << 8);
+
+ ath9k_htc_ps_wakeup(priv);
+ REG_WRITE(priv->ah, AR_STA_ID0, low);
+ REG_WRITE(priv->ah, AR_STA_ID1, upper & AR_STA_ID1_SADH_MASK);
+ ath9k_htc_ps_restore(priv);
+
+ return count;
+}
+
+static const struct file_operations fops_macaddr = {
+ .read = read_file_macaddr,
+ .write = write_file_macaddr,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_bssidmask(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len;
+ unsigned int low, upper;
+
+ ath9k_htc_ps_wakeup(priv);
+ low = REG_READ(priv->ah, AR_BSSMSKL);
+ upper = REG_READ(priv->ah, AR_BSSMSKU);
+ ath9k_htc_ps_restore(priv);
+
+ len = snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X\n",
+ low & 0xFF, (low >> 8) & 0xFF, (low >> 16) & 0xFF,
+ (low >> 24) & 0xFF, upper & 0xFF, (upper >> 8) & 0xFF);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_bssidmask(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[32];
+ unsigned int mask[6];
+ unsigned int low, upper;
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[sizeof(buf) - 1] = 0;
+
+ if ( 6 != sscanf(buf, "%x:%x:%x:%x:%x:%x", &mask[0], &mask[1], &mask[2], &mask[3], &mask[4], &mask[5]) )
+ return -EINVAL;
+
+ low = mask[0] | (mask[1] << 8) | (mask[2] << 16) | (mask[3] << 24);
+ upper = mask[4] | (mask[5] << 8);
+
+ ath9k_htc_ps_wakeup(priv);
+ REG_WRITE(priv->ah, AR_BSSMSKL, low);
+ REG_WRITE(priv->ah, AR_BSSMSKU, upper & AR_BSS_ID1_U16);
+ ath9k_htc_ps_restore(priv);
+
+ return count;
+}
+
+static const struct file_operations fops_bssidmask = {
+ .read = read_file_bssidmask,
+ .write = write_file_bssidmask,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_inject_noack(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[64];
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "%d\n", priv->inject_noack);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_inject_noack(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[32];
+ unsigned long val;
+ int len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ priv->inject_noack = val;
+
+ return count;
+}
+
+static const struct file_operations fops_inject_noack = {
+ .read = read_file_inject_noack,
+ .write = write_file_inject_noack,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_fastreply_packet(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[128] = "Write the reply packet used in fastreply_start to this file.\n";
+ return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
+}
+
+static ssize_t write_file_fastreply_packet(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct wmi_fastreply_cmd cmd;
+ uint8_t buff[256];
+ unsigned int offset;
+ int reply, rval;
+
+ if (*ppos != 0) return 0;
+
+ //
+ // 1. copy input
+ //
+
+ if (count > 256) {
+ printk("fastreply_packet: packet is too long (%zu)\n", count);
+ return -EMSGSIZE;
+ }
+
+ if (copy_from_user(buff, user_buf, count))
+ return -EFAULT;
+
+ //
+ // 2. send the buffer to the firmware
+ //
+
+ cmd.type = FASTREPLY_PKT;
+ cmd.pkt.length = count;
+
+ ath9k_htc_ps_wakeup(priv);
+
+ for (offset = 0; offset < count; offset += sizeof(cmd.pkt.data))
+ {
+ cmd.pkt.offset = offset;
+ cmd.pkt.datalen = min(40U, (unsigned int)(count - offset));
+ memcpy(cmd.pkt.data, &buff[offset], cmd.pkt.datalen);
+
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_FASTREPLY_CMDID,
+ (u8*)&cmd, sizeof(cmd),
+ (u8*)&reply, sizeof(reply),
+ 2*HZ);
+
+ if (unlikely(rval)) {
+ printk("ath9k_htc %s: WMI_FASTREPLY_CMDID failed with %d\n", __FUNCTION__, rval);
+ ath9k_htc_ps_restore(priv);
+ return -EIO;
+ }
+ }
+
+ ath9k_htc_ps_restore(priv);
+
+ return count;
+}
+
+
+static const struct file_operations fops_fastreply_packet = {
+ .read = read_file_fastreply_packet,
+ .write = write_file_fastreply_packet,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_fastreply_start(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[128] = "Write the source MAC and duration ( 90:18:7c:6e:6b:20,10000 ) to this file.\n"
+ "Set the reply packet using fastreply_packet.\n";
+ return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
+}
+
+static ssize_t write_file_fastreply_start(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct wmi_fastreply_cmd cmd;
+ char input[256];
+ int mac[6];
+ unsigned int duration;
+ int len, reply, rval, i;
+
+ if (*ppos != 0) return 0;
+
+ // 1. parse input
+
+ len = min(count, sizeof(input) - 1);
+ if (copy_from_user(input, user_buf, len))
+ return -EFAULT;
+ input[len] = '\0';
+
+ if (sscanf(input, "%x:%x:%x:%x:%x:%x,%u", &mac[0], &mac[1], &mac[2],
+ &mac[3], &mac[4], &mac[5], &duration) != 7) {
+ printk("%s: sscanf parsing failed\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ // 2. send the start command
+
+ cmd.type = FASTREPLY_START;
+ cmd.start.mduration = cpu_to_be32(duration);
+ for (i = 0; i < 6; ++i)
+ cmd.start.source[i] = mac[i];
+
+ ath9k_htc_ps_wakeup(priv);
+
+ rval = ath9k_wmi_cmd(priv->wmi, WMI_FASTREPLY_CMDID,
+ (u8*)&cmd, sizeof(cmd),
+ (u8*)&reply, sizeof(reply),
+ HZ * (duration / 1000 + 4));
+
+ ath9k_htc_ps_restore(priv);
+
+ if (unlikely(rval)) {
+ printk("ath9k_htc %s: WMI_FASTREPLY_CMDID failed with %d\n", __FUNCTION__, rval);
+ return -EBUSY;
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_fastreply_start = {
+ .read = read_file_fastreply_start,
+ .write = write_file_fastreply_start,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+
+static ssize_t read_file_timefunc(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct time_func_context *context = file->private_data;
+ struct time_func *timefunc = context->timefunc;
+ struct ath9k_htc_priv *priv = context->htcpriv;
+ char buf[512];
+ unsigned int len, val;
+
+ // FIXME: Is the wakeup/restore call needed?
+ ath9k_htc_ps_wakeup(priv);
+ val = timefunc->getter(priv->ah);
+ ath9k_htc_ps_restore(priv);
+
+ len = snprintf(buf, sizeof(buf), "%s: %s\nValue: 0x%08X = %d\n",
+ timefunc->name, timefunc->comments, val, val);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_timefunc(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct time_func_context *context = file->private_data;
+ struct time_func *timefunc = context->timefunc;
+ struct ath9k_htc_priv *priv = context->htcpriv;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EINVAL;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ // FIXME: Is the wakeup/restore call needed?
+ ath9k_htc_ps_wakeup(priv);
+ timefunc->setter(priv->ah, (u32)val);
+ ath9k_htc_ps_restore(priv);
+
+ return count;
+}
+
+static const struct file_operations fops_timefunc = {
+ .read = read_file_timefunc,
+ .write = write_file_timefunc,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
/* Ethtool support for get-stats */
#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = {
@@ -488,6 +1170,8 @@
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct reg_ops_instance *previnstance;
+ int i;
priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
priv->hw->wiphy->debugfsdir);
@@ -516,9 +1200,79 @@
priv, &fops_queue);
debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
priv, &fops_debug);
+ debugfs_create_file("dmesg", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_dmesg);
+ debugfs_create_file("reactivejam", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_reactivejam);
+ debugfs_create_file("constantjam", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_constantjam);
+ debugfs_create_file("fastreply_packet", S_IRUSR | S_IWUSR,
+ priv->debug.debugfs_phy, priv, &fops_fastreply_packet);
+ debugfs_create_file("fastreply_start", S_IRUSR | S_IWUSR,
+ priv->debug.debugfs_phy, priv, &fops_fastreply_start);
+ debugfs_create_file("macaddr", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
+ priv, &fops_macaddr);
+ debugfs_create_file("bssidmask", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
+ priv, &fops_bssidmask);
+ debugfs_create_file("inject_noack", S_IRUSR | S_IWUSR,
+ priv->debug.debugfs_phy, priv, &fops_inject_noack);
ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah);
ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah);
+ //
+ // Read/write access to registers
+ //
+
+ priv->debug.debugfs_phy_regs = debugfs_create_dir("registers", priv->debug.debugfs_phy);
+ if (!priv->debug.debugfs_phy_regs)
+ return -ENOMEM;
+
+ previnstance = NULL;
+ for (i = 0; i < sizeof(registers) / sizeof(registers[0]); ++i)
+ {
+ struct reg_ops *regops = ®isters[i];
+ struct reg_ops_instance *instance;
+
+ // Allocated linked list is freed in ath9k_hw_deinit
+ instance = kzalloc(sizeof(struct reg_ops_instance), GFP_KERNEL);
+ if (!instance) return -ENOMEM;
+
+ instance->regops = regops;
+ instance->owner = priv;
+
+ instance->valueset = 0;
+ instance->value = 0;
+ instance->next = previnstance;
+
+ // Read/write access using general functions
+ debugfs_create_file(regops->name, S_IRUSR|S_IWUSR,
+ priv->debug.debugfs_phy_regs, instance, &fops_reg_ops);
+
+ previnstance = instance;
+ }
+
+ priv->ah->modified_registers = previnstance;
+
+
+ //
+ // Time functions
+ //
+
+ for (i = 0; i < sizeof(timefunctions) / sizeof(timefunctions[0]); ++i)
+ {
+ // Allocate a context
+ struct time_func_context *context;
+ context = devm_kzalloc(priv->dev, sizeof(struct time_func_context), GFP_KERNEL);
+ if (!context) return -ENOMEM;
+
+ context->timefunc = &timefunctions[i];
+ context->htcpriv = priv;
+
+ // Read/write access using general functions
+ debugfs_create_file(context->timefunc->name, S_IRUSR|S_IWUSR,
+ priv->debug.debugfs_phy, context, &fops_timefunc);
+ }
+
return 0;
}
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_init.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_init.c
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_init.c 2016-02-18 22:41:35.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_init.c 2016-04-03 13:28:54.000000000 +0200
@@ -99,6 +99,18 @@
static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
{
+ if (priv->debug.debugfs_phy_regs)
+ debugfs_remove(priv->debug.debugfs_phy_regs);
+ priv->debug.debugfs_phy_regs = NULL;
+
+ if (priv->debug.debugfs_phy)
+ debugfs_remove(priv->debug.debugfs_phy);
+ priv->debug.debugfs_phy = NULL;
+
+ if (priv->hw->wiphy->debugfsdir)
+ debugfs_remove(priv->hw->wiphy->debugfsdir);
+ priv->hw->wiphy->debugfsdir = NULL;
+
ath9k_hw_deinit(priv->ah);
kfree(priv->ah);
priv->ah = NULL;
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 2016-02-18 22:41:36.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c 2016-04-03 13:28:54.000000000 +0200
@@ -211,6 +211,7 @@
return error;
}
+/** Used to handle management and injected frames */
static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv,
struct ath9k_htc_vif *avp,
struct sk_buff *skb,
@@ -222,6 +223,7 @@
struct tx_mgmt_hdr mgmt_hdr;
struct ath9k_htc_tx_ctl *tx_ctl;
u8 *tx_fhdr;
+ u8 flags = 0;
tx_ctl = HTC_SKB_CB(skb);
hdr = (struct ieee80211_hdr *) skb->data;
@@ -238,12 +240,19 @@
mgmt->u.probe_resp.timestamp = avp->tsfadjust;
}
+ /* Should firmware assign sequence number */
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ flags |= ATH9K_HTC_TX_ASSIGN_SEQ;
+ /* Don't retransmit injected packets if requested so */
+ if (unlikely(priv->inject_noack && (tx_info->flags & IEEE80211_TX_CTL_INJECTED)))
+ flags |= ATH9K_HTC_TX_NO_ACK;
+
tx_ctl->type = ATH9K_HTC_MGMT;
mgmt_hdr.node_idx = sta_idx;
mgmt_hdr.vif_idx = vif_idx;
mgmt_hdr.tidno = 0;
- mgmt_hdr.flags = 0;
+ mgmt_hdr.flags = flags;
mgmt_hdr.cookie = slot;
mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
@@ -302,6 +311,13 @@
tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
}
+ /* Should firmware assign sequence number */
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ flags |= ATH9K_HTC_TX_ASSIGN_SEQ;
+ /* Don't retransmit injected packets if requested so */
+ if (unlikely(priv->inject_noack && (tx_info->flags & IEEE80211_TX_CTL_INJECTED)))
+ flags |= ATH9K_HTC_TX_NO_ACK;
+
/* Check for RTS protection */
if (priv->hw->wiphy->rts_threshold != (u32) -1)
if (skb->len > priv->hw->wiphy->rts_threshold)
@@ -373,12 +389,11 @@
sta_idx = priv->vif_sta_pos[vif_idx];
}
- if (ieee80211_is_data(hdr->frame_control))
- ath9k_htc_tx_data(priv, vif, skb,
- sta_idx, vif_idx, slot, is_cab);
+ /** Treat injected frames as management frames to avoid modifications to them */
+ if (ieee80211_is_data(hdr->frame_control) && !(tx_info->flags & IEEE80211_TX_CTL_INJECTED))
+ ath9k_htc_tx_data(priv, vif, skb, sta_idx, vif_idx, slot, is_cab);
else
- ath9k_htc_tx_mgmt(priv, avp, skb,
- sta_idx, vif_idx, slot);
+ ath9k_htc_tx_mgmt(priv, avp, skb, sta_idx, vif_idx, slot);
return htc_send(priv->htc, skb);
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc.h backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc.h
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/htc.h 2016-02-18 22:41:35.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/htc.h 2016-04-03 13:28:54.000000000 +0200
@@ -69,6 +69,8 @@
#define ATH9K_HTC_TX_CTSONLY 0x1
#define ATH9K_HTC_TX_RTSCTS 0x2
+#define ATH9K_HTC_TX_ASSIGN_SEQ 0x10
+#define ATH9K_HTC_TX_NO_ACK 0x20
struct tx_frame_hdr {
u8 data_type;
@@ -357,6 +359,7 @@
struct ath9k_debug {
struct dentry *debugfs_phy;
+ struct dentry *debugfs_phy_regs;
struct ath_tx_stats tx_stats;
struct ath_rx_stats rx_stats;
struct ath_skbrx_stats skbrx_stats;
@@ -510,6 +513,9 @@
bool ps_enabled;
bool ps_idle;
+ /** If set, injected packets are never retransmitted (not waiting for ACK) */
+ u8 inject_noack;
+
#ifdef CPTCFG_MAC80211_LEDS
enum led_brightness brightness;
bool led_registered;
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.c
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.c 2016-02-18 22:41:36.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.c 2016-04-03 13:28:54.000000000 +0200
@@ -67,6 +67,7 @@
common->clockrate = clockrate;
}
+/** This is the clockrate of the wireless chip (not the chip running the firmware for ath9k_htc) */
static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
{
struct ath_common *common = ath9k_hw_common(ah);
@@ -74,6 +75,17 @@
return usecs * common->clockrate;
}
+/** This is the clockrate of the wireless chip (not the chip running the firmware for ath9k_htc) */
+static u32 ath9k_hw_mac_to_usecs(struct ath_hw *ah, u32 clks)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (common->clockrate == 0)
+ return 0xFFFFFFFF;
+
+ return clks / common->clockrate;
+}
+
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
{
int i;
@@ -246,6 +258,24 @@
centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
}
+static void ath9k_restore_registers(struct ath_hw *ah)
+{
+ struct reg_ops_instance *saved_reg = ah->modified_registers;
+ int regval;
+
+ while (saved_reg != NULL)
+ {
+ if (saved_reg->valueset)
+ {
+ regval = REG_READ(ah, saved_reg->regops->address);
+ regval = (regval & ~saved_reg->regops->mask) | saved_reg->value;
+ REG_WRITE(ah, saved_reg->regops->address, regval);
+ }
+
+ saved_reg = saved_reg->next;
+ }
+}
+
/******************/
/* Chip Revisions */
/******************/
@@ -972,33 +1002,78 @@
}
}
-static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us)
+void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us - 2);
- val = min(val, (u32) 0xFFFF);
+ val &= AR_D_GBL_IFS_SIFS_M;
REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val);
}
+EXPORT_SYMBOL(ath9k_hw_set_sifs_time);
void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
- val = min(val, (u32) 0xFFFF);
+ val &= AR_D_GBL_IFS_SLOT_M;
REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
}
+EXPORT_SYMBOL(ath9k_hw_setslottime);
void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
- val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
}
+EXPORT_SYMBOL(ath9k_hw_set_ack_timeout);
void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
{
u32 val = ath9k_hw_mac_to_clks(ah, us);
- val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val);
}
+EXPORT_SYMBOL(ath9k_hw_set_cts_timeout);
+
+void ath9k_hw_set_eifs_timeout(struct ath_hw *ah, u32 us)
+{
+ u32 val = ath9k_hw_mac_to_clks(ah, us);
+ val &= AR_D_GBL_IFS_EIFS;
+ REG_WRITE(ah, AR_D_GBL_IFS_EIFS, val);
+}
+EXPORT_SYMBOL(ath9k_hw_set_eifs_timeout);
+
+u32 ath9k_hw_get_sifs_time(struct ath_hw *ah)
+{
+ u32 val = REG_READ(ah, AR_D_GBL_IFS_SIFS) & AR_D_GBL_IFS_SIFS_M;
+ return ath9k_hw_mac_to_usecs(ah, val) + 2;
+}
+EXPORT_SYMBOL(ath9k_hw_get_sifs_time);
+
+u32 ath9k_hw_getslottime(struct ath_hw *ah)
+{
+ u32 val = REG_READ(ah, AR_D_GBL_IFS_SLOT) & AR_D_GBL_IFS_SLOT_M;
+ return ath9k_hw_mac_to_usecs(ah, val);
+}
+EXPORT_SYMBOL(ath9k_hw_getslottime);
+
+u32 ath9k_hw_get_ack_timeout(struct ath_hw *ah)
+{
+ u32 val = MS(REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK);
+ return ath9k_hw_mac_to_usecs(ah, val);
+}
+EXPORT_SYMBOL(ath9k_hw_get_ack_timeout);
+
+u32 ath9k_hw_get_cts_timeout(struct ath_hw *ah)
+{
+ u32 val = MS(REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS);
+ return ath9k_hw_mac_to_usecs(ah, val);
+}
+EXPORT_SYMBOL(ath9k_hw_get_cts_timeout);
+
+u32 ath9k_hw_get_eifs_timeout(struct ath_hw *ah)
+{
+ u32 val = REG_READ(ah, AR_D_GBL_IFS_EIFS) & AR_D_GBL_IFS_EIFS_M;
+ return ath9k_hw_mac_to_usecs(ah, val);
+}
+EXPORT_SYMBOL(ath9k_hw_get_eifs_timeout);
static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
{
@@ -2025,6 +2100,8 @@
if (AR_SREV_9565(ah) && common->bt_ant_diversity)
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
+ ath9k_restore_registers(ah);
+
if (ah->hw->conf.radar_enabled) {
/* set HW specific DFS configuration */
ah->radar_conf.ext_channel = IS_CHAN_HT40(chan);
@@ -2173,6 +2250,8 @@
REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ ath9k_restore_registers(ah);
+
return true;
}
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.h backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.h
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/hw.h 2016-02-18 22:41:36.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/hw.h 2016-04-03 13:28:54.000000000 +0200
@@ -761,6 +761,40 @@
TX_CL_CAL = BIT(2),
};
+/**
+ * reg_ops - describes one specific functionality of a particular register
+ *
+ * @name: name of the register as used in debugfs
+ * @address: memory address of the register
+ * @mask: mask for the specific functionality we are exposing. One single addresses
+ * may have multiple reg_ops, one for each mask/functionality.
+ * @description: human readable description of the functionality
+ */
+struct reg_ops {
+ const char *name;
+ unsigned int address;
+ unsigned int mask;
+ const char *description;
+};
+
+/**
+ * reg_ops_instance - describes a specific configuration of a reg_ops register
+ *
+ * @regops: the register functionality we are referencing
+ * @valueset: did the user write a custom value to this register?
+ * @value: the value the user wrote to the register
+ * @owner: the interface on which the custom value was set
+ *
+ * @next: pointer to next reg_ops_instance, to create linked lists
+ */
+struct reg_ops_instance {
+ struct reg_ops *regops;
+ char valueset;
+ unsigned int value;
+ struct ath9k_htc_priv *owner;
+ struct reg_ops_instance *next;
+};
+
/* ah_flags */
#define AH_USE_EEPROM 0x1
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
@@ -972,6 +1006,9 @@
struct ath_dynack dynack;
+ /** Linked list of (possibly) manually overwritten registers */
+ struct reg_ops_instance *modified_registers;
+
bool tpc_enabled;
u8 tx_power[Ar5416RateSize];
u8 tx_power_stbc[Ar5416RateSize];
@@ -1066,6 +1103,18 @@
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
+void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us);
+void ath9k_hw_setslottime(struct ath_hw *ah, u32 us);
+void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us);
+void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us);
+void ath9k_hw_set_eifs_timeout(struct ath_hw *ah, u32 us);
+
+u32 ath9k_hw_get_sifs_time(struct ath_hw *ah);
+u32 ath9k_hw_getslottime(struct ath_hw *ah);
+u32 ath9k_hw_get_ack_timeout(struct ath_hw *ah);
+u32 ath9k_hw_get_cts_timeout(struct ath_hw *ah);
+u32 ath9k_hw_get_eifs_timeout(struct ath_hw *ah);
+
/* Generic hw timer primitives */
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/Kconfig backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/Kconfig
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/Kconfig 2016-02-18 22:41:36.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/Kconfig 2016-04-03 13:28:55.000000000 +0200
@@ -167,6 +167,7 @@
select BPAUTO_LEDS_CLASS
select BPAUTO_NEW_LEDS
select ATH9K_COMMON
+ select ATH9K_HTC_DEBUGFS
---help---
Support for Atheros HTC based cards.
Chipsets supported: AR9271
@@ -177,6 +178,6 @@
config ATH9K_HTC_DEBUGFS
bool "Atheros ath9k_htc debugging"
- depends on ATH9K_HTC && DEBUG_FS
+ depends on DEBUG_FS
---help---
Say Y, if you need access to ath9k_htc's statistics.
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.c backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.c
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.c 2016-02-18 22:41:35.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.c 2016-04-03 13:28:54.000000000 +0200
@@ -83,6 +83,14 @@
return "WMI_RX_STATS_CMDID";
case WMI_BITRATE_MASK_CMDID:
return "WMI_BITRATE_MASK_CMDID";
+ case WMI_DEBUGMSG_CMDID:
+ return "WMI_DEBUGMSG_CMDID";
+ case WMI_REACTIVEJAM_CMDID:
+ return "WMI_REACTIVEJAM_CMDID";
+ case WMI_FASTREPLY_CMDID:
+ return "WMI_FASTREPLY_CMDID";
+ case WMI_CONSTANTJAM_CMDID:
+ return "WMI_CONSTANTJAM_CMDID";
}
return "Bogus";
diff -Naur backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.h backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.h
--- backports-4.4.2-1/drivers/net/wireless/ath/ath9k/wmi.h 2016-02-18 22:41:36.000000000 +0100
+++ backports-4.4.2-1-modwifi/drivers/net/wireless/ath/ath9k/wmi.h 2016-04-03 13:28:54.000000000 +0200
@@ -113,6 +113,12 @@
WMI_RX_STATS_CMDID,
WMI_BITRATE_MASK_CMDID,
WMI_REG_RMW_CMDID,
+
+ /* Custom commands added */
+ WMI_DEBUGMSG_CMDID = 0x0080,
+ WMI_REACTIVEJAM_CMDID,
+ WMI_FASTREPLY_CMDID,
+ WMI_CONSTANTJAM_CMDID,
};
enum wmi_event_id {
@@ -145,6 +151,65 @@
struct list_head list;
};
+struct wmi_debugmsg_cmd {
+ __be16 offset;
+} __packed;
+
+struct wmi_debugmsg_resp {
+ /** Length of zero signifies that no more data is available */
+ u8 length;
+ /** Debug message(s) **/
+ u8 buffer[40];
+} __packed;
+
+struct wmi_reactivejam_cmd {
+ u8 bssid[6];
+ u32 mduration;
+} __packed;
+
+struct wmi_constantjam_cmd {
+ /** A value from CONSTJAM_REQUEST to denote the request */
+ u8 request;
+ /** Set to 1 to disable CS and inter-frame-timeouts */
+ u8 conf_radio;
+ /** Length of the packet which is continuously transmitted */
+ u16 len;
+} __packed;
+
+struct wmi_constantjam_resp {
+ /** Is 1 when jammer is running, 0 otherwise */
+ u8 status;
+} __packed;
+
+enum CONSTJAM_REQUEST {
+ CONSTJAM_START,
+ CONSTJAM_STOP,
+ CONSTJAM_STATUS
+};
+
+struct wmi_fastreply_cmd {
+ u8 type;
+ union {
+ // transmit response packet in multiple commands
+ struct {
+ u8 length;
+ u8 offset;
+ u8 datalen;
+ u8 data[40];
+ } pkt;
+ // command to start monitoring
+ struct {
+ u32 mduration;
+ u8 source[6];
+ } start;
+ };
+} __packed;
+
+enum FASTREPLY_TYPE {
+ FASTREPLY_PKT,
+ FASTREPLY_START
+};
+
struct wmi {
struct ath9k_htc_priv *drv_priv;
struct htc_target *htc;