diff options
author | Dmitry Torokhov <dtor@mail.ru> | 2006-03-20 21:59:05 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-03-20 21:59:05 -0500 |
commit | 3b99b93baba4cbf4fd3d206e65e81a070b21b560 (patch) | |
tree | 7aa59a126614296b561b4d27bd92730a65fa188c /drivers/net/irda/nsc-ircc.c | |
parent | ec4f32d550b94b4b66c9c7689bc09c6b32c8e82e (diff) |
[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>
Diffstat (limited to 'drivers/net/irda/nsc-ircc.c')
-rw-r--r-- | drivers/net/irda/nsc-ircc.c | 131 |
1 files changed, 97 insertions, 34 deletions
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 282414ba22f0..81a4ccf54c57 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c | |||
@@ -55,14 +55,12 @@ | |||
55 | #include <linux/rtnetlink.h> | 55 | #include <linux/rtnetlink.h> |
56 | #include <linux/dma-mapping.h> | 56 | #include <linux/dma-mapping.h> |
57 | #include <linux/pnp.h> | 57 | #include <linux/pnp.h> |
58 | #include <linux/platform_device.h> | ||
58 | 59 | ||
59 | #include <asm/io.h> | 60 | #include <asm/io.h> |
60 | #include <asm/dma.h> | 61 | #include <asm/dma.h> |
61 | #include <asm/byteorder.h> | 62 | #include <asm/byteorder.h> |
62 | 63 | ||
63 | #include <linux/pm.h> | ||
64 | #include <linux/pm_legacy.h> | ||
65 | |||
66 | #include <net/irda/wrapper.h> | 64 | #include <net/irda/wrapper.h> |
67 | #include <net/irda/irda.h> | 65 | #include <net/irda/irda.h> |
68 | #include <net/irda/irda_device.h> | 66 | #include <net/irda/irda_device.h> |
@@ -74,6 +72,19 @@ | |||
74 | 72 | ||
75 | static char *driver_name = "nsc-ircc"; | 73 | static char *driver_name = "nsc-ircc"; |
76 | 74 | ||
75 | /* Power Management */ | ||
76 | #define NSC_IRCC_DRIVER_NAME "nsc-ircc" | ||
77 | static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state); | ||
78 | static int nsc_ircc_resume(struct platform_device *dev); | ||
79 | |||
80 | static struct platform_driver nsc_ircc_driver = { | ||
81 | .suspend = nsc_ircc_suspend, | ||
82 | .resume = nsc_ircc_resume, | ||
83 | .driver = { | ||
84 | .name = NSC_IRCC_DRIVER_NAME, | ||
85 | }, | ||
86 | }; | ||
87 | |||
77 | /* Module parameters */ | 88 | /* Module parameters */ |
78 | static int qos_mtt_bits = 0x07; /* 1 ms or more */ | 89 | static int qos_mtt_bits = 0x07; /* 1 ms or more */ |
79 | static int dongle_id; | 90 | static int dongle_id; |
@@ -164,7 +175,6 @@ static int nsc_ircc_net_open(struct net_device *dev); | |||
164 | static int nsc_ircc_net_close(struct net_device *dev); | 175 | static int nsc_ircc_net_close(struct net_device *dev); |
165 | static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 176 | static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
166 | static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); | 177 | static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); |
167 | static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); | ||
168 | 178 | ||
169 | /* Globals */ | 179 | /* Globals */ |
170 | static int pnp_registered; | 180 | static int pnp_registered; |
@@ -186,6 +196,12 @@ static int __init nsc_ircc_init(void) | |||
186 | int reg; | 196 | int reg; |
187 | int i = 0; | 197 | int i = 0; |
188 | 198 | ||
199 | ret = platform_driver_register(&nsc_ircc_driver); | ||
200 | if (ret) { | ||
201 | IRDA_ERROR("%s, Can't register driver!\n", driver_name); | ||
202 | return ret; | ||
203 | } | ||
204 | |||
189 | /* Register with PnP subsystem to detect disable ports */ | 205 | /* Register with PnP subsystem to detect disable ports */ |
190 | ret = pnp_register_driver(&nsc_ircc_pnp_driver); | 206 | ret = pnp_register_driver(&nsc_ircc_pnp_driver); |
191 | 207 | ||
@@ -274,6 +290,7 @@ static int __init nsc_ircc_init(void) | |||
274 | } | 290 | } |
275 | 291 | ||
276 | if (ret) { | 292 | if (ret) { |
293 | platform_driver_unregister(&nsc_ircc_driver); | ||
277 | pnp_unregister_driver(&nsc_ircc_pnp_driver); | 294 | pnp_unregister_driver(&nsc_ircc_pnp_driver); |
278 | pnp_registered = 0; | 295 | pnp_registered = 0; |
279 | } | 296 | } |
@@ -291,13 +308,13 @@ static void __exit nsc_ircc_cleanup(void) | |||
291 | { | 308 | { |
292 | int i; | 309 | int i; |
293 | 310 | ||
294 | pm_unregister_all(nsc_ircc_pmproc); | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(dev_self); i++) { | 311 | for (i = 0; i < ARRAY_SIZE(dev_self); i++) { |
297 | if (dev_self[i]) | 312 | if (dev_self[i]) |
298 | nsc_ircc_close(dev_self[i]); | 313 | nsc_ircc_close(dev_self[i]); |
299 | } | 314 | } |
300 | 315 | ||
316 | platform_driver_unregister(&nsc_ircc_driver); | ||
317 | |||
301 | if (pnp_registered) | 318 | if (pnp_registered) |
302 | pnp_unregister_driver(&nsc_ircc_pnp_driver); | 319 | pnp_unregister_driver(&nsc_ircc_pnp_driver); |
303 | 320 | ||
@@ -314,7 +331,6 @@ static int __init nsc_ircc_open(chipio_t *info) | |||
314 | { | 331 | { |
315 | struct net_device *dev; | 332 | struct net_device *dev; |
316 | struct nsc_ircc_cb *self; | 333 | struct nsc_ircc_cb *self; |
317 | struct pm_dev *pmdev; | ||
318 | void *ret; | 334 | void *ret; |
319 | int err, chip_index; | 335 | int err, chip_index; |
320 | 336 | ||
@@ -444,11 +460,18 @@ static int __init nsc_ircc_open(chipio_t *info) | |||
444 | self->io.dongle_id = dongle_id; | 460 | self->io.dongle_id = dongle_id; |
445 | nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); | 461 | nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); |
446 | 462 | ||
447 | pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc); | 463 | self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME, |
448 | if (pmdev) | 464 | self->index, NULL, 0); |
449 | pmdev->data = self; | 465 | if (IS_ERR(self->pldev)) { |
466 | err = PTR_ERR(self->pldev); | ||
467 | goto out5; | ||
468 | } | ||
469 | platform_set_drvdata(self->pldev, self); | ||
450 | 470 | ||
451 | return chip_index; | 471 | return chip_index; |
472 | |||
473 | out5: | ||
474 | unregister_netdev(dev); | ||
452 | out4: | 475 | out4: |
453 | dma_free_coherent(NULL, self->tx_buff.truesize, | 476 | dma_free_coherent(NULL, self->tx_buff.truesize, |
454 | self->tx_buff.head, self->tx_buff_dma); | 477 | self->tx_buff.head, self->tx_buff_dma); |
@@ -479,6 +502,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self) | |||
479 | 502 | ||
480 | iobase = self->io.fir_base; | 503 | iobase = self->io.fir_base; |
481 | 504 | ||
505 | platform_device_unregister(self->pldev); | ||
506 | |||
482 | /* Remove netdevice */ | 507 | /* Remove netdevice */ |
483 | unregister_netdev(self->netdev); | 508 | unregister_netdev(self->netdev); |
484 | 509 | ||
@@ -2278,45 +2303,83 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) | |||
2278 | return &self->stats; | 2303 | return &self->stats; |
2279 | } | 2304 | } |
2280 | 2305 | ||
2281 | static void nsc_ircc_suspend(struct nsc_ircc_cb *self) | 2306 | static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state) |
2282 | { | 2307 | { |
2283 | IRDA_MESSAGE("%s, Suspending\n", driver_name); | 2308 | struct nsc_ircc_cb *self = platform_get_drvdata(dev); |
2309 | int bank; | ||
2310 | unsigned long flags; | ||
2311 | int iobase = self->io.fir_base; | ||
2284 | 2312 | ||
2285 | if (self->io.suspended) | 2313 | if (self->io.suspended) |
2286 | return; | 2314 | return 0; |
2287 | 2315 | ||
2288 | nsc_ircc_net_close(self->netdev); | 2316 | IRDA_DEBUG(1, "%s, Suspending\n", driver_name); |
2289 | 2317 | ||
2318 | rtnl_lock(); | ||
2319 | if (netif_running(self->netdev)) { | ||
2320 | netif_device_detach(self->netdev); | ||
2321 | spin_lock_irqsave(&self->lock, flags); | ||
2322 | /* Save current bank */ | ||
2323 | bank = inb(iobase+BSR); | ||
2324 | |||
2325 | /* Disable interrupts */ | ||
2326 | switch_bank(iobase, BANK0); | ||
2327 | outb(0, iobase+IER); | ||
2328 | |||
2329 | /* Restore bank register */ | ||
2330 | outb(bank, iobase+BSR); | ||
2331 | |||
2332 | spin_unlock_irqrestore(&self->lock, flags); | ||
2333 | free_irq(self->io.irq, self->netdev); | ||
2334 | disable_dma(self->io.dma); | ||
2335 | } | ||
2290 | self->io.suspended = 1; | 2336 | self->io.suspended = 1; |
2337 | rtnl_unlock(); | ||
2338 | |||
2339 | return 0; | ||
2291 | } | 2340 | } |
2292 | 2341 | ||
2293 | static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) | 2342 | static int nsc_ircc_resume(struct platform_device *dev) |
2294 | { | 2343 | { |
2344 | struct nsc_ircc_cb *self = platform_get_drvdata(dev); | ||
2345 | unsigned long flags; | ||
2346 | |||
2295 | if (!self->io.suspended) | 2347 | if (!self->io.suspended) |
2296 | return; | 2348 | return 0; |
2297 | 2349 | ||
2350 | IRDA_DEBUG(1, "%s, Waking up\n", driver_name); | ||
2351 | |||
2352 | rtnl_lock(); | ||
2298 | nsc_ircc_setup(&self->io); | 2353 | nsc_ircc_setup(&self->io); |
2299 | nsc_ircc_net_open(self->netdev); | 2354 | nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id); |
2300 | |||
2301 | IRDA_MESSAGE("%s, Waking up\n", driver_name); | ||
2302 | 2355 | ||
2356 | if (netif_running(self->netdev)) { | ||
2357 | if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, | ||
2358 | self->netdev->name, self->netdev)) { | ||
2359 | IRDA_WARNING("%s, unable to allocate irq=%d\n", | ||
2360 | driver_name, self->io.irq); | ||
2361 | |||
2362 | /* | ||
2363 | * Don't fail resume process, just kill this | ||
2364 | * network interface | ||
2365 | */ | ||
2366 | unregister_netdevice(self->netdev); | ||
2367 | } else { | ||
2368 | spin_lock_irqsave(&self->lock, flags); | ||
2369 | nsc_ircc_change_speed(self, self->io.speed); | ||
2370 | spin_unlock_irqrestore(&self->lock, flags); | ||
2371 | netif_device_attach(self->netdev); | ||
2372 | } | ||
2373 | |||
2374 | } else { | ||
2375 | spin_lock_irqsave(&self->lock, flags); | ||
2376 | nsc_ircc_change_speed(self, 9600); | ||
2377 | spin_unlock_irqrestore(&self->lock, flags); | ||
2378 | } | ||
2303 | self->io.suspended = 0; | 2379 | self->io.suspended = 0; |
2304 | } | 2380 | rtnl_unlock(); |
2305 | 2381 | ||
2306 | static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) | 2382 | return 0; |
2307 | { | ||
2308 | struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data; | ||
2309 | if (self) { | ||
2310 | switch (rqst) { | ||
2311 | case PM_SUSPEND: | ||
2312 | nsc_ircc_suspend(self); | ||
2313 | break; | ||
2314 | case PM_RESUME: | ||
2315 | nsc_ircc_wakeup(self); | ||
2316 | break; | ||
2317 | } | ||
2318 | } | ||
2319 | return 0; | ||
2320 | } | 2383 | } |
2321 | 2384 | ||
2322 | MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); | 2385 | MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); |