--- a/sys/dev/misc/pps/pps.c +++ b/sys/dev/misc/pps/pps.c @@ -36,6 +36,7 @@ int pps_open; struct ppb_device pps_dev; struct pps_state pps; + cdev_t pps_cdev; struct resource *intr_resource; /* interrupt resource */ void *intr_cookie; /* interrupt registration cookie */ @@ -55,6 +56,7 @@ static d_open_t ppsopen; static d_close_t ppsclose; static d_ioctl_t ppsioctl; +static int ppsdetach(device_t); static struct dev_ops pps_ops = { { PPS_NAME, 0, 0 }, @@ -100,8 +102,26 @@ return (ENXIO); unit = device_get_unit(ppsdev); - make_dev(&pps_ops, unit, UID_ROOT, GID_WHEEL, - 0644, PPS_NAME "%d", unit); + sc->pps_cdev = make_dev(&pps_ops, unit, UID_ROOT, GID_WHEEL, + 0644, PPS_NAME "%d", unit); + return (0); +} + +static int +ppsdetach(device_t ppsdev) +{ + struct pps_data *sc = DEVTOSOFTC(ppsdev); + + /* + * Refuse to detach while a client has us open: ppsopen() owns the + * ppbus and a registered interrupt handler at that point + * (pps.c:118-133), and ppb_release_bus() is the only thing that + * tears that registration down (ppbconf.c:514-521). + */ + if (sc->pps_open) + return (EBUSY); + if (sc->pps_cdev != NULL) + destroy_dev(sc->pps_cdev); return (0); } @@ -192,6 +212,7 @@ DEVMETHOD(device_identify, bus_generic_identify), DEVMETHOD(device_probe, ppsprobe), DEVMETHOD(device_attach, ppsattach), + DEVMETHOD(device_detach, ppsdetach), DEVMETHOD_END };