From df48c3235c90095a2f7dbcaba444add363ffb0ef Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 6 Mar 2008 10:40:19 -0800 Subject: iwlwifi: add iwl-core module This patch adds iwl-core module to iwlwifi driver. This module will contain common code and infrastracture for iwlwifi driver Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 3bbd38358d53..6b85cca9b3f1 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,3 +1,6 @@ +obj-$(CONFIG_IWLCORE) += iwlcore.o +iwlcore-objs = iwl-core.o + obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o -- cgit v1.2.3-59-g8ed1b From 6bc913bd965e03b5273a5366eecce5c28c9b01da Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Tue, 11 Mar 2008 16:17:18 -0700 Subject: iwlwifi: Use eeprom form iwlcore This patch puts in use eeprom from iwlcore module Signed-off-by: Assaf Krauss Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 310 ---------------------------- drivers/net/wireless/iwlwifi/iwl-4965.c | 45 ++-- drivers/net/wireless/iwlwifi/iwl-4965.h | 4 +- drivers/net/wireless/iwlwifi/iwl-core.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.h | 10 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 84 +------- 7 files changed, 30 insertions(+), 426 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 6b85cca9b3f1..59d9c90d3610 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o -iwlcore-objs = iwl-core.o +iwlcore-objs = iwl-core.o iwl-eeprom.o obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 4a29b44950a7..c66993eb5b6a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -92,316 +92,6 @@ /* RSSI to dBm */ #define IWL_RSSI_OFFSET 44 -/* - * EEPROM related constants, enums, and structures. - */ - -/* - * EEPROM access time values: - * - * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, - * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit - * CSR_EEPROM_REG_BIT_CMD (0x2). - * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). - * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. - * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. - */ -#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ -#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ - -/* - * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags. - * - * IBSS and/or AP operation is allowed *only* on those channels with - * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because - * RADAR detection is not supported by the 4965 driver, but is a - * requirement for establishing a new network for legal operation on channels - * requiring RADAR detection or restricting ACTIVE scanning. - * - * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. - * It only indicates that 20 MHz channel use is supported; FAT channel - * usage is indicated by a separate set of regulatory flags for each - * FAT channel pair. - * - * NOTE: Using a channel inappropriately will result in a uCode error! - */ -enum { - EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ - EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ - /* Bit 2 Reserved */ - EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ - EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ - EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ - EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ - EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ -}; - -/* SKU Capabilities */ -#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) -#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) - -/* *regulatory* channel data format in eeprom, one for each channel. - * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ -struct iwl4965_eeprom_channel { - u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ - s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ -} __attribute__ ((packed)); - -/* 4965 has two radio transmitters (and 3 radio receivers) */ -#define EEPROM_TX_POWER_TX_CHAINS (2) - -/* 4965 has room for up to 8 sets of txpower calibration data */ -#define EEPROM_TX_POWER_BANDS (8) - -/* 4965 factory calibration measures txpower gain settings for - * each of 3 target output levels */ -#define EEPROM_TX_POWER_MEASUREMENTS (3) - -/* 4965 driver does not work with txpower calibration version < 5. - * Look for this in calib_version member of struct iwl4965_eeprom. */ -#define EEPROM_TX_POWER_VERSION_NEW (5) - - -/* - * 4965 factory calibration data for one txpower level, on one channel, - * measured on one of the 2 tx chains (radio transmitter and associated - * antenna). EEPROM contains: - * - * 1) Temperature (degrees Celsius) of device when measurement was made. - * - * 2) Gain table index used to achieve the target measurement power. - * This refers to the "well-known" gain tables (see iwl-4965-hw.h). - * - * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). - * - * 4) RF power amplifier detector level measurement (not used). - */ -struct iwl4965_eeprom_calib_measure { - u8 temperature; /* Device temperature (Celsius) */ - u8 gain_idx; /* Index into gain table */ - u8 actual_pow; /* Measured RF output power, half-dBm */ - s8 pa_det; /* Power amp detector level (not used) */ -} __attribute__ ((packed)); - - -/* - * 4965 measurement set for one channel. EEPROM contains: - * - * 1) Channel number measured - * - * 2) Measurements for each of 3 power levels for each of 2 radio transmitters - * (a.k.a. "tx chains") (6 measurements altogether) - */ -struct iwl4965_eeprom_calib_ch_info { - u8 ch_num; - struct iwl4965_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] - [EEPROM_TX_POWER_MEASUREMENTS]; -} __attribute__ ((packed)); - -/* - * 4965 txpower subband info. - * - * For each frequency subband, EEPROM contains the following: - * - * 1) First and last channels within range of the subband. "0" values - * indicate that this sample set is not being used. - * - * 2) Sample measurement sets for 2 channels close to the range endpoints. - */ -struct iwl4965_eeprom_calib_subband_info { - u8 ch_from; /* channel number of lowest channel in subband */ - u8 ch_to; /* channel number of highest channel in subband */ - struct iwl4965_eeprom_calib_ch_info ch1; - struct iwl4965_eeprom_calib_ch_info ch2; -} __attribute__ ((packed)); - - -/* - * 4965 txpower calibration info. EEPROM contains: - * - * 1) Factory-measured saturation power levels (maximum levels at which - * tx power amplifier can output a signal without too much distortion). - * There is one level for 2.4 GHz band and one for 5 GHz band. These - * values apply to all channels within each of the bands. - * - * 2) Factory-measured power supply voltage level. This is assumed to be - * constant (i.e. same value applies to all channels/bands) while the - * factory measurements are being made. - * - * 3) Up to 8 sets of factory-measured txpower calibration values. - * These are for different frequency ranges, since txpower gain - * characteristics of the analog radio circuitry vary with frequency. - * - * Not all sets need to be filled with data; - * struct iwl4965_eeprom_calib_subband_info contains range of channels - * (0 if unused) for each set of data. - */ -struct iwl4965_eeprom_calib_info { - u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ - u8 saturation_power52; /* half-dBm */ - s16 voltage; /* signed */ - struct iwl4965_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; -} __attribute__ ((packed)); - - -/* - * 4965 EEPROM map - */ -struct iwl4965_eeprom { - u8 reserved0[16]; -#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ - u16 device_id; /* abs.ofs: 16 */ - u8 reserved1[2]; -#define EEPROM_PMC (2*0x0A) /* 2 bytes */ - u16 pmc; /* abs.ofs: 20 */ - u8 reserved2[20]; -#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ - u8 mac_address[6]; /* abs.ofs: 42 */ - u8 reserved3[58]; -#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ - u16 board_revision; /* abs.ofs: 106 */ - u8 reserved4[11]; -#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ - u8 board_pba_number[9]; /* abs.ofs: 119 */ - u8 reserved5[8]; -#define EEPROM_VERSION (2*0x44) /* 2 bytes */ - u16 version; /* abs.ofs: 136 */ -#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ - u8 sku_cap; /* abs.ofs: 138 */ -#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ - u8 leds_mode; /* abs.ofs: 139 */ -#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ - u16 oem_mode; -#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ - u16 wowlan_mode; /* abs.ofs: 142 */ -#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ - u16 leds_time_interval; /* abs.ofs: 144 */ -#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ - u8 leds_off_time; /* abs.ofs: 146 */ -#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ - u8 leds_on_time; /* abs.ofs: 147 */ -#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ - u8 almgor_m_version; /* abs.ofs: 148 */ -#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ - u8 antenna_switch_type; /* abs.ofs: 149 */ - u8 reserved6[8]; -#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ - u16 board_revision_4965; /* abs.ofs: 158 */ - u8 reserved7[13]; -#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ - u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ - u8 reserved8[10]; -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ - u8 sku_id[4]; /* abs.ofs: 192 */ - -/* - * Per-channel regulatory data. - * - * Each channel that *might* be supported by 3945 or 4965 has a fixed location - * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory - * txpower (MSB). - * - * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) - * channels (only for 4965, not supported by 3945) appear later in the EEPROM. - * - * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ - u16 band_1_count; /* abs.ofs: 196 */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ - struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ - -/* - * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, - * 5.0 GHz channels 7, 8, 11, 12, 16 - * (4915-5080MHz) (none of these is ever supported) - */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ - u16 band_2_count; /* abs.ofs: 226 */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ - struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ - -/* - * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 - * (5170-5320MHz) - */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ - u16 band_3_count; /* abs.ofs: 254 */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ - struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ - -/* - * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 - * (5500-5700MHz) - */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ - u16 band_4_count; /* abs.ofs: 280 */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ - struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ - -/* - * 5.7 GHz channels 145, 149, 153, 157, 161, 165 - * (5725-5825MHz) - */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ - u16 band_5_count; /* abs.ofs: 304 */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ - struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ - - u8 reserved10[2]; - - -/* - * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) - * - * The channel listed is the center of the lower 20 MHz half of the channel. - * The overall center frequency is actually 2 channels (10 MHz) above that, - * and the upper half of each FAT channel is centered 4 channels (20 MHz) away - * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, - * and the overall FAT channel width centers on channel 3. - * - * NOTE: The RXON command uses 20 MHz channel numbers to specify the - * control channel to which to tune. RXON also specifies whether the - * control channel is the upper or lower half of a FAT channel. - * - * NOTE: 4965 does not support FAT channels on 2.4 GHz. - */ -#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ - struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ - u8 reserved11[2]; - -/* - * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), - * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) - */ -#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ - struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ - u8 reserved12[6]; - -/* - * 4965 driver requires txpower calibration format version 5 or greater. - * Driver does not work with txpower calibration version < 5. - * This value is simply a 16-bit number, no major/minor versions here. - */ -#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ - u16 calib_version; /* abs.ofs: 364 */ - u8 reserved13[2]; - u8 reserved14[96]; /* abs.ofs: 368 */ - -/* - * 4965 Txpower calibration data. - */ -#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ - struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */ - - u8 reserved16[140]; /* fill out to full 1024 byte block */ - - -} __attribute__ ((packed)); - -#define IWL_EEPROM_IMAGE_SIZE 1024 - -/* End of EEPROM */ #include "iwl-4965-commands.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a79e8c383a39..dc55ff294b73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -38,6 +38,7 @@ #include #include +#include "iwl-eeprom.h" #include "iwl-core.h" #include "iwl-4965.h" #include "iwl-helpers.h" @@ -4824,10 +4825,23 @@ void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv) cancel_delayed_work(&priv->init_alive_start); } +static struct iwl_lib_ops iwl4965_lib = { + .eeprom_ops = { + .verify_signature = iwlcore_eeprom_verify_signature, + .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, + .release_semaphore = iwlcore_eeprom_release_semaphore, + }, +}; + +static struct iwl_ops iwl4965_ops = { + .lib = &iwl4965_lib, +}; + static struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl4965_ops, }; struct pci_device_id iwl4965_hw_card_ids[] = { @@ -4836,35 +4850,4 @@ struct pci_device_id iwl4965_hw_card_ids[] = { {0} }; -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv) -{ - u16 count; - int rc; - - for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - /* Request semaphore */ - iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - rc = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); - if (rc >= 0) { - IWL_DEBUG_IO("Acquired semaphore after %d tries.\n", - count+1); - return rc; - } - } - - return rc; -} - MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 6ce408137365..f4e395fcb807 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -40,6 +40,7 @@ extern struct pci_device_id iwl4965_hw_card_ids[]; #define DRV_NAME "iwl4965" +#include "iwl-eeprom.h" #include "iwl-4965-hw.h" #include "iwl-csr.h" #include "iwl-prph.h" @@ -640,7 +641,6 @@ extern u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, extern int iwl4965_is_network_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header); extern int iwl4965_power_init_handle(struct iwl4965_priv *priv); -extern int iwl4965_eeprom_init(struct iwl4965_priv *priv); extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb, void *data, short len, @@ -746,8 +746,6 @@ struct iwl4965_priv; /* * Forward declare iwl-4965.c functions for iwl-base.c */ -extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv); - extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq, u16 byte_cnt); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b8383c83f18d..9ca539861db2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -31,6 +31,7 @@ #include #include "iwl-4965-debug.h" +#include "iwl-eeprom.h" #include "iwl-core.h" MODULE_DESCRIPTION("iwl core"); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index bdd32f891683..88fd49abdabd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -75,10 +75,20 @@ #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 +struct iwl_lib_ops { + /* eeprom operations (as defined in iwl-eeprom.h) */ + struct iwl_eeprom_ops eeprom_ops; +}; + +struct iwl_ops { + const struct iwl_lib_ops *lib; +}; + struct iwl_cfg { const char *name; const char *fw_name; unsigned int sku; + const struct iwl_ops *ops; }; #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index ce1c3f68fde0..d84a7f296d90 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -45,6 +45,7 @@ #include +#include "iwl-eeprom.h" #include "iwl-core.h" #include "iwl-4965.h" #include "iwl-helpers.h" @@ -1560,85 +1561,6 @@ static int iwl4965_send_beacon_cmd(struct iwl4965_priv *priv) return rc; } -/****************************************************************************** - * - * EEPROM related functions - * - ******************************************************************************/ - -static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac) -{ - memcpy(mac, priv->eeprom.mac_address, 6); -} - -static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv) -{ - iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); -} - -/** - * iwl4965_eeprom_init - read EEPROM contents - * - * Load the EEPROM contents from adapter into priv->eeprom - * - * NOTE: This routine uses the non-debug IO access functions. - */ -int iwl4965_eeprom_init(struct iwl4965_priv *priv) -{ - u16 *e = (u16 *)&priv->eeprom; - u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP); - u32 r; - int sz = sizeof(priv->eeprom); - int rc; - int i; - u16 addr; - - /* The EEPROM structure has several padding buffers within it - * and when adding new EEPROM maps is subject to programmer errors - * which may be very difficult to identify without explicitly - * checking the resulting size of the eeprom map. */ - BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE); - - if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) { - IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp); - return -ENOENT; - } - - /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - rc = iwl4965_eeprom_acquire_semaphore(priv); - if (rc < 0) { - IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); - return -ENOENT; - } - - /* eeprom is an array of 16bit values */ - for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); - - for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; - i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } - - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { - IWL_ERROR("Time out reading EEPROM[%d]", addr); - rc = -ETIMEDOUT; - goto done; - } - e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); - } - rc = 0; - -done: - iwl4965_eeprom_release_semaphore(priv); - return rc; -} - /****************************************************************************** * * Misc. internal state and helper functions @@ -8765,13 +8687,13 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e goto out_remove_sysfs; } /* Read the EEPROM */ - err = iwl4965_eeprom_init(priv); + err = iwl_eeprom_init(priv); if (err) { IWL_ERROR("Unable to init EEPROM\n"); goto out_remove_sysfs; } /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_mac(priv, priv->mac_addr); + iwl_eeprom_get_mac(priv, priv->mac_addr); IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); -- cgit v1.2.3-59-g8ed1b From 712b6cf57a53da608a682b5f782c5785bda76001 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 12 Mar 2008 16:58:52 -0700 Subject: iwlwifi: Add debugfs to iwl core This patch adds debugfs support to iwl core currently only iwl4965 is supported Signed-off-by: Tomas Winkler Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 6 + drivers/net/wireless/iwlwifi/Makefile | 4 + drivers/net/wireless/iwlwifi/iwl-4965.h | 6 +- drivers/net/wireless/iwlwifi/iwl-core.c | 3 +- drivers/net/wireless/iwlwifi/iwl-debug.h | 31 ++- drivers/net/wireless/iwlwifi/iwl-debugfs.c | 319 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 14 +- 7 files changed, 377 insertions(+), 6 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-debugfs.c (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index acb807936131..1ab14ed33f58 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -76,6 +76,12 @@ config IWLWIFI_DEBUG as the debug information can assist others in helping you resolve any problems you may encounter. +config IWLWIFI_DEBUGFS + bool "Iwlwifi debugfs support" + depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS + ---help--- + Enable creation of debugfs files for the iwlwifi drivers. + config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 59d9c90d3610..86ac1fc60bbb 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,6 +1,10 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o iwlcore-objs = iwl-core.o iwl-eeprom.o +ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y) + iwlcore-objs += iwl-debugfs.o +endif + obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index aded6010ce20..cec62ba803b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -1212,7 +1212,11 @@ struct iwl_priv { /* debugging info */ u32 framecnt_to_us; atomic_t restrict_refcnt; -#endif +#ifdef CONFIG_IWLWIFI_DEBUGFS + /* debugfs */ + struct iwl_debugfs *dbgfs; +#endif /* CONFIG_IWLWIFI_DEBUGFS */ +#endif /* CONFIG_IWLWIFI_DEBUG */ struct work_struct txpower_work; #ifdef CONFIG_IWL4965_SENSITIVITY diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 4645d194773e..3a9fc905e6bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -30,6 +30,7 @@ #include #include +struct iwl_priv; /* FIXME: remove */ #include "iwl-debug.h" #include "iwl-eeprom.h" #include "iwl-core.h" @@ -37,7 +38,7 @@ MODULE_DESCRIPTION("iwl core"); MODULE_VERSION(IWLWIFI_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); -MODULE_LICENSE("GPL/BSD"); +MODULE_LICENSE("GPL"); #ifdef CONFIG_IWLWIFI_DEBUG u32 iwl_debug_level; diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 067700620e21..c60724c21db8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -49,8 +49,27 @@ static inline void iwl_print_hex_dump(int level, void *p, u32 len) print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); } -#else +#ifdef CONFIG_IWLWIFI_DEBUGFS +struct iwl_debugfs { + const char *name; + struct dentry *dir_drv; + struct dentry *dir_data; + struct dir_data_files{ + struct dentry *file_sram; + struct dentry *file_stations; + struct dentry *file_rx_statistics; + struct dentry *file_tx_statistics; + } dbgfs_data_files; + u32 sram_offset; + u32 sram_len; +}; + +int iwl_dbgfs_register(struct iwl_priv *priv, const char *name); +void iwl_dbgfs_unregister(struct iwl_priv *priv); +#endif + +#else static inline void IWL_DEBUG(int level, const char *fmt, ...) { } @@ -64,6 +83,16 @@ static inline void iwl_print_hex_dump(int level, void *p, u32 len) +#ifndef CONFIG_IWLWIFI_DEBUGFS +static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) +{ + return 0; +} +static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) +{ +} +#endif /* CONFIG_IWLWIFI_DEBUGFS */ + /* * To use the debug system; * diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c new file mode 100644 index 000000000000..c659bd3bc346 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -0,0 +1,319 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include +#include +#include + +#include +#include + + +#include "iwl-4965.h" +#include "iwl-debug.h" +#include "iwl-4965-io.h" + + +/* create and remove of files */ +#define DEBUGFS_ADD_DIR(name, parent) do { \ + dbgfs->dir_##name = debugfs_create_dir(#name, parent); \ + if (!(dbgfs->dir_##name)) \ + goto err; \ +} while (0) + +#define DEBUGFS_ADD_FILE(name, parent) do { \ + dbgfs->dbgfs_##parent##_files.file_##name = \ + debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ + &iwl_dbgfs_##name##_ops); \ + if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ + goto err; \ +} while (0) + +#define DEBUGFS_REMOVE(name) do { \ + debugfs_remove(name); \ + name = NULL; \ +} while (0); + +/* file operation */ +#define DEBUGFS_READ_FUNC(name) \ +static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos); + +#define DEBUGFS_WRITE_FUNC(name) \ +static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos); + + +static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +#define DEBUGFS_READ_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .read = iwl_dbgfs_##name##_read, \ + .open = iwl_dbgfs_open_file_generic, \ +}; + +#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .read = iwl_dbgfs_##name##_read, \ + .open = iwl_dbgfs_open_file_generic, \ +}; + + +static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[256]; + int pos = 0; + + pos += sprintf(buf+pos, "mgmt: %u\n", priv->tx_stats[0].cnt); + pos += sprintf(buf+pos, "ctrl: %u\n", priv->tx_stats[1].cnt); + pos += sprintf(buf+pos, "data: %u\n", priv->tx_stats[2].cnt); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + char buf[256]; + int pos = 0; + + pos += sprintf(buf+pos, "mgmt: %u\n", priv->rx_stats[0].cnt); + pos += sprintf(buf+pos, "ctrl: %u\n", priv->rx_stats[1].cnt); + pos += sprintf(buf+pos, "data: %u\n", priv->rx_stats[2].cnt); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +#define BYTE1_MASK 0x000000ff; +#define BYTE2_MASK 0x0000ffff; +#define BYTE3_MASK 0x00ffffff; +static ssize_t iwl_dbgfs_sram_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + u32 val; + char buf[1024]; + ssize_t ret; + int i; + int pos = 0; + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + + printk(KERN_DEBUG "offset is: 0x%x\tlen is: 0x%x\n", + priv->dbgfs->sram_offset, priv->dbgfs->sram_len); + + iwl4965_grab_nic_access(priv); + for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { + val = iwl4965_read_targ_mem(priv, priv->dbgfs->sram_offset + \ + priv->dbgfs->sram_len - i); + if (i < 4) { + switch (i) { + case 1: + val &= BYTE1_MASK; + break; + case 2: + val &= BYTE2_MASK; + break; + case 3: + val &= BYTE3_MASK; + break; + } + } + pos += sprintf(buf+pos, "0x%08x ", val); + } + pos += sprintf(buf+pos, "\n"); + iwl4965_release_nic_access(priv); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret; +} + +static ssize_t iwl_dbgfs_sram_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[64]; + int buf_size; + u32 offset, len; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + if (sscanf(buf, "%x,%x", &offset, &len) == 2) { + priv->dbgfs->sram_offset = offset; + priv->dbgfs->sram_len = len; + } else { + priv->dbgfs->sram_offset = 0; + priv->dbgfs->sram_len = 0; + } + + return count; +} + +static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct iwl4965_station_entry *station; + int max_sta = priv->hw_setting.max_stations; + char *buf; + int i, j, pos = 0; + ssize_t ret; + /* Add 30 for initial string */ + const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations); + DECLARE_MAC_BUF(mac); + + buf = kmalloc(bufsz, GFP_KERNEL); + if(!buf) + return -ENOMEM; + + pos += sprintf(buf+pos, "num of stations: %d\n\n", + priv->num_stations); + + for (i = 0; i < max_sta; i++) { + station = &priv->stations[i]; + if (station->used) { + pos += sprintf(buf+pos, "station %d:\ngeneral data:\n", + i+1); + print_mac(mac, station->sta.sta.addr); + pos += sprintf(buf+pos, "id: %u\n", + station->sta.sta.sta_id); + pos += sprintf(buf+pos, "mode: %u\n", + station->sta.mode); + pos += sprintf(buf+pos, "flags: 0x%x\n", + station->sta.station_flags_msk); + pos += sprintf(buf+pos, "ps_status: %u\n", + station->ps_status); + + pos += sprintf(buf+pos, "tid data:\n"); + + pos += sprintf(buf+pos, "seq_num\t\ttxq_id\t"); + pos += sprintf(buf+pos, "frame_count\twait_for_ba\t"); + pos += sprintf(buf+pos, "start_idx\tbitmap0\t"); + pos += sprintf(buf+pos, "bitmap1\trate_n_flags\n"); + + for (j = 0; j < MAX_TID_COUNT; j++) { + pos += sprintf(buf+pos, "[%d]:\t\t%u\t", + j, station->tid[j].seq_number); + pos += sprintf(buf+pos, "%u\t\t%u\t\t%u\t\t", + station->tid[j].agg.txq_id, + station->tid[j].agg.frame_count, + station->tid[j].agg.wait_for_ba); + pos += sprintf(buf+pos, "%u\t%llu\t%u\n", + station->tid[j].agg.start_idx, + station->tid[j].agg.bitmap, + station->tid[j].agg.rate_n_flags); + } + pos += sprintf(buf+pos, "\n"); + } + } + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + +DEBUGFS_READ_WRITE_FILE_OPS(sram); +DEBUGFS_READ_FILE_OPS(stations); +DEBUGFS_READ_FILE_OPS(rx_statistics); +DEBUGFS_READ_FILE_OPS(tx_statistics); + +/* + * Create the debugfs files and directories + * + */ +int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) +{ + struct iwl_debugfs *dbgfs; + + dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); + if (!dbgfs) { + goto err; + } + + priv->dbgfs = dbgfs; + dbgfs->name = name; + dbgfs->dir_drv = debugfs_create_dir(name, NULL); + if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){ + goto err; + } + + DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); + DEBUGFS_ADD_FILE(sram, data); + DEBUGFS_ADD_FILE(stations, data); + DEBUGFS_ADD_FILE(rx_statistics, data); + DEBUGFS_ADD_FILE(tx_statistics, data); + + return 0; + +err: + IWL_ERROR("Can't open the debugfs directory\n"); + iwl_dbgfs_unregister(priv); + return -ENOENT; +} +EXPORT_SYMBOL(iwl_dbgfs_register); + +/** + * Remove the debugfs files and directories + * + */ +void iwl_dbgfs_unregister(struct iwl_priv *priv) +{ + if (!(priv->dbgfs)) + return; + + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); + DEBUGFS_REMOVE(priv->dbgfs->dir_data); + DEBUGFS_REMOVE(priv->dbgfs->dir_drv); + kfree(priv->dbgfs); + priv->dbgfs = NULL; +} +EXPORT_SYMBOL(iwl_dbgfs_unregister); + + diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 4f6ed6942065..396940e701e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -8690,6 +8690,11 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e goto out_release_irq; } + err = iwl_dbgfs_register(priv, DRV_NAME); + if (err) { + IWL_ERROR("failed to create debugfs files\n"); + goto out_remove_sysfs; + } /* nic init */ iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); @@ -8700,13 +8705,13 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (err < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); - goto out_remove_sysfs; + goto out_remove_dbgfs; } /* Read the EEPROM */ err = iwl_eeprom_init(priv); if (err) { IWL_ERROR("Unable to init EEPROM\n"); - goto out_remove_sysfs; + goto out_remove_dbgfs; } /* MAC Address location in EEPROM same for 3945/4965 */ iwl_eeprom_get_mac(priv, priv->mac_addr); @@ -8716,7 +8721,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = iwl4965_init_channel_map(priv); if (err) { IWL_ERROR("initializing regulatory failed: %d\n", err); - goto out_remove_sysfs; + goto out_remove_dbgfs; } err = iwl4965_init_geos(priv); @@ -8743,6 +8748,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e iwl4965_free_geos(priv); out_free_channel_map: iwl4965_free_channel_map(priv); + out_remove_dbgfs: + iwl_dbgfs_unregister(priv); out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); @@ -8787,6 +8794,7 @@ static void iwl4965_pci_remove(struct pci_dev *pdev) } } + iwl_dbgfs_unregister(priv); sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); iwl4965_dealloc_ucode_pci(priv); -- cgit v1.2.3-59-g8ed1b From 857485c0c46ceee5c658c1761bba4d9a5ddf433f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 21 Mar 2008 13:53:44 -0700 Subject: iwlwifi: move host command sending functions to core module 1. Host command sending functions moved from iwl4965-base.c to iwl-hcmd.c in iwlcore module 2. enqueue_hcmd function currently stays in iwl4965-base.c. It is invoked through the new 'utils' field in priv's ops. Signed-off-by: Tomas Winkler Signed-off-by: Assaf Krauss Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 14 +- drivers/net/wireless/iwlwifi/iwl-4965-hw.h | 3 - drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 7 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 86 +++---- drivers/net/wireless/iwlwifi/iwl-4965.h | 33 ++- drivers/net/wireless/iwlwifi/iwl-core.h | 26 ++ drivers/net/wireless/iwlwifi/iwl-hcmd.c | 251 +++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 299 ++++------------------- 9 files changed, 399 insertions(+), 322 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-hcmd.c (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 86ac1fc60bbb..6be8012a1743 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWLCORE) += iwlcore.o -iwlcore-objs = iwl-core.o iwl-eeprom.o +iwlcore-objs = iwl-core.o iwl-eeprom.o iwl-hcmd.o ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y) iwlcore-objs += iwl-debugfs.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h index 1d82f105cc26..7e36ecb27575 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -139,7 +139,7 @@ enum { REPLY_PHY_CALIBRATION_CMD = 0xb0, REPLY_RX_PHY_CMD = 0xc0, REPLY_RX_MPDU_CMD = 0xc1, - REPLY_4965_RX = 0xc3, + REPLY_RX = 0xc3, REPLY_COMPRESSED_BA = 0xc5, REPLY_MAX = 0xff }; @@ -151,16 +151,16 @@ enum { * *****************************************************************************/ -/* iwl4965_cmd_header flags value */ +/* iwl_cmd_header flags value */ #define IWL_CMD_FAILED_MSK 0x40 /** - * struct iwl4965_cmd_header + * struct iwl_cmd_header * * This header format appears in the beginning of each command sent from the * driver, and each response/notification received from uCode. */ -struct iwl4965_cmd_header { +struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* IWL_CMD_* */ /* @@ -194,7 +194,7 @@ struct iwl4965_cmd_header { * 4965 rate_n_flags bit fields * * rate_n_flags format is used in following 4965 commands: - * REPLY_4965_RX (response only) + * REPLY_RX (response only) * REPLY_TX (both command and response) * REPLY_TX_LINK_QUALITY_CMD * @@ -939,7 +939,7 @@ struct iwl4965_rx_non_cfg_phy { } __attribute__ ((packed)); /* - * REPLY_4965_RX = 0xc3 (response only, not a command) + * REPLY_RX = 0xc3 (response only, not a command) * Used only for legacy (non 11n) frames. */ #define RX_RES_PHY_CNT 14 @@ -2664,7 +2664,7 @@ struct iwl4965_led_cmd { struct iwl4965_rx_packet { __le32 len; - struct iwl4965_cmd_header hdr; + struct iwl_cmd_header hdr; union { struct iwl4965_alive_resp alive_frame; struct iwl4965_rx_frame rx_frame; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index c66993eb5b6a..1898888e71f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -113,9 +113,6 @@ #define TFD_TX_CMD_SLOTS 256 #define TFD_CMD_SLOTS 32 -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \ - sizeof(struct iwl4965_cmd_meta)) - /* * RX related structures and functions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 02990aeabab5..7d7ce7489ab5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -39,6 +39,7 @@ #include "../net/mac80211/ieee80211_rate.h" #include "iwl-4965.h" +#include "iwl-core.h" #include "iwl-helpers.h" #define RS_NAME "iwl-4965-rs" @@ -230,7 +231,7 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { }; static int iwl4965_lq_sync_callback(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb) + struct iwl_cmd *cmd, struct sk_buff *skb) { /*We didn't cache the SKB; let the caller free it */ return 1; @@ -247,7 +248,7 @@ static int rs_send_lq_cmd(struct iwl_priv *priv, #ifdef CONFIG_IWLWIFI_DEBUG int i; #endif - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_TX_LINK_QUALITY_CMD, .len = sizeof(struct iwl4965_link_quality_cmd), .meta.flags = flags, @@ -276,7 +277,7 @@ static int rs_send_lq_cmd(struct iwl_priv *priv, if (iwl4965_is_associated(priv) && priv->assoc_station_added && priv->lq_mngr.lq_ready) - return iwl4965_send_cmd(priv, &cmd); + return iwl_send_cmd(priv, &cmd); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index c0c35d38cf5e..46b3f47edefd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -861,7 +861,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) u32 temp_th; u32 crit_temperature; unsigned long flags; - int rc = 0; + int ret = 0; spin_lock_irqsave(&priv->lock, flags); iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, @@ -882,9 +882,9 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; cmd.critical_temperature_R = cpu_to_le32(crit_temperature); - rc = iwl4965_send_cmd_pdu(priv, - REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); - if (rc) + ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, + sizeof(cmd), &cmd); + if (ret) IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); else IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); @@ -1157,7 +1157,7 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, } static int iwl4965_sensitivity_callback(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb) + struct iwl_cmd *cmd, struct sk_buff *skb) { /* We didn't cache the SKB; let the caller free it */ return 1; @@ -1166,15 +1166,15 @@ static int iwl4965_sensitivity_callback(struct iwl_priv *priv, /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) { - int rc = 0; struct iwl4965_sensitivity_cmd cmd ; struct iwl4965_sensitivity_data *data = NULL; - struct iwl4965_host_cmd cmd_out = { + struct iwl_host_cmd cmd_out = { .id = SENSITIVITY_CMD, .len = sizeof(struct iwl4965_sensitivity_cmd), .meta.flags = flags, .data = &cmd, }; + int ret; data = &(priv->sensitivity_data); @@ -1232,20 +1232,18 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16)*HD_TABLE_SIZE); - rc = iwl4965_send_cmd(priv, &cmd_out); - if (!rc) { - IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n"); - return rc; - } + ret = iwl_send_cmd(priv, &cmd_out); + if (ret) + IWL_ERROR("SENSITIVITY_CMD failed\n"); - return 0; + return ret; } void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) { - int rc = 0; - int i; struct iwl4965_sensitivity_data *data = NULL; + int i; + int ret = 0; IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n"); @@ -1289,8 +1287,8 @@ void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) memset(&(priv->sensitivity_tbl[0]), 0, sizeof(u16)*HD_TABLE_SIZE); - rc |= iwl4965_sensitivity_write(priv, flags); - IWL_DEBUG_CALIB("<chain_noise_data); if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl4965_is_associated(priv)) { @@ -1313,7 +1310,7 @@ void iwl4965_chain_noise_reset(struct iwl_priv *priv) cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; - rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, sizeof(cmd), &cmd); msleep(4); data->state = IWL_CHAIN_NOISE_ACCUMULATE; @@ -1332,7 +1329,7 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv, struct iwl4965_notif_statistics *stat_resp) { struct iwl4965_chain_noise_data *data = NULL; - int rc = 0; + int ret = 0; u32 chain_noise_a; u32 chain_noise_b; @@ -1538,9 +1535,9 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv, cmd.diff_gain_a = data->delta_gain_code[0]; cmd.diff_gain_b = data->delta_gain_code[1]; cmd.diff_gain_c = data->delta_gain_code[2]; - rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, sizeof(cmd), &cmd); - if (rc) + if (ret) IWL_DEBUG_CALIB("fail sending cmd " "REPLY_PHY_CALIBRATION_CMD \n"); @@ -1564,7 +1561,6 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv, static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, struct iwl4965_notif_statistics *resp) { - int rc = 0; u32 rx_enable_time; u32 fa_cck; u32 fa_ofdm; @@ -1577,6 +1573,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, struct statistics_rx *statistics = &(resp->rx); unsigned long flags; struct statistics_general_data statis; + int ret; data = &(priv->sensitivity_data); @@ -1661,7 +1658,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time); iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis); - rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC); + ret = iwl4965_sensitivity_write(priv, CMD_ASYNC); return; } @@ -1789,7 +1786,7 @@ int iwl4965_alive_notify(struct iwl_priv *priv) u32 a; int i = 0; unsigned long flags; - int rc; + int ret; spin_lock_irqsave(&priv->lock, flags); @@ -1802,10 +1799,10 @@ int iwl4965_alive_notify(struct iwl_priv *priv) priv->chain_noise_data.delta_gain_code[i] = CHAIN_NOISE_DELTA_GAIN_INIT_VAL; #endif /* CONFIG_IWL4965_SENSITIVITY*/ - rc = iwl4965_grab_nic_access(priv); - if (rc) { + ret = iwl4965_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } /* Clear 4965's internal Tx Scheduler data base */ @@ -1868,7 +1865,7 @@ int iwl4965_alive_notify(struct iwl_priv *priv) iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - return 0; + return ret; } /** @@ -2719,7 +2716,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv) { struct iwl4965_txpowertable_cmd cmd = { 0 }; - int rc = 0; + int ret; u8 band = 0; u8 is_fat = 0; u8 ctrl_chan_high = 0; @@ -2743,14 +2740,16 @@ int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv) cmd.band = band; cmd.channel = priv->active_rxon.channel; - rc = iwl4965_fill_txpower_tbl(priv, band, + ret = iwl4965_fill_txpower_tbl(priv, band, le16_to_cpu(priv->active_rxon.channel), is_fat, ctrl_chan_high, &cmd.tx_power); - if (rc) - return rc; + if (ret) + goto out; - rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); - return rc; + ret = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); + +out: + return ret; } int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) @@ -2790,7 +2789,7 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) return rc; } - rc = iwl4965_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); + rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); return rc; } @@ -2798,7 +2797,7 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) #define RTS_DFAULT_RETRY_LIMIT 60 void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, + struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int sta_id, int is_hcca) @@ -3863,7 +3862,7 @@ static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -/* Called for REPLY_4965_RX (legacy ABG frames), or +/* Called for REPLY_RX (legacy ABG frames), or * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb) @@ -3874,7 +3873,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, /* Use phy data (Rx signal strength, etc.) contained within * this rx packet for legacy frames, * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ - int include_phy = (pkt->hdr.cmd == REPLY_4965_RX); + int include_phy = (pkt->hdr.cmd == REPLY_RX); struct iwl4965_rx_phy_res *rx_start = (include_phy) ? (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; @@ -4562,7 +4561,7 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) /* Update the rate scaling for control frame Tx to AP */ link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_setting.bcast_sta_id; - iwl4965_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), + iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), &link_cmd); } @@ -4915,7 +4914,7 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv) { /* Legacy Rx frames */ - priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx; + priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx; /* High-throughput (HT) Rx frames */ priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy; @@ -4948,6 +4947,10 @@ void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv) cancel_delayed_work(&priv->init_alive_start); } +static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { + .enqueue_hcmd = iwl4965_enqueue_hcmd, +}; + static struct iwl_lib_ops iwl4965_lib = { .init_drv = iwl4965_init_drv, .eeprom_ops = { @@ -4959,6 +4962,7 @@ static struct iwl_lib_ops iwl4965_lib = { static struct iwl_ops iwl4965_ops = { .lib = &iwl4965_lib, + .utils = &iwl4965_hcmd_utils, }; static struct iwl_cfg iwl4965_agn_cfg = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index b73c1544e909..810b8e28dc83 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -140,7 +140,7 @@ struct iwl4965_tx_info { struct iwl4965_tx_queue { struct iwl4965_queue q; struct iwl4965_tfd_frame *bd; - struct iwl4965_cmd *cmd; + struct iwl_cmd *cmd; dma_addr_t dma_addr_cmd; struct iwl4965_tx_info *txb; int need_update; @@ -312,15 +312,15 @@ enum { CMD_WANT_SKB = (1 << 2), }; -struct iwl4965_cmd; +struct iwl_cmd; struct iwl_priv; -struct iwl4965_cmd_meta { - struct iwl4965_cmd_meta *source; +struct iwl_cmd_meta { + struct iwl_cmd_meta *source; union { struct sk_buff *skb; int (*callback)(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb); + struct iwl_cmd *cmd, struct sk_buff *skb); } __attribute__ ((packed)) u; /* The CMD_SIZE_HUGE flag bit indicates that the command @@ -330,15 +330,15 @@ struct iwl4965_cmd_meta { } __attribute__ ((packed)); /** - * struct iwl4965_cmd + * struct iwl_cmd * * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for a scan command * (which is relatively huge; space is allocated separately). */ -struct iwl4965_cmd { - struct iwl4965_cmd_meta meta; /* driver data */ - struct iwl4965_cmd_header hdr; /* uCode API */ +struct iwl_cmd { + struct iwl_cmd_meta meta; /* driver data */ + struct iwl_cmd_header hdr; /* uCode API */ union { struct iwl4965_addsta_cmd addsta; struct iwl4965_led_cmd led; @@ -358,15 +358,15 @@ struct iwl4965_cmd { } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); -struct iwl4965_host_cmd { +struct iwl_host_cmd { u8 id; u16 len; - struct iwl4965_cmd_meta meta; + struct iwl_cmd_meta meta; const void *data; }; -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \ - sizeof(struct iwl4965_cmd_meta)) +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ + sizeof(struct iwl_cmd_meta)) /* * RX related structures and functions @@ -656,10 +656,6 @@ extern int iwl4965_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq, int count, u32 id); extern void iwl4965_rx_replenish(void *data); extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); -extern int iwl4965_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, - const void *data); -extern int __must_check iwl4965_send_cmd(struct iwl_priv *priv, - struct iwl4965_host_cmd *cmd); extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left); @@ -674,6 +670,7 @@ int iwl4965_init_geos(struct iwl_priv *priv); void iwl4965_free_geos(struct iwl_priv *priv); extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; +int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /* * Currently used by iwl-3945-rs... look at restructuring so that it doesn't @@ -718,7 +715,7 @@ extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl4965_frame *frame, u8 rate); extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv); extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, + struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int sta_id, int tx_id); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4dde4d628a80..ce7f90ebf367 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -63,6 +63,13 @@ #ifndef __iwl_core_h__ #define __iwl_core_h__ +/************************ + * forward declarations * + ************************/ +struct iwl_host_cmd; +struct iwl_cmd; + + #define IWLWIFI_VERSION "1.2.26k" #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" @@ -75,6 +82,10 @@ #define IWL_SKU_A 0x2 #define IWL_SKU_N 0x8 +struct iwl_hcmd_utils_ops { + int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +}; + struct iwl_lib_ops { /* iwlwifi driver (priv) init */ int (*init_drv)(struct iwl_priv *priv); @@ -84,6 +95,7 @@ struct iwl_lib_ops { struct iwl_ops { const struct iwl_lib_ops *lib; + const struct iwl_hcmd_utils_ops *utils; }; struct iwl_mod_params { @@ -120,4 +132,18 @@ int iwlcore_set_rxon_channel(struct iwl_priv *priv, int iwl_setup(struct iwl_priv *priv); +/***************************************************** + * S e n d i n g H o s t C o m m a n d s * + *****************************************************/ + +const char *get_cmd_string(u8 cmd); +int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data); +int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, + const void *data, + int (*callback)(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb)); + #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c new file mode 100644 index 000000000000..559ff739961e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -0,0 +1,251 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Tomas Winkler + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include +#include +#include +#include + +#include "iwl-4965.h" /* FIXME: remove */ +#include "iwl-debug.h" +#include "iwl-eeprom.h" +#include "iwl-core.h" + + +#define IWL_CMD(x) case x : return #x + +const char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IWL_CMD(REPLY_ALIVE); + IWL_CMD(REPLY_ERROR); + IWL_CMD(REPLY_RXON); + IWL_CMD(REPLY_RXON_ASSOC); + IWL_CMD(REPLY_QOS_PARAM); + IWL_CMD(REPLY_RXON_TIMING); + IWL_CMD(REPLY_ADD_STA); + IWL_CMD(REPLY_REMOVE_STA); + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_TX); + IWL_CMD(REPLY_RATE_SCALE); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(RADAR_NOTIFICATION); + IWL_CMD(REPLY_QUIET_CMD); + IWL_CMD(REPLY_CHANNEL_SWITCH); + IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); + IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); + IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); + IWL_CMD(POWER_TABLE_CMD); + IWL_CMD(PM_SLEEP_NOTIFICATION); + IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); + IWL_CMD(REPLY_SCAN_CMD); + IWL_CMD(REPLY_SCAN_ABORT_CMD); + IWL_CMD(SCAN_START_NOTIFICATION); + IWL_CMD(SCAN_RESULTS_NOTIFICATION); + IWL_CMD(SCAN_COMPLETE_NOTIFICATION); + IWL_CMD(BEACON_NOTIFICATION); + IWL_CMD(REPLY_TX_BEACON); + IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); + IWL_CMD(QUIET_NOTIFICATION); + IWL_CMD(REPLY_TX_PWR_TABLE_CMD); + IWL_CMD(MEASURE_ABORT_NOTIFICATION); + IWL_CMD(REPLY_BT_CONFIG); + IWL_CMD(REPLY_STATISTICS_CMD); + IWL_CMD(STATISTICS_NOTIFICATION); + IWL_CMD(REPLY_CARD_STATE_CMD); + IWL_CMD(CARD_STATE_NOTIFICATION); + IWL_CMD(MISSED_BEACONS_NOTIFICATION); + IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); + IWL_CMD(SENSITIVITY_CMD); + IWL_CMD(REPLY_PHY_CALIBRATION_CMD); + IWL_CMD(REPLY_RX_PHY_CMD); + IWL_CMD(REPLY_RX_MPDU_CMD); + IWL_CMD(REPLY_RX); + IWL_CMD(REPLY_COMPRESSED_BA); + default: + return "UNKNOWN"; + + } +} +EXPORT_SYMBOL(get_cmd_string); + +#define HOST_COMPLETE_TIMEOUT (HZ / 2) + +static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int ret; + + BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); + + /* An asynchronous command can not expect an SKB to be set. */ + BUG_ON(cmd->meta.flags & CMD_WANT_SKB); + + /* An asynchronous command MUST have a callback. */ + BUG_ON(!cmd->meta.u.callback); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return -EBUSY; + + ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + if (ret < 0) { + IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + return ret; + } + return 0; +} + +int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + int cmd_idx; + int ret; + static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ + + BUG_ON(cmd->meta.flags & CMD_ASYNC); + + /* A synchronous command can not have a callback set. */ + BUG_ON(cmd->meta.u.callback != NULL); + + if (atomic_xchg(&entry, 1)) { + IWL_ERROR("Error sending %s: Already sending a host command\n", + get_cmd_string(cmd->id)); + return -EBUSY; + } + + set_bit(STATUS_HCMD_ACTIVE, &priv->status); + + if (cmd->meta.flags & CMD_WANT_SKB) + cmd->meta.source = &cmd->meta; + + cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd); + if (cmd_idx < 0) { + ret = cmd_idx; + IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n", + get_cmd_string(cmd->id), ret); + goto out; + } + + ret = wait_event_interruptible_timeout(priv->wait_command_queue, + !test_bit(STATUS_HCMD_ACTIVE, &priv->status), + HOST_COMPLETE_TIMEOUT); + if (!ret) { + if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { + IWL_ERROR("Error sending %s: time out after %dms.\n", + get_cmd_string(cmd->id), + jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); + + clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + ret = -ETIMEDOUT; + goto cancel; + } + } + + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { + IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", + get_cmd_string(cmd->id)); + ret = -ECANCELED; + goto fail; + } + if (test_bit(STATUS_FW_ERROR, &priv->status)) { + IWL_DEBUG_INFO("Command %s failed: FW Error\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto fail; + } + if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { + IWL_ERROR("Error: Response NULL in '%s'\n", + get_cmd_string(cmd->id)); + ret = -EIO; + goto out; + } + + ret = 0; + goto out; + +cancel: + if (cmd->meta.flags & CMD_WANT_SKB) { + struct iwl_cmd *qcmd; + + /* Cancel the CMD_WANT_SKB flag for the cmd in the + * TX cmd queue. Otherwise in case the cmd comes + * in later, it will possibly set an invalid + * address (cmd->meta.source). */ + qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; + qcmd->meta.flags &= ~CMD_WANT_SKB; + } +fail: + if (cmd->meta.u.skb) { + dev_kfree_skb_any(cmd->meta.u.skb); + cmd->meta.u.skb = NULL; + } +out: + atomic_set(&entry, 0); + return ret; +} +EXPORT_SYMBOL(iwl_send_cmd_sync); + +int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +{ + if (cmd->meta.flags & CMD_ASYNC) + return iwl_send_cmd_async(priv, cmd); + + return iwl_send_cmd_sync(priv, cmd); +} +EXPORT_SYMBOL(iwl_send_cmd); + +int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + return iwl_send_cmd_sync(priv, &cmd); +} +EXPORT_SYMBOL(iwl_send_cmd_pdu); + +int iwl_send_cmd_pdu_async(struct iwl_priv *priv, + u8 id, u16 len, const void *data, + int (*callback)(struct iwl_priv *priv, + struct iwl_cmd *cmd, + struct sk_buff *skb)) +{ + struct iwl_host_cmd cmd = { + .id = id, + .len = len, + .data = data, + }; + + cmd.meta.flags |= CMD_ASYNC; + cmd.meta.u.callback = callback; + + return iwl_send_cmd_async(priv, &cmd); +} +EXPORT_SYMBOL(iwl_send_cmd_pdu_async); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index fac9bf1aa1d7..8fe09e893279 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -305,7 +305,7 @@ int iwl4965_tx_queue_init(struct iwl_priv *priv, * For normal Tx queues (all other queues), no super-size command * space is needed. */ - len = sizeof(struct iwl4965_cmd) * slots_num; + len = sizeof(struct iwl_cmd) * slots_num; if (txq_id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd); @@ -356,7 +356,7 @@ void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) iwl4965_hw_txq_free_tfd(priv, txq); - len = sizeof(struct iwl4965_cmd) * q->n_window; + len = sizeof(struct iwl_cmd) * q->n_window; if (q->id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; @@ -541,65 +541,6 @@ static inline int iwl4965_is_ready_rf(struct iwl_priv *priv) /*************** HOST COMMAND QUEUE FUNCTIONS *****/ -#define IWL_CMD(x) case x : return #x - -static const char *get_cmd_string(u8 cmd) -{ - switch (cmd) { - IWL_CMD(REPLY_ALIVE); - IWL_CMD(REPLY_ERROR); - IWL_CMD(REPLY_RXON); - IWL_CMD(REPLY_RXON_ASSOC); - IWL_CMD(REPLY_QOS_PARAM); - IWL_CMD(REPLY_RXON_TIMING); - IWL_CMD(REPLY_ADD_STA); - IWL_CMD(REPLY_REMOVE_STA); - IWL_CMD(REPLY_REMOVE_ALL_STA); - IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_RATE_SCALE); - IWL_CMD(REPLY_LEDS_CMD); - IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); - IWL_CMD(RADAR_NOTIFICATION); - IWL_CMD(REPLY_QUIET_CMD); - IWL_CMD(REPLY_CHANNEL_SWITCH); - IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); - IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); - IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); - IWL_CMD(POWER_TABLE_CMD); - IWL_CMD(PM_SLEEP_NOTIFICATION); - IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); - IWL_CMD(REPLY_SCAN_CMD); - IWL_CMD(REPLY_SCAN_ABORT_CMD); - IWL_CMD(SCAN_START_NOTIFICATION); - IWL_CMD(SCAN_RESULTS_NOTIFICATION); - IWL_CMD(SCAN_COMPLETE_NOTIFICATION); - IWL_CMD(BEACON_NOTIFICATION); - IWL_CMD(REPLY_TX_BEACON); - IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); - IWL_CMD(QUIET_NOTIFICATION); - IWL_CMD(REPLY_TX_PWR_TABLE_CMD); - IWL_CMD(MEASURE_ABORT_NOTIFICATION); - IWL_CMD(REPLY_BT_CONFIG); - IWL_CMD(REPLY_STATISTICS_CMD); - IWL_CMD(STATISTICS_NOTIFICATION); - IWL_CMD(REPLY_CARD_STATE_CMD); - IWL_CMD(CARD_STATE_NOTIFICATION); - IWL_CMD(MISSED_BEACONS_NOTIFICATION); - IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); - IWL_CMD(SENSITIVITY_CMD); - IWL_CMD(REPLY_PHY_CALIBRATION_CMD); - IWL_CMD(REPLY_RX_PHY_CMD); - IWL_CMD(REPLY_RX_MPDU_CMD); - IWL_CMD(REPLY_4965_RX); - IWL_CMD(REPLY_COMPRESSED_BA); - default: - return "UNKNOWN"; - - } -} - -#define HOST_COMPLETE_TIMEOUT (HZ / 2) - /** * iwl4965_enqueue_hcmd - enqueue a uCode command * @priv: device private data point @@ -609,13 +550,13 @@ static const char *get_cmd_string(u8 cmd) * failed. On success, it turns the index (> 0) of command in the * command queue. */ -static int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl4965_host_cmd *cmd) +int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl4965_queue *q = &txq->q; struct iwl4965_tfd_frame *tfd; u32 *control_flags; - struct iwl4965_cmd *out_cmd; + struct iwl_cmd *out_cmd; u32 idx; u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); dma_addr_t phys_addr; @@ -662,7 +603,7 @@ static int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl4965_host_cmd * out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME); phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx + - offsetof(struct iwl4965_cmd, hdr); + offsetof(struct iwl_cmd, hdr); iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " @@ -684,118 +625,6 @@ static int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl4965_host_cmd * return ret ? ret : idx; } -static int iwl4965_send_cmd_async(struct iwl_priv *priv, struct iwl4965_host_cmd *cmd) -{ - int ret; - - BUG_ON(!(cmd->meta.flags & CMD_ASYNC)); - - /* An asynchronous command can not expect an SKB to be set. */ - BUG_ON(cmd->meta.flags & CMD_WANT_SKB); - - /* An asynchronous command MUST have a callback. */ - BUG_ON(!cmd->meta.u.callback); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return -EBUSY; - - ret = iwl4965_enqueue_hcmd(priv, cmd); - if (ret < 0) { - IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n", - get_cmd_string(cmd->id), ret); - return ret; - } - return 0; -} - -static int iwl4965_send_cmd_sync(struct iwl_priv *priv, struct iwl4965_host_cmd *cmd) -{ - int cmd_idx; - int ret; - static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */ - - BUG_ON(cmd->meta.flags & CMD_ASYNC); - - /* A synchronous command can not have a callback set. */ - BUG_ON(cmd->meta.u.callback != NULL); - - if (atomic_xchg(&entry, 1)) { - IWL_ERROR("Error sending %s: Already sending a host command\n", - get_cmd_string(cmd->id)); - return -EBUSY; - } - - set_bit(STATUS_HCMD_ACTIVE, &priv->status); - - if (cmd->meta.flags & CMD_WANT_SKB) - cmd->meta.source = &cmd->meta; - - cmd_idx = iwl4965_enqueue_hcmd(priv, cmd); - if (cmd_idx < 0) { - ret = cmd_idx; - IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n", - get_cmd_string(cmd->id), ret); - goto out; - } - - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - !test_bit(STATUS_HCMD_ACTIVE, &priv->status), - HOST_COMPLETE_TIMEOUT); - if (!ret) { - if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { - IWL_ERROR("Error sending %s: time out after %dms.\n", - get_cmd_string(cmd->id), - jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); - - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - ret = -ETIMEDOUT; - goto cancel; - } - } - - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n", - get_cmd_string(cmd->id)); - ret = -ECANCELED; - goto fail; - } - if (test_bit(STATUS_FW_ERROR, &priv->status)) { - IWL_DEBUG_INFO("Command %s failed: FW Error\n", - get_cmd_string(cmd->id)); - ret = -EIO; - goto fail; - } - if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) { - IWL_ERROR("Error: Response NULL in '%s'\n", - get_cmd_string(cmd->id)); - ret = -EIO; - goto out; - } - - ret = 0; - goto out; - -cancel: - if (cmd->meta.flags & CMD_WANT_SKB) { - struct iwl4965_cmd *qcmd; - - /* Cancel the CMD_WANT_SKB flag for the cmd in the - * TX cmd queue. Otherwise in case the cmd comes - * in later, it will possibly set an invalid - * address (cmd->meta.source). */ - qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx]; - qcmd->meta.flags &= ~CMD_WANT_SKB; - } -fail: - if (cmd->meta.u.skb) { - dev_kfree_skb_any(cmd->meta.u.skb); - cmd->meta.u.skb = NULL; - } -out: - atomic_set(&entry, 0); - return ret; -} - static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; @@ -807,39 +636,11 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } -int iwl4965_send_cmd(struct iwl_priv *priv, struct iwl4965_host_cmd *cmd) -{ - if (cmd->meta.flags & CMD_ASYNC) - return iwl4965_send_cmd_async(priv, cmd); - - return iwl4965_send_cmd_sync(priv, cmd); -} - -int iwl4965_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) -{ - struct iwl4965_host_cmd cmd = { - .id = id, - .len = len, - .data = data, - }; - - return iwl4965_send_cmd_sync(priv, &cmd); -} - -static int __must_check iwl4965_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) -{ - struct iwl4965_host_cmd cmd = { - .id = id, - .len = sizeof(val), - .data = &val, - }; - - return iwl4965_send_cmd_sync(priv, &cmd); -} - int iwl4965_send_statistics_request(struct iwl_priv *priv) { - return iwl4965_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); + u32 flags = 0; + return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD, + sizeof(flags), &flags); } /** @@ -1000,7 +801,7 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) int rc = 0; struct iwl4965_rx_packet *res = NULL; struct iwl4965_rxon_assoc_cmd rxon_assoc; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_RXON_ASSOC, .len = sizeof(rxon_assoc), .meta.flags = CMD_WANT_SKB, @@ -1033,7 +834,7 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv) priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; - rc = iwl4965_send_cmd_sync(priv, &cmd); + rc = iwl_send_cmd_sync(priv, &cmd); if (rc) return rc; @@ -1112,7 +913,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON, + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl4965_rxon_cmd), &priv->active_rxon); @@ -1137,7 +938,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) iwl4965_set_rxon_hwcrypto(priv, priv->cfg->mod_params->hw_crypto); /* Apply the new configuration */ - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON, + rc = iwl_send_cmd_pdu(priv, REPLY_RXON, sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon); if (rc) { IWL_ERROR("Error setting new configuration (%d).\n", rc); @@ -1196,7 +997,7 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv) .kill_cts_mask = 0, }; - return iwl4965_send_cmd_pdu(priv, REPLY_BT_CONFIG, + return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, sizeof(struct iwl4965_bt_cmd), &bt_cmd); } @@ -1204,7 +1005,7 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv) { int rc = 0; struct iwl4965_rx_packet *res; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .meta.flags = CMD_WANT_SKB, }; @@ -1217,7 +1018,7 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv) return 0; } - rc = iwl4965_send_cmd_sync(priv, &cmd); + rc = iwl_send_cmd_sync(priv, &cmd); if (rc) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return rc; @@ -1242,7 +1043,7 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv) } static int iwl4965_card_state_sync_callback(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, + struct iwl_cmd *cmd, struct sk_buff *skb) { return 1; @@ -1260,7 +1061,7 @@ static int iwl4965_card_state_sync_callback(struct iwl_priv *priv, */ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) { - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_CARD_STATE_CMD, .len = sizeof(u32), .data = &flags, @@ -1270,11 +1071,11 @@ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_fla if (meta_flag & CMD_ASYNC) cmd.meta.u.callback = iwl4965_card_state_sync_callback; - return iwl4965_send_cmd(priv, &cmd); + return iwl_send_cmd(priv, &cmd); } static int iwl4965_add_sta_sync_callback(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, struct sk_buff *skb) + struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl4965_rx_packet *res = NULL; @@ -1306,7 +1107,7 @@ int iwl4965_send_add_station(struct iwl_priv *priv, { struct iwl4965_rx_packet *res = NULL; int rc = 0; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_ADD_STA, .len = sizeof(struct iwl4965_addsta_cmd), .meta.flags = flags, @@ -1318,7 +1119,7 @@ int iwl4965_send_add_station(struct iwl_priv *priv, else cmd.meta.flags |= CMD_WANT_SKB; - rc = iwl4965_send_cmd(priv, &cmd); + rc = iwl_send_cmd(priv, &cmd); if (rc || (flags & CMD_ASYNC)) return rc; @@ -1579,7 +1380,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); - rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); iwl4965_free_frame(priv, frame); @@ -1756,7 +1557,7 @@ static int iwl4965_send_qos_params_command(struct iwl_priv *priv, struct iwl4965_qosparam_cmd *qos) { - return iwl4965_send_cmd_pdu(priv, REPLY_QOS_PARAM, + return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, sizeof(struct iwl4965_qosparam_cmd), qos); } @@ -1966,7 +1767,7 @@ static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode) iwl4965_update_power_cmd(priv, &cmd, final_mode); - rc = iwl4965_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); @@ -2345,7 +2146,7 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, struct ieee80211_tx_control *ctl, - struct iwl4965_cmd *cmd, + struct iwl_cmd *cmd, struct sk_buff *skb_frag, int sta_id) { @@ -2390,7 +2191,7 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, * handle build REPLY_TX command notification. */ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl4965_cmd *cmd, + struct iwl_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) @@ -2531,7 +2332,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - struct iwl4965_cmd *out_cmd = NULL; + struct iwl_cmd *out_cmd = NULL; u16 len, idx, len_org; u8 id, hdr_len, unicast; u8 sta_id; @@ -2660,7 +2461,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, * We'll tell device about this padding later. */ len = priv->hw_setting.tx_cmd_len + - sizeof(struct iwl4965_cmd_header) + hdr_len; + sizeof(struct iwl_cmd_header) + hdr_len; len_org = len; len = (len + 3) & ~3; @@ -2672,8 +2473,8 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl4965_cmd) * idx + - offsetof(struct iwl4965_cmd, hdr); + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + + offsetof(struct iwl_cmd, hdr); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ @@ -2707,7 +2508,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv, iwl_update_tx_stats(priv, fc, len); - scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl4965_tx_cmd, scratch); out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); @@ -3020,7 +2821,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, { struct iwl4965_spectrum_cmd spectrum; struct iwl4965_rx_packet *res; - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, .meta.flags = CMD_WANT_SKB, @@ -3060,7 +2861,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv, spectrum.flags |= RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - rc = iwl4965_send_cmd_sync(priv, &cmd); + rc = iwl_send_cmd_sync(priv, &cmd); if (rc) return rc; @@ -3835,7 +3636,7 @@ static void iwl4965_tx_cmd_complete(struct iwl_priv *priv, int index = SEQ_TO_INDEX(sequence); int huge = sequence & SEQ_HUGE_FRAME; int cmd_index; - struct iwl4965_cmd *cmd; + struct iwl_cmd *cmd; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -4337,7 +4138,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) * but apparently a few don't get set; catch them here. */ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && - (pkt->hdr.cmd != REPLY_4965_RX) && + (pkt->hdr.cmd != REPLY_RX) && (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); @@ -4360,7 +4161,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv) if (reclaim) { /* Invoke any callbacks, transfer the skb to caller, and - * fire off the (possibly) blocking iwl4965_send_cmd() + * fire off the (possibly) blocking iwl_send_cmd() * as we reclaim the driver command queue */ if (rxb && rxb->skb) iwl4965_tx_cmd_complete(priv, rxb); @@ -6213,17 +6014,17 @@ static void iwl4965_bg_request_scan(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, request_scan); - struct iwl4965_host_cmd cmd = { + struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl4965_scan_cmd), .meta.flags = CMD_SIZE_HUGE, }; - int rc = 0; struct iwl4965_scan_cmd *scan; struct ieee80211_conf *conf = NULL; u16 cmd_len; enum ieee80211_band band; u8 direct_mask; + int ret = 0; conf = ieee80211_get_hw_conf(priv->hw); @@ -6244,7 +6045,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) if (test_bit(STATUS_SCAN_HW, &priv->status)) { IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " "Ignoring second request.\n"); - rc = -EIO; + ret = -EIO; goto done; } @@ -6277,7 +6078,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) priv->scan = kmalloc(sizeof(struct iwl4965_scan_cmd) + IWL_MAX_SCAN_SIZE, GFP_KERNEL); if (!priv->scan) { - rc = -ENOMEM; + ret = -ENOMEM; goto done; } } @@ -6329,8 +6130,9 @@ static void iwl4965_bg_request_scan(struct work_struct *data) scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); direct_mask = 1; - } else + } else { direct_mask = 0; + } scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; @@ -6405,8 +6207,8 @@ static void iwl4965_bg_request_scan(struct work_struct *data) scan->len = cpu_to_le16(cmd.len); set_bit(STATUS_SCAN_HW, &priv->status); - rc = iwl4965_send_cmd_sync(priv, &cmd); - if (rc) + ret = iwl_send_cmd_sync(priv, &cmd); + if (ret) goto done; queue_delayed_work(priv->workqueue, &priv->scan_check, @@ -6463,9 +6265,8 @@ static void iwl4965_bg_post_associate(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, post_associate.work); - - int rc = 0; struct ieee80211_conf *conf = NULL; + int ret = 0; DECLARE_MAC_BUF(mac); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { @@ -6496,9 +6297,9 @@ static void iwl4965_bg_post_associate(struct work_struct *data) memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); iwl4965_setup_rxon_timing(priv); - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING, + ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); - if (rc) + if (ret) IWL_WARNING("REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); @@ -6894,7 +6695,7 @@ out: static void iwl4965_config_ap(struct iwl_priv *priv) { - int rc = 0; + int ret = 0; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6909,9 +6710,9 @@ static void iwl4965_config_ap(struct iwl_priv *priv) /* RXON Timing */ memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); iwl4965_setup_rxon_timing(priv); - rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING, + ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); - if (rc) + if (ret) IWL_WARNING("REPLY_RXON_TIMING failed - " "Attempting to continue.\n"); -- cgit v1.2.3-59-g8ed1b From ab53d8af6772b22d4d68b1bcd74f7a5dba693983 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Tue, 25 Mar 2008 16:33:36 -0700 Subject: iwlwifi: Add led support This patch add LEDS support to 3965 and 4965 drivers. It is based on led trigger and class. For our drivers we needed to avoid two things. 1- We receive led trigger on/off on each Rx\Tx frame. In our driver we can not call led command like that. In this driver once driver receive a start of traffic it call the led command to start blinking then we count all bytes of Tx and Rx frame, after two second we count the blink rate of last two second then id blink rate changed we call the led commands 2- Since we can call led command very often, we make sure we call the led command after we receive the statistics notification so we don't need to wake up the ucode id it is in sleep state. This patch was tested with 4965 and 3945. Signed-off-by: Mohamed Abbas Signed-off-by: Ian Schram Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 20 ++ drivers/net/wireless/iwlwifi/Makefile | 10 + drivers/net/wireless/iwlwifi/iwl-3945-led.c | 433 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-3945-led.h | 73 +++++ drivers/net/wireless/iwlwifi/iwl-3945.c | 6 + drivers/net/wireless/iwlwifi/iwl-3945.h | 13 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 6 +- drivers/net/wireless/iwlwifi/iwl-4965.h | 12 +- drivers/net/wireless/iwlwifi/iwl-csr.h | 6 + drivers/net/wireless/iwlwifi/iwl-led.c | 446 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-led.h | 82 +++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 9 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 7 +- 13 files changed, 1107 insertions(+), 16 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-led.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-3945-led.h create mode 100644 drivers/net/wireless/iwlwifi/iwl-led.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-led.h (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 1ab14ed33f58..4bdb75ecb170 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -2,6 +2,13 @@ config IWLCORE tristate "Intel Wireless Wifi Core" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL +config IWLWIFI_LEDS + bool "Enable LEDS features in iwlwifi driver" + depends on IWLCORE && MAC80211_LEDS && LEDS_CLASS + ---help--- + This option enables LEDS for the iwlwifi drivers + + config IWL4965 tristate "Intel Wireless WiFi 4965AGN" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL @@ -37,6 +44,13 @@ config IWL4965_HT This option enables IEEE 802.11n High Throughput features for the iwl4965 driver. +config IWL4965_LEDS + bool "Enable LEDS features in iwl4965 driver" + depends on IWL4965 && IWLWIFI_LEDS + ---help--- + This option enables LEDS for the iwlwifi drivers + + config IWL4965_SPECTRUM_MEASUREMENT bool "Enable Spectrum Measurement in iwl4965 driver" depends on IWL4965 @@ -114,6 +128,12 @@ config IWL3945_SPECTRUM_MEASUREMENT ---help--- This option will enable spectrum measurement for the iwl3945 driver. +config IWL3945_LEDS + bool "Enable LEDS features in iwl3945 driver" + depends on IWL3945 && MAC80211_LEDS && LEDS_CLASS + ---help--- + This option enables LEDS for the iwl3945 driver. + config IWL3945_DEBUG bool "Enable full debugging output in iwl3945 driver" depends on IWL3945 diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 6be8012a1743..64fca4d9ac76 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -5,8 +5,18 @@ ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y) iwlcore-objs += iwl-debugfs.o endif +ifeq ($(CONFIG_IWLWIFI_LEDS),y) + iwlcore-objs += iwl-led.o +endif + obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o +ifeq ($(CONFIG_IWL3945_LEDS),y) + iwl3945-objs += iwl-3945-led.o +endif + + obj-$(CONFIG_IWL4965) += iwl4965.o iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c new file mode 100644 index 000000000000..d200d08fb086 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -0,0 +1,433 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwl-3945.h" +#include "iwl-helpers.h" + +#define IWL_1MB_RATE (128 * 1024) +#define IWL_LED_THRESHOLD (16) +#define IWL_MAX_BLINK_TBL (10) + +static const struct { + u16 brightness; + u8 on_time; + u8 of_time; +} blink_tbl[] = +{ + {300, 25, 25}, + {200, 40, 40}, + {100, 55, 55}, + {70, 65, 65}, + {50, 75, 75}, + {20, 85, 85}, + {15, 95, 95 }, + {10, 110, 110}, + {5, 130, 130}, + {0, 167, 167} +}; + +static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, + struct sk_buff *skb) +{ + return 1; +} + + +/* Send led command */ +static int iwl_send_led_cmd(struct iwl3945_priv *priv, + struct iwl3945_led_cmd *led_cmd) +{ + struct iwl3945_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl3945_led_cmd), + .data = led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl3945_led_cmd_callback + }; + + return iwl3945_send_cmd(priv, &cmd); +} + + +/* Set led on command */ +static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = IWL_LED_SOLID, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led on command */ +static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id, + enum led_brightness brightness) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + if (brightness == LED_FULL) { + led_cmd.on = IWL_LED_SOLID; + led_cmd.off = 0; + } + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led register off */ +static int iwl3945_led_on_reg(struct iwl3945_priv *priv, int led_id) +{ + IWL_DEBUG_LED("led on %d\n", led_id); + return iwl3945_led_on(priv, led_id); +} + +/* Set led off command */ +static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = 0, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + IWL_DEBUG_LED("led off %d\n", led_id); + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led register off */ +static int iwl3945_led_off_reg(struct iwl3945_priv *priv, int led_id) +{ + iwl3945_led_off(priv, led_id); + return 0; +} + +/* Set led blink command */ +static int iwl3945_led_not_solid(struct iwl3945_priv *priv, int led_id, + u8 brightness) +{ + struct iwl3945_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + + return iwl_send_led_cmd(priv, &led_cmd); +} + + +/* + * brightness call back function for Tx/Rx LED + */ +static int iwl3945_led_associated(struct iwl3945_priv *priv, int led_id) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return 0; + + + /* start counting Tx/Rx bytes */ + if (!priv->last_blink_time && priv->allow_blinking) + priv->last_blink_time = jiffies; + return 0; +} + +/* + * brightness call back for association and radio + */ +static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct iwl3945_led *led = container_of(led_cdev, + struct iwl3945_led, led_dev); + struct iwl3945_priv *priv = led->priv; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + switch (brightness) { + case LED_FULL: + if (led->type == IWL_LED_TRG_ASSOC) { + priv->allow_blinking = 1; + IWL_DEBUG_LED("MAC is associated\n"); + } + if (led->led_on) + led->led_on(priv, IWL_LED_LINK); + break; + case LED_OFF: + if (led->type == IWL_LED_TRG_ASSOC) { + priv->allow_blinking = 0; + IWL_DEBUG_LED("MAC is disassociated\n"); + } + if (led->led_off) + led->led_off(priv, IWL_LED_LINK); + break; + default: + if (led->led_pattern) + led->led_pattern(priv, IWL_LED_LINK, brightness); + break; + } +} + + + +/* + * Register led class with the system + */ +static int iwl3945_led_register_led(struct iwl3945_priv *priv, + struct iwl3945_led *led, + enum led_type type, u8 set_led, + const char *name, char *trigger) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret; + + led->led_dev.name = name; + led->led_dev.brightness_set = iwl3945_led_brightness_set; + led->led_dev.default_trigger = trigger; + + ret = led_classdev_register(device, &led->led_dev); + if (ret) { + IWL_ERROR("Error: failed to register led handler.\n"); + return ret; + } + + led->priv = priv; + led->type = type; + led->registered = 1; + + if (set_led && led->led_on) + led->led_on(priv, IWL_LED_LINK); + return 0; +} + + +/* + * calculate blink rate according to last 2 sec Tx/Rx activities + */ +static inline u8 get_blink_rate(struct iwl3945_priv *priv) +{ + int index; + u8 blink_rate; + + if (priv->rxtxpackets < IWL_LED_THRESHOLD) + index = 10; + else { + for (index = 0; index < IWL_MAX_BLINK_TBL; index++) { + if (priv->rxtxpackets > (blink_tbl[index].brightness * + IWL_1MB_RATE)) + break; + } + } + /* if 0 frame is transfered */ + if ((index == IWL_MAX_BLINK_TBL) || !priv->allow_blinking) + blink_rate = IWL_LED_SOLID; + else + blink_rate = blink_tbl[index].on_time; + + return blink_rate; +} + +static inline int is_rf_kill(struct iwl3945_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +/* + * this function called from handler. Since setting Led command can + * happen very frequent we postpone led command to be called from + * REPLY handler so we know ucode is up + */ +void iwl3945_led_background(struct iwl3945_priv *priv) +{ + u8 blink_rate; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + priv->last_blink_time = 0; + return; + } + if (is_rf_kill(priv)) { + priv->last_blink_time = 0; + return; + } + + if (!priv->allow_blinking) { + priv->last_blink_time = 0; + if (priv->last_blink_rate != IWL_LED_SOLID) { + priv->last_blink_rate = IWL_LED_SOLID; + iwl3945_led_on(priv, IWL_LED_LINK); + } + return; + } + if (!priv->last_blink_time || + !time_after(jiffies, priv->last_blink_time + + msecs_to_jiffies(1000))) + return; + + blink_rate = get_blink_rate(priv); + + /* call only if blink rate change */ + if (blink_rate != priv->last_blink_rate) { + if (blink_rate != IWL_LED_SOLID) { + priv->last_blink_time = jiffies + + msecs_to_jiffies(1000); + iwl3945_led_not_solid(priv, IWL_LED_LINK, blink_rate); + } else { + priv->last_blink_time = 0; + iwl3945_led_on(priv, IWL_LED_LINK); + } + } + + priv->last_blink_rate = blink_rate; + priv->rxtxpackets = 0; +} + + +/* Register all led handler */ +int iwl3945_led_register(struct iwl3945_priv *priv) +{ + char *trigger; + char name[32]; + int ret; + + priv->last_blink_rate = 0; + priv->rxtxpackets = 0; + priv->last_blink_time = 0; + priv->allow_blinking = 0; + + trigger = ieee80211_get_radio_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:radio", + wiphy_name(priv->hw->wiphy)); + + priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on_reg; + priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off_reg; + priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; + + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_RADIO], + IWL_LED_TRG_RADIO, 1, + name, trigger); + if (ret) + goto exit_fail; + + trigger = ieee80211_get_assoc_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:assoc", + wiphy_name(priv->hw->wiphy)); + + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_ASSOC], + IWL_LED_TRG_ASSOC, 0, + name, trigger); + /* for assoc always turn led on */ + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_rx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:RX", + wiphy_name(priv->hw->wiphy)); + + + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_RX], + IWL_LED_TRG_RX, 0, + name, trigger); + + priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated; + priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated; + priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_tx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:TX", + wiphy_name(priv->hw->wiphy)); + ret = iwl3945_led_register_led(priv, + &priv->led[IWL_LED_TRG_TX], + IWL_LED_TRG_TX, 0, + name, trigger); + priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated; + priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated; + priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern; + + if (ret) + goto exit_fail; + + return 0; + +exit_fail: + iwl3945_led_unregister(priv); + return ret; +} + + +/* unregister led class */ +static void iwl3945_led_unregister_led(struct iwl3945_led *led, u8 set_led) +{ + if (!led->registered) + return; + + led_classdev_unregister(&led->led_dev); + + if (set_led) + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->registered = 0; +} + +/* Unregister all led handlers */ +void iwl3945_led_unregister(struct iwl3945_priv *priv) +{ + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); + iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h new file mode 100644 index 000000000000..b1d2f6b8b259 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef IWL3945_LEDS_H +#define IWL3945_LEDS_H + +struct iwl3945_priv; + +#ifdef CONFIG_IWL3945_LEDS +#define IWL_LED_SOLID 11 +#define IWL_LED_NAME_LEN 31 +#define IWL_DEF_LED_INTRVL __constant_cpu_to_le32(1000) + +#define IWL_LED_ACTIVITY (0<<1) +#define IWL_LED_LINK (1<<1) + +enum led_type { + IWL_LED_TRG_TX, + IWL_LED_TRG_RX, + IWL_LED_TRG_ASSOC, + IWL_LED_TRG_RADIO, + IWL_LED_TRG_MAX, +}; + +#include + +struct iwl3945_led { + struct iwl3945_priv *priv; + struct led_classdev led_dev; + + int (*led_on) (struct iwl3945_priv *priv, int led_id); + int (*led_off) (struct iwl3945_priv *priv, int led_id); + int (*led_pattern) (struct iwl3945_priv *priv, int led_id, + enum led_brightness brightness); + + enum led_type type; + unsigned int registered; +}; + +extern int iwl3945_led_register(struct iwl3945_priv *priv); +extern void iwl3945_led_unregister(struct iwl3945_priv *priv); +extern void iwl3945_led_background(struct iwl3945_priv *priv); + +#else +static inline int iwl3945_led_register(struct iwl3945_priv *priv) { return 0; } +static inline void iwl3945_led_unregister(struct iwl3945_priv *priv) {} +static inline void iwl3945_led_background(struct iwl3945_priv *priv) {} +#endif /* CONFIG_IWL3945_LEDS */ + +#endif /* IWL3945_LEDS_H */ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index e116ed77c5ad..eb30819cddc4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -358,6 +358,8 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics)); + iwl3945_led_background(priv); + priv->last_statistics_time = jiffies; } @@ -640,6 +642,10 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, if (priv->add_radiotap) iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); +#ifdef CONFIG_IWL3945_LEDS + if (is_data) + priv->rxtxpackets += len; +#endif ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); rxb->skb = NULL; } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 931c465f9e5e..e0655b988f44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -44,6 +44,7 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-prph.h" #include "iwl-3945-hw.h" #include "iwl-3945-debug.h" +#include "iwl-3945-led.h" /* Change firmware file name, using "-" and incrementing number, * *only* when uCode interface or architecture changes so that it @@ -777,13 +778,15 @@ struct iwl3945_priv { struct iwl3945_init_alive_resp card_alive_init; struct iwl3945_alive_resp card_alive; -#ifdef LED - /* LED related variables */ - struct iwl3945_activity_blink activity; - unsigned long led_packets; - int led_state; +#ifdef CONFIG_IWL4965_LEDS + struct iwl3945_led led[IWL_LED_TRG_MAX]; + unsigned long last_blink_time; + u8 last_blink_rate; + u8 allow_blinking; + unsigned int rxtxpackets; #endif + u16 active_rate; u16 active_rate_basic; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 1db873b02f1e..8b5cacb14618 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -3258,6 +3258,8 @@ void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffe #endif } + iwl_leds_background(priv); + /* If the hardware hasn't reported a change in * temperature then don't bother computing a * calibrated temperature value */ @@ -3539,10 +3541,6 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); priv->alloc_rxb_skb--; rxb->skb = NULL; -#ifdef LED - priv->led_packets += len; - iwl4965_setup_activity_timer(priv); -#endif } /* Calc max signal level (dBm) among 3 possible receivers */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 960b53b20df8..32c21d266f98 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -45,6 +45,7 @@ extern struct pci_device_id iwl4965_hw_card_ids[]; #include "iwl-csr.h" #include "iwl-prph.h" #include "iwl-debug.h" +#include "iwl-led.h" /* Change firmware file name, using "-" and incrementing number, * *only* when uCode interface or architecture changes so that it @@ -1050,11 +1051,12 @@ struct iwl_priv { struct iwl4965_init_alive_resp card_alive_init; struct iwl4965_alive_resp card_alive; -#ifdef LED - /* LED related variables */ - struct iwl4965_activity_blink activity; - unsigned long led_packets; - int led_state; +#ifdef CONFIG_IWL4965_LEDS + struct iwl4965_led led[IWL_LED_TRG_MAX]; + unsigned long last_blink_time; + u8 last_blink_rate; + u8 allow_blinking; + u64 led_tpt; #endif u16 active_rate; diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index f0a2c8d180f0..12725796ea5f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -93,6 +93,7 @@ #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) +#define CSR_LED_REG (CSR_BASE+0x094) /* Analog phase-lock-loop configuration (3945 only) * Set bit 24. */ @@ -214,6 +215,11 @@ #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) +/* LED */ +#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) +#define CSR_LED_REG_TRUN_ON (0x78) +#define CSR_LED_REG_TRUN_OFF (0x38) + /*=== HBUS (Host-side Bus) ===*/ #define HBUS_BASE (0x400) /* diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c new file mode 100644 index 000000000000..6f5424bd365b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -0,0 +1,446 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-helpers.h" + +#define IWL_1MB_RATE (128 * 1024) +#define IWL_LED_THRESHOLD (16) +#define IWL_MAX_BLINK_TBL (10) + +static const struct { + u16 tpt; + u8 on_time; + u8 of_time; +} blink_tbl[] = +{ + {300, 25, 25}, + {200, 40, 40}, + {100, 55, 55}, + {70, 65, 65}, + {50, 75, 75}, + {20, 85, 85}, + {15, 95, 95 }, + {10, 110, 110}, + {5, 130, 130}, + {0, 167, 167} +}; + +static int iwl_led_cmd_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + return 1; +} + + +/* Send led command */ +static int iwl_send_led_cmd(struct iwl_priv *priv, + struct iwl4965_led_cmd *led_cmd) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl4965_led_cmd), + .data = led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl_led_cmd_callback + }; + u32 reg; + + reg = iwl4965_read32(priv, CSR_LED_REG); + if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) + iwl4965_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + + return iwl_send_cmd(priv, &cmd); +} + + +/* Set led on command */ +static int iwl4965_led_on(struct iwl_priv *priv, int led_id) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = IWL_LED_SOLID, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led on command */ +static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, + enum led_brightness brightness) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + if (brightness == LED_FULL) { + led_cmd.on = IWL_LED_SOLID; + led_cmd.off = 0; + } + return iwl_send_led_cmd(priv, &led_cmd); +} + +/* Set led register off */ +static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED("led on %d\n", led_id); + iwl4965_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); + return 0; +} + +#if 0 +/* Set led off command */ +int iwl4965_led_off(struct iwl_priv *priv, int led_id) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = 0, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + IWL_DEBUG_LED("led off %d\n", led_id); + return iwl_send_led_cmd(priv, &led_cmd); +} +#endif + + +/* Set led register off */ +static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) +{ + IWL_DEBUG_LED("radio off\n"); + iwl4965_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); + return 0; +} + +/* Set led blink command */ +static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id, + u8 brightness) +{ + struct iwl4965_led_cmd led_cmd = { + .id = led_id, + .on = brightness, + .off = brightness, + .interval = IWL_DEF_LED_INTRVL + }; + + return iwl_send_led_cmd(priv, &led_cmd); +} + + +/* + * brightness call back function for Tx/Rx LED + */ +static int iwl4965_led_associated(struct iwl_priv *priv, int led_id) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return 0; + + + /* start counting Tx/Rx bytes */ + if (!priv->last_blink_time && priv->allow_blinking) + priv->last_blink_time = jiffies; + return 0; +} + +/* + * brightness call back for association and radio + */ +static void iwl4965_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct iwl4965_led *led = container_of(led_cdev, + struct iwl4965_led, led_dev); + struct iwl_priv *priv = led->priv; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + switch (brightness) { + case LED_FULL: + if (led->type == IWL_LED_TRG_ASSOC) + priv->allow_blinking = 1; + + if (led->led_on) + led->led_on(priv, IWL_LED_LINK); + break; + case LED_OFF: + if (led->type == IWL_LED_TRG_ASSOC) + priv->allow_blinking = 0; + + if (led->led_off) + led->led_off(priv, IWL_LED_LINK); + break; + default: + if (led->led_pattern) + led->led_pattern(priv, IWL_LED_LINK, brightness); + break; + } +} + + + +/* + * Register led class with the system + */ +static int iwl_leds_register_led(struct iwl_priv *priv, + struct iwl4965_led *led, + enum led_type type, u8 set_led, + const char *name, char *trigger) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret; + + led->led_dev.name = name; + led->led_dev.brightness_set = iwl4965_led_brightness_set; + led->led_dev.default_trigger = trigger; + + ret = led_classdev_register(device, &led->led_dev); + if (ret) { + IWL_ERROR("Error: failed to register led handler.\n"); + return ret; + } + + led->priv = priv; + led->type = type; + led->registered = 1; + + if (set_led && led->led_on) + led->led_on(priv, IWL_LED_LINK); + return 0; +} + + +/* + * calculate blink rate according to last 2 sec Tx/Rx activities + */ +static inline u8 get_blink_rate(struct iwl_priv *priv) +{ + int i; + u8 blink_rate; + u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; + s64 tpt = current_tpt - priv->led_tpt; + + if (tpt < 0) /* wrapparound */ + tpt = -tpt; + + priv->led_tpt = current_tpt; + + if (tpt < IWL_LED_THRESHOLD) { + i = IWL_MAX_BLINK_TBL; + } else { + for (i = 0; i < IWL_MAX_BLINK_TBL; i++) + if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) + break; + } + /* if 0 frame is transfered */ + if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking) + blink_rate = IWL_LED_SOLID; + else + blink_rate = blink_tbl[i].on_time; + + return blink_rate; +} + +static inline int is_rf_kill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + +/* + * this function called from handler. Since setting Led command can + * happen very frequent we postpone led command to be called from + * REPLY handler so we know ucode is up + */ +void iwl_leds_background(struct iwl_priv *priv) +{ + u8 blink_rate; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + priv->last_blink_time = 0; + return; + } + if (is_rf_kill(priv)) { + priv->last_blink_time = 0; + return; + } + + if (!priv->allow_blinking) { + priv->last_blink_time = 0; + if (priv->last_blink_rate != IWL_LED_SOLID) { + priv->last_blink_rate = IWL_LED_SOLID; + iwl4965_led_on(priv, IWL_LED_LINK); + } + return; + } + if (!priv->last_blink_time || + !time_after(jiffies, priv->last_blink_time + + msecs_to_jiffies(1000))) + return; + + blink_rate = get_blink_rate(priv); + + /* call only if blink rate change */ + if (blink_rate != priv->last_blink_rate) { + if (blink_rate != IWL_LED_SOLID) { + priv->last_blink_time = jiffies + + msecs_to_jiffies(1000); + iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate); + } else { + priv->last_blink_time = 0; + iwl4965_led_on(priv, IWL_LED_LINK); + } + } + + priv->last_blink_rate = blink_rate; +} +EXPORT_SYMBOL(iwl_leds_background); + +/* Register all led handler */ +int iwl_leds_register(struct iwl_priv *priv) +{ + char *trigger; + char name[32]; + int ret; + + priv->last_blink_rate = 0; + priv->led_tpt = 0; + priv->last_blink_time = 0; + priv->allow_blinking = 0; + + trigger = ieee80211_get_radio_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:radio", + wiphy_name(priv->hw->wiphy)); + + priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg; + priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; + + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_RADIO], + IWL_LED_TRG_RADIO, 1, + name, trigger); + if (ret) + goto exit_fail; + + trigger = ieee80211_get_assoc_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:assoc", + wiphy_name(priv->hw->wiphy)); + + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_ASSOC], + IWL_LED_TRG_ASSOC, 0, + name, trigger); + /* for assoc always turn led on */ + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_rx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:RX", + wiphy_name(priv->hw->wiphy)); + + + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_RX], + IWL_LED_TRG_RX, 0, + name, trigger); + + priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated; + priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated; + priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern; + + if (ret) + goto exit_fail; + + trigger = ieee80211_get_tx_led_name(priv->hw); + snprintf(name, sizeof(name), "iwl-%s:TX", + wiphy_name(priv->hw->wiphy)); + ret = iwl_leds_register_led(priv, + &priv->led[IWL_LED_TRG_TX], + IWL_LED_TRG_TX, 0, + name, trigger); + priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated; + priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated; + priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern; + + if (ret) + goto exit_fail; + + return 0; + +exit_fail: + iwl_leds_unregister(priv); + return ret; +} +EXPORT_SYMBOL(iwl_leds_register); + +/* unregister led class */ +static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led) +{ + if (!led->registered) + return; + + led_classdev_unregister(&led->led_dev); + + if (set_led) + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->registered = 0; +} + +/* Unregister all led handlers */ +void iwl_leds_unregister(struct iwl_priv *priv) +{ + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0); + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0); + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0); + iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1); +} +EXPORT_SYMBOL(iwl_leds_unregister); + diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h new file mode 100644 index 000000000000..5bb04128cd65 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl_leds_h__ +#define __iwl_leds_h__ + + +struct iwl_priv; + +#ifdef CONFIG_IWLWIFI_LEDS +#include + +#define IWL_LED_SOLID 11 +#define IWL_LED_NAME_LEN 31 +#define IWL_DEF_LED_INTRVL __constant_cpu_to_le32(1000) + +#define IWL_LED_ACTIVITY (0<<1) +#define IWL_LED_LINK (1<<1) + +enum led_type { + IWL_LED_TRG_TX, + IWL_LED_TRG_RX, + IWL_LED_TRG_ASSOC, + IWL_LED_TRG_RADIO, + IWL_LED_TRG_MAX, +}; + + +struct iwl4965_led { + struct iwl_priv *priv; + struct led_classdev led_dev; + + int (*led_on) (struct iwl_priv *priv, int led_id); + int (*led_off) (struct iwl_priv *priv, int led_id); + int (*led_pattern) (struct iwl_priv *priv, int led_id, + enum led_brightness brightness); + + enum led_type type; + unsigned int registered; +}; + +int iwl_leds_register(struct iwl_priv *priv); +void iwl_leds_unregister(struct iwl_priv *priv); +void iwl_leds_background(struct iwl_priv *priv); + +#else +static inline int iwl_leds_register(struct iwl_priv *priv) +{ + return 0; +} +static inline void iwl_leds_unregister(struct iwl_priv *priv) +{ +} +static inline void iwl_leds_background(struct iwl_priv *priv) +{ +} + +#endif /* CONFIG_IWLWIFI_LEDS */ +#endif /* __iwl_leds_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4ba959153cb1..470a9abf12c3 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -2481,8 +2481,12 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else + } else { cmd->cmd.tx.timeout.pm_frame_timeout = 0; +#ifdef CONFIG_IWL3945_LEDS + priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len); +#endif + } cmd->cmd.tx.driver_txop = 0; cmd->cmd.tx.tx_flags = tx_flags; @@ -5855,6 +5859,8 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) IWL_DEBUG_INFO("ALIVE processing complete.\n"); wake_up_interruptible(&priv->wait_command_queue); + iwl3945_led_register(priv); + if (priv->error_recovering) iwl3945_error_recovery(priv); @@ -5879,6 +5885,7 @@ static void __iwl3945_down(struct iwl3945_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); + iwl3945_led_unregister(priv); iwl3945_clear_stations_table(priv); /* Unblock any waiting calls */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 9ae3d2981df5..a04127a8acf7 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2238,8 +2238,9 @@ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv, cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); - } else + } else { cmd->cmd.tx.timeout.pm_frame_timeout = 0; + } cmd->cmd.tx.driver_txop = 0; cmd->cmd.tx.tx_flags = tx_flags; @@ -5712,6 +5713,8 @@ static void iwl4965_alive_start(struct iwl_priv *priv) IWL_DEBUG_INFO("ALIVE processing complete.\n"); wake_up_interruptible(&priv->wait_command_queue); + iwl_leds_register(priv); + if (priv->error_recovering) iwl4965_error_recovery(priv); @@ -5736,6 +5739,8 @@ static void __iwl4965_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); + iwl_leds_unregister(priv); + iwlcore_clear_stations_table(priv); /* Unblock any waiting calls */ -- cgit v1.2.3-59-g8ed1b From ad97edd2f524940d524c26ae273a4eb23067a7c0 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 28 Mar 2008 16:21:06 -0700 Subject: iwlwifi: hook iwlwifi with Linux rfkill This patch hook IWL with Linux rfkill. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 6 + drivers/net/wireless/iwlwifi/Makefile | 4 + drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-4965.h | 5 + drivers/net/wireless/iwlwifi/iwl-core.c | 4 + drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-rfkill.c | 174 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-rfkill.h | 56 +++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 54 ++++----- 9 files changed, 271 insertions(+), 34 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-rfkill.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-rfkill.h (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index c26ca749fc1e..4a5c8c0d007d 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -9,6 +9,12 @@ config IWLWIFI_LEDS This option enables LEDS for the iwlwifi drivers +config IWLCORE_RFKILL + boolean "IWLWIFI RF kill support" + depends on IWLCORE + select RFKILL + select RFKILL_INPUT + config IWL4965 tristate "Intel Wireless WiFi 4965AGN" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 64fca4d9ac76..2751e8aa97d7 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -9,6 +9,10 @@ ifeq ($(CONFIG_IWLWIFI_LEDS),y) iwlcore-objs += iwl-led.o endif +ifeq ($(CONFIG_IWLCORE_RFKILL),y) + iwlcore-objs += iwl-rfkill.o +endif + obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e5f64d7fbfde..3ab5d8292502 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -4961,6 +4961,7 @@ static struct iwl_lib_ops iwl4965_lib = { .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, }, + .radio_kill_sw = iwl4965_radio_kill_sw, }; static struct iwl_ops iwl4965_ops = { diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 069e591981b2..ca864fa65ca4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -40,6 +40,7 @@ extern struct pci_device_id iwl4965_hw_card_ids[]; #define DRV_NAME "iwl4965" +#include "iwl-rfkill.h" #include "iwl-eeprom.h" #include "iwl-4965-hw.h" #include "iwl-csr.h" @@ -739,6 +740,7 @@ extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index extern int iwl4965_queue_space(const struct iwl4965_queue *q); struct iwl_priv; +extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio); /* * Forward declare iwl-4965.c functions for iwl-base.c */ @@ -1050,6 +1052,9 @@ struct iwl_priv { * 4965's initialize alive response contains some calibration data. */ struct iwl4965_init_alive_resp card_alive_init; struct iwl4965_alive_resp card_alive; +#ifdef CONFIG_IWLCORE_RFKILL + struct iwl_rfkill_mngr rfkill_mngr; +#endif #ifdef CONFIG_IWL4965_LEDS struct iwl4965_led led[IWL_LED_TRG_MAX]; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 342a269b8abb..49fb52f07354 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -35,6 +35,7 @@ struct iwl_priv; /* FIXME: remove */ #include "iwl-debug.h" #include "iwl-eeprom.h" #include "iwl-core.h" +#include "iwl-rfkill.h" #include "iwl-4965.h" /* FIXME: remove */ @@ -257,12 +258,15 @@ int iwlcore_low_level_notify(struct iwl_priv *priv, { switch (notify) { case IWLCORE_INIT_EVT: + iwl_rfkill_init(priv); break; case IWLCORE_START_EVT: break; case IWLCORE_STOP_EVT: break; case IWLCORE_REMOVE_EVT: + iwl_rfkill_unregister(priv); + iwl_rfkill_free(priv); break; } diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4dfa05948d73..5efafe1a1d86 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -91,6 +91,7 @@ struct iwl_lib_ops { int (*init_drv)(struct iwl_priv *priv); /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; + void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio); }; struct iwl_ops { diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c new file mode 100644 index 000000000000..66abf52e8987 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -0,0 +1,174 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ +#include +#include +#include +#include + +#include + +#include "iwl-eeprom.h" +#include "iwl-core.h" +#include "iwl-4965.h" +#include "iwl-helpers.h" + + +static inline int iwl_is_rfkill(struct iwl_priv *priv) +{ + return test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status); +} + + +/* software rf-kill from user */ +static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) +{ + struct iwl_priv *priv = data; + int err = 0; + + if (!priv->rfkill_mngr.rfkill) + return 0; + + IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + mutex_lock(&priv->mutex); + + switch (state) { + case RFKILL_STATE_ON: + priv->cfg->ops->lib->radio_kill_sw(priv, 0); + /* if HW rf-kill is set dont allow ON state */ + if (iwl_is_rfkill(priv)) + err = -EBUSY; + break; + case RFKILL_STATE_OFF: + priv->cfg->ops->lib->radio_kill_sw(priv, 1); + if (!iwl_is_rfkill(priv)) + err = -EBUSY; + break; + } + mutex_unlock(&priv->mutex); + + return err; +} + +int iwl_rfkill_init(struct iwl_priv *priv) +{ + struct device *device = wiphy_dev(priv->hw->wiphy); + int ret = 0; + + BUG_ON(device == NULL); + + priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); + if (!priv->rfkill_mngr.rfkill) { + ret = -ENOMEM; + goto error; + } + + priv->rfkill_mngr.rfkill->name = priv->cfg->name; + priv->rfkill_mngr.rfkill->data = priv; + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + priv->rfkill_mngr.rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; + priv->rfkill_mngr.rfkill->user_claim_unsupported = 1; + + priv->rfkill_mngr.rfkill->dev.class->suspend = NULL; + priv->rfkill_mngr.rfkill->dev.class->resume = NULL; + + priv->rfkill_mngr.input_dev = input_allocate_device(); + if (!priv->rfkill_mngr.input_dev) { + ret = -ENOMEM; + goto freed_rfkill; + } + + priv->rfkill_mngr.input_dev->name = priv->cfg->name; + priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy); + priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST; + priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor; + priv->rfkill_mngr.input_dev->dev.parent = device; + priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit); + + ret = rfkill_register(priv->rfkill_mngr.rfkill); + if (ret) + goto free_input_dev; + + ret = input_register_device(priv->rfkill_mngr.input_dev); + if (ret) + goto unregister_rfkill; + + return ret; + +unregister_rfkill: + rfkill_unregister(priv->rfkill_mngr.rfkill); + +free_input_dev: + input_free_device(priv->rfkill_mngr.input_dev); + priv->rfkill_mngr.input_dev = NULL; + +freed_rfkill: + rfkill_free(priv->rfkill_mngr.rfkill); + priv->rfkill_mngr.rfkill = NULL; + +error: + return ret; +} +EXPORT_SYMBOL(iwl_rfkill_init); + +void iwl_rfkill_unregister(struct iwl_priv *priv) +{ + + if (priv->rfkill_mngr.input_dev) + input_unregister_device(priv->rfkill_mngr.input_dev); + + if (priv->rfkill_mngr.rfkill) + rfkill_unregister(priv->rfkill_mngr.rfkill); +} +EXPORT_SYMBOL(iwl_rfkill_unregister); + + +void iwl_rfkill_free(struct iwl_priv *priv) +{ + if (priv->rfkill_mngr.input_dev) + input_free_device(priv->rfkill_mngr.input_dev); + + if (priv->rfkill_mngr.rfkill) + rfkill_free(priv->rfkill_mngr.rfkill); +} +EXPORT_SYMBOL(iwl_rfkill_free); + +/* set rf-kill to the right state. */ +void iwl_rfkill_set_hw_state(struct iwl_priv *priv) +{ + + if (!priv->rfkill_mngr.rfkill) + return; + + if (!iwl_is_rfkill(priv)) + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; + else + priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF; +} +EXPORT_SYMBOL(iwl_rfkill_set_hw_state); diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h new file mode 100644 index 000000000000..a5cbc5ab45d9 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ +#ifndef __iwl_rf_kill_h__ +#define __iwl_rf_kill_h__ + +struct iwl_priv; + +#include +#include + + +#ifdef CONFIG_IWLCORE_RFKILL +struct iwl_rfkill_mngr { + struct rfkill *rfkill; + struct input_dev *input_dev; +}; + +void iwl_rfkill_set_hw_state(struct iwl_priv *priv); +void iwl_rfkill_free(struct iwl_priv *priv); +void iwl_rfkill_unregister(struct iwl_priv *priv); +int iwl_rfkill_init(struct iwl_priv *priv); +#else +static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {} +static inline void iwl_rfkill_free(struct iwl_priv *priv) {} +static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {} +static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; } +#endif + + + +#endif /* __iwl_rf_kill_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 5261b6179a86..7f56565b4002 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -2607,7 +2607,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -static void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio) +void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio) { unsigned long flags; @@ -2625,8 +2625,16 @@ static void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio) iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); spin_unlock_irqrestore(&priv->lock, flags); - iwl4965_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + /* call the host command only if no hw rf-kill set */ + if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) + iwl4965_send_card_state(priv, + CARD_STATE_CMD_DISABLE, + 0); set_bit(STATUS_RF_KILL_SW, &priv->status); + + /* make sure mac80211 stop sending Tx frame */ + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); } return; } @@ -5852,6 +5860,7 @@ static int __iwl4965_up(struct iwl_priv *priv) if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { IWL_WARNING("Radio disabled by SW RF kill (module " "parameter)\n"); + iwl_rfkill_set_hw_state(priv); return -ENODEV; } @@ -5867,11 +5876,13 @@ static int __iwl4965_up(struct iwl_priv *priv) else { set_bit(STATUS_RF_KILL_HW, &priv->status); if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) { + iwl_rfkill_set_hw_state(priv); IWL_WARNING("Radio disabled by HW RF Kill switch\n"); return -ENODEV; } } + iwl_rfkill_set_hw_state(priv); iwl_write32(priv, CSR_INT, 0xFFFFFFFF); rc = iwl4965_hw_nic_init(priv); @@ -5985,6 +5996,9 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) queue_work(priv->workqueue, &priv->restart); } else { + /* make sure mac80211 stop sending Tx frame */ + if (priv->mac80211_registered) + ieee80211_stop_queues(priv->hw); if (!test_bit(STATUS_RF_KILL_HW, &priv->status)) IWL_DEBUG_RF_KILL("Can not turn radio back on - " @@ -5994,6 +6008,8 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) "Kill switch must be turned off for " "wireless networking to work.\n"); } + iwl_rfkill_set_hw_state(priv); + mutex_unlock(&priv->mutex); } @@ -6674,7 +6690,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co } #endif - iwl4965_radio_kill_sw(priv, !conf->radio_enabled); + if (priv->cfg->ops->lib->radio_kill_sw) + priv->cfg->ops->lib->radio_kill_sw(priv, !conf->radio_enabled); if (!conf->radio_enabled) { IWL_DEBUG_MAC80211("leave - radio disabled\n"); @@ -7449,36 +7466,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, #endif /* CONFIG_IWLWIFI_DEBUG */ -static ssize_t show_rf_kill(struct device *d, - struct device_attribute *attr, char *buf) -{ - /* - * 0 - RF kill not enabled - * 1 - SW based RF kill active (sysfs) - * 2 - HW based RF kill active - * 3 - Both HW and SW based RF kill active - */ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | - (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); - - return sprintf(buf, "%i\n", val); -} - -static ssize_t store_rf_kill(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - - mutex_lock(&priv->mutex); - iwl4965_radio_kill_sw(priv, buf[0] == '1'); - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) @@ -7964,7 +7951,6 @@ static struct attribute *iwl4965_sysfs_entries[] = { #endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, - &dev_attr_rf_kill.attr, &dev_attr_rs_window.attr, &dev_attr_statistics.attr, &dev_attr_status.attr, -- cgit v1.2.3-59-g8ed1b From 6974e36356524fa856435cb1be40aaffbac9601a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 14 Apr 2008 21:16:06 -0700 Subject: iwlwifi: default WEP HW encryption This patch adds HW encryption support in default WEP mode. When no key mapping key/pairwise key is used. The key is broadcast key is used as default/global/static key. This code assumes that group cast key is added after pairwise key. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.h | 3 + drivers/net/wireless/iwlwifi/iwl-sta.c | 119 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-sta.h | 46 +++++++++++ drivers/net/wireless/iwlwifi/iwl4965-base.c | 90 ++++++++++++--------- 5 files changed, 220 insertions(+), 40 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-sta.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-sta.h (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 2751e8aa97d7..741ea346a295 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -22,5 +22,5 @@ endif obj-$(CONFIG_IWL4965) += iwl4965.o -iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o +iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 65e536782706..93df29e4689a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -1112,6 +1112,9 @@ struct iwl_priv { spinlock_t sta_lock; int num_stations; struct iwl4965_station_entry stations[IWL_STATION_COUNT]; + struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; + u8 default_wep_key; + u8 key_mapping_key; /* Indication if ieee80211_ops->open has been called */ u8 is_open; diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c new file mode 100644 index 000000000000..a48e228e2ffd --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include + +#include "iwl-eeprom.h" +#include "iwl-4965.h" +#include "iwl-core.h" +#include "iwl-sta.h" +#include "iwl-io.h" +#include "iwl-helpers.h" + +int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) +{ + int i, not_empty = 0; + u8 buff[sizeof(struct iwl_wep_cmd) + + sizeof(struct iwl_wep_key) * WEP_KEYS_MAX]; + struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff; + size_t cmd_size = sizeof(struct iwl_wep_cmd); + struct iwl_host_cmd cmd = { + .id = REPLY_WEPKEY, + .data = wep_cmd, + .meta.flags = CMD_ASYNC, + }; + + memset(wep_cmd, 0, cmd_size + + (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX)); + + for (i = 0; i < WEP_KEYS_MAX ; i++) { + wep_cmd->key[i].key_index = i; + if (priv->wep_keys[i].key_size) { + wep_cmd->key[i].key_offset = i; + not_empty = 1; + } else { + wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET; + } + + wep_cmd->key[i].key_size = priv->wep_keys[i].key_size; + memcpy(&wep_cmd->key[i].key[3], priv->wep_keys[i].key, + priv->wep_keys[i].key_size); + } + + wep_cmd->global_key_type = WEP_KEY_WEP_TYPE; + wep_cmd->num_keys = WEP_KEYS_MAX; + + cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX; + + cmd.len = cmd_size; + + if (not_empty || send_if_empty) + return iwl_send_cmd(priv, &cmd); + else + return 0; +} + +int iwl_remove_default_wep_key(struct iwl_priv *priv, + struct ieee80211_key_conf *key) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->default_wep_key--; + memset(&priv->wep_keys[key->keyidx], 0, sizeof(priv->wep_keys[0])); + ret = iwl_send_static_wepkey_cmd(priv, 1); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return ret; +} + +int iwl_set_default_wep_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf) +{ + int ret; + unsigned long flags; + + keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; + keyconf->hw_key_idx = keyconf->keyidx; + priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->default_wep_key++; + + priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; + memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key, + keyconf->keylen); + + ret = iwl_send_static_wepkey_cmd(priv, 0); + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return ret; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h new file mode 100644 index 000000000000..50e9f1470d8d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * James P. Ketrenos + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#ifndef __iwl_sta_h__ +#define __iwl_sta_h__ + +#include + +#include "iwl-eeprom.h" +#include "iwl-core.h" +#include "iwl-4965.h" +#include "iwl-io.h" +#include "iwl-helpers.h" + +int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty); +int iwl_remove_default_wep_key(struct iwl_priv *priv, + struct ieee80211_key_conf *key); +int iwl_set_default_wep_key(struct iwl_priv *priv, + struct ieee80211_key_conf *key); + +#endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index ecc9cba62bf9..dfd2b75492e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -50,6 +50,7 @@ #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" +#include "iwl-sta.h" static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_tx_queue *txq); @@ -941,6 +942,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) return -EIO; } priv->assoc_station_added = 1; + if (priv->default_wep_key && + iwl_send_static_wepkey_cmd(priv, 0)) + IWL_ERROR("Could not send WEP static key.\n"); } return 0; @@ -1180,6 +1184,8 @@ static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) { unsigned long flags; + priv->key_mapping_key = 0; + spin_lock_irqsave(&priv->sta_lock, flags); memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key)); memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); @@ -1198,6 +1204,8 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv, { int ret; + priv->key_mapping_key = 1; + switch (key->alg) { case ALG_CCMP: ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id); @@ -1216,23 +1224,6 @@ static int iwl4965_set_dynamic_key(struct iwl_priv *priv, return ret; } -static int iwl4965_remove_static_key(struct iwl_priv *priv) -{ - int ret = -EOPNOTSUPP; - - return ret; -} - -static int iwl4965_set_static_key(struct iwl_priv *priv, - struct ieee80211_key_conf *key) -{ - if (key->alg == ALG_WEP) - return -EOPNOTSUPP; - - IWL_ERROR("Static key invalid: alg %d\n", key->alg); - return -EINVAL; -} - static void iwl4965_clear_free_frames(struct iwl_priv *priv) { struct list_head *element; @@ -2115,6 +2106,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, int sta_id) { struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo; + struct iwl_wep_key *wepkey; + int keyidx = 0; + + BUG_ON(ctl->key_idx > 3); switch (keyinfo->alg) { case ALG_CCMP: @@ -2133,16 +2128,24 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv, break; case ALG_WEP: - cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP | - (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT; - - if (keyinfo->keylen == 13) - cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; + wepkey = &priv->wep_keys[ctl->key_idx]; + cmd->cmd.tx.sec_ctl = 0; + if (priv->default_wep_key) { + /* the WEP key was sent as static */ + keyidx = ctl->key_idx; + memcpy(&cmd->cmd.tx.key[3], wepkey->key, + wepkey->key_size); + if (wepkey->key_size == WEP_KEY_LEN_128) + cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128; + } else { + IWL_ERROR("No support for WEP key mappings key\n"); + } - memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen); + cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP | + (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT); IWL_DEBUG_TX("Configuring packet for WEP encryption " - "with key %d\n", ctl->key_idx); + "with key %d\n", keyidx); break; default: @@ -6989,7 +6992,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, DECLARE_MAC_BUF(mac); int ret = 0; u8 sta_id = IWL_INVALID_STATION; - u8 static_key; + u8 is_default_wep_key = 0; IWL_DEBUG_MAC80211("enter\n"); @@ -7002,33 +7005,42 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, /* only support pairwise keys */ return -EOPNOTSUPP; - /* FIXME: need to differenciate between static and dynamic key - * in the level of mac80211 */ - static_key = !iwl_is_associated(priv); + sta_id = iwl4965_hw_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %s not in station map.\n", + print_mac(mac, addr)); + return -EINVAL; - if (!static_key) { - sta_id = iwl4965_hw_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); - return -EINVAL; - } } + mutex_lock(&priv->mutex); iwl4965_scan_cancel_timeout(priv, 100); + mutex_unlock(&priv->mutex); + + /* If we are getting WEP group key and we didn't receive any key mapping + * so far, we are in legacy wep mode (group key only), otherwise we are + * in 1X mode. + * In legacy wep mode, we use another host command to the uCode */ + if (key->alg == ALG_WEP && sta_id == priv->hw_setting.bcast_sta_id && + priv->iw_mode != IEEE80211_IF_TYPE_AP) { + if (cmd == SET_KEY) + is_default_wep_key = !priv->key_mapping_key; + else + is_default_wep_key = priv->default_wep_key; + } switch (cmd) { case SET_KEY: - if (static_key) - ret = iwl4965_set_static_key(priv, key); + if (is_default_wep_key) + ret = iwl_set_default_wep_key(priv, key); else ret = iwl4965_set_dynamic_key(priv, key, sta_id); IWL_DEBUG_MAC80211("enable hwcrypto key\n"); break; case DISABLE_KEY: - if (static_key) - ret = iwl4965_remove_static_key(priv); + if (is_default_wep_key) + ret = iwl_remove_default_wep_key(priv, key); else ret = iwl4965_clear_sta_key_info(priv, sta_id); -- cgit v1.2.3-59-g8ed1b From eadd3c4b9a90e31d5b6034a8813bfabecbe48681 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Mon, 14 Apr 2008 21:16:12 -0700 Subject: iwlwifi: make Makefile more concise Also change CONFIG_IWLCORE_RFKILL to CONFIG_IWLWIFI_RFKILL to be more consistent with other config variables. Signed-off-by: Reinette Chatre Acked-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 2 +- drivers/net/wireless/iwlwifi/Makefile | 29 ++++++++--------------------- drivers/net/wireless/iwlwifi/iwl-4965.h | 2 +- drivers/net/wireless/iwlwifi/iwl-rfkill.h | 2 +- 4 files changed, 11 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless/iwlwifi/Makefile') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index bcaa61b7c563..f844b738d34e 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -6,7 +6,7 @@ config IWLWIFI_LEDS bool default n -config IWLCORE_RFKILL +config IWLWIFI_RFKILL boolean "IWLWIFI RF kill support" depends on IWLCORE select RFKILL diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 741ea346a295..4f3e88b12e3a 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,26 +1,13 @@ -obj-$(CONFIG_IWLCORE) += iwlcore.o -iwlcore-objs = iwl-core.o iwl-eeprom.o iwl-hcmd.o - -ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y) - iwlcore-objs += iwl-debugfs.o -endif - -ifeq ($(CONFIG_IWLWIFI_LEDS),y) - iwlcore-objs += iwl-led.o -endif - -ifeq ($(CONFIG_IWLCORE_RFKILL),y) - iwlcore-objs += iwl-rfkill.o -endif +obj-$(CONFIG_IWLCORE) := iwlcore.o +iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o +iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o +iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o +iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o obj-$(CONFIG_IWL3945) += iwl3945.o -iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o - -ifeq ($(CONFIG_IWL3945_LEDS),y) - iwl3945-objs += iwl-3945-led.o -endif - +iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o +iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o obj-$(CONFIG_IWL4965) += iwl4965.o -iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o +iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index daf157adf24e..17c4bcfe113b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -1034,7 +1034,7 @@ struct iwl_priv { * 4965's initialize alive response contains some calibration data. */ struct iwl4965_init_alive_resp card_alive_init; struct iwl4965_alive_resp card_alive; -#ifdef CONFIG_IWLCORE_RFKILL +#ifdef CONFIG_IWLWIFI_RFKILL struct iwl_rfkill_mngr rfkill_mngr; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h index e7aa51a1db18..a7f04b855403 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -34,7 +34,7 @@ struct iwl_priv; #include -#ifdef CONFIG_IWLCORE_RFKILL +#ifdef CONFIG_IWLWIFI_RFKILL struct iwl_rfkill_mngr { struct rfkill *rfkill; struct input_dev *input_dev; -- cgit v1.2.3-59-g8ed1b