2511 lines
65 KiB
C
Executable File
2511 lines
65 KiB
C
Executable File
/*
|
|
* Copyright (c) 2022, Fuzhou Rockchip Electronics Co., Ltd
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
/*Linux version 3.4.0 compilation*/
|
|
//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0))
|
|
#include<linux/module.h>
|
|
//#endif
|
|
#include <linux/debugfs.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/ieee80211.h>
|
|
#include "rk960.h"
|
|
#include "debug.h"
|
|
#include "scan.h"
|
|
|
|
int rk960_debug_flag =
|
|
DEBUG_BH |
|
|
DEBUG_IO |
|
|
DEBUG_FW |
|
|
DEBUG_MAIN |
|
|
DEBUG_PM |
|
|
DEBUG_QUEUE |
|
|
DEBUG_SCAN |
|
|
DEBUG_STA |
|
|
DEBUG_TXRX |
|
|
DEBUG_WSM |
|
|
DEBUG_AP |
|
|
DEBUG_TXPOLICY |
|
|
DEBUG_FW_REC;
|
|
|
|
static int debug_level =
|
|
DEBUG_LEVEL_ERROR;
|
|
module_param(debug_level, int, 0644);
|
|
MODULE_PARM_DESC(debug_level, "debug level");
|
|
|
|
static int max_payload = 2304;
|
|
module_param(max_payload, int, 0644);
|
|
MODULE_PARM_DESC(max_payload, "max payload size");
|
|
|
|
int rk960_debug_level;
|
|
|
|
void rk960_debug_level_init(void)
|
|
{
|
|
rk960_debug_level = debug_level;
|
|
//pr_info("%s: rk960_debug_level %d\n", __func__, rk960_debug_level);
|
|
}
|
|
|
|
#define MAX_WRITE_STR_LEN 128
|
|
|
|
/* join_status */
|
|
static const char *const rk960_debug_join_status[] = {
|
|
"passive",
|
|
"monitor",
|
|
"station",
|
|
"access point",
|
|
};
|
|
|
|
/* WSM_JOIN_PREAMBLE_... */
|
|
static const char *const rk960_debug_preamble[] = {
|
|
"long",
|
|
"short",
|
|
"long on 1 and 2 Mbps",
|
|
};
|
|
|
|
static const char *const rk960_debug_fw_types[] = {
|
|
"ETF",
|
|
"WFM",
|
|
"WSM",
|
|
"HI test",
|
|
"Platform test",
|
|
};
|
|
|
|
static const char *const rk960_debug_link_id[] = {
|
|
"OFF",
|
|
"REQ",
|
|
"SOFT",
|
|
"HARD",
|
|
};
|
|
|
|
int rk960_rate_to_rate_index(int rate)
|
|
{
|
|
int rate_index = -EINVAL;
|
|
|
|
switch (rate) {
|
|
case 10:
|
|
rate_index = 0;
|
|
break;
|
|
case 20:
|
|
rate_index = 1;
|
|
break;
|
|
case 55:
|
|
rate_index = 2;
|
|
break;
|
|
case 110:
|
|
rate_index = 3;
|
|
break;
|
|
case 60:
|
|
rate_index = 6;
|
|
break;
|
|
case 90:
|
|
rate_index = 7;
|
|
break;
|
|
case 120:
|
|
rate_index = 8;
|
|
break;
|
|
case 180:
|
|
rate_index = 9;
|
|
break;
|
|
case 240:
|
|
rate_index = 10;
|
|
break;
|
|
case 360:
|
|
rate_index = 11;
|
|
break;
|
|
case 480:
|
|
rate_index = 12;
|
|
break;
|
|
case 540:
|
|
rate_index = 13;
|
|
break;
|
|
case 65:
|
|
rate_index = 14;
|
|
break;
|
|
case 130:
|
|
rate_index = 15;
|
|
break;
|
|
case 195:
|
|
rate_index = 16;
|
|
break;
|
|
case 260:
|
|
rate_index = 17;
|
|
break;
|
|
case 390:
|
|
rate_index = 18;
|
|
break;
|
|
case 520:
|
|
rate_index = 19;
|
|
break;
|
|
case 585:
|
|
rate_index = 20;
|
|
break;
|
|
case 650:
|
|
rate_index = 21;
|
|
break;
|
|
default:
|
|
//RK960_ERROR_IO("invalid rate %d\n", rate);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return rate_index;
|
|
}
|
|
|
|
static const char *rk960_debug_mode(int mode)
|
|
{
|
|
switch (mode) {
|
|
case NL80211_IFTYPE_UNSPECIFIED:
|
|
return "unspecified";
|
|
case NL80211_IFTYPE_MONITOR:
|
|
return "monitor";
|
|
case NL80211_IFTYPE_STATION:
|
|
return "station";
|
|
case NL80211_IFTYPE_ADHOC:
|
|
return "ad-hok";
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
return "mesh point";
|
|
case NL80211_IFTYPE_AP:
|
|
return "access point";
|
|
case NL80211_IFTYPE_P2P_CLIENT:
|
|
return "p2p client";
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
return "p2p go";
|
|
default:
|
|
return "unsupported";
|
|
}
|
|
}
|
|
|
|
static void rk960_queue_status_show(struct seq_file *seq, struct rk960_queue *q)
|
|
{
|
|
int i, if_id;
|
|
seq_printf(seq, "Queue %d:\n", q->queue_id);
|
|
seq_printf(seq, " capacity: %d\n", (int)q->capacity);
|
|
seq_printf(seq, " queued: %d\n", (int)q->num_queued);
|
|
seq_printf(seq, " pending: %d\n", (int)q->num_pending);
|
|
seq_printf(seq, " sent: %d\n", (int)q->num_sent);
|
|
seq_printf(seq, " locked: %s\n", q->tx_locked_cnt ? "yes" : "no");
|
|
seq_printf(seq, " overfull: %s\n", q->overfull ? "yes" : "no");
|
|
seq_puts(seq, " link map: 0-> ");
|
|
for (if_id = 0; if_id < RK960_MAX_VIFS; if_id++) {
|
|
for (i = 0; i < q->stats->map_capacity; ++i)
|
|
seq_printf(seq, "%.2d ", q->link_map_cache[if_id][i]);
|
|
seq_printf(seq, "<-%d\n", (int)q->stats->map_capacity);
|
|
}
|
|
}
|
|
|
|
static void rk960_debug_print_map(struct seq_file *seq,
|
|
struct rk960_vif *priv,
|
|
const char *label, u32 map)
|
|
{
|
|
int i;
|
|
seq_printf(seq, "%s0-> ", label);
|
|
for (i = 0; i < priv->hw_priv->tx_queue_stats.map_capacity; ++i)
|
|
seq_printf(seq, "%s ", (map & BIT(i)) ? "**" : "..");
|
|
seq_printf(seq, "<-%d\n",
|
|
(int)priv->hw_priv->tx_queue_stats.map_capacity - 1);
|
|
}
|
|
|
|
static int rk960_status_show_common(struct seq_file *seq, void *v)
|
|
{
|
|
int i;
|
|
struct list_head *item;
|
|
struct rk960_common *hw_priv = seq->private;
|
|
struct rk960_debug_common *d = hw_priv->debug;
|
|
int ba_cnt, ba_acc, ba_cnt_rx, ba_acc_rx, ba_avg = 0, ba_avg_rx = 0;
|
|
bool ba_ena;
|
|
#ifdef RK960_CSYNC_ADJUST
|
|
struct rk960_vif *priv;
|
|
struct csync_params *csync = &hw_priv->csync_params;
|
|
#endif
|
|
spin_lock_bh(&hw_priv->ba_lock);
|
|
ba_cnt = hw_priv->debug->ba_cnt;
|
|
ba_acc = hw_priv->debug->ba_acc;
|
|
ba_cnt_rx = hw_priv->debug->ba_cnt_rx;
|
|
ba_acc_rx = hw_priv->debug->ba_acc_rx;
|
|
ba_ena = hw_priv->ba_ena;
|
|
if (ba_cnt)
|
|
ba_avg = ba_acc / ba_cnt;
|
|
if (ba_cnt_rx)
|
|
ba_avg_rx = ba_acc_rx / ba_cnt_rx;
|
|
spin_unlock_bh(&hw_priv->ba_lock);
|
|
|
|
seq_puts(seq, "RK960 Wireless LAN driver status\n");
|
|
seq_printf(seq, "Hardware: %d.%d\n",
|
|
hw_priv->wsm_caps.hardwareId,
|
|
hw_priv->wsm_caps.hardwareSubId);
|
|
seq_printf(seq, "Firmware: %s %d.%d\n",
|
|
rk960_debug_fw_types[hw_priv->wsm_caps.firmwareType],
|
|
hw_priv->wsm_caps.firmwareVersion,
|
|
hw_priv->wsm_caps.firmwareBuildNumber);
|
|
seq_printf(seq, "FW API: %d\n", hw_priv->wsm_caps.firmwareApiVer);
|
|
seq_printf(seq, "FW caps: 0x%.4X\n", hw_priv->wsm_caps.firmwareCap);
|
|
if (hw_priv->channel)
|
|
seq_printf(seq, "Channel: %d%s\n",
|
|
hw_priv->channel->hw_value,
|
|
hw_priv->channel_switch_in_progress ?
|
|
" (switching)" : "");
|
|
seq_printf(seq, "HT: %s\n",
|
|
rk960_is_ht(&hw_priv->ht_info) ? "on" : "off");
|
|
if (rk960_is_ht(&hw_priv->ht_info)) {
|
|
seq_printf(seq, "Greenfield: %s\n",
|
|
rk960_ht_greenfield(&hw_priv->
|
|
ht_info) ? "yes" : "no");
|
|
seq_printf(seq, "AMPDU dens: %d\n",
|
|
rk960_ht_ampdu_density(&hw_priv->ht_info));
|
|
}
|
|
spin_lock_bh(&hw_priv->tx_policy_cache.lock);
|
|
i = 0;
|
|
list_for_each(item, &hw_priv->tx_policy_cache.used)
|
|
++ i;
|
|
spin_unlock_bh(&hw_priv->tx_policy_cache.lock);
|
|
seq_printf(seq, "RC in use: %d\n", i);
|
|
seq_printf(seq, "BA stat: %d, %d (%d)\n", ba_cnt, ba_acc, ba_avg);
|
|
seq_printf(seq, "BA RX stat: %d, %d (%d)\n",
|
|
ba_cnt_rx, ba_acc_rx, ba_avg_rx);
|
|
seq_printf(seq, "Block ACK: %s\n", ba_ena ? "on" : "off");
|
|
|
|
seq_puts(seq, "\n");
|
|
for (i = 0; i < 4; ++i) {
|
|
rk960_queue_status_show(seq, &hw_priv->tx_queue[i]);
|
|
seq_puts(seq, "\n");
|
|
}
|
|
|
|
seq_printf(seq, "TX conf max(ms): %d\n",
|
|
(int)hw_priv->ms_max_tx_conf_time);
|
|
seq_printf(seq, "TX conf max queue_id: %d\n",
|
|
hw_priv->max_tx_conf_queueid);
|
|
seq_printf(seq, "TX conf max status: %d\n",
|
|
hw_priv->max_tx_conf_status);
|
|
seq_printf(seq, "TX conf max txedRate: %d\n",
|
|
hw_priv->max_tx_conf_txedrate);
|
|
seq_printf(seq, "TX conf max ackFailures: %d\n",
|
|
hw_priv->max_tx_conf_ackfailures);
|
|
seq_printf(seq, "TX conf max mediaDelay: %d\n",
|
|
hw_priv->max_tx_conf_mediadelay);
|
|
seq_printf(seq, "TX conf max txQueueDelay: %d\n",
|
|
hw_priv->max_tx_conf_txQueuedelay);
|
|
|
|
seq_printf(seq, "TX burst: %d\n", d->tx_burst);
|
|
seq_printf(seq, "RX burst: %d\n", d->rx_burst);
|
|
seq_printf(seq, "TX miss: %d\n", d->tx_cache_miss);
|
|
seq_printf(seq, "TX drops: %d\n", d->tx_drops);
|
|
seq_printf(seq, "Long retr: %d\n", hw_priv->long_frame_max_tx_count);
|
|
seq_printf(seq, "Short retr: %d\n", hw_priv->short_frame_max_tx_count);
|
|
|
|
seq_printf(seq, "BH status: %s\n",
|
|
atomic_read(&hw_priv->bh_term) ? "terminated" : "alive");
|
|
seq_printf(seq, "Pending RX: %d\n", atomic_read(&hw_priv->bh_rx));
|
|
seq_printf(seq, "Pending TX: %d\n", atomic_read(&hw_priv->bh_tx));
|
|
if (hw_priv->bh_error)
|
|
seq_printf(seq, "BH errcode: %d\n", hw_priv->bh_error);
|
|
seq_printf(seq, "TX bufs: %d x %d bytes\n",
|
|
hw_priv->wsm_caps.numInpChBufs,
|
|
hw_priv->wsm_caps.sizeInpChBuf);
|
|
seq_printf(seq, "Used bufs: %d\n", hw_priv->hw_bufs_used);
|
|
seq_printf(seq, "Device: %s\n",
|
|
hw_priv->device_can_sleep ? "alseep" : "awake");
|
|
|
|
spin_lock(&hw_priv->wsm_cmd.lock);
|
|
seq_printf(seq, "WSM status: %s\n",
|
|
hw_priv->wsm_cmd.done ? "idle" : "active");
|
|
seq_printf(seq, "WSM cmd: 0x%.4X (%d bytes)\n",
|
|
hw_priv->wsm_cmd.cmd, (int)hw_priv->wsm_cmd.len);
|
|
seq_printf(seq, "WSM retval: %d\n", hw_priv->wsm_cmd.ret);
|
|
spin_unlock(&hw_priv->wsm_cmd.lock);
|
|
|
|
seq_printf(seq, "Datapath: %s\n",
|
|
atomic_read(&hw_priv->tx_lock) ? "locked" : "unlocked");
|
|
if (atomic_read(&hw_priv->tx_lock))
|
|
seq_printf(seq, "TXlock cnt: %d\n",
|
|
atomic_read(&hw_priv->tx_lock));
|
|
|
|
seq_printf(seq, "Scan: %s\n",
|
|
atomic_read(&hw_priv->scan.in_progress) ? "active" : "idle");
|
|
seq_printf(seq, "Scan counter: %d %d\n",
|
|
hw_priv->scan_counter, hw_priv->scan_comp_counter);
|
|
seq_printf(seq, "Led state: 0x%.2X\n", hw_priv->softled_state);
|
|
|
|
#ifdef RK960_CSYNC_ADJUST
|
|
seq_printf(seq, "\ncsync enable(%d):\n", !csync->csync_disable);
|
|
for (i = 0; i < 2; i++) {
|
|
if (hw_priv->if_id_slot & BIT(i)) {
|
|
priv =
|
|
rk960_get_vif_from_ieee80211(hw_priv->vif_list[i]);
|
|
if (priv) {
|
|
seq_printf(seq,
|
|
"idx(%d) vif_addr = %pM, bssid = %pM,"
|
|
" join_status = %d\n", i,
|
|
hw_priv->vif_list[i]->addr,
|
|
priv->join_bssid, priv->join_status);
|
|
seq_printf(seq, "thresh_accum = %d\n",
|
|
csync->thresh_accum[i]);
|
|
seq_printf(seq, "avg_thresh = %d\n",
|
|
csync->avg_thresh[i]);
|
|
seq_printf(seq, "new_thresh = %d\n",
|
|
csync->new_thresh[i]);
|
|
}
|
|
}
|
|
}
|
|
seq_printf(seq, "cur_seted_thresh: %03d\n", csync->cur_seted_thresh);
|
|
seq_printf(seq, "last_sam_size: %d %d\n", csync->last_sam_size[0],
|
|
csync->last_sam_size[1]);
|
|
seq_printf(seq, "threld history:\n");
|
|
seq_printf(seq, "offset %02d: ", csync->cur_thr_offset);
|
|
for (i = 0; i < RK960_CSYNC_SETED_THRESH_COUNT; i++) {
|
|
if (csync->cur_thr_offset == i + 1) {
|
|
seq_printf(seq, "***");
|
|
} else if (csync->cur_thr_offset == 0) {
|
|
if (i == RK960_CSYNC_SETED_THRESH_COUNT - 1)
|
|
seq_printf(seq, "***");
|
|
}
|
|
seq_printf(seq, "%03d ", csync->thr_history[i]);
|
|
}
|
|
seq_printf(seq, "\n");
|
|
seq_printf(seq, "\ntimer hit %d (%d)\n",
|
|
csync->timer_hit, csync->set_hit);
|
|
seq_printf(seq, "tx_counter %d in last 1s\n", hw_priv->last_tx_counter);
|
|
seq_printf(seq, "rx_counter %d in last 1s\n", hw_priv->last_rx_counter);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rk960_status_open_common(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, &rk960_status_show_common, inode->i_private);
|
|
}
|
|
|
|
static const struct file_operations fops_status_common = {
|
|
.open = rk960_status_open_common,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
static int rk960_counters_show(struct seq_file *seq, void *v)
|
|
{
|
|
int ret;
|
|
struct rk960_common *hw_priv = seq->private;
|
|
struct wsm_counters_table counters;
|
|
|
|
ret = wsm_get_counters_table(hw_priv, &counters);
|
|
if (ret)
|
|
return ret;
|
|
|
|
#define CAT_STR(x, y) x ## y
|
|
#define PUT_COUNTER(tab, name) \
|
|
seq_printf(seq, "%s:" tab "%d\n", #name, \
|
|
__le32_to_cpu(counters.CAT_STR(count, name)))
|
|
|
|
PUT_COUNTER("\t\t", PlcpErrors);
|
|
PUT_COUNTER("\t\t", FcsErrors);
|
|
PUT_COUNTER("\t\t", TxPackets);
|
|
PUT_COUNTER("\t\t", RxPackets);
|
|
PUT_COUNTER("\t\t", RxPacketErrors);
|
|
PUT_COUNTER("\t\t", RtsSuccess);
|
|
PUT_COUNTER("\t\t", RtsFailures);
|
|
PUT_COUNTER("\t\t", RxFramesSuccess);
|
|
PUT_COUNTER("\t", RxDecryptionFailures);
|
|
PUT_COUNTER("\t\t", RxMicFailures);
|
|
PUT_COUNTER("\t", RxNoKeyFailures);
|
|
PUT_COUNTER("\t", TxMulticastFrames);
|
|
PUT_COUNTER("\t", TxFramesSuccess);
|
|
PUT_COUNTER("\t", TxFrameFailures);
|
|
PUT_COUNTER("\t", TxFramesRetried);
|
|
PUT_COUNTER("\t", TxFramesMultiRetried);
|
|
PUT_COUNTER("\t", RxFrameDuplicates);
|
|
PUT_COUNTER("\t\t", AckFailures);
|
|
PUT_COUNTER("\t", RxMulticastFrames);
|
|
PUT_COUNTER("\t", RxCMACICVErrors);
|
|
PUT_COUNTER("\t\t", RxCMACReplays);
|
|
PUT_COUNTER("\t", RxMgmtCCMPReplays);
|
|
PUT_COUNTER("\t", RxBIPMICErrors);
|
|
|
|
#undef PUT_COUNTER
|
|
#undef CAT_STR
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rk960_counters_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, &rk960_counters_show, inode->i_private);
|
|
}
|
|
|
|
static const struct file_operations fops_counters = {
|
|
.open = rk960_counters_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
static int rk960_generic_open(struct inode *inode, struct file *file)
|
|
{
|
|
file->private_data = inode->i_private;
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t rk960_11n_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
struct ieee80211_supported_band *band =
|
|
hw_priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
|
|
return simple_read_from_buffer(user_buf, count, ppos,
|
|
band->ht_cap.
|
|
ht_supported ? "1\n" : "0\n", 2);
|
|
}
|
|
|
|
static ssize_t rk960_11n_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
struct ieee80211_supported_band *band[2] = {
|
|
hw_priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ],
|
|
hw_priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ],
|
|
};
|
|
char buf[1];
|
|
int ena = 0;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, 1))
|
|
return -EFAULT;
|
|
if (buf[0] == 1)
|
|
ena = 1;
|
|
|
|
band[0]->ht_cap.ht_supported = ena;
|
|
#ifdef CONFIG_RK960_5GHZ_SUPPORT
|
|
band[1]->ht_cap.ht_supported = ena;
|
|
#endif /* CONFIG_RK960_5GHZ_SUPPORT */
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations fops_11n = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_11n_read,
|
|
.write = rk960_11n_write,
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_mem_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
int i, size = 0;
|
|
u32 *data;
|
|
u32 addr;
|
|
int ret = 0;
|
|
|
|
if (!hw_priv->debug_dump_data)
|
|
return 0;
|
|
|
|
if (wait_event_interruptible_timeout(hw_priv->debug_dump_done,
|
|
hw_priv->debug_dump_ready,
|
|
3 * HZ) <= 0) {
|
|
RK960_ERROR_IO("%s: wait debug_dump_ready failed\n", __func__);
|
|
goto mem_read_exit;
|
|
}
|
|
|
|
hw_priv->debug_dump_data_str = vmalloc(1024 * 4);
|
|
if (!hw_priv->debug_dump_data_str)
|
|
goto mem_read_exit;
|
|
|
|
hw_priv->mem_rw_len = round_up(hw_priv->mem_rw_len, 16);
|
|
data = (u32 *) hw_priv->debug_dump_data;
|
|
addr = hw_priv->mem_rw_addr;
|
|
for (i = 0; i < hw_priv->mem_rw_len / 16; i++) {
|
|
size +=
|
|
sprintf(&hw_priv->debug_dump_data_str[size],
|
|
"%08x: %08x %08x %08x %08x\n", addr, *data,
|
|
*(data + 1), *(data + 2), *(data + 3));
|
|
addr += 16;
|
|
data += 4;
|
|
}
|
|
|
|
ret = simple_read_from_buffer(user_buf, count, ppos,
|
|
hw_priv->debug_dump_data_str, size);
|
|
|
|
mem_read_exit:
|
|
if (hw_priv->debug_dump_data) {
|
|
vfree(hw_priv->debug_dump_data);
|
|
hw_priv->debug_dump_data = NULL;
|
|
}
|
|
if (hw_priv->debug_dump_data_str) {
|
|
vfree(hw_priv->debug_dump_data_str);
|
|
hw_priv->debug_dump_data_str = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_mem_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
unsigned long addr, len;
|
|
char *addr_s, *len_s;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
// r=0x10001000,0x4
|
|
// w=0x10001000,0x20002000
|
|
if (buf[0] == 'r' || buf[0] == 'w') {
|
|
addr_s = strstr(buf, "=");
|
|
len_s = strstr(buf, ",");
|
|
if (!addr_s || !len_s)
|
|
return -EINVAL;
|
|
*len_s = 0;
|
|
buf[count] = 0;
|
|
if (kstrtoul(addr_s + 1, 16, &addr))
|
|
return -EINVAL;
|
|
if (kstrtoul(len_s + 1, 16, &len))
|
|
return -EINVAL;
|
|
if (buf[0] == 'r') {
|
|
struct wsm_mem_rw mem_rw = {
|
|
.link_id = 0,
|
|
.address = addr,
|
|
.length = len,
|
|
.flags = WSM_RW_F_IRQ_PROTECT,
|
|
};
|
|
|
|
if (len > 1024)
|
|
len = 1024;
|
|
|
|
RK960_INFO_IO("%s: r 0x%08x %d\n", __func__, (u32) addr,
|
|
(u32) len);
|
|
|
|
hw_priv->mem_rw_addr = addr;
|
|
hw_priv->mem_rw_len = len;
|
|
hw_priv->debug_dump_ready = 0;
|
|
if (hw_priv->debug_dump_data)
|
|
vfree(hw_priv->debug_dump_data);
|
|
hw_priv->debug_dump_data = vmalloc(1024);
|
|
if (hw_priv->debug_dump_data) {
|
|
memset(hw_priv->debug_dump_data, 0xAA, 1024);
|
|
wsm_mem_rw(hw_priv, &mem_rw, 1, 0);
|
|
}
|
|
} else {
|
|
struct wsm_mem_rw mem_rw = {
|
|
.link_id = 0,
|
|
.address = addr,
|
|
.length = 4,
|
|
.flags = WSM_RW_F_IRQ_PROTECT,
|
|
};
|
|
|
|
RK960_INFO_IO("%s: w 0x%08x 0x%08x\n", __func__,
|
|
(u32) addr, (u32) len);
|
|
|
|
mem_rw.data[0] = len;
|
|
wsm_mem_rw(hw_priv, &mem_rw, 0, 0);
|
|
}
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_mem = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_mem_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_mem_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
#define RK960_ADC_SAVE_PATH "/data/rk960_adc.txt"
|
|
static ssize_t rk960_adc_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
int i, size = 0;
|
|
u32 *data;
|
|
int ret = 0;
|
|
|
|
if (!hw_priv->debug_dump_data)
|
|
return 0;
|
|
|
|
if (wait_event_interruptible_timeout(hw_priv->debug_dump_done,
|
|
hw_priv->debug_dump_ready,
|
|
3 * HZ) <= 0) {
|
|
RK960_ERROR_IO("%s: wait debug_dump_ready failed\n", __func__);
|
|
goto adc_read_exit;
|
|
}
|
|
|
|
hw_priv->debug_dump_data_str = vmalloc(hw_priv->debug_adc_size * 3);
|
|
if (!hw_priv->debug_dump_data_str)
|
|
goto adc_read_exit;
|
|
|
|
data = (u32 *) hw_priv->debug_dump_data;
|
|
for (i = 0; i < hw_priv->debug_adc_size / 4; i++) {
|
|
size +=
|
|
sprintf(&hw_priv->debug_dump_data_str[size], "%08x\n",
|
|
*data);
|
|
data++;
|
|
}
|
|
|
|
rk960_access_file(RK960_ADC_SAVE_PATH, hw_priv->debug_dump_data_str,
|
|
size, 0);
|
|
|
|
size = sprintf(&hw_priv->debug_dump_data_str[0], "%s\n",
|
|
"adc data is saved at: " RK960_ADC_SAVE_PATH);
|
|
ret = simple_read_from_buffer(user_buf, count, ppos,
|
|
hw_priv->debug_dump_data_str, size);
|
|
|
|
adc_read_exit:
|
|
if (hw_priv->debug_dump_data) {
|
|
vfree(hw_priv->debug_dump_data);
|
|
hw_priv->debug_dump_data = NULL;
|
|
}
|
|
if (hw_priv->debug_dump_data_str) {
|
|
vfree(hw_priv->debug_dump_data_str);
|
|
hw_priv->debug_dump_data_str = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t rk960_adc_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
int adc_size;
|
|
int channel;
|
|
//int i;
|
|
int adc_count;
|
|
int abbf, lna;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
// adc 1 10 65536
|
|
if (strstr(buf, "adc") != NULL) {
|
|
sscanf(buf + 4, "%d %d %d %d %d", &channel, &adc_count,
|
|
&adc_size, &abbf, &lna);
|
|
|
|
if (channel > 14 || channel < 1) {
|
|
RK960_ERROR_IO("invalid channel %d\n", channel);
|
|
return -EINVAL;
|
|
}
|
|
if (abbf > 48 || abbf < 24) {
|
|
RK960_ERROR_IO("invalid abbf %d\n", abbf);
|
|
abbf = 0;
|
|
}
|
|
if (lna > 6 || lna < 0) {
|
|
RK960_ERROR_IO("invalid lna %d\n", lna);
|
|
lna = 0;
|
|
}
|
|
|
|
if (adc_count <= 0)
|
|
adc_count = 1;
|
|
|
|
if (adc_size > 65536)
|
|
adc_size = 65536;
|
|
if (adc_size < 25600)
|
|
adc_size = 25600;
|
|
|
|
RK960_INFO_IO
|
|
("%s: adc: ch %d count %d size %d abbf %d lna %d\n",
|
|
__func__, channel, adc_count, adc_size, abbf, lna);
|
|
|
|
adc_size <<= 2; // I/Q data
|
|
|
|
hw_priv->debug_adc_offset = 0;
|
|
hw_priv->debug_adc_block = 1024;
|
|
hw_priv->debug_adc_size = adc_size;
|
|
hw_priv->debug_dump_ready = 0;
|
|
|
|
if (hw_priv->debug_dump_data)
|
|
vfree(hw_priv->debug_dump_data);
|
|
hw_priv->debug_dump_data = vmalloc(adc_size);
|
|
if (hw_priv->debug_dump_data) {
|
|
struct wsm_adc_data_r adc_data_r;
|
|
|
|
adc_data_r.size = adc_size;
|
|
adc_data_r.block = hw_priv->debug_adc_block;
|
|
adc_data_r.channel = channel;
|
|
adc_data_r.count = adc_count;
|
|
adc_data_r.abbf = abbf;
|
|
adc_data_r.lna = lna;
|
|
//for (i = 0; i < adc_size/hw_priv->debug_adc_block; i++) {
|
|
adc_data_r.offset = 0 * hw_priv->debug_adc_block;
|
|
wsm_adc_data_read(hw_priv, &adc_data_r, 0);
|
|
//}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_adc = {
|
|
.open = rk960_generic_open,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.read = rk960_adc_read,
|
|
.write = rk960_adc_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
#define DEVICE_DEBUG_STRUCT_INFO_SAVE_PATH "/sdcard/rk960_device_debug_struct_info.bin"
|
|
static ssize_t rk960_device_debug_struct_info_read(struct file *file,
|
|
char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
int size = 0;
|
|
int ret = 0;
|
|
|
|
if (!hw_priv->debug_dump_data)
|
|
return 0;
|
|
|
|
if (wait_event_interruptible_timeout(hw_priv->debug_dump_done,
|
|
hw_priv->debug_dump_ready,
|
|
3 * HZ) <= 0) {
|
|
RK960_ERROR_IO("%s: wait debug_dump_ready failed\n", __func__);
|
|
goto device_debug_read_exit;
|
|
}
|
|
|
|
RK960_INFO_MAIN("%s: read 0x%08x %d!!!\n", __func__, (u32) size,
|
|
(u32) count);
|
|
|
|
hw_priv->debug_dump_data_str = vmalloc(1024 * 4);
|
|
if (!hw_priv->debug_dump_data_str)
|
|
goto device_debug_read_exit;
|
|
size = sprintf(&hw_priv->debug_dump_data_str[0], "%s\n",
|
|
"device_debug_struct_info data is saved at: "
|
|
DEVICE_DEBUG_STRUCT_INFO_SAVE_PATH);
|
|
ret =
|
|
simple_read_from_buffer(user_buf, count, ppos,
|
|
hw_priv->debug_dump_data_str, size);
|
|
//save data to file
|
|
rk960_access_file(DEVICE_DEBUG_STRUCT_INFO_SAVE_PATH,
|
|
hw_priv->debug_dump_data, hw_priv->mem_rw_len, 0);
|
|
|
|
device_debug_read_exit:
|
|
if (hw_priv->debug_dump_data) {
|
|
vfree(hw_priv->debug_dump_data);
|
|
hw_priv->debug_dump_data = NULL;
|
|
}
|
|
if (hw_priv->debug_dump_data_str) {
|
|
vfree(hw_priv->debug_dump_data_str);
|
|
hw_priv->debug_dump_data_str = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t rk960_device_debug_struct_info_write(struct file *file,
|
|
const char __user *
|
|
user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
unsigned long addr, len;
|
|
struct wsm_device_debug_struct_info info;
|
|
struct wsm_mem_rw mem_rw;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN) {
|
|
count = MAX_WRITE_STR_LEN;
|
|
}
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
memset(&info, 0, sizeof(struct wsm_device_debug_struct_info));
|
|
wsm_get_device_debug_struct_info(hw_priv, &info);
|
|
addr = info.mem_addr;
|
|
len = info.size;
|
|
mem_rw.link_id = 0;
|
|
mem_rw.address = addr;
|
|
mem_rw.length = len;
|
|
mem_rw.flags = WSM_RW_F_IRQ_PROTECT;
|
|
|
|
if (len > 1024)
|
|
len = 1024;
|
|
|
|
RK960_INFO_MAIN("%s: read 0x%08x %d!!!\n", __func__, (u32) addr,
|
|
(u32) len);
|
|
|
|
hw_priv->mem_rw_addr = addr;
|
|
hw_priv->mem_rw_len = len;
|
|
hw_priv->debug_dump_ready = 0;
|
|
if (hw_priv->debug_dump_data)
|
|
vfree(hw_priv->debug_dump_data);
|
|
hw_priv->debug_dump_data = vmalloc(1024);
|
|
if (hw_priv->debug_dump_data) {
|
|
memset(hw_priv->debug_dump_data, 0x0, 1024);
|
|
wsm_mem_rw(hw_priv, &mem_rw, 1, 0);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_device_debug_struct_info = {
|
|
.open = rk960_generic_open,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.read = rk960_device_debug_struct_info_read,
|
|
.write = rk960_device_debug_struct_info_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_rftest_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#if 1//def ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_rftest_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
int channel, rate, rate_index, len;
|
|
int times = 0;
|
|
int sgi = 0;
|
|
int tx_power;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
// start_tx channel rate length
|
|
if (strstr(buf, "start_tx") != NULL) {
|
|
sscanf(buf + 9, "%d %d %d %d %d %d",
|
|
&channel, &rate, &tx_power, &len, ×, &sgi);
|
|
|
|
if (channel > 14 || channel < 1) {
|
|
RK960_ERROR_IO("invalid channel %d\n", channel);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rate_index = rk960_rate_to_rate_index(rate);
|
|
|
|
if (len < 200 || len > max_payload) {
|
|
RK960_ERROR_IO("invalid len %d[200-%d]\n", len,
|
|
max_payload);
|
|
return -EINVAL;
|
|
}
|
|
if (rate_index < 14) {
|
|
sgi = 0;
|
|
}
|
|
|
|
if (!tx_power)
|
|
tx_power = RK960_DEFAULT_TX_POWER * 10;
|
|
else if (tx_power > 20)
|
|
tx_power = 20 * 16; // 20db
|
|
else
|
|
tx_power *= 16;
|
|
|
|
RK960_INFO_IO("%s: start_tx: channel:%d rate:%d tx_power %d "
|
|
"len:%d count:%d sgi:%d\n",
|
|
__func__, channel, rate, tx_power, len, times,
|
|
sgi);
|
|
rk960_rftest_start_tx(hw_priv, channel, rate_index, tx_power,
|
|
len, times, sgi);
|
|
// stop_txrx
|
|
} else if (strstr(buf, "stop_txrx") != NULL) {
|
|
RK960_INFO_IO("%s: stop_txrx\n", __func__);
|
|
rk960_rftest_stop_txrx(hw_priv);
|
|
// start_rx channel
|
|
} else if (strstr(buf, "start_rx") != NULL) {
|
|
sscanf(buf + 9, "%d", &channel);
|
|
|
|
if (channel > 14 || channel < 1) {
|
|
RK960_ERROR_IO("invalid channel %d\n", channel);
|
|
return -EINVAL;
|
|
}
|
|
|
|
RK960_INFO_IO("%s: start_rx: channel:%d\n", __func__, channel);
|
|
rk960_rftest_start_rx(hw_priv, channel);
|
|
// start_tone channel
|
|
} else if (strstr(buf, "start_tone") != NULL) {
|
|
sscanf(buf + 11, "%d", &channel);
|
|
|
|
if (channel > 14 || channel < 1) {
|
|
RK960_ERROR_IO("invalid channel %d\n", channel);
|
|
return -EINVAL;
|
|
}
|
|
|
|
RK960_INFO_IO("%s: start_tone: channel:%d\n", __func__,
|
|
channel);
|
|
rk960_rftest_start_tone(hw_priv, channel, 1);
|
|
// start_dc channel
|
|
} else if (strstr(buf, "start_dc") != NULL) {
|
|
sscanf(buf + 9, "%d", &channel);
|
|
|
|
if (channel > 14 || channel < 1) {
|
|
RK960_ERROR_IO("invalid channel %d\n", channel);
|
|
return -EINVAL;
|
|
}
|
|
|
|
RK960_INFO_IO("%s: start_dc: channel:%d\n", __func__, channel);
|
|
rk960_rftest_start_tone(hw_priv, channel, 0);
|
|
// start_monitor channel
|
|
} else if (strstr(buf, "start_monitor") != NULL) {
|
|
sscanf(buf + 14, "%d", &channel);
|
|
|
|
if (channel > 14 || channel < 1) {
|
|
RK960_ERROR_IO("invalid channel %d\n", channel);
|
|
return -EINVAL;
|
|
}
|
|
|
|
RK960_INFO_IO("%s: start_monitor: channel:%d\n", __func__,
|
|
channel);
|
|
rk960_rftest_start_rx(hw_priv, channel | 0x80);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_rftest = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_rftest_read,
|
|
#if 1//def ENABLE_DBGFS_WRITE
|
|
.write = rk960_rftest_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_csync_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
#ifdef RK960_CSYNC_ADJUST
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[20];
|
|
size_t size = 0;
|
|
|
|
sprintf(buf, "%d\n", hw_priv->fw_csync);
|
|
size = strlen(buf);
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_csync_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
#ifdef RK960_CSYNC_ADJUST
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
int csync;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%d", &csync);
|
|
if (csync > 0 || csync < -95) {
|
|
RK960_ERROR_IO("invalid csync %d\n", csync);
|
|
hw_priv->csync_params.csync_disable = 0;
|
|
return -EINVAL;
|
|
}
|
|
|
|
hw_priv->csync_params.csync_disable = 1;
|
|
wsm_set_csync_thr(hw_priv, (s8) csync, 0);
|
|
#endif
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_csync = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_csync_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_csync_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_fw_dbg_leve_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
size_t size = 0;
|
|
u32 dbg_level;
|
|
|
|
wsm_get_fw_dbg_level(hw_priv, &dbg_level);
|
|
|
|
sprintf(buf, "%x\n", dbg_level);
|
|
size = strlen(buf);
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_fw_dbg_leve_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
u32 value;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%x", &value);
|
|
|
|
RK960_DEBUG_IO("%s: value %x\n", __func__, value);
|
|
|
|
wsm_set_fw_dbg_level(hw_priv, value);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_fw_dbg_level = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_fw_dbg_leve_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_fw_dbg_leve_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_drv_dbg_level_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
char buf[16];
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%x", &rk960_debug_level);
|
|
|
|
RK960_DEBUG_IO("%s: value %x\n", __func__, rk960_debug_level);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_drv_dbg_level = {
|
|
.open = rk960_generic_open,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_drv_dbg_level_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_drv_dbg_flag_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
char buf[16];
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%x", &rk960_debug_flag);
|
|
|
|
RK960_DEBUG_IO("%s: value %x\n", __func__, rk960_debug_flag);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_drv_dbg_flag = {
|
|
.open = rk960_generic_open,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_drv_dbg_flag_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef RK960_FW_ERROR_RECOVERY
|
|
static ssize_t rk960_fw_err_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
size_t size = 0;
|
|
struct wsm_com_cmd_s *cmd;
|
|
int length = 0;
|
|
int n = 0;
|
|
int ret;
|
|
u8 *buf;
|
|
int i;
|
|
|
|
buf = vmalloc(8 * 1024);
|
|
if (!buf)
|
|
return 0;
|
|
|
|
n += sprintf(buf, "fw_error_counter: %d:", hw_priv->fw_error_counter);
|
|
for (i = 0; i < hw_priv->fw_error_counter; i++)
|
|
n += sprintf(buf + n, " %d", hw_priv->fw_error_reason[i]);
|
|
n += sprintf(buf + n, "\nsave cmds:\n");
|
|
|
|
list_for_each_entry(cmd, &hw_priv->wsm_cmds_list, list) {
|
|
length++;
|
|
if (cmd->cmd == 0x0006)
|
|
n += sprintf(buf + n, " %s 0x%.4X [MIB: 0x%.4X] "
|
|
"if_id %d\n",
|
|
wsm_conv_req_resp_to_str(cmd->cmd),
|
|
cmd->cmd, cmd->mibId, cmd->if_id);
|
|
else
|
|
n += sprintf(buf + n, " %s 0x%.4X if_id %d\n",
|
|
wsm_conv_req_resp_to_str(cmd->cmd),
|
|
cmd->cmd, cmd->if_id);
|
|
}
|
|
|
|
buf[n] = 0;
|
|
size = strlen(buf);
|
|
ret = simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
vfree(buf);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_fw_err_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
char buf[16];
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
int enable;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%d", &enable);
|
|
|
|
if (enable)
|
|
hw_priv->fw_error_enable = 1;
|
|
else
|
|
hw_priv->fw_error_enable = 0;
|
|
|
|
//rk960_signal_fw_error(hw_priv, RK960_FWERR_REASON_TEST);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_fw_err = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_fw_err_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_fw_err_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
#endif
|
|
|
|
static ssize_t rk960_rts_threshold_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
size_t size = 0;
|
|
|
|
if (!hw_priv->rts_threshold)
|
|
hw_priv->rts_threshold = 3000; // default value
|
|
sprintf(buf, "%d\n", hw_priv->rts_threshold);
|
|
size = strlen(buf);
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_rts_threshold_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
__le32 rts_threshold;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%d", &rts_threshold);
|
|
if (rts_threshold >= 0) {
|
|
if (!rts_threshold)
|
|
rts_threshold = 3000;
|
|
RK960_DEBUG_IO("%s: rts_threshold %x\n", __func__, rts_threshold);
|
|
|
|
hw_priv->rts_threshold = rts_threshold;
|
|
wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD,
|
|
&rts_threshold, sizeof(rts_threshold), 0);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_rts_threshold = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_rts_threshold_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_rts_threshold_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef SUPPORT_FWCR
|
|
static ssize_t rk960_fwcr_save_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
|
|
rk960_fwcr_write(hw_priv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct file_operations fops_fwcr_save = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_fwcr_save_read,
|
|
.llseek = default_llseek,
|
|
};
|
|
#endif
|
|
|
|
static ssize_t rk960_fixed_rate_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[256];
|
|
size_t size = 0;
|
|
|
|
size += sprintf(buf + size, "tx_fixed_rate: %d\n",
|
|
hw_priv->tx_fixed_rate);
|
|
size += sprintf(buf + size,
|
|
"support rates:\n");
|
|
size += sprintf(buf + size,
|
|
"10, 20, 55, 110\n");
|
|
size += sprintf(buf + size,
|
|
"60, 90, 120, 180, 240, 360, 480, 540\n");
|
|
size += sprintf(buf + size,
|
|
"65, 130, 195, 260, 390, 520, 585, 650\n");
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_fixed_rate_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
int tx_fixed_rate;
|
|
int index;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%d", &tx_fixed_rate);
|
|
index = rk960_rate_to_rate_index(tx_fixed_rate);
|
|
if (index >= 0)
|
|
hw_priv->tx_fixed_rate = tx_fixed_rate;
|
|
else
|
|
hw_priv->tx_fixed_rate = 0;
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_fixed_rate = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_fixed_rate_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_fixed_rate_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_tx_agg_num_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
int tx_agg_num;
|
|
struct wsm_set_tx_agg_control tx_agg_ctrl;
|
|
int i;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%d", &tx_agg_num);
|
|
if (tx_agg_num > 16)
|
|
tx_agg_num = 16;
|
|
for (i = 0; i < 8; i++)
|
|
tx_agg_ctrl.tx_max_agg_num[i] = tx_agg_num;
|
|
wsm_set_agg_control(hw_priv, &tx_agg_ctrl);
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_tx_agg_num = {
|
|
.open = rk960_generic_open,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_tx_agg_num_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_dtim_int_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[32];
|
|
size_t size = 0;
|
|
|
|
size += sprintf(buf, "dtim_interval: %d\n",
|
|
hw_priv->dtim_interval);
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_dtim_int_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
int dtim_interval;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%d", &dtim_interval);
|
|
hw_priv->dtim_interval = dtim_interval;
|
|
wsm_set_beacon_wakeup_period(hw_priv,
|
|
hw_priv->dtim_interval,
|
|
hw_priv->listen_interval, 0);
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_dtim_int = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_dtim_int_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_dtim_int_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_listen_int_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[32];
|
|
size_t size = 0;
|
|
|
|
size += sprintf(buf, "listen_interval: %d\n",
|
|
hw_priv->listen_interval);
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_listen_int_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[16];
|
|
int listen_interval;
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
sscanf(buf, "%d", &listen_interval);
|
|
hw_priv->listen_interval = listen_interval;
|
|
wsm_set_beacon_wakeup_period(hw_priv,
|
|
hw_priv->dtim_interval,
|
|
hw_priv->listen_interval, 0);
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_listen_int = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_listen_int_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_listen_int_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_efuse_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[RK960_EFUSE_SIZE];
|
|
char buf_str[RK960_EFUSE_SIZE * 4];
|
|
size_t size = 0;
|
|
int i;
|
|
|
|
if (*ppos)
|
|
return size;
|
|
|
|
wsm_read_efuse(hw_priv, buf);
|
|
|
|
for (i = 0; i < RK960_EFUSE_SIZE; i++) {
|
|
size += sprintf(&buf_str[size], "%02x ", buf[i]);
|
|
if (((i + 1) % 16) == 0)
|
|
size += sprintf(&buf_str[size], "\n");
|
|
}
|
|
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf_str, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_efuse_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
int offset, value;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
// echo offset value > efuse
|
|
// e.g. offset = 16, value = 0x55
|
|
// echo 16 0x55 > efuse
|
|
sscanf(buf, "%d %x", &offset, &value);
|
|
if (offset > 63 || offset < 0) {
|
|
RK960_ERROR_IO("invalid offset %d\n", offset);
|
|
return -EINVAL;
|
|
}
|
|
|
|
RK960_DEBUG_IO("%s: off %d val 0x%02x\n", __func__, offset, value);
|
|
|
|
wsm_write_efuse(hw_priv, offset, value);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_efuse = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_efuse_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_efuse_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_wifi_efuse_mac_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf_str[32];
|
|
size_t size = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
size += sprintf(&buf_str[size], "%02x",
|
|
hw_priv->wifi_efuse_mac_addr[i]);
|
|
if (i < 5)
|
|
size += sprintf(&buf_str[size], ":");
|
|
}
|
|
size += sprintf(&buf_str[size], "\n");
|
|
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf_str, size);
|
|
}
|
|
|
|
static const struct file_operations fops_wifi_efuse_mac = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_wifi_efuse_mac_read,
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_bt_efuse_mac_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf_str[32];
|
|
size_t size = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
size += sprintf(&buf_str[size], "%02x",
|
|
hw_priv->bt_efuse_mac_addr[i]);
|
|
if (i < 5)
|
|
size += sprintf(&buf_str[size], ":");
|
|
}
|
|
size += sprintf(&buf_str[size], "\n");
|
|
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf_str, size);
|
|
}
|
|
|
|
static const struct file_operations fops_bt_efuse_mac = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_bt_efuse_mac_read,
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_rxgain_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
int abbf, lna, en;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
// echo abbf lna en > rxgain
|
|
// e.g.: min gain: echo 48 8 1 > rxgain
|
|
// e.g.: enable agc: echo 48 8 0 > rxgain
|
|
sscanf(buf, "%d %d %d", &abbf, &lna, &en);
|
|
if (abbf > 48 || abbf < 24) {
|
|
RK960_ERROR_IO("invalid abbf %d[24-48]\n", abbf);
|
|
return -EINVAL;
|
|
}
|
|
if (lna > 8 || lna < 0) {
|
|
RK960_ERROR_IO("invalid lna %d[0-8]\n", lna);
|
|
return -EINVAL;
|
|
}
|
|
if (en)
|
|
en = 1;
|
|
|
|
RK960_DEBUG_IO("%s: abbf %d lna %d en %d\n", __func__, abbf, lna, en);
|
|
|
|
wsm_set_manual_rxgain(hw_priv, en, abbf, lna);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_rxgain = {
|
|
.open = rk960_generic_open,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_rxgain_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_txpower_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[20];
|
|
size_t size = 0;
|
|
|
|
sprintf(buf, "%d\n", hw_priv->fw_output_power);
|
|
size = strlen(buf);
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_txpower_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[MAX_WRITE_STR_LEN];
|
|
int tx_power;
|
|
|
|
if (!count || count > MAX_WRITE_STR_LEN)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
// echo txpower > txpower
|
|
// echo 20 > txpower
|
|
sscanf(buf, "%d", &tx_power);
|
|
if (!tx_power)
|
|
tx_power = RK960_DEFAULT_TX_POWER * 10;
|
|
else if (tx_power > 20)
|
|
tx_power = 20 * 16; // 20db
|
|
else
|
|
tx_power *= 16;
|
|
|
|
RK960_DEBUG_IO("%s: tx_power %d\n", __func__, tx_power);
|
|
|
|
wsm_set_output_power(hw_priv, tx_power, 0);
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_txpower = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_txpower_read,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_txpower_write,
|
|
#endif
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#define RK960_TXPWR_COMP_DUMP(rate, n) \
|
|
do { \
|
|
size += sprintf(buf + size, "%s=", rate); \
|
|
for (i = 0; i < 14; i++) { \
|
|
size += sprintf(buf + size, "%d,", hw_priv->txpwr_comp_tbl[i][n]); \
|
|
} \
|
|
size += sprintf(buf + size, "\n"); \
|
|
} while (0)
|
|
|
|
static ssize_t rk960_txpower_comp_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
size_t size = 0;
|
|
int i, ret = 0;
|
|
u8 *buf;
|
|
|
|
hw_priv->debug_dump_data_str = vmalloc(1024 * 4);
|
|
if (!hw_priv->debug_dump_data_str)
|
|
goto txpower_comp_read_exit;
|
|
|
|
buf = hw_priv->debug_dump_data_str;
|
|
|
|
RK960_TXPWR_COMP_DUMP("txpwr_dsss_comp", 0);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_cck_comp", 1);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_bpsk_12_comp", 2);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_bpsk_34_comp", 3);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_qpsk_12_comp", 4);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_qpsk_34_comp", 5);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_16qam_12_comp", 6);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_16qam_34_comp", 7);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_64qam_23_comp", 8);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_64qam_34_comp", 9);
|
|
RK960_TXPWR_COMP_DUMP("txpwr_64qam_56_comp", 10);
|
|
|
|
ret = simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
|
|
txpower_comp_read_exit:
|
|
if (hw_priv->debug_dump_data_str) {
|
|
vfree(hw_priv->debug_dump_data_str);
|
|
hw_priv->debug_dump_data_str = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static const struct file_operations fops_txpower_comp = {
|
|
.open = rk960_generic_open,
|
|
.read = rk960_txpower_comp_read,
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
static ssize_t rk960_wsm_dumps(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[1];
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, 1))
|
|
return -EFAULT;
|
|
|
|
if (buf[0] == '1')
|
|
hw_priv->wsm_enable_wsm_dumps = 1;
|
|
else
|
|
hw_priv->wsm_enable_wsm_dumps = 0;
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations fops_wsm_dumps = {
|
|
.open = rk960_generic_open,
|
|
.write = rk960_wsm_dumps,
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
#if defined(CONFIG_RK960_WSM_DUMPS_SHORT)
|
|
static ssize_t rk960_short_dump_read(struct file *file,
|
|
char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_common *hw_priv = file->private_data;
|
|
char buf[20];
|
|
size_t size = 0;
|
|
|
|
sprintf(buf, "Size: %u\n", hw_priv->wsm_dump_max_size);
|
|
size = strlen(buf);
|
|
|
|
return simple_read_from_buffer(user_buf, count, ppos, buf, size);
|
|
}
|
|
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
static ssize_t rk960_short_dump_write(struct file *file,
|
|
const char __user * user_buf,
|
|
size_t count, loff_t * ppos)
|
|
{
|
|
struct rk960_common *priv = file->private_data;
|
|
char buf[20];
|
|
unsigned long dump_size = 0;
|
|
|
|
if (!count || count > 20)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, count))
|
|
return -EFAULT;
|
|
|
|
if (kstrtoul(buf, 10, &dump_size))
|
|
return -EINVAL;
|
|
|
|
priv->wsm_dump_max_size = dump_size;
|
|
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static const struct file_operations fops_short_dump = {
|
|
.open = rk960_generic_open,
|
|
#ifdef ENABLE_DBGFS_WRITE
|
|
.write = rk960_short_dump_write,
|
|
#endif
|
|
.read = rk960_short_dump_read,
|
|
.llseek = default_llseek,
|
|
};
|
|
#endif /* CONFIG_RK960_WSM_DUMPS_SHORT */
|
|
|
|
int rk960_debug_init_common(struct rk960_common *hw_priv)
|
|
{
|
|
int ret = -ENOMEM;
|
|
struct rk960_debug_common *d =
|
|
kzalloc(sizeof(struct rk960_debug_common), GFP_KERNEL);
|
|
hw_priv->debug = d;
|
|
if (!d)
|
|
return ret;
|
|
|
|
d->debugfs_phy = debugfs_create_dir("rk960",
|
|
hw_priv->hw->wiphy->debugfsdir);
|
|
if (!d->debugfs_phy)
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy,
|
|
hw_priv, &fops_status_common))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("counters", S_IRUSR, d->debugfs_phy,
|
|
hw_priv, &fops_counters))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("11n", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_11n))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("mem", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_mem))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("rftest", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_rftest))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("adc", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_adc))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("csync", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_csync))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("efuse", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_efuse))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("wifi_efuse_mac", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_wifi_efuse_mac))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("bt_efuse_mac", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_bt_efuse_mac))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("rxgain", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_rxgain))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("txpower", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_txpower))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("txpower_comp", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_txpower_comp))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("fw_dbg_level", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_fw_dbg_level))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("drv_dbg_level", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_drv_dbg_level))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("drv_dbg_flag", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_drv_dbg_flag))
|
|
goto err;
|
|
|
|
#ifdef RK960_FW_ERROR_RECOVERY
|
|
if (!debugfs_create_file("fw_err", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_fw_err))
|
|
goto err;
|
|
#endif
|
|
|
|
if (!debugfs_create_file("rts_threshold", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_rts_threshold))
|
|
goto err;
|
|
|
|
#ifdef SUPPORT_FWCR
|
|
if (!debugfs_create_file("fwcr_save", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_fwcr_save))
|
|
goto err;
|
|
#endif
|
|
|
|
if (!debugfs_create_file("fixed_rate", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_fixed_rate))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("tx_agg_num", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_tx_agg_num))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("dtim_int", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_dtim_int))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("listen_int", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_listen_int))
|
|
goto err;
|
|
|
|
/*if (!debugfs_create_file("device_debug", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
|
|
d->debugfs_phy, hw_priv, &fops_device_debug_struct_info))
|
|
goto err; */
|
|
|
|
if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy,
|
|
hw_priv, &fops_wsm_dumps))
|
|
goto err;
|
|
|
|
#if defined(CONFIG_RK960_WSM_DUMPS_SHORT)
|
|
if (!debugfs_create_file("wsm_dump_size", S_IRUSR | S_IWUSR,
|
|
d->debugfs_phy, hw_priv, &fops_short_dump))
|
|
goto err;
|
|
#endif /* CONFIG_RK960_WSM_DUMPS_SHORT */
|
|
|
|
ret = rk960_itp_init(hw_priv);
|
|
if (ret)
|
|
goto err;
|
|
|
|
return 0;
|
|
|
|
err:
|
|
hw_priv->debug = NULL;
|
|
debugfs_remove_recursive(d->debugfs_phy);
|
|
kfree(d);
|
|
return ret;
|
|
}
|
|
|
|
void rk960_debug_release_common(struct rk960_common *hw_priv)
|
|
{
|
|
struct rk960_debug_common *d = hw_priv->debug;
|
|
if (d) {
|
|
rk960_itp_release(hw_priv);
|
|
hw_priv->debug = NULL;
|
|
kfree(d);
|
|
}
|
|
}
|
|
|
|
static int rk960_status_show_priv(struct seq_file *seq, void *v)
|
|
{
|
|
int i;
|
|
struct rk960_vif *priv = seq->private;
|
|
struct rk960_debug_priv *d = priv->debug;
|
|
|
|
seq_printf(seq, "Mode: %s%s\n",
|
|
rk960_debug_mode(priv->mode),
|
|
priv->listening ? " (listening)" : "");
|
|
seq_printf(seq, "Assoc: %s\n",
|
|
rk960_debug_join_status[priv->join_status]);
|
|
if (priv->rx_filter.promiscuous)
|
|
seq_puts(seq, "Filter: promisc\n");
|
|
else if (priv->rx_filter.fcs)
|
|
seq_puts(seq, "Filter: fcs\n");
|
|
if (priv->rx_filter.bssid)
|
|
seq_puts(seq, "Filter: bssid\n");
|
|
if (priv->bf_control.bcn_count)
|
|
seq_puts(seq, "Filter: beacons\n");
|
|
|
|
if (priv->enable_beacon ||
|
|
priv->mode == NL80211_IFTYPE_AP ||
|
|
priv->mode == NL80211_IFTYPE_ADHOC ||
|
|
priv->mode == NL80211_IFTYPE_MESH_POINT ||
|
|
priv->mode == NL80211_IFTYPE_P2P_GO)
|
|
seq_printf(seq, "Beaconing: %s\n",
|
|
priv->enable_beacon ? "enabled" : "disabled");
|
|
if (priv->ssid_length ||
|
|
priv->mode == NL80211_IFTYPE_AP ||
|
|
priv->mode == NL80211_IFTYPE_ADHOC ||
|
|
priv->mode == NL80211_IFTYPE_MESH_POINT ||
|
|
priv->mode == NL80211_IFTYPE_P2P_GO)
|
|
seq_printf(seq, "SSID: %.*s\n",
|
|
(int)priv->ssid_length, priv->ssid);
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
seq_printf(seq, "EDCA(%d): %d, %d, %d, %d, %d\n", i,
|
|
priv->edca.params[i].cwMin,
|
|
priv->edca.params[i].cwMax,
|
|
priv->edca.params[i].aifns,
|
|
priv->edca.params[i].txOpLimit,
|
|
priv->edca.params[i].maxReceiveLifetime);
|
|
}
|
|
if (priv->join_status == RK960_JOIN_STATUS_STA) {
|
|
static const char *pmMode = "unknown";
|
|
switch (priv->powersave_mode.pmMode) {
|
|
case WSM_PSM_ACTIVE:
|
|
pmMode = "off";
|
|
break;
|
|
case WSM_PSM_PS:
|
|
pmMode = "on";
|
|
break;
|
|
case WSM_PSM_FAST_PS:
|
|
pmMode = "dynamic";
|
|
break;
|
|
}
|
|
seq_printf(seq, "Preamble: %s\n",
|
|
rk960_debug_preamble[priv->association_mode.
|
|
preambleType]);
|
|
seq_printf(seq, "AMPDU spcn: %d\n",
|
|
priv->association_mode.mpduStartSpacing);
|
|
seq_printf(seq, "Basic rate: 0x%.8X\n",
|
|
le32_to_cpu(priv->association_mode.basicRateSet));
|
|
seq_printf(seq, "Bss lost: %d beacons\n",
|
|
priv->bss_params.beaconLostCount);
|
|
seq_printf(seq, "AID: %d\n", priv->bss_params.aid);
|
|
seq_printf(seq, "Rates: 0x%.8X\n",
|
|
priv->bss_params.operationalRateSet);
|
|
seq_printf(seq, "Powersave: %s\n", pmMode);
|
|
}
|
|
seq_printf(seq, "RSSI thold: %d\n", priv->cqm_rssi_thold);
|
|
seq_printf(seq, "RSSI hyst: %d\n", priv->cqm_rssi_hyst);
|
|
seq_printf(seq, "TXFL thold: %d\n", priv->cqm_tx_failure_thold);
|
|
seq_printf(seq, "Linkloss: %d\n", priv->cqm_link_loss_count);
|
|
seq_printf(seq, "Bcnloss: %d\n", priv->cqm_beacon_loss_count);
|
|
|
|
rk960_debug_print_map(seq, priv, "Link map: ", priv->link_id_map);
|
|
rk960_debug_print_map(seq, priv, "Asleep map: ", priv->sta_asleep_mask);
|
|
rk960_debug_print_map(seq, priv, "PSPOLL map: ", priv->pspoll_mask);
|
|
|
|
seq_puts(seq, "\n");
|
|
|
|
for (i = 0; i < RK960_MAX_STA_IN_AP_MODE; ++i) {
|
|
if (priv->link_id_db[i].status) {
|
|
seq_printf(seq, "Link %d: %s, %pM\n",
|
|
i + 1,
|
|
rk960_debug_link_id[priv->link_id_db[i].
|
|
status],
|
|
priv->link_id_db[i].mac);
|
|
}
|
|
}
|
|
|
|
seq_puts(seq, "\n");
|
|
|
|
seq_printf(seq, "Powermgmt: 0x%02x\n", priv->firmware_ps_mode.pmMode);
|
|
|
|
seq_printf(seq, "TXed: %d\n", d->tx);
|
|
seq_printf(seq, "AGG TXed: %d\n", d->tx_agg);
|
|
seq_printf(seq, "MULTI TXed: %d (%d)\n",
|
|
d->tx_multi, d->tx_multi_frames);
|
|
seq_printf(seq, "RXed: %d\n", d->rx);
|
|
seq_printf(seq, "AGG RXed: %d\n", d->rx_agg);
|
|
seq_printf(seq, "TX align: %d\n", d->tx_align);
|
|
seq_printf(seq, "TX TTL: %d\n", d->tx_ttl);
|
|
return 0;
|
|
}
|
|
|
|
static int rk960_status_open_priv(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, &rk960_status_show_priv, inode->i_private);
|
|
}
|
|
|
|
static const struct file_operations fops_status_priv = {
|
|
.open = rk960_status_open_priv,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
static int rk960_tp_show_priv(struct seq_file *seq, void *v)
|
|
{
|
|
int i, j;
|
|
struct rk960_vif *priv = seq->private;
|
|
struct rk960_common *hw_priv = priv->hw_priv;
|
|
struct wsm_rx_tp_info rx_tp_info[RK960_RX_TP_INFO_RATE_NUM];
|
|
int rate_table[] = {
|
|
10, 20, 55, 110, 0, 0,
|
|
60, 90, 120, 180, 240, 360, 480, 540,
|
|
65, 130, 195, 260, 390, 520, 585, 650
|
|
};
|
|
|
|
wsm_get_rx_tp_info(hw_priv, rx_tp_info);
|
|
|
|
for (i = 0; i < RK960_RX_TP_INFO_RATE_NUM; i++) {
|
|
struct wsm_rx_tp_info_s *info = rx_tp_info[i].rx_tp_info_s;
|
|
s8 s_rssi;
|
|
|
|
if (i == 4 || i == 5)
|
|
continue;
|
|
|
|
seq_printf(seq, "Rate %d: frames %d ", rate_table[i],
|
|
rx_tp_info[i].count);
|
|
for (j = 0; j < RK960_RX_TP_INFO_DUMP_NUM; j++) {
|
|
s_rssi = (s8) info->rssi;
|
|
seq_printf(seq,
|
|
" (type %02x size %d rssi %d snr %d ch %d mode %d)",
|
|
info->frame_type, info->size, s_rssi,
|
|
info->snr, info->ch, info->mode);
|
|
}
|
|
seq_printf(seq, "\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int rk960_tp_open_priv(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, &rk960_tp_show_priv, inode->i_private);
|
|
}
|
|
|
|
static const struct file_operations fops_tp_priv = {
|
|
.open = rk960_tp_open_priv,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.owner = THIS_MODULE,
|
|
};
|
|
|
|
#if defined(CONFIG_RK960_USE_STE_EXTENSIONS)
|
|
|
|
static ssize_t rk960_hang_write(struct file *file,
|
|
const char __user * user_buf, size_t count,
|
|
loff_t * ppos)
|
|
{
|
|
struct rk960_vif *priv = file->private_data;
|
|
struct rk960_common *hw_priv = rk960_vifpriv_to_hwpriv(priv);
|
|
char buf[1];
|
|
|
|
if (!count)
|
|
return -EINVAL;
|
|
if (copy_from_user(buf, user_buf, 1))
|
|
return -EFAULT;
|
|
|
|
if (priv->vif) {
|
|
rk960_pm_stay_awake(&hw_priv->pm_state, 3 * HZ);
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
|
|
pr_err("%s: ieee80211_driver_hang_notify\n", __func__);
|
|
#else
|
|
ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL);
|
|
#endif
|
|
} else
|
|
return -ENODEV;
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations fops_hang = {
|
|
.open = rk960_generic_open,
|
|
.write = rk960_hang_write,
|
|
.llseek = default_llseek,
|
|
};
|
|
#endif
|
|
|
|
#define VIF_DEBUGFS_NAME_S 10
|
|
int rk960_debug_init_priv(struct rk960_common *hw_priv, struct rk960_vif *priv)
|
|
{
|
|
int ret = -ENOMEM;
|
|
struct rk960_debug_priv *d;
|
|
char name[VIF_DEBUGFS_NAME_S];
|
|
|
|
if (WARN_ON(!hw_priv))
|
|
return ret;
|
|
|
|
if (WARN_ON(!hw_priv->debug))
|
|
return ret;
|
|
|
|
d = kzalloc(sizeof(struct rk960_debug_priv), GFP_KERNEL);
|
|
priv->debug = d;
|
|
if (WARN_ON(!d))
|
|
return ret;
|
|
|
|
memset(name, 0, VIF_DEBUGFS_NAME_S);
|
|
ret = snprintf(name, VIF_DEBUGFS_NAME_S, "vif_%d", priv->if_id);
|
|
if (WARN_ON(ret < 0))
|
|
goto err;
|
|
|
|
d->debugfs_phy = debugfs_create_dir(name, hw_priv->debug->debugfs_phy);
|
|
if (WARN_ON(!d->debugfs_phy))
|
|
goto err;
|
|
|
|
#if defined(CONFIG_RK960_USE_STE_EXTENSIONS)
|
|
if (WARN_ON(!debugfs_create_file("hang", S_IWUSR, d->debugfs_phy,
|
|
priv, &fops_hang)))
|
|
goto err;
|
|
#endif
|
|
|
|
if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy,
|
|
priv, &fops_status_priv))
|
|
goto err;
|
|
|
|
if (!debugfs_create_file("tp", S_IRUSR, d->debugfs_phy,
|
|
priv, &fops_tp_priv))
|
|
goto err;
|
|
|
|
return 0;
|
|
err:
|
|
priv->debug = NULL;
|
|
debugfs_remove_recursive(d->debugfs_phy);
|
|
kfree(d);
|
|
return ret;
|
|
|
|
}
|
|
|
|
void rk960_debug_release_priv(struct rk960_vif *priv)
|
|
{
|
|
struct rk960_debug_priv *d = priv->debug;
|
|
if (d) {
|
|
priv->debug = NULL;
|
|
kfree(d);
|
|
}
|
|
}
|
|
|
|
int rk960_print_fw_version(struct rk960_common *hw_priv, u8 * buf, size_t len)
|
|
{
|
|
return snprintf(buf, len, "%s %d.%d",
|
|
rk960_debug_fw_types[hw_priv->wsm_caps.firmwareType],
|
|
hw_priv->wsm_caps.firmwareVersion,
|
|
hw_priv->wsm_caps.firmwareBuildNumber);
|
|
}
|
|
|
|
#ifdef DUMP_TXRX_MAC_FRAME_INFO
|
|
|
|
#include <net/cfg80211.h>
|
|
#include <net/ip.h>
|
|
#include <linux/tcp.h>
|
|
#include <linux/etherdevice.h>
|
|
|
|
#define CIPHER_TYPE_WEP40 0
|
|
#define CIPHER_TYPE_WEP104 1
|
|
#define CIPHER_TYPE_TKIP 2
|
|
#define CIPHER_TYPE_CCMP 3
|
|
#define CIPHER_TYPE_WAPI 4
|
|
|
|
static int g_cipher_type = CIPHER_TYPE_TKIP;
|
|
int ieee80211_crypt_hdrlen(u16 fc)
|
|
{
|
|
int hdrlen = 0;
|
|
|
|
if (ieee80211_has_protected(fc)) {
|
|
switch (g_cipher_type) {
|
|
case CIPHER_TYPE_WEP40:
|
|
case CIPHER_TYPE_WEP104:
|
|
hdrlen = 4; //WEP_IV_LEN;
|
|
break;
|
|
case CIPHER_TYPE_TKIP:
|
|
case CIPHER_TYPE_CCMP:
|
|
hdrlen = 8;
|
|
break;
|
|
}
|
|
}
|
|
return hdrlen;
|
|
}
|
|
|
|
static int ieee8022_ll_hdrlen(u8 * payload, u16 ethertype)
|
|
{
|
|
if ((ether_addr_equal(payload, rfc1042_header) &&
|
|
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
|
ether_addr_equal(payload, bridge_tunnel_header)) {
|
|
return 8;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 802.11 frame struct (for example ICMP):
|
|
*
|
|
* | 802.11 header | crypt header | 802.2 LL header | IP header| ICMP |
|
|
*
|
|
* option option
|
|
*/
|
|
static void dump_ip_info(u8 * data, int len, u8 * str, int tx)
|
|
{
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
|
|
u16 fc = hdr->frame_control;
|
|
|
|
if (ieee80211_is_data(fc) /*&&
|
|
is_unicast_ether_addr(ieee80211_get_DA(hdr)) */ ) {
|
|
int offset, ieee8022_hdrlen;
|
|
u8 *ieee8022_payload;
|
|
int ethertype, n;
|
|
struct iphdr *ip;
|
|
|
|
offset = ieee80211_hdrlen(fc); /* 802.11 header */
|
|
if (!tx)
|
|
offset += ieee80211_crypt_hdrlen(fc); /* crypt header */
|
|
|
|
if (offset >= len) {
|
|
return;
|
|
}
|
|
|
|
ieee8022_payload = data + offset; /* ieee802.2 ll header */
|
|
ethertype = (ieee8022_payload[6] << 8) | ieee8022_payload[7];
|
|
ieee8022_hdrlen =
|
|
ieee8022_ll_hdrlen(ieee8022_payload, ethertype);
|
|
|
|
n = sprintf(str, "ethertype %04x ", ethertype);
|
|
str += n;
|
|
if (ieee8022_hdrlen && ethertype == ETH_P_IP /* &&
|
|
ethertype == ETH_P_IPV6 */ ) {
|
|
offset += ieee8022_hdrlen;
|
|
ip = (struct iphdr *)(data + offset); /* IP header */
|
|
n = sprintf(str, "protocol %03d %pI4 -> %pI4 ",
|
|
ip->protocol, &(ip->saddr), &(ip->daddr));
|
|
str += n;
|
|
if (ip->protocol == IPPROTO_UDP) {
|
|
struct udphdr *uh =
|
|
(struct udphdr *)((u8 *) ip + ip->ihl * 4);
|
|
|
|
sprintf(str, "UDP Port %d -> %d ",
|
|
ntohs(uh->source), ntohs(uh->dest));
|
|
} else if (ip->protocol == IPPROTO_TCP) {
|
|
struct tcphdr *th =
|
|
(struct tcphdr *)((u8 *) ip + ip->ihl * 4);
|
|
|
|
sprintf(str, "TCP Port %d -> %d ",
|
|
ntohs(th->source), ntohs(th->dest));
|
|
} else if (ip->protocol == IPPROTO_ICMP) {
|
|
u8 *icmp_payload = (u8 *) ip + ip->ihl * 4;
|
|
u16 *seq = (u16 *) & icmp_payload[6];
|
|
|
|
if (icmp_payload[0] == 0x00) { // Replay
|
|
sprintf(str, "icmp rep %d\n",
|
|
ntohs(*seq));
|
|
} else if (icmp_payload[0] == 0x08) { // Request
|
|
sprintf(str, "icmp req %d\n",
|
|
ntohs(*seq));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum p2p_action_frame_type {
|
|
P2P_GO_NEG_REQ = 0,
|
|
P2P_GO_NEG_RESP = 1,
|
|
P2P_GO_NEG_CONF = 2,
|
|
P2P_INVITATION_REQ = 3,
|
|
P2P_INVITATION_RESP = 4,
|
|
P2P_DEV_DISC_REQ = 5,
|
|
P2P_DEV_DISC_RESP = 6,
|
|
P2P_PROV_DISC_REQ = 7,
|
|
P2P_PROV_DISC_RESP = 8
|
|
};
|
|
|
|
static inline u32 WPA_GET_BE32(const u8 * a)
|
|
{
|
|
return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
|
|
}
|
|
|
|
static char *dump_action_type(struct ieee80211_hdr *hdr, int tx)
|
|
{
|
|
u8 *payload;
|
|
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr;
|
|
u8 *category;
|
|
|
|
category = (u8 *) & mgmt->u.action.category;
|
|
if (!tx) {
|
|
category += ieee80211_crypt_hdrlen(mgmt->frame_control);
|
|
}
|
|
|
|
payload = (u8 *) hdr + sizeof(struct ieee80211_hdr_3addr);
|
|
|
|
#define WLAN_ACTION_PUBLIC 4
|
|
#define WLAN_PA_VENDOR_SPECIFIC 9
|
|
#define P2P_IE_VENDOR_TYPE 0x506f9a09
|
|
|
|
if (ieee80211_is_action(mgmt->frame_control) &&
|
|
*category == WLAN_CATEGORY_BACK) {
|
|
switch (*(category + 1)) {
|
|
case WLAN_ACTION_ADDBA_REQ:
|
|
return "ADDBA_REQ";
|
|
case WLAN_ACTION_ADDBA_RESP:
|
|
return "ADDBA_RESP";
|
|
case WLAN_ACTION_DELBA:
|
|
return "ADDBA_DELBA";
|
|
default:
|
|
break;
|
|
}
|
|
} else if (mgmt->u.action.category == WLAN_ACTION_PUBLIC) {
|
|
switch (payload[1]) {
|
|
case WLAN_PA_VENDOR_SPECIFIC:
|
|
payload += 2;
|
|
if (WPA_GET_BE32(payload) != P2P_IE_VENDOR_TYPE)
|
|
return "";
|
|
|
|
payload += 4;
|
|
switch (payload[0]) {
|
|
case P2P_GO_NEG_REQ:
|
|
return "P2P_GO_NEG_REQ";
|
|
case P2P_GO_NEG_RESP:
|
|
return "P2P_GO_NEG_RESP";
|
|
case P2P_GO_NEG_CONF:
|
|
return "P2P_GO_NEG_CONF";
|
|
case P2P_INVITATION_REQ:
|
|
return "P2P_INVITATION_REQ";
|
|
case P2P_INVITATION_RESP:
|
|
return "P2P_INVITATION_RESP";
|
|
case P2P_PROV_DISC_REQ:
|
|
return "P2P_PROV_DISC_REQ";
|
|
case P2P_PROV_DISC_RESP:
|
|
return "P2P_PROV_DISC_RESP";
|
|
case P2P_DEV_DISC_REQ:
|
|
return "P2P_DEV_DISC_REQ";
|
|
case P2P_DEV_DISC_RESP:
|
|
return "P2P_DEV_DISC_RESP";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
void dump_ieee80211_hdr_info(unsigned char *data, int len, int tx, s8 rssi)
|
|
{
|
|
int n;
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
|
|
char direct_str[512];
|
|
u8 *DA = ieee80211_get_DA(hdr);
|
|
u8 *SA = ieee80211_get_SA(hdr);
|
|
int retr = (hdr->frame_control & 0x0800) >> 11;
|
|
int pm = (hdr->frame_control & 0x1000) >> 12;
|
|
|
|
if (!(rk960_debug_level & DEBUG_LEVEL_DEBUG)) {
|
|
return;
|
|
}
|
|
//print_hex_dump(KERN_INFO, " ", DUMP_PREFIX_NONE, 16, 1, data, len, 1);
|
|
|
|
/* at here: tx protected frame have no ccmp header,
|
|
rx protected frame have ccmp header, so need to skip ccmp header
|
|
with rx frame when parse */
|
|
|
|
n = sprintf(direct_str,
|
|
"%s fc %04x sn %04d retr %d pm %d len %04d %pM -> %pM rssi %d ",
|
|
tx ? "tx" : "rx", cpu_to_le16(hdr->frame_control),
|
|
hdr->seq_ctrl >> 4, retr, pm, len, SA, DA, rssi);
|
|
dump_ip_info(data, len, &direct_str[n], tx);
|
|
|
|
if (hdr != NULL) {
|
|
//RK960_DEBUG_UMACIF("%s\n", __func__);
|
|
if (ieee80211_is_mgmt(hdr->frame_control)) {
|
|
if (ieee80211_is_assoc_req(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s assoc req\n", direct_str);
|
|
} else if (ieee80211_is_assoc_resp(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s assoc resp\n", direct_str);
|
|
} else if (ieee80211_is_reassoc_req(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s reassoc req\n", direct_str);
|
|
} else
|
|
if (ieee80211_is_reassoc_resp(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s reassoc resp\n",
|
|
direct_str);
|
|
} else if (ieee80211_is_probe_req(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s probe req\n", direct_str);
|
|
} else if (ieee80211_is_probe_resp(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s probe resp\n", direct_str);
|
|
} else if (ieee80211_is_beacon(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s beacon\n", direct_str);
|
|
} else if (ieee80211_is_atim(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s atim\n", direct_str);
|
|
} else if (ieee80211_is_disassoc(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s disassoc\n", direct_str);
|
|
} else if (ieee80211_is_auth(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s auth\n", direct_str);
|
|
} else if (ieee80211_is_deauth(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s deauth\n", direct_str);
|
|
} else if (ieee80211_is_action(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s action %s\n", direct_str,
|
|
dump_action_type(hdr, tx));
|
|
} else {
|
|
RK960_INFO_TXRX("%s mgmt\n", direct_str);
|
|
}
|
|
} else if (ieee80211_is_ctl(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s ctl\n", direct_str);
|
|
} else if (ieee80211_is_data(hdr->frame_control)) {
|
|
RK960_INFO_TXRX("%s data\n", direct_str);
|
|
} else {
|
|
RK960_INFO_TXRX("%s unknow\n", direct_str);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
void dump_ieee80211_hdr_info(unsigned char *data, int len, int tx, s8 rssi)
|
|
{
|
|
}
|
|
#endif
|