Logo Search packages:      
Sourcecode: linux version File versions  Download package

debugfs.c

#include <linux/module.h>
#include <linux/dcache.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <net/iw_handler.h>

#include "dev.h"
#include "decl.h"
#include "host.h"
#include "debugfs.h"

static struct dentry *libertas_dir = NULL;
static char *szStates[] = {
      "Connected",
      "Disconnected"
};

#ifdef PROC_DEBUG
static void libertas_debug_init(wlan_private * priv, struct net_device *dev);
#endif

static int open_file_generic(struct inode *inode, struct file *file)
{
      file->private_data = inode->i_private;
      return 0;
}

static ssize_t write_file_dummy(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
{
        return -EINVAL;
}

static const size_t len = PAGE_SIZE;

static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      size_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;
      ssize_t res;

      pos += snprintf(buf+pos, len-pos, "state = %s\n",
                        szStates[priv->adapter->connect_status]);
      pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
                        (u32) priv->adapter->regioncode);

      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);

      free_page(addr);
      return res;
}


static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      size_t pos = 0;
      int numscansdone = 0, res;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;
      DECLARE_MAC_BUF(mac);
      struct bss_descriptor * iter_bss;

      pos += snprintf(buf+pos, len-pos,
            "# | ch  | rssi |       bssid       |   cap    | Qual | SSID \n");

      mutex_lock(&priv->adapter->lock);
      list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
            u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
            u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
            u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);

            pos += snprintf(buf+pos, len-pos,
                  "%02u| %03d | %04ld | %s |",
                  numscansdone, iter_bss->channel, iter_bss->rssi,
                  print_mac(mac, iter_bss->bssid));
            pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
            pos += snprintf(buf+pos, len-pos, "%c%c%c |",
                        ibss ? 'A' : 'I', privacy ? 'P' : ' ',
                        spectrum_mgmt ? 'S' : ' ');
            pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
            pos += snprintf(buf+pos, len-pos, " %s\n",
                            escape_essid(iter_bss->ssid, iter_bss->ssid_len));

            numscansdone++;
      }
      mutex_unlock(&priv->adapter->lock);

      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);

      free_page(addr);
      return res;
}

static ssize_t libertas_sleepparams_write(struct file *file,
                        const char __user *user_buf, size_t count,
                        loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      ssize_t buf_size, res;
      int p1, p2, p3, p4, p5, p6;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, user_buf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
      if (res != 6) {
            res = -EFAULT;
            goto out_unlock;
      }
      priv->adapter->sp.sp_error = p1;
      priv->adapter->sp.sp_offset = p2;
      priv->adapter->sp.sp_stabletime = p3;
      priv->adapter->sp.sp_calcontrol = p4;
      priv->adapter->sp.sp_extsleepclk = p5;
      priv->adapter->sp.sp_reserved = p6;

        res = libertas_prepare_and_send_command(priv,
                        CMD_802_11_SLEEP_PARAMS,
                        CMD_ACT_SET,
                        CMD_OPTION_WAITFORRSP, 0, NULL);

      if (!res)
            res = count;
      else
            res = -EINVAL;

out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      ssize_t res;
      size_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

        res = libertas_prepare_and_send_command(priv,
                        CMD_802_11_SLEEP_PARAMS,
                        CMD_ACT_GET,
                        CMD_OPTION_WAITFORRSP, 0, NULL);
      if (res) {
            res = -EFAULT;
            goto out_unlock;
      }

      pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
                  adapter->sp.sp_offset, adapter->sp.sp_stabletime,
                  adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
                  adapter->sp.sp_reserved);

      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);

out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      union iwreq_data wrqu;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }

      libertas_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);

      memset(&wrqu, 0, sizeof(union iwreq_data));
      wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);

out_unlock:
      free_page(addr);
      return count;
}

