return 0;
}
+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 __devinit p54p_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
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");
priv = dev->priv;
priv->pdev = pdev;
+ init_completion(&priv->fw_loaded);
SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);
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);
pci_release_regions(pdev);
err_disable_dev:
pci_disable_device(pdev);
+ pci_dev_put(pdev);
return err;
}
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);