return (match & id_table->match_flags) == id_table->match_flags;
 }
 
-static bool is_fw_unit(struct device *dev);
-
-static int fw_unit_match(struct device *dev, struct device_driver *drv)
+static const struct ieee1394_device_id *unit_match(struct device *dev,
+                                                  struct device_driver *drv)
 {
        const struct ieee1394_device_id *id_table =
                        container_of(drv, struct fw_driver, driver)->id_table;
        int id[] = {0, 0, 0, 0};
 
-       /* We only allow binding to fw_units. */
-       if (!is_fw_unit(dev))
-               return 0;
-
        get_modalias_ids(fw_unit(dev), id);
 
        for (; id_table->match_flags != 0; id_table++)
                if (match_ids(id_table, id))
-                       return 1;
+                       return id_table;
 
-       return 0;
+       return NULL;
+}
+
+static bool is_fw_unit(struct device *dev);
+
+static int fw_unit_match(struct device *dev, struct device_driver *drv)
+{
+       /* We only allow binding to fw_units. */
+       return is_fw_unit(dev) && unit_match(dev, drv) != NULL;
+}
+
+static int fw_unit_probe(struct device *dev)
+{
+       struct fw_driver *driver =
+                       container_of(dev->driver, struct fw_driver, driver);
+
+       if (driver->probe)
+               return driver->probe(fw_unit(dev), unit_match(dev, dev->driver));
+       else
+               return driver->driver.probe(dev);
+}
+
+static int fw_unit_remove(struct device *dev)
+{
+       struct fw_driver *driver =
+                       container_of(dev->driver, struct fw_driver, driver);
+
+       if (driver->remove)
+               return driver->remove(fw_unit(dev)), 0;
+       else
+               return driver->driver.remove(dev);
 }
 
 static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
 struct bus_type fw_bus_type = {
        .name = "firewire",
        .match = fw_unit_match,
+       .probe = fw_unit_probe,
+       .remove = fw_unit_remove,
 };
 EXPORT_SYMBOL(fw_bus_type);
 
 
        return 0;
 }
 
-static int fwnet_probe(struct device *_dev)
+static int fwnet_probe(struct fw_unit *unit,
+                      const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(_dev);
        struct fw_device *device = fw_parent_device(unit);
        struct fw_card *card = device->card;
        struct net_device *net;
        return ret;
 }
 
+/*
+ * FIXME abort partially sent fragmented datagrams,
+ * discard partially received fragmented datagrams
+ */
+static void fwnet_update(struct fw_unit *unit)
+{
+       struct fw_device *device = fw_parent_device(unit);
+       struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
+       int generation;
+
+       generation = device->generation;
+
+       spin_lock_irq(&peer->dev->lock);
+       peer->node_id    = device->node_id;
+       peer->generation = generation;
+       spin_unlock_irq(&peer->dev->lock);
+}
+
 static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
 {
        struct fwnet_partial_datagram *pd, *pd_next;
        kfree(peer);
 }
 
-static int fwnet_remove(struct device *_dev)
+static void fwnet_remove(struct fw_unit *unit)
 {
-       struct fwnet_peer *peer = dev_get_drvdata(_dev);
+       struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
        struct fwnet_device *dev = peer->dev;
        struct net_device *net;
        int i;
        }
 
        mutex_unlock(&fwnet_device_mutex);
-
-       return 0;
-}
-
-/*
- * FIXME abort partially sent fragmented datagrams,
- * discard partially received fragmented datagrams
- */
-static void fwnet_update(struct fw_unit *unit)
-{
-       struct fw_device *device = fw_parent_device(unit);
-       struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
-       int generation;
-
-       generation = device->generation;
-
-       spin_lock_irq(&peer->dev->lock);
-       peer->node_id    = device->node_id;
-       peer->generation = generation;
-       spin_unlock_irq(&peer->dev->lock);
 }
 
 static const struct ieee1394_device_id fwnet_id_table[] = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = fwnet_probe,
-               .remove = fwnet_remove,
        },
+       .probe    = fwnet_probe,
        .update   = fwnet_update,
+       .remove   = fwnet_remove,
        .id_table = fwnet_id_table,
 };
 
 
 }
 
 static struct scsi_host_template scsi_driver_template;
-static int sbp2_remove(struct device *dev);
+static void sbp2_remove(struct fw_unit *unit);
 
-static int sbp2_probe(struct device *dev)
+static int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(dev);
        struct fw_device *device = fw_parent_device(unit);
        struct sbp2_target *tgt;
        struct sbp2_logical_unit *lu;
        return 0;
 
  fail_remove:
-       sbp2_remove(dev);
+       sbp2_remove(unit);
        return -ENOMEM;
 
  fail_shost_put:
        }
 }
 
