1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
4 * All rights reserved.
5 *
6 * Purpose: Handles the management command interface functions
7 *
8 * Author: Lyndon Chen
9 *
10 * Date: May 8, 2003
11 *
12 * Functions:
13 *	vnt_cmd_complete - Command Complete function
14 *	vnt_schedule_command - Push Command and wait Command Scheduler to do
15 *	vnt_cmd_timer_wait- Call back timer
16 *
17 * Revision History:
18 *
19 */
20
21#include "device.h"
22#include "mac.h"
23#include "wcmd.h"
24#include "power.h"
25#include "usbpipe.h"
26#include "rxtx.h"
27#include "rf.h"
28
29static void vnt_cmd_timer_wait(struct vnt_private *priv, unsigned long msecs)
30{
31	schedule_delayed_work(&priv->run_command_work, msecs_to_jiffies(msecs));
32}
33
34static u32 add_one_with_wrap_around(u32 var, u8 modulo)
35{
36	if (var >= (modulo - 1))
37		var = 0;
38	else
39		var++;
40	return var;
41}
42
43static int vnt_cmd_complete(struct vnt_private *priv)
44{
45	priv->command_state = WLAN_CMD_IDLE;
46	if (priv->free_cmd_queue == CMD_Q_SIZE) {
47		/* Command Queue Empty */
48		priv->cmd_running = false;
49		return true;
50	}
51
52	priv->command = priv->cmd_queue[priv->cmd_dequeue_idx];
53
54	priv->cmd_dequeue_idx = add_one_with_wrap_around(priv->cmd_dequeue_idx, CMD_Q_SIZE);
55	priv->free_cmd_queue++;
56	priv->cmd_running = true;
57
58	switch (priv->command) {
59	case WLAN_CMD_INIT_MAC80211:
60		priv->command_state = WLAN_CMD_INIT_MAC80211_START;
61		break;
62
63	case WLAN_CMD_TBTT_WAKEUP:
64		priv->command_state = WLAN_CMD_TBTT_WAKEUP_START;
65		break;
66
67	case WLAN_CMD_BECON_SEND:
68		priv->command_state = WLAN_CMD_BECON_SEND_START;
69		break;
70
71	case WLAN_CMD_SETPOWER:
72		priv->command_state = WLAN_CMD_SETPOWER_START;
73		break;
74
75	case WLAN_CMD_CHANGE_ANTENNA:
76		priv->command_state = WLAN_CMD_CHANGE_ANTENNA_START;
77		break;
78
79	default:
80		break;
81	}
82
83	vnt_cmd_timer_wait(priv, 0);
84
85	return true;
86}
87
88void vnt_run_command(struct work_struct *work)
89{
90	struct vnt_private *priv =
91		container_of(work, struct vnt_private, run_command_work.work);
92
93	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
94		return;
95
96	if (!priv->cmd_running)
97		return;
98
99	switch (priv->command_state) {
100	case WLAN_CMD_INIT_MAC80211_START:
101		if (priv->mac_hw)
102			break;
103
104		dev_info(&priv->usb->dev, "Starting mac80211\n");
105
106		if (vnt_init(priv)) {
107			/* If fail all ends TODO retry */
108			dev_err(&priv->usb->dev, "failed to start\n");
109			usb_set_intfdata(priv->intf, NULL);
110			ieee80211_free_hw(priv->hw);
111			return;
112		}
113
114		break;
115
116	case WLAN_CMD_TBTT_WAKEUP_START:
117		vnt_next_tbtt_wakeup(priv);
118		break;
119
120	case WLAN_CMD_BECON_SEND_START:
121		if (!priv->vif)
122			break;
123
124		vnt_beacon_make(priv, priv->vif);
125
126		vnt_mac_reg_bits_on(priv, MAC_REG_TCR, TCR_AUTOBCNTX);
127
128		break;
129
130	case WLAN_CMD_SETPOWER_START:
131
132		vnt_rf_setpower(priv, priv->hw->conf.chandef.chan);
133
134		break;
135
136	case WLAN_CMD_CHANGE_ANTENNA_START:
137		dev_dbg(&priv->usb->dev, "Change from Antenna%d to",
138			priv->rx_antenna_sel);
139
140		if (priv->rx_antenna_sel == 0) {
141			priv->rx_antenna_sel = 1;
142			if (priv->tx_rx_ant_inv)
143				vnt_set_antenna_mode(priv, ANT_RXA);
144			else
145				vnt_set_antenna_mode(priv, ANT_RXB);
146		} else {
147			priv->rx_antenna_sel = 0;
148			if (priv->tx_rx_ant_inv)
149				vnt_set_antenna_mode(priv, ANT_RXB);
150			else
151				vnt_set_antenna_mode(priv, ANT_RXA);
152		}
153		break;
154
155	default:
156		break;
157	}
158
159	vnt_cmd_complete(priv);
160}
161
162int vnt_schedule_command(struct vnt_private *priv, enum vnt_cmd command)
163{
164	if (priv->free_cmd_queue == 0)
165		return false;
166
167	priv->cmd_queue[priv->cmd_enqueue_idx] = command;
168
169	priv->cmd_enqueue_idx = add_one_with_wrap_around(priv->cmd_enqueue_idx, CMD_Q_SIZE);
170	priv->free_cmd_queue--;
171
172	if (!priv->cmd_running)
173		vnt_cmd_complete(priv);
174
175	return true;
176}
177
178void vnt_reset_command_timer(struct vnt_private *priv)
179{
180	priv->free_cmd_queue = CMD_Q_SIZE;
181	priv->cmd_dequeue_idx = 0;
182	priv->cmd_enqueue_idx = 0;
183	priv->command_state = WLAN_CMD_IDLE;
184	priv->cmd_running = false;
185}
186