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/types.h> 27 #include <sys/ioctl.h> 28 29 #include <dev/ofw/openfirmio.h> 30 31 #include <err.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sysexits.h> 38 #include <unistd.h> 39 40 #include "pathnames.h" 41 #include "ofw_util.h" 42 43 #define OFW_IOCTL(fd, cmd, val) do { \ 44 if (ioctl(fd, cmd, val) == -1) \ 45 err(EX_IOERR, "ioctl(..., " #cmd ", ...) failed"); \ 46 } while (0) 47 48 int 49 ofw_open(int mode) 50 { 51 int fd; 52 53 if ((fd = open(PATH_DEV_OPENFIRM, mode)) == -1) 54 err(EX_UNAVAILABLE, "could not open " PATH_DEV_OPENFIRM); 55 return (fd); 56 } 57 58 void 59 ofw_close(int fd) 60 { 61 62 close(fd); 63 } 64 65 phandle_t 66 ofw_root(int fd) 67 { 68 69 return (ofw_peer(fd, 0)); 70 } 71 72 phandle_t 73 ofw_optnode(int fd) 74 { 75 phandle_t rv; 76 77 OFW_IOCTL(fd, OFIOCGETOPTNODE, &rv); 78 return (rv); 79 } 80 81 phandle_t 82 ofw_peer(int fd, phandle_t node) 83 { 84 phandle_t rv; 85 86 rv = node; 87 OFW_IOCTL(fd, OFIOCGETNEXT, &rv); 88 return (rv); 89 } 90 91 phandle_t 92 ofw_child(int fd, phandle_t node) 93 { 94 phandle_t rv; 95 96 rv = node; 97 OFW_IOCTL(fd, OFIOCGETCHILD, &rv); 98 return (rv); 99 } 100 101 phandle_t 102 ofw_finddevice(int fd, const char *name) 103 { 104 struct ofiocdesc d; 105 106 d.of_nodeid = 0; 107 d.of_namelen = strlen(name); 108 d.of_name = name; 109 d.of_buflen = 0; 110 d.of_buf = NULL; 111 if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) { 112 if (errno == ENOENT) 113 err(EX_UNAVAILABLE, "Node '%s' not found", name); 114 else 115 err(EX_IOERR, 116 "ioctl(..., OFIOCFINDDEVICE, ...) failed"); 117 } 118 return (d.of_nodeid); 119 } 120 121 int 122 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen) 123 { 124 125 return (ofw_nextprop(fd, node, NULL, buf, buflen)); 126 } 127 128 int 129 ofw_nextprop(int fd, phandle_t node, const char *prev, char *buf, int buflen) 130 { 131 struct ofiocdesc d; 132 133 d.of_nodeid = node; 134 d.of_namelen = prev != NULL ? strlen(prev) : 0; 135 d.of_name = prev; 136 d.of_buflen = buflen; 137 d.of_buf = buf; 138 if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) { 139 if (errno == ENOENT) 140 return (0); 141 else 142 err(EX_IOERR, "ioctl(..., OFIOCNEXTPROP, ...) failed"); 143 } 144 return (d.of_buflen); 145 } 146 147 static void * 148 ofw_malloc(int size) 149 { 150 void *p; 151 152 if ((p = malloc(size)) == NULL) 153 err(EX_OSERR, "malloc() failed"); 154 return (p); 155 } 156 157 int 158 ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen) 159 { 160 struct ofiocdesc d; 161 162 d.of_nodeid = node; 163 d.of_namelen = strlen(name); 164 d.of_name = name; 165 d.of_buflen = buflen; 166 d.of_buf = buf; 167 OFW_IOCTL(fd, OFIOCGET, &d); 168 return (d.of_buflen); 169 } 170 171 int 172 ofw_setprop(int fd, phandle_t node, const char *name, const void *buf, 173 int buflen) 174 { 175 struct ofiocdesc d; 176 177 d.of_nodeid = node; 178 d.of_namelen = strlen(name); 179 d.of_name = name; 180 d.of_buflen = buflen; 181 d.of_buf = ofw_malloc(buflen); 182 memcpy(d.of_buf, buf, buflen); 183 OFW_IOCTL(fd, OFIOCSET, &d); 184 free(d.of_buf); 185 return (d.of_buflen); 186 } 187 188 int 189 ofw_getproplen(int fd, phandle_t node, const char *name) 190 { 191 struct ofiocdesc d; 192 193 d.of_nodeid = node; 194 d.of_namelen = strlen(name); 195 d.of_name = name; 196 OFW_IOCTL(fd, OFIOCGETPROPLEN, &d); 197 return (d.of_buflen); 198 } 199 200 int 201 ofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf, 202 int *buflen, int reserve) 203 { 204 struct ofiocdesc d; 205 int len, rv; 206 207 do { 208 len = ofw_getproplen(fd, node, name); 209 if (len < 0) 210 return (len); 211 if (*buflen < len + reserve) { 212 if (*buf != NULL) 213 free(*buf); 214 *buflen = len + reserve + OFIOCMAXVALUE; 215 *buf = ofw_malloc(*buflen); 216 } 217 d.of_nodeid = node; 218 d.of_namelen = strlen(name); 219 d.of_name = name; 220 d.of_buflen = *buflen - reserve; 221 d.of_buf = *buf; 222 rv = ioctl(fd, OFIOCGET, &d); 223 } while (rv == -1 && errno == ENOMEM); 224 if (rv == -1) 225 err(EX_IOERR, "ioctl(..., OFIOCGET, ...) failed"); 226 return (d.of_buflen); 227 } 228