Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea6a634e authored by David S. Miller's avatar David S. Miller
Browse files
parents fa1a9c68 b2e3abdc
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -6,6 +6,35 @@ be removed from this file.

---------------------------

What:	PRISM54
When:	2.6.34

Why:	prism54 FullMAC PCI / Cardbus devices used to be supported only by the
	prism54 wireless driver. After Intersil stopped selling these
	devices in preference for the newer more flexible SoftMAC devices
	a SoftMAC device driver was required and prism54 did not support
	them. The p54pci driver now exists and has been present in the kernel for
	a while. This driver supports both SoftMAC devices and FullMAC devices.
	The main difference between these devices was the amount of memory which
	could be used for the firmware. The SoftMAC devices support a smaller
	amount of memory. Because of this the SoftMAC firmware fits into FullMAC
	devices's memory. p54pci supports not only PCI / Cardbus but also USB
	and SPI. Since p54pci supports all devices prism54 supports
	you will have a conflict. I'm not quite sure how distributions are
	handling this conflict right now. prism54 was kept around due to
	claims users may experience issues when using the SoftMAC driver.
	Time has passed users have not reported issues. If you use prism54
	and for whatever reason you cannot use p54pci please let us know!
	E-mail us at: linux-wireless@vger.kernel.org

	For more information see the p54 wiki page:

	http://wireless.kernel.org/en/users/Drivers/p54

Who:	Luis R. Rodriguez <lrodriguez@atheros.com>

---------------------------

What:	IRQF_SAMPLE_RANDOM
Check:	IRQF_SAMPLE_RANDOM
When:	July 2009
+2 −0
Original line number Diff line number Diff line
@@ -876,6 +876,7 @@ M: "Luis R. Rodriguez" <lrodriguez@atheros.com>
M:	Bob Copeland <me@bobcopeland.com>
L:	linux-wireless@vger.kernel.org
L:	ath5k-devel@lists.ath5k.org
W:	http://wireless.kernel.org/en/users/Drivers/ath5k
S:	Maintained
F:	drivers/net/wireless/ath/ath5k/

@@ -887,6 +888,7 @@ M: Vasanthakumar Thiagarajan <vasanth@atheros.com>
M:	Senthil Balasubramanian <senthilkumar@atheros.com>
L:	linux-wireless@vger.kernel.org
L:	ath9k-devel@lists.ath9k.org
W:	http://wireless.kernel.org/en/users/Drivers/ath9k
S:	Supported
F:	drivers/net/wireless/ath/ath9k/

+8 −2
Original line number Diff line number Diff line
@@ -1303,10 +1303,13 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind)
		     & MDIO_CTRL_MAXF_MASK)));
		break;
	case SSB_BUSTYPE_PCI:
	case SSB_BUSTYPE_PCMCIA:
		bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
		     (0x0d & MDIO_CTRL_MAXF_MASK)));
		break;
	case SSB_BUSTYPE_PCMCIA:
	case SSB_BUSTYPE_SDIO:
		WARN_ON(1); /* A device with this bus does not exist. */
		break;
	}

	br32(bp, B44_MDIO_CTRL);
@@ -1764,10 +1767,13 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf
	case SSB_BUSTYPE_PCI:
		strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
		break;
	case SSB_BUSTYPE_PCMCIA:
	case SSB_BUSTYPE_SSB:
		strlcpy(info->bus_info, "SSB", sizeof(info->bus_info));
		break;
	case SSB_BUSTYPE_PCMCIA:
	case SSB_BUSTYPE_SDIO:
		WARN_ON(1); /* A device with this bus does not exist. */
		break;
	}
}

+16 −41
Original line number Diff line number Diff line
@@ -275,51 +275,26 @@ config PCMCIA_WL3501
	 micro support for ethtool.

