[IRDA]: nsc-ircc: PM update
This patch brings the nsc-ircc code to a more up to date power management scheme, following the current device model. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Rudolf Marek <r.marek@sh.cvut.cz> Signed-off-by: Samuel Ortiz <samuel.ortiz@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ec4f32d550
commit
3b99b93bab
2 changed files with 105 additions and 42 deletions
|
@ -55,14 +55,12 @@
|
|||
#include <linux/rtnetlink.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_legacy.h>
|
||||
|
||||
#include <net/irda/wrapper.h>
|
||||
#include <net/irda/irda.h>
|
||||
#include <net/irda/irda_device.h>
|
||||
|
@ -74,6 +72,19 @@
|
|||
|
||||
static char *driver_name = "nsc-ircc";
|
||||
|
||||
/* Power Management */
|
||||
#define NSC_IRCC_DRIVER_NAME "nsc-ircc"
|
||||
static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state);
|
||||
static int nsc_ircc_resume(struct platform_device *dev);
|
||||
|
||||
static struct platform_driver nsc_ircc_driver = {
|
||||
.suspend = nsc_ircc_suspend,
|
||||
.resume = nsc_ircc_resume,
|
||||
.driver = {
|
||||
.name = NSC_IRCC_DRIVER_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
/* Module parameters */
|
||||
static int qos_mtt_bits = 0x07; /* 1 ms or more */
|
||||
static int dongle_id;
|
||||
|
@ -164,7 +175,6 @@ static int nsc_ircc_net_open(struct net_device *dev);
|
|||
static int nsc_ircc_net_close(struct net_device *dev);
|
||||
static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||
static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
|
||||
static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
|
||||
|
||||
/* Globals */
|
||||
static int pnp_registered;
|
||||
|
@ -186,6 +196,12 @@ static int __init nsc_ircc_init(void)
|
|||
int reg;
|
||||
int i = 0;
|
||||
|
||||
ret = platform_driver_register(&nsc_ircc_driver);
|
||||
if (ret) {
|
||||
IRDA_ERROR("%s, Can't register driver!\n", driver_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Register with PnP subsystem to detect disable ports */
|
||||
ret = pnp_register_driver(&nsc_ircc_pnp_driver);
|
||||
|
||||
|
@ -274,6 +290,7 @@ static int __init nsc_ircc_init(void)
|
|||
}
|
||||
|
||||
if (ret) {
|
||||
platform_driver_unregister(&nsc_ircc_driver);
|
||||
pnp_unregister_driver(&nsc_ircc_pnp_driver);
|
||||
pnp_registered = 0;
|
||||
}
|
||||
|
@ -291,13 +308,13 @@ static void __exit nsc_ircc_cleanup(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
pm_unregister_all(nsc_ircc_pmproc);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
|
||||
if (dev_self[i])
|
||||
nsc_ircc_close(dev_self[i]);
|
||||
}
|
||||
|
||||
platform_driver_unregister(&nsc_ircc_driver);
|
||||
|
||||
if (pnp_registered)
|
||||
pnp_unregister_driver(&nsc_ircc_pnp_driver);
|
||||
|
||||
|
@ -314,7 +331,6 @@ static int __init nsc_ircc_open(chipio_t *info)
|
|||
{
|
||||
struct net_device *dev;
|
||||
struct nsc_ircc_cb *self;
|
||||
struct pm_dev *pmdev;
|
||||
void *ret;
|
||||
int err, chip_index;
|
||||
|
||||
|
@ -444,11 +460,18 @@ static int __init nsc_ircc_open(chipio_t *info)
|
|||
self->io.dongle_id = dongle_id;
|
||||
nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
|
||||
|
||||
pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc);
|
||||
if (pmdev)
|
||||
pmdev->data = self;
|
||||
self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME,
|
||||
self->index, NULL, 0);
|
||||
if (IS_ERR(self->pldev)) {
|
||||
err = PTR_ERR(self->pldev);
|
||||
goto out5;
|
||||
}
|
||||
platform_set_drvdata(self->pldev, self);
|
||||
|
||||
return chip_index;
|
||||
|
||||
out5:
|
||||
unregister_netdev(dev);
|
||||
out4:
|
||||
dma_free_coherent(NULL, self->tx_buff.truesize,
|
||||
self->tx_buff.head, self->tx_buff_dma);
|
||||
|
@ -479,6 +502,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self)
|
|||
|
||||
iobase = self->io.fir_base;
|
||||
|
||||
platform_device_unregister(self->pldev);
|
||||
|
||||
/* Remove netdevice */
|
||||
unregister_netdev(self->netdev);
|
||||
|
||||
|
@ -2278,47 +2303,85 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
|
|||
return &self->stats;
|
||||
}
|
||||
|
||||
static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
|
||||
static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
IRDA_MESSAGE("%s, Suspending\n", driver_name);
|
||||
struct nsc_ircc_cb *self = platform_get_drvdata(dev);
|
||||
int bank;
|
||||
unsigned long flags;
|
||||
int iobase = self->io.fir_base;
|
||||
|
||||
if (self->io.suspended)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
nsc_ircc_net_close(self->netdev);
|
||||
IRDA_DEBUG(1, "%s, Suspending\n", driver_name);
|
||||
|
||||
rtnl_lock();
|
||||
if (netif_running(self->netdev)) {
|
||||
netif_device_detach(self->netdev);
|
||||
spin_lock_irqsave(&self->lock, flags);
|
||||
/* Save current bank */
|
||||
bank = inb(iobase+BSR);
|
||||
|
||||
/* Disable interrupts */
|
||||
switch_bank(iobase, BANK0);
|
||||
outb(0, iobase+IER);
|
||||
|
||||
/* Restore bank register */
|
||||
outb(bank, iobase+BSR);
|
||||
|
||||
spin_unlock_irqrestore(&self->lock, flags);
|
||||
free_irq(self->io.irq, self->netdev);
|
||||
disable_dma(self->io.dma);
|
||||
}
|
||||
self->io.suspended = 1;
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
|
||||
{
|
||||
if (!self->io.suspended)
|
||||
return;
|
||||
|
||||
nsc_ircc_setup(&self->io);
|
||||
nsc_ircc_net_open(self->netdev);
|
||||
|
||||
IRDA_MESSAGE("%s, Waking up\n", driver_name);
|
||||
|
||||
self->io.suspended = 0;
|
||||
}
|
||||
|
||||
static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
|
||||
{
|
||||
struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data;
|
||||
if (self) {
|
||||
switch (rqst) {
|
||||
case PM_SUSPEND:
|
||||
nsc_ircc_suspend(self);
|
||||
break;
|
||||
case PM_RESUME:
|
||||
nsc_ircc_wakeup(self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nsc_ircc_resume(struct platform_device *dev)
|
||||
{
|
||||
struct nsc_ircc_cb *self = platform_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
if (!self->io.suspended)
|
||||
return 0;
|
||||
|
||||
IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
|
||||
|
||||
rtnl_lock();
|
||||
nsc_ircc_setup(&self->io);
|
||||
nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id);
|
||||
|
||||
if (netif_running(self->netdev)) {
|
||||
if (request_irq(self->io.irq, nsc_ircc_interrupt, 0,
|
||||
self->netdev->name, self->netdev)) {
|
||||
IRDA_WARNING("%s, unable to allocate irq=%d\n",
|
||||
driver_name, self->io.irq);
|
||||
|
||||
/*
|
||||
* Don't fail resume process, just kill this
|
||||
* network interface
|
||||
*/
|
||||
unregister_netdevice(self->netdev);
|
||||
} else {
|
||||
spin_lock_irqsave(&self->lock, flags);
|
||||
nsc_ircc_change_speed(self, self->io.speed);
|
||||
spin_unlock_irqrestore(&self->lock, flags);
|
||||
netif_device_attach(self->netdev);
|
||||
}
|
||||
|
||||
} else {
|
||||
spin_lock_irqsave(&self->lock, flags);
|
||||
nsc_ircc_change_speed(self, 9600);
|
||||
spin_unlock_irqrestore(&self->lock, flags);
|
||||
}
|
||||
self->io.suspended = 0;
|
||||
rtnl_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
|
||||
MODULE_DESCRIPTION("NSC IrDA Device Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -269,7 +269,7 @@ struct nsc_ircc_cb {
|
|||
__u32 new_speed;
|
||||
int index; /* Instance index */
|
||||
|
||||
struct pm_dev *dev;
|
||||
struct platform_device *pldev;
|
||||
};
|
||||
|
||||
static inline void switch_bank(int iobase, int bank)
|
||||
|
|
Loading…
Reference in a new issue