📄 ipw2100.c
字号:
} err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED); if (err) { IPW_DEBUG_INFO("%s: card not responding to init command.\n", priv->net_dev->name); goto fail_up; } if (priv->stop_hang_check) { priv->stop_hang_check = 0; queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); } fail_up: up(&priv->adapter_sem); return err;}static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv){#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100)) struct host_command cmd = { .host_command = HOST_PRE_POWER_DOWN, .host_command_sequence = 0, .host_command_length = 0, }; int err, i; u32 reg; if (!(priv->status & STATUS_RUNNING)) return 0; priv->status |= STATUS_STOPPING; /* We can only shut down the card if the firmware is operational. So, * if we haven't reset since a fatal_error, then we can not send the * shutdown commands. */ if (!priv->fatal_error) { /* First, make sure the adapter is enabled so that the PHY_OFF * command can shut it down */ ipw2100_enable_adapter(priv); err = ipw2100_hw_phy_off(priv); if (err) printk(KERN_WARNING DRV_NAME ": Error disabling radio %d\n", err); /* * If in D0-standby mode going directly to D3 may cause a * PCI bus violation. Therefore we must change out of the D0 * state. * * Sending the PREPARE_FOR_POWER_DOWN will restrict the * hardware from going into standby mode and will transition * out of D0-standy if it is already in that state. * * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the * driver upon completion. Once received, the driver can * proceed to the D3 state. * * Prepare for power down command to fw. This command would * take HW out of D0-standby and prepare it for D3 state. * * Currently FW does not support event notification for this * event. Therefore, skip waiting for it. Just wait a fixed * 100ms */ IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n"); err = ipw2100_hw_send_command(priv, &cmd); if (err) printk(KERN_WARNING DRV_NAME ": " "%s: Power down command failed: Error %d\n", priv->net_dev->name, err); else schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY); } priv->status &= ~STATUS_ENABLED; /* * Set GPIO 3 writable by FW; GPIO 1 writable * by driver and enable clock */ ipw2100_hw_set_gpio(priv); /* * Power down adapter. Sequence: * 1. Stop master assert (RESET_REG[9]=1) * 2. Wait for stop master (RESET_REG[8]==1) * 3. S/w reset assert (RESET_REG[7] = 1) */ /* Stop master assert */ write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_STOP_MASTER); /* wait stop master not more than 50 usec. * Otherwise return error. */ for (i = 5; i > 0; i--) { udelay(10); /* Check master stop bit */ read_register(priv->net_dev, IPW_REG_RESET_REG, ®); if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) break; } if (i == 0) printk(KERN_WARNING DRV_NAME ": %s: Could now power down adapter.\n", priv->net_dev->name); /* assert s/w reset */ write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_SW_RESET); priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING); return 0;}static int ipw2100_disable_adapter(struct ipw2100_priv *priv){ struct host_command cmd = { .host_command = CARD_DISABLE, .host_command_sequence = 0, .host_command_length = 0 }; int err = 0; IPW_DEBUG_HC("CARD_DISABLE\n"); if (!(priv->status & STATUS_ENABLED)) return 0; /* Make sure we clear the associated state */ priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); if (!priv->stop_hang_check) { priv->stop_hang_check = 1; cancel_delayed_work(&priv->hang_check); } down(&priv->adapter_sem); err = ipw2100_hw_send_command(priv, &cmd); if (err) { printk(KERN_WARNING DRV_NAME ": exit - failed to send CARD_DISABLE command\n"); goto fail_up; } err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED); if (err) { printk(KERN_WARNING DRV_NAME ": exit - card failed to change to DISABLED\n"); goto fail_up; } IPW_DEBUG_INFO("TODO: implement scan state machine\n"); fail_up: up(&priv->adapter_sem); return err;}static int ipw2100_set_scan_options(struct ipw2100_priv *priv){ struct host_command cmd = { .host_command = SET_SCAN_OPTIONS, .host_command_sequence = 0, .host_command_length = 8 }; int err; IPW_DEBUG_INFO("enter\n"); IPW_DEBUG_SCAN("setting scan options\n"); cmd.host_command_parameters[0] = 0; if (!(priv->config & CFG_ASSOCIATE)) cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE; if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled) cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL; if (priv->config & CFG_PASSIVE_SCAN) cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE; cmd.host_command_parameters[1] = priv->channel_mask; err = ipw2100_hw_send_command(priv, &cmd); IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n", cmd.host_command_parameters[0]); return err;}static int ipw2100_start_scan(struct ipw2100_priv *priv){ struct host_command cmd = { .host_command = BROADCAST_SCAN, .host_command_sequence = 0, .host_command_length = 4 }; int err; IPW_DEBUG_HC("START_SCAN\n"); cmd.host_command_parameters[0] = 0; /* No scanning if in monitor mode */ if (priv->ieee->iw_mode == IW_MODE_MONITOR) return 1; if (priv->status & STATUS_SCANNING) { IPW_DEBUG_SCAN("Scan requested while already in scan...\n"); return 0; } IPW_DEBUG_INFO("enter\n"); /* Not clearing here; doing so makes iwlist always return nothing... * * We should modify the table logic to use aging tables vs. clearing * the table on each scan start. */ IPW_DEBUG_SCAN("starting scan\n"); priv->status |= STATUS_SCANNING; err = ipw2100_hw_send_command(priv, &cmd); if (err) priv->status &= ~STATUS_SCANNING; IPW_DEBUG_INFO("exit\n"); return err;}static int ipw2100_up(struct ipw2100_priv *priv, int deferred){ unsigned long flags; int rc = 0; u32 lock; u32 ord_len = sizeof(lock); /* Quite if manually disabled. */ if (priv->status & STATUS_RF_KILL_SW) { IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable " "switch\n", priv->net_dev->name); return 0; } /* If the interrupt is enabled, turn it off... */ spin_lock_irqsave(&priv->low_lock, flags); ipw2100_disable_interrupts(priv); /* Reset any fatal_error conditions */ ipw2100_reset_fatalerror(priv); spin_unlock_irqrestore(&priv->low_lock, flags); if (priv->status & STATUS_POWERED || (priv->status & STATUS_RESET_PENDING)) { /* Power cycle the card ... */ if (ipw2100_power_cycle_adapter(priv)) { printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n", priv->net_dev->name); rc = 1; goto exit; } } else priv->status |= STATUS_POWERED; /* Load the firmware, start the clocks, etc. */ if (ipw2100_start_adapter(priv)) { printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n", priv->net_dev->name); rc = 1; goto exit; } ipw2100_initialize_ordinals(priv); /* Determine capabilities of this particular HW configuration */ if (ipw2100_get_hw_features(priv)) { printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n", priv->net_dev->name); rc = 1; goto exit; } lock = LOCK_NONE; if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n", priv->net_dev->name); rc = 1; goto exit; } priv->status &= ~STATUS_SCANNING; if (rf_kill_active(priv)) { printk(KERN_INFO "%s: Radio is disabled by RF switch.\n", priv->net_dev->name); if (priv->stop_rf_kill) { priv->stop_rf_kill = 0; queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); } deferred = 1; } /* Turn on the interrupt so that commands can be processed */ ipw2100_enable_interrupts(priv); /* Send all of the commands that must be sent prior to * HOST_COMPLETE */ if (ipw2100_adapter_setup(priv)) { printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n", priv->net_dev->name); rc = 1; goto exit; } if (!deferred) { /* Enable the adapter - sends HOST_COMPLETE */ if (ipw2100_enable_adapter(priv)) { printk(KERN_ERR DRV_NAME ": " "%s: failed in call to enable adapter.\n", priv->net_dev->name); ipw2100_hw_stop_adapter(priv); rc = 1; goto exit; } /* Start a scan . . . */ ipw2100_set_scan_options(priv); ipw2100_start_scan(priv); } exit: return rc;}/* Called by register_netdev() */static int ipw2100_net_init(struct net_device *dev){ struct ipw2100_priv *priv = ieee80211_priv(dev); return ipw2100_up(priv, 1);}static void ipw2100_down(struct ipw2100_priv *priv){ unsigned long flags; union iwreq_data wrqu = { .ap_addr = { .sa_family = ARPHRD_ETHER} }; int associated = priv->status & STATUS_ASSOCIATED; /* Kill the RF switch timer */ if (!priv->stop_rf_kill) { priv->stop_rf_kill = 1; cancel_delayed_work(&priv->rf_kill); } /* Kill the firmare hang check timer */ if (!priv->stop_hang_check) { priv->stop_hang_check = 1; cancel_delayed_work(&priv->hang_check); } /* Kill any pending resets */ if (priv->status & STATUS_RESET_PENDING) cancel_delayed_work(&priv->reset_work); /* Make sure the interrupt is on so that FW commands will be * processed correctly */ spin_lock_irqsave(&priv->low_lock, flags); ipw2100_enable_interrupts(priv); spin_unlock_irqrestore(&priv->low_lock, flags); if (ipw2100_hw_stop_adapter(priv)) printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n", priv->net_dev->name); /* Do not disable the interrupt until _after_ we disable * the adaptor. Otherwise the CARD_DISABLE command will never * be ack'd by the firmware */ spin_lock_irqsave(&priv->low_lock, flags); ipw2100_disable_interrupts(priv); spin_unlock_irqrestore(&priv->low_lock, flags);#ifdef ACPI_CSTATE_LIMIT_DEFINED if (priv->config & CFG_C3_DISABLED) { IPW_DEBUG_INFO(": Resetting C3 transitions.\n"); acpi_set_cstate_limit(priv->cstate_limit); priv->config &= ~CFG_C3_DISABLED; }#endif /* We have to signal any supplicant if we are disassociating */ if (associated) wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); netif_carrier_off(priv->net_dev); netif_stop_queue(priv->net_dev);}static void ipw2100_reset_adapter(struct ipw2100_priv *priv){ unsigned long flags; union iwreq_data wrqu = { .ap_addr = { .sa_family = ARPHRD_ETHER} }; int associated = priv->status & STATUS_ASSOCIATED; spin_lock_irqsave(&priv->low_lock, flags); IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name); priv->resets++; priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); priv->status |= STATUS_SECURITY_UPDATED; /* Force a power cycle even if interface hasn't been opened * yet */ cancel_delayed_work(&priv->reset_work); priv->status |= STATUS_RESET_PENDING; spin_unlock_irqrestore(&priv->low_lock, flags); down(&priv->action_sem); /* stop timed checks so that they don't interfere with reset */ priv->stop_hang_check = 1; cancel_delayed_work(&priv->hang_check); /* We have to signal any supplicant if we are disassociating */ if (associated) wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); ipw2100_up(priv, 0); up(&priv->action_sem);}static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status){#define MAC_ASSOCIATION_READ_DELAY (HZ) int ret, len, essid_len; char essid[IW_ESSID_MAX_SIZE]; u32 txrate; u32 chan; char *txratename; u8 bssid[ETH_ALEN]; /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not * an actual MAC of the AP. Seems like FW sets this * address too late. Read it later and expose through * /proc or schedule a later task to query and update */ essid_len = IW_ESSID_MAX_SIZE; ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &essid_len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -