Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libdevctl/devctl.c
39475 views
1
/*-
2
* Copyright (c) 2014 John Baldwin <[email protected]>
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/types.h>
27
#include <sys/bus.h>
28
#include <errno.h>
29
#include <fcntl.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include "devctl.h"
33
34
static int
35
devctl_request(u_long cmd, struct devreq *req)
36
{
37
static int devctl2_fd = -1;
38
39
if (devctl2_fd == -1) {
40
devctl2_fd = open("/dev/devctl2", O_RDONLY);
41
if (devctl2_fd == -1)
42
return (-1);
43
}
44
return (ioctl(devctl2_fd, cmd, req));
45
}
46
47
static int
48
devctl_simple_request(u_long cmd, const char *name, int flags)
49
{
50
struct devreq req;
51
52
memset(&req, 0, sizeof(req));
53
if (strlcpy(req.dr_name, name, sizeof(req.dr_name)) >=
54
sizeof(req.dr_name)) {
55
errno = EINVAL;
56
return (-1);
57
}
58
req.dr_flags = flags;
59
return (devctl_request(cmd, &req));
60
}
61
62
int
63
devctl_attach(const char *device)
64
{
65
66
return (devctl_simple_request(DEV_ATTACH, device, 0));
67
}
68
69
int
70
devctl_detach(const char *device, bool force)
71
{
72
73
return (devctl_simple_request(DEV_DETACH, device, force ?
74
DEVF_FORCE_DETACH : 0));
75
}
76
77
int
78
devctl_enable(const char *device)
79
{
80
81
return (devctl_simple_request(DEV_ENABLE, device, 0));
82
}
83
84
int
85
devctl_disable(const char *device, bool force_detach)
86
{
87
88
return (devctl_simple_request(DEV_DISABLE, device, force_detach ?
89
DEVF_FORCE_DETACH : 0));
90
}
91
92
int
93
devctl_suspend(const char *device)
94
{
95
96
return (devctl_simple_request(DEV_SUSPEND, device, 0));
97
}
98
99
int
100
devctl_resume(const char *device)
101
{
102
103
return (devctl_simple_request(DEV_RESUME, device, 0));
104
}
105
106
int
107
devctl_set_driver(const char *device, const char *driver, bool force)
108
{
109
struct devreq req;
110
111
memset(&req, 0, sizeof(req));
112
if (strlcpy(req.dr_name, device, sizeof(req.dr_name)) >=
113
sizeof(req.dr_name)) {
114
errno = EINVAL;
115
return (-1);
116
}
117
req.dr_data = __DECONST(char *, driver);
118
if (force)
119
req.dr_flags |= DEVF_SET_DRIVER_DETACH;
120
return (devctl_request(DEV_SET_DRIVER, &req));
121
}
122
123
int
124
devctl_clear_driver(const char *device, bool force)
125
{
126
127
return (devctl_simple_request(DEV_CLEAR_DRIVER, device, force ?
128
DEVF_CLEAR_DRIVER_DETACH : 0));
129
}
130
131
int
132
devctl_rescan(const char *device)
133
{
134
135
return (devctl_simple_request(DEV_RESCAN, device, 0));
136
}
137
138
int
139
devctl_delete(const char *device, bool force)
140
{
141
142
return (devctl_simple_request(DEV_DELETE, device, force ?
143
DEVF_FORCE_DELETE : 0));
144
}
145
146
int
147
devctl_freeze(void)
148
{
149
150
return (devctl_simple_request(DEV_FREEZE, "", 0));
151
}
152
153
int
154
devctl_thaw(void)
155
{
156
157
return (devctl_simple_request(DEV_THAW, "", 0));
158
}
159
160
int
161
devctl_reset(const char *device, bool detach)
162
{
163
164
return (devctl_simple_request(DEV_RESET, device, detach ?
165
DEVF_RESET_DETACH : 0));
166
}
167
168
#define BUFLEN 1024
169
170
int
171
devctl_getpath(const char *device, const char *locator, char **buffer)
172
{
173
struct devreq req;
174
int serrno;
175
176
memset(&req, 0, sizeof(req));
177
if (strlcpy(req.dr_name, device, sizeof(req.dr_name)) >=
178
sizeof(req.dr_name)) {
179
errno = EINVAL;
180
*buffer = NULL;
181
return (-1);
182
}
183
184
/*
185
* Maybe do the request twice. Once to get the length, and then again to
186
* get the string if BUFLEN bytes is insufficient.
187
*/
188
req.dr_flags = 0;
189
req.dr_buffer.length = BUFLEN;
190
again:
191
req.dr_buffer.buffer = malloc(req.dr_buffer.length);
192
strlcpy(req.dr_buffer.buffer, locator, req.dr_buffer.length);
193
if (devctl_request(DEV_GET_PATH, &req) == 0) {
194
*buffer = req.dr_buffer.buffer;
195
return (0);
196
}
197
if (errno == ENAMETOOLONG && req.dr_buffer.length != BUFLEN) {
198
free(req.dr_buffer.buffer);
199
goto again;
200
}
201
serrno = errno;
202
free(req.dr_buffer.buffer);
203
errno = serrno;
204
*buffer = NULL;
205
return (-1);
206
}
207
208