Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 1 Feb 2016 23:07:31 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r295131 - in stable/10: contrib/mdocml lib lib/libdevctl share/mk sys/conf sys/dev/acpica sys/dev/pci sys/kern sys/sys usr.sbin usr.sbin/devctl
Message-ID:  <201602012307.u11N7Vom064597@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Mon Feb  1 23:07:31 2016
New Revision: 295131
URL: https://svnweb.freebsd.org/changeset/base/295131

Log:
  MFC 278320,278336,278830,285621:
  Add devctl(8): a utility for manipulating new-bus devices.  Note that
  this version does not include the 'suspend' and 'resume' commands
  present in HEAD as those depend on larger changes to the suspend and
  resume code in the kernel.
  
  278320:
  Add a new device control utility for new-bus devices called devctl.  This
  allows the user to request administrative changes to individual devices
  such as attach or detaching drivers or disabling and re-enabling devices.
  - Add a new /dev/devctl2 character device which uses ioctls for device
    requests.  The ioctls use a common 'struct devreq' which is somewhat
    similar to 'struct ifreq'.
  - The ioctls identify the device to operate on via a string.  This
    string can either by the device's name, or it can be a bus-specific
    address.  (For unattached devices, a bus address is the only way to
    locate a device.)  Bus drivers register an eventhandler to claim
    unrecognized device names that the driver recognizes as a valid address.
    Two buses currently support addresses: ACPI recognizes any device
    in the ACPI namespace via its full path starting with "\" and
    the PCI bus driver recognizes an address specification of
    'pci[<domain>:]<bus>:<slot>:<func>' (identical to the PCI selector
    strings supported by pciconf).
  - To make it easier to cut and paste, change the PnP location string
    in the PCI bus driver to output a full PCI selector string rather
    than 'slot=<slot> function=<func>'.
  - Add a devctl(3) interface in libdevctl which provides a wrapper around
    the ioctls and is the preferred interface for other userland code.
  - Add a devctl(8) program which is a simple wrapper around the requests
    supported by devctl(3).
  - Add a resource_unset_value() function that can be used to remove a
    hint from the kernel environment.  This is used to clear a
    hint.<driver>.<unit>.disabled hint when re-enabling a boot-time
    disabled device.
  
  278336:
  Unbreak the build (memchr is explicitly required by devctl(9) after r278320)
  
  278830:
  install the man page...
  
  285621:
  Fix formatting.
  
  Approved by:	re (marius)

Added:
  stable/10/lib/libdevctl/
     - copied from r278320, head/lib/libdevctl/
  stable/10/usr.sbin/devctl/
     - copied from r278320, head/usr.sbin/devctl/
Modified:
  stable/10/contrib/mdocml/lib.in
  stable/10/lib/Makefile
  stable/10/lib/libdevctl/devctl.3
  stable/10/lib/libdevctl/devctl.c
  stable/10/lib/libdevctl/devctl.h
  stable/10/share/mk/bsd.libnames.mk
  stable/10/sys/conf/files
  stable/10/sys/dev/acpica/acpi.c
  stable/10/sys/dev/pci/pci.c
  stable/10/sys/kern/subr_bus.c
  stable/10/sys/kern/subr_hints.c
  stable/10/sys/sys/bus.h
  stable/10/usr.sbin/Makefile
  stable/10/usr.sbin/devctl/Makefile
  stable/10/usr.sbin/devctl/devctl.8
  stable/10/usr.sbin/devctl/devctl.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/contrib/mdocml/lib.in