static int libertas_parse_chan(char *buf, size_t count,
                  struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
{
      char *start, *end, *hold, *str;
      int i = 0;

      start = strstr(buf, "chan=");
      if (!start)
            return -EINVAL;
      start += 5;
      end = strchr(start, ' ');
      if (!end)
            end = buf + count;
      hold = kzalloc((end - start)+1, GFP_KERNEL);
      if (!hold)
            return -ENOMEM;
      strncpy(hold, start, end - start);
      hold[(end-start)+1] = '\0';
      while(hold && (str = strsep(&hold, ","))) {
            int chan;
            char band, passive = 0;
            sscanf(str, "%d%c%c", &chan, &band, &passive);
            scan_cfg->chanlist[i].channumber = chan;
            scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
            if (band == 'b' || band == 'g')
                  scan_cfg->chanlist[i].radiotype = 0;
            else if (band == 'a')
                  scan_cfg->chanlist[i].radiotype = 1;

            scan_cfg->chanlist[i].scantime = dur;
            i++;
      }

      kfree(hold);
      return i;
}

static void libertas_parse_bssid(char *buf, size_t count,
                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
{
      char *hold;
      unsigned int mac[ETH_ALEN];

      hold = strstr(buf, "bssid=");
      if (!hold)
            return;
      hold += 6;
      sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
      memcpy(scan_cfg->bssid, mac, ETH_ALEN);
}

static void libertas_parse_ssid(char *buf, size_t count,
                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
{
      char *hold, *end;
      ssize_t size;

      hold = strstr(buf, "ssid=");
      if (!hold)
            return;
      hold += 5;
      end = strchr(hold, ' ');
      if (!end)
            end = buf + count - 1;

      size = min((size_t)IW_ESSID_MAX_SIZE, (size_t) (end - hold));
      strncpy(scan_cfg->ssid, hold, size);

      return;
}

static int libertas_parse_clear(char *buf, size_t count, const char *tag)
{
      char *hold;
      int val;

      hold = strstr(buf, tag);
      if (!hold)
            return 0;
      hold += strlen(tag);
      sscanf(hold, "%d", &val);

      if (val != 0)
            val = 1;

      return val;
}

static int libertas_parse_dur(char *buf, size_t count,
                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
{
      char *hold;
      int val;

      hold = strstr(buf, "dur=");
      if (!hold)
            return 0;
      hold += 4;
      sscanf(hold, "%d", &val);

      return val;
}

static void libertas_parse_probes(char *buf, size_t count,
                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
{
      char *hold;
      int val;

      hold = strstr(buf, "probes=");
      if (!hold)
            return;
      hold += 7;
      sscanf(hold, "%d", &val);

      scan_cfg->numprobes = val;

      return;
}

static void libertas_parse_type(char *buf, size_t count,
                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
{
      char *hold;
      int val;

      hold = strstr(buf, "type=");
      if (!hold)
            return;
      hold += 5;
      sscanf(hold, "%d", &val);

      /* type=1,2 or 3 */
      if (val < 1 || val > 3)
            return;

      scan_cfg->bsstype = val;

      return;
}

static ssize_t libertas_setuserscan(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      struct wlan_ioctl_user_scan_cfg *scan_cfg;
      union iwreq_data wrqu;
      int dur;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
      if (!scan_cfg)
            return -ENOMEM;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }

      scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;

      dur = libertas_parse_dur(buf, count, scan_cfg);
      libertas_parse_chan(buf, count, scan_cfg, dur);
      libertas_parse_bssid(buf, count, scan_cfg);
      scan_cfg->clear_bssid = libertas_parse_clear(buf, count, "clear_bssid=");
      libertas_parse_ssid(buf, count, scan_cfg);
      scan_cfg->clear_ssid = libertas_parse_clear(buf, count, "clear_ssid=");
      libertas_parse_probes(buf, count, scan_cfg);
      libertas_parse_type(buf, count, scan_cfg);

      wlan_scan_networks(priv, scan_cfg, 1);
      wait_event_interruptible(priv->adapter->cmd_pending,
                         !priv->adapter->nr_cmd_pending);

      memset(&wrqu, 0x00, sizeof(union iwreq_data));
      wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);

out_unlock:
      free_page(addr);
      kfree(scan_cfg);
      return count;
}

static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
                  struct cmd_ctrl_node **cmdnode,
                  struct cmd_ds_command **cmd)
{
      u16 wait_option = CMD_OPTION_WAITFORRSP;

      if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
            lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
            return -ENOMEM;
      }
      if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
            lbs_deb_debugfs("failed to allocate response buffer!\n");
            return -ENOMEM;
      }
      libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
      init_waitqueue_head(&(*cmdnode)->cmdwait_q);
      (*cmdnode)->pdata_buf = *response_buf;
      (*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
      (*cmdnode)->cmdwaitqwoken = 0;
      *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
      (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT);
      (*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
      (*cmd)->result = 0;
      return 0;
}

static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      void *response_buf;
      int res, cmd_len;
      ssize_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0) {
            free_page(addr);
            return res;
      }

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_GET);
      pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;
      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      event = (void *)(response_buf + S_DS_GEN);
      while (cmd_len < le16_to_cpu(pcmdptr->size)) {
            struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
            switch (header->type) {
            struct mrvlietypes_rssithreshold  *Lowrssi;
            case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW):
                  Lowrssi = (void *)(response_buf + cmd_len);
                  pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
                              Lowrssi->rssivalue,
                              Lowrssi->rssifreq,
                              (event->events & cpu_to_le16(0x0001))?1:0);
            default:
                  cmd_len += sizeof(struct mrvlietypes_snrthreshold);
                  break;
            }
      }

      kfree(response_buf);
      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);
      return res;
}

