static int rtl8180_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8180_priv *priv = dev->priv; if (priv->mode != NL80211_IFTYPE_MONITOR) return -EOPNOTSUPP; switch (conf->type) { case NL80211_IFTYPE_STATION: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } priv->vif = conf->vif; rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], le32_to_cpu(*(__le32 *)conf->mac_addr)); rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); return 0; }
static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) { struct ieee80211_hw *dev = dev_id; struct rtl8180_priv *priv = dev->priv; u16 reg; spin_lock(&priv->lock); reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); if (unlikely(reg == 0xFFFF)) { spin_unlock(&priv->lock); return IRQ_HANDLED; } rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) rtl8180_handle_tx(dev, 3); if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR)) rtl8180_handle_tx(dev, 2); if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) rtl8180_handle_tx(dev, 1); if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) rtl8180_handle_tx(dev, 0); if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) rtl8180_handle_rx(dev); spin_unlock(&priv->lock); return IRQ_HANDLED; }
static void rtl8180_stop(struct ieee80211_hw *dev) { struct rtl8180_priv *priv = dev->priv; u8 reg; int i; priv->mode = NL80211_IFTYPE_UNSPECIFIED; rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); reg = rtl818x_ioread8(priv, &priv->map->CMD); reg &= ~RTL818X_CMD_TX_ENABLE; reg &= ~RTL818X_CMD_RX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); priv->rf->stop(dev); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); free_irq(priv->pdev->irq, dev); rtl8180_free_rx_ring(dev); for (i = 0; i < 4; i++) rtl8180_free_tx_ring(dev, i); }
/* Sets the MAC address of the card. */ static void rtl818x_set_hwaddr(struct net80211_device *dev, u8 *hwaddr) { struct rtl818x_priv *priv = dev->priv; rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); rtl818x_iowrite32(priv, (u32 *)&priv->map->MAC[0], le32_to_cpu(*(u32 *)hwaddr)); rtl818x_iowrite16(priv, (u16 *)&priv->map->MAC[4], le16_to_cpu(*(u16 *)(hwaddr + 4))); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); }
static void rtl818x_poll(struct net80211_device *dev) { struct rtl818x_priv *priv = dev->priv; u16 reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); if (reg == 0xFFFF) return; rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) rtl818x_handle_tx(dev); if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) rtl818x_handle_rx(dev); }
static void write_sa2400(struct net80211_device *dev, u8 addr, u32 data) { struct rtl818x_priv *priv = dev->priv; u32 phy_config; /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ phy_config = 0xb0000000; phy_config |= ((u32)(addr & 0xf)) << 24; phy_config |= data & 0xffffff; /* This was originally a 32-bit write to a typecast RFPinsOutput, but gcc complained about aliasing rules. -JBO */ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, phy_config & 0xffff); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, phy_config >> 16); mdelay(3); }
static int rtl8180_start(struct ieee80211_hw *dev) { struct rtl8180_priv *priv = dev->priv; int ret, i; u32 reg; ret = rtl8180_init_rx_ring(dev); if (ret) return ret; for (i = 0; i < 4; i++) if ((ret = rtl8180_init_tx_ring(dev, i, 16))) goto err_free_rings; ret = rtl8180_init_hw(dev); if (ret) goto err_free_rings; rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); ret = request_irq(priv->pdev->irq, &rtl8180_interrupt, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) { printk(KERN_ERR "%s: failed to register IRQ handler\n", wiphy_name(dev->wiphy)); goto err_free_rings; } rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); reg = RTL818X_RX_CONF_ONLYERLPKT | RTL818X_RX_CONF_RX_AUTORESETPHY | RTL818X_RX_CONF_MGMT | RTL818X_RX_CONF_DATA | (7 << 8 /* MAX RX DMA */) | RTL818X_RX_CONF_BROADCAST | RTL818X_RX_CONF_NICMAC; if (priv->r8185) reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; else { reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) ? RTL818X_RX_CONF_CSDM1 : 0; reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) ? RTL818X_RX_CONF_CSDM2 : 0; } priv->rx_conf = reg; rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); if (priv->r8185) { reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); /* disable early TX */ rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f); } reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); reg |= (6 << 21 /* MAX TX DMA */) | RTL818X_TX_CONF_NO_ICV; if (priv->r8185) reg &= ~RTL818X_TX_CONF_PROBE_DTS; else reg &= ~RTL818X_TX_CONF_HW_SEQNUM; /* different meaning, same value on both rtl8185 and rtl8180 */ reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->CMD); reg |= RTL818X_CMD_RX_ENABLE; reg |= RTL818X_CMD_TX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); priv->mode = NL80211_IFTYPE_MONITOR; return 0; err_free_rings: rtl8180_free_rx_ring(dev); for (i = 0; i < 4; i++) if (priv->tx_ring[i].desc) rtl8180_free_tx_ring(dev, i); return ret; }
static int rtl8180_init_hw(struct ieee80211_hw *dev) { struct rtl8180_priv *priv = dev->priv; u16 reg; rtl818x_iowrite8(priv, &priv->map->CMD, 0); rtl818x_ioread8(priv, &priv->map->CMD); msleep(10); /* reset */ rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); rtl818x_ioread8(priv, &priv->map->CMD); reg = rtl818x_ioread8(priv, &priv->map->CMD); reg &= (1 << 1); reg |= RTL818X_CMD_RESET; rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET); rtl818x_ioread8(priv, &priv->map->CMD); msleep(200); /* check success of reset */ if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) { printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy)); return -ETIMEDOUT; } rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); rtl818x_ioread8(priv, &priv->map->CMD); msleep(200); if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) { /* For cardbus */ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); reg |= 1 << 1; rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); reg = rtl818x_ioread16(priv, &priv->map->FEMR); reg |= (1 << 15) | (1 << 14) | (1 << 4); rtl818x_iowrite16(priv, &priv->map->FEMR, reg); } rtl818x_iowrite8(priv, &priv->map->MSR, 0); if (!priv->r8185) rtl8180_set_anaparam(priv, priv->anaparam); rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); /* TODO: necessary? specs indicate not */ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); if (priv->r8185) { reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); } rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); /* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */ /* TODO: turn off hw wep on rtl8180 */ rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); if (priv->r8185) { rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); /* TODO: set ClkRun enable? necessary? */ reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6)); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); } else { rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1); rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C); } priv->rf->init(dev); if (priv->r8185) rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); return 0; }
static int rtl818x_start(struct net80211_device *dev) { struct rtl818x_priv *priv = dev->priv; int ret; u32 reg; ret = rtl818x_init_rx_ring(dev); if (ret) return ret; ret = rtl818x_init_tx_ring(dev); if (ret) goto err_free_rings; ret = rtl818x_init_hw(dev); if (ret) goto err_free_rings; rtl818x_set_hwaddr(dev, dev->netdev->ll_addr); rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring_dma); rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); reg = RTL818X_RX_CONF_ONLYERLPKT | RTL818X_RX_CONF_RX_AUTORESETPHY | RTL818X_RX_CONF_MGMT | RTL818X_RX_CONF_DATA | (7 << 8 /* MAX RX DMA */) | RTL818X_RX_CONF_BROADCAST | RTL818X_RX_CONF_NICMAC; if (priv->r8185) reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; else { reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) ? RTL818X_RX_CONF_CSDM1 : 0; reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) ? RTL818X_RX_CONF_CSDM2 : 0; } priv->rx_conf = reg; rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); if (priv->r8185) { reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); /* disable early TX */ rtl818x_iowrite8(priv, (u8 *)priv->map + 0xec, 0x3f); } reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); reg |= (6 << 21 /* MAX TX DMA */) | RTL818X_TX_CONF_NO_ICV; if (priv->r8185) reg &= ~RTL818X_TX_CONF_PROBE_DTS; else reg &= ~RTL818X_TX_CONF_HW_SEQNUM; /* different meaning, same value on both rtl8185 and rtl8180 */ reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->CMD); reg |= RTL818X_CMD_RX_ENABLE; reg |= RTL818X_CMD_TX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); DBG("%s rtl818x: started\n", dev->netdev->name); return 0; err_free_rings: rtl818x_free_rx_ring(dev); if (priv->tx_ring) rtl818x_free_tx_ring(dev); DBG("%s rtl818x: failed to start\n", dev->netdev->name); return ret; }
static void rtl818x_irq(struct net80211_device *dev, int enable) { struct rtl818x_priv *priv = dev->priv; rtl818x_iowrite16(priv, &priv->map->INT_MASK, enable? 0xFFFF : 0); }