aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/p54/p54pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/p54/p54pci.c')
-rw-r--r--drivers/net/wireless/p54/p54pci.c161
1 files changed, 90 insertions, 71 deletions
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index b1f51a21579..d411de40905 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -13,7 +13,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/firmware.h>
@@ -488,7 +487,59 @@ static int p54p_open(struct ieee80211_hw *dev)
return 0;
}
-static int __devinit p54p_probe(struct pci_dev *pdev,
+static void p54p_firmware_step2(const struct firmware *fw,
+ void *context)
+{
+ struct p54p_priv *priv = context;
+ struct ieee80211_hw *dev = priv->common.hw;
+ struct pci_dev *pdev = priv->pdev;
+ int err;
+
+ if (!fw) {
+ dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
+ err = -ENOENT;
+ goto out;
+ }
+
+ priv->firmware = fw;
+
+ err = p54p_open(dev);
+ if (err)
+ goto out;
+ err = p54_read_eeprom(dev);
+ p54p_stop(dev);
+ if (err)
+ goto out;
+
+ err = p54_register_common(dev, &pdev->dev);
+ if (err)
+ goto out;
+
+out:
+
+ complete(&priv->fw_loaded);
+
+ if (err) {
+ struct device *parent = pdev->dev.parent;
+
+ if (parent)
+ device_lock(parent);
+
+ /*
+ * This will indirectly result in a call to p54p_remove.
+ * Hence, we don't need to bother with freeing any
+ * allocated ressources at all.
+ */
+ device_release_driver(&pdev->dev);
+
+ if (parent)
+ device_unlock(parent);
+ }
+
+ pci_dev_put(pdev);
+}
+
+static int p54p_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct p54p_priv *priv;
@@ -496,6 +547,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
unsigned long mem_addr, mem_len;
int err;
+ pci_dev_get(pdev);
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Cannot enable new PCI device\n");
@@ -506,6 +558,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
mem_len = pci_resource_len(pdev, 0);
if (mem_len < sizeof(struct p54p_csr)) {
dev_err(&pdev->dev, "Too short PCI resources\n");
+ err = -ENODEV;
goto err_disable_dev;
}
@@ -515,8 +568,10 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
goto err_disable_dev;
}
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err) {
dev_err(&pdev->dev, "No suitable DMA available\n");
goto err_free_reg;
}
@@ -537,6 +592,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
priv = dev->priv;
priv->pdev = pdev;
+ init_completion(&priv->fw_loaded);
SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);
@@ -561,32 +617,12 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
- err = request_firmware(&priv->firmware, "isl3886pci",
- &priv->pdev->dev);
- if (err) {
- dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
- err = request_firmware(&priv->firmware, "isl3886",
- &priv->pdev->dev);
- if (err)
- goto err_free_common;
- }
-
- err = p54p_open(dev);
- if (err)
- goto err_free_common;
- err = p54_read_eeprom(dev);
- p54p_stop(dev);
- if (err)
- goto err_free_common;
-
- err = p54_register_common(dev, &pdev->dev);
- if (err)
- goto err_free_common;
-
- return 0;
+ err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
+ &priv->pdev->dev, GFP_KERNEL,
+ priv, p54p_firmware_step2);
+ if (!err)
+ return 0;
- err_free_common:
- release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -594,17 +630,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
iounmap(priv->map);
err_free_dev:
- pci_set_drvdata(pdev, NULL);
p54_free_common(dev);
err_free_reg:
pci_release_regions(pdev);
err_disable_dev:
pci_disable_device(pdev);
+ pci_dev_put(pdev);
return err;
}
-static void __devexit p54p_remove(struct pci_dev *pdev)
+static void p54p_remove(struct pci_dev *pdev)
{
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct p54p_priv *priv;
@@ -612,8 +648,9 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev)
return;
- p54_unregister_common(dev);
priv = dev->priv;
+ wait_for_completion(&priv->fw_loaded);
+ p54_unregister_common(dev);
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -623,59 +660,41 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
p54_free_common(dev);
}
-#ifdef CONFIG_PM
-static int p54p_suspend(struct pci_dev *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int p54p_suspend(struct device *device)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct p54p_priv *priv = dev->priv;
-
- if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
- ieee80211_stop_queues(dev);
- p54p_stop(dev);
- }
+ struct pci_dev *pdev = to_pci_dev(device);
pci_save_state(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ pci_set_power_state(pdev, PCI_D3hot);
+ pci_disable_device(pdev);
return 0;
}
-static int p54p_resume(struct pci_dev *pdev)
+static int p54p_resume(struct device *device)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct p54p_priv *priv = dev->priv;
+ struct pci_dev *pdev = to_pci_dev(device);
+ int err;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
+ err = pci_reenable_device(pdev);
+ if (err)
+ return err;
+ return pci_set_power_state(pdev, PCI_D0);
+}
- if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) {
- p54p_open(dev);
- ieee80211_wake_queues(dev);
- }
+static SIMPLE_DEV_PM_OPS(p54pci_pm_ops, p54p_suspend, p54p_resume);
- return 0;
-}
-#endif /* CONFIG_PM */
+#define P54P_PM_OPS (&p54pci_pm_ops)
+#else
+#define P54P_PM_OPS (NULL)
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver p54p_driver = {
.name = "p54pci",
.id_table = p54p_table,
.probe = p54p_probe,
- .remove = __devexit_p(p54p_remove),
-#ifdef CONFIG_PM
- .suspend = p54p_suspend,
- .resume = p54p_resume,
-#endif /* CONFIG_PM */
+ .remove = p54p_remove,
+ .driver.pm = P54P_PM_OPS,
};
-static int __init p54p_init(void)
-{
- return pci_register_driver(&p54p_driver);
-}
-
-static void __exit p54p_exit(void)
-{
- pci_unregister_driver(&p54p_driver);
-}
-
-module_init(p54p_init);
-module_exit(p54p_exit);
+module_pci_driver(p54p_driver);