Implement device_quiesce. This method means 'you are about to be
unloaded, cleanup, or return ebusy of that's inconvenient.' The default module hanlder for newbus will now call this when we get a MOD_QUIESCE event, but in the future may call this at other times. This shouldn't change any actual behavior until drivers start to use it.
This commit is contained in:
parent
7432b7cc84
commit
d0d4cc63e3
@ -57,6 +57,11 @@ CODE {
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int null_quiesce(device_t dev)
|
||||
{
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -283,3 +288,29 @@ METHOD int suspend {
|
||||
METHOD int resume {
|
||||
device_t dev;
|
||||
} DEFAULT null_resume;
|
||||
|
||||
/**
|
||||
* @brief This is called when the driver is asked to quiesce itself.
|
||||
*
|
||||
* The driver should arrange for the orderly shutdown of this device.
|
||||
* All further access to the device should be curtailed. Soon there
|
||||
* will be a request to detach, but there won't necessarily be one.
|
||||
*
|
||||
* To include this method in a device driver, use a line like this
|
||||
* in the driver's method list:
|
||||
*
|
||||
* @code
|
||||
* KOBJMETHOD(device_quiesce, foo_quiesce)
|
||||
* @endcode
|
||||
*
|
||||
* @param dev the device being quiesced
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval non-zero an error occurred while attempting to quiesce the
|
||||
* device
|
||||
*
|
||||
* @see DEVICE_DETACH()
|
||||
*/
|
||||
METHOD int quiesce {
|
||||
device_t dev;
|
||||
} DEFAULT null_quiesce;
|
||||
|
@ -947,6 +947,71 @@ devclass_delete_driver(devclass_t busclass, driver_t *driver)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Quiesces a set of device drivers from a device class
|
||||
*
|
||||
* Quiesce a device driver from a devclass. This is normally called
|
||||
* automatically by DRIVER_MODULE().
|
||||
*
|
||||
* If the driver is currently attached to any devices,
|
||||
* devclass_quiesece_driver() will first attempt to quiesce each
|
||||
* device.
|
||||
*
|
||||
* @param dc the devclass to edit
|
||||
* @param driver the driver to unregister
|
||||
*/
|
||||
int
|
||||
devclass_quiesce_driver(devclass_t busclass, driver_t *driver)
|
||||
{
|
||||
devclass_t dc = devclass_find(driver->name);
|
||||
driverlink_t dl;
|
||||
device_t dev;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass)));
|
||||
|
||||
if (!dc)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Find the link structure in the bus' list of drivers.
|
||||
*/
|
||||
TAILQ_FOREACH(dl, &busclass->drivers, link) {
|
||||
if (dl->driver == driver)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dl) {
|
||||
PDEBUG(("%s not found in %s list", driver->name,
|
||||
busclass->name));
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Quiesce all devices. We iterate through all the devices in
|
||||
* the devclass of the driver and quiesce any which are using
|
||||
* the driver and which have a parent in the devclass which we
|
||||
* are quiescing.
|
||||
*
|
||||
* Note that since a driver can be in multiple devclasses, we
|
||||
* should not quiesce devices which are not children of
|
||||
* devices in the affected devclass.
|
||||
*/
|
||||
for (i = 0; i < dc->maxunit; i++) {
|
||||
if (dc->devices[i]) {
|
||||
dev = dc->devices[i];
|
||||
if (dev->driver == driver && dev->parent &&
|
||||
dev->parent->devclass == busclass) {
|
||||
if ((error = device_quiesce(dev)) != 0)
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@ -2313,6 +2378,32 @@ device_detach(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tells a driver to quiesce itself.
|
||||
*
|
||||
* This function is a wrapper around the DEVICE_QUIESCE() driver
|
||||
* method. If the call to DEVICE_QUIESCE() succeeds.
|
||||
*
|
||||
* @param dev the device to quiesce
|
||||
*
|
||||
* @retval 0 success
|
||||
* @retval ENXIO no driver was found
|
||||
* @retval ENOMEM memory allocation failure
|
||||
* @retval non-zero some other unix error code
|
||||
*/
|
||||
int
|
||||
device_quiesce(device_t dev)
|
||||
{
|
||||
|
||||
PDEBUG(("%s", DEVICENAME(dev)));
|
||||
if (dev->state == DS_BUSY)
|
||||
return (EBUSY);
|
||||
if (dev->state != DS_ATTACHED)
|
||||
return (0);
|
||||
|
||||
return (DEVICE_QUIESCE(dev));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Notify a device of system shutdown
|
||||
*
|
||||
@ -3561,6 +3652,16 @@ driver_module_handler(module_t mod, int what, void *arg)
|
||||
error = devclass_delete_driver(bus_devclass,
|
||||
dmd->dmd_driver);
|
||||
|
||||
if (!error && dmd->dmd_chainevh)
|
||||
error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
|
||||
break;
|
||||
case MOD_QUIESCE:
|
||||
PDEBUG(("Quiesce module: driver %s from bus %s",
|
||||
DRIVERNAME(dmd->dmd_driver),
|
||||
dmd->dmd_busname));
|
||||
error = devclass_quiesce_driver(bus_devclass,
|
||||
dmd->dmd_driver);
|
||||
|
||||
if (!error && dmd->dmd_chainevh)
|
||||
error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
|
||||
break;
|
||||
|
@ -357,6 +357,7 @@ int device_is_quiet(device_t dev);
|
||||
int device_print_prettyname(device_t dev);
|
||||
int device_printf(device_t dev, const char *, ...) __printflike(2, 3);
|
||||
int device_probe_and_attach(device_t dev);
|
||||
int device_quiesce(device_t dev);
|
||||
void device_quiet(device_t dev);
|
||||
void device_set_desc(device_t dev, const char* desc);
|
||||
void device_set_desc_copy(device_t dev, const char* desc);
|
||||
@ -388,6 +389,7 @@ void devclass_set_parent(devclass_t dc, devclass_t pdc);
|
||||
devclass_t devclass_get_parent(devclass_t dc);
|
||||
struct sysctl_ctx_list *devclass_get_sysctl_ctx(devclass_t dc);
|
||||
struct sysctl_oid *devclass_get_sysctl_tree(devclass_t dc);
|
||||
int devclass_quiesce_driver(devclass_t dc, kobj_class_t driver);
|
||||
|
||||
/*
|
||||
* Access functions for device resources.
|
||||
|
Loading…
Reference in New Issue
Block a user