config PRISM54
	tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' 
	tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)'
	depends on PCI && EXPERIMENTAL && WLAN_80211
	select WIRELESS_EXT
	select FW_LOADER
	---help---
	  Enable PCI and Cardbus support for the following chipset based cards:

	  ISL3880 - Prism GT            802.11 b/g
	  ISL3877 - Prism Indigo        802.11 a
	  ISL3890 - Prism Duette        802.11 a/b/g
	  
	  For a complete list of supported cards visit <http://prism54.org>.
	  Here is the latest confirmed list of supported cards:

	  3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1)
	  Allnet ALL0271 PCI Card
	  Compex WL54G Cardbus Card
	  Corega CG-WLCB54GT Cardbus Card
	  D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650
	  I-O Data WN-G54/CB Cardbus Card
	  Kobishi XG-300 aka Z-Com Cardbus Card
	  Netgear WG511 Cardbus Card
	  Ovislink WL-5400PCI PCI Card
	  Peabird WLG-PCI PCI Card
	  Sitecom WL-100i Cardbus Card
	  Sitecom WL-110i PCI Card
	  SMC2802W -    EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card
	  SMC2835W -    EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
	  SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
	  Z-Com XG-900 PCI Card
	  Zyxel G-100 Cardbus Card

	  If you enable this you will need a firmware file as well.
	  You will need to copy this to /usr/lib/hotplug/firmware/isl3890.
	  You can get this non-GPL'd firmware file from the Prism54 project page:
	  <http://prism54.org>
	  You will also need the /etc/hotplug/firmware.agent script from
	  a current hotplug package.
	  This enables support for FullMAC PCI/Cardbus prism54 devices. This
	  driver is now deprecated in favor for the SoftMAC driver, p54pci.
	  p54pci supports FullMAC PCI/Cardbus devices as well. For details on
	  the scheduled removal of this driver on the kernel see the feature
	  removal schedule:

	  Documentation/feature-removal-schedule.txt

	  For more information refer to the p54 wiki:

	  http://wireless.kernel.org/en/users/Drivers/p54

	  Note: You need a motherboard with DMA support to use any of these cards

	  If you want to compile the driver as a module ( = code which can be
	  inserted in and removed from the running kernel whenever you want),
	  say M here and read <file:Documentation/kbuild/modules.txt>.
	  The module will be called prism54.
	  When built as module you get the module prism54

config USB_ZD1201
	tristate "USB ZD1201 based Wireless device support"
+419 −1
Original line number Diff line number Diff line
@@ -396,6 +396,136 @@ static struct ar9170_phy_init ar5416_phy_init[] = {
	{ 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, }
};

/*
 * look up a certain register in ar5416_phy_init[] and return the init. value
 * for the band and bandwidth given. Return 0 if register address not found.
 */
static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz)
{
	unsigned int i;
	for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
		if (ar5416_phy_init[i].reg != reg)
			continue;

		if (is_2ghz) {
			if (is_40mhz)
				return ar5416_phy_init[i]._2ghz_40;
			else
				return ar5416_phy_init[i]._2ghz_20;
		} else {
			if (is_40mhz)
				return ar5416_phy_init[i]._5ghz_40;
			else
				return ar5416_phy_init[i]._5ghz_20;
		}
	}
	return 0;
}

/*
 * initialize some phy regs from eeprom values in modal_header[]
 * acc. to band and bandwith
 */
