summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdevinfo/devinfo_prop_decode.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libdevinfo/devinfo_prop_decode.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libdevinfo/devinfo_prop_decode.c')
-rw-r--r--usr/src/lib/libdevinfo/devinfo_prop_decode.c935
1 files changed, 935 insertions, 0 deletions
diff --git a/usr/src/lib/libdevinfo/devinfo_prop_decode.c b/usr/src/lib/libdevinfo/devinfo_prop_decode.c
new file mode 100644
index 0000000000..542cb54d52
--- /dev/null
+++ b/usr/src/lib/libdevinfo/devinfo_prop_decode.c
@@ -0,0 +1,935 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains kernel property decode routines adopted from
+ * sunddi.c and ddi_impl.c. The following changes have been applied.
+ *
+ * (1) Replace kmem_alloc by malloc. Remove negative indexing
+ * (2) Decoding applies only to prom properties.
+ * (3) For strings, the return value is a composite string, not a string array.
+ * (4) impl_ddi_prop_int_from_prom() uses _LITTLE_ENDIAN from isa_defs.h
+ *
+ * XXX This file should be kept in sync with kernel property encoding.
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <synch.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/dditypes.h>
+#include <sys/ddipropdefs.h>
+#include <sys/isa_defs.h>
+
+#include "libdevinfo.h"
+
+/*
+ * Return an integer in native machine format from an OBP 1275 integer
+ * representation, which is big-endian, with no particular alignment
+ * guarantees. intp points to the OBP data, and n the number of bytes.
+ *
+ * Byte-swapping may be needed on some implementations.
+ */
+int
+impl_di_prop_int_from_prom(uchar_t *intp, int n)
+{
+ int i = 0;
+
+#if defined(_LITTLE_ENDIAN)
+ intp += n;
+ while (n-- > 0) {
+ i = (i << 8) | *(--intp);
+ }
+#else
+ while (n-- > 0) {
+ i = (i << 8) | *intp++;
+ }
+#endif /* defined(_LITTLE_ENDIAN) */
+
+ return (i);
+}
+
+/*
+ * Reset the current location pointer in the property handle to the
+ * beginning of the data.
+ */
+void
+di_prop_reset_pos(prop_handle_t *ph)
+{
+ ph->ph_cur_pos = ph->ph_data;
+ ph->ph_save_pos = ph->ph_data;
+}
+
+/*
+ * Restore the current location pointer in the property handle to the
+ * saved position.
+ */
+void
+di_prop_save_pos(prop_handle_t *ph)
+{
+ ph->ph_save_pos = ph->ph_cur_pos;
+}
+
+/*
+ * Save the location that the current location poiner is pointing to..
+ */
+void
+di_prop_restore_pos(prop_handle_t *ph)
+{
+ ph->ph_cur_pos = ph->ph_save_pos;
+}
+
+/*
+ * Property encode/decode functions
+ */
+
+/*
+ * Decode an array of integers property
+ */
+static int
+di_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
+{
+ int i;
+ int cnt = 0;
+ int *tmp;
+ int *intp;
+ int n;
+
+ /*
+ * Figure out how many array elements there are by going through the
+ * data without decoding it first and counting.
+ */
+ for (;;) {
+ i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
+ if (i < 0)
+ break;
+ cnt++;
+ }
+
+ /*
+ * If there are no elements return an error
+ */
+ if (cnt == 0)
+ return (DDI_PROP_END_OF_DATA);
+
+ /*
+ * If we cannot skip through the data, we cannot decode it
+ */
+ if (i == DDI_PROP_RESULT_ERROR)
+ return (DDI_PROP_CANNOT_DECODE);
+
+ /*
+ * Reset the data pointer to the beginning of the encoded data
+ */
+ di_prop_reset_pos(ph);
+
+ /*
+ * Allocated memory to store the decoded value in.
+ */
+ if ((intp = malloc(cnt * sizeof (int))) == NULL) {
+ return (DDI_PROP_CANNOT_DECODE);
+ }
+
+
+ /*
+ * Decode each elemente and place it in the space we just allocated
+ */
+ tmp = intp;
+ for (n = 0; n < cnt; n++, tmp++) {
+ i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
+ if (i < DDI_PROP_RESULT_OK) {
+ /*
+ * Free the space we just allocated
+ * and return an error.
+ */
+ free(intp);
+ switch (i) {
+ case DDI_PROP_RESULT_EOF:
+ return (DDI_PROP_END_OF_DATA);
+
+ case DDI_PROP_RESULT_ERROR:
+ return (DDI_PROP_CANNOT_DECODE);
+ }
+ }
+ }
+
+ *nelements = cnt;
+ *(int **)data = intp;
+
+ return (DDI_PROP_SUCCESS);
+}
+
+/*
+ * Decode an array of strings.
+ */
+static int
+di_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
+{
+ int cnt = 0;
+ char *strs;
+ char *tmp;
+ int size;
+ int i;
+ int n;
+ int nbytes;
+
+ /*
+ * Figure out how much memory we need for the sum total
+ */
+ nbytes = 0;
+
+ for (;;) {
+ /*
+ * Get the decoded size of the current encoded string.
+ */
+ size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
+ if (size < 0)
+ break;
+
+ cnt++;
+ nbytes += size;
+ }
+
+ /*
+ * If there are no elements return an error
+ */
+ if (cnt == 0)
+ return (DDI_PROP_END_OF_DATA);
+
+ /*
+ * If we cannot skip through the data, we cannot decode it
+ */
+ if (size == DDI_PROP_RESULT_ERROR)
+ return (DDI_PROP_CANNOT_DECODE);
+
+ /*
+ * Allocate memory in which to store the decoded strings.
+ */
+ if ((strs = malloc(nbytes)) == NULL) {
+ return (DDI_PROP_CANNOT_DECODE);
+ }
+
+ /*
+ * Finally, we can decode each string
+ */
+ di_prop_reset_pos(ph);
+ tmp = strs;
+ for (n = 0; n < cnt; n++) {
+ i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
+ if (i < DDI_PROP_RESULT_OK) {
+ /*
+ * Free the space we just allocated
+ * and return an error
+ */
+ free(strs);
+ switch (i) {
+ case DDI_PROP_RESULT_EOF:
+ return (DDI_PROP_END_OF_DATA);
+
+ case DDI_PROP_RESULT_ERROR:
+ return (DDI_PROP_CANNOT_DECODE);
+ }
+ }
+ tmp += strlen(tmp) + 1;
+ }
+
+ *(char **)data = strs;
+ *nelements = cnt;
+
+ return (DDI_PROP_SUCCESS);
+}
+
+/*
+ * Decode an array of bytes.
+ */
+static int
+di_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
+{
+ uchar_t *tmp;
+ int nbytes;
+ int i;
+
+ /*
+ * If there are no elements return an error
+ */
+ if (ph->ph_size == 0)
+ return (DDI_PROP_END_OF_DATA);
+
+ /*
+ * Get the size of the encoded array of bytes.
+ */
+ nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
+ data, ph->ph_size);
+ if (nbytes < DDI_PROP_RESULT_OK) {
+ switch (nbytes) {
+ case DDI_PROP_RESULT_EOF:
+ return (DDI_PROP_END_OF_DATA);
+
+ case DDI_PROP_RESULT_ERROR:
+ return (DDI_PROP_CANNOT_DECODE);
+ }
+ }
+
+ /*
+ * Allocated memory to store the decoded value in.
+ */
+ if ((tmp = malloc(nbytes)) == NULL) {
+ return (DDI_PROP_CANNOT_DECODE);
+ }
+
+ /*
+ * Decode each element and place it in the space we just allocated
+ */
+ i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
+ if (i < DDI_PROP_RESULT_OK) {
+ /*
+ * Free the space we just allocated
+ * and return an error
+ */
+ free(tmp);
+ switch (i) {
+ case DDI_PROP_RESULT_EOF:
+ return (DDI_PROP_END_OF_DATA);
+
+ case DDI_PROP_RESULT_ERROR:
+ return (DDI_PROP_CANNOT_DECODE);
+ }
+ }
+
+ *(uchar_t **)data = tmp;
+ *nelements = nbytes;
+
+ return (DDI_PROP_SUCCESS);
+}
+
+/*
+ * OBP 1275 integer, string and byte operators.
+ *
+ * DDI_PROP_CMD_DECODE:
+ *
+ * DDI_PROP_RESULT_ERROR: cannot decode the data
+ * DDI_PROP_RESULT_EOF: end of data
+ * DDI_PROP_OK: data was decoded
+ *
+ * DDI_PROP_CMD_ENCODE:
+ *
+ * DDI_PROP_RESULT_ERROR: cannot encode the data
+ * DDI_PROP_RESULT_EOF: end of data
+ * DDI_PROP_OK: data was encoded
+ *
+ * DDI_PROP_CMD_SKIP:
+ *
+ * DDI_PROP_RESULT_ERROR: cannot skip the data
+ * DDI_PROP_RESULT_EOF: end of data
+ * DDI_PROP_OK: data was skipped
+ *
+ * DDI_PROP_CMD_GET_ESIZE:
+ *
+ * DDI_PROP_RESULT_ERROR: cannot get encoded size
+ * DDI_PROP_RESULT_EOF: end of data
+ * > 0: the encoded size
+ *
+ * DDI_PROP_CMD_GET_DSIZE:
+ *
+ * DDI_PROP_RESULT_ERROR: cannot get decoded size
+ * DDI_PROP_RESULT_EOF: end of data
+ * > 0: the decoded size
+ */
+
+/*
+ * OBP 1275 integer operator
+ *
+ * OBP properties are a byte stream of data, so integers may not be
+ * properly aligned. Therefore we need to copy them one byte at a time.
+ */
+int
+di_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
+{
+ int i;
+
+ switch (cmd) {
+ case DDI_PROP_CMD_DECODE:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
+ return (DDI_PROP_RESULT_ERROR);
+ if (ph->ph_flags & PH_FROM_PROM) {
+ i = ph->ph_size < PROP_1275_INT_SIZE ?
+ ph->ph_size : PROP_1275_INT_SIZE;
+ if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
+ ph->ph_size - i))
+ return (DDI_PROP_RESULT_ERROR);
+ } else if (ph->ph_size < sizeof (int) ||
+ ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
+ ph->ph_size - sizeof (int)))) {
+ return (DDI_PROP_RESULT_ERROR);
+ }
+
+ /*
+ * Copy the integer, using the implementation-specific
+ * copy function if the property is coming from the PROM.
+ */
+ if (ph->ph_flags & PH_FROM_PROM) {
+ *data = impl_di_prop_int_from_prom(
+ (uchar_t *)ph->ph_cur_pos,
+ (ph->ph_size < PROP_1275_INT_SIZE) ?
+ ph->ph_size : PROP_1275_INT_SIZE);
+ } else {
+ bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int));
+ }
+
+ /*
+ * Move the current location to the start of the next
+ * bit of undecoded data.
+ */
+ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_ENCODE:
+ /*
+ * Check that there is room to encoded the data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
+ ph->ph_size < PROP_1275_INT_SIZE ||
+ ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
+ ph->ph_size - sizeof (int))))
+ return (DDI_PROP_RESULT_ERROR);
+
+ /*
+ * Encode the integer into the byte stream one byte at a
+ * time.
+ */
+ bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int));
+
+ /*
+ * Move the current location to the start of the next bit of
+ * space where we can store encoded data.
+ */
+ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_SKIP:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
+ ph->ph_size < PROP_1275_INT_SIZE)
+ return (DDI_PROP_RESULT_ERROR);
+
+
+ if ((caddr_t)ph->ph_cur_pos ==
+ (caddr_t)ph->ph_data + ph->ph_size) {
+ return (DDI_PROP_RESULT_EOF);
+ } else if ((caddr_t)ph->ph_cur_pos >
+ (caddr_t)ph->ph_data + ph->ph_size) {
+ return (DDI_PROP_RESULT_EOF);
+ }
+
+ /*
+ * Move the current location to the start of the next bit of
+ * undecoded data.
+ */
+ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_GET_ESIZE:
+ /*
+ * Return the size of an encoded integer on OBP
+ */
+ return (PROP_1275_INT_SIZE);
+
+ case DDI_PROP_CMD_GET_DSIZE:
+ /*
+ * Return the size of a decoded integer on the system.
+ */
+ return (sizeof (int));
+ }
+
+ /*NOTREACHED*/
+ return (0); /* keep gcc happy */
+}
+
+/*
+ * 64 bit integer operator
+ *
+ * This is an extension, defined by Sun, to the 1275 integer
+ * operator. This routine handles the encoding/decoding of
+ * 64 bit integer properties.
+ */
+int
+di_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
+{
+ switch (cmd) {
+ case DDI_PROP_CMD_DECODE:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
+ return (DDI_PROP_RESULT_ERROR);
+ if (ph->ph_flags & PH_FROM_PROM) {
+ return (DDI_PROP_RESULT_ERROR);
+ } else if (ph->ph_size < sizeof (int64_t) ||
+ ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
+ ph->ph_size - sizeof (int64_t)))) {
+ return (DDI_PROP_RESULT_ERROR);
+ }
+
+ /*
+ * Copy the integer, using the implementation-specific
+ * copy function if the property is coming from the PROM.
+ */
+ bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int64_t));
+
+ /*
+ * Move the current location to the start of the next
+ * bit of undecoded data.
+ */
+ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
+ sizeof (int64_t);
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_ENCODE:
+ /*
+ * Check that there is room to encoded the data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
+ ph->ph_size < sizeof (int64_t) ||
+ ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
+ ph->ph_size - sizeof (int64_t))))
+ return (DDI_PROP_RESULT_ERROR);
+
+ /*
+ * Encode the integer into the byte stream one byte at a
+ * time.
+ */
+ bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int64_t));
+
+ /*
+ * Move the current location to the start of the next bit of
+ * space where we can store encoded data.
+ */
+ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
+ sizeof (int64_t);
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_SKIP:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
+ ph->ph_size < sizeof (int64_t))
+ return (DDI_PROP_RESULT_ERROR);
+
+
+ if ((caddr_t)ph->ph_cur_pos ==
+ (caddr_t)ph->ph_data + ph->ph_size) {
+ return (DDI_PROP_RESULT_EOF);
+ } else if ((caddr_t)ph->ph_cur_pos >
+ (caddr_t)ph->ph_data + ph->ph_size) {
+ return (DDI_PROP_RESULT_EOF);
+ }
+
+ /*
+ * Move the current location to the start of the next bit of
+ * undecoded data.
+ */
+ ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
+ sizeof (int64_t);
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_GET_ESIZE:
+ /*
+ * Return the size of an encoded integer on OBP
+ */
+ return (sizeof (int64_t));
+
+ case DDI_PROP_CMD_GET_DSIZE:
+ /*
+ * Return the size of a decoded integer on the system.
+ */
+ return (sizeof (int64_t));
+ }
+
+ /*NOTREACHED*/
+ return (0); /* keep gcc happy */
+}
+
+/*
+ * OBP 1275 string operator.
+ *
+ * OBP strings are NULL terminated.
+ */
+int
+di_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
+{
+ int n;
+ char *p;
+ char *end;
+
+ switch (cmd) {
+ case DDI_PROP_CMD_DECODE:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
+ return (DDI_PROP_RESULT_ERROR);
+ }
+
+ n = strlen((char *)ph->ph_cur_pos) + 1;
+ if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
+ ph->ph_size - n)) {
+ return (DDI_PROP_RESULT_ERROR);
+ }
+
+ /*
+ * Copy the NULL terminated string
+ */
+ bcopy((char *)ph->ph_cur_pos, data, n);
+
+ /*
+ * Move the current location to the start of the next bit of
+ * undecoded data.
+ */
+ ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_ENCODE:
+ /*
+ * Check that there is room to encoded the data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
+ return (DDI_PROP_RESULT_ERROR);
+ }
+
+ n = strlen(data) + 1;
+ if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
+ ph->ph_size - n)) {
+ return (DDI_PROP_RESULT_ERROR);
+ }
+
+ /*
+ * Copy the NULL terminated string
+ */
+ bcopy(data, (char *)ph->ph_cur_pos, n);
+
+ /*
+ * Move the current location to the start of the next bit of
+ * space where we can store encoded data.
+ */
+ ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_SKIP:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
+ return (DDI_PROP_RESULT_ERROR);
+ }
+
+ /*
+ * Return the string length plus one for the NULL
+ * We know the size of the property, we need to
+ * ensure that the string is properly formatted,
+ * since we may be looking up random OBP data.
+ */
+ p = (char *)ph->ph_cur_pos;
+ end = (char *)ph->ph_data + ph->ph_size;
+
+ if (p == end) {
+ return (DDI_PROP_RESULT_EOF);
+ }
+
+ /*
+ * Make sure each char is printable
+ */
+ for (n = 0; p < end && isascii(*p) && !iscntrl(*p); n++, p++)
+ ;
+
+ /* Check termination and non-zero length */
+ if ((*p == 0) && (n != 0)) {
+ ph->ph_cur_pos = p + 1;
+ return (DDI_PROP_RESULT_OK);
+ }
+
+ return (DDI_PROP_RESULT_ERROR);
+
+ case DDI_PROP_CMD_GET_ESIZE:
+ /*
+ * Return the size of the encoded string on OBP.
+ */
+ return (strlen(data) + 1);
+
+ case DDI_PROP_CMD_GET_DSIZE:
+ /*
+ * Return the string length plus one for the NULL
+ * We know the size of the property, we need to
+ * ensure that the string is properly formatted,
+ * since we may be looking up random OBP data.
+ */
+ p = (char *)ph->ph_cur_pos;
+ end = (char *)ph->ph_data + ph->ph_size;
+ for (n = 0; p < end; n++) {
+ if (*p++ == '\0') {
+ ph->ph_cur_pos = p;
+ return (n+1);
+ }
+ }
+
+ /*
+ * Add check here to separate EOF and ERROR.
+ */
+ if (p == end)
+ return (DDI_PROP_RESULT_EOF);
+
+ return (DDI_PROP_RESULT_ERROR);
+
+ }
+
+ /*NOTREACHED*/
+ return (0); /* keep gcc happy */
+}
+
+/*
+ * OBP 1275 byte operator
+ *
+ * Caller must specify the number of bytes to get. OBP encodes bytes
+ * as a byte so there is a 1-to-1 translation.
+ */
+int
+di_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
+ uint_t nelements)
+{
+ switch (cmd) {
+ case DDI_PROP_CMD_DECODE:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
+ ph->ph_size < nelements ||
+ ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
+ ph->ph_size - nelements)))
+ return (DDI_PROP_RESULT_ERROR);
+
+ /*
+ * Copy out the bytes
+ */
+ bcopy((char *)ph->ph_cur_pos, (char *)data, nelements);
+
+ /*
+ * Move the current location
+ */
+ ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_ENCODE:
+ /*
+ * Check that there is room to encode the data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
+ ph->ph_size < nelements ||
+ ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
+ ph->ph_size - nelements)))
+ return (DDI_PROP_RESULT_ERROR);
+
+ /*
+ * Copy in the bytes
+ */
+ bcopy((char *)data, (char *)ph->ph_cur_pos, nelements);
+
+ /*
+ * Move the current location to the start of the next bit of
+ * space where we can store encoded data.
+ */
+ ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_SKIP:
+ /*
+ * Check that there is encoded data
+ */
+ if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
+ ph->ph_size < nelements)
+ return (DDI_PROP_RESULT_ERROR);
+
+ if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
+ ph->ph_size - nelements))
+ return (DDI_PROP_RESULT_EOF);
+
+ /*
+ * Move the current location
+ */
+ ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
+ return (DDI_PROP_RESULT_OK);
+
+ case DDI_PROP_CMD_GET_ESIZE:
+ /*
+ * The size in bytes of the encoded size is the
+ * same as the decoded size provided by the caller.
+ */
+ return (nelements);
+
+ case DDI_PROP_CMD_GET_DSIZE:
+ /*
+ * Just return the number of bytes specified by the caller.
+ */
+ return (nelements);
+
+ }
+
+ /*NOTREACHED*/
+ return (0); /* keep gcc happy */
+}
+
+/*
+ * Used for properties that come from the OBP, hardware configuration files,
+ * or that are created by calls to ddi_prop_update(9F).
+ */
+static struct prop_handle_ops prop_1275_ops = {
+ di_prop_1275_int,
+ di_prop_1275_string,
+ di_prop_1275_bytes,
+ di_prop_int64_op
+};
+
+/*
+ * Now the real thing:
+ * Extract type-specific values of an property
+ */
+int
+di_prop_decode_common(void *data, int size, int prop_type, int prom)
+{
+ int n;
+ int nelements;
+ char *cp, *end;
+ prop_handle_t ph;
+ int (*prop_decoder)(prop_handle_t *, void *, uint_t *);
+
+ /*
+ * If the encoded data came from software, no decoding needed
+ */
+ if (!prom) {
+ switch (prop_type) {
+ case DI_PROP_TYPE_INT:
+ if (size % sizeof (int))
+ nelements = -1;
+ else
+ nelements = size / sizeof (int);
+ break;
+
+ case DI_PROP_TYPE_INT64:
+ if (size % sizeof (int64_t))
+ nelements = -1;
+ else
+ nelements = size / sizeof (int64_t);
+ break;
+
+ case DI_PROP_TYPE_STRING:
+ nelements = 0;
+ cp = *(char **)data;
+ end = cp + size;
+ /*
+ * Don't trust the data passed in by the caller.
+ * Check every char to make sure it is indeed a
+ * string property.
+ */
+ while (cp < end) {
+ /* skip to next non-printable char */
+ for (n = 0; cp < end &&
+ isascii(*cp) && !iscntrl(*cp); n++, cp++)
+ ;
+
+ /*
+ * Fail if reached end (i.e. last char != 0),
+ * or has a non-printable char. A zero length
+ * string is acceptable.
+ */
+ if (cp == end || *cp != 0) {
+ nelements = -1;
+ break;
+ }
+ /*
+ * Increment # strings and keep going
+ */
+ nelements++;
+ cp++;
+ }
+
+ break;
+
+ case DI_PROP_TYPE_BYTE:
+ nelements = size;
+ }
+
+ return (nelements);
+ }
+
+ /*
+ * Get the encoded data
+ */
+ bzero((caddr_t)&ph, sizeof (prop_handle_t));
+ ph.ph_data = *(uchar_t **)data;
+ ph.ph_size = size;
+
+ /*
+ * The data came from prom, use the 1275 OBP decode/encode routines.
+ */
+ ph.ph_cur_pos = ph.ph_data;
+ ph.ph_save_pos = ph.ph_data;
+ ph.ph_ops = &prop_1275_ops;
+ ph.ph_flags = PH_FROM_PROM;
+
+ switch (prop_type) {
+ case DI_PROP_TYPE_INT:
+ prop_decoder = di_prop_fm_decode_ints;
+ break;
+ case DI_PROP_TYPE_STRING:
+ prop_decoder = di_prop_fm_decode_strings;
+ break;
+ case DI_PROP_TYPE_BYTE:
+ default:
+ prop_decoder = di_prop_fm_decode_bytes;
+ break;
+ }
+
+ if ((*prop_decoder)(&ph, data, (uint_t *)&nelements)
+ != DDI_PROP_SUCCESS)
+ return (-1);
+
+ /*
+ * Free the encoded data
+ */
+ if (size != 0)
+ free(ph.ph_data);
+
+ return (nelements);
+}
+
+/* end of devinfo_prop_decode.c */