linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / net / irda / nsc-ircc.c
index cb62f2a..ee717d0 100644 (file)
@@ -12,7 +12,6 @@
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
  *     Copyright (c) 1998 Actisys Corp., www.actisys.com
- *     Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com>
  *     All Rights Reserved
  *      
  *     This program is free software; you can redistribute it and/or 
 #include <linux/init.h>
 #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>
 
 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;
 
 /* Use BIOS settions by default, but user may supply module parameters */
-static unsigned int io[]  = { ~0, ~0, ~0, ~0, ~0 };
-static unsigned int irq[] = {  0,  0,  0,  0,  0 };
-static unsigned int dma[] = {  0,  0,  0,  0,  0 };
+static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = { 0, 0, 0, 0, 0 };
+static unsigned int dma[] = { 0, 0, 0, 0, 0 };
 
 static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
@@ -100,7 +87,6 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
 static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
-static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
 
 /* These are the known NSC chips */
 static nsc_chip_t chips[] = {
@@ -115,16 +101,11 @@ static nsc_chip_t chips[] = {
        /* Contributed by Jan Frey - IBM A30/A31 */
        { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, 
          nsc_ircc_probe_39x, nsc_ircc_init_39x },
-       /* IBM ThinkPads using PC8738x (T60/X60/Z60) */
-       { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
-         nsc_ircc_probe_39x, nsc_ircc_init_39x },
-       /* IBM ThinkPads using PC8394T (T43/R52/?) */
-       { "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff,
-         nsc_ircc_probe_39x, nsc_ircc_init_39x },
        { NULL }
 };
 
-static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
+/* Max 4 instances for now */
+static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
 
 static char *dongle_types[] = {
        "Differential serial interface",
@@ -145,24 +126,8 @@ static char *dongle_types[] = {
        "No dongle connected",
 };
 
-/* PNP probing */
-static chipio_t pnp_info;
-static const struct pnp_device_id nsc_ircc_pnp_table[] = {
-       { .id = "NSC6001", .driver_data = 0 },
-       { .id = "IBM0071", .driver_data = 0 },
-       { }
-};
-
-MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
-
-static struct pnp_driver nsc_ircc_pnp_driver = {
-       .name = "nsc-ircc",
-       .id_table = nsc_ircc_pnp_table,
-       .probe = nsc_ircc_pnp_probe,
-};
-
 /* Some prototypes */
-static int  nsc_ircc_open(chipio_t *info);
+static int  nsc_ircc_open(int i, chipio_t *info);
 static int  nsc_ircc_close(struct nsc_ircc_cb *self);
 static int  nsc_ircc_setup(chipio_t *info);
 static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
@@ -181,10 +146,7 @@ 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);
-
-/* Globals */
-static int pnp_registered;
-static int pnp_succeeded;
+static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data);
 
 /*
  * Function nsc_ircc_init ()
@@ -196,36 +158,28 @@ static int __init nsc_ircc_init(void)
 {
        chipio_t info;
        nsc_chip_t *chip;
-       int ret;
+       int ret = -ENODEV;
        int cfg_base;
        int cfg, id;
        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);
-
-       if (!ret)
-               pnp_registered = 1;
-
-       ret = -ENODEV;
-
        /* Probe for all the NSC chipsets we know about */