static u16 libertas_get_events_bitmap(wlan_private *priv)
{
      wlan_adapter *adapter = priv->adapter;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      void *response_buf;
      int res;
      u16 event_bitmap;

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0)
            return res;

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_GET);
      pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            return 0;
      }

      if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            return 0;
      }

      event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
      event_bitmap = le16_to_cpu(event->events);
      kfree(response_buf);
      return event_bitmap;
}

static ssize_t libertas_lowrssi_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      ssize_t res, buf_size;
      int value, freq, subscribed, cmd_len;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      struct mrvlietypes_rssithreshold *rssi_threshold;
      void *response_buf;
      u16 event_bitmap;
      u8 *ptr;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
      if (res != 3) {
            res = -EFAULT;
            goto out_unlock;
      }

      event_bitmap = libertas_get_events_bitmap(priv);

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0)
            goto out_unlock;

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_SET);
      pcmdptr->size = cpu_to_le16(S_DS_GEN +
            sizeof(struct cmd_ds_802_11_subscribe_event) +
            sizeof(struct mrvlietypes_rssithreshold));

      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      ptr = (u8*) pcmdptr+cmd_len;
      rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
      rssi_threshold->header.type = cpu_to_le16(0x0104);
      rssi_threshold->header.len = cpu_to_le16(2);
      rssi_threshold->rssivalue = value;
      rssi_threshold->rssifreq = freq;
      event_bitmap |= subscribed ? 0x0001 : 0x0;
      event->events = cpu_to_le16(event_bitmap);

      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      void *response_buf;
      int res, cmd_len;
      ssize_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0) {
            free_page(addr);
            return res;
      }

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_GET);
      pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      event = (void *)(response_buf + S_DS_GEN);
      while (cmd_len < le16_to_cpu(pcmdptr->size)) {
            struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
            switch (header->type) {
            struct mrvlietypes_snrthreshold *LowSnr;
            case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW):
                  LowSnr = (void *)(response_buf + cmd_len);
                  pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
                              LowSnr->snrvalue,
                              LowSnr->snrfreq,
                              (event->events & cpu_to_le16(0x0002))?1:0);
            default:
                  cmd_len += sizeof(struct mrvlietypes_snrthreshold);
                  break;
            }
      }

      kfree(response_buf);

      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);
      return res;
}

static ssize_t libertas_lowsnr_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      ssize_t res, buf_size;
      int value, freq, subscribed, cmd_len;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      struct mrvlietypes_snrthreshold *snr_threshold;
      void *response_buf;
      u16 event_bitmap;
      u8 *ptr;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
      if (res != 3) {
            res = -EFAULT;
            goto out_unlock;
      }

      event_bitmap = libertas_get_events_bitmap(priv);

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0)
            goto out_unlock;

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_SET);
      pcmdptr->size = cpu_to_le16(S_DS_GEN +
            sizeof(struct cmd_ds_802_11_subscribe_event) +
            sizeof(struct mrvlietypes_snrthreshold));
      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      ptr = (u8*) pcmdptr+cmd_len;
      snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
      snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
      snr_threshold->header.len = cpu_to_le16(2);
      snr_threshold->snrvalue = value;
      snr_threshold->snrfreq = freq;
      event_bitmap |= subscribed ? 0x0002 : 0x0;
      event->events = cpu_to_le16(event_bitmap);

      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      res = count;

out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      void *response_buf;
      int res, cmd_len;
      ssize_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0) {
            free_page(addr);
            return res;
      }

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_GET);
      pcmdptr->size =   cpu_to_le16(sizeof(*event) + S_DS_GEN);
      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      event = (void *)(response_buf + S_DS_GEN);
      while (cmd_len < le16_to_cpu(pcmdptr->size)) {
            struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
            switch (header->type) {
            struct mrvlietypes_failurecount *failcount;
            case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT):
                  failcount = (void *)(response_buf + cmd_len);
                  pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
                              failcount->failvalue,
                              failcount->Failfreq,
                              (event->events & cpu_to_le16(0x0004))?1:0);
            default:
                  cmd_len += sizeof(struct mrvlietypes_failurecount);
                  break;
            }
      }

      kfree(response_buf);
      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);
      return res;
}

static ssize_t libertas_failcount_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      ssize_t res, buf_size;
      int value, freq, subscribed, cmd_len;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      struct mrvlietypes_failurecount *failcount;
      void *response_buf;
      u16 event_bitmap;
      u8 *ptr;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
      if (res != 3) {
            res = -EFAULT;
            goto out_unlock;
      }

      event_bitmap = libertas_get_events_bitmap(priv);

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0)
            goto out_unlock;

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_SET);
      pcmdptr->size = cpu_to_le16(S_DS_GEN +
            sizeof(struct cmd_ds_802_11_subscribe_event) +
            sizeof(struct mrvlietypes_failurecount));
      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      ptr = (u8*) pcmdptr+cmd_len;
      failcount = (struct mrvlietypes_failurecount *)(ptr);
      failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
      failcount->header.len = cpu_to_le16(2);
      failcount->failvalue = value;
      failcount->Failfreq = freq;
      event_bitmap |= subscribed ? 0x0004 : 0x0;
      event->events = cpu_to_le16(event_bitmap);

      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = (struct cmd_ds_command *)response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      void *response_buf;
      int res, cmd_len;
      ssize_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0) {
            free_page(addr);
            return res;
      }

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_GET);
      pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            free_page(addr);
            kfree(response_buf);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            free_page(addr);
            kfree(response_buf);
            return 0;
      }

      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      event = (void *)(response_buf + S_DS_GEN);
      while (cmd_len < le16_to_cpu(pcmdptr->size)) {
            struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
            switch (header->type) {
            struct mrvlietypes_beaconsmissed *bcnmiss;
            case __constant_cpu_to_le16(TLV_TYPE_BCNMISS):
                  bcnmiss = (void *)(response_buf + cmd_len);
                  pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
                              bcnmiss->beaconmissed,
                              (event->events & cpu_to_le16(0x0008))?1:0);
            default:
                  cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
                  break;
            }
      }

      kfree(response_buf);

      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);
      return res;
}

