diff options
author | joerg <joerg@FreeBSD.org> | 2001-07-04 22:10:33 +0000 |
---|---|---|
committer | joerg <joerg@FreeBSD.org> | 2001-07-04 22:10:33 +0000 |
commit | 7d47b95265432e1c42e4bfe4943f3d2ab0eaa4d8 (patch) | |
tree | 6ae68c1863a90b6b9ad11aa58803fdbac97aaec6 /sys/dev/fdc | |
parent | 04b5406a227d99e550191eb7d24720be3991a9bd (diff) | |
download | FreeBSD-src-7d47b95265432e1c42e4bfe4943f3d2ab0eaa4d8.zip FreeBSD-src-7d47b95265432e1c42e4bfe4943f3d2ab0eaa4d8.tar.gz |
More cleanup when detaching. Clone device entries will now be
destroyed properly (otherwise bad things would happen after a clone
dev had been created, and the module was kldunloaded). Allocated
children that have not successfully probed are being deleted again
(otherwise fd0 and fd1 have always been allocated, even if only
fd0 was acutally present, and fd1 even survived kldunloading the
module).
Still, kldunloading leaves remnants of the previously existing devices
intact. Why doesn't it destroy all the devices? As a consequence,
since dev->descr now points into no longer allocated memory, the
system panics deep inside printf(9) when running devinfo(1) after
kldunloading the module. Ideas sought...
Also, when kldloading the module on a hints-populated isab0, this bus
somehow has already created an fdc0 entry (a dummy) so the load
attempt fails and will register fdc1 instead. What are those dummy
entries for? Loading the module from the bootloader works, and it
can be unloaded an re-loaded then later.
Diffstat (limited to 'sys/dev/fdc')
-rw-r--r-- | sys/dev/fdc/fdc.c | 58 |
1 files changed, 41 insertions, 17 deletions
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index 5e95d0c..da45cb2 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -181,6 +181,8 @@ struct fd_data { struct devstat device_stats; eventhandler_tag clonetag; dev_t masterdev; +#define NCLONEDEVS 10 /* must match the table below */ + dev_t clonedevs[NCLONEDEVS]; device_t dev; fdu_t fdu; }; @@ -832,8 +834,9 @@ static int fdc_attach(device_t dev) { struct fdc_data *fdc; - int i, error, dunit; const char *name, *dname; + device_t *children; + int i, error, dunit, nchildren; fdc = device_get_softc(dev); error = fdc_alloc_resources(fdc); @@ -875,7 +878,17 @@ fdc_attach(device_t dev) while ((resource_find_match(&i, &dname, &dunit, "at", name)) == 0) fdc_add_child(dev, dname, dunit); - return (bus_generic_attach(dev)); + if ((error = bus_generic_attach(dev)) != 0) + return (error); + + /* Now remove all children not successfully probed (if any). */ + if ((error = device_get_children(dev, &children, &nchildren)) != 0) + return (error); + for (i = 0; i < nchildren; i++) + if (!device_is_alive(children[i])) + device_delete_child(dev, children[i]); + + return (0); } static int @@ -949,14 +962,10 @@ static struct { int minor; int link; } fd_suffix[] = { - { "a", 0, 1 }, - { "b", 0, 1 }, - { "c", 0, 1 }, - { "d", 0, 1 }, - { "e", 0, 1 }, - { "f", 0, 1 }, - { "g", 0, 1 }, - { "h", 0, 1 }, + /* + * Genuine clone devices must come first, and their number must + * match NCLONEDEVS above. + */ { ".1720", 1, 0 }, { ".1480", 2, 0 }, { ".1440", 3, 0 }, @@ -967,15 +976,24 @@ static struct { { ".360", 8, 0 }, { ".640", 9, 0 }, { ".1232", 10, 0 }, + { "a", 0, 1 }, + { "b", 0, 1 }, + { "c", 0, 1 }, + { "d", 0, 1 }, + { "e", 0, 1 }, + { "f", 0, 1 }, + { "g", 0, 1 }, + { "h", 0, 1 }, { 0, 0 } }; static void -fd_clone (void *arg, char *name, int namelen, dev_t *dev) +fd_clone(void *arg, char *name, int namelen, dev_t *dev) { + struct fd_data *fd; int u, d, i; char *n; - dev_t pdev; + fd = (struct fd_data *)arg; if (*dev != NODEV) return; if (dev_stdclone(name, &n, "fd", &u) != 2) @@ -991,9 +1009,9 @@ fd_clone (void *arg, char *name, int namelen, dev_t *dev) if (fd_suffix[i].link == 0) { *dev = make_dev(&fd_cdevsw, (u << 6) + d, UID_ROOT, GID_OPERATOR, 0640, name); + fd->clonedevs[i] = *dev; } else { - pdev = makedev(fd_cdevsw.d_maj, (u << 6) + d); - *dev = make_dev_alias(pdev, name); + *dev = make_dev_alias(fd->masterdev, name); } } @@ -1148,15 +1166,18 @@ fd_attach(device_t dev) { struct fd_data *fd; static int cdevsw_add_done; + int i; if (!cdevsw_add_done) { cdevsw_add(&fd_cdevsw); /* XXX */ cdevsw_add_done = 1; } fd = device_get_softc(dev); - fd->clonetag = EVENTHANDLER_REGISTER(dev_clone, fd_clone, 0, 1000); + fd->clonetag = EVENTHANDLER_REGISTER(dev_clone, fd_clone, fd, 1000); fd->masterdev = make_dev(&fd_cdevsw, fd->fdu << 6, UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu); + for (i = 0; i < NCLONEDEVS; i++) + fd->clonedevs[i] = NODEV; devstat_add_entry(&fd->device_stats, device_get_name(dev), device_get_unit(dev), 0, DEVSTAT_NO_ORDERED_TAGS, DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER, @@ -1168,14 +1189,17 @@ static int fd_detach(device_t dev) { struct fd_data *fd; + int i; fd = device_get_softc(dev); + untimeout(fd_turnoff, fd, fd->toffhandle); devstat_remove_entry(&fd->device_stats); destroy_dev(fd->masterdev); + for (i = 0; i < NCLONEDEVS; i++) + if (fd->clonedevs[i] != NODEV) + destroy_dev(fd->clonedevs[i]); cdevsw_remove(&fd_cdevsw); - /* XXX need to destroy cloned devs as well */ EVENTHANDLER_DEREGISTER(dev_clone, fd->clonetag); - untimeout(fd_turnoff, fd, fd->toffhandle); return (0); } |