static int ar9170_init_phy_from_eeprom(struct ar9170 *ar,
				bool is_2ghz, bool is_40mhz)
{
	static const u8 xpd2pd[16] = {
		0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2,
		0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2
	};
	u32 defval, newval;
	/* pointer to the modal_header acc. to band */
	struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz];

	ar9170_regwrite_begin(ar);

	/* ant common control (index 0) */
	newval = le32_to_cpu(m->antCtrlCommon);
	ar9170_regwrite(0x1c5964, newval);

	/* ant control chain 0 (index 1) */
	newval = le32_to_cpu(m->antCtrlChain[0]);
	ar9170_regwrite(0x1c5960, newval);

	/* ant control chain 2 (index 2) */
	newval = le32_to_cpu(m->antCtrlChain[1]);
	ar9170_regwrite(0x1c7960, newval);

	/* SwSettle (index 3) */
	if (!is_40mhz) {
		defval = ar9170_get_default_phy_reg_val(0x1c5844,
							is_2ghz, is_40mhz);
		newval = (defval & ~0x3f80) |
			((m->switchSettling & 0x7f) << 7);
		ar9170_regwrite(0x1c5844, newval);
	}

	/* adcDesired, pdaDesired (index 4) */
	defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz);
	newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) |
		((u8)m->adcDesiredSize);
	ar9170_regwrite(0x1c5850, newval);

	/* TxEndToXpaOff, TxFrameToXpaOn (index 5) */
	defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz);
	newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) |
		(m->txFrameToXpaOn << 8) | m->txFrameToXpaOn;
	ar9170_regwrite(0x1c5834, newval);

	/* TxEndToRxOn (index 6) */
	defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz);
	newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16);
	ar9170_regwrite(0x1c5828, newval);

	/* thresh62 (index 7) */
	defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz);
	newval = (defval & ~0x7f000) | (m->thresh62 << 12);
	ar9170_regwrite(0x1c8864, newval);

	/* tx/rx attenuation chain 0 (index 8) */
	defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz);
	newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12);
	ar9170_regwrite(0x1c5848, newval);

	/* tx/rx attenuation chain 2 (index 9) */
	defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz);
	newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12);
	ar9170_regwrite(0x1c7848, newval);

	/* tx/rx margin chain 0 (index 10) */
	defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz);
	newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18);
	/* bsw margin chain 0 for 5GHz only */
	if (!is_2ghz)
		newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10);
	ar9170_regwrite(0x1c620c, newval);

	/* tx/rx margin chain 2 (index 11) */
	defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz);
	newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18);
	ar9170_regwrite(0x1c820c, newval);

	/* iqCall, iqCallq chain 0 (index 12) */
	defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz);
	newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) |
		((u8)m->iqCalQCh[0] & 0x1f);
	ar9170_regwrite(0x1c5920, newval);

	/* iqCall, iqCallq chain 2 (index 13) */
	defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz);
	newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) |
		((u8)m->iqCalQCh[1] & 0x1f);
	ar9170_regwrite(0x1c7920, newval);

	/* xpd gain mask (index 14) */
	defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz);
	newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16);
	ar9170_regwrite(0x1c6258, newval);
	ar9170_regwrite_finish();

	return ar9170_regwrite_result();
}

int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
{
	int i, err;
@@ -426,7 +556,9 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
	if (err)
		return err;

	/* XXX: use EEPROM data here! */
	err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz);
	if (err)
		return err;

	err = ar9170_init_power_cal(ar);
	if (err)
@@ -987,6 +1119,282 @@ static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2)
#undef SHIFT
}

static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array)
{
	int i;

	for (i = 0; i < 3; i++)
		if (x <= x_array[i + 1])
			break;

	return ar9170_interpolate_u8(x,
				     x_array[i],
				     y_array[i],
				     x_array[i + 1],
				     y_array[i + 1]);
}

static int ar9170_set_freq_cal_data(struct ar9170 *ar,
				    struct ieee80211_channel *channel)
{
	u8 *cal_freq_pier;
	u8 vpds[2][AR5416_PD_GAIN_ICEPTS];
	u8 pwrs[2][AR5416_PD_GAIN_ICEPTS];
	int chain, idx, i;
	u8 f;

	switch (channel->band) {
	case IEEE80211_BAND_2GHZ:
		f = channel->center_freq - 2300;
		cal_freq_pier = ar->eeprom.cal_freq_pier_2G;
		i = AR5416_NUM_2G_CAL_PIERS - 1;
		break;

	case IEEE80211_BAND_5GHZ:
		f = (channel->center_freq - 4800) / 5;
		cal_freq_pier = ar->eeprom.cal_freq_pier_5G;
		i = AR5416_NUM_5G_CAL_PIERS - 1;
		break;

	default:
		return -EINVAL;
		break;
	}

