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