Merge branch 'master' of git://nbd.name/openwrt
[openwrt.git] / package / kernel / mac80211 / patches / 440-ath5k_channel_bw_debugfs.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
This adds a bwmode debugfs file which can be used to set alternate
channel operating bandwidths.  Only tested with AR5413 and only at
5 and 20 mhz channels.
 
Signed-off-by: Pat Erley <pat-lkml at erley.org>
---
Other devices will need to be added to the switch in  write_file_bwmode
 
drivers/net/wireless/ath/ath5k/debug.c |   86 ++++++++++++++++++++++++++++++++
 1 files changed, 86 insertions(+), 0 deletions(-)
 
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -821,6 +821,97 @@ static const struct file_operations fops
        .llseek = default_llseek,
 };
 
+/* debugfs: bwmode */
+
+static ssize_t read_file_bwmode(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_hw *ah = file->private_data;
+       char buf[15];
+       unsigned int len = 0;
+
+       int cur_ah_bwmode = ah->ah_bwmode_debug;
+
+#define print_selected(MODE, LABEL) \
+       if (cur_ah_bwmode == MODE) \
+               len += snprintf(buf+len, sizeof(buf)-len, "[%s]", LABEL); \
+       else \
+               len += snprintf(buf+len, sizeof(buf)-len, "%s", LABEL); \
+       len += snprintf(buf+len, sizeof(buf)-len, " ");
+
+       print_selected(AR5K_BWMODE_5MHZ, "5");
+       print_selected(AR5K_BWMODE_10MHZ, "10");
+       print_selected(AR5K_BWMODE_DEFAULT, "20");
+       print_selected(AR5K_BWMODE_40MHZ, "40");
+#undef print_selected
+
+       len += snprintf(buf+len, sizeof(buf)-len, "\n");
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_bwmode(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_hw *ah = file->private_data;
+       char buf[3];
+       int bw = 20;
+       int tobwmode = AR5K_BWMODE_DEFAULT;
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
+
+       /* TODO: Add check for active interface */
+
+       if(strncmp(buf, "5", 1) == 0 ) {
+               tobwmode = AR5K_BWMODE_5MHZ;
+               bw = 5;
+       } else if ( strncmp(buf, "10", 2) == 0 ) {
+               tobwmode = AR5K_BWMODE_10MHZ;
+               bw = 10;
+       } else if ( strncmp(buf, "20", 2) == 0 ) {
+               tobwmode = AR5K_BWMODE_DEFAULT;
+               bw = 20;
+       } else if ( strncmp(buf, "40", 2) == 0 ) {
+               tobwmode = AR5K_BWMODE_40MHZ;
+               bw = 40;
+       } else
+               return -EINVAL;
+
+       ATH5K_INFO(ah, "Changing to %imhz channel width[%i]\n",
+               bw, tobwmode);
+
+       switch (ah->ah_radio) {
+       /* TODO: only define radios that actually support 5/10mhz channels */
+       case AR5K_RF5413:
+       case AR5K_RF5110:
+       case AR5K_RF5111:
+       case AR5K_RF5112:
+       case AR5K_RF2413:
+       case AR5K_RF2316:
+       case AR5K_RF2317:
+       case AR5K_RF2425:
+               if(ah->ah_bwmode_debug != tobwmode) {
+                       mutex_lock(&ah->lock);
+                       ah->ah_bwmode = tobwmode;
+                       ah->ah_bwmode_debug = tobwmode;
+                       mutex_unlock(&ah->lock);
+               }
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return count;
+}
+
+static const struct file_operations fops_bwmode = {
+       .read = read_file_bwmode,
+       .write = write_file_bwmode,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
 
 /* debugfs: queues etc */
 
@@ -914,6 +1005,9 @@ ath5k_debug_init_device(struct ath5k_hw 
        debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
                            &fops_beacon);
 
+       debugfs_create_file("bwmode", S_IWUSR | S_IRUSR, phydir, ah,
+                           &fops_bwmode);
+
        debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset);
 
        debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah,
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1369,6 +1369,7 @@ struct ath5k_hw {
        u8                      ah_coverage_class;
        bool                    ah_ack_bitrate_high;
        u8                      ah_bwmode;
+       u8                      ah_bwmode_debug;
        bool                    ah_short_slot;
 
        /* Antenna Control */
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru
                return -EINVAL;
        }
 
+       if (ah->ah_bwmode_debug != AR5K_BWMODE_DEFAULT)
+               ah->ah_bwmode = ah->ah_bwmode_debug;
+
        /*
         * To switch channels clear any pending DMA operations;
         * wait long enough for the RX fifo to drain, reset the
 
comments