[PATCH2.6] nsc-ircc to platform device + suspend/resume redo
Hello all,
I have never been able to get the nsc-ircc driver working after
resume. As the result I developed a patch that convert driver
to platform_driver stuff plus it adds a working resume for me.
The patch is not yet to be included. What I want is some test/comment
from nsc-ircc users/irda developers.
I know it works for SIR transfers up to 115K. I dont have any faster device
so I cant test it...
Please can someone do some tests with the patch?
I would like to know if I need to call .._change_speed
even when the device was down to provide some defined state
of those registers, I'm setting speed to 9600.
Good would be if someone can comment the progranm logic.
The patch was a bit inspired by smsc irda driver. If all will
go well I will prepare more cleaner patch for inclusion.
The patch is against 2.6.15-rc6
Thank you,
Regards
Rudolf
diff -Naur a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
--- a/drivers/net/irda/nsc-ircc.c 2005-12-19 01:36:54.000000000 +0100
+++ b/drivers/net/irda/nsc-ircc.c 2005-12-23 22:31:58.000000000 +0100
<at> <at> -57,10 +57,9 <at> <at>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
+#include <linux/platform_device.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>
<at> <at> -70,6 +69,21 <at> <at>
#define CHIP_IO_EXTENT 8
#define BROKEN_DONGLE_ID
+/* 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,
+ },
+};
+
+
static char *driver_name = "nsc-ircc";
/* Module parameters */
<at> <at> -129,7 +143,7 <at> <at>
/* Some prototypes */
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 int nsc_ircc_setup(chipio_t *info, int inte);
static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self);
static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase);
<at> <at> -158,12 +172,20 <at> <at>
{
chipio_t info;
nsc_chip_t *chip;
- int ret = -ENODEV;
+ int ret;
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;
+ }
+
+ ret = -ENODEV;
+
/* Probe for all the NSC chipsets we know about */
for (chip=chips; chip->name ; chip++) {
IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__,
<at> <at> -213,7 +235,8 <at> <at>
}
}
-
+ if (ret)
+ platform_driver_unregister(&nsc_ircc_driver);
return ret;
}
<at> <at> -227,12 +250,11 <at> <at>
{
int 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);
}
/*
<at> <at> -254,7 +276,7 <at> <at>
IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
info->cfg_base);
- if ((nsc_ircc_setup(info)) == -1)
+ if ((nsc_ircc_setup(info, 1)) == -1)
return -1;
IRDA_MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
<at> <at> -363,12 +385,18 <at> <at>
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 0;
+ out5:
+ unregister_netdev(dev);
out4:
dma_free_coherent(NULL, self->tx_buff.truesize,
self->tx_buff.head, self->tx_buff_dma);
<at> <at> -399,6 +427,8 <at> <at>
iobase = self->io.fir_base;
+ platform_device_unregister(self->pldev);
+
/* Remove netdevice */
unregister_netdev(self->netdev);
<at> <at> -812,7 +842,7 <at> <at>
* Returns non-negative on success.
*
*/
-static int nsc_ircc_setup(chipio_t *info)
+static int nsc_ircc_setup(chipio_t *info, int inte)
{
int version;
int iobase = info->fir_base;
<at> <at> -860,7 +890,8 <at> <at>
/* Enable receive interrupts */
switch_bank(iobase, BANK0);
- outb(IER_RXHDL_IE, iobase+IER);
+ if (inte)
+ outb(IER_RXHDL_IE, iobase+IER);
return 0;
}
<at> <at> -2161,47 +2192,85 <at> <at>
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) {
+ 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);
- if (self->io.suspended)
- return;
+ /* 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();
+ }
- self->io.suspended = 1;
+ return 0;
}
-static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
+static int nsc_ircc_resume(struct platform_device *dev)
{
- if (!self->io.suspended)
- return;
-
- nsc_ircc_setup(&self->io);
- nsc_ircc_net_open(self->netdev);
-
- IRDA_MESSAGE("%s, Waking up\n", driver_name);
+ struct nsc_ircc_cb *self = platform_get_drvdata(dev);
+ int iobase = self->io.fir_base;
+ unsigned long flags;
- self->io.suspended = 0;
-}
+ if (self->io.suspended) {
+ IRDA_DEBUG(1, "%s, Waking up\n", driver_name);
+ rtnl_lock();
+ nsc_ircc_setup(&self->io, 0);
+ 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 {
+ printk("tady1 %d\n",self->io.speed);
+ 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);
+ }
-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;
- }
- }
+ } else {
+ printk("tady2 %d\n",self->io.speed);
+ 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@...>");
MODULE_DESCRIPTION("NSC IrDA Device Driver");
MODULE_LICENSE("GPL");
diff -Naur a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h
--- a/drivers/net/irda/nsc-ircc.h 2005-12-19 01:36:54.000000000 +0100
+++ b/drivers/net/irda/nsc-ircc.h 2005-12-23 17:21:59.000000000 +0100
<at> <at> -269,7 +269,7 <at> <at>
__u32 new_speed;
int index; /* Instance index */
- struct pm_dev *dev;
+ struct platform_device *pldev;
};
static inline void switch_bank(int iobase, int bank)