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$"); 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 36 static int 37 devctl_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 49 static int 50 devctl_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 64 int 65 devctl_attach(const char *device) 66 { 67 68 return (devctl_simple_request(DEV_ATTACH, device, 0)); 69 } 70 71 int 72 devctl_detach(const char *device, bool force) 73 { 74 75 return (devctl_simple_request(DEV_DETACH, device, force ? 76 DEVF_FORCE_DETACH : 0)); 77 } 78 79 int 80 devctl_enable(const char *device) 81 { 82 83 return (devctl_simple_request(DEV_ENABLE, device, 0)); 84 } 85 86 int 87 devctl_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 94 int 95 devctl_suspend(const char *device) 96 { 97 98 return (devctl_simple_request(DEV_SUSPEND, device, 0)); 99 } 100 101 int 102 devctl_resume(const char *device) 103 { 104 105 return (devctl_simple_request(DEV_RESUME, device, 0)); 106 } 107 108 int 109 devctl_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 125 int 126 devctl_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 133 int 134 devctl_rescan(const char *device) 135 { 136 137 return (devctl_simple_request(DEV_RESCAN, device, 0)); 138 } 139 140 int 141 devctl_delete(const char *device, bool force) 142 { 143 144 return (devctl_simple_request(DEV_DELETE, device, force ? 145 DEVF_FORCE_DELETE : 0)); 146 } 147 148 int 149 devctl_freeze(void) 150 { 151 152 return (devctl_simple_request(DEV_FREEZE, "", 0)); 153 } 154 155 int 156 devctl_thaw(void) 157 { 158 159 return (devctl_simple_request(DEV_THAW, "", 0)); 160 } 161 162 int 163 devctl_reset(const char *device, bool detach) 164 { 165 166 return (devctl_simple_request(DEV_RESET, device, detach ? 167 DEVF_RESET_DETACH : 0)); 168 } 169