--- a/ath/if_ath_ahb.c +++ b/ath/if_ath_ahb.c @@ -33,20 +33,15 @@ #include "if_ath_ahb.h" #include "ah_soc.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -#error "Kernel versions older than 2.6.19 are not supported!" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) +#include #endif struct ath_ahb_softc { struct ath_softc aps_sc; -#ifdef CONFIG_PM - u32 aps_pmstate[16]; -#endif + struct ar531x_config aps_config; }; -static struct ath_ahb_softc *sclist[2] = {NULL, NULL}; -static u_int8_t num_activesc = 0; - /* * Module glue. */ @@ -101,13 +96,13 @@ ahb_enable_wmac(u_int16_t devid, u_int16 while (REG_READ(AR5315_PCI_MAC_PCICFG) & AR5315_PCI_MAC_PCICFG_SPWR_DN); } else { switch (wlanNum) { - case AR531X_WLAN0_NUM: + case 0: reset = (AR531X_RESET_WLAN0 | AR531X_RESET_WARM_WLAN0_MAC | AR531X_RESET_WARM_WLAN0_BB); enable = AR531X_ENABLE_WLAN0; break; - case AR531X_WLAN1_NUM: + case 1: reset = (AR531X_RESET_WLAN1 | AR531X_RESET_WARM_WLAN1_MAC | AR531X_RESET_WARM_WLAN1_BB); @@ -144,10 +139,10 @@ ahb_disable_wmac(u_int16_t devid, u_int1 *en &= ~AR5315_ARB_WLAN; } else { switch (wlanNum) { - case AR531X_WLAN0_NUM: + case 0: enable = AR531X_ENABLE_WLAN0; break; - case AR531X_WLAN1_NUM: + case 1: enable = AR531X_ENABLE_WLAN1; break; default: @@ -159,29 +154,6 @@ ahb_disable_wmac(u_int16_t devid, u_int1 } -static int -exit_ath_wmac(u_int16_t wlanNum, struct ar531x_config *config) -{ - struct ath_ahb_softc *sc = sclist[wlanNum]; - struct net_device *dev; - u_int16_t devid; - - if (sc == NULL) - return -ENODEV; /* XXX: correct return value? */ - - dev = sc->aps_sc.sc_dev; - ath_detach(dev); - if (dev->irq) - free_irq(dev->irq, dev); - devid = sc->aps_sc.devid; - config->tag = (void *)((unsigned long) devid); - - ahb_disable_wmac(devid, wlanNum); - free_netdev(dev); - sclist[wlanNum] = NULL; - return 0; -} - static const char ubnt[] = "Ubiquiti Networks"; /* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */ static const struct ath_hw_detect cards[] = { @@ -201,6 +173,114 @@ static const struct ath_hw_detect cards[ { ubnt, "Bullet5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc205 }, }; +static void +ahb_hw_detect(struct ath_ahb_softc *sc, const char *radio) +{ + u16 *radio_data = (u16 *) radio; + if (radio_data) { + u16 vendor, id, subvendor, subid; + vendor = radio_data[1]; + id = radio_data[0]; + subvendor = radio_data[8]; + subid = radio_data[7]; + ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), vendor, id, subvendor, subid); + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) + +static int ahb_wmac_probe(struct platform_device *pdev) +{ + struct ar231x_board_config *bcfg = pdev->dev.platform_data; + struct ath_ahb_softc *sc; + struct net_device *dev; + struct resource *res; + const char *athname; + int err; + + ahb_enable_wmac(bcfg->devid, pdev->id); + dev = alloc_netdev(sizeof(struct ath_ahb_softc), "wifi%d", ether_setup); + if (!dev) + return -ENOMEM; + + sc = dev->priv; + sc->aps_sc.sc_dev = dev; + + dev->irq = platform_get_irq(pdev, 0); + if (dev->irq <= 0) { + printk("%s: Cannot find IRQ resource\n", dev->name); + goto error; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + printk("%s: Cannot find MMIO resource\n", dev->name); + goto error; + } + + dev->mem_start = KSEG1ADDR(res->start); + dev->mem_end = KSEG1ADDR(res->end); + sc->aps_sc.sc_iobase = (void __iomem *) dev->mem_start; + sc->aps_sc.sc_bdev = NULL; + + /* bus information for the HAL */ + sc->aps_config.board = (const struct ar531x_boarddata *) bcfg->config; + sc->aps_config.radio = bcfg->radio; + sc->aps_config.unit = pdev->id; + sc->aps_config.tag = NULL; + + err = ath_attach(bcfg->devid, dev, &sc->aps_config); + if (err != 0) { + printk("%s: ath_attach failed: %d\n", dev->name, err); + goto error; + } + + athname = ath_hal_probe(ATHEROS_VENDOR_ID, bcfg->devid); + printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n", + dev_info, dev->name, athname ? athname : "Atheros ???", dev->mem_start, dev->irq); + + if (request_irq(dev->irq, ath_intr, IRQF_SHARED|IRQF_DISABLED, dev->name, dev)) { + printk(KERN_WARNING "%s: %s: request_irq failed\n", dev_info, dev->name); + goto error; + } + + sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */ + sc->aps_sc.sc_ledpin = bcfg->config->sysLedGpio; + sc->aps_sc.sc_invalid = 0; + ahb_hw_detect(sc, bcfg->radio); + platform_set_drvdata(pdev, dev); + return 0; + +error_dev: + free_irq(dev->irq, dev); +error: + free_netdev(dev); + + return -ENODEV; +} + + +static int ahb_wmac_remove(struct platform_device *pdev) +{ + struct ar231x_board_config *bcfg = pdev->dev.platform_data; + struct net_device *dev; + + dev = platform_get_drvdata(pdev); + ath_detach(dev); + + if (dev->irq) + free_irq(dev->irq, dev); + + ahb_disable_wmac(bcfg->devid, pdev->id); + free_netdev(dev); + + return 0; +} + +#else + +static struct ath_ahb_softc *sclist[2] = {NULL, NULL}; + static int init_ath_wmac(u_int16_t devid, u_int16_t wlanNum, struct ar531x_config *config) { @@ -253,7 +333,7 @@ init_ath_wmac(u_int16_t devid, u_int16_t sc->aps_sc.sc_iobase = (void __iomem *) dev->mem_start; sc->aps_sc.sc_bdev = NULL; - if (request_irq(dev->irq, ath_intr, IRQF_SHARED, dev->name, dev)) { + if (request_irq(dev->irq, ath_intr, IRQF_SHARED|IRQF_DISABLED, dev->name, dev)) { printk(KERN_WARNING "%s: %s: request_irq failed\n", dev_info, dev->name); goto bad3; } @@ -263,21 +343,12 @@ init_ath_wmac(u_int16_t devid, u_int16_t athname = ath_hal_probe(ATHEROS_VENDOR_ID, devid); printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n", dev_info, dev->name, athname ? athname : "Atheros ???", dev->mem_start, dev->irq); - num_activesc++; /* Ready to process interrupts */ sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */ sc->aps_sc.sc_ledpin = config->board->sysLedGpio; sc->aps_sc.sc_invalid = 0; - radio_data = (u16 *) config->radio; - if (radio_data) { - u16 vendor, id, subvendor, subid; - vendor = radio_data[1]; - id = radio_data[0]; - subvendor = radio_data[8]; - subid = radio_data[7]; - ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), vendor, id, subvendor, subid); - } + ahb_hw_detect(sc, config->radio); return 0; @@ -292,6 +363,29 @@ init_ath_wmac(u_int16_t devid, u_int16_t return -ENODEV; } +static int +exit_ath_wmac(u_int16_t wlanNum, struct ar531x_config *config) +{ + struct ath_ahb_softc *sc = sclist[wlanNum]; + struct net_device *dev; + u_int16_t devid; + + if (sc == NULL) + return -ENODEV; /* XXX: correct return value? */ + + dev = sc->aps_sc.sc_dev; + ath_detach(dev); + if (dev->irq) + free_irq(dev->irq, dev); + devid = sc->aps_sc.devid; + config->tag = (void *)((unsigned long) devid); + + ahb_disable_wmac(devid, wlanNum); + free_netdev(dev); + sclist[wlanNum] = NULL; + return 0; +} + static int ahb_wmac_probe(struct platform_device *pdev) { u_int16_t devid; @@ -312,11 +406,18 @@ static int ahb_wmac_remove(struct platfo return 0; } +#endif + static struct platform_driver ahb_wmac_driver = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) + .driver.name = "ar231x-wmac", +#else .driver.name = "ar531x-wmac", +#endif .probe = ahb_wmac_probe, .remove = ahb_wmac_remove }; + int ath_ioctl_ethtool(struct ath_softc *sc, int cmd, void __user *addr) {