/* ZD1211 USB-WLAN driver for Linux
*
*/
/* 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
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include "zd_def.h"
#include "zd_chip.h"
#include "zd_mac.h"
#include "zd_rf.h"
void zd_chip_init(struct zd_chip *chip,
struct ieee80211_hw *hw,
struct usb_interface *intf)
{
memset(chip, 0, sizeof(*chip));
mutex_init(&chip->mutex);
zd_usb_init(&chip->usb, hw, intf);
zd_rf_init(&chip->rf);
}
void zd_chip_clear(struct zd_chip *chip)
{
ZD_ASSERT(!mutex_is_locked(&chip->mutex));
zd_usb_clear(&chip->usb);
zd_rf_clear(&chip->rf);
mutex_destroy(&chip->mutex);
ZD_MEMCLEAR(chip, sizeof(*chip));
}
static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size)
{
u8 *addr = zd_mac_get_perm_addr(zd_chip_to_mac(chip));
return scnprintf(buffer, size, "%02x-%02x-%02x",
addr[0], addr[1], addr[2]);
}
/* Prints an identifier line, which will support debugging. */
static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
{
int i = 0;
i = scnprintf(buffer, size, "zd1211%s chip ",
zd_chip_is_zd1211b(chip) ? "b" : "");
i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " ");
i += scnprint_mac_oui(chip, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " ");
i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
chip->patch_cck_gain ? 'g' : '-',
chip->patch_cr157 ? '7' : '-',
chip->patch_6m_band_edge ? '6' : '-',
chip->new_phy_layout ? 'N' : '-',
chip->al2230s_bit ? 'S' : '-');
return i;
}
static void print_id(struct zd_chip *chip)
{
char buffer[80];
scnprint_id(chip, buffer, sizeof(buffer));
buffer[sizeof(buffer)-1] = 0;
dev_info(zd_chip_dev(chip), "%s\n", buffer);
}
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,
unsigned int count)
{
int r;
int i;
zd_addr_t a16[USB_MAX_IOREAD32_COUNT * 2];
u16 v16[USB_MAX_IOREAD32_COUNT * 2];
unsigned int 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: zd_ioread16v_locked. Error number %d\n", r);
return r;
}
for (i = 0; i < count; i++) {
int j = 2*i;
values[i] = (v16[j] << 16) | v16[j+1];
}
return 0;
}
static int _zd_iowrite32v_async_locked(struct zd_chip *chip,
const struct zd_ioreq32 *ioreqs,
unsigned int count)
{
int i, j, r;
struct zd_ioreq16 ioreqs16[USB_MAX_IOWRITE32_COUNT * 2];
unsigned int count16;
/* Use stack for values and addresses. */
ZD_ASSERT(mutex_is_locked(&chip->mutex));
if (count == 0)
return 0;
if (count > USB_MAX_IOWRITE32_COUNT)
return -EINVAL;
count16 = 2 * count;
BUG_ON(count16 * sizeof(struct zd_ioreq16) > sizeof(ioreqs16));
for (i = 0; i < count; i++) {
j = 2*i;
/* We write the high word always first. */
ioreqs16[j].value = ioreqs[i].value >> 16;
ioreqs16[j].addr = inc_addr(ioreqs[i].addr);
ioreqs16[j+1].value = ioreqs[i].value;
ioreqs16[j+1].addr = ioreqs[i].addr;
}
r = zd_usb_iowrite16v_async(&chip->usb, ioreqs16, count16);
#ifdef DEBUG
if (r) {
dev_dbg_f(zd_chip_dev(chip),
"error %d in zd_usb_write16v\n", r);
}
#endif /* DEBUG */
return r;
}
int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
unsigned int count)
{
int r;
zd_usb_iowrite16v_async_start(&chip->usb);
r = _zd_iowrite32v_async_locked(chip, ioreqs, count);
if (r) {
zd_usb_iowrite16v_async_end(&chip->usb, 0);
return r;
}
return zd_usb_iowrite16v_async_end(&chip->usb, 50 /* ms */);
}
int zd_iowrite16a_locked(struct zd_chip *chip,
const struct zd_ioreq16 *ioreqs, unsigned int count)
{
int r;
unsigned int i, j, t, max;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
zd_usb_iowrite16v_async_start(&chip->usb);
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,
const struct zd_ioreq32 *ioreqs, unsigned int count)
{
int r;
unsigned int 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 _zd_iowrite32v_locked."
" Error number %d\n", 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, unsigned int count)
{
int r;
mutex_lock(&chip->mutex);
r = zd_ioread32v_locked(chip, values, addresses, count);
mutex_unlock(&chip->mutex);
return r;
}
int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
unsigned int count)
{
int r;
mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, ioreqs, count);
mutex_unlock(&chip->mutex);
return r;
}
static int read_pod(struct zd_chip *chip, u8 *rf_type)
{
int r;
u32 value;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
r = zd_ioread32_locked(chip, &value, E2P_POD);
if (r)
goto error;
dev_dbg_f(zd_chip_dev(chip), "E2P_POD %#010x\n", value);
/* FIXME: AL2230 handling (Bit 7 in POD) */
*rf_type = value & 0x0f;
chip->pa_type = (value >> 16) & 0x0f;
chip->patch_cck_gain = (value >> 8) & 0x1;
chip->patch_cr157 = (value >> 13) & 0x1;
chip->patch_6m_band_edge = (value >> 21) & 0x1;
chip->new_phy_layout = (value >> 31) & 0x