1/*-
2 * Copyright (c) 2014 John Baldwin <jhb@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: stable/11/lib/libdevctl/devctl.c 367457 2020-11-07 18:10:59Z dim $");
28
29#include <sys/types.h>
30#include <sys/bus.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <string.h>
34#include "devctl.h"
35
36static int
37devctl_request(u_long cmd, struct devreq *req)
38{
39	static int devctl2_fd = -1;
40
41	if (devctl2_fd == -1) {
42		devctl2_fd = open("/dev/devctl2", O_RDONLY);
43		if (devctl2_fd == -1)
44			return (-1);
45	}
46	return (ioctl(devctl2_fd, cmd, req));
47}
48
49static int
50devctl_simple_request(u_long cmd, const char *name, int flags)
51{
52	struct devreq req;
53
54	memset(&req, 0, sizeof(req));
55	if (strlcpy(req.dr_name, name, sizeof(req.dr_name)) >=
56	    sizeof(req.dr_name)) {
57		errno = EINVAL;
58		return (-1);
59	}
60	req.dr_flags = flags;
61	return (devctl_request(cmd, &req));
62}
63
64int
65devctl_attach(const char *device)
66{
67
68	return (devctl_simple_request(DEV_ATTACH, device, 0));
69}
70
71int
72devctl_detach(const char *device, bool force)
73{
74
75	return (devctl_simple_request(DEV_DETACH, device, force ?
76	    DEVF_FORCE_DETACH : 0));
77}
78
79int
80devctl_enable(const char *device)
81{
82
83	return (devctl_simple_request(DEV_ENABLE, device, 0));
84}
85
86int
87devctl_disable(const char *device, bool force_detach)
88{
89
90	return (devctl_simple_request(DEV_DISABLE, device, force_detach ?
91	    DEVF_FORCE_DETACH : 0));
92}
93
94int
95devctl_suspend(const char *device)
96{
97
98	return (devctl_simple_request(DEV_SUSPEND, device, 0));
99}
100
101int
102devctl_resume(const char *device)
103{
104
105	return (devctl_simple_request(DEV_RESUME, device, 0));
106}
107
108int
109devctl_set_driver(const char *device, const char *driver, bool force)
110{
111	struct devreq req;
112
113	memset(&req, 0, sizeof(req));
114	if (strlcpy(req.dr_name, device, sizeof(req.dr_name)) >=
115	    sizeof(req.dr_name)) {
116		errno = EINVAL;
117		return (-1);
118	}
119	req.dr_data = __DECONST(char *, driver);
120	if (force)
121		req.dr_flags |= DEVF_SET_DRIVER_DETACH;
122	return (devctl_request(DEV_SET_DRIVER, &req));
123}
124
125int
126devctl_clear_driver(const char *device, bool force)
127{
128
129	return (devctl_simple_request(DEV_CLEAR_DRIVER, device, force ?
130	    DEVF_CLEAR_DRIVER_DETACH : 0));
131}
132
133int
134devctl_rescan(const char *device)
135{
136
137	return (devctl_simple_request(DEV_RESCAN, device, 0));
138}
139
140int
141devctl_delete(const char *device, bool force)
142{
143
144	return (devctl_simple_request(DEV_DELETE, device, force ?
145	    DEVF_FORCE_DELETE : 0));
146}
147
148int
149devctl_reset(const char *device, bool detach)
150{
151
152	return (devctl_simple_request(DEV_RESET, device, detach ?
153	    DEVF_RESET_DETACH : 0));
154}
155