==============================================================================
--- stable/10/contrib/mdocml/lib.in	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/contrib/mdocml/lib.in	Mon Feb  1 23:07:31 2016	(r295131)
@@ -37,6 +37,7 @@ LINE("libcipher",	"FreeSec Crypt Library
 LINE("libcompat",	"Compatibility Library (libcompat, \\-lcompat)")
 LINE("libcrypt",	"Crypt Library (libcrypt, \\-lcrypt)")
 LINE("libcurses",	"Curses Library (libcurses, \\-lcurses)")
+LINE("libdevctl",	"Device Control Library (libdevctl, \\-ldevctl)")
 LINE("libdevinfo",	"Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
 LINE("libdevstat",	"Device Statistics Library (libdevstat, \\-ldevstat)")
 LINE("libdisk",		"Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")

Modified: stable/10/lib/Makefile
==============================================================================
--- stable/10/lib/Makefile	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/lib/Makefile	Mon Feb  1 23:07:31 2016	(r295131)
@@ -37,6 +37,7 @@ SUBDIR=	${SUBDIR_ORDERED} \
 	${_libcom_err} \
 	libcompat \
 	libcrypt \
+	libdevctl \
 	libdevinfo \
 	libdevstat \
 	libdpv \

Modified: stable/10/lib/libdevctl/devctl.3
==============================================================================
--- head/lib/libdevctl/devctl.3	Fri Feb  6 16:09:01 2015	(r278320)
+++ stable/10/lib/libdevctl/devctl.3	Mon Feb  1 23:07:31 2016	(r295131)
@@ -33,9 +33,7 @@
 .Nm devctl_attach ,
 .Nm devctl_detach ,
 .Nm devctl_disable ,
-.Nm devctl_enable ,
-.Nm devctl_resume ,
-.Nm devctl_suspend
+.Nm devctl_enable
 .Nd device control library
 .Sh LIBRARY
 .Lb libdevctl
@@ -50,10 +48,6 @@
 .Ft int
 .Fn devctl_enable "const char *device"
 .Ft int
-.Fn devctl_resume "const char *device"
-.Ft int
-.Fn devctl_suspend "const char *device"
-.Ft int
 .Fn devctl_set_driver "const char *device" "const char *driver" "bool force"
 .Sh DESCRIPTION
 The
@@ -125,16 +119,6 @@ function re-enables a disabled device.
 The device will probe and attach if a suitable device driver is found.
 .Pp
 The
-.Fn devctl_suspend
-function suspends a device.
-This may include placing the device in a reduced power state,
-but any device driver currently attached to the device will remain attached.
-.Pp
-The
-.Fn devctl_resume
-function resumes a suspended device to a fully working state.
-.Pp
-The
 .Fn devctl_set_driver
 function attaches a device driver named
 .Fa driver
@@ -150,7 +134,7 @@ the device will be detached from its cur
 attached to the new device driver.
 .Sh RETURN VALUES
 .Rv -std devctl_attach devctl_detach devctl_disable devctl_enable \
-devctl_suspend devctl_resume devctl_set_driver
+devctl_set_driver
 .Sh ERRORS
 In addition to specific errors noted below,
 all of the
@@ -235,26 +219,6 @@ does not support detaching.
 .El
 .Pp
 The
-.Fn devctl_suspend
-function may fail if:
-.Bl -tag -width Er
-.It Bq Er EBUSY
-The device is already suspended.
-.It Bq Er EINVAL
-The device to be suspended is the root bus device.
-.El
-.Pp
-The
-.Fn devctl_resume
-function may fail if:
-.Bl -tag -width Er
-.It Bq Er EINVAL
-The device is not suspended.
-.It Bq Er EINVAL
-The device to be resumed is the root bus device.
-.El
-.Pp
-The
 .Fn devctl_set_driver
 function may fail if:
 .Bl -tag -width Er
@@ -288,8 +252,3 @@ The
 .Nm
 library first appeared in
 .Fx 11.0 .
-.Sh BUGS
-If a device is suspended individually via
-.Fn devctl_suspend
-and the entire machine is subsequently suspended,
-the device will be resumed when the machine resumes.

Modified: stable/10/lib/libdevctl/devctl.c
==============================================================================
--- head/lib/libdevctl/devctl.c	Fri Feb  6 16:09:01 2015	(r278320)
+++ stable/10/lib/libdevctl/devctl.c	Mon Feb  1 23:07:31 2016	(r295131)
@@ -93,20 +93,6 @@ devctl_disable(const char *device, bool 
 }
 
 int
-devctl_suspend(const char *device)
-{
-
-	return (devctl_simple_request(DEV_SUSPEND, device, 0));
-}
-
-int
-devctl_resume(const char *device)
-{
-
-	return (devctl_simple_request(DEV_RESUME, device, 0));
-}
-
-int
 devctl_set_driver(const char *device, const char *driver, bool force)
 {
 	struct devreq req;

Modified: stable/10/lib/libdevctl/devctl.h
==============================================================================
--- head/lib/libdevctl/devctl.h	Fri Feb  6 16:09:01 2015	(r278320)
+++ stable/10/lib/libdevctl/devctl.h	Mon Feb  1 23:07:31 2016	(r295131)
@@ -35,8 +35,6 @@ int	devctl_attach(const char *device);
 int	devctl_detach(const char *device, bool force);
 int	devctl_enable(const char *device);
 int	devctl_disable(const char *device, bool force_detach);
-int	devctl_suspend(const char *device);
-int	devctl_resume(const char *device);
 int	devctl_set_driver(const char *device, const char *driver, bool force);
 
 #endif /* !__DEVCTL_H__ */

Modified: stable/10/share/mk/bsd.libnames.mk
==============================================================================
--- stable/10/share/mk/bsd.libnames.mk	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/share/mk/bsd.libnames.mk	Mon Feb  1 23:07:31 2016	(r295131)
@@ -38,6 +38,7 @@ LIBCRYPT?=	${DESTDIR}${LIBDIR}/libcrypt.
 LIBCRYPTO?=	${DESTDIR}${LIBDIR}/libcrypto.a
 LIBCTF?=	${DESTDIR}${LIBDIR}/libctf.a
 LIBCURSES?=	${DESTDIR}${LIBDIR}/libcurses.a
+LIBDEVCTL?=	${DESTDIR}${LIBDIR}/libdevctl.a
 LIBDEVINFO?=	${DESTDIR}${LIBDIR}/libdevinfo.a
 LIBDEVSTAT?=	${DESTDIR}${LIBDIR}/libdevstat.a
 LIBDIALOG?=	${DESTDIR}${LIBDIR}/libdialog.a

Modified: stable/10/sys/conf/files
==============================================================================
--- stable/10/sys/conf/files	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/sys/conf/files	Mon Feb  1 23:07:31 2016	(r295131)
@@ -3238,7 +3238,7 @@ libkern/jenkins_hash.c		standard
 libkern/murmur3_32.c		standard
 libkern/mcount.c		optional profiling-routine
 libkern/memcchr.c		standard
-libkern/memchr.c		optional fdt
+libkern/memchr.c		standard
 libkern/memcmp.c		standard
 libkern/qsort.c			standard
 libkern/qsort_r.c		standard

Modified: stable/10/sys/dev/acpica/acpi.c
==============================================================================
--- stable/10/sys/dev/acpica/acpi.c	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/sys/dev/acpica/acpi.c	Mon Feb  1 23:07:31 2016	(r295131)
@@ -100,6 +100,7 @@ int		acpi_quirks;
 /* Supported sleep states. */
 static BOOLEAN	acpi_sleep_states[ACPI_S_STATE_COUNT];
 
+static void	acpi_lookup(void *arg, const char *name, device_t *dev);
 static int	acpi_modevent(struct module *mod, int event, void *junk);
 static int	acpi_probe(device_t dev);
 static int	acpi_attach(device_t dev);
@@ -670,8 +671,10 @@ acpi_attach(device_t dev)
     /* Register ACPI again to pass the correct argument of pm_func. */
     power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc);
 
-    if (!acpi_disabled("bus"))
+    if (!acpi_disabled("bus")) {
+	EVENTHANDLER_REGISTER(dev_lookup, acpi_lookup, NULL, 1000);
 	acpi_probe_children(dev);
+    }
 
     /* Update all GPEs and enable runtime GPEs. */
     status = AcpiUpdateAllGpes();
@@ -3404,6 +3407,31 @@ acpi_disabled(char *subsys)
     return (0);
 }
 
+static void
+acpi_lookup(void *arg, const char *name, device_t *dev)
+{
+    ACPI_HANDLE handle;
+
+    if (*dev != NULL)
+	return;
+
+    /*
+     * Allow any handle name that is specified as an absolute path and
+     * starts with '\'.  We could restrict this to \_SB and friends,
+     * but see acpi_probe_children() for notes on why we scan the entire
+     * namespace for devices.
+     *
+     * XXX: The pathname argument to AcpiGetHandle() should be fixed to
+     * be const.
+     */
+    if (name[0] != '\\')
+	return;
+    if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, __DECONST(char *, name),
+	&handle)))
+	return;
+    *dev = acpi_get_device(handle);
+}
+
 /*
  * Control interface.
  *

Modified: stable/10/sys/dev/pci/pci.c
==============================================================================
--- stable/10/sys/dev/pci/pci.c	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/sys/dev/pci/pci.c	Mon Feb  1 23:07:31 2016	(r295131)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/limits.h>
 #include <sys/linker.h>
 #include <sys/fcntl.h>
 #include <sys/conf.h>
@@ -4924,8 +4925,8 @@ pci_child_location_str_method(device_t d
     size_t buflen)
 {
 
-	snprintf(buf, buflen, "slot=%d function=%d", pci_get_slot(child),
-	    pci_get_function(child));
+	snprintf(buf, buflen, "pci%d:%d:%d:%d", pci_get_domain(child),
+	    pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
 	return (0);
 }
 
@@ -4955,10 +4956,60 @@ pci_assign_interrupt_method(device_t dev
 	    cfg->intpin));
 }
 
+static void
+pci_lookup(void *arg, const char *name, device_t *dev)
+{
+	long val;
+	char *end;
+	int domain, bus, slot, func;
+
+	if (*dev != NULL)
+		return;
+
+	/*
+	 * Accept pciconf-style selectors of either pciD:B:S:F or
+	 * pciB:S:F.  In the latter case, the domain is assumed to
+	 * be zero.
+	 */
+	if (strncmp(name, "pci", 3) != 0)
+		return;
+	val = strtol(name + 3, &end, 10);
+	if (val < 0 || val > INT_MAX || *end != ':')
+		return;
+	domain = val;
+	val = strtol(end + 1, &end, 10);
+	if (val < 0 || val > INT_MAX || *end != ':')
+		return;
+	bus = val;
+	val = strtol(end + 1, &end, 10);
+	if (val < 0 || val > INT_MAX)
+		return;
+	slot = val;
+	if (*end == ':') {
+		val = strtol(end + 1, &end, 10);
+		if (val < 0 || val > INT_MAX || *end != '\0')
+			return;
+		func = val;
+	} else if (*end == '\0') {
+		func = slot;
+		slot = bus;
+		bus = domain;
+		domain = 0;
+	} else
+		return;
+
+	if (domain > PCI_DOMAINMAX || bus > PCI_BUSMAX || slot > PCI_SLOTMAX ||
+	    func > PCIE_ARI_FUNCMAX || (slot != 0 && func > PCI_FUNCMAX))
+		return;
+
+	*dev = pci_find_dbsf(domain, bus, slot, func);
+}
+
 static int
 pci_modevent(module_t mod, int what, void *arg)
 {
 	static struct cdev *pci_cdev;
+	static eventhandler_tag tag;
 
 	switch (what) {
 	case MOD_LOAD:
@@ -4967,9 +5018,13 @@ pci_modevent(module_t mod, int what, voi
 		pci_cdev = make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644,
 		    "pci");
 		pci_load_vendor_data();
+		tag = EVENTHANDLER_REGISTER(dev_lookup, pci_lookup, NULL,
+		    1000);
 		break;
 
 	case MOD_UNLOAD:
+		if (tag != NULL)
+			EVENTHANDLER_DEREGISTER(dev_lookup, tag);
 		destroy_dev(pci_cdev);
 		break;
 	}

Modified: stable/10/sys/kern/subr_bus.c
==============================================================================
--- stable/10/sys/kern/subr_bus.c	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/sys/kern/subr_bus.c	Mon Feb  1 23:07:31 2016	(r295131)
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/poll.h>
+#include <sys/priv.h>
 #include <sys/proc.h>
 #include <sys/condvar.h>
 #include <sys/queue.h>
@@ -147,6 +148,8 @@ struct device {
 static MALLOC_DEFINE(M_BUS, "bus", "Bus data structures");
 static MALLOC_DEFINE(M_BUS_SC, "bus-sc", "Bus data structures, softc");
 
+static void devctl2_init(void);
+
 #ifdef BUS_DEBUG
 
 static int bus_debug = 1;
@@ -434,6 +437,7 @@ devinit(void)
 	cv_init(&devsoftc.cv, "dev cv");
 	TAILQ_INIT(&devsoftc.devq);
 	knlist_init_mtx(&devsoftc.sel.si_note, &devsoftc.mtx);
+	devctl2_init();
 }
 
 static int
@@ -4998,3 +5002,229 @@ bus_free_resource(device_t dev, int type
 		return (0);
 	return (bus_release_resource(dev, type, rman_get_rid(r), r));
 }
+
+/*
+ * /dev/devctl2 implementation.  The existing /dev/devctl device has
+ * implicit semantics on open, so it could not be reused for this.
+ * Another option would be to call this /dev/bus?
+ */
+static int
+find_device(struct devreq *req, device_t *devp)
+{
+	device_t dev;
+
+	/*
+	 * First, ensure that the name is nul terminated.
+	 */
+	if (memchr(req->dr_name, '\0', sizeof(req->dr_name)) == NULL)
+		return (EINVAL);
+
+	/*
+	 * Second, try to find an attached device whose name matches
+	 * 'name'.
+	 */
+	TAILQ_FOREACH(dev, &bus_data_devices, devlink) {
+		if (dev->nameunit != NULL &&
+		    strcmp(dev->nameunit, req->dr_name) == 0) {
+			*devp = dev;
+			return (0);
+		}
+	}
+
+	/* Finally, give device enumerators a chance. */
+	dev = NULL;
+	EVENTHANDLER_INVOKE(dev_lookup, req->dr_name, &dev);
+	if (dev == NULL)
+		return (ENOENT);
+	*devp = dev;
+	return (0);
+}
+
+static bool
+driver_exists(struct device *bus, const char *driver)
+{
+	devclass_t dc;
+
+	for (dc = bus->devclass; dc != NULL; dc = dc->parent) {
+		if (devclass_find_driver_internal(dc, driver) != NULL)
+			return (true);
+	}
+	return (false);
+}
+
+static int
+devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
+    struct thread *td)
+{
+	struct devreq *req;
+	device_t dev;
+	int error, old;
+
+	/* Locate the device to control. */
+	mtx_lock(&Giant);
+	req = (struct devreq *)data;
+	switch (cmd) {
+	case DEV_ATTACH:
+	case DEV_DETACH:
+	case DEV_ENABLE:
+	case DEV_DISABLE:
+	case DEV_SET_DRIVER:
+		error = priv_check(td, PRIV_DRIVER);
+		if (error == 0)
+			error = find_device(req, &dev);
+		break;
+	default:
+		error = ENOTTY;
+		break;
+	}
+	if (error) {
+		mtx_unlock(&Giant);
+		return (error);
+	}
+
+	/* Perform the requested operation. */
+	switch (cmd) {
+	case DEV_ATTACH:
+		if (device_is_attached(dev) && (dev->flags & DF_REBID) == 0)
+			error = EBUSY;
+		else if (!device_is_enabled(dev))
+			error = ENXIO;
+		else
+			error = device_probe_and_attach(dev);
+		break;
+	case DEV_DETACH:
+		if (!device_is_attached(dev)) {
+			error = ENXIO;
+			break;
+		}
+		if (!(req->dr_flags & DEVF_FORCE_DETACH)) {
+			error = device_quiesce(dev);
+			if (error)
+				break;
+		}
+		error = device_detach(dev);
+		break;
+	case DEV_ENABLE:
+		if (device_is_enabled(dev)) {
+			error = EBUSY;
+			break;
+		}
+
+		/*
+		 * If the device has been probed but not attached (e.g.
+		 * when it has been disabled by a loader hint), just
+		 * attach the device rather than doing a full probe.
+		 */
+		device_enable(dev);
+		if (device_is_alive(dev)) {
+			/*
+			 * If the device was disabled via a hint, clear
+			 * the hint.
+			 */
+			if (resource_disabled(dev->driver->name, dev->unit))
+				resource_unset_value(dev->driver->name,
+				    dev->unit, "disabled");
+			error = device_attach(dev);
+		} else
+			error = device_probe_and_attach(dev);
+		break;
+	case DEV_DISABLE:
+		if (!device_is_enabled(dev)) {
+			error = ENXIO;
+			break;
+		}
+
+		if (!(req->dr_flags & DEVF_FORCE_DETACH)) {
+			error = device_quiesce(dev);
+			if (error)
+				break;
+		}
+
+		/*
+		 * Force DF_FIXEDCLASS on around detach to preserve
+		 * the existing name.
+		 */
+		old = dev->flags;
+		dev->flags |= DF_FIXEDCLASS;
+		error = device_detach(dev);
+		if (!(old & DF_FIXEDCLASS))
+			dev->flags &= ~DF_FIXEDCLASS;
+		if (error == 0)
+			device_disable(dev);
+		break;
+	case DEV_SET_DRIVER: {
+		devclass_t dc;
+		char driver[128];
+
+		error = copyinstr(req->dr_data, driver, sizeof(driver), NULL);
+		if (error)
+			break;
+		if (driver[0] == '\0') {
+			error = EINVAL;
+			break;
+		}
+		if (dev->devclass != NULL &&
+		    strcmp(driver, dev->devclass->name) == 0)
+			/* XXX: Could possibly force DF_FIXEDCLASS on? */
+			break;
+
+		/*
+		 * Scan drivers for this device's bus looking for at
+		 * least one matching driver.
+		 */
+		if (dev->parent == NULL) {
+			error = EINVAL;
+			break;
+		}
+		if (!driver_exists(dev->parent, driver)) {
+			error = ENOENT;
+			break;
+		}
+		dc = devclass_create(driver);
+		if (dc == NULL) {
+			error = ENOMEM;
+			break;
+		}
+
+		/* Detach device if necessary. */
+		if (device_is_attached(dev)) {
+			if (req->dr_flags & DEVF_SET_DRIVER_DETACH)
+				error = device_detach(dev);
+			else
+				error = EBUSY;
+			if (error)
+				break;
+		}
+
+		/* Clear any previously-fixed device class and unit. */
+		if (dev->flags & DF_FIXEDCLASS)
+			devclass_delete_device(dev->devclass, dev);
+		dev->flags |= DF_WILDCARD;
+		dev->unit = -1;
+
+		/* Force the new device class. */
+		error = devclass_add_device(dc, dev);
+		if (error)
+			break;
+		dev->flags |= DF_FIXEDCLASS;
+		error = device_probe_and_attach(dev);
+		break;
+	}
+	}
+	mtx_unlock(&Giant);
+	return (error);
+}
+
+static struct cdevsw devctl2_cdevsw = {
+	.d_version =	D_VERSION,
+	.d_ioctl =	devctl2_ioctl,
+	.d_name =	"devctl2",
+};
+
+static void
+devctl2_init(void)
+{
+
+	make_dev_credf(MAKEDEV_ETERNAL, &devctl2_cdevsw, 0, NULL,
+	    UID_ROOT, GID_WHEEL, 0600, "devctl2");
+}

