From: Pavel Roskin Copy PCI suspend/resume functions from orinoco_pci.c. Signed-off-by: Pavel Roskin Signed-off-by: Andrew Morton --- drivers/net/wireless/orinoco_nortel.c | 87 ++++++++++++++++++++++-- drivers/net/wireless/orinoco_plx.c | 79 +++++++++++++++++++++ drivers/net/wireless/orinoco_tmd.c | 79 +++++++++++++++++++++ 3 files changed, 241 insertions(+), 4 deletions(-) diff -puN drivers/net/wireless/orinoco_nortel.c~orinoco-support-pci-suspend-resume-for-nortel-plx-and-tmd-adaptors drivers/net/wireless/orinoco_nortel.c --- 25/drivers/net/wireless/orinoco_nortel.c~orinoco-support-pci-suspend-resume-for-nortel-plx-and-tmd-adaptors Fri Apr 7 15:37:44 2006 +++ 25-akpm/drivers/net/wireless/orinoco_nortel.c Fri Apr 7 15:37:44 2006 @@ -263,6 +263,83 @@ static void __devexit nortel_pci_remove_ pci_disable_device(pdev); } +static int orinoco_nortel_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_lock(priv, &flags); + if (err) { + printk(KERN_ERR "%s: cannot lock hardware for suspend\n", + dev->name); + return err; + } + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: error %d bringing interface down " + "for suspend\n", dev->name, err); + + netif_device_detach(dev); + + priv->hw_unavailable++; + + orinoco_unlock(priv, &flags); + + free_irq(pdev->irq, dev); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int orinoco_nortel_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + pci_set_power_state(pdev, 0); + pci_enable_device(pdev); + pci_restore_state(pdev); + + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); + if (err) { + printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", + dev->name); + pci_disable_device(pdev); + return -EBUSY; + } + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: error %d re-initializing firmware " + "on resume\n", dev->name, err); + return err; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + + priv->hw_unavailable--; + + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card on resume\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} static struct pci_device_id nortel_pci_id_table[] = { /* Nortel emobility PCI */ @@ -275,10 +352,12 @@ static struct pci_device_id nortel_pci_i MODULE_DEVICE_TABLE(pci, nortel_pci_id_table); static struct pci_driver nortel_pci_driver = { - .name = DRIVER_NAME, - .id_table = nortel_pci_id_table, - .probe = nortel_pci_init_one, - .remove = __devexit_p(nortel_pci_remove_one), + .name = DRIVER_NAME, + .id_table = nortel_pci_id_table, + .probe = nortel_pci_init_one, + .remove = __devexit_p(nortel_pci_remove_one), + .suspend = orinoco_nortel_suspend, + .resume = orinoco_nortel_resume, }; static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION diff -puN drivers/net/wireless/orinoco_plx.c~orinoco-support-pci-suspend-resume-for-nortel-plx-and-tmd-adaptors drivers/net/wireless/orinoco_plx.c --- 25/drivers/net/wireless/orinoco_plx.c~orinoco-support-pci-suspend-resume-for-nortel-plx-and-tmd-adaptors Fri Apr 7 15:37:44 2006 +++ 25-akpm/drivers/net/wireless/orinoco_plx.c Fri Apr 7 15:37:44 2006 @@ -343,6 +343,83 @@ static void __devexit orinoco_plx_remove pci_disable_device(pdev); } +static int orinoco_plx_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_lock(priv, &flags); + if (err) { + printk(KERN_ERR "%s: cannot lock hardware for suspend\n", + dev->name); + return err; + } + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: error %d bringing interface down " + "for suspend\n", dev->name, err); + + netif_device_detach(dev); + + priv->hw_unavailable++; + + orinoco_unlock(priv, &flags); + + free_irq(pdev->irq, dev); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int orinoco_plx_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + pci_set_power_state(pdev, 0); + pci_enable_device(pdev); + pci_restore_state(pdev); + + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); + if (err) { + printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", + dev->name); + pci_disable_device(pdev); + return -EBUSY; + } + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: error %d re-initializing firmware " + "on resume\n", dev->name, err); + return err; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + + priv->hw_unavailable--; + + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card on resume\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} static struct pci_device_id orinoco_plx_pci_id_table[] = { {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ @@ -369,6 +446,8 @@ static struct pci_driver orinoco_plx_dri .id_table = orinoco_plx_pci_id_table, .probe = orinoco_plx_init_one, .remove = __devexit_p(orinoco_plx_remove_one), + .suspend = orinoco_plx_suspend, + .resume = orinoco_plx_resume, }; static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION diff -puN drivers/net/wireless/orinoco_tmd.c~orinoco-support-pci-suspend-resume-for-nortel-plx-and-tmd-adaptors drivers/net/wireless/orinoco_tmd.c --- 25/drivers/net/wireless/orinoco_tmd.c~orinoco-support-pci-suspend-resume-for-nortel-plx-and-tmd-adaptors Fri Apr 7 15:37:44 2006 +++ 25-akpm/drivers/net/wireless/orinoco_tmd.c Fri Apr 7 15:37:44 2006 @@ -215,6 +215,83 @@ static void __devexit orinoco_tmd_remove pci_disable_device(pdev); } +static int orinoco_tmd_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_lock(priv, &flags); + if (err) { + printk(KERN_ERR "%s: cannot lock hardware for suspend\n", + dev->name); + return err; + } + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: error %d bringing interface down " + "for suspend\n", dev->name, err); + + netif_device_detach(dev); + + priv->hw_unavailable++; + + orinoco_unlock(priv, &flags); + + free_irq(pdev->irq, dev); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int orinoco_tmd_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + pci_set_power_state(pdev, 0); + pci_enable_device(pdev); + pci_restore_state(pdev); + + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); + if (err) { + printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", + dev->name); + pci_disable_device(pdev); + return -EBUSY; + } + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: error %d re-initializing firmware " + "on resume\n", dev->name, err); + return err; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + + priv->hw_unavailable--; + + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card on resume\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} static struct pci_device_id orinoco_tmd_pci_id_table[] = { {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ @@ -228,6 +305,8 @@ static struct pci_driver orinoco_tmd_dri .id_table = orinoco_tmd_pci_id_table, .probe = orinoco_tmd_init_one, .remove = __devexit_p(orinoco_tmd_remove_one), + .suspend = orinoco_tmd_suspend, + .resume = orinoco_tmd_resume, }; static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION _