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