Modified: stable/10/sys/kern/subr_hints.c
==============================================================================
--- stable/10/sys/kern/subr_hints.c	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/sys/kern/subr_hints.c	Mon Feb  1 23:07:31 2016	(r295131)
@@ -461,3 +461,31 @@ resource_disabled(const char *name, int 
 	       return (0);
 	return (value);
 }
+
+/*
+ * Clear a value associated with a device by removing it from
+ * the kernel environment.  This only removes a hint for an
+ * exact unit.
+ */
+int
+resource_unset_value(const char *name, int unit, const char *resname)
+{
+	char varname[128];
+	const char *retname, *retvalue;
+	int error, line;
+	size_t len;
+
+	line = 0;
+	error = resource_find(&line, NULL, name, &unit, resname, NULL,
+	    &retname, NULL, NULL, NULL, NULL, &retvalue);
+	if (error)
+		return (error);
+
+	retname -= strlen("hint.");
+	len = retvalue - retname - 1;
+	if (len > sizeof(varname) - 1)
+		return (ENAMETOOLONG);
+	memcpy(varname, retname, len);
+	varname[len] = '\0';
+	return (unsetenv(varname));
+}

Modified: stable/10/sys/sys/bus.h
==============================================================================
--- stable/10/sys/sys/bus.h	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/sys/sys/bus.h	Mon Feb  1 23:07:31 2016	(r295131)
@@ -31,6 +31,7 @@
 
 #include <machine/_limits.h>
 #include <sys/_bus_dma.h>
