From: Jeff Mahoney The following 3 patches, combined with the userspace patches referenced below, implement hotplug events for open firmware/macio devices such as apple airport wireless ethernet cards. * 01-openfirmware-device-table.diff - Converts struct of_match to a MODULE_DEVICE_TABLE-compatible struct of_device_id - Uses the information to generate a device table parsable by depmod(8) * 02-openfirmware-sysfs.diff - Exports openfirmware variables via sysfs so that coldplug can read and take appropriate action * 03-openfirmware-hotplug.diff - Adds the hotplug routine for generating hotplug events. Uses the information published to provide the hotplug environment variables to userspace. In addition to the kernel patches, userspace patches for hotplug and module-init-tools are also required. These patches, including the kernel patches, are available here: ftp://ftp.suse.com/pub/people/jeffm/linux/macio-hotplug/ macio.rc: implements coldplug support for macio devices of.agent: implements module loading for of-table devices module-init-tools-3.0-pre10-openfirmware.diff: adds modules.ofmap to depmod This patch converts the usage of struct of_match to struct of_device_id, similar to pci_device_id. This allows a device table to be generated, which can be parsed by depmod(8) to generate a map file for module loading. In order for hotplug to work with macio devices, patches to module-init-tools and hotplug must be applied. Those patches are available at: ftp://ftp.suse.com/pub/people/jeffm/linux/macio-hotplug/ Signed-off-by: Jeff Mahoney Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton --- arch/ppc/syslib/of_device.c | 15 ++++++++------- arch/ppc64/kernel/of_device.c | 15 ++++++++------- drivers/i2c/busses/i2c-keywest.c | 7 +++---- drivers/ide/ppc/pmac.c | 12 ++---------- drivers/macintosh/macio_asic.c | 4 ++-- drivers/macintosh/mediabay.c | 7 ++----- drivers/macintosh/therm_pm72.c | 9 ++++----- drivers/macintosh/therm_windtunnel.c | 6 +++--- drivers/net/bmac.c | 7 ++----- drivers/net/mace.c | 6 ++---- drivers/net/wireless/airport.c | 8 ++++---- drivers/scsi/mac53c94.c | 7 +++---- drivers/scsi/mesh.c | 8 +++----- drivers/serial/pmac_zilog.c | 9 +++------ drivers/video/platinumfb.c | 6 ++---- include/asm-ppc/macio.h | 5 +++-- include/asm-ppc/of_device.h | 20 ++++---------------- include/linux/mod_devicetable.h | 11 +++++++++++ scripts/mod/file2alias.c | 21 +++++++++++++++++++++ 19 files changed, 90 insertions(+), 93 deletions(-) diff -puN arch/ppc64/kernel/of_device.c~openfirmware-generate-device-table-for-userspace arch/ppc64/kernel/of_device.c --- 25/arch/ppc64/kernel/of_device.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/arch/ppc64/kernel/of_device.c 2005-06-28 22:40:38.000000000 -0700 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -15,20 +16,20 @@ * Used by a driver to check whether an of_device present in the * system is in its list of supported devices. */ -const struct of_match * of_match_device(const struct of_match *matches, +const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct of_device *dev) { if (!dev->node) return NULL; - while (matches->name || matches->type || matches->compatible) { + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { int match = 1; - if (matches->name && matches->name != OF_ANY_MATCH) + if (matches->name[0]) match &= dev->node->name && !strcmp(matches->name, dev->node->name); - if (matches->type && matches->type != OF_ANY_MATCH) + if (matches->type[0]) match &= dev->node->type && !strcmp(matches->type, dev->node->type); - if (matches->compatible && matches->compatible != OF_ANY_MATCH) + if (matches->compatible[0]) match &= device_is_compatible(dev->node, matches->compatible); if (match) @@ -42,7 +43,7 @@ static int of_platform_bus_match(struct { struct of_device * of_dev = to_of_device(dev); struct of_platform_driver * of_drv = to_of_platform_driver(drv); - const struct of_match * matches = of_drv->match_table; + const struct of_device_id * matches = of_drv->match_table; if (!matches) return 0; @@ -75,7 +76,7 @@ static int of_device_probe(struct device int error = -ENODEV; struct of_platform_driver *drv; struct of_device *of_dev; - const struct of_match *match; + const struct of_device_id *match; drv = to_of_platform_driver(dev->driver); of_dev = to_of_device(dev); diff -puN arch/ppc/syslib/of_device.c~openfirmware-generate-device-table-for-userspace arch/ppc/syslib/of_device.c --- 25/arch/ppc/syslib/of_device.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/arch/ppc/syslib/of_device.c 2005-06-28 22:40:38.000000000 -0700 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -15,20 +16,20 @@ * Used by a driver to check whether an of_device present in the * system is in its list of supported devices. */ -const struct of_match * of_match_device(const struct of_match *matches, +const struct of_device_id * of_match_device(const struct of_device_id *matches, const struct of_device *dev) { if (!dev->node) return NULL; - while (matches->name || matches->type || matches->compatible) { + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { int match = 1; - if (matches->name && matches->name != OF_ANY_MATCH) + if (matches->name[0]) match &= dev->node->name && !strcmp(matches->name, dev->node->name); - if (matches->type && matches->type != OF_ANY_MATCH) + if (matches->type[0]) match &= dev->node->type && !strcmp(matches->type, dev->node->type); - if (matches->compatible && matches->compatible != OF_ANY_MATCH) + if (matches->compatible[0]) match &= device_is_compatible(dev->node, matches->compatible); if (match) @@ -42,7 +43,7 @@ static int of_platform_bus_match(struct { struct of_device * of_dev = to_of_device(dev); struct of_platform_driver * of_drv = to_of_platform_driver(drv); - const struct of_match * matches = of_drv->match_table; + const struct of_device_id * matches = of_drv->match_table; if (!matches) return 0; @@ -75,7 +76,7 @@ static int of_device_probe(struct device int error = -ENODEV; struct of_platform_driver *drv; struct of_device *of_dev; - const struct of_match *match; + const struct of_device_id *match; drv = to_of_platform_driver(dev->driver); of_dev = to_of_device(dev); diff -puN drivers/i2c/busses/i2c-keywest.c~openfirmware-generate-device-table-for-userspace drivers/i2c/busses/i2c-keywest.c --- 25/drivers/i2c/busses/i2c-keywest.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/i2c/busses/i2c-keywest.c 2005-06-28 22:40:38.000000000 -0700 @@ -698,7 +698,7 @@ dispose_iface(struct device *dev) } static int -create_iface_macio(struct macio_dev* dev, const struct of_match *match) +create_iface_macio(struct macio_dev* dev, const struct of_device_id *match) { return create_iface(dev->ofdev.node, &dev->ofdev.dev); } @@ -710,7 +710,7 @@ dispose_iface_macio(struct macio_dev* de } static int -create_iface_of_platform(struct of_device* dev, const struct of_match *match) +create_iface_of_platform(struct of_device* dev, const struct of_device_id *match) { return create_iface(dev->node, &dev->dev); } @@ -721,10 +721,9 @@ dispose_iface_of_platform(struct of_devi return dispose_iface(&dev->dev); } -static struct of_match i2c_keywest_match[] = +static struct of_device_id i2c_keywest_match[] = { { - .name = OF_ANY_MATCH, .type = "i2c", .compatible = "keywest" }, diff -puN drivers/ide/ppc/pmac.c~openfirmware-generate-device-table-for-userspace drivers/ide/ppc/pmac.c --- 25/drivers/ide/ppc/pmac.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/ide/ppc/pmac.c 2005-06-28 22:40:38.000000000 -0700 @@ -1419,7 +1419,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p * Attach to a macio probed interface */ static int __devinit -pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match) +pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) { void __iomem *base; unsigned long regbase; @@ -1637,27 +1637,19 @@ pmac_ide_pci_resume(struct pci_dev *pdev return rc; } -static struct of_match pmac_ide_macio_match[] = +static struct of_device_id pmac_ide_macio_match[] = { { .name = "IDE", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, { .name = "ATA", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, { - .name = OF_ANY_MATCH, .type = "ide", - .compatible = OF_ANY_MATCH }, { - .name = OF_ANY_MATCH, .type = "ata", - .compatible = OF_ANY_MATCH }, {}, }; diff -puN drivers/macintosh/macio_asic.c~openfirmware-generate-device-table-for-userspace drivers/macintosh/macio_asic.c --- 25/drivers/macintosh/macio_asic.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/macintosh/macio_asic.c 2005-06-28 22:42:43.000000000 -0700 @@ -33,7 +33,7 @@ static int macio_bus_match(struct device { struct macio_dev * macio_dev = to_macio_device(dev); struct macio_driver * macio_drv = to_macio_driver(drv); - const struct of_match * matches = macio_drv->match_table; + const struct of_device_id * matches = macio_drv->match_table; if (!matches) return 0; @@ -66,7 +66,7 @@ static int macio_device_probe(struct dev int error = -ENODEV; struct macio_driver *drv; struct macio_dev *macio_dev; - const struct of_match *match; + const struct of_device_id *match; drv = to_macio_driver(dev->driver); macio_dev = to_macio_device(dev); diff -puN drivers/macintosh/mediabay.c~openfirmware-generate-device-table-for-userspace drivers/macintosh/mediabay.c --- 25/drivers/macintosh/mediabay.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/macintosh/mediabay.c 2005-06-28 22:40:38.000000000 -0700 @@ -642,7 +642,7 @@ static int __pmac media_bay_task(void *x } } -static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_match *match) +static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match) { struct media_bay_info* bay; u32 __iomem *regbase; @@ -797,23 +797,20 @@ static struct mb_ops keylargo_mb_ops __p * Therefore we do it all by polling the media bay once each tick. */ -static struct of_match media_bay_match[] = +static struct of_device_id media_bay_match[] = { { .name = "media-bay", - .type = OF_ANY_MATCH, .compatible = "keylargo-media-bay", .data = &keylargo_mb_ops, }, { .name = "media-bay", - .type = OF_ANY_MATCH, .compatible = "heathrow-media-bay", .data = &heathrow_mb_ops, }, { .name = "media-bay", - .type = OF_ANY_MATCH, .compatible = "ohare-media-bay", .data = &ohare_mb_ops, }, diff -puN drivers/macintosh/therm_pm72.c~openfirmware-generate-device-table-for-userspace drivers/macintosh/therm_pm72.c --- 25/drivers/macintosh/therm_pm72.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/macintosh/therm_pm72.c 2005-06-28 22:40:38.000000000 -0700 @@ -120,6 +120,7 @@ #include #include #include +#include #include "therm_pm72.h" @@ -1986,7 +1987,7 @@ static void fcu_lookup_fans(struct devic } } -static int fcu_of_probe(struct of_device* dev, const struct of_match *match) +static int fcu_of_probe(struct of_device* dev, const struct of_device_id *match) { int rc; @@ -2009,12 +2010,10 @@ static int fcu_of_remove(struct of_devic return 0; } -static struct of_match fcu_of_match[] = +static struct of_device_id fcu_match[] = { { - .name = OF_ANY_MATCH, .type = "fcu", - .compatible = OF_ANY_MATCH }, {}, }; @@ -2022,7 +2021,7 @@ static struct of_match fcu_of_match[] = static struct of_platform_driver fcu_of_platform_driver = { .name = "temperature", - .match_table = fcu_of_match, + .match_table = fcu_match, .probe = fcu_of_probe, .remove = fcu_of_remove }; diff -puN drivers/macintosh/therm_windtunnel.c~openfirmware-generate-device-table-for-userspace drivers/macintosh/therm_windtunnel.c --- 25/drivers/macintosh/therm_windtunnel.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/macintosh/therm_windtunnel.c 2005-06-28 22:40:38.000000000 -0700 @@ -43,6 +43,7 @@ #include #include #include +#include #define LOG_TEMP 0 /* continously log temperature */ @@ -450,7 +451,7 @@ do_probe( struct i2c_adapter *adapter, i /************************************************************************/ static int -therm_of_probe( struct of_device *dev, const struct of_match *match ) +therm_of_probe( struct of_device *dev, const struct of_device_id *match ) { return i2c_add_driver( &g4fan_driver ); } @@ -461,9 +462,8 @@ therm_of_remove( struct of_device *dev ) return i2c_del_driver( &g4fan_driver ); } -static struct of_match therm_of_match[] = {{ +static struct of_device_id therm_of_match[] = {{ .name = "fan", - .type = OF_ANY_MATCH, .compatible = "adm1030" }, {} }; diff -puN drivers/net/bmac.c~openfirmware-generate-device-table-for-userspace drivers/net/bmac.c --- 25/drivers/net/bmac.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/net/bmac.c 2005-06-28 22:40:38.000000000 -0700 @@ -1261,7 +1261,7 @@ static void bmac_reset_and_enable(struct spin_unlock_irqrestore(&bp->lock, flags); } -static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_match *match) +static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match) { int j, rev, ret; struct bmac_data *bp; @@ -1645,16 +1645,13 @@ static int __devexit bmac_remove(struct return 0; } -static struct of_match bmac_match[] = +static struct of_device_id bmac_match[] = { { .name = "bmac", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH, .data = (void *)0, }, { - .name = OF_ANY_MATCH, .type = "network", .compatible = "bmac+", .data = (void *)1, diff -puN drivers/net/mace.c~openfirmware-generate-device-table-for-userspace drivers/net/mace.c --- 25/drivers/net/mace.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/net/mace.c 2005-06-28 22:40:38.000000000 -0700 @@ -109,7 +109,7 @@ bitrev(int b) } -static int __devinit mace_probe(struct macio_dev *mdev, const struct of_match *match) +static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *mace = macio_get_of_node(mdev); struct net_device *dev; @@ -1009,12 +1009,10 @@ static irqreturn_t mace_rxdma_intr(int i return IRQ_HANDLED; } -static struct of_match mace_match[] = +static struct of_device_id mace_match[] = { { .name = "mace", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH }, {}, }; diff -puN drivers/net/wireless/airport.c~openfirmware-generate-device-table-for-userspace drivers/net/wireless/airport.c --- 25/drivers/net/wireless/airport.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/drivers/net/wireless/airport.c 2005-06-28 22:40:38.000000000 -0700 @@ -184,7 +184,7 @@ static int airport_hard_reset(struct ori } static int -airport_attach(struct macio_dev *mdev, const struct of_match *match) +airport_attach(struct macio_dev *mdev, const struct of_device_id *match) { struct orinoco_private *priv; struct net_device *dev; @@ -266,16 +266,16 @@ MODULE_AUTHOR("Benjamin Herrenschmidt node; struct fb_info *info; @@ -647,12 +647,10 @@ static int __devexit platinumfb_remove(s return 0; } -static struct of_match platinumfb_match[] = +static struct of_device_id platinumfb_match[] = { { .name = "platinum", - .type = OF_ANY_MATCH, - .compatible = OF_ANY_MATCH, }, {}, }; diff -puN include/asm-ppc/macio.h~openfirmware-generate-device-table-for-userspace include/asm-ppc/macio.h --- 25/include/asm-ppc/macio.h~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/include/asm-ppc/macio.h 2005-06-28 22:40:38.000000000 -0700 @@ -1,6 +1,7 @@ #ifndef __MACIO_ASIC_H__ #define __MACIO_ASIC_H__ +#include #include extern struct bus_type macio_bus_type; @@ -120,10 +121,10 @@ static inline struct pci_dev *macio_get_ struct macio_driver { char *name; - struct of_match *match_table; + struct of_device_id *match_table; struct module *owner; - int (*probe)(struct macio_dev* dev, const struct of_match *match); + int (*probe)(struct macio_dev* dev, const struct of_device_id *match); int (*remove)(struct macio_dev* dev); int (*suspend)(struct macio_dev* dev, pm_message_t state); diff -puN include/asm-ppc/of_device.h~openfirmware-generate-device-table-for-userspace include/asm-ppc/of_device.h --- 25/include/asm-ppc/of_device.h~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/include/asm-ppc/of_device.h 2005-06-28 22:40:38.000000000 -0700 @@ -24,20 +24,8 @@ struct of_device }; #define to_of_device(d) container_of(d, struct of_device, dev) -/* - * Struct used for matching a device - */ -struct of_match -{ - char *name; - char *type; - char *compatible; - void *data; -}; -#define OF_ANY_MATCH ((char *)-1L) - -extern const struct of_match *of_match_device( - const struct of_match *matches, const struct of_device *dev); +extern const struct of_device_id *of_match_device( + const struct of_device_id *matches, const struct of_device *dev); extern struct of_device *of_dev_get(struct of_device *dev); extern void of_dev_put(struct of_device *dev); @@ -49,10 +37,10 @@ extern void of_dev_put(struct of_device struct of_platform_driver { char *name; - struct of_match *match_table; + struct of_device_id *match_table; struct module *owner; - int (*probe)(struct of_device* dev, const struct of_match *match); + int (*probe)(struct of_device* dev, const struct of_device_id *match); int (*remove)(struct of_device* dev); int (*suspend)(struct of_device* dev, pm_message_t state); diff -puN include/linux/mod_devicetable.h~openfirmware-generate-device-table-for-userspace include/linux/mod_devicetable.h --- 25/include/linux/mod_devicetable.h~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/include/linux/mod_devicetable.h 2005-06-28 22:40:38.000000000 -0700 @@ -174,6 +174,17 @@ struct serio_device_id { __u8 proto; }; +/* + * Struct used for matching a device + */ +struct of_device_id +{ + char name[32]; + char type[32]; + char compatible[128]; + void *data; +}; + /* PCMCIA */ diff -puN scripts/mod/file2alias.c~openfirmware-generate-device-table-for-userspace scripts/mod/file2alias.c --- 25/scripts/mod/file2alias.c~openfirmware-generate-device-table-for-userspace 2005-06-28 22:40:38.000000000 -0700 +++ 25-akpm/scripts/mod/file2alias.c 2005-06-28 22:40:38.000000000 -0700 @@ -25,6 +25,8 @@ typedef Elf64_Addr kernel_ulong_t; #include #endif +#include + typedef uint32_t __u32; typedef uint16_t __u16; typedef unsigned char __u8; @@ -323,6 +325,22 @@ static int do_pcmcia_entry(const char *f +static int do_of_entry (const char *filename, struct of_device_id *of, char *alias) +{ + char *tmp; + sprintf(alias, "of:N%sT%sC%s", + of->name[0] ? of->name : "*", + of->type[0] ? of->type : "*", + of->compatible[0] ? of->compatible : "*"); + + /* Replace all whitespace with underscores */ + for (tmp = alias; tmp && *tmp; tmp++) + if (isspace (*tmp)) + *tmp = '_'; + + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -401,6 +419,9 @@ void handle_moddevtable(struct module *m else if (sym_is(symname, "__mod_pcmcia_device_table")) do_table(symval, sym->st_size, sizeof(struct pcmcia_device_id), do_pcmcia_entry, mod); + else if (sym_is(symname, "__mod_of_device_table")) + do_table(symval, sym->st_size, sizeof(struct of_device_id), + do_of_entry, mod); } /* Now add out buffered information to the generated C source */ _