	for (; i >= 0; i--) {
		if (cal_freq_pier[i] != 0xff)
			break;
	}
	if (i < 0)
		return -EINVAL;

	idx = ar9170_find_freq_idx(i, cal_freq_pier, f);

	ar9170_regwrite_begin(ar);

	for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) {
		for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) {
			struct ar9170_calibration_data_per_freq *cal_pier_data;
			int j;

			switch (channel->band) {
			case IEEE80211_BAND_2GHZ:
				cal_pier_data = &ar->eeprom.
					cal_pier_data_2G[chain][idx];
				break;

			case IEEE80211_BAND_5GHZ:
				cal_pier_data = &ar->eeprom.
					cal_pier_data_5G[chain][idx];
				break;

			default:
				return -EINVAL;
			}

			for (j = 0; j < 2; j++) {
				vpds[j][i] = ar9170_interpolate_u8(f,
					cal_freq_pier[idx],
					cal_pier_data->vpd_pdg[j][i],
					cal_freq_pier[idx + 1],
					cal_pier_data[1].vpd_pdg[j][i]);

				pwrs[j][i] = ar9170_interpolate_u8(f,
					cal_freq_pier[idx],
					cal_pier_data->pwr_pdg[j][i],
					cal_freq_pier[idx + 1],
					cal_pier_data[1].pwr_pdg[j][i]) / 2;
			}
		}

		for (i = 0; i < 76; i++) {
			u32 phy_data;
			u8 tmp;

			if (i < 25) {
				tmp = ar9170_interpolate_val(i, &pwrs[0][0],
							     &vpds[0][0]);
			} else {
				tmp = ar9170_interpolate_val(i - 12,
							     &pwrs[1][0],
							     &vpds[1][0]);
			}

			phy_data |= tmp << ((i & 3) << 3);
			if ((i & 3) == 3) {
				ar9170_regwrite(0x1c6280 + chain * 0x1000 +
						(i & ~3), phy_data);
				phy_data = 0;
			}
		}

		for (i = 19; i < 32; i++)
			ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2),
					0x0);
	}

	ar9170_regwrite_finish();
	return ar9170_regwrite_result();
}

static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
				    struct ar9170_calctl_edges edges[],
				    u32 freq)
{
/* TODO: move somewhere else */
#define AR5416_MAX_RATE_POWER        63

	int i;
	u8 rc = AR5416_MAX_RATE_POWER;
	u8 f;
	if (freq < 3000)
		f = freq - 2300;
	else
		f = (freq - 4800) / 5;

	for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
		if (edges[i].channel == 0xff)
			break;
		if (f == edges[i].channel) {
			/* exact freq match */
			rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS;
			break;
		}
		if (i > 0 && f < edges[i].channel) {
			if (f > edges[i-1].channel &&
			    edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
				/* lower channel has the inband flag set */
				rc = edges[i-1].power_flags &
					~AR9170_CALCTL_EDGE_FLAGS;
			}
			break;
		}
	}

	if (i == AR5416_NUM_BAND_EDGES) {
		if (f > edges[i-1].channel &&
		    edges[i-1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
			/* lower channel has the inband flag set */
			rc = edges[i-1].power_flags &
				~AR9170_CALCTL_EDGE_FLAGS;
		}
	}
	return rc;
}

/* calculate the conformance test limits and apply them to ar->power*
 * (derived from otus hal/hpmain.c, line 3706 ff.)
 */