+#include <sys/ioccom.h>
 
 /**
  * @defgroup NEWBUS newbus - a generic framework for managing devices
@@ -75,9 +76,43 @@ struct u_device {
 	/* XXX more driver info? */
 };
 
+/**
+ * @brief Device request structure used for ioctl's.
+ *
+ * Used for ioctl's on /dev/devctl2.  All device ioctl's
+ * must have parameter definitions which begin with dr_name.
+ */
+struct devreq_buffer {
+	void	*buffer;
+	size_t	length;
+};
+
+struct devreq {
+	char		dr_name[128];
+	int		dr_flags;		/* request-specific flags */
+	union {
+		struct devreq_buffer dru_buffer;
+		void	*dru_data;
+	} dr_dru;
+#define	dr_buffer	dr_dru.dru_buffer	/* variable-sized buffer */
+#define	dr_data		dr_dru.dru_data		/* fixed-size buffer */
+};
+
+#define	DEV_ATTACH	_IOW('D', 1, struct devreq)
+#define	DEV_DETACH	_IOW('D', 2, struct devreq)
+#define	DEV_ENABLE	_IOW('D', 3, struct devreq)
+#define	DEV_DISABLE	_IOW('D', 4, struct devreq)
+#define	DEV_SET_DRIVER	_IOW('D', 7, struct devreq)
+
+/* Flags for DEV_DETACH and DEV_DISABLE. */
+#define	DEVF_FORCE_DETACH	0x0000001
+
+/* Flags for DEV_SET_DRIVER. */
+#define	DEVF_SET_DRIVER_DETACH	0x0000001	/* Detach existing driver. */
+
 #ifdef _KERNEL
 
