Commit 395c52e3 authored by Russell King's avatar Russell King Committed by Stephen Hemminger

[irda sa1100_ir] "resurrect from bitrot hell"

- Don't dereference net device in suspend/resume methods until we
  know the device data has actually been set.

- Remove deprecated MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT

- System devices in their original form are long since dead.  Convert
  to using a platform device.

- Convert to parameters to moduleparam format.

- Use register_netdev not register_netdevice - the latter causes us
  to register "irda%d" as the device name rather than a properly
  formatted device name.
parent 3c1efe41
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -358,9 +359,13 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si) ...@@ -358,9 +359,13 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si)
static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level) static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level)
{ {
struct net_device *dev = dev_get_drvdata(_dev); struct net_device *dev = dev_get_drvdata(_dev);
struct sa1100_irda *si = dev->priv; struct sa1100_irda *si;
if (!dev || level != SUSPEND_DISABLE)
return 0;
if (si && si->open && level == SUSPEND_DISABLE) { si = dev->priv;
if (si->open) {
/* /*
* Stop the transmit queue * Stop the transmit queue
*/ */
...@@ -379,9 +384,13 @@ static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level) ...@@ -379,9 +384,13 @@ static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level)
static int sa1100_irda_resume(struct device *_dev, u32 level) static int sa1100_irda_resume(struct device *_dev, u32 level)
{ {
struct net_device *dev = dev_get_drvdata(_dev); struct net_device *dev = dev_get_drvdata(_dev);
struct sa1100_irda *si = dev->priv; struct sa1100_irda *si;
if (!dev || level != RESUME_ENABLE)
return 0;
if (si && si->open && level == RESUME_ENABLE) { si = dev->priv;
if (si->open) {
/* /*
* If we missed a speed change, initialise at the new speed * If we missed a speed change, initialise at the new speed
* directly. It is debatable whether this is actually * directly. It is debatable whether this is actually
...@@ -833,8 +842,6 @@ static int sa1100_irda_start(struct net_device *dev) ...@@ -833,8 +842,6 @@ static int sa1100_irda_start(struct net_device *dev)
struct sa1100_irda *si = dev->priv; struct sa1100_irda *si = dev->priv;
int err; int err;
MOD_INC_USE_COUNT;
si->speed = 9600; si->speed = 9600;
err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev);
...@@ -890,7 +897,6 @@ static int sa1100_irda_start(struct net_device *dev) ...@@ -890,7 +897,6 @@ static int sa1100_irda_start(struct net_device *dev)
err_rx_dma: err_rx_dma:
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
err_irq: err_irq:
MOD_DEC_USE_COUNT;
return err; return err;
} }
...@@ -930,8 +936,6 @@ static int sa1100_irda_stop(struct net_device *dev) ...@@ -930,8 +936,6 @@ static int sa1100_irda_stop(struct net_device *dev)
sa1100_set_power(si, 0); sa1100_set_power(si, 0);
MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -947,47 +951,47 @@ static int sa1100_irda_init_iobuf(iobuff_t *io, int size) ...@@ -947,47 +951,47 @@ static int sa1100_irda_init_iobuf(iobuff_t *io, int size)
return io->head ? 0 : -ENOMEM; return io->head ? 0 : -ENOMEM;
} }
static struct device_driver sa1100ir_driver = { static int sa1100_irda_probe(struct device *_dev)
.name = "sa1100ir",
.bus = &system_bus_type,
.suspend = sa1100_irda_suspend,
.resume = sa1100_irda_resume,
};
static struct sys_device sa1100ir_device = {
.name = "sa1100ir",
.id = 0,
.root = NULL,
.dev = {
.name = "Intel Corporation SA11x0 [IrDA]",
.bus_id = "0",
.driver = &sa1100ir_driver,
},
};
static int sa1100_irda_net_init(struct net_device *dev)
{ {
struct sa1100_irda *si = dev->priv; struct platform_device *pdev = to_platform_device(_dev);
struct net_device *dev;
struct sa1100_irda *si;
unsigned int baudrate_mask; unsigned int baudrate_mask;
int err; int err;
si->dev = &sa1100ir_device.dev; err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_1;
err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_2;
err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_3;
dev = alloc_irdadev(sizeof(struct sa1100_irda));
if (!dev)
goto err_mem_4;
si = dev->priv;
si->dev = &pdev->dev;
/* /*
* Initialise the HP-SIR buffers * Initialise the HP-SIR buffers
*/ */
err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); err = sa1100_irda_init_iobuf(&si->rx_buff, 14384);
if (err) if (err)
goto out; goto err_mem_5;
err = sa1100_irda_init_iobuf(&si->tx_buff, 4000); err = sa1100_irda_init_iobuf(&si->tx_buff, 4000);
if (err) if (err)
goto out_free_rx; goto err_mem_5;
dev->hard_start_xmit = sa1100_irda_hard_xmit; dev->hard_start_xmit = sa1100_irda_hard_xmit;
dev->open = sa1100_irda_start; dev->open = sa1100_irda_start;
dev->stop = sa1100_irda_stop; dev->stop = sa1100_irda_stop;
dev->do_ioctl = sa1100_irda_ioctl; dev->do_ioctl = sa1100_irda_ioctl;
dev->get_stats = sa1100_irda_stats; dev->get_stats = sa1100_irda_stats;
dev->irq = IRQ_Ser2ICP;
irda_init_max_qos_capabilies(&si->qos); irda_init_max_qos_capabilies(&si->qos);
...@@ -1022,136 +1026,95 @@ static int sa1100_irda_net_init(struct net_device *dev) ...@@ -1022,136 +1026,95 @@ static int sa1100_irda_net_init(struct net_device *dev)
Ser2UTCR4 = si->utcr4; Ser2UTCR4 = si->utcr4;
Ser2HSCR0 = HSCR0_UART; Ser2HSCR0 = HSCR0_UART;
return 0; err = register_netdev(dev);
if (err == 0)
dev_set_drvdata(&pdev->dev, si);
kfree(si->tx_buff.head); if (err) {
out_free_rx: err_mem_5:
kfree(si->rx_buff.head); kfree(si->tx_buff.head);
out: kfree(si->rx_buff.head);
free_netdev(dev);
err_mem_4:
release_mem_region(__PREG(Ser2HSCR2), 0x04);
err_mem_3:
release_mem_region(__PREG(Ser2HSCR0), 0x1c);
err_mem_2:
release_mem_region(__PREG(Ser2UTCR0), 0x24);
}
err_mem_1:
return err; return err;
} }
static int __init sa1100_irda_init(void) static int sa1100_irda_remove(struct device *_dev)
{ {
struct net_device *dev; struct net_device *dev = dev_get_drvdata(_dev);
struct sa1100_irda *si;
int err;
/*
* Limit power level a sensible range.
*/
if (power_level < 1)
power_level = 1;
if (power_level > 3)
power_level = 3;
err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_1;
err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_2;
err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY;
if (err)
goto err_mem_3;
dev = alloc_irdadev(sizeof(struct sa1100_irda));
if (!dev)
goto err_alloc;
driver_register(&sa1100ir_driver);
sys_device_register(&sa1100ir_device);
dev->irq = IRQ_Ser2ICP;
err = sa1100_irda_net_init(dev);
if (err)
goto err_init;
rtnl_lock(); if (dev) {
err = register_netdevice(dev); struct sa1100_irda *si = dev->priv;
if (err) unregister_netdev(dev);
goto err_register; kfree(si->tx_buff.head);
dev_set_drvdata(&sa1100ir_device.dev, dev); kfree(si->rx_buff.head);
rtnl_unlock(); free_netdev(dev);
return 0; }
err_register:
rtnl_unlock();
si = dev->priv;
kfree(si->tx_buff.head);
kfree(si->rx_buff.head);
err_init:
free_netdev(dev);
sys_device_unregister(&sa1100ir_device);
driver_unregister(&sa1100ir_driver);
err_alloc:
release_mem_region(__PREG(Ser2HSCR2), 0x04); release_mem_region(__PREG(Ser2HSCR2), 0x04);
err_mem_3:
release_mem_region(__PREG(Ser2HSCR0), 0x1c); release_mem_region(__PREG(Ser2HSCR0), 0x1c);
err_mem_2:
release_mem_region(__PREG(Ser2UTCR0), 0x24); release_mem_region(__PREG(Ser2UTCR0), 0x24);
err_mem_1:
return err; return 0;
} }
static void __exit sa1100_irda_exit(void) static struct device_driver sa1100ir_driver = {
{ .name = "sa11x0-ir",
struct net_device *dev = dev_get_drvdata(&sa1100ir_device.dev); .bus = &platform_bus_type,
.probe = sa1100_irda_probe,
.remove = sa1100_irda_remove,
.suspend = sa1100_irda_suspend,
.resume = sa1100_irda_resume,
};
if (dev) static struct platform_device sa1100ir_device = {
unregister_netdev(dev); .name = "sa11x0-ir",
.id = 0,
};
sys_device_unregister(&sa1100ir_device); static int __init sa1100_irda_init(void)
driver_unregister(&sa1100ir_driver); {
int ret;
release_mem_region(__PREG(Ser2HSCR2), 0x04); /*
release_mem_region(__PREG(Ser2HSCR0), 0x1c); * Limit power level a sensible range.
release_mem_region(__PREG(Ser2UTCR0), 0x24); */
if (power_level < 1)
power_level = 1;
if (power_level > 3)
power_level = 3;
if(dev) { ret = driver_register(&sa1100ir_driver);
struct sa1100_irda *si = dev->priv; if (ret == 0) {
kfree(si->tx_buff.head); ret = platform_device_register(&sa1100ir_device);
kfree(si->rx_buff.head); if (ret)
free_netdev(dev); driver_unregister(&sa1100ir_driver);
} }
return ret;
} }
static int __init sa1100ir_setup(char *line) static void __exit sa1100_irda_exit(void)
{ {
char *opt; driver_unregister(&sa1100ir_driver);
platform_device_unregister(&sa1100ir_device);
if (!line)
return 0;
while ((opt = strsep(&line, ",")) != NULL) {
if (!strncmp(opt, "max_rate:", 9)) {
max_rate = simple_strtoul(opt + 9, NULL, 0);
continue;
}
if (!strncmp(opt, "power_level:", 12)) {
power_level = simple_strtoul(opt + 12, NULL, 0);
continue;
}
if (!strncmp(opt, "tx_lpm:", 7)) {
tx_lpm = simple_strtoul(opt + 7, NULL, 0);
continue;
}
}
return 1;
} }
__setup("sa1100ir=", sa1100ir_setup);
module_init(sa1100_irda_init); module_init(sa1100_irda_init);
module_exit(sa1100_irda_exit); module_exit(sa1100_irda_exit);
module_param(power_level, int, 0);
module_param(tx_lpm, int, 0);
module_param(max_rate, int, 0);
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver"); MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(power_level, "i");
MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)");
MODULE_PARM(tx_lpm, "i");
MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode");
MODULE_PARM(max_rate, "i");
MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment