mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Implement 'devctl clear driver' to undo a previous 'devctl set driver'.
Add a new 'clear driver' command for devctl along with the accompanying ioctl and devctl_clear_driver() library routine to reset a device to use a wildcard devclass instead of a fixed devclass. This can be used to undo a previous 'set driver' command. After the device's name has been reset to permit wildcard names, it is reprobed so that it can attach to newly-available (to it) device drivers. MFC after: 1 month Sponsored by: Chelsio Communications
This commit is contained in:
parent
a3d5eb2481
commit
e05ec081fe
7 changed files with 132 additions and 5 deletions
|
|
@ -25,12 +25,13 @@
|
|||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 27, 2016
|
||||
.Dd August 29, 2016
|
||||
.Dt DEVCTL 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm devctl ,
|
||||
.Nm devctl_attach ,
|
||||
.Nm devctl_clear_driver ,
|
||||
.Nm devctl_delete ,
|
||||
.Nm devctl_detach ,
|
||||
.Nm devctl_disable ,
|
||||
|
|
@ -47,6 +48,8 @@
|
|||
.Ft int
|
||||
.Fn devctl_attach "const char *device"
|
||||
.Ft int
|
||||
.Fn devctl_clear_driver "const char *device" "bool force"
|
||||
.Ft int
|
||||
.Fn devctl_delete "const char *device" "bool force"
|
||||
.Ft int
|
||||
.Fn devctl_detach "const char *device" "bool force"
|
||||
|
|
@ -166,12 +169,30 @@ the device will be detached from its current device driver before it is
|
|||
attached to the new device driver.
|
||||
.Pp
|
||||
The
|
||||
.Fn devctl_clear_driver
|
||||
function resets a device so that it can be attached to any valid device
|
||||
driver rather than only drivers with a previously specified name.
|
||||
This function is used to undo a previous call to
|
||||
.Fn devctl_set_driver .
|
||||
If the device is already attached and
|
||||
.Fa force
|
||||
is false,
|
||||
the request will fail.
|
||||
If the device is already attached and
|
||||
.Fa force
|
||||
is true,
|
||||
the device will be detached from its current device driver.
|
||||
After the device's name is reset,
|
||||
it is reprobed and attached to a suitable device driver if one is found.
|
||||
.Pp
|
||||
The
|
||||
.Fn devctl_rescan
|
||||
function rescans a bus device checking for devices that have been added or
|
||||
removed.
|
||||
.Sh RETURN VALUES
|
||||
.Rv -std devctl_attach devctl_delete devctl_detach devctl_disable \
|
||||
devctl_enable devctl_suspend devctl_rescan devctl_resume devctl_set_driver
|
||||
.Rv -std devctl_attach devctl_clear_driver devctl_delete devctl_detach \
|
||||
devctl_disable devctl_enable devctl_suspend devctl_rescan devctl_resume \
|
||||
devctl_set_driver
|
||||
.Sh ERRORS
|
||||
In addition to specific errors noted below,
|
||||
all of the
|
||||
|
|
@ -302,6 +323,24 @@ The new device driver failed to attach.
|
|||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn devctl_clear_driver
|
||||
function may fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EBUSY
|
||||
The device is currently attached to a device driver and
|
||||
.Fa force
|
||||
is false.
|
||||
.It Bq Er EBUSY
|
||||
The current device driver for
|
||||
.Fa device
|
||||
is busy and cannot detach at this time.
|
||||
.It Bq Er EINVAL
|
||||
The device is not configured for a specific device driver name.
|
||||
.It Bq Er ENXIO
|
||||
The device driver chosen after reprobing failed to attach.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn devctl_rescan
|
||||
function may fail if:
|
||||
.Bl -tag -width Er
|
||||
|
|
|
|||
|
|
@ -123,6 +123,14 @@ devctl_set_driver(const char *device, const char *driver, bool force)
|
|||
return (devctl_request(DEV_SET_DRIVER, &req));
|
||||
}
|
||||
|
||||
int
|
||||
devctl_clear_driver(const char *device, bool force)
|
||||
{
|
||||
|
||||
return (devctl_simple_request(DEV_CLEAR_DRIVER, device, force ?
|
||||
DEVF_CLEAR_DRIVER_DETACH : 0));
|
||||
}
|
||||
|
||||
int
|
||||
devctl_rescan(const char *device)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ 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);
|
||||
int devctl_clear_driver(const char *device, bool force);
|
||||
int devctl_rescan(const char *device);
|
||||
int devctl_delete(const char *device, bool force);
|
||||
|
||||
|
|
|
|||
|
|
@ -5349,6 +5349,7 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
|
|||
case DEV_SUSPEND:
|
||||
case DEV_RESUME:
|
||||
case DEV_SET_DRIVER:
|
||||
case DEV_CLEAR_DRIVER:
|
||||
case DEV_RESCAN:
|
||||
case DEV_DELETE:
|
||||
error = priv_check(td, PRIV_DRIVER);
|
||||
|
|
@ -5514,6 +5515,25 @@ devctl2_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
|
|||
error = device_probe_and_attach(dev);
|
||||
break;
|
||||
}
|
||||
case DEV_CLEAR_DRIVER:
|
||||
if (!(dev->flags & DF_FIXEDCLASS)) {
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
if (device_is_attached(dev)) {
|
||||
if (req->dr_flags & DEVF_CLEAR_DRIVER_DETACH)
|
||||
error = device_detach(dev);
|
||||
else
|
||||
error = EBUSY;
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
dev->flags &= ~DF_FIXEDCLASS;
|
||||
dev->flags |= DF_WILDCARD;
|
||||
devclass_delete_device(dev->devclass, dev);
|
||||
error = device_probe_and_attach(dev);
|
||||
break;
|
||||
case DEV_RESCAN:
|
||||
if (!device_is_attached(dev)) {
|
||||
error = ENXIO;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ struct devreq {
|
|||
#define DEV_SUSPEND _IOW('D', 5, struct devreq)
|
||||
#define DEV_RESUME _IOW('D', 6, struct devreq)
|
||||
#define DEV_SET_DRIVER _IOW('D', 7, struct devreq)
|
||||
#define DEV_CLEAR_DRIVER _IOW('D', 8, struct devreq)
|
||||
#define DEV_RESCAN _IOW('D', 9, struct devreq)
|
||||
#define DEV_DELETE _IOW('D', 10, struct devreq)
|
||||
|
||||
|
|
@ -126,6 +127,9 @@ struct devreq {
|
|||
/* Flags for DEV_SET_DRIVER. */
|
||||
#define DEVF_SET_DRIVER_DETACH 0x0000001 /* Detach existing driver. */
|
||||
|
||||
/* Flags for DEV_CLEAR_DRIVER. */
|
||||
#define DEVF_CLEAR_DRIVER_DETACH 0x0000001 /* Detach existing driver. */
|
||||
|
||||
/* Flags for DEV_DELETE. */
|
||||
#define DEVF_FORCE_DELETE 0x0000001
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 27, 2016
|
||||
.Dd August 29, 2016
|
||||
.Dt DEVCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
|
@ -36,6 +36,10 @@
|
|||
.Cm attach
|
||||
.Ar device
|
||||
.Nm
|
||||
.Cm clear driver
|
||||
.Op Fl f
|
||||
.Ar device
|
||||
.Nm
|
||||
.Cm detach
|
||||
.Op Fl f
|
||||
.Ar device
|
||||
|
|
@ -133,6 +137,21 @@ If the device is already attached to a device driver and the
|
|||
.Fl f
|
||||
flag is not specified,
|
||||
the device will not be changed.
|
||||
.It Xo Cm clear driver
|
||||
.Op Fl f
|
||||
.Ar device
|
||||
.Xc
|
||||
Clear a previously-forced driver name so that the device is able to use any
|
||||
valid device driver.
|
||||
After the previous name has been cleared,
|
||||
the device is reprobed so that other device drivers may attach to it.
|
||||
This can be used to undo an earlier
|
||||
.Cm set driver
|
||||
command.
|
||||
If the device is currently attached to a device driver and the
|
||||
.Fl f
|
||||
flag is not specified,
|
||||
the device will not be changed.
|
||||
.It Cm rescan Ar device
|
||||
Rescan a bus device checking for devices that have been added or
|
||||
removed.
|
||||
|
|
|
|||
|
|
@ -65,12 +65,13 @@ static int devctl_table_handler(struct devctl_command **start,
|
|||
|
||||
SET_DECLARE(DEVCTL_DATASET(top), struct devctl_command);
|
||||
|
||||
DEVCTL_TABLE(top, clear);
|
||||
DEVCTL_TABLE(top, set);
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n%s\n%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%s\n%s\n%s\n%s\n%s\n",
|
||||
"usage: devctl attach device",
|
||||
" devctl detach [-f] device",
|
||||
" devctl disable [-f] device",
|
||||
|
|
@ -78,6 +79,7 @@ usage(void)
|
|||
" devctl suspend device",
|
||||
" devctl resume device",
|
||||
" devctl set driver [-f] device driver",
|
||||
" devctl clear driver [-f] device",
|
||||
" devctl rescan device",
|
||||
" devctl delete [-f] device");
|
||||
exit(1);
|
||||
|
|
@ -261,6 +263,40 @@ set_driver(int ac, char **av)
|
|||
}
|
||||
DEVCTL_COMMAND(set, driver, set_driver);
|
||||
|
||||
static void
|
||||
clear_driver_usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "usage: devctl clear driver [-f] device\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int
|
||||
clear_driver(int ac, char **av)
|
||||
{
|
||||
bool force;
|
||||
int ch;
|
||||
|
||||
force = false;
|
||||
while ((ch = getopt(ac, av, "f")) != -1)
|
||||
switch (ch) {
|
||||
case 'f':
|
||||
force = true;
|
||||
break;
|
||||
default:
|
||||
clear_driver_usage();
|
||||
}
|
||||
ac -= optind;
|
||||
av += optind;
|
||||
|
||||
if (ac != 1)
|
||||
clear_driver_usage();
|
||||
if (devctl_clear_driver(av[0], force) < 0)
|
||||
err(1, "Failed to clear %s driver", av[0]);
|
||||
return (0);
|
||||
}
|
||||
DEVCTL_COMMAND(clear, driver, clear_driver);
|
||||
|
||||
static int
|
||||
rescan(int ac, char **av)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue