#include #include #include #include #include #include #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; struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, "# | ch | ss | bssid | cap | TSF | 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 | %03ld | " MAC_FMT " |", numscansdone, iter_bss->channel, iter_bss->rssi, MAC_ARG(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, " %08llx |", iter_bss->networktsf); pos += snprintf(buf+pos, len-pos, " %d |", 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 = strstr(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 = strstr(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 (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; idebugfs_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; idebugfs_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; idebugfs_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; idebugfs_regs_files[i]); debugfs_remove(priv->regs_dir); for(i=0; idebugfs_events_files[i]); debugfs_remove(priv->events_dir); #ifdef PROC_DEBUG debugfs_remove(priv->debugfs_debug); #endif for(i=0; idebugfs_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 = (char *)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