// SPDX-License-Identifier: GPL-2.0-or-later /* ZD1211 USB-WLAN driver for Linux * * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org>
*/
/* This file implements all the hardware specific functions for the ZD1211 * and ZD1211B chips. Support for the ZD1211B was possible after Timothy * Legge sent me a ZD1211B device. Thank you Tim. -- 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 * exceed USB_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 * that in several USB requests. A split can be forced by inserting an IO * request with an zero address field.
*/ 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_P2 must be overwritten
*/ 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;
} return 0;
}
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; return 0;
}
/* 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) return 0;
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);
}
/* * 6M band edge can be optionally overwritten for certain RF's * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge * bit (for AL2230, AL2230S)
*/ staticint patch_6m_band_edge(struct zd_chip *chip, u8 channel)
{
ZD_ASSERT(mutex_is_locked(&chip->mutex)); if (!chip->patch_6m_band_edge) return 0;
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 * that the device is supporting. Until further notice we should try * to support 802.11g also for full speed USB.
*/ 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);
return 0;
}
/* 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. * It might be discussed, whether we should support pure b mode for * full speed USB.
*/
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)) return 0;
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;
}
return 0;
}
/* 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)) return 0;
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;
}
/** * zd_rx_rate - report zd-rate * @rx_frame: received frame * @status: rx_status as given by the device * * This function converts the rate as encoded in the received packet to the * zd-rate, we are using on other places in the driver.
*/
u8 zd_rx_rate(constvoid *rx_frame, conststruct rx_status *status)
{
u8 zd_rate; if (status->frame_status & ZD_RX_OFDM) {
zd_rate = zd_rate_from_ofdm_plcp_header(rx_frame);
} else { switch (zd_cck_plcp_header_signal(rx_frame)) { case ZD_CCK_PLCP_SIGNAL_1M:
zd_rate = ZD_CCK_RATE_1M; break; case ZD_CCK_PLCP_SIGNAL_2M:
zd_rate = ZD_CCK_RATE_2M; break; case ZD_CCK_PLCP_SIGNAL_5M5:
zd_rate = ZD_CCK_RATE_5_5M; break; case ZD_CCK_PLCP_SIGNAL_11M:
zd_rate = ZD_CCK_RATE_11M; break; default:
zd_rate = 0;
}
}
return zd_rate;
}
int zd_chip_switch_radio_on(struct zd_chip *chip)
{ int r;
mutex_lock(&chip->mutex);
r = zd_switch_radio_on(&chip->rf);
mutex_unlock(&chip->mutex); return r;
}
int zd_chip_switch_radio_off(struct zd_chip *chip)
{ int r;
mutex_lock(&chip->mutex);
r = zd_switch_radio_off(&chip->rf);
mutex_unlock(&chip->mutex); return r;
}
int zd_chip_enable_int(struct zd_chip *chip)
{ int r;
mutex_lock(&chip->mutex);
r = zd_usb_enable_int(&chip->usb);
mutex_unlock(&chip->mutex); return r;
}
int zd_rfwritev_locked(struct zd_chip *chip, const u32* values, unsignedint count, u8 bits)
{ int r; unsignedint i;
for (i = 0; i < count; i++) {
r = zd_rfwrite_locked(chip, values[i], bits); if (r) return r;
}
return 0;
}
/* * We can optionally program the RF directly through CR regs, if supported by * the hardware. This is much faster than the older method.
*/ int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
{ conststruct zd_ioreq16 ioreqs[] = {
{ ZD_CR244, (value >> 16) & 0xff },
{ ZD_CR243, (value >> 8) & 0xff },
{ ZD_CR242, value & 0xff },
};
ZD_ASSERT(mutex_is_locked(&chip->mutex)); return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
int zd_rfwritev_cr_locked(struct zd_chip *chip, const u32 *values, unsignedint count)
{ int r; unsignedint i;
for (i = 0; i < count; i++) {
r = zd_rfwrite_cr_locked(chip, values[i]); if (r) 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.