* 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);
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[] = {
/* 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",
"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);
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 ()
{
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);
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;
{
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;
}
/*
* 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);
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;
/* 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,
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);
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;
}
iobase = self->io.fir_base;
- platform_device_unregister(self->pldev);
-
/* Remove netdevice */
unregister_netdev(self->netdev);
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);
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)
*
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>");