Adapt PowerMac "airport" driver to new driver model

parent fa56cc98
...@@ -25,8 +25,6 @@ ...@@ -25,8 +25,6 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -48,44 +46,22 @@ struct airport { ...@@ -48,44 +46,22 @@ struct airport {
int ndev_registered; int ndev_registered;
}; };
#ifdef CONFIG_PMAC_PBOOK
static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier airport_sleep_notifier = {
airport_sleep_notify, SLEEP_LEVEL_NET,
};
#endif
/*
* Function prototypes
*/
static struct net_device *airport_attach(struct device_node *of_node);
static void airport_detach(struct net_device *dev);
static struct net_device *airport_dev;
#ifdef CONFIG_PMAC_PBOOK
static int static int
airport_sleep_notify(struct pmu_sleep_notifier *self, int when) airport_suspend(struct macio_dev *mdev, u32 state)
{ {
struct net_device *dev = airport_dev; struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
struct orinoco_private *priv = dev->priv; struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card; struct airport *card = priv->card;
unsigned long flags; unsigned long flags;
int err; int err;
if (! airport_dev)
return PBOOK_SLEEP_OK;
switch (when) {
case PBOOK_SLEEP_NOW:
printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name); printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
err = orinoco_lock(priv, &flags); err = orinoco_lock(priv, &flags);
if (err) { if (err) {
printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n", printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
dev->name); dev->name);
break; return 0;
} }
err = __orinoco_down(dev); err = __orinoco_down(dev);
...@@ -101,10 +77,21 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -101,10 +77,21 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
disable_irq(dev->irq); disable_irq(dev->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
break;
case PBOOK_WAKE: return 0;
}
static int
airport_resume(struct macio_dev *mdev)
{
struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
unsigned long flags;
int err;
printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
mdelay(200); mdelay(200);
...@@ -114,7 +101,7 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -114,7 +101,7 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
if (err) { if (err) {
printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n", printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
dev->name, err); dev->name, err);
break; return 0;
} }
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
...@@ -133,11 +120,41 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -133,11 +120,41 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
break; return 0;
} }
return PBOOK_SLEEP_OK;
static int
airport_detach(struct macio_dev *mdev)
{
struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
if (card->ndev_registered)
unregister_netdev(dev);
card->ndev_registered = 0;
if (card->irq_requested)
free_irq(dev->irq, dev);
card->irq_requested = 0;
if (card->vaddr)
iounmap(card->vaddr);
card->vaddr = 0;
dev->base_addr = 0;
release_OF_resource(card->node, 0);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ);
dev_set_drvdata(&mdev->ofdev.dev, NULL);
free_netdev(dev);
return 0;
} }
#endif /* CONFIG_PMAC_PBOOK */
static int airport_hard_reset(struct orinoco_private *priv) static int airport_hard_reset(struct orinoco_private *priv)
{ {
...@@ -170,25 +187,26 @@ static int airport_hard_reset(struct orinoco_private *priv) ...@@ -170,25 +187,26 @@ static int airport_hard_reset(struct orinoco_private *priv)
return 0; return 0;
} }
static struct net_device * static int
airport_attach(struct device_node *of_node) airport_attach(struct macio_dev *mdev, const struct of_match *match)
{ {
struct orinoco_private *priv; struct orinoco_private *priv;
struct net_device *dev; struct net_device *dev;
struct airport *card; struct airport *card;
unsigned long phys_addr; unsigned long phys_addr;
struct device_node *of_node = mdev->ofdev.node;
hermes_t *hw; hermes_t *hw;
if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { if (of_node->n_addrs < 1 || of_node->n_intrs < 1) {
printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
return NULL; return -ENODEV;
} }
/* Allocate space for private device-specific data */ /* Allocate space for private device-specific data */
dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
if (! dev) { if (! dev) {
printk(KERN_ERR "airport: can't allocate device datas\n"); printk(KERN_ERR "airport: can't allocate device datas\n");
return NULL; return -ENODEV;
} }
priv = dev->priv; priv = dev->priv;
card = priv->card; card = priv->card;
...@@ -199,11 +217,14 @@ airport_attach(struct device_node *of_node) ...@@ -199,11 +217,14 @@ airport_attach(struct device_node *of_node)
if (! request_OF_resource(of_node, 0, " (airport)")) { if (! request_OF_resource(of_node, 0, " (airport)")) {
printk(KERN_ERR "airport: can't request IO resource !\n"); printk(KERN_ERR "airport: can't request IO resource !\n");
kfree(dev); kfree(dev);
return NULL; return -ENODEV;
} }
dev->name[0] = '\0'; /* register_netdev will give us an ethX name */ dev->name[0] = '\0'; /* register_netdev will give us an ethX name */
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
dev_set_drvdata(&mdev->ofdev.dev, dev);
/* Setup interrupts & base address */ /* Setup interrupts & base address */
dev->irq = of_node->intrs[0].line; dev->irq = of_node->intrs[0].line;
...@@ -240,79 +261,50 @@ airport_attach(struct device_node *of_node) ...@@ -240,79 +261,50 @@ airport_attach(struct device_node *of_node)
} }
printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name); printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
card->ndev_registered = 1; card->ndev_registered = 1;
return 0;
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&airport_sleep_notifier);
#endif
return dev;
failed: failed:
airport_detach(dev); airport_detach(mdev);
return NULL; return -ENODEV;
} /* airport_attach */ } /* airport_attach */
/*======================================================================
This deletes a driver "instance".
======================================================================*/
static void
airport_detach(struct net_device *dev)
{
struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
#ifdef CONFIG_PMAC_PBOOK
pmu_unregister_sleep_notifier(&airport_sleep_notifier);
#endif
if (card->ndev_registered)
unregister_netdev(dev);
card->ndev_registered = 0;
if (card->irq_requested)
free_irq(dev->irq, dev);
card->irq_requested = 0;
if (card->vaddr)
iounmap(card->vaddr);
card->vaddr = 0;
dev->base_addr = 0;
release_OF_resource(card->node, 0);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ);
free_netdev(dev);
} /* airport_detach */
static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
MODULE_LICENSE("Dual MPL/GPL"); MODULE_LICENSE("Dual MPL/GPL");
static struct of_match airport_match[] =
{
{
.name = "radio",
.type = OF_ANY_MATCH,
.compatible = OF_ANY_MATCH
},
{},
};
static struct macio_driver airport_driver =
{
.name = "airport",
.match_table = airport_match,
.probe = airport_attach,
.remove = airport_detach,
.suspend = airport_suspend,
.resume = airport_resume,
};
static int __init static int __init
init_airport(void) init_airport(void)
{ {
struct device_node *airport_node;
printk(KERN_DEBUG "%s\n", version); printk(KERN_DEBUG "%s\n", version);
/* Lookup card in device tree */ return macio_register_driver(&airport_driver);
airport_node = find_devices("radio");
if (airport_node && !strcmp(airport_node->parent->name, "mac-io"))
airport_dev = airport_attach(airport_node);
return airport_dev ? 0 : -ENODEV;
} }
static void __exit static void __exit
exit_airport(void) exit_airport(void)
{ {
if (airport_dev) return macio_unregister_driver(&airport_driver);
airport_detach(airport_dev);
airport_dev = NULL;
} }
module_init(init_airport); module_init(init_airport);
......
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