1/* 2 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. 3 * All rights reserved. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * File: wcmd.c 20 * 21 * Purpose: Handles the management command interface functions 22 * 23 * Author: Lyndon Chen 24 * 25 * Date: May 8, 2003 26 * 27 * Functions: 28 * vnt_cmd_complete - Command Complete function 29 * vnt_schedule_command - Push Command and wait Command Scheduler to do 30 * vnt_cmd_timer_wait- Call back timer 31 * 32 * Revision History: 33 * 34 */ 35 36#include "device.h" 37#include "mac.h" 38#include "wcmd.h" 39#include "power.h" 40#include "usbpipe.h" 41#include "rxtx.h" 42#include "rf.h" 43 44static void vnt_cmd_timer_wait(struct vnt_private *priv, unsigned long msecs) 45{ 46 schedule_delayed_work(&priv->run_command_work, msecs_to_jiffies(msecs)); 47} 48 49static int vnt_cmd_complete(struct vnt_private *priv) 50{ 51 52 priv->command_state = WLAN_CMD_IDLE; 53 if (priv->free_cmd_queue == CMD_Q_SIZE) { 54 /* Command Queue Empty */ 55 priv->cmd_running = false; 56 return true; 57 } 58 59 priv->command = priv->cmd_queue[priv->cmd_dequeue_idx]; 60 61 ADD_ONE_WITH_WRAP_AROUND(priv->cmd_dequeue_idx, CMD_Q_SIZE); 62 priv->free_cmd_queue++; 63 priv->cmd_running = true; 64 65 switch (priv->command) { 66 case WLAN_CMD_INIT_MAC80211: 67 priv->command_state = WLAN_CMD_INIT_MAC80211_START; 68 break; 69 70 case WLAN_CMD_TBTT_WAKEUP: 71 priv->command_state = WLAN_CMD_TBTT_WAKEUP_START; 72 break; 73 74 case WLAN_CMD_BECON_SEND: 75 priv->command_state = WLAN_CMD_BECON_SEND_START; 76 break; 77 78 case WLAN_CMD_SETPOWER: 79 priv->command_state = WLAN_CMD_SETPOWER_START; 80 break; 81 82 case WLAN_CMD_CHANGE_ANTENNA: 83 priv->command_state = WLAN_CMD_CHANGE_ANTENNA_START; 84 break; 85 86 default: 87 break; 88 } 89 90 vnt_cmd_timer_wait(priv, 0); 91 92 return true; 93} 94 95void vnt_run_command(struct work_struct *work) 96{ 97 struct vnt_private *priv = 98 container_of(work, struct vnt_private, run_command_work.work); 99 100 if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) 101 return; 102 103 if (priv->cmd_running != true) 104 return; 105 106 switch (priv->command_state) { 107 case WLAN_CMD_INIT_MAC80211_START: 108 if (priv->mac_hw) 109 break; 110 111 dev_info(&priv->usb->dev, "Starting mac80211\n"); 112 113 if (vnt_init(priv)) { 114 /* If fail all ends TODO retry */ 115 dev_err(&priv->usb->dev, "failed to start\n"); 116 ieee80211_free_hw(priv->hw); 117 return; 118 } 119 120 break; 121 122 case WLAN_CMD_TBTT_WAKEUP_START: 123 vnt_next_tbtt_wakeup(priv); 124 break; 125 126 case WLAN_CMD_BECON_SEND_START: 127 if (!priv->vif) 128 break; 129 130 vnt_beacon_make(priv, priv->vif); 131 132 vnt_mac_reg_bits_on(priv, MAC_REG_TCR, TCR_AUTOBCNTX); 133 134 break; 135 136 case WLAN_CMD_SETPOWER_START: 137 138 vnt_rf_setpower(priv, priv->current_rate, 139 priv->hw->conf.chandef.chan->hw_value); 140 141 break; 142 143 case WLAN_CMD_CHANGE_ANTENNA_START: 144 dev_dbg(&priv->usb->dev, "Change from Antenna%d to", 145 priv->rx_antenna_sel); 146 147 if (priv->rx_antenna_sel == 0) { 148 priv->rx_antenna_sel = 1; 149 if (priv->tx_rx_ant_inv == true) 150 vnt_set_antenna_mode(priv, ANT_RXA); 151 else 152 vnt_set_antenna_mode(priv, ANT_RXB); 153 } else { 154 priv->rx_antenna_sel = 0; 155 if (priv->tx_rx_ant_inv == true) 156 vnt_set_antenna_mode(priv, ANT_RXB); 157 else 158 vnt_set_antenna_mode(priv, ANT_RXA); 159 } 160 break; 161 162 default: 163 break; 164 } 165 166 vnt_cmd_complete(priv); 167} 168 169int vnt_schedule_command(struct vnt_private *priv, enum vnt_cmd command) 170{ 171 172 if (priv->free_cmd_queue == 0) 173 return false; 174 175 priv->cmd_queue[priv->cmd_enqueue_idx] = command; 176 177 ADD_ONE_WITH_WRAP_AROUND(priv->cmd_enqueue_idx, CMD_Q_SIZE); 178 priv->free_cmd_queue--; 179 180 if (priv->cmd_running == false) 181 vnt_cmd_complete(priv); 182 183 return true; 184 185} 186 187void vnt_reset_command_timer(struct vnt_private *priv) 188{ 189 priv->free_cmd_queue = CMD_Q_SIZE; 190 priv->cmd_dequeue_idx = 0; 191 priv->cmd_enqueue_idx = 0; 192 priv->command_state = WLAN_CMD_IDLE; 193 priv->cmd_running = false; 194} 195