static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
{
	u8 ctl_grp; /* CTL group */
	u8 ctl_idx; /* CTL index */
	int i, j;
	struct ctl_modes {
		u8 ctl_mode;
		u8 max_power;
		u8 *pwr_cal_data;
		int pwr_cal_len;
	} *modes;

	/* order is relevant in the mode_list_*: we fall back to the
	 * lower indices if any mode is missed in the EEPROM.
	 */
	struct ctl_modes mode_list_2ghz[] = {
		{ CTL_11B, 0, ar->power_2G_cck, 4 },
		{ CTL_11G, 0, ar->power_2G_ofdm, 4 },
		{ CTL_2GHT20, 0, ar->power_2G_ht20, 8 },
		{ CTL_2GHT40, 0, ar->power_2G_ht40, 8 },
	};
	struct ctl_modes mode_list_5ghz[] = {
		{ CTL_11A, 0, ar->power_5G_leg, 4 },
		{ CTL_5GHT20, 0, ar->power_5G_ht20, 8 },
		{ CTL_5GHT40, 0, ar->power_5G_ht40, 8 },
	};
	int nr_modes;

#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])

	/* TODO: investigate the differences between OTUS'
	 * hpreg.c::zfHpGetRegulatoryDomain() and
	 * ath/regd.c::ath_regd_get_band_ctl() -
	 * e.g. for FCC3_WORLD the OTUS procedure
	 * always returns CTL_FCC, while the one in ath/ delivers
	 * CTL_ETSI for 2GHz and CTL_FCC for 5GHz.
	 */
	ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory,
					ar->hw->conf.channel->band);

	/* ctl group not found - either invalid band (NO_CTL) or ww roaming */
	if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL)
		ctl_grp = CTL_FCC;

	if (ctl_grp != CTL_FCC)
		/* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */
		return;

	if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
		modes = mode_list_2ghz;
		nr_modes = ARRAY_SIZE(mode_list_2ghz);
	} else {
		modes = mode_list_5ghz;
		nr_modes = ARRAY_SIZE(mode_list_5ghz);
	}

	for (i = 0; i < nr_modes; i++) {
		u8 c = ctl_grp | modes[i].ctl_mode;
		for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++)
			if (c == ar->eeprom.ctl_index[ctl_idx])
				break;
		if (ctl_idx < AR5416_NUM_CTLS) {
			int f_off = 0;

			/* adjust freq for 40MHz */
			if (modes[i].ctl_mode == CTL_2GHT40 ||
			    modes[i].ctl_mode == CTL_5GHT40) {
				if (bw == AR9170_BW_40_BELOW)
					f_off = -10;
				else
					f_off = 10;
			}

			modes[i].max_power =
				ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1),
							  freq+f_off);

			/* TODO: check if the regulatory max. power is
			 *  controlled by cfg80211 for DFS
			 * (hpmain applies it to max_power itself for DFS freq)
			 */

		} else {
			/* Workaround in otus driver, hpmain.c, line 3906:
			 * if no data for 5GHT20 are found, take the
			 * legacy 5G value.
			 * We extend this here to fallback from any other *HT or
			 * 11G, too.
			 */
			int k = i;

			modes[i].max_power = AR5416_MAX_RATE_POWER;
			while (k-- > 0) {
				if (modes[k].max_power !=
				    AR5416_MAX_RATE_POWER) {
					modes[i].max_power = modes[k].max_power;
					break;
				}
			}
		}

		/* apply max power to pwr_cal_data (ar->power_*) */
		for (j = 0; j < modes[i].pwr_cal_len; j++) {
			modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j],
						       modes[i].max_power);
		}
	}
#undef EDGES
}

static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
{
	struct ar9170_calibration_target_power_legacy *ctpl;
@@ -1089,6 +1497,12 @@ static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
					ctph[idx + 1].power[n]);
	}


	/* calc. conformance test limits and apply to ar->power*[] */
	ar9170_calc_ctl(ar, freq, bw);

	/* TODO: (heavy clip) regulatory domain power level fine-tuning. */

	/* set ACK/CTS TX power */
	ar9170_regwrite_begin(ar);

@@ -1207,6 +1621,10 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
	if (err)
		return err;

	err = ar9170_set_freq_cal_data(ar, channel);
	if (err)
		return err;

	err = ar9170_set_power_cal(ar, channel->center_freq, bw);
	if (err)
		return err;
Loading