Merge branch 'address-masking'
[linux-2.6-microblaze.git] / drivers / staging / vt6656 / wcmd.c
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
29 static 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
34 static 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
43 static 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
88 void 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
162 int 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
178 void 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 }