// SPDX-License-Identifier: GPL-2.0-or-later /* ZD1211 USB-WLAN driver for Linux * *Copyright(C)2005-2007UlrichKunitz<kune@deine-taler.de> *Copyright(C)2006-2007DanielDrake<dsd@gentoo.org>
*/
/* This file implements all the hardware specific functions for the ZD1211 *andZD1211Bchips.SupportfortheZD1211BwaspossibleafterTimothy *LeggesentmeaZD1211Bdevice.ThankyouTim.--Uli
*/
static zd_addr_t inc_addr(zd_addr_t addr)
{
u16 a = (u16)addr; /* Control registers use byte addressing, but everything else uses word
* addressing. */ if ((a & 0xf000) == CR_START)
a += 2; else
a += 1; return (zd_addr_t)a;
}
/* Read a variable number of 32-bit values. Parameter count is not allowed to *exceedUSB_MAX_IOREAD32_COUNT.
*/ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr, unsignedint count)
{ int r; int i;
zd_addr_t a16[USB_MAX_IOREAD32_COUNT * 2];
u16 v16[USB_MAX_IOREAD32_COUNT * 2]; unsignedint count16;
if (count > USB_MAX_IOREAD32_COUNT) return -EINVAL;
/* Use stack for values and addresses. */
count16 = 2 * count;
BUG_ON(count16 * sizeof(zd_addr_t) > sizeof(a16));
BUG_ON(count16 * sizeof(u16) > sizeof(v16));
for (i = 0; i < count; i++) { int j = 2*i; /* We read the high word always first. */
a16[j] = inc_addr(addr[i]);
a16[j+1] = addr[i];
}
r = zd_ioread16v_locked(chip, v16, a16, count16); if (r) {
dev_dbg_f(zd_chip_dev(chip), "error: %s. Error number %d\n", __func__, r); return r;
}
for (i = 0; i < count; i++) { int j = 2*i;
values[i] = (v16[j] << 16) | v16[j+1];
}
for (i = 0; i < count; i += j + t) {
t = 0;
max = count-i; if (max > USB_MAX_IOWRITE16_COUNT)
max = USB_MAX_IOWRITE16_COUNT; for (j = 0; j < max; j++) { if (!ioreqs[i+j].addr) {
t = 1; break;
}
}
r = zd_usb_iowrite16v_async(&chip->usb, &ioreqs[i], j); if (r) {
zd_usb_iowrite16v_async_end(&chip->usb, 0);
dev_dbg_f(zd_chip_dev(chip), "error zd_usb_iowrite16v. Error number %d\n",
r); return r;
}
}
return zd_usb_iowrite16v_async_end(&chip->usb, 50/* ms */);
}
/* Writes a variable number of 32 bit registers. The functions will split *thatinseveralUSBrequests.AsplitcanbeforcedbyinsertinganIO *requestwithanzeroaddressfield.
*/ int zd_iowrite32a_locked(struct zd_chip *chip, conststruct zd_ioreq32 *ioreqs, unsignedint count)
{ int r; unsignedint i, j, t, max;
zd_usb_iowrite16v_async_start(&chip->usb);
for (i = 0; i < count; i += j + t) {
t = 0;
max = count-i; if (max > USB_MAX_IOWRITE32_COUNT)
max = USB_MAX_IOWRITE32_COUNT; for (j = 0; j < max; j++) { if (!ioreqs[i+j].addr) {
t = 1; break;
}
}
r = _zd_iowrite32v_async_locked(chip, &ioreqs[i], j); if (r) {
zd_usb_iowrite16v_async_end(&chip->usb, 0);
dev_dbg_f(zd_chip_dev(chip), "error _%s. Error number %d\n", __func__,
r); return r;
}
}
return zd_usb_iowrite16v_async_end(&chip->usb, 50/* ms */);
}
int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value)
{ int r;
mutex_lock(&chip->mutex);
r = zd_ioread16_locked(chip, value, addr);
mutex_unlock(&chip->mutex); return r;
}
int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value)
{ int r;
mutex_lock(&chip->mutex);
r = zd_ioread32_locked(chip, value, addr);
mutex_unlock(&chip->mutex); return r;
}
int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value)
{ int r;
mutex_lock(&chip->mutex);
r = zd_iowrite16_locked(chip, value, addr);
mutex_unlock(&chip->mutex); return r;
}
int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value)
{ int r;
mutex_lock(&chip->mutex);
r = zd_iowrite32_locked(chip, value, addr);
mutex_unlock(&chip->mutex); return r;
}
int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
u32 *values, unsignedint count)
{ int r;
mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
mutex_unlock(&chip->mutex); return r;
}
/* MAC address: if custom mac addresses are to be used CR_MAC_ADDR_P1 and *CR_MAC_ADDR_P2mustbeoverwritten
*/ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
{ staticconststruct zd_ioreq32 reqs[2] = {
[0] = { .addr = CR_MAC_ADDR_P1 },
[1] = { .addr = CR_MAC_ADDR_P2 },
};
staticint read_ofdm_cal_values(struct zd_chip *chip)
{ int r; int i; staticconst zd_addr_t addresses[] = {
E2P_36M_CAL_VALUE1,
E2P_48M_CAL_VALUE1,
E2P_54M_CAL_VALUE1,
};
for (i = 0; i < 3; i++) {
r = read_values(chip, chip->ofdm_cal_values[i],
E2P_CHANNEL_COUNT, addresses[i], 0); if (r) return r;
} return0;
}
staticint read_cal_int_tables(struct zd_chip *chip)
{ int r;
r = read_pwr_cal_values(chip); if (r) return r;
r = read_pwr_int_values(chip); if (r) return r;
r = read_ofdm_cal_values(chip); if (r) return r; return0;
}
/* phy means physical registers */ int zd_chip_lock_phy_regs(struct zd_chip *chip)
{ int r;
u32 tmp;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
r = zd_ioread32_locked(chip, &tmp, CR_REG1); if (r) {
dev_err(zd_chip_dev(chip), "error ioread32(CR_REG1): %d\n", r); return r;
}
tmp &= ~UNLOCK_PHY_REGS;
r = zd_iowrite32_locked(chip, tmp, CR_REG1); if (r)
dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r); return r;
}
int zd_chip_unlock_phy_regs(struct zd_chip *chip)
{ int r;
u32 tmp;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
r = zd_ioread32_locked(chip, &tmp, CR_REG1); if (r) {
dev_err(zd_chip_dev(chip), "error ioread32(CR_REG1): %d\n", r); return r;
}
tmp |= UNLOCK_PHY_REGS;
r = zd_iowrite32_locked(chip, tmp, CR_REG1); if (r)
dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r); return r;
}
/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ staticint patch_cr157(struct zd_chip *chip)
{ int r;
u16 value;
if (!chip->patch_cr157) return0;
r = zd_ioread16_locked(chip, &value, E2P_PHY_REG); if (r) return r;
dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); return zd_iowrite32_locked(chip, value >> 8, ZD_CR157);
}
staticint set_mandatory_rates(struct zd_chip *chip, int gmode)
{
u32 rates;
ZD_ASSERT(mutex_is_locked(&chip->mutex)); /* This sets the mandatory rates, which only depend from the standard *thatthedeviceissupporting.Untilfurthernoticeweshouldtry *tosupport802.11galsoforfullspeedUSB.
*/ if (!gmode)
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M; else
rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, int preamble)
{
u32 value = 0;
dev_dbg_f(zd_chip_dev(chip), "preamble=%x\n", preamble);
value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
value |= preamble << RTSCTS_SH_CTS_PMB_TYPE;
/* We always send 11M RTS/self-CTS messages, like the vendor driver. */
value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_RTS_RATE;
value |= ZD_RX_CCK << RTSCTS_SH_RTS_MOD_TYPE;
value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE;
value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE;
int zd_chip_disable_hwint(struct zd_chip *chip)
{ int r;
mutex_lock(&chip->mutex);
r = disable_hwint(chip);
mutex_unlock(&chip->mutex); return r;
}
staticint read_fw_regs_offset(struct zd_chip *chip)
{ int r;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
FWRAW_REGS_ADDR); if (r) return r;
dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
(u16)chip->fw_regs_base);
return0;
}
/* Read mac address using pre-firmware interface */ int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr)
{
dev_dbg_f(zd_chip_dev(chip), "\n"); return zd_usb_read_fw(&chip->usb, E2P_MAC_ADDR_P1, addr,
ETH_ALEN);
}
int zd_chip_init_hw(struct zd_chip *chip)
{ int r;
u8 rf_type;
dev_dbg_f(zd_chip_dev(chip), "\n");
mutex_lock(&chip->mutex);
#ifdef DEBUG
r = test_init(chip); if (r) goto out; #endif
r = zd_iowrite32_locked(chip, 1, CR_AFTER_PNP); if (r) goto out;
r = read_fw_regs_offset(chip); if (r) goto out;
/* GPI is always disabled, also in the other driver.
*/
r = zd_iowrite32_locked(chip, 0, CR_GPI_EN); if (r) goto out;
r = zd_iowrite32_locked(chip, CWIN_SIZE, CR_CWMIN_CWMAX); if (r) goto out; /* Currently we support IEEE 802.11g for full and high speed USB. *Itmightbediscussed,whetherweshouldsupportpurebmodefor *fullspeedUSB.
*/
r = set_mandatory_rates(chip, 1); if (r) goto out; /* Disabling interrupts is certainly a smart thing here.
*/
r = disable_hwint(chip); if (r) goto out;
r = read_pod(chip, &rf_type); if (r) goto out;
r = hw_init(chip); if (r) goto out;
r = zd_rf_init_hw(&chip->rf, rf_type); if (r) goto out;
r = print_fw_version(chip); if (r) goto out;
#ifdef DEBUG
dump_fw_registers(chip);
r = test_init(chip); if (r) goto out; #endif/* DEBUG */
staticint update_channel_integration_and_calibration(struct zd_chip *chip,
u8 channel)
{ int r;
if (!zd_rf_should_update_pwr_int(&chip->rf)) return0;
r = update_pwr_int(chip, channel); if (r) return r; if (zd_chip_is_zd1211b(chip)) { staticconststruct zd_ioreq16 ioreqs[] = {
{ ZD_CR69, 0x28 },
{},
{ ZD_CR69, 0x2a },
};
r = update_ofdm_cal(chip, channel); if (r) return r;
r = update_pwr_cal(chip, channel); if (r) return r;
r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); if (r) return r;
}
return0;
}
/* The CCK baseband gain can be optionally patched by the EEPROM */ staticint patch_cck_gain(struct zd_chip *chip)
{ int r;
u32 value;
if (!chip->patch_cck_gain || !zd_rf_should_patch_cck_gain(&chip->rf)) return0;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
r = zd_ioread32_locked(chip, &value, E2P_PHY_REG); if (r) return r;
dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47);
}
int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
{ int r, t;
mutex_lock(&chip->mutex);
r = zd_chip_lock_phy_regs(chip); if (r) goto out;
r = zd_rf_set_channel(&chip->rf, channel); if (r) goto unlock;
r = update_channel_integration_and_calibration(chip, channel); if (r) goto unlock;
r = patch_cck_gain(chip); if (r) goto unlock;
r = patch_6m_band_edge(chip, channel); if (r) goto unlock;
r = zd_iowrite32_locked(chip, 0, CR_CONFIG_PHILIPS);
unlock:
t = zd_chip_unlock_phy_regs(chip); if (t && !r)
r = t;
out:
mutex_unlock(&chip->mutex); return r;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.