-       for (chip = chips; chip->name ; chip++) {
+       for (chip=chips; chip->name ; chip++) {
                IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__,
                           chip->name);
                
                /* Try all config registers for this chip */
-               for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) {
+               for (cfg=0; cfg<3; cfg++) {
                        cfg_base = chip->cfg[cfg];
                        if (!cfg_base)
                                continue;
+                       
+                       memset(&info, 0, sizeof(chipio_t));
+                       info.cfg_base = cfg_base;
+                       info.fir_base = io[i];
+                       info.dma = dma[i];
+                       info.irq = irq[i];
 
                        /* Read index register */
                        reg = inb(cfg_base);
@@ -240,65 +194,24 @@ static int __init nsc_ircc_init(void)
                        if ((id & chip->cid_mask) == chip->cid_value) {
                                IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
                                           __FUNCTION__, chip->name, id & ~chip->cid_mask);
+                               /* 
+                                * If the user supplies the base address, then
+                                * we init the chip, if not we probe the values
+                                * set by the BIOS
+                                */                             
+                               if (io[i] < 0x2000) {
+                                       chip->init(chip, &info);
+                               } else
+                                       chip->probe(chip, &info);
 
-                               /*
-                                * If we found a correct PnP setting,
-                                * we first try it.
-                                */
-                               if (pnp_succeeded) {
-                                       memset(&info, 0, sizeof(chipio_t));
-                                       info.cfg_base = cfg_base;
-                                       info.fir_base = pnp_info.fir_base;
-                                       info.dma = pnp_info.dma;
-                                       info.irq = pnp_info.irq;
-
-                                       if (info.fir_base < 0x2000) {
-                                               IRDA_MESSAGE("%s, chip->init\n", driver_name);
-                                               chip->init(chip, &info);
-                                       } else
-                                               chip->probe(chip, &info);
-
-                                       if (nsc_ircc_open(&info) >= 0)
-                                               ret = 0;
-                               }
-
-                               /*
-                                * Opening based on PnP values failed.
-                                * Let's fallback to user values, or probe
-                                * the chip.
-                                */
-                               if (ret) {
-                                       IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name);
-                                       memset(&info, 0, sizeof(chipio_t));
-                                       info.cfg_base = cfg_base;
-                                       info.fir_base = io[i];
-                                       info.dma = dma[i];
-                                       info.irq = irq[i];
-
-                                       /*
-                                        * If the user supplies the base address, then
-                                        * we init the chip, if not we probe the values
-                                        * set by the BIOS
-                                        */
-                                       if (io[i] < 0x2000) {
-                                               chip->init(chip, &info);
-                                       } else
-                                               chip->probe(chip, &info);
-
-                                       if (nsc_ircc_open(&info) >= 0)
-                                               ret = 0;
-                               }
+                               if (nsc_ircc_open(i, &info) == 0)
+                                       ret = 0;
                                i++;
                        } else {
                                IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id);
                        }
                } 
-       }
-
-       if (ret) {
-               platform_driver_unregister(&nsc_ircc_driver);
-               pnp_unregister_driver(&nsc_ircc_pnp_driver);
-               pnp_registered = 0;
+               
        }
 
        return ret;
@@ -314,17 +227,12 @@ static void __exit nsc_ircc_cleanup(void)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(dev_self); i++) {
+       pm_unregister_all(nsc_ircc_pmproc);
+
+       for (i=0; i < 4; 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);
-
-       pnp_registered = 0;
 }
 
 /*
@@ -333,26 +241,16 @@ static void __exit nsc_ircc_cleanup(void)
  *    Open driver instance
  *
  */
-static int __init nsc_ircc_open(chipio_t *info)
+static int __init nsc_ircc_open(int i, chipio_t *info)
 {
        struct net_device *dev;
        struct nsc_ircc_cb *self;
+        struct pm_dev *pmdev;
        void *ret;
-       int err, chip_index;
+       int err;
 
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
-
-       for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) {
-               if (!dev_self[chip_index])
-                       break;
-       }
-
-       if (chip_index == ARRAY_SIZE(dev_self)) {
-               IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__);
-               return -ENOMEM;
-       }
-
        IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
                     info->cfg_base);
 
@@ -373,8 +271,8 @@ static int __init nsc_ircc_open(chipio_t *info)
        spin_lock_init(&self->lock);
    
        /* Need to store self somewhere */
-       dev_self[chip_index] = self;
-       self->index = chip_index;
+       dev_self[i] = self;
+       self->index = i;
 
        /* Initialize IO */
        self->io.cfg_base  = info->cfg_base;