-static int sbp2_remove(struct device *dev)
+static void sbp2_remove(struct fw_unit *unit)
 {
-       struct fw_unit *unit = fw_unit(dev);
        struct fw_device *device = fw_parent_device(unit);
        struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
        struct sbp2_logical_unit *lu, *next;
                kfree(lu);
        }
        scsi_remove_host(shost);
-       dev_notice(dev, "released target %d:0:0\n", shost->host_no);
+       dev_notice(&unit->device, "released target %d:0:0\n", shost->host_no);
 
        scsi_host_put(shost);
-       return 0;
 }
 
 #define SBP2_UNIT_SPEC_ID_ENTRY        0x0000609e
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = sbp2_probe,
-               .remove = sbp2_remove,
        },
+       .probe    = sbp2_probe,
        .update   = sbp2_update,
+       .remove   = sbp2_remove,
        .id_table = sbp2_id_table,
 };
 
 
 /* Adjust the template string if models with longer names appear. */
 #define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
 
-static int node_probe(struct device *dev)
+static int node_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 {
        struct firedtv *fdtv;
        char name[MAX_MODEL_NAME_LEN];
        if (!fdtv)
                return -ENOMEM;
 
-       dev_set_drvdata(dev, fdtv);
-       fdtv->device            = dev;
+       dev_set_drvdata(&unit->device, fdtv);
+       fdtv->device            = &unit->device;
        fdtv->isochannel        = -1;
        fdtv->voltage           = 0xff;
        fdtv->tone              = 0xff;
        mutex_init(&fdtv->demux_mutex);
        INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
 
-       name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+       name_len = fw_csr_string(unit->directory, CSR_MODEL,
                                 name, sizeof(name));
        for (i = ARRAY_SIZE(model_names); --i; )
                if (strlen(model_names[i]) <= name_len &&
                        break;
        fdtv->type = i;
 
-       err = fdtv_register_rc(fdtv, dev);
+       err = fdtv_register_rc(fdtv, &unit->device);
        if (err)
                goto fail_free;
 
        return err;
 }
 
-static int node_remove(struct device *dev)
+static void node_remove(struct fw_unit *unit)
 {
-       struct firedtv *fdtv = dev_get_drvdata(dev);
+       struct firedtv *fdtv = dev_get_drvdata(&unit->device);
 
        fdtv_dvb_unregister(fdtv);
 
        fdtv_unregister_rc(fdtv);
 
        kfree(fdtv);
-       return 0;
 }
 
 static void node_update(struct fw_unit *unit)
                .owner  = THIS_MODULE,
                .name   = "firedtv",
                .bus    = &fw_bus_type,
-               .probe  = node_probe,
-               .remove = node_remove,
        },
+       .probe    = node_probe,
        .update   = node_update,
+       .remove   = node_remove,
        .id_table = fdtv_id_table,
 };
 
 
  * last peer for a given fw_card triggering the destruction of the same
  * fw_serial for the same fw_card.
  */
-static int fwserial_probe(struct device *dev)
+static int fwserial_probe(struct fw_unit *unit,
+                         const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(dev);
        struct fw_serial *serial;
        int err;
 
  * specific fw_card). If this is the last peer being removed, then trigger
  * the destruction of the underlying TTYs.
  */
-static int fwserial_remove(struct device *dev)
+static void fwserial_remove(struct fw_unit *unit)
 {
-       struct fwtty_peer *peer = dev_get_drvdata(dev);
+       struct fwtty_peer *peer = dev_get_drvdata(&unit->device);
        struct fw_serial *serial = peer->serial;
        int i;
 
                kref_put(&serial->kref, fwserial_destroy);
        }
        mutex_unlock(&fwserial_list_mutex);
-
-       return 0;
 }
 
 /**
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = fwserial_probe,
-               .remove = fwserial_remove,
        },
+       .probe    = fwserial_probe,
        .update   = fwserial_update,
+       .remove   = fwserial_remove,
        .id_table = fwserial_id_table,
 };
 
 
 
 struct fw_driver {
        struct device_driver driver;
+       int (*probe)(struct fw_unit *unit, const struct ieee1394_device_id *id);
        /* Called when the parent device sits through a bus reset. */
        void (*update)(struct fw_unit *unit);
+       void (*remove)(struct fw_unit *unit);
        const struct ieee1394_device_id *id_table;
 };
 
 
        return 0;
 }
 
-static int isight_probe(struct device *unit_dev)
+static int isight_probe(struct fw_unit *unit,
+                       const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(unit_dev);
        struct fw_device *fw_dev = fw_parent_device(unit);
        struct snd_card *card;
        struct isight *isight;
        err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*isight), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, unit_dev);