static ssize_t libertas_bcnmiss_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      ssize_t res, buf_size;
      int value, freq, subscribed, cmd_len;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      struct mrvlietypes_beaconsmissed *bcnmiss;
      void *response_buf;
      u16 event_bitmap;
      u8 *ptr;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
      if (res != 3) {
            res = -EFAULT;
            goto out_unlock;
      }

      event_bitmap = libertas_get_events_bitmap(priv);

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0)
            goto out_unlock;

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_SET);
      pcmdptr->size = cpu_to_le16(S_DS_GEN +
            sizeof(struct cmd_ds_802_11_subscribe_event) +
            sizeof(struct mrvlietypes_beaconsmissed));
      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      ptr = (u8*) pcmdptr+cmd_len;
      bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
      bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
      bcnmiss->header.len = cpu_to_le16(2);
      bcnmiss->beaconmissed = value;
      event_bitmap |= subscribed ? 0x0008 : 0x0;
      event->events = cpu_to_le16(event_bitmap);

      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            free_page(addr);
            kfree(response_buf);
            return 0;
      }

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      void *response_buf;
      int res, cmd_len;
      ssize_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0) {
            free_page(addr);
            return res;
      }

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_GET);
      pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      event = (void *)(response_buf + S_DS_GEN);
      while (cmd_len < le16_to_cpu(pcmdptr->size)) {
            struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
            switch (header->type) {
            struct mrvlietypes_rssithreshold  *Highrssi;
            case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH):
                  Highrssi = (void *)(response_buf + cmd_len);
                  pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
                              Highrssi->rssivalue,
                              Highrssi->rssifreq,
                              (event->events & cpu_to_le16(0x0010))?1:0);
            default:
                  cmd_len += sizeof(struct mrvlietypes_snrthreshold);
                  break;
            }
      }

      kfree(response_buf);

      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);
      return res;
}

static ssize_t libertas_highrssi_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      ssize_t res, buf_size;
      int value, freq, subscribed, cmd_len;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      struct mrvlietypes_rssithreshold *rssi_threshold;
      void *response_buf;
      u16 event_bitmap;
      u8 *ptr;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
      if (res != 3) {
            res = -EFAULT;
            goto out_unlock;
      }

      event_bitmap = libertas_get_events_bitmap(priv);

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0)
            goto out_unlock;

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_SET);
      pcmdptr->size = cpu_to_le16(S_DS_GEN +
            sizeof(struct cmd_ds_802_11_subscribe_event) +
            sizeof(struct mrvlietypes_rssithreshold));
      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      ptr = (u8*) pcmdptr+cmd_len;
      rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
      rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
      rssi_threshold->header.len = cpu_to_le16(2);
      rssi_threshold->rssivalue = value;
      rssi_threshold->rssifreq = freq;
      event_bitmap |= subscribed ? 0x0010 : 0x0;
      event->events = cpu_to_le16(event_bitmap);

      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            return 0;
      }

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      void *response_buf;
      int res, cmd_len;
      ssize_t pos = 0;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0) {
            free_page(addr);
            return res;
      }

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_GET);
      pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      event = (void *)(response_buf + S_DS_GEN);
      while (cmd_len < le16_to_cpu(pcmdptr->size)) {
            struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
            switch (header->type) {
            struct mrvlietypes_snrthreshold *HighSnr;
            case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH):
                  HighSnr = (void *)(response_buf + cmd_len);
                  pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
                              HighSnr->snrvalue,
                              HighSnr->snrfreq,
                              (event->events & cpu_to_le16(0x0020))?1:0);
            default:
                  cmd_len += sizeof(struct mrvlietypes_snrthreshold);
                  break;
            }
      }

      kfree(response_buf);

      res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);
      return res;
}

static ssize_t libertas_highsnr_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      ssize_t res, buf_size;
      int value, freq, subscribed, cmd_len;
      struct cmd_ctrl_node *pcmdnode;
      struct cmd_ds_command *pcmdptr;
      struct cmd_ds_802_11_subscribe_event *event;
      struct mrvlietypes_snrthreshold *snr_threshold;
      void *response_buf;
      u16 event_bitmap;
      u8 *ptr;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
      if (res != 3) {
            res = -EFAULT;
            goto out_unlock;
      }

      event_bitmap = libertas_get_events_bitmap(priv);

      res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
      if (res < 0)
            goto out_unlock;

      event = &pcmdptr->params.subscribe_event;
      event->action = cpu_to_le16(CMD_ACT_SET);
      pcmdptr->size = cpu_to_le16(S_DS_GEN +
            sizeof(struct cmd_ds_802_11_subscribe_event) +
            sizeof(struct mrvlietypes_snrthreshold));
      cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
      ptr = (u8*) pcmdptr+cmd_len;
      snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
      snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
      snr_threshold->header.len = cpu_to_le16(2);
      snr_threshold->snrvalue = value;
      snr_threshold->snrfreq = freq;
      event_bitmap |= subscribed ? 0x0020 : 0x0;
      event->events = cpu_to_le16(event_bitmap);

      libertas_queue_cmd(adapter, pcmdnode, 1);
      wake_up_interruptible(&priv->waitq);

      /* Sleep until response is generated by FW */
      wait_event_interruptible(pcmdnode->cmdwait_q,
                         pcmdnode->cmdwaitqwoken);

      pcmdptr = response_buf;

      if (pcmdptr->result) {
            lbs_pr_err("%s: fail, result=%d\n", __func__,
                     le16_to_cpu(pcmdptr->result));
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
            lbs_pr_err("command response incorrect!\n");
            kfree(response_buf);
            free_page(addr);
            return 0;
      }

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct wlan_offset_value offval;
      ssize_t pos = 0;
      int ret;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      offval.offset = priv->mac_offset;
      offval.value = 0;

      ret = libertas_prepare_and_send_command(priv,
                        CMD_MAC_REG_ACCESS, 0,
                        CMD_OPTION_WAITFORRSP, 0, &offval);
      mdelay(10);
      pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
                        priv->mac_offset, adapter->offsetvalue.value);

      ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);
      return ret;
}

static ssize_t libertas_rdmac_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_wrmac_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{

      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      u32 offset, value;
      struct wlan_offset_value offval;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%x %x", &offset, &value);
      if (res != 2) {
            res = -EFAULT;
            goto out_unlock;
      }

      offval.offset = offset;
      offval.value = value;
      res = libertas_prepare_and_send_command(priv,
                        CMD_MAC_REG_ACCESS, 1,
                        CMD_OPTION_WAITFORRSP, 0, &offval);
      mdelay(10);

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct wlan_offset_value offval;
      ssize_t pos = 0;
      int ret;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      offval.offset = priv->bbp_offset;
      offval.value = 0;

      ret = libertas_prepare_and_send_command(priv,
                        CMD_BBP_REG_ACCESS, 0,
                        CMD_OPTION_WAITFORRSP, 0, &offval);
      mdelay(10);
      pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
                        priv->bbp_offset, adapter->offsetvalue.value);

      ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);

      return ret;
}

static ssize_t libertas_rdbbp_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_wrbbp_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{

      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      u32 offset, value;
      struct wlan_offset_value offval;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%x %x", &offset, &value);
      if (res != 2) {
            res = -EFAULT;
            goto out_unlock;
      }

      offval.offset = offset;
      offval.value = value;
      res = libertas_prepare_and_send_command(priv,
                        CMD_BBP_REG_ACCESS, 1,
                        CMD_OPTION_WAITFORRSP, 0, &offval);
      mdelay(10);

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
                          size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      wlan_adapter *adapter = priv->adapter;
      struct wlan_offset_value offval;
      ssize_t pos = 0;
      int ret;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      offval.offset = priv->rf_offset;
      offval.value = 0;

      ret = libertas_prepare_and_send_command(priv,
                        CMD_RF_REG_ACCESS, 0,
                        CMD_OPTION_WAITFORRSP, 0, &offval);
      mdelay(10);
      pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
                        priv->rf_offset, adapter->offsetvalue.value);

      ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
      free_page(addr);

      return ret;
}

static ssize_t libertas_rdrf_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{
      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
      res = count;
out_unlock:
      free_page(addr);
      return res;
}

static ssize_t libertas_wrrf_write(struct file *file,
                            const char __user *userbuf,
                            size_t count, loff_t *ppos)
{

      wlan_private *priv = file->private_data;
      ssize_t res, buf_size;
      u32 offset, value;
      struct wlan_offset_value offval;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      buf_size = min(count, len - 1);
      if (copy_from_user(buf, userbuf, buf_size)) {
            res = -EFAULT;
            goto out_unlock;
      }
      res = sscanf(buf, "%x %x", &offset, &value);
      if (res != 2) {
            res = -EFAULT;
            goto out_unlock;
      }

      offval.offset = offset;
      offval.value = value;
      res = libertas_prepare_and_send_command(priv,
                        CMD_RF_REG_ACCESS, 1,
                        CMD_OPTION_WAITFORRSP, 0, &offval);
      mdelay(10);

      res = count;
out_unlock:
      free_page(addr);
      return res;
}

#define FOPS(fread, fwrite) { \
      .owner = THIS_MODULE, \
      .open = open_file_generic, \
      .read = (fread), \
      .write = (fwrite), \
}

struct libertas_debugfs_files {
      char *name;
      int perm;
      struct file_operations fops;
};

static struct libertas_debugfs_files debugfs_files[] = {
      { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
      { "getscantable", 0444, FOPS(libertas_getscantable,
                              write_file_dummy), },
      { "sleepparams", 0644, FOPS(libertas_sleepparams_read,
                        libertas_sleepparams_write), },
      { "extscan", 0600, FOPS(NULL, libertas_extscan), },
      { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
};

static struct libertas_debugfs_files debugfs_events_files[] = {
      {"low_rssi", 0644, FOPS(libertas_lowrssi_read,
                        libertas_lowrssi_write), },
      {"low_snr", 0644, FOPS(libertas_lowsnr_read,
                        libertas_lowsnr_write), },
      {"failure_count", 0644, FOPS(libertas_failcount_read,
                        libertas_failcount_write), },
      {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
                        libertas_bcnmiss_write), },
      {"high_rssi", 0644, FOPS(libertas_highrssi_read,
                        libertas_highrssi_write), },
      {"high_snr", 0644, FOPS(libertas_highsnr_read,
                        libertas_highsnr_write), },
};

static struct libertas_debugfs_files debugfs_regs_files[] = {
      {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
      {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
      {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
      {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
      {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
      {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
};

void libertas_debugfs_init(void)
{
      if (!libertas_dir)
            libertas_dir = debugfs_create_dir("libertas_wireless", NULL);

      return;
}

void libertas_debugfs_remove(void)
{
      if (libertas_dir)
             debugfs_remove(libertas_dir);
      return;
}

void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
{
      int i;
      struct libertas_debugfs_files *files;
      if (!libertas_dir)
            goto exit;

      priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
      if (!priv->debugfs_dir)
            goto exit;

      for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
            files = &debugfs_files[i];
            priv->debugfs_files[i] = debugfs_create_file(files->name,
                                               files->perm,
                                               priv->debugfs_dir,
                                               priv,
                                               &files->fops);
      }

      priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
      if (!priv->events_dir)
            goto exit;

      for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
            files = &debugfs_events_files[i];
            priv->debugfs_events_files[i] = debugfs_create_file(files->name,
                                               files->perm,
                                               priv->events_dir,
                                               priv,
                                               &files->fops);
      }

      priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
      if (!priv->regs_dir)
            goto exit;

      for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
            files = &debugfs_regs_files[i];
            priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
                                               files->perm,
                                               priv->regs_dir,
                                               priv,
                                               &files->fops);
      }

#ifdef PROC_DEBUG
      libertas_debug_init(priv, dev);
#endif
exit:
      return;
}

void libertas_debugfs_remove_one(wlan_private *priv)
{
      int i;

      for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
            debugfs_remove(priv->debugfs_regs_files[i]);

      debugfs_remove(priv->regs_dir);

      for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
            debugfs_remove(priv->debugfs_events_files[i]);

      debugfs_remove(priv->events_dir);
#ifdef PROC_DEBUG
      debugfs_remove(priv->debugfs_debug);
#endif
      for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
            debugfs_remove(priv->debugfs_files[i]);
      debugfs_remove(priv->debugfs_dir);
}



/* debug entry */

#ifdef PROC_DEBUG

#define item_size(n)    (FIELD_SIZEOF(wlan_adapter, n))
#define item_addr(n)    (offsetof(wlan_adapter, n))


struct debug_data {
      char name[32];
      u32 size;
      size_t addr;
};

/* To debug any member of wlan_adapter, simply add one line here.
 */
static struct debug_data items[] = {
      {"intcounter", item_size(intcounter), item_addr(intcounter)},
      {"psmode", item_size(psmode), item_addr(psmode)},
      {"psstate", item_size(psstate), item_addr(psstate)},
};

static int num_of_items = ARRAY_SIZE(items);

/**
 *  @brief proc read function
 *
 *  @param page      pointer to buffer
 *  @param s       read data starting position
 *  @param off     offset
 *  @param cnt     counter
 *  @param eof     end of file flag
 *  @param data    data to output
 *  @return          number of output data
 */
static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
                  size_t count, loff_t *ppos)
{
      int val = 0;
      size_t pos = 0;
      ssize_t res;
      char *p;
      int i;
      struct debug_data *d;
      unsigned long addr = get_zeroed_page(GFP_KERNEL);
      char *buf = (char *)addr;

      p = buf;

      d = (struct debug_data *)file->private_data;

      for (i = 0; i < num_of_items; i++) {
            if (d[i].size == 1)
                  val = *((u8 *) d[i].addr);
            else if (d[i].size == 2)
                  val = *((u16 *) d[i].addr);
            else if (d[i].size == 4)
                  val = *((u32 *) d[i].addr);
            else if (d[i].size == 8)
                  val = *((u64 *) d[i].addr);

            pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
      }

      res = simple_read_from_buffer(userbuf, count, ppos, p, pos);

      free_page(addr);
      return res;
}

/**
 *  @brief proc write function
 *
 *  @param f         file pointer
 *  @param buf     pointer to data buffer
 *  @param cnt     data number to write
 *  @param data    data to write
 *  @return          number of data
 */
static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
                      size_t cnt, loff_t *ppos)
{
      int r, i;
      char *pdata;
      char *p;
      char *p0;
      char *p1;
      char *p2;
      struct debug_data *d = (struct debug_data *)f->private_data;

      pdata = kmalloc(cnt, GFP_KERNEL);
      if (pdata == NULL)
            return 0;

      if (copy_from_user(pdata, buf, cnt)) {
            lbs_deb_debugfs("Copy from user failed\n");
            kfree(pdata);
            return 0;
      }

      p0 = pdata;
      for (i = 0; i < num_of_items; i++) {
            do {
                  p = strstr(p0, d[i].name);
                  if (p == NULL)
                        break;
                  p1 = strchr(p, '\n');
                  if (p1 == NULL)
                        break;
                  p0 = p1++;
                  p2 = strchr(p, '=');
                  if (!p2)
                        break;
                  p2++;
                  r = simple_strtoul(p2, NULL, 0);
                  if (d[i].size == 1)
                        *((u8 *) d[i].addr) = (u8) r;
                  else if (d[i].size == 2)
                        *((u16 *) d[i].addr) = (u16) r;
                  else if (d[i].size == 4)
                        *((u32 *) d[i].addr) = (u32) r;
                  else if (d[i].size == 8)
                        *((u64 *) d[i].addr) = (u64) r;
                  break;
            } while (1);
      }
      kfree(pdata);

      return (ssize_t)cnt;
}

static struct file_operations libertas_debug_fops = {
      .owner = THIS_MODULE,
      .open = open_file_generic,
      .write = wlan_debugfs_write,
      .read = wlan_debugfs_read,
};

/**
 *  @brief create debug proc file
 *
 *  @param priv      pointer wlan_private
 *  @param dev     pointer net_device
 *  @return          N/A
 */
static void libertas_debug_init(wlan_private * priv, struct net_device *dev)
{
      int i;

      if (!priv->debugfs_dir)
            return;

      for (i = 0; i < num_of_items; i++)
            items[i].addr += (size_t) priv->adapter;

      priv->debugfs_debug = debugfs_create_file("debug", 0644,
                                      priv->debugfs_dir, &items[0],
                                      &libertas_debug_fops);
}
#endif


Generated by  Doxygen 1.6.0   Back to index