xref: /openwifi/driver/sdrctl_intf.c (revision db8c69b6aa4437ad8f8929a3c5137b8df20faeea)
1 // Author: Xianjun Jiao, Michael Mehari, Wei Liu
2 // SPDX-FileCopyrightText: 2019 UGent
3 // SPDX-License-Identifier: AGPL-3.0-or-later
4 
openwifi_testmode_cmd(struct ieee80211_hw * hw,struct ieee80211_vif * vif,void * data,int len)5 static int openwifi_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len)
6 {
7 	struct openwifi_priv *priv = hw->priv;
8 	struct nlattr *tb[OPENWIFI_ATTR_MAX + 1];
9 	struct sk_buff *skb;
10 	int err;
11 	u32 tmp=-1, reg_cat, reg_addr, reg_val, reg_addr_idx, tsft_high, tsft_low;
12 	int tmp_int;
13 
14 	err = nla_parse(tb, OPENWIFI_ATTR_MAX, data, len, openwifi_testmode_policy, NULL);
15 	if (err)
16 		return err;
17 
18 	if (!tb[OPENWIFI_ATTR_CMD])
19 		return -EINVAL;
20 
21 	switch (nla_get_u32(tb[OPENWIFI_ATTR_CMD])) {
22 	case OPENWIFI_CMD_SET_GAP:
23 		if (!tb[OPENWIFI_ATTR_GAP])
24 			return -EINVAL;
25 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_GAP]);
26 		printk("%s XPU_REG_CSMA_CFG_write %08x (Check openwifi_conf_tx() in sdr.c to understand)\n", sdr_compatible_str, tmp);
27 		xpu_api->XPU_REG_CSMA_CFG_write(tmp); // unit us
28 		return 0;
29 	case OPENWIFI_CMD_GET_GAP:
30 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
31 		if (!skb)
32 			return -ENOMEM;
33 		tmp = xpu_api->XPU_REG_CSMA_CFG_read();
34 		if (nla_put_u32(skb, OPENWIFI_ATTR_GAP, tmp))
35 			goto nla_put_failure;
36 		return cfg80211_testmode_reply(skb);
37 	case OPENWIFI_CMD_SET_SLICE_IDX:
38 		if (!tb[OPENWIFI_ATTR_SLICE_IDX])
39 			return -EINVAL;
40 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_IDX]);
41 		printk("%s set openwifi slice_idx in hex: %08x\n", sdr_compatible_str, tmp);
42 		if (tmp == MAX_NUM_HW_QUEUE) {
43 			printk("%s set openwifi slice_idx reset all queue counter.\n", sdr_compatible_str);
44 			xpu_api->XPU_REG_MULTI_RST_write(1<<7); //bit7 reset the counter for all queues at the same time
45 			xpu_api->XPU_REG_MULTI_RST_write(0<<7);
46 		} else {
47 			priv->slice_idx = tmp;
48 		}
49 		return 0;
50 	case OPENWIFI_CMD_GET_SLICE_IDX:
51 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
52 		if (!skb)
53 			return -ENOMEM;
54 		tmp = priv->slice_idx;
55 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_IDX, tmp))
56 			goto nla_put_failure;
57 		printk("%s get openwifi slice_idx in hex: %08x\n", sdr_compatible_str, tmp);
58 		return cfg80211_testmode_reply(skb);
59 	case OPENWIFI_CMD_SET_ADDR:
60 		if (!tb[OPENWIFI_ATTR_ADDR])
61 			return -EINVAL;
62 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_ADDR]);
63 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
64 			printk("%s set openwifi slice_target_mac_addr(low32) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
65 			return -EOPNOTSUPP;
66 		} else {
67 			printk("%s set openwifi slice_target_mac_addr(low32) in hex: %08x to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
68 			priv->dest_mac_addr_queue_map[priv->slice_idx] = reverse32(tmp);
69 		}
70 		return 0;
71 	case OPENWIFI_CMD_GET_ADDR:
72 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
73 		if (!skb)
74 			return -ENOMEM;
75 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
76 			tmp = -1;
77 		} else {
78 			tmp = reverse32(priv->dest_mac_addr_queue_map[priv->slice_idx]);
79 		}
80 		if (nla_put_u32(skb, OPENWIFI_ATTR_ADDR, tmp))
81 			goto nla_put_failure;
82 		printk("%s get openwifi slice_target_mac_addr(low32) in hex: %08x of slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
83 		return cfg80211_testmode_reply(skb);
84 
85 	case OPENWIFI_CMD_SET_SLICE_TOTAL:
86 		if (!tb[OPENWIFI_ATTR_SLICE_TOTAL])
87 			return -EINVAL;
88 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_TOTAL]);
89 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
90 			printk("%s set SLICE_TOTAL(duration) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
91 			return -EOPNOTSUPP;
92 		} else {
93 			printk("%s set SLICE_TOTAL(duration) %d usec to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
94 			xpu_api->XPU_REG_SLICE_COUNT_TOTAL_write((priv->slice_idx<<20)|tmp);
95 		}
96 		return 0;
97 	case OPENWIFI_CMD_GET_SLICE_TOTAL:
98 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
99 		if (!skb)
100 			return -ENOMEM;
101 		tmp = (xpu_api->XPU_REG_SLICE_COUNT_TOTAL_read());
102 		printk("%s get SLICE_TOTAL(duration) %d usec of slice %d\n", sdr_compatible_str, tmp&0xFFFFF, tmp>>20);
103 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_TOTAL, tmp))
104 			goto nla_put_failure;
105 		return cfg80211_testmode_reply(skb);
106 
107 	case OPENWIFI_CMD_SET_SLICE_START:
108 		if (!tb[OPENWIFI_ATTR_SLICE_START])
109 			return -EINVAL;
110 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_START]);
111 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
112 			printk("%s set SLICE_START(duration) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
113 			return -EOPNOTSUPP;
114 		} else {
115 			printk("%s set SLICE_START(duration) %d usec to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
116 			xpu_api->XPU_REG_SLICE_COUNT_START_write((priv->slice_idx<<20)|tmp);
117 		}
118 		return 0;
119 	case OPENWIFI_CMD_GET_SLICE_START:
120 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
121 		if (!skb)
122 			return -ENOMEM;
123 		tmp = (xpu_api->XPU_REG_SLICE_COUNT_START_read());
124 		printk("%s get SLICE_START(duration) %d usec of slice %d\n", sdr_compatible_str, tmp&0xFFFFF, tmp>>20);
125 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_START, tmp))
126 			goto nla_put_failure;
127 		return cfg80211_testmode_reply(skb);
128 
129 	case OPENWIFI_CMD_SET_SLICE_END:
130 		if (!tb[OPENWIFI_ATTR_SLICE_END])
131 			return -EINVAL;
132 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_END]);
133 		if (priv->slice_idx>=MAX_NUM_HW_QUEUE) {
134 			printk("%s set SLICE_END(duration) WARNING: current slice idx %d is invalid!\n", sdr_compatible_str, priv->slice_idx);
135 			return -EOPNOTSUPP;
136 		} else {
137 			printk("%s set SLICE_END(duration) %d usec to slice %d\n", sdr_compatible_str, tmp, priv->slice_idx);
138 			xpu_api->XPU_REG_SLICE_COUNT_END_write((priv->slice_idx<<20)|tmp);
139 		}
140 		return 0;
141 	case OPENWIFI_CMD_GET_SLICE_END:
142 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
143 		if (!skb)
144 			return -ENOMEM;
145 		tmp = (xpu_api->XPU_REG_SLICE_COUNT_END_read());
146 		printk("%s get SLICE_END(duration) %d usec of slice %d\n", sdr_compatible_str, tmp&0xFFFFF, tmp>>20);
147 		if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_END, tmp))
148 			goto nla_put_failure;
149 		return cfg80211_testmode_reply(skb);
150 
151 	// case OPENWIFI_CMD_SET_SLICE_TOTAL1:
152 	// 	if (!tb[OPENWIFI_ATTR_SLICE_TOTAL1])
153 	// 		return -EINVAL;
154 	// 	tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_TOTAL1]);
155 	// 	printk("%s set SLICE_TOTAL1(duration) to %d usec\n", sdr_compatible_str, tmp);
156 	// 	// xpu_api->XPU_REG_SLICE_COUNT_TOTAL1_write(tmp);
157 	// 	return 0;
158 	// case OPENWIFI_CMD_GET_SLICE_TOTAL1:
159 	// 	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
160 	// 	if (!skb)
161 	// 		return -ENOMEM;
162 	// 	// tmp = (xpu_api->XPU_REG_SLICE_COUNT_TOTAL1_read());
163 	// 	if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_TOTAL1, tmp))
164 	// 		goto nla_put_failure;
165 	// 	return cfg80211_testmode_reply(skb);
166 
167 	// case OPENWIFI_CMD_SET_SLICE_START1:
168 	// 	if (!tb[OPENWIFI_ATTR_SLICE_START1])
169 	// 		return -EINVAL;
170 	// 	tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_START1]);
171 	// 	printk("%s set SLICE_START1(duration) to %d usec\n", sdr_compatible_str, tmp);
172 	// 	// xpu_api->XPU_REG_SLICE_COUNT_START1_write(tmp);
173 	// 	return 0;
174 	// case OPENWIFI_CMD_GET_SLICE_START1:
175 	// 	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
176 	// 	if (!skb)
177 	// 		return -ENOMEM;
178 	// 	// tmp = (xpu_api->XPU_REG_SLICE_COUNT_START1_read());
179 	// 	if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_START1, tmp))
180 	// 		goto nla_put_failure;
181 	// 	return cfg80211_testmode_reply(skb);
182 
183 	// case OPENWIFI_CMD_SET_SLICE_END1:
184 	// 	if (!tb[OPENWIFI_ATTR_SLICE_END1])
185 	// 		return -EINVAL;
186 	// 	tmp = nla_get_u32(tb[OPENWIFI_ATTR_SLICE_END1]);
187 	// 	printk("%s set SLICE_END1(duration) to %d usec\n", sdr_compatible_str, tmp);
188 	// 	// xpu_api->XPU_REG_SLICE_COUNT_END1_write(tmp);
189 	// 	return 0;
190 	// case OPENWIFI_CMD_GET_SLICE_END1:
191 	// 	skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
192 	// 	if (!skb)
193 	// 		return -ENOMEM;
194 	// 	// tmp = (xpu_api->XPU_REG_SLICE_COUNT_END1_read());
195 	// 	if (nla_put_u32(skb, OPENWIFI_ATTR_SLICE_END1, tmp))
196 	// 		goto nla_put_failure;
197 	// 	return cfg80211_testmode_reply(skb);
198 
199 	case OPENWIFI_CMD_SET_RSSI_TH:
200 		if (!tb[OPENWIFI_ATTR_RSSI_TH])
201 			return -EINVAL;
202 		tmp = nla_get_u32(tb[OPENWIFI_ATTR_RSSI_TH]);
203 		// printk("%s set RSSI_TH to %d\n", sdr_compatible_str, tmp);
204 		// xpu_api->XPU_REG_LBT_TH_write(tmp);
205 		// return 0;
206 		printk("%s WARNING Please use command: sdrctl dev sdr0 set reg drv_xpu 0 reg_value! (1~2047, 0 means AUTO)!\n", sdr_compatible_str);
207 		return -EOPNOTSUPP;
208 	case OPENWIFI_CMD_GET_RSSI_TH:
209 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
210 		if (!skb)
211 			return -ENOMEM;
212 		tmp_int = rssi_half_db_to_rssi_dbm(xpu_api->XPU_REG_LBT_TH_read(), priv->rssi_correction); //rssi_dbm
213 		tmp = (-tmp_int);
214 		if (nla_put_u32(skb, OPENWIFI_ATTR_RSSI_TH, tmp))
215 			goto nla_put_failure;
216 		return cfg80211_testmode_reply(skb);
217 
218 	case OPENWIFI_CMD_SET_TSF:
219 		printk("openwifi_set_tsf_1");
220 		if ( (!tb[OPENWIFI_ATTR_HIGH_TSF]) || (!tb[OPENWIFI_ATTR_LOW_TSF]) )
221 				return -EINVAL;
222 		printk("openwifi_set_tsf_2");
223 		tsft_high = nla_get_u32(tb[OPENWIFI_ATTR_HIGH_TSF]);
224 		tsft_low  = nla_get_u32(tb[OPENWIFI_ATTR_LOW_TSF]);
225 		xpu_api->XPU_REG_TSF_LOAD_VAL_write(tsft_high,tsft_low);
226 		printk("%s openwifi_set_tsf: %08x%08x\n", sdr_compatible_str,tsft_high,tsft_low);
227 		return 0;
228 
229 	case REG_CMD_SET:
230 		if ( (!tb[REG_ATTR_ADDR]) || (!tb[REG_ATTR_VAL]) )
231 			return -EINVAL;
232 		reg_addr = nla_get_u32(tb[REG_ATTR_ADDR]);
233 		reg_val  = nla_get_u32(tb[REG_ATTR_VAL]);
234 		reg_cat = ((reg_addr>>16)&0xFFFF);
235 		reg_addr = (reg_addr&0xFFFF);
236 		reg_addr_idx = (reg_addr>>2);
237 		printk("%s recv set cmd reg cat %d addr %08x val %08x idx %d\n", sdr_compatible_str, reg_cat, reg_addr, reg_val, reg_addr_idx);
238 		if (reg_cat==SDRCTL_REG_CAT_RF) {
239 			// printk("%s WARNING reg cat 1 (rf) is not supported yet!\n", sdr_compatible_str);
240 			// return -EOPNOTSUPP;
241 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_RF_REG) {
242 				priv->rf_reg_val[reg_addr_idx]=reg_val;
243 				if (reg_addr_idx==RF_TX_REG_IDX_ATT) {//change the tx ON att (if a RF chain is ON)
244 					tmp = ad9361_get_tx_atten(priv->ad9361_phy, 1);
245 					printk("%s ad9361_get_tx_atten ant0 %d\n",sdr_compatible_str, tmp);
246 					if (tmp<AD9361_RADIO_OFF_TX_ATT) {
247 						err = ad9361_set_tx_atten(priv->ad9361_phy, AD9361_RADIO_ON_TX_ATT+reg_val, true, false, true);
248 						if (err < 0) {
249 							printk("%s WARNING ad9361_set_tx_atten ant0 %d FAIL!\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
250 							return -EIO;
251 						} else {
252 							printk("%s ad9361_set_tx_atten ant0 %d OK\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
253 						}
254 					}
255 					tmp = ad9361_get_tx_atten(priv->ad9361_phy, 2);
256 					printk("%s ad9361_get_tx_atten ant1 %d\n",sdr_compatible_str, tmp);
257 					if (tmp<AD9361_RADIO_OFF_TX_ATT) {
258 						err = ad9361_set_tx_atten(priv->ad9361_phy, AD9361_RADIO_ON_TX_ATT+reg_val, false, true, true);
259 						if (err < 0) {
260 							printk("%s WARNING ad9361_set_tx_atten ant1 %d FAIL!\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
261 							return -EIO;
262 						} else {
263 							printk("%s ad9361_set_tx_atten ant1 %d OK\n",sdr_compatible_str, AD9361_RADIO_ON_TX_ATT+reg_val);
264 						}
265 					}
266 				} else if (reg_addr_idx==RF_TX_REG_IDX_FREQ_MHZ) { // apply the tx fo
267 					clk_set_rate(priv->ad9361_phy->clks[TX_RFPLL], ( ((u64)1000000ull)*((u64)priv->rf_reg_val[RF_TX_REG_IDX_FREQ_MHZ]) )>>1 );
268 					ad9361_tx_calibration(priv, priv->rf_reg_val[RF_TX_REG_IDX_FREQ_MHZ]);
269 					printk("%s clk_set_rate TX_RFPLL %dMHz done\n",sdr_compatible_str, priv->rf_reg_val[RF_TX_REG_IDX_FREQ_MHZ]);
270 				} else if (reg_addr_idx==RF_RX_REG_IDX_FREQ_MHZ) { // apply the rx fo
271 					clk_set_rate(priv->ad9361_phy->clks[RX_RFPLL], ( ((u64)1000000ull)*((u64)priv->rf_reg_val[RF_RX_REG_IDX_FREQ_MHZ]) )>>1 );
272 					openwifi_rf_rx_update_after_tuning(priv, priv->rf_reg_val[RF_RX_REG_IDX_FREQ_MHZ]);
273 					printk("%s clk_set_rate RX_RFPLL %dMHz done\n",sdr_compatible_str, priv->rf_reg_val[RF_RX_REG_IDX_FREQ_MHZ]);
274 				}
275 			} else {
276 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
277 				return -EOPNOTSUPP;
278 			}
279 		}
280 		else if (reg_cat==SDRCTL_REG_CAT_RX_INTF)
281 			rx_intf_api->reg_write(reg_addr,reg_val);
282 		else if (reg_cat==SDRCTL_REG_CAT_TX_INTF)
283 			tx_intf_api->reg_write(reg_addr,reg_val);
284 		else if (reg_cat==SDRCTL_REG_CAT_RX)
285 			openofdm_rx_api->reg_write(reg_addr,reg_val);
286 		else if (reg_cat==SDRCTL_REG_CAT_TX)
287 			openofdm_tx_api->reg_write(reg_addr,reg_val);
288 		else if (reg_cat==SDRCTL_REG_CAT_XPU)
289 			xpu_api->reg_write(reg_addr,reg_val);
290 		else if (reg_cat==SDRCTL_REG_CAT_DRV_RX) {
291 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
292 				if (reg_addr_idx==DRV_RX_REG_IDX_ANT_CFG) {
293 					tmp = openwifi_set_antenna(hw, (priv->drv_tx_reg_val[reg_addr_idx]==0?1:2), (reg_val==0?1:2));
294 					if (tmp) {
295 						printk("%s WARNING openwifi_set_antenna return %d!\n", sdr_compatible_str, tmp);
296 						return -EIO;
297 					} else {
298 						priv->drv_rx_reg_val[reg_addr_idx]=reg_val;
299 					}
300 				} else {
301 					priv->drv_rx_reg_val[reg_addr_idx]=reg_val;
302 					if (reg_addr_idx==DRV_RX_REG_IDX_DEMOD_TH) {
303 						openofdm_rx_api->OPENOFDM_RX_REG_POWER_THRES_write((OPENOFDM_RX_DC_RUNNING_SUM_TH_INIT<<16)|rssi_dbm_to_rssi_half_db((reg_val==0?OPENOFDM_RX_RSSI_DBM_TH_DEFAULT:(-reg_val)), priv->rssi_correction));
304 					}
305 				}
306 			} else {
307 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
308 				return -EOPNOTSUPP;
309 			}
310 		}
311 		else if (reg_cat==SDRCTL_REG_CAT_DRV_TX) {
312 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
313 				if ((reg_addr_idx == DRV_TX_REG_IDX_RATE || reg_addr_idx == DRV_TX_REG_IDX_RATE_HT) &&
314 				    (reg_val != 0 && (!((reg_val&0xF)>=4 && (reg_val&0xF)<=11)) ) ) {
315 					printk("%s WARNING rate override value should be 0 or 4~11!\n", sdr_compatible_str);
316 					return -EOPNOTSUPP;
317 				} else {
318 					if (reg_addr_idx==DRV_TX_REG_IDX_ANT_CFG) {
319 						tmp = openwifi_set_antenna(hw, reg_val+1, priv->drv_rx_reg_val[reg_addr_idx]+1);
320 						if (tmp) {
321 							printk("%s WARNING openwifi_set_antenna return %d!\n", sdr_compatible_str, tmp);
322 							return -EIO;
323 						} else {
324 							priv->drv_tx_reg_val[reg_addr_idx]=reg_val;
325 						}
326 					} else {
327 						priv->drv_tx_reg_val[reg_addr_idx]=reg_val;
328 					}
329 				}
330 			} else {
331 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
332 				return -EOPNOTSUPP;
333 			}
334 		}
335 		else if (reg_cat==SDRCTL_REG_CAT_DRV_XPU) {
336 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
337 				priv->drv_xpu_reg_val[reg_addr_idx]=reg_val;
338 				if (reg_addr_idx==DRV_XPU_REG_IDX_LBT_TH) {
339 					if (reg_val) {
340 						tmp_int = (-reg_val); // rssi_dbm
341 						tmp = rssi_dbm_to_rssi_half_db(tmp_int, priv->rssi_correction);
342 						xpu_api->XPU_REG_LBT_TH_write( tmp );
343 						printk("%s override FPGA LBT threshold to %d(%ddBm). The last_auto_fpga_lbt_th %d(%ddBm). rssi corr %d (%d/%dMHz)\n", sdr_compatible_str, tmp, tmp_int, priv->last_auto_fpga_lbt_th, rssi_half_db_to_rssi_dbm(priv->last_auto_fpga_lbt_th, priv->rssi_correction), priv->rssi_correction, priv->actual_tx_lo, priv->actual_rx_lo);
344 					} else {
345 						xpu_api->XPU_REG_LBT_TH_write(priv->last_auto_fpga_lbt_th);
346 						printk("%s Restore last_auto_fpga_lbt_th %d(%ddBm) to FPGA. ad9361_rf_set_channel will take control. rssi corr %d (%d/%dMHz)\n", sdr_compatible_str, priv->last_auto_fpga_lbt_th, rssi_half_db_to_rssi_dbm(priv->last_auto_fpga_lbt_th, priv->rssi_correction), priv->rssi_correction, priv->actual_tx_lo, priv->actual_rx_lo);
347 					}
348 				}
349 			} else {
350 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
351 				return -EOPNOTSUPP;
352 			}
353 		}
354 		else {
355 			printk("%s WARNING reg cat %d is not supported yet!\n", sdr_compatible_str, reg_cat);
356 			return -EOPNOTSUPP;
357 		}
358 
359 		return 0;
360 	case REG_CMD_GET:
361 		skb = (struct sk_buff *)cfg80211_testmode_alloc_reply_skb(hw->wiphy, nla_total_size(sizeof(u32)));
362 		if (!skb)
363 			return -ENOMEM;
364 		reg_addr = nla_get_u32(tb[REG_ATTR_ADDR]);
365 		reg_cat = ((reg_addr>>16)&0xFFFF);
366 		reg_addr = (reg_addr&0xFFFF);
367 		reg_addr_idx = (reg_addr>>2);
368 		printk("%s recv get cmd reg cat %d addr %08x idx %d\n", sdr_compatible_str, reg_cat, reg_addr, reg_addr_idx);
369 		if (reg_cat==SDRCTL_REG_CAT_RF) {
370 			// printk("%s WARNING reg cat 1 (rf) is not supported yet!\n", sdr_compatible_str);
371 			// tmp = 0xFFFFFFFF;
372 			// return -EOPNOTSUPP;
373 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_RF_REG) {
374 				tmp = priv->rf_reg_val[reg_addr_idx];
375 			} else {
376 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
377 				return -EOPNOTSUPP;
378 			}
379 		}
380 		else if (reg_cat==SDRCTL_REG_CAT_RX_INTF)
381 			tmp = rx_intf_api->reg_read(reg_addr);
382 		else if (reg_cat==SDRCTL_REG_CAT_TX_INTF)
383 			tmp = tx_intf_api->reg_read(reg_addr);
384 		else if (reg_cat==SDRCTL_REG_CAT_RX)
385 			tmp = openofdm_rx_api->reg_read(reg_addr);
386 		else if (reg_cat==SDRCTL_REG_CAT_TX)
387 			tmp = openofdm_tx_api->reg_read(reg_addr);
388 		else if (reg_cat==SDRCTL_REG_CAT_XPU)
389 			tmp = xpu_api->reg_read(reg_addr);
390 		else if (reg_cat==SDRCTL_REG_CAT_DRV_RX) {
391 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
392 				tmp = priv->drv_rx_reg_val[reg_addr_idx];
393 				if (reg_addr_idx==DRV_RX_REG_IDX_ANT_CFG)
394 					openwifi_get_antenna(hw, &tsft_high, &tsft_low);
395 			} else {
396 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
397 				return -EOPNOTSUPP;
398 			}
399 		}
400 		else if (reg_cat==SDRCTL_REG_CAT_DRV_TX) {
401 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
402 				tmp = priv->drv_tx_reg_val[reg_addr_idx];
403 				if (reg_addr_idx==DRV_TX_REG_IDX_ANT_CFG)
404 					openwifi_get_antenna(hw, &tsft_high, &tsft_low);
405 			} else {
406 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
407 				return -EOPNOTSUPP;
408 			}
409 		}
410 		else if (reg_cat==SDRCTL_REG_CAT_DRV_XPU) {
411 			if (reg_addr_idx>=0 && reg_addr_idx<MAX_NUM_DRV_REG) {
412 				if (reg_addr_idx==DRV_XPU_REG_IDX_LBT_TH) {
413 					tmp = xpu_api->XPU_REG_LBT_TH_read();//rssi_half_db
414 					tmp_int = rssi_half_db_to_rssi_dbm(tmp, priv->rssi_correction); //rssi_dbm
415 					printk("%s FPGA LBT threshold %d(%ddBm). The last_auto_fpga_lbt_th %d(%ddBm). rssi corr %d (%d/%dMHz)\n", sdr_compatible_str, tmp, tmp_int, priv->last_auto_fpga_lbt_th, rssi_half_db_to_rssi_dbm(priv->last_auto_fpga_lbt_th, priv->rssi_correction), priv->rssi_correction, priv->actual_tx_lo, priv->actual_rx_lo);
416 				}
417 				tmp = priv->drv_xpu_reg_val[reg_addr_idx];
418 			} else {
419 				printk("%s WARNING reg_addr_idx %d is out of range!\n", sdr_compatible_str, reg_addr_idx);
420 				return -EOPNOTSUPP;
421 			}
422 		}
423 		else {
424 			printk("%s WARNING reg cat %d is not supported yet!\n", sdr_compatible_str, reg_cat);
425 			return -EOPNOTSUPP;
426 		}
427 
428 		if (nla_put_u32(skb, REG_ATTR_VAL, tmp))
429 			goto nla_put_failure;
430 		return cfg80211_testmode_reply(skb);
431 
432 	default:
433 		return -EOPNOTSUPP;
434 	}
435 
436  nla_put_failure:
437 	dev_kfree_skb(skb);
438 	return -ENOBUFS;
439 }
440