@@ -453,7 +351,7 @@ static int __init nsc_ircc_open(chipio_t *info)
 
        /* Check if user has supplied a valid dongle id or not */
        if ((dongle_id <= 0) ||
-           (dongle_id >= ARRAY_SIZE(dongle_types))) {
+           (dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) {
                dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
                
                IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name,
@@ -466,18 +364,11 @@ 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);
 
-       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;
+        pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc);
+        if (pmdev)
+                pmdev->data = self;
 
- out5:
-       unregister_netdev(dev);
+       return 0;
  out4:
        dma_free_coherent(NULL, self->tx_buff.truesize,
                          self->tx_buff.head, self->tx_buff_dma);
@@ -488,7 +379,7 @@ static int __init nsc_ircc_open(chipio_t *info)
        release_region(self->io.fir_base, self->io.fir_ext);
  out1:
        free_netdev(dev);
-       dev_self[chip_index] = NULL;
+       dev_self[i] = NULL;
        return err;
 }
 
@@ -508,8 +399,6 @@ 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);
 
@@ -816,7 +705,7 @@ static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info)
        int cfg_base = info->cfg_base;
        int enabled;
 
-       /* User is sure about his config... accept it. */
+       /* User is shure about his config... accept it. */
        IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): "
                   "io=0x%04x, irq=%d, dma=%d\n", 
                   __FUNCTION__, info->fir_base, info->irq, info->dma);
@@ -917,43 +806,6 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
        return 0;
 }
 
-/* PNP probing */
-static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
-{
-       memset(&pnp_info, 0, sizeof(chipio_t));
-       pnp_info.irq = -1;
-       pnp_info.dma = -1;
-       pnp_succeeded = 1;
-
-       /* There don't seem to be any way to get the cfg_base.
-        * On my box, cfg_base is in the PnP descriptor of the
-        * motherboard. Oh well... Jean II */
-
-       if (pnp_port_valid(dev, 0) &&
-               !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED))
-               pnp_info.fir_base = pnp_port_start(dev, 0);
-
-       if (pnp_irq_valid(dev, 0) &&
-               !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED))
-               pnp_info.irq = pnp_irq(dev, 0);
-
-       if (pnp_dma_valid(dev, 0) &&
-               !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED))
-               pnp_info.dma = pnp_dma(dev, 0);
-
-       IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n",
-                  __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma);
-
-       if((pnp_info.fir_base == 0) ||
-          (pnp_info.irq == -1) || (pnp_info.dma == -1)) {
-               /* Returning an error will disable the device. Yuck ! */
-               //return -EINVAL;
-               pnp_succeeded = 0;
-       }
-
-       return 0;
-}
-
 /*
  * Function nsc_ircc_setup (info)
  *
@@ -2309,83 +2161,45 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
        return &self->stats;
 }
 
-static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
+static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
 {
-       struct nsc_ircc_cb *self = platform_get_drvdata(dev);
-       int bank;
-       unsigned long flags;
-       int iobase = self->io.fir_base;
+       IRDA_MESSAGE("%s, Suspending\n", driver_name);
 
        if (self->io.suspended)
-               return 0;
-
-       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);
+               return;
 
-               /* Disable interrupts */
-               switch_bank(iobase, BANK0);
-               outb(0, iobase+IER);
-
-               /* Restore bank register */
-               outb(bank, iobase+BSR);
+       nsc_ircc_net_close(self->netdev);
 
-               spin_unlock_irqrestore(&self->lock, flags);
-               free_irq(self->io.irq, self->netdev);
-               disable_dma(self->io.dma);
-       }
        self->io.suspended = 1;
-       rtnl_unlock();
-
-       return 0;
 }
 
-static int nsc_ircc_resume(struct platform_device *dev)
+static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
 {
-       struct nsc_ircc_cb *self = platform_get_drvdata(dev);
-       unsigned long flags;
-
        if (!self->io.suspended)
-               return 0;
+               return;
 
-       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);
-               }
+       nsc_ircc_net_open(self->netdev);
+       
+       IRDA_MESSAGE("%s, Waking up\n", driver_name);
 
-       } 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;
+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;
 }
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");