mac80211: oops, add missing patches
authorGabor Juhos <juhosg@openwrt.org>
Wed, 7 Jan 2009 18:21:53 +0000 (18:21 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Wed, 7 Jan 2009 18:21:53 +0000 (18:21 +0000)
SVN-Revision: 13926

package/mac80211/patches/403-ath9k-introduce-bus-specific-cache-size-routine.patch [new file with mode: 0644]
package/mac80211/patches/404-ath9k-introduce-bus-specific-cleanup-routine.patch [new file with mode: 0644]
package/mac80211/patches/405-ath9k-move-PCI-code-into-separate-file.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/403-ath9k-introduce-bus-specific-cache-size-routine.patch b/package/mac80211/patches/403-ath9k-introduce-bus-specific-cache-size-routine.patch
new file mode 100644 (file)
index 0000000..4fd4969
--- /dev/null
@@ -0,0 +1,85 @@
+From 1306e6b6d72b2bc0b91bcdd15b1d982965210bda Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Mon, 5 Jan 2009 10:57:42 +0100
+Subject: [PATCH 03/11] ath9k: introduce bus specific cache size routine
+
+The PCI specific bus_read_cachesize routine won't work on the AHB bus,
+we have to replace it with a suitable one later.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+ drivers/net/wireless/ath9k/core.h |   10 ++++++++++
+ drivers/net/wireless/ath9k/main.c |    9 +++++++--
+ 2 files changed, 17 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/wireless/ath9k/core.h
++++ b/drivers/net/wireless/ath9k/core.h
+@@ -693,6 +693,10 @@ enum PROT_MODE {
+ #define SC_OP_RFKILL_SW_BLOCKED       BIT(12)
+ #define SC_OP_RFKILL_HW_BLOCKED       BIT(13)
++struct ath_bus_ops {
++      void            (*read_cachesize)(struct ath_softc *sc, int *csz);
++};
++
+ struct ath_softc {
+       struct ieee80211_hw *hw;
+       struct device *dev;
+@@ -743,6 +747,7 @@ struct ath_softc {
+ #ifdef CONFIG_ATH9K_DEBUG
+       struct ath9k_debug sc_debug;
+ #endif
++      struct ath_bus_ops *bus_ops;
+ };
+ int ath_reset(struct ath_softc *sc, bool retry_tx);
+@@ -750,4 +755,9 @@ int ath_get_hal_qnum(u16 queue, struct a
+ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
+ int ath_cabq_update(struct ath_softc *);
++static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
++{
++      sc->bus_ops->read_cachesize(sc, csz);
++}
++
+ #endif /* CORE_H */
+--- a/drivers/net/wireless/ath9k/main.c
++++ b/drivers/net/wireless/ath9k/main.c
+@@ -42,7 +42,7 @@ static void ath_detach(struct ath_softc 
+ /* return bus cachesize in 4B word units */
+-static void bus_read_cachesize(struct ath_softc *sc, int *csz)
++static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
+ {
+       u8 u8tmp;
+@@ -1338,7 +1338,7 @@ static int ath_init(u16 devid, struct at
+        * Cache line size is used to size and align various
+        * structures used to communicate with the hardware.
+        */
+-      bus_read_cachesize(sc, &csz);
++      ath_read_cachesize(sc, &csz);
+       /* XXX assert csz is non-zero */
+       sc->sc_cachelsz = csz << 2;     /* convert to bytes */
+@@ -2529,6 +2529,10 @@ ath_rf_name(u16 rf_version)
+       return "????";
+ }
++static struct ath_bus_ops ath_pci_bus_ops = {
++      .read_cachesize = ath_pci_read_cachesize,
++};
++
+ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ {
+       void __iomem *mem;
+@@ -2617,6 +2621,7 @@ static int ath_pci_probe(struct pci_dev 
+       sc->hw = hw;
+       sc->dev = &pdev->dev;
+       sc->mem = mem;
++      sc->bus_ops = &ath_pci_bus_ops;
+       if (ath_attach(id->device, sc) != 0) {
+               ret = -ENODEV;
diff --git a/package/mac80211/patches/404-ath9k-introduce-bus-specific-cleanup-routine.patch b/package/mac80211/patches/404-ath9k-introduce-bus-specific-cleanup-routine.patch
new file mode 100644 (file)
index 0000000..d1b2f3c
--- /dev/null
@@ -0,0 +1,90 @@
+From 4167fb37cceda6a5ebfbfc4431abc69a1857ce43 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Mon, 5 Jan 2009 10:59:29 +0100
+Subject: [PATCH 04/11] ath9k: introduce bus specific cleanup routine
+
+We have left only some PCI specific cleanup code. We have to convert
+them as well.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+ drivers/net/wireless/ath9k/core.h |    6 ++++++
+ drivers/net/wireless/ath9k/main.c |   30 ++++++++++++++++--------------
+ 2 files changed, 22 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/wireless/ath9k/core.h
++++ b/drivers/net/wireless/ath9k/core.h
+@@ -695,6 +695,7 @@ enum PROT_MODE {
+ struct ath_bus_ops {
+       void            (*read_cachesize)(struct ath_softc *sc, int *csz);
++      void            (*cleanup)(struct ath_softc *sc);
+ };
+ struct ath_softc {
+@@ -760,4 +761,9 @@ static inline void ath_read_cachesize(st
+       sc->bus_ops->read_cachesize(sc, csz);
+ }
++static inline void ath_bus_cleanup(struct ath_softc *sc)
++{
++      sc->bus_ops->cleanup(sc);
++}
++
+ #endif /* CORE_H */
+--- a/drivers/net/wireless/ath9k/main.c
++++ b/drivers/net/wireless/ath9k/main.c
+@@ -1267,13 +1267,7 @@ static int ath_start_rfkill_poll(struct 
+                       rfkill_free(sc->rf_kill.rfkill);
+                       /* Deinitialize the device */
+-                      ath_detach(sc);
+-                      if (to_pci_dev(sc->dev)->irq)
+-                              free_irq(to_pci_dev(sc->dev)->irq, sc);
+-                      pci_iounmap(to_pci_dev(sc->dev), sc->mem);
+-                      pci_release_region(to_pci_dev(sc->dev), 0);
+-                      pci_disable_device(to_pci_dev(sc->dev));
+-                      ieee80211_free_hw(sc->hw);
++                      ath_bus_cleanup(sc);
+                       return -EIO;
+               } else {
+                       sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+@@ -2529,8 +2523,22 @@ ath_rf_name(u16 rf_version)
+       return "????";
+ }
++static void ath_pci_cleanup(struct ath_softc *sc)
++{
++      struct pci_dev *pdev = to_pci_dev(sc->dev);
++
++      ath_detach(sc);
++      if (pdev->irq)
++              free_irq(pdev->irq, sc);
++      pci_iounmap(pdev, sc->mem);
++      pci_release_region(pdev, 0);
++      pci_disable_device(pdev);
++      ieee80211_free_hw(sc->hw);
++}
++
+ static struct ath_bus_ops ath_pci_bus_ops = {
+       .read_cachesize = ath_pci_read_cachesize,
++      .cleanup = ath_pci_cleanup,
+ };
+ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+@@ -2667,13 +2675,7 @@ static void ath_pci_remove(struct pci_de
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath_softc *sc = hw->priv;
+-      ath_detach(sc);
+-      if (pdev->irq)
+-              free_irq(pdev->irq, sc);
+-      pci_iounmap(pdev, sc->mem);
+-      pci_release_region(pdev, 0);
+-      pci_disable_device(pdev);
+-      ieee80211_free_hw(hw);
++      ath_pci_cleanup(sc);
+ }
+ #ifdef CONFIG_PM
diff --git a/package/mac80211/patches/405-ath9k-move-PCI-code-into-separate-file.patch b/package/mac80211/patches/405-ath9k-move-PCI-code-into-separate-file.patch
new file mode 100644 (file)
index 0000000..0cdf4da
--- /dev/null
@@ -0,0 +1,725 @@
+From d95e670cd1395ffd8410bed809b6d060f2183d6b Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Mon, 5 Jan 2009 11:01:09 +0100
+Subject: [PATCH 05/11] ath9k: move PCI code into separate file
+
+Now that we have converted all bus specific routines to replaceable, we
+can move the PCI specific codes into a separate file.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
+---
+ drivers/net/wireless/ath9k/Makefile |    1 +
+ drivers/net/wireless/ath9k/core.h   |   18 ++-
+ drivers/net/wireless/ath9k/main.c   |  299 +++--------------------------------
+ drivers/net/wireless/ath9k/pci.c    |  289 +++++++++++++++++++++++++++++++++
+ 4 files changed, 328 insertions(+), 279 deletions(-)
+
+--- a/drivers/net/wireless/ath9k/Makefile
++++ b/drivers/net/wireless/ath9k/Makefile
+@@ -11,6 +11,7 @@ ath9k-y +=   hw.o \
+               xmit.o \
+               rc.o
++ath9k-$(CONFIG_PCI) += pci.o
+ ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o
+ obj-$(CONFIG_ATH9K) += ath9k.o
+--- a/drivers/net/wireless/ath9k/core.h
++++ b/drivers/net/wireless/ath9k/core.h
+@@ -18,7 +18,7 @@
+ #define CORE_H
+ #include <linux/etherdevice.h>
+-#include <linux/pci.h>
++#include <linux/device.h>
+ #include <net/mac80211.h>
+ #include <linux/leds.h>
+ #include <linux/rfkill.h>
+@@ -766,4 +766,20 @@ static inline void ath_bus_cleanup(struc
+       sc->bus_ops->cleanup(sc);
+ }
++extern struct ieee80211_ops ath9k_ops;
++
++irqreturn_t ath_isr(int irq, void *dev);
++int ath_attach(u16 devid, struct ath_softc *sc);
++void ath_detach(struct ath_softc *sc);
++const char *ath_mac_bb_name(u32 mac_bb_version);
++const char *ath_rf_name(u16 rf_version);
++
++#ifdef CONFIG_PCI
++int ath_pci_init(void);
++void ath_pci_exit(void);
++#else
++static inline int ath_pci_init(void) { return 0; };
++static inline void ath_pci_exit(void) {};
++#endif
++
+ #endif /* CORE_H */
+--- a/drivers/net/wireless/ath9k/main.c
++++ b/drivers/net/wireless/ath9k/main.c
+@@ -28,38 +28,6 @@ MODULE_DESCRIPTION("Support for Atheros 
+ MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
+ MODULE_LICENSE("Dual BSD/GPL");
+-static struct pci_device_id ath_pci_id_table[] __devinitdata = {
+-      { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI   */
+-      { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
+-      { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
+-      { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
+-      { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
+-      { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
+-      { 0 }
+-};
+-
+-static void ath_detach(struct ath_softc *sc);
+-
+-/* return bus cachesize in 4B word units */
+-
+-static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
+-{
+-      u8 u8tmp;
+-
+-      pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE,
+-                           (u8 *)&u8tmp);
+-      *csz = (int)u8tmp;
+-
+-      /*
+-       * This check was put in to avoid "unplesant" consequences if
+-       * the bootrom has not fully initialized all PCI devices.
+-       * Sometimes the cache line size register is not set
+-       */
+-
+-      if (*csz == 0)
+-              *csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
+-}
+-
+ static void ath_cache_conf_rate(struct ath_softc *sc,
+                               struct ieee80211_conf *conf)
+ {
+@@ -497,7 +465,7 @@ static void ath9k_tasklet(unsigned long 
+       ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+ }
+-static irqreturn_t ath_isr(int irq, void *dev)
++irqreturn_t ath_isr(int irq, void *dev)
+ {
+       struct ath_softc *sc = dev;
+       struct ath_hal *ah = sc->sc_ah;
+@@ -1278,7 +1246,7 @@ static int ath_start_rfkill_poll(struct 
+ }
+ #endif /* CONFIG_RFKILL */
+-static void ath_detach(struct ath_softc *sc)
++void ath_detach(struct ath_softc *sc)
+ {
+       struct ieee80211_hw *hw = sc->hw;
+       int i = 0;
+@@ -1529,7 +1497,7 @@ bad:
+       return error;
+ }
+-static int ath_attach(u16 devid, struct ath_softc *sc)
++int ath_attach(u16 devid, struct ath_softc *sc)
+ {
+       struct ieee80211_hw *hw = sc->hw;
+       int error = 0;
+@@ -2448,7 +2416,7 @@ static int ath9k_ampdu_action(struct iee
+       return ret;
+ }
+-static struct ieee80211_ops ath9k_ops = {
++struct ieee80211_ops ath9k_ops = {
+       .tx                 = ath9k_tx,
+       .start              = ath9k_start,
+       .stop               = ath9k_stop,
+@@ -2492,7 +2460,7 @@ static struct {
+ /*
+  * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown.
+  */
+-static const char *
++const char *
+ ath_mac_bb_name(u32 mac_bb_version)
+ {
+       int i;
+@@ -2509,7 +2477,7 @@ ath_mac_bb_name(u32 mac_bb_version)
+ /*
+  * Return the RF name. "????" is returned if the RF is unknown.
+  */
+-static const char *
++const char *
+ ath_rf_name(u16 rf_version)
+ {
+       int i;
+@@ -2523,236 +2491,7 @@ ath_rf_name(u16 rf_version)
+       return "????";
+ }
+-static void ath_pci_cleanup(struct ath_softc *sc)
+-{
+-      struct pci_dev *pdev = to_pci_dev(sc->dev);
+-
+-      ath_detach(sc);
+-      if (pdev->irq)
+-              free_irq(pdev->irq, sc);
+-      pci_iounmap(pdev, sc->mem);
+-      pci_release_region(pdev, 0);
+-      pci_disable_device(pdev);
+-      ieee80211_free_hw(sc->hw);
+-}
+-
+-static struct ath_bus_ops ath_pci_bus_ops = {
+-      .read_cachesize = ath_pci_read_cachesize,
+-      .cleanup = ath_pci_cleanup,
+-};
+-
+-static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+-{
+-      void __iomem *mem;
+-      struct ath_softc *sc;
+-      struct ieee80211_hw *hw;
+-      u8 csz;
+-      u32 val;
+-      int ret = 0;
+-      struct ath_hal *ah;
+-
+-      if (pci_enable_device(pdev))
+-              return -EIO;
+-
+-      ret =  pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+-
+-      if (ret) {
+-              printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
+-              goto bad;
+-      }
+-
+-      ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+-
+-      if (ret) {
+-              printk(KERN_ERR "ath9k: 32-bit DMA consistent "
+-                      "DMA enable failed\n");
+-              goto bad;
+-      }
+-
+-      /*
+-       * Cache line size is used to size and align various
+-       * structures used to communicate with the hardware.
+-       */
+-      pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+-      if (csz == 0) {
+-              /*
+-               * Linux 2.4.18 (at least) writes the cache line size
+-               * register as a 16-bit wide register which is wrong.
+-               * We must have this setup properly for rx buffer
+-               * DMA to work so force a reasonable value here if it
+-               * comes up zero.
+-               */
+-              csz = L1_CACHE_BYTES / sizeof(u32);
+-              pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+-      }
+-      /*
+-       * The default setting of latency timer yields poor results,
+-       * set it to the value used by other systems. It may be worth
+-       * tweaking this setting more.
+-       */
+-      pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+-
+-      pci_set_master(pdev);
+-
+-      /*
+-       * Disable the RETRY_TIMEOUT register (0x41) to keep
+-       * PCI Tx retries from interfering with C3 CPU state.
+-       */
+-      pci_read_config_dword(pdev, 0x40, &val);
+-      if ((val & 0x0000ff00) != 0)
+-              pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+-
+-      ret = pci_request_region(pdev, 0, "ath9k");
+-      if (ret) {
+-              dev_err(&pdev->dev, "PCI memory region reserve error\n");
+-              ret = -ENODEV;
+-              goto bad;
+-      }
+-
+-      mem = pci_iomap(pdev, 0, 0);
+-      if (!mem) {
+-              printk(KERN_ERR "PCI memory map error\n") ;
+-              ret = -EIO;
+-              goto bad1;
+-      }
+-
+-      hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
+-      if (hw == NULL) {
+-              printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
+-              goto bad2;
+-      }
+-
+-      SET_IEEE80211_DEV(hw, &pdev->dev);
+-      pci_set_drvdata(pdev, hw);
+-
+-      sc = hw->priv;
+-      sc->hw = hw;
+-      sc->dev = &pdev->dev;
+-      sc->mem = mem;
+-      sc->bus_ops = &ath_pci_bus_ops;
+-
+-      if (ath_attach(id->device, sc) != 0) {
+-              ret = -ENODEV;
+-              goto bad3;
+-      }
+-
+-      /* setup interrupt service routine */
+-
+-      if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) {
+-              printk(KERN_ERR "%s: request_irq failed\n",
+-                      wiphy_name(hw->wiphy));
+-              ret = -EIO;
+-              goto bad4;
+-      }
+-
+-      ah = sc->sc_ah;
+-      printk(KERN_INFO
+-             "%s: Atheros AR%s MAC/BB Rev:%x "
+-             "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
+-             wiphy_name(hw->wiphy),
+-             ath_mac_bb_name(ah->ah_macVersion),
+-             ah->ah_macRev,
+-             ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
+-             ah->ah_phyRev,
+-             (unsigned long)mem, pdev->irq);
+-
+-      return 0;
+-bad4:
+-      ath_detach(sc);
+-bad3:
+-      ieee80211_free_hw(hw);
+-bad2:
+-      pci_iounmap(pdev, mem);
+-bad1:
+-      pci_release_region(pdev, 0);
+-bad:
+-      pci_disable_device(pdev);
+-      return ret;
+-}
+-
+-static void ath_pci_remove(struct pci_dev *pdev)
+-{
+-      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+-      struct ath_softc *sc = hw->priv;
+-
+-      ath_pci_cleanup(sc);
+-}
+-
+-#ifdef CONFIG_PM
+-
+-static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+-{
+-      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+-      struct ath_softc *sc = hw->priv;
+-
+-      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+-
+-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+-      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+-              cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+-#endif
+-
+-      pci_save_state(pdev);
+-      pci_disable_device(pdev);
+-      pci_set_power_state(pdev, 3);
+-
+-      return 0;
+-}
+-
+-static int ath_pci_resume(struct pci_dev *pdev)
+-{
+-      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+-      struct ath_softc *sc = hw->priv;
+-      u32 val;
+-      int err;
+-
+-      err = pci_enable_device(pdev);
+-      if (err)
+-              return err;
+-      pci_restore_state(pdev);
+-      /*
+-       * Suspend/Resume resets the PCI configuration space, so we have to
+-       * re-disable the RETRY_TIMEOUT register (0x41) to keep
+-       * PCI Tx retries from interfering with C3 CPU state
+-       */
+-      pci_read_config_dword(pdev, 0x40, &val);
+-      if ((val & 0x0000ff00) != 0)
+-              pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+-
+-      /* Enable LED */
+-      ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+-                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+-      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+-
+-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+-      /*
+-       * check the h/w rfkill state on resume
+-       * and start the rfkill poll timer
+-       */
+-      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+-              queue_delayed_work(sc->hw->workqueue,
+-                                 &sc->rf_kill.rfkill_poll, 0);
+-#endif
+-
+-      return 0;
+-}
+-
+-#endif /* CONFIG_PM */
+-
+-MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
+-
+-static struct pci_driver ath_pci_driver = {
+-      .name       = "ath9k",
+-      .id_table   = ath_pci_id_table,
+-      .probe      = ath_pci_probe,
+-      .remove     = ath_pci_remove,
+-#ifdef CONFIG_PM
+-      .suspend    = ath_pci_suspend,
+-      .resume     = ath_pci_resume,
+-#endif /* CONFIG_PM */
+-};
+-
+-static int __init init_ath_pci(void)
++static int __init ath9k_init(void)
+ {
+       int error;
+@@ -2764,26 +2503,30 @@ static int __init init_ath_pci(void)
+               printk(KERN_ERR
+                       "Unable to register rate control algorithm: %d\n",
+                       error);
+-              ath_rate_control_unregister();
+-              return error;
++              goto err_out;
+       }
+-      if (pci_register_driver(&ath_pci_driver) < 0) {
++      error = ath_pci_init();
++      if (error < 0) {
+               printk(KERN_ERR
+                       "ath_pci: No devices found, driver not installed.\n");
+-              ath_rate_control_unregister();
+-              pci_unregister_driver(&ath_pci_driver);
+-              return -ENODEV;
++              error = -ENODEV;
++              goto err_rate_unregister;
+       }
+       return 0;
++
++ err_rate_unregister:
++      ath_rate_control_unregister();
++ err_out:
++      return error;
+ }
+-module_init(init_ath_pci);
++module_init(ath9k_init);
+-static void __exit exit_ath_pci(void)
++static void __exit ath9k_exit(void)
+ {
++      ath_pci_exit();
+       ath_rate_control_unregister();
+-      pci_unregister_driver(&ath_pci_driver);
+       printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+ }
+-module_exit(exit_ath_pci);
++module_exit(ath9k_exit);
+--- /dev/null
++++ b/drivers/net/wireless/ath9k/pci.c
+@@ -0,0 +1,289 @@
++/*
++ * Copyright (c) 2008 Atheros Communications Inc.
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <linux/nl80211.h>
++#include <linux/pci.h>
++#include "core.h"
++#include "reg.h"
++#include "hw.h"
++
++static struct pci_device_id ath_pci_id_table[] __devinitdata = {
++      { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI   */
++      { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
++      { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
++      { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
++      { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
++      { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
++      { 0 }
++};
++
++/* return bus cachesize in 4B word units */
++static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
++{
++      u8 u8tmp;
++
++      pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE,
++                           (u8 *)&u8tmp);
++      *csz = (int)u8tmp;
++
++      /*
++       * This check was put in to avoid "unplesant" consequences if
++       * the bootrom has not fully initialized all PCI devices.
++       * Sometimes the cache line size register is not set
++       */
++
++      if (*csz == 0)
++              *csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
++}
++
++static void ath_pci_cleanup(struct ath_softc *sc)
++{
++      struct pci_dev *pdev = to_pci_dev(sc->dev);
++
++      ath_detach(sc);
++      if (pdev->irq)
++              free_irq(pdev->irq, sc);
++      pci_iounmap(pdev, sc->mem);
++      pci_release_region(pdev, 0);
++      pci_disable_device(pdev);
++      ieee80211_free_hw(sc->hw);
++}
++
++static struct ath_bus_ops ath_pci_bus_ops = {
++      .read_cachesize = ath_pci_read_cachesize,
++      .cleanup = ath_pci_cleanup,
++};
++
++static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++      void __iomem *mem;
++      struct ath_softc *sc;
++      struct ieee80211_hw *hw;
++      u8 csz;
++      u32 val;
++      int ret = 0;
++      struct ath_hal *ah;
++
++      if (pci_enable_device(pdev))
++              return -EIO;
++
++      ret =  pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++
++      if (ret) {
++              printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
++              goto bad;
++      }
++
++      ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
++
++      if (ret) {
++              printk(KERN_ERR "ath9k: 32-bit DMA consistent "
++                      "DMA enable failed\n");
++              goto bad;
++      }
++
++      /*
++       * Cache line size is used to size and align various
++       * structures used to communicate with the hardware.
++       */
++      pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
++      if (csz == 0) {
++              /*
++               * Linux 2.4.18 (at least) writes the cache line size
++               * register as a 16-bit wide register which is wrong.
++               * We must have this setup properly for rx buffer
++               * DMA to work so force a reasonable value here if it
++               * comes up zero.
++               */
++              csz = L1_CACHE_BYTES / sizeof(u32);
++              pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
++      }
++      /*
++       * The default setting of latency timer yields poor results,
++       * set it to the value used by other systems. It may be worth
++       * tweaking this setting more.
++       */
++      pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
++
++      pci_set_master(pdev);
++
++      /*
++       * Disable the RETRY_TIMEOUT register (0x41) to keep
++       * PCI Tx retries from interfering with C3 CPU state.
++       */
++      pci_read_config_dword(pdev, 0x40, &val);
++      if ((val & 0x0000ff00) != 0)
++              pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
++
++      ret = pci_request_region(pdev, 0, "ath9k");
++      if (ret) {
++              dev_err(&pdev->dev, "PCI memory region reserve error\n");
++              ret = -ENODEV;
++              goto bad;
++      }
++
++      mem = pci_iomap(pdev, 0, 0);
++      if (!mem) {
++              printk(KERN_ERR "PCI memory map error\n") ;
++              ret = -EIO;
++              goto bad1;
++      }
++
++      hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
++      if (hw == NULL) {
++              printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
++              goto bad2;
++      }
++
++      SET_IEEE80211_DEV(hw, &pdev->dev);
++      pci_set_drvdata(pdev, hw);
++
++      sc = hw->priv;
++      sc->hw = hw;
++      sc->dev = &pdev->dev;
++      sc->mem = mem;
++      sc->bus_ops = &ath_pci_bus_ops;
++
++      if (ath_attach(id->device, sc) != 0) {
++              ret = -ENODEV;
++              goto bad3;
++      }
++
++      /* setup interrupt service routine */
++
++      if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) {
++              printk(KERN_ERR "%s: request_irq failed\n",
++                      wiphy_name(hw->wiphy));
++              ret = -EIO;
++              goto bad4;
++      }
++
++      ah = sc->sc_ah;
++      printk(KERN_INFO
++             "%s: Atheros AR%s MAC/BB Rev:%x "
++             "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
++             wiphy_name(hw->wiphy),
++             ath_mac_bb_name(ah->ah_macVersion),
++             ah->ah_macRev,
++             ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
++             ah->ah_phyRev,
++             (unsigned long)mem, pdev->irq);
++
++      return 0;
++bad4:
++      ath_detach(sc);
++bad3:
++      ieee80211_free_hw(hw);
++bad2:
++      pci_iounmap(pdev, mem);
++bad1:
++      pci_release_region(pdev, 0);
++bad:
++      pci_disable_device(pdev);
++      return ret;
++}
++
++static void ath_pci_remove(struct pci_dev *pdev)
++{
++      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
++      struct ath_softc *sc = hw->priv;
++
++      ath_pci_cleanup(sc);
++}
++
++#ifdef CONFIG_PM
++
++static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
++{
++      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
++      struct ath_softc *sc = hw->priv;
++
++      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
++
++#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
++      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
++              cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
++#endif
++
++      pci_save_state(pdev);
++      pci_disable_device(pdev);
++      pci_set_power_state(pdev, 3);
++
++      return 0;
++}
++
++static int ath_pci_resume(struct pci_dev *pdev)
++{
++      struct ieee80211_hw *hw = pci_get_drvdata(pdev);
++      struct ath_softc *sc = hw->priv;
++      u32 val;
++      int err;
++
++      err = pci_enable_device(pdev);
++      if (err)
++              return err;
++      pci_restore_state(pdev);
++      /*
++       * Suspend/Resume resets the PCI configuration space, so we have to
++       * re-disable the RETRY_TIMEOUT register (0x41) to keep
++       * PCI Tx retries from interfering with C3 CPU state
++       */
++      pci_read_config_dword(pdev, 0x40, &val);
++      if ((val & 0x0000ff00) != 0)
++              pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
++
++      /* Enable LED */
++      ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
++                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++      ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
++
++#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
++      /*
++       * check the h/w rfkill state on resume
++       * and start the rfkill poll timer
++       */
++      if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
++              queue_delayed_work(sc->hw->workqueue,
++                                 &sc->rf_kill.rfkill_poll, 0);
++#endif
++
++      return 0;
++}
++
++#endif /* CONFIG_PM */
++
++MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
++
++static struct pci_driver ath_pci_driver = {
++      .name       = "ath9k",
++      .id_table   = ath_pci_id_table,
++      .probe      = ath_pci_probe,
++      .remove     = ath_pci_remove,
++#ifdef CONFIG_PM
++      .suspend    = ath_pci_suspend,
++      .resume     = ath_pci_resume,
++#endif /* CONFIG_PM */
++};
++
++int __init ath_pci_init(void)
++{
++      return pci_register_driver(&ath_pci_driver);
++}
++
++void ath_pci_exit(void)
++{
++      pci_unregister_driver(&ath_pci_driver);
++}