1 /*- 2 * Copyright (c) 2002 by Thomas Moestl <tmm@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 ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/types.h> 30 #include <sys/ioctl.h> 31 32 #include <dev/ofw/openfirmio.h> 33 34 #include <err.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sysexits.h> 41 #include <unistd.h> 42 43 #include "pathnames.h" 44 #include "ofw_util.h" 45 46 #define OFW_IOCTL(fd, cmd, val) do { \ 47 if (ioctl(fd, cmd, val) == -1) \ 48 err(EX_IOERR, "ioctl(..., " #cmd ", ...) failed"); \ 49 } while (0) 50 51 int 52 ofw_open(int mode) 53 { 54 int fd; 55 56 if ((fd = open(PATH_DEV_OPENFIRM, mode)) == -1) 57 err(EX_UNAVAILABLE, "could not open " PATH_DEV_OPENFIRM); 58 return (fd); 59 } 60 61 void 62 ofw_close(int fd) 63 { 64 65 close(fd); 66 } 67 68 phandle_t 69 ofw_root(int fd) 70 { 71 72 return (ofw_peer(fd, 0)); 73 } 74 75 phandle_t 76 ofw_optnode(int fd) 77 { 78 phandle_t rv; 79 80 OFW_IOCTL(fd, OFIOCGETOPTNODE, &rv); 81 return (rv); 82 } 83 84 phandle_t 85 ofw_peer(int fd, phandle_t node) 86 { 87 phandle_t rv; 88 89 rv = node; 90 OFW_IOCTL(fd, OFIOCGETNEXT, &rv); 91 return (rv); 92 } 93 94 phandle_t 95 ofw_child(int fd, phandle_t node) 96 { 97 phandle_t rv; 98 99 rv = node; 100 OFW_IOCTL(fd, OFIOCGETCHILD, &rv); 101 return (rv); 102 } 103 104 phandle_t 105 ofw_finddevice(int fd, const char *name) 106 { 107 struct ofiocdesc d; 108 109 d.of_nodeid = 0; 110 d.of_namelen = strlen(name); 111 d.of_name = name; 112 d.of_buflen = 0; 113 d.of_buf = NULL; 114 if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) { 115 if (errno == ENOENT) 116 err(EX_UNAVAILABLE, "Node '%s' not found", name); 117 else 118 err(EX_IOERR, 119 "ioctl(..., OFIOCFINDDEVICE, ...) failed"); 120 } 121 return (d.of_nodeid); 122 } 123 124 int 125 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen) 126 { 127 128 return (ofw_nextprop(fd, node, NULL, buf, buflen)); 129 } 130 131 int 132 ofw_nextprop(int fd, phandle_t node, const char *prev, char *buf, int buflen) 133 { 134 struct ofiocdesc d; 135 136 d.of_nodeid = node; 137 d.of_namelen = prev != NULL ? strlen(prev) : 0; 138 d.of_name = prev; 139 d.of_buflen = buflen; 140 d.of_buf = buf; 141 if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) { 142 if (errno == ENOENT) 143 return (0); 144 else 145 err(EX_IOERR, "ioctl(..., OFIOCNEXTPROP, ...) failed"); 146 } 147 return (d.of_buflen); 148 } 149 150 static void * 151 ofw_malloc(int size) 152 { 153 void *p; 154 155 if ((p = malloc(size)) == NULL) 156 err(EX_OSERR, "malloc() failed"); 157 return (p); 158 } 159 160 int 161 ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen) 162 { 163 struct ofiocdesc d; 164 165 d.of_nodeid = node; 166 d.of_namelen = strlen(name); 167 d.of_name = name; 168 d.of_buflen = buflen; 169 d.of_buf = buf; 170 OFW_IOCTL(fd, OFIOCGET, &d); 171 return (d.of_buflen); 172 } 173 174 int 175 ofw_setprop(int fd, phandle_t node, const char *name, const void *buf, 176 int buflen) 177 { 178 struct ofiocdesc d; 179 180 d.of_nodeid = node; 181 d.of_namelen = strlen(name); 182 d.of_name = name; 183 d.of_buflen = buflen; 184 d.of_buf = ofw_malloc(buflen); 185 memcpy(d.of_buf, buf, buflen); 186 OFW_IOCTL(fd, OFIOCSET, &d); 187 free(d.of_buf); 188 return (d.of_buflen); 189 } 190 191 int 192 ofw_getproplen(int fd, phandle_t node, const char *name) 193 { 194 struct ofiocdesc d; 195 196 d.of_nodeid = node; 197 d.of_namelen = strlen(name); 198 d.of_name = name; 199 OFW_IOCTL(fd, OFIOCGETPROPLEN, &d); 200 return (d.of_buflen); 201 } 202 203 int 204 ofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf, 205 int *buflen, int reserve) 206 { 207 struct ofiocdesc d; 208 int len, rv; 209 210 do { 211 len = ofw_getproplen(fd, node, name); 212 if (len < 0) 213 return (len); 214 if (*buflen < len + reserve) { 215 if (*buf != NULL) 216 free(*buf); 217 *buflen = len + reserve + OFIOCMAXVALUE; 218 *buf = ofw_malloc(*buflen); 219 } 220 d.of_nodeid = node; 221 d.of_namelen = strlen(name); 222 d.of_name = name; 223 d.of_buflen = *buflen - reserve; 224 d.of_buf = *buf; 225 rv = ioctl(fd, OFIOCGET, &d); 226 } while (rv == -1 && errno == ENOMEM); 227 if (rv == -1) 228 err(EX_IOERR, "ioctl(..., OFIOCGET, ...) failed"); 229 return (d.of_buflen); 230 } 231