-#include <sys/queue.h>
+#include <sys/eventhandler.h>
 #include <sys/kobj.h>
 
 /**
@@ -94,6 +129,14 @@ void devctl_queue_data_f(char *__data, i
 void devctl_queue_data(char *__data);
 
 /**
+ * Device name parsers.  Hook to allow device enumerators to map
+ * scheme-specific names to a device.
+ */
+typedef void (*dev_lookup_fn)(void *arg, const char *name,
+    device_t *result);
+EVENTHANDLER_DECLARE(dev_lookup, dev_lookup_fn);
+
+/**
  * @brief A device driver (included mainly for compatibility with
  * FreeBSD 4.x).
  */
@@ -454,6 +497,7 @@ struct sysctl_oid *device_get_sysctl_tre
 int	device_is_alive(device_t dev);	/* did probe succeed? */
 int	device_is_attached(device_t dev);	/* did attach succeed? */
 int	device_is_enabled(device_t dev);
+int	device_is_suspended(device_t dev);
 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);
@@ -517,6 +561,8 @@ int	resource_set_long(const char *name, 
 			  long value);
 int	resource_set_string(const char *name, int unit, const char *resname,
 			    const char *value);
+int	resource_unset_value(const char *name, int unit, const char *resname);
+
 /*
  * Functions for maintaining and checking consistency of
  * bus information exported to userspace.

Modified: stable/10/usr.sbin/Makefile
==============================================================================
--- stable/10/usr.sbin/Makefile	Mon Feb  1 22:16:41 2016	(r295130)
+++ stable/10/usr.sbin/Makefile	Mon Feb  1 23:07:31 2016	(r295131)
@@ -20,6 +20,7 @@ SUBDIR=	adduser \
 	ctld \
 	daemon \
 	dconschat \
+	devctl \
 	devinfo \
 	digictl \
 	diskinfo \

Modified: stable/10/usr.sbin/devctl/Makefile
==============================================================================
--- head/usr.sbin/devctl/Makefile	Fri Feb  6 16:09:01 2015	(r278320)
+++ stable/10/usr.sbin/devctl/Makefile	Mon Feb  1 23:07:31 2016	(r295131)
@@ -2,8 +2,8 @@
 
 PROG=	devctl
 MAN=	devctl.8
-MAN=
 
-LIBADD=	devctl
+DPADD=	${LIBDEVCTL}
+LDADD=	-ldevctl
 
 .include <bsd.prog.mk>

Modified: stable/10/usr.sbin/devctl/devctl.8
==============================================================================
--- head/usr.sbin/devctl/devctl.8	Fri Feb  6 16:09:01 2015	(r278320)
+++ stable/10/usr.sbin/devctl/devctl.8	Mon Feb  1 23:07:31 2016	(r295131)
@@ -47,12 +47,6 @@
 .Cm enable
 .Ar device
 .Nm
-.Cm suspend
-.Ar device
-.Nm
-.Cm resume
-.Ar device
-.Nm
 .Cm set driver
 .Op Fl f
 .Ar device driver
@@ -106,11 +100,6 @@ Enable a device.
 The device will probe and attach if a suitable device driver is found.
 Note that this can re-enable a device disabled at boot time via a
 loader tunable.
-.It Cm suspend Ar device
-Suspend a device.
-This may include placing the device in a reduced power state.
-.It Cm resume device
-Resume a suspended device to a fully working state.
 .It Xo Cm set driver
 .Op Fl f
 .Ar device driver

Modified: stable/10/usr.sbin/devctl/devctl.c
==============================================================================
--- head/usr.sbin/devctl/devctl.c	Fri Feb  6 16:09:01 2015	(r278320)
+++ stable/10/usr.sbin/devctl/devctl.c	Mon Feb  1 23:07:31 2016	(r295131)
@@ -70,13 +70,11 @@ DEVCTL_TABLE(top, set);
 static void
 usage(void)
 {
-	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
 	    "usage: devctl attach device",
 	    "       devctl detach [-f] device",
 	    "       devctl disable [-f] device",
 	    "       devctl enable device",
-	    "       devctl suspend device",
-	    "       devctl resume device",
 	    "       devctl set driver [-f] device driver");
 	exit(1);
 }
@@ -201,30 +199,6 @@ enable(int ac, char **av)
 }
 DEVCTL_COMMAND(top, enable, enable);
 
-static int
-suspend(int ac, char **av)
-{
-
-	if (ac != 2)
-		usage();
-	if (devctl_suspend(av[1]) < 0)
-		err(1, "Failed to suspend %s", av[1]);
-	return (0);
-}
-DEVCTL_COMMAND(top, suspend, suspend);
-
-static int
-resume(int ac, char **av)
-{
-
-	if (ac != 2)
-		usage();
-	if (devctl_resume(av[1]) < 0)
-		err(1, "Failed to resume %s", av[1]);
-	return (0);
-}
-DEVCTL_COMMAND(top, resume, resume);
-
 static void
 set_driver_usage(void)
 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201602012307.u11N7Vom064597>