+       snd_card_set_dev(card, &unit->device);
 
        isight = card->private_data;
        isight->card = card;
        if (err < 0)
                goto error;
 
-       dev_set_drvdata(unit_dev, isight);
+       dev_set_drvdata(&unit->device, isight);
 
        return 0;
 
        return err;
 }
 
-static int isight_remove(struct device *dev)
-{
-       struct isight *isight = dev_get_drvdata(dev);
-
-       isight_pcm_abort(isight);
-
-       snd_card_disconnect(isight->card);
-
-       mutex_lock(&isight->mutex);
-       isight_stop_streaming(isight);
-       mutex_unlock(&isight->mutex);
-
-       snd_card_free_when_closed(isight->card);
-
-       return 0;
-}
-
 static void isight_bus_reset(struct fw_unit *unit)
 {
        struct isight *isight = dev_get_drvdata(&unit->device);
        }
 }
 
+static void isight_remove(struct fw_unit *unit)
+{
+       struct isight *isight = dev_get_drvdata(&unit->device);
+
+       isight_pcm_abort(isight);
+
+       snd_card_disconnect(isight->card);
+
+       mutex_lock(&isight->mutex);
+       isight_stop_streaming(isight);
+       mutex_unlock(&isight->mutex);
+
+       snd_card_free_when_closed(isight->card);
+}
+
 static const struct ieee1394_device_id isight_id_table[] = {
        {
                .match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = isight_probe,
-               .remove = isight_remove,
        },
+       .probe    = isight_probe,
        .update   = isight_bus_reset,
+       .remove   = isight_remove,
        .id_table = isight_id_table,
 };
 
 
        kfree(scs->buffer);
 }
 
-static int scs_probe(struct device *unit_dev)
+static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
 {
-       struct fw_unit *unit = fw_unit(unit_dev);
        struct fw_device *fw_dev = fw_parent_device(unit);
        struct snd_card *card;
        struct scs *scs;
        err = snd_card_create(-16, NULL, THIS_MODULE, sizeof(*scs), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, unit_dev);
+       snd_card_set_dev(card, &unit->device);
 
        scs = card->private_data;
        scs->card = card;
        if (err < 0)
                goto err_card;
 
-       dev_set_drvdata(unit_dev, scs);
+       dev_set_drvdata(&unit->device, scs);
 
        return 0;
 
        return err;
 }
 
-static int scs_remove(struct device *dev)
+static void scs_update(struct fw_unit *unit)
 {
-       struct scs *scs = dev_get_drvdata(dev);
+       struct scs *scs = dev_get_drvdata(&unit->device);
+       __be64 data;
+
+       data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
+                          scs->hss_handler.offset);
+       snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
+                          HSS1394_ADDRESS, &data, 8);
+}
+
+static void scs_remove(struct fw_unit *unit)
+{
+       struct scs *scs = dev_get_drvdata(&unit->device);
 
        snd_card_disconnect(scs->card);
 
        tasklet_kill(&scs->tasklet);
 
        snd_card_free_when_closed(scs->card);
-
-       return 0;
-}
-
-static void scs_update(struct fw_unit *unit)
-{
-       struct scs *scs = dev_get_drvdata(&unit->device);
-       __be64 data;
-
-       data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
-                          scs->hss_handler.offset);
-       snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
-                          HSS1394_ADDRESS, &data, 8);
 }
 
 static const struct ieee1394_device_id scs_id_table[] = {
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = scs_probe,
-               .remove = scs_remove,
        },
+       .probe    = scs_probe,
        .update   = scs_update,
+       .remove   = scs_remove,
        .id_table = scs_id_table,
 };
 
 
        mutex_destroy(&fwspk->mutex);
 }
 
-static const struct device_info *fwspk_detect(struct fw_device *dev)
+static int fwspk_probe(struct fw_unit *unit,
+                      const struct ieee1394_device_id *id)
 {
-       static const struct device_info griffin_firewave = {
-               .driver_name = "FireWave",
-               .short_name  = "FireWave",
-               .long_name   = "Griffin FireWave Surround",
-               .pcm_constraints = firewave_constraints,
-               .mixer_channels = 6,
-               .mute_fb_id   = 0x01,
-               .volume_fb_id = 0x02,
-       };
-       static const struct device_info lacie_speakers = {
-               .driver_name = "FWSpeakers",
-               .short_name  = "FireWire Speakers",
-               .long_name   = "LaCie FireWire Speakers",
-               .pcm_constraints = lacie_speakers_constraints,
-               .mixer_channels = 1,
-               .mute_fb_id   = 0x01,
-               .volume_fb_id = 0x01,
-       };
-       struct fw_csr_iterator i;
-       int key, value;
-
-       fw_csr_iterator_init(&i, dev->config_rom);
-       while (fw_csr_iterator_next(&i, &key, &value))
-               if (key == CSR_VENDOR)
-                       switch (value) {
-                       case VENDOR_GRIFFIN:
-                               return &griffin_firewave;
-                       case VENDOR_LACIE:
-                               return &lacie_speakers;
-                       }
-
-       return NULL;
-}
-
-static int fwspk_probe(struct device *unit_dev)
-{
-       struct fw_unit *unit = fw_unit(unit_dev);
        struct fw_device *fw_dev = fw_parent_device(unit);
        struct snd_card *card;
        struct fwspk *fwspk;
        err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*fwspk), &card);
        if (err < 0)
                return err;
-       snd_card_set_dev(card, unit_dev);
+       snd_card_set_dev(card, &unit->device);
 
        fwspk = card->private_data;
        fwspk->card = card;
        mutex_init(&fwspk->mutex);
        fwspk->unit = fw_unit_get(unit);
-       fwspk->device_info = fwspk_detect(fw_dev);
-       if (!fwspk->device_info) {
-               err = -ENODEV;
-               goto err_unit;
-       }
+       fwspk->device_info = (const struct device_info *)id->driver_data;
 
        err = cmp_connection_init(&fwspk->connection, unit, 0);
        if (err < 0)
        if (err < 0)
                goto error;
 
-       dev_set_drvdata(unit_dev, fwspk);
+       dev_set_drvdata(&unit->device, fwspk);
 
        return 0;
 
        return err;
 }
 
-static int fwspk_remove(struct device *dev)
-{
-       struct fwspk *fwspk = dev_get_drvdata(dev);
-
-       amdtp_out_stream_pcm_abort(&fwspk->stream);
-       snd_card_disconnect(fwspk->card);
-
-       mutex_lock(&fwspk->mutex);
-       fwspk_stop_stream(fwspk);
-       mutex_unlock(&fwspk->mutex);
-
-       snd_card_free_when_closed(fwspk->card);
-
-       return 0;
-}
-
 static void fwspk_bus_reset(struct fw_unit *unit)
 {
        struct fwspk *fwspk = dev_get_drvdata(&unit->device);
        amdtp_out_stream_update(&fwspk->stream);
 }
 
+static void fwspk_remove(struct fw_unit *unit)
+{
+       struct fwspk *fwspk = dev_get_drvdata(&unit->device);
+
+       amdtp_out_stream_pcm_abort(&fwspk->stream);
+       snd_card_disconnect(fwspk->card);
+
+       mutex_lock(&fwspk->mutex);
+       fwspk_stop_stream(fwspk);
+       mutex_unlock(&fwspk->mutex);
+
+       snd_card_free_when_closed(fwspk->card);
+}
+
+static const struct device_info griffin_firewave = {
+       .driver_name = "FireWave",
+       .short_name  = "FireWave",
+       .long_name   = "Griffin FireWave Surround",
+       .pcm_constraints = firewave_constraints,
+       .mixer_channels = 6,
+       .mute_fb_id   = 0x01,
+       .volume_fb_id = 0x02,
+};
+
+static const struct device_info lacie_speakers = {
+       .driver_name = "FWSpeakers",
+       .short_name  = "FireWire Speakers",
+       .long_name   = "LaCie FireWire Speakers",
+       .pcm_constraints = lacie_speakers_constraints,
+       .mixer_channels = 1,
+       .mute_fb_id   = 0x01,
+       .volume_fb_id = 0x01,
+};
+
 static const struct ieee1394_device_id fwspk_id_table[] = {
        {
                .match_flags  = IEEE1394_MATCH_VENDOR_ID |
                .model_id     = 0x00f970,
                .specifier_id = SPECIFIER_1394TA,
                .version      = VERSION_AVC,
+               .driver_data  = (kernel_ulong_t)&griffin_firewave,
        },
        {
                .match_flags  = IEEE1394_MATCH_VENDOR_ID |
                .model_id     = 0x00f970,
                .specifier_id = SPECIFIER_1394TA,
                .version      = VERSION_AVC,
+               .driver_data  = (kernel_ulong_t)&lacie_speakers,
        },
        { }
 };
                .owner  = THIS_MODULE,
                .name   = KBUILD_MODNAME,
                .bus    = &fw_bus_type,
-               .probe  = fwspk_probe,
-               .remove = fwspk_remove,
        },
+       .probe    = fwspk_probe,
        .update   = fwspk_bus_reset,
+       .remove   = fwspk_remove,
        .id_table = fwspk_id_table,
 };