📄 ipw2200.c
字号:
IPW_ERROR("Invalid args\n"); return -1; } return ipw_send_cmd(priv, &cmd);}static int ipw_send_system_config(struct ipw_priv *priv, struct ipw_sys_config *config){ struct host_cmd cmd = { .cmd = IPW_CMD_SYSTEM_CONFIG, .len = sizeof(*config) }; if (!priv || !config) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, config, sizeof(*config)); return ipw_send_cmd(priv, &cmd);}static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len){ struct host_cmd cmd = { .cmd = IPW_CMD_SSID, .len = min(len, IW_ESSID_MAX_SIZE) }; if (!priv || !ssid) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, ssid, cmd.len); return ipw_send_cmd(priv, &cmd);}static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac){ struct host_cmd cmd = { .cmd = IPW_CMD_ADAPTER_ADDRESS, .len = ETH_ALEN }; if (!priv || !mac) { IPW_ERROR("Invalid args\n"); return -1; } IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(mac)); memcpy(cmd.param, mac, ETH_ALEN); return ipw_send_cmd(priv, &cmd);}/* * NOTE: This must be executed from our workqueue as it results in udelay * being called which may corrupt the keyboard if executed on default * workqueue */static void ipw_adapter_restart(void *adapter){ struct ipw_priv *priv = adapter; if (priv->status & STATUS_RF_KILL_MASK) return; ipw_down(priv); if (priv->assoc_network && (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS)) ipw_remove_current_network(priv); if (ipw_up(priv)) { IPW_ERROR("Failed to up device\n"); return; }}static void ipw_bg_adapter_restart(void *data){ struct ipw_priv *priv = data; down(&priv->sem); ipw_adapter_restart(data); up(&priv->sem);}#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)static void ipw_scan_check(void *data){ struct ipw_priv *priv = data; if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { IPW_DEBUG_SCAN("Scan completion watchdog resetting " "adapter (%dms).\n", IPW_SCAN_CHECK_WATCHDOG / 100); queue_work(priv->workqueue, &priv->adapter_restart); }}static void ipw_bg_scan_check(void *data){ struct ipw_priv *priv = data; down(&priv->sem); ipw_scan_check(data); up(&priv->sem);}static int ipw_send_scan_request_ext(struct ipw_priv *priv, struct ipw_scan_request_ext *request){ struct host_cmd cmd = { .cmd = IPW_CMD_SCAN_REQUEST_EXT, .len = sizeof(*request) }; memcpy(cmd.param, request, sizeof(*request)); return ipw_send_cmd(priv, &cmd);}static int ipw_send_scan_abort(struct ipw_priv *priv){ struct host_cmd cmd = { .cmd = IPW_CMD_SCAN_ABORT, .len = 0 }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } return ipw_send_cmd(priv, &cmd);}static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens){ struct host_cmd cmd = { .cmd = IPW_CMD_SENSITIVITY_CALIB, .len = sizeof(struct ipw_sensitivity_calib) }; struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *) &cmd.param; calib->beacon_rssi_raw = sens; return ipw_send_cmd(priv, &cmd);}static int ipw_send_associate(struct ipw_priv *priv, struct ipw_associate *associate){ struct host_cmd cmd = { .cmd = IPW_CMD_ASSOCIATE, .len = sizeof(*associate) }; struct ipw_associate tmp_associate; memcpy(&tmp_associate, associate, sizeof(*associate)); tmp_associate.policy_support = cpu_to_le16(tmp_associate.policy_support); tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw); tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw); tmp_associate.capability = cpu_to_le16(tmp_associate.capability); tmp_associate.listen_interval = cpu_to_le16(tmp_associate.listen_interval); tmp_associate.beacon_interval = cpu_to_le16(tmp_associate.beacon_interval); tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); if (!priv || !associate) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, &tmp_associate, sizeof(*associate)); return ipw_send_cmd(priv, &cmd);}static int ipw_send_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *rates){ struct host_cmd cmd = { .cmd = IPW_CMD_SUPPORTED_RATES, .len = sizeof(*rates) }; if (!priv || !rates) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, rates, sizeof(*rates)); return ipw_send_cmd(priv, &cmd);}static int ipw_set_random_seed(struct ipw_priv *priv){ struct host_cmd cmd = { .cmd = IPW_CMD_SEED_NUMBER, .len = sizeof(u32) }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } get_random_bytes(&cmd.param, sizeof(u32)); return ipw_send_cmd(priv, &cmd);}static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off){ struct host_cmd cmd = { .cmd = IPW_CMD_CARD_DISABLE, .len = sizeof(u32) }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } *((u32 *) & cmd.param) = phy_off; return ipw_send_cmd(priv, &cmd);}static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power){ struct host_cmd cmd = { .cmd = IPW_CMD_TX_POWER, .len = sizeof(*power) }; if (!priv || !power) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, power, sizeof(*power)); return ipw_send_cmd(priv, &cmd);}static int ipw_set_tx_power(struct ipw_priv *priv){ const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); struct ipw_tx_power tx_power; s8 max_power; int i; memset(&tx_power, 0, sizeof(tx_power)); /* configure device for 'G' band */ tx_power.ieee_mode = IPW_G_MODE; tx_power.num_channels = geo->bg_channels; for (i = 0; i < geo->bg_channels; i++) { max_power = geo->bg[i].max_power; tx_power.channels_tx_power[i].channel_number = geo->bg[i].channel; tx_power.channels_tx_power[i].tx_power = max_power ? min(max_power, priv->tx_power) : priv->tx_power; } if (ipw_send_tx_power(priv, &tx_power)) return -EIO; /* configure device to also handle 'B' band */ tx_power.ieee_mode = IPW_B_MODE; if (ipw_send_tx_power(priv, &tx_power)) return -EIO; /* configure device to also handle 'A' band */ if (priv->ieee->abg_true) { tx_power.ieee_mode = IPW_A_MODE; tx_power.num_channels = geo->a_channels; for (i = 0; i < tx_power.num_channels; i++) { max_power = geo->a[i].max_power; tx_power.channels_tx_power[i].channel_number = geo->a[i].channel; tx_power.channels_tx_power[i].tx_power = max_power ? min(max_power, priv->tx_power) : priv->tx_power; } if (ipw_send_tx_power(priv, &tx_power)) return -EIO; } return 0;}static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts){ struct ipw_rts_threshold rts_threshold = { .rts_threshold = rts, }; struct host_cmd cmd = { .cmd = IPW_CMD_RTS_THRESHOLD, .len = sizeof(rts_threshold) }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold)); return ipw_send_cmd(priv, &cmd);}static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag){ struct ipw_frag_threshold frag_threshold = { .frag_threshold = frag, }; struct host_cmd cmd = { .cmd = IPW_CMD_FRAG_THRESHOLD, .len = sizeof(frag_threshold) }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold)); return ipw_send_cmd(priv, &cmd);}static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode){ struct host_cmd cmd = { .cmd = IPW_CMD_POWER_MODE, .len = sizeof(u32) }; u32 *param = (u32 *) (&cmd.param); if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } /* If on battery, set to 3, if AC set to CAM, else user * level */ switch (mode) { case IPW_POWER_BATTERY: *param = IPW_POWER_INDEX_3; break; case IPW_POWER_AC: *param = IPW_POWER_MODE_CAM; break; default: *param = mode; break; } return ipw_send_cmd(priv, &cmd);}static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit){ struct ipw_retry_limit retry_limit = { .short_retry_limit = slimit, .long_retry_limit = llimit }; struct host_cmd cmd = { .cmd = IPW_CMD_RETRY_LIMIT, .len = sizeof(retry_limit) }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } memcpy(cmd.param, &retry_limit, sizeof(retry_limit)); return ipw_send_cmd(priv, &cmd);}/* * The IPW device contains a Microwire compatible EEPROM that stores * various data like the MAC address. Usually the firmware has exclusive * access to the eeprom, but during device initialization (before the * device driver has sent the HostComplete command to the firmware) the * device driver has read access to the EEPROM by way of indirect addressing * through a couple of memory mapped registers. * * The following is a simplified implementation for pulling data out of the * the eeprom, along with some helper functions to find information in * the per device private data's copy of the eeprom. * * NOTE: To better understand how these functions work (i.e what is a chip * select and why do have to keep driving the eeprom clock?), read * just about any data sheet for a Microwire compatible EEPROM. *//* write a 32 bit value into the indirect accessor register */static inline void eeprom_write_reg(struct ipw_priv *p, u32 data){ ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data); /* the eeprom requires some time to complete the operation */ udelay(p->eeprom_delay); return;}/* perform a chip select operation */static inline void eeprom_cs(struct ipw_priv *priv){ eeprom_write_reg(priv, 0); eeprom_write_reg(priv, EEPROM_BIT_CS); eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK); eeprom_write_reg(priv, EEPROM_BIT_CS);}/* perform a chip select operation */static inline void eeprom_disable_cs(struct ipw_priv *priv){ eeprom_write_reg(priv, EEPROM_BIT_CS); eeprom_write_reg(priv, 0); eeprom_write_reg(priv, EEPROM_BIT_SK);}/* push a single bit down to the eeprom */static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit){ int d = (bit ? EEPROM_BIT_DI : 0); eeprom_write_reg(p, EEPROM_BIT_CS | d); eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK);}/* push an opcode followed by an address down to the eeprom */static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr){ int i; eeprom_cs(priv); eeprom_write_bit(priv, 1); eeprom_write_bit(priv, op & 2); eeprom_write_bit(priv, op & 1); for (i = 7; i >= 0; i--) { eeprom_write_bit(priv, addr & (1 << i)); }}/* pull 16 bits off the eeprom, one bit at a time */static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr){ int i; u16 r = 0; /* Send READ Opcode */ eeprom_op(priv, EEPROM_CMD_READ, addr); /* Send dummy bit */ eeprom_write_reg(priv, EEPROM_BIT_CS); /* Read the byte off the eeprom one bit at a time */ for (i = 0; i < 16; i++) { u32 data = 0; eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK); eeprom_write_reg(priv, EEPROM_BIT_CS); data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS); r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0); } /* Send another dummy bit */ eeprom_write_reg(priv, 0); eeprom_disable_cs(priv); return r;}/* helper function for pulling the mac address out of the private *//* data's copy of the eeprom data */static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac){ memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6);}/* * Either the device driver (i.e. the host) or the firmware can * load eeprom data into the designated region in SRAM. If neither * happens then the FW will shutdown with a fatal error. * * In order to signal the FW to load the EEPROM, the EEPROM_L
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -