176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Linux device driver for RTL8180 / RTL8185
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Modified for gPXE, June 2009, by Joshua Oreman <oremanj@rwcr.net>
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Based on the r8180 driver, which is:
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Thanks to Realtek for their support!
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or modify
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it under the terms of the GNU General Public License version 2 as
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * published by the Free Software Foundation.
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE(GPL2_ONLY);
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h>
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h>
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h>
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <byteswap.h>
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h>
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/malloc.h>
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/pci.h>
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/net80211.h>
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h>
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/threewire.h>
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "rtl818x.h"
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* rtl818x_rates[hw rate number] = rate in 100kbps units */
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u16 rtl818x_rates[] = {
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	10, 20, 55, 110, /* 802.11b */
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	60, 90, 120, 180, 240, 360, 480, 540, /* 802.11g */
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	0, 0, 0, 0,		/* index safely using a value masked with 0xF */
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define RTL818X_NR_B_RATES  4
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define RTL818X_NR_RATES    12
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* used by RF drivers */
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid rtl818x_write_phy(struct net80211_device *dev, u8 addr, u32 data)
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i = 10;
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 buf;
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	buf = (data << 8) | addr;
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, (u32 *)&priv->map->PHY[0], buf | 0x80);
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while (i--) {
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite32(priv, (u32 *)&priv->map->PHY[0], buf);
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF))
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return;
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_handle_rx(struct net80211_device *dev)
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int count = RTL818X_RX_RING_SIZE;
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while (count--) {
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		struct rtl818x_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		struct io_buffer *iob = priv->rx_buf[priv->rx_idx];
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u32 flags = le32_to_cpu(entry->flags);
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (flags & RTL818X_RX_DESC_FLAG_OWN)
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return;
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     RTL818X_RX_DESC_FLAG_FOF |
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     RTL818X_RX_DESC_FLAG_RX_ERR)) {
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			/* This is crappy hardware. The Linux driver
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			   doesn't even log these. */
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			goto done;
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) {
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			/* This is actually a corrupt packet. */
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBG2("rtl818x RX:%d CRC fail: flags %08x\n",
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     priv->rx_idx, flags);
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			net80211_rx_err(dev, NULL, EIO);
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else {
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			u32 flags2 = le32_to_cpu(entry->flags2);
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			struct io_buffer *new_iob = alloc_iob(MAX_RX_SIZE);
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			if (!new_iob) {
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				net80211_rx_err(dev, NULL, ENOMEM);
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				goto done;
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			}
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBGP("rtl818x RX:%d success: flags %08x %08x\n",
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     priv->rx_idx, flags, flags2);
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			iob_put(iob, flags & 0xFFF);
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			net80211_rx(dev, iob, (flags2 >> 8) & 0x7f,
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				    rtl818x_rates[(flags >> 20) & 0xf]);
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			iob = new_iob;
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			priv->rx_buf[priv->rx_idx] = iob;
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	done:
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry->rx_buf = cpu_to_le32(virt_to_bus(iob->data));
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | MAX_RX_SIZE);
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (priv->rx_idx == RTL818X_RX_RING_SIZE - 1)
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->rx_idx = (priv->rx_idx + 1) % RTL818X_RX_RING_SIZE;
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_handle_tx(struct net80211_device *dev)
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	unsigned int count = RTL818X_TX_RING_SIZE;
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while (count--) {
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		struct rtl818x_tx_desc *entry = &priv->tx_ring[priv->tx_cons];
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		struct io_buffer *iob = priv->tx_buf[priv->tx_cons];
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u32 flags = le32_to_cpu(entry->flags);
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int rc;
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ((flags & RTL818X_TX_DESC_FLAG_OWN) || !iob)
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return;
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rc = 0;
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!(flags & RTL818X_TX_DESC_FLAG_TX_OK)) {
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			/* our packet was not ACKed properly */
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			rc = EIO;
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		net80211_tx_complete(dev, iob, flags & 0xFF, rc);
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->tx_buf[priv->tx_cons] = NULL;
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->tx_cons = (priv->tx_cons + 1) % RTL818X_TX_RING_SIZE;
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_poll(struct net80211_device *dev)
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS);
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (reg == 0xFFFF)
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return;
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_handle_tx(dev);
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR))
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_handle_rx(dev);
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define DIV_ROUND_UP(n,d) (((n)+(d)-1)/(d))
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_tx(struct net80211_device *dev, struct io_buffer *iob)
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_tx_desc *entry;
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 tx_flags;
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 plcp_len = 0;
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int len = iob_len(iob);
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS |
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		RTL818X_TX_DESC_FLAG_LS | (priv->hw_rate << 24) | len;
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185) {
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    RTL818X_TX_DESC_FLAG_NO_ENC;
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		unsigned int remainder;
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		plcp_len = DIV_ROUND_UP(16 * (len + 4),
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman					(dev->rates[dev->rate] * 2) / 10);
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		remainder = (16 * (len + 4)) %
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    ((dev->rates[dev->rate] * 2) / 10);
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (remainder > 0 && remainder <= 6)
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			plcp_len |= 1 << 15;
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry = &priv->tx_ring[priv->tx_prod];
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (dev->phy_flags & NET80211_PHY_USE_PROTECTION) {
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx_flags |= priv->hw_rtscts_rate << 19;
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry->rts_duration = net80211_cts_duration(dev, len);
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry->rts_duration = 0;
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (entry->flags & RTL818X_TX_DESC_FLAG_OWN) {
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* card hasn't processed the old packet yet! */
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -EBUSY;
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->tx_buf[priv->tx_prod] = iob;
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->tx_prod = (priv->tx_prod + 1) % RTL818X_TX_RING_SIZE;
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry->plcp_len = cpu_to_le16(plcp_len);
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry->tx_buf = cpu_to_le32(virt_to_bus(iob->data));
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry->frame_len = cpu_to_le32(len);
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry->flags2 = /* alternate retry rate in 100kbps << 4 */ 0;
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry->retry_limit = RTL818X_MAX_RETRIES;
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry->flags = cpu_to_le32(tx_flags);
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << 5));
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid rtl818x_set_anaparam(struct rtl818x_priv *priv, u32 anaparam)
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u8 reg;
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam);
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		 reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_init_hw(struct net80211_device *dev)
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 reg;
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CMD, 0);
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_ioread8(priv, &priv->map->CMD);
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdelay(10);
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* reset */
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_ioread8(priv, &priv->map->CMD);
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread8(priv, &priv->map->CMD);
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg &= (1 << 1);
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg |= RTL818X_CMD_RESET;
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET);
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_ioread8(priv, &priv->map->CMD);
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdelay(200);
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* check success of reset */
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) {
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x %s: reset timeout!\n", dev->netdev->name);
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ETIMEDOUT;
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_ioread8(priv, &priv->map->CMD);
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	mdelay(200);
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) {
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* For cardbus */
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg |= 1 << 1;
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg = rtl818x_ioread16(priv, &priv->map->FEMR);
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg |= (1 << 15) | (1 << 14) | (1 << 4);
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite16(priv, &priv->map->FEMR, reg);
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->MSR, 0);
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!priv->r8185)
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_set_anaparam(priv, priv->anaparam);
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring_dma);
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* TODO: necessary? specs indicate not */
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3));
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185) {
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4));
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* TODO: turn off hw wep on rtl8180 */
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185) {
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* TODO: set ClkRun enable? necessary? */
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE);
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6));
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2));
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1);
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->SECURITY, 0);
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6);
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C);
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rf->init(dev);
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185)
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_init_rx_ring(struct net80211_device *dev)
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_rx_desc *entry;
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rx_ring = malloc_dma(sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE,
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				   RTL818X_RING_ALIGN);
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rx_ring_dma = virt_to_bus(priv->rx_ring);
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!priv->rx_ring) {
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x %s: cannot allocate RX ring\n", dev->netdev->name);
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE);
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rx_idx = 0;
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < RTL818X_RX_RING_SIZE; i++) {
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		struct io_buffer *iob = alloc_iob(MAX_RX_SIZE);
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry = &priv->rx_ring[i];
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!iob)
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return -ENOMEM;
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->rx_buf[i] = iob;
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry->rx_buf = cpu_to_le32(virt_to_bus(iob->data));
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN |
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman					   MAX_RX_SIZE);
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_free_rx_ring(struct net80211_device *dev)
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < RTL818X_RX_RING_SIZE; i++) {
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		free_iob(priv->rx_buf[i]);
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->rx_buf[i] = NULL;
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free_dma(priv->rx_ring, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE);
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rx_ring = NULL;
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_init_tx_ring(struct net80211_device *dev)
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->tx_ring = malloc_dma(sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE,
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				   RTL818X_RING_ALIGN);
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->tx_ring_dma = virt_to_bus(priv->tx_ring);
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!priv->tx_ring) {
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x %s: cannot allocate TX ring\n", dev->netdev->name);
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(priv->tx_ring, 0, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE);
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->tx_prod = priv->tx_cons = 0;
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < RTL818X_TX_RING_SIZE; i++)
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->tx_ring[i].next_tx_desc = cpu_to_le32(priv->tx_ring_dma +
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				((i + 1) % RTL818X_TX_RING_SIZE) * sizeof(*priv->tx_ring));
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_free_tx_ring(struct net80211_device *dev)
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < RTL818X_TX_RING_SIZE; i++) {
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (priv->tx_buf[i])
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			net80211_tx_complete(dev, priv->tx_buf[i], 0, ECANCELED);
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->tx_buf[i] = NULL;
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free_dma(priv->tx_ring, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE);
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->tx_ring = NULL;
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_irq(struct net80211_device *dev, int enable)
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite16(priv, &priv->map->INT_MASK, enable? 0xFFFF : 0);
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Sets the MAC address of the card. */
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_set_hwaddr(struct net80211_device *dev, u8 *hwaddr)
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, (u32 *)&priv->map->MAC[0],
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  le32_to_cpu(*(u32 *)hwaddr));
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite16(priv, (u16 *)&priv->map->MAC[4],
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			  le16_to_cpu(*(u16 *)(hwaddr + 4)));
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_start(struct net80211_device *dev)
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int ret;
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 reg;
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ret = rtl818x_init_rx_ring(dev);
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (ret)
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return ret;
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ret = rtl818x_init_tx_ring(dev);
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (ret)
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_free_rings;
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ret = rtl818x_init_hw(dev);
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (ret)
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_free_rings;
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_set_hwaddr(dev, dev->netdev->ll_addr);
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring_dma);
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = RTL818X_RX_CONF_ONLYERLPKT |
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      RTL818X_RX_CONF_RX_AUTORESETPHY |
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      RTL818X_RX_CONF_MGMT |
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      RTL818X_RX_CONF_DATA |
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      (7 << 8 /* MAX RX DMA */) |
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      RTL818X_RX_CONF_BROADCAST |
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      RTL818X_RX_CONF_NICMAC;
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185)
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2;
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else {
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1)
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			? RTL818X_RX_CONF_CSDM1 : 0;
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2)
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			? RTL818X_RX_CONF_CSDM2 : 0;
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rx_conf = reg;
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185) {
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg |=  RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* disable early TX */
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, (u8 *)priv->map + 0xec, 0x3f);
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg |= (6 << 21 /* MAX TX DMA */) |
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       RTL818X_TX_CONF_NO_ICV;
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185)
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg &= ~RTL818X_TX_CONF_PROBE_DTS;
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		reg &= ~RTL818X_TX_CONF_HW_SEQNUM;
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* different meaning, same value on both rtl8185 and rtl8180 */
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg &= ~RTL818X_TX_CONF_SAT_HWPLCP;
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread8(priv, &priv->map->CMD);
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg |= RTL818X_CMD_RX_ENABLE;
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg |= RTL818X_CMD_TX_ENABLE;
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG("%s rtl818x: started\n", dev->netdev->name);
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err_free_rings:
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_free_rx_ring(dev);
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->tx_ring)
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_free_tx_ring(dev);
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG("%s rtl818x: failed to start\n", dev->netdev->name);
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return ret;
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_stop(struct net80211_device *dev)
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u8 reg;
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_irq(dev, 0);
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread8(priv, &priv->map->CMD);
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg &= ~RTL818X_CMD_TX_ENABLE;
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg &= ~RTL818X_CMD_RX_ENABLE;
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rf->stop(dev);
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_free_rx_ring(dev);
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_free_tx_ring(dev);
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_config(struct net80211_device *dev, int changed)
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = dev->priv;
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int i;
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (changed & NET80211_CFG_CHANNEL)
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->rf->set_chan(dev, &dev->channels[dev->channel]);
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (changed & NET80211_CFG_ASSOC) {
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		for (i = 0; i < ETH_ALEN; i++)
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			rtl818x_iowrite8(priv, &priv->map->BSSID[i], dev->bssid[i]);
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		rtl818x_iowrite8(priv, &priv->map->MSR,
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 dev->state & NET80211_ASSOCIATED?
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman					RTL818X_MSR_INFRA : RTL818X_MSR_NO_LINK);
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (changed & NET80211_CFG_PHY_PARAMS)
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->rf->conf_erp(dev);
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (changed & NET80211_CFG_RATE) {
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* figure out the hardware rate number for the new
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   logical rate */
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int hw_rate;
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		for (hw_rate = 0; hw_rate < RTL818X_NR_RATES &&
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     rtl818x_rates[hw_rate] != dev->rates[dev->rate];
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		     hw_rate++)
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			;
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (hw_rate >= RTL818X_NR_RATES)
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			return -EINVAL;
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->hw_rate = hw_rate;
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* and the RTS/CTS rate */
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		for (hw_rate = 0; hw_rate < RTL818X_NR_RATES &&
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     rtl818x_rates[hw_rate] !=
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				dev->rates[dev->rtscts_rate];
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		     hw_rate++)
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			;
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (hw_rate >= RTL818X_NR_RATES)
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			hw_rate = priv->hw_rate;
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->hw_rtscts_rate = hw_rate;
58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u8 rtl818x_eeprom_bits[] = {
59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	[SPI_BIT_SCLK] = RTL818X_EEPROM_CMD_CK,
59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	[SPI_BIT_MISO] = RTL818X_EEPROM_CMD_READ,
59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	[SPI_BIT_MOSI] = RTL818X_EEPROM_CMD_WRITE,
59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	[SPI_BIT_SS(0)] = RTL818X_EEPROM_CMD_CS,
59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_spi_read_bit(struct bit_basher *basher, unsigned int bit_id)
60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = container_of(basher, struct rtl818x_priv,
60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman						 spibit.basher);
60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return reg & rtl818x_eeprom_bits[bit_id];
60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_spi_write_bit(struct bit_basher *basher,
61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				  unsigned int bit_id, unsigned long data)
61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv = container_of(basher, struct rtl818x_priv,
61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman						 spibit.basher);
61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u8 mask = rtl818x_eeprom_bits[bit_id];
61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = (reg & ~mask) | (data & mask);
61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	udelay(10);
62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct bit_basher_operations rtl818x_basher_ops = {
62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.read = rtl818x_spi_read_bit,
62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.write = rtl818x_spi_write_bit,
62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if DBGLVL_MAX
63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char *rtl818x_rf_names[] = {
63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	NULL,			/* no 0 */
63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	"Intersil", "RFMD",	/* unsupported 1-2 */
63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	"SA2400", "max2820", "GRF5101",	/* supported 3-5 */
63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	NULL, NULL, NULL,	/* no 6-8 */
63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	"RTL8225",		/* supported 9 */
63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	"RTL8255",		/* unsupported 10 */
63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define RTL818X_NR_RF_NAMES 11
64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct net80211_device_operations rtl818x_operations = {
64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.open = rtl818x_start,
64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.close = rtl818x_stop,
64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.transmit = rtl818x_tx,
64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.poll = rtl818x_poll,
64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.irq = rtl818x_irq,
64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.config = rtl818x_config,
65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int rtl818x_probe(struct pci_device *pdev,
65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			 const struct pci_device_id *id __unused)
65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net80211_device *dev;
65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_priv *priv;
65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct rtl818x_rf_ops *rf;
65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int err, i;
65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	const char *chip_name;
66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u32 reg;
66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	u16 eeprom_val;
66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net80211_hw_info *hwinfo;
66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hwinfo = zalloc(sizeof(*hwinfo));
66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!hwinfo) {
66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x: hwinfo alloc failed\n");
66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	adjust_pci_device(pdev);
67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dev = net80211_alloc(sizeof(*priv));
67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!dev) {
67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x: net80211 alloc failed\n");
67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return -ENOMEM;
67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv = dev->priv;
67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->pdev = pdev;
68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	dev->netdev->dev = &pdev->dev;
68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->map = (struct rtl818x_csr *)pdev->ioaddr;
68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!priv->map) {
68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x: cannot find device memory\n");
68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		err = -ENXIO;
68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_free_dev;
68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	reg &= RTL818X_TX_CONF_HWVER_MASK;
69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (reg) {
69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL818X_TX_CONF_R8180_ABCD:
69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		chip_name = "0";
69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL818X_TX_CONF_R8180_F:
69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		chip_name = "0vF";
69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL818X_TX_CONF_R8185_ABC:
69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		chip_name = "5";
70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case RTL818X_TX_CONF_R8185_D:
70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		chip_name = "5vD";
70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x: Unknown chip! (0x%x)\n", reg >> 25);
70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		err = -ENOSYS;
70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_free_dev;
70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC;
71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hwinfo->bands = NET80211_BAND_BIT_2GHZ;
71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hwinfo->flags = NET80211_HW_RX_HAS_FCS;
71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hwinfo->signal_type = NET80211_SIGNAL_ARBITRARY;
71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hwinfo->signal_max = 65;
71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hwinfo->channel_change_time = 1000;
71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(hwinfo->rates[NET80211_BAND_2GHZ], rtl818x_rates,
71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       sizeof(*rtl818x_rates) * RTL818X_NR_RATES);
72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185) {
72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		hwinfo->modes = NET80211_MODE_B | NET80211_MODE_G;
72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		hwinfo->nr_rates[NET80211_BAND_2GHZ] = RTL818X_NR_RATES;
72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		hwinfo->modes = NET80211_MODE_B;
72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		hwinfo->nr_rates[NET80211_BAND_2GHZ] = RTL818X_NR_B_RATES;
72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->spibit.basher.op = &rtl818x_basher_ops;
73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->spibit.bus.mode = SPI_MODE_THREEWIRE;
73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	init_spi_bit_basher(&priv->spibit);
73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG2("rtl818x RX_CONF: %08x\n", rtl818x_ioread32(priv, &priv->map->RX_CONF));
73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		init_at93c66(&priv->eeprom, 16);
73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		init_at93c46(&priv->eeprom, 16);
73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->eeprom.bus = &priv->spibit.bus;
74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM);
74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	udelay(10);
74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nvs_read(&priv->eeprom.nvs, 0x06, &eeprom_val, 2);
74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG2("rtl818x eeprom val = %04x\n", eeprom_val);
74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	eeprom_val &= 0xFF;
74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->rf = NULL;
75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for_each_table_entry(rf, RTL818X_RF_DRIVERS) {
75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (rf->id == eeprom_val) {
75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			priv->rf = rf;
75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			break;
75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!priv->rf) {
75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if DBGLVL_MAX
75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (eeprom_val < RTL818X_NR_RF_NAMES &&
76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    rtl818x_rf_names[eeprom_val] != NULL)
76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBG("rtl818x: %s RF frontend not supported!\n",
76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    rtl818x_rf_names[eeprom_val]);
76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		else
76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			DBG("rtl818x: RF frontend #%d not recognized!\n",
76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    eeprom_val);
76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		err = -ENOSYS;
76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_free_dev;
77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nvs_read(&priv->eeprom.nvs, 0x17, &eeprom_val, 2);
77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	priv->csthreshold = eeprom_val >> 8;
77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!priv->r8185) {
77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nvs_read(&priv->eeprom.nvs, 0xD, &priv->anaparam, 4);
77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nvs_read(&priv->eeprom.nvs, 0x19, &priv->rfparam, 2);
77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->anaparam = le32_to_cpu(priv->anaparam);
77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->rfparam = le16_to_cpu(priv->rfparam);
77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* read the MAC address */
78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	nvs_read(&priv->eeprom.nvs, 0x7, hwinfo->hwaddr, 6);
78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* CCK TX power */
78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < 14; i += 2) {
78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		u16 txpwr;
78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		nvs_read(&priv->eeprom.nvs, 0x10 + (i >> 1), &txpwr, 2);
78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->txpower[i] = txpwr & 0xFF;
78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		priv->txpower[i + 1] = txpwr >> 8;
79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* OFDM TX power */
79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (priv->r8185) {
79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		for (i = 0; i < 14; i += 2) {
79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			u16 txpwr;
79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			nvs_read(&priv->eeprom.nvs, 0x20 + (i >> 1), &txpwr, 2);
79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			priv->txpower[i] |= (txpwr & 0xFF) << 8;
79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			priv->txpower[i + 1] |= txpwr & 0xFF00;
79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	err = net80211_register(dev, &rtl818x_operations, hwinfo);
80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (err) {
80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		DBG("rtl818x: cannot register device\n");
80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		goto err_free_dev;
80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free(hwinfo);
81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	DBG("rtl818x: Realtek RTL818%s (RF chip %s) with address %s\n",
81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    chip_name, priv->rf->name, netdev_addr(dev->netdev));
81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;
81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err_free_dev:
81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	pci_set_drvdata(pdev, NULL);
81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	net80211_free(dev);
82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	free(hwinfo);
82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return err;
82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void rtl818x_remove(struct pci_device *pdev)
82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	struct net80211_device *dev = pci_get_drvdata(pdev);
82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!dev)
82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return;
83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	net80211_unregister(dev);
83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	net80211_free(dev);
83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Hide PCI_ROM definitions in here from parserom.pl; the definitions
83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   that should be used are in rtl8180.c and rtl8185.c. */
83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define RTL_ROM PCI_ROM
83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id rtl818x_nics[] = {
84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_ROM(0x10ec, 0x8185, "rtl8185", "Realtek 8185", 0),
84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_ROM(0x1799, 0x700f, "f5d7000", "Belkin F5D7000", 0),
84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_ROM(0x1799, 0x701f, "f5d7010", "Belkin F5D7010", 0),
84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_ROM(0x10ec, 0x8180, "rtl8180", "Realtek 8180", 0),
84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_ROM(0x1799, 0x6001, "f5d6001", "Belkin F5D6001", 0),
84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_ROM(0x1799, 0x6020, "f5d6020", "Belkin F5D6020", 0),
84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	RTL_ROM(0x1186, 0x3300, "dwl510",  "D-Link DWL-510", 0),
84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct pci_driver rtl818x_driver __pci_driver = {
85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.ids            = rtl818x_nics,
85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.id_count       = sizeof(rtl818x_nics) / sizeof(rtl818x_nics[0]),
85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.probe		= rtl818x_probe,
85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	.remove		= rtl818x_remove,
85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
856