BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
}
-int iwl_probe(struct pci_dev *pdev, struct iwl_cfg *cfg)
+int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops,
+ struct iwl_cfg *cfg)
{
int err = 0;
struct iwl_priv *priv;
/************************
* 1. Allocating HW data
************************/
+ /* TODO: remove this nasty hack when PCI encapsulation is done
+ * assumes that struct pci_dev * is at the very beginning of whatever
+ * is pointed by bus_specific */
+ unsigned long *ppdev = bus_specific;
+ struct pci_dev *pdev = (struct pci_dev *) *ppdev;
hw = iwl_alloc_all(cfg);
if (!hw) {
err = -ENOMEM;
goto out; }
priv = hw->priv;
+
+ priv->bus.priv = priv;
+ priv->bus.bus_specific = bus_specific;
+ priv->bus.ops = bus_ops;
+ priv->bus.ops->set_drv_data(&priv->bus, priv);
+
/* At this point both hw and priv are allocated. */
SET_IEEE80211_DEV(hw, &pdev->dev);
if (err)
goto out_pci_disable_device;
- pci_set_drvdata(pdev, priv);
-
-
/***********************
* 3. Read REV register
***********************/
out_iounmap:
pci_iounmap(pdev, priv->hw_base);
out_pci_release_regions:
- pci_set_drvdata(pdev, NULL);
+ priv->bus.ops->set_drv_data(&priv->bus, NULL);
pci_release_regions(pdev);
out_pci_disable_device:
pci_disable_device(pdev);
return err;
}
-void __devexit iwl_remove(struct pci_dev *pdev)
+void __devexit iwl_remove(struct iwl_priv * priv)
{
- struct iwl_priv *priv = pci_get_drvdata(pdev);
+ struct pci_dev *pdev = priv->pci_dev;
unsigned long flags;
- if (!priv)
- return;
-
wait_for_completion(&priv->_agn.firmware_loading_complete);
IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
pci_iounmap(pdev, priv->hw_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
+ priv->bus.ops->set_drv_data(&priv->bus, NULL);
iwl_uninit_drv(priv);
}
#endif
-int iwl_probe(struct pci_dev *pdev, struct iwl_cfg *cfg);
-void iwl_remove(struct pci_dev *pdev);
+int iwl_probe(void *bus_specific, struct iwl_bus_ops *bus_ops,
+ struct iwl_cfg *cfg);
+void __devexit iwl_remove(struct iwl_priv * priv);
#endif /* __iwl_agn_h__ */
bool trace_enabled;
};
#endif
+
+struct iwl_bus;
+
+/**
+ * struct iwl_bus_ops - bus specific operations
+ * @set_drv_data: set the priv pointer to the bus layer
+ */
+struct iwl_bus_ops {
+ void (*set_drv_data)(struct iwl_bus *bus, void *priv);
+};
+
+struct iwl_bus {
+ /* pointer to bus specific struct */
+ void *bus_specific;
+
+ /* Common data to all buses */
+ struct iwl_priv *priv; /* driver's context */
+ struct iwl_bus_ops *ops;
+};
+
struct iwl_priv {
/* ieee device used by generic ieee processing code */
spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex;
+ /* TODO: remove this after PCI abstraction is done */
/* basic pci-network driver stuff */
struct pci_dev *pci_dev;
/* pci hardware address support */
void __iomem *hw_base;
+ struct iwl_bus bus; /* bus specific data */
+
/* microcode/device supports multiple contexts */
u8 valid_contexts;
#include "iwl-agn.h"
#include "iwl-core.h"
+struct iwl_pci_bus {
+ /* basic pci-network driver stuff */
+ struct pci_dev *pci_dev;
+
+ /* pci hardware address support */
+ void __iomem *hw_base;
+};
+
+#define IWL_BUS_GET_PCI_BUS(_iwl_bus) \
+ ((struct iwl_pci_bus *) ((_iwl_bus)->bus_specific))
+
+#define IWL_BUS_GET_PCI_DEV(_iwl_bus) \
+ ((IWL_BUS_GET_PCI_BUS(_iwl_bus))->pci_dev)
+
+static void iwl_pci_set_drv_data(struct iwl_bus *bus, void *drv_priv)
+{
+ pci_set_drvdata(IWL_BUS_GET_PCI_DEV(bus), drv_priv);
+}
+
+static struct iwl_bus_ops pci_ops = {
+ .set_drv_data = iwl_pci_set_drv_data,
+};
+
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
.vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \
.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
-
- return iwl_probe(pdev, cfg);
+ struct iwl_pci_bus *bus;
+ int err;
+
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus) {
+ pr_err("Couldn't allocate iwl_pci_bus");
+ err = -ENOMEM;
+ goto out_no_pci;
+ }
+
+ bus->pci_dev = pdev;
+
+ err = iwl_probe((void *) bus, &pci_ops, cfg);
+ if (err)
+ goto out_no_pci;
+ return 0;
+
+out_no_pci:
+ kfree(bus);
+ return err;
}
static void __devexit iwl_pci_remove(struct pci_dev *pdev)
{
- iwl_remove(pdev);
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+ /* This can happen if probe failed */
+ if (unlikely(!priv))
+ return;
+
+ iwl_remove(priv);
+ kfree(IWL_BUS_GET_PCI_BUS(&priv->bus));
}
#ifdef CONFIG_PM