OpenSolaris_b135/lib/efcode/engine/properties.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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 (c) 2000 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcode/private.h>
#include <fcode/log.h>

void
create_prop(fcode_env_t *env, char *name)
{
	push_a_string(env, name);
	property(env);
}

void
create_int_prop(fcode_env_t *env, char *name, int val)
{
	PUSH(DS, val);
	encode_int(env);
	create_prop(env, name);
}

void
create_string_prop(fcode_env_t *env, char *name, char *val)
{
	push_a_string(env, val);
	encode_string(env);
	create_prop(env, name);
}

static int
addr_cmp(void *a, void *b)
{
	return ((uchar_t *)a == (uchar_t *)b);
}

static void *
add_property_buffer(fcode_env_t *env, int len)
{
	void *data = MALLOC(len+1);
	return (add_resource(&env->propbufs, data, addr_cmp));
}

static void
free_property_buffer(fcode_env_t *env, void *buffer)
{
	free_resource(&env->propbufs, buffer, addr_cmp);
	FREE(buffer);
}

/*
 * Golden Rule:
 * DO NOT cache the value of the head of the property list *before*
 * looking up a property.
 * This routine is also responsible for purging dead properties
 * and that *can* affect the head pointer.
 * you have been warned!
 */
prop_t *
find_property(device_t *d, char *name)
{
	prop_t *p = d->properties, *prev;
	prop_t *found = NULL;

	prev = NULL;
	while (p && !found) {
		if (p->name) {
			if (strcmp(name, p->name) == 0) {
				found = p;
			}
			prev = p;
			p = p->next;
		} else {
			prop_t *dead;

			if (prev)
				prev->next = p->next;
			else {
				/* last prop in chain */
				d->properties = p->next;
			}
			dead = p;
			p = p->next;
			FREE(dead->name);
			FREE(dead->data);
			FREE(dead);
		}
	}
	return (found);
}

static prop_t *
stack_find_property(fcode_env_t *env, device_t *d)
{
	char *propname;

	propname = pop_a_string(env, NULL);
	return (find_property(d, propname));
}

void
property(fcode_env_t *env)
{
	int datalen;
	char *propname, *srcptr;
	prop_t *p;
	device_t *d;

	CHECK_DEPTH(env, 4, "property");
	if (MYSELF) {
		d = MYSELF->device;
	} else {
		d = env->current_device;
		if (!d) {
			void *buffer;

			two_drop(env);
			if ((buffer = pop_a_string(env, NULL)) != NULL)
				free_property_buffer(env, buffer);
			return;
		}
	}
	propname = pop_a_string(env, NULL);
	p = find_property(d, propname);
	if (p == NULL) {
		p = MALLOC(sizeof (prop_t));
		p->next = d->properties;
		d->properties = p;
		p->name = STRDUP(propname);
	} else if (p->data)
		FREE(p->data);	/* release old resources */
	srcptr = pop_a_string(env, &datalen);
	p->data = MALLOC(datalen+1);
	p->size = datalen;
	memcpy(p->data, srcptr, datalen);
	p->data[datalen] = 0;
	if (srcptr)
		free_property_buffer(env, srcptr);
}

prop_t *
lookup_package_property(fcode_env_t *env, char *propname, device_t *d)
{
	prop_t *p;

	p = find_property(d, propname);
	if (p) {
		return (p);
	}
	if (d->vectors.get_package_prop) {
		static prop_t sp;
		fstack_t fail, n;

		/* recreate the FORTH environment for the remote call */
		push_a_string(env, propname);
		REVERT_PHANDLE(env, n, d);
		PUSH(DS, n);
		d->vectors.get_package_prop(env);
		fail = POP(DS);
		if (fail)
			return (NULL);
		sp.size = POP(DS);
		sp.data = (uchar_t *)POP(DS);
		sp.name = propname;
		sp.next = NULL;
		return (&sp);
	}
	return (NULL);
}

void
get_package_property(fcode_env_t *env)
{
	prop_t *p;
	device_t *d;
	char *propname;

	CHECK_DEPTH(env, 3, "get-package-property");
	CONVERT_PHANDLE(env, d, POP(DS));
	propname = pop_a_string(env, NULL);
	p = lookup_package_property(env, propname, d);
	if (p) {
		PUSH(DS, (fstack_t)p->data);
		PUSH(DS, p->size);
		PUSH(DS, FALSE);
	} else
		PUSH(DS, TRUE);
}

void
get_inherited_prop(fcode_env_t *env)
{
	instance_t *ih;
	device_t *dev;
	prop_t *prop;
	char *pname;
	int plen;

	/*
	 * First, we look thru the in-memory device tree for the property.
	 * If we don't find it, we call get_inherited_prop, which "knows" it's
	 * not going to find the property below the attachment point.
	 */

	CHECK_DEPTH(env, 2, "get-inherited-property");
	pname = pop_a_string(env, &plen);
	ih = MYSELF;
	if (ih) {
		for (; ih; ih = ih->parent) {
			dev = ih->device;
			prop = find_property(dev, pname);
			if (prop) {
				PUSH(DS, (fstack_t)prop->data);
				PUSH(DS, (fstack_t)prop->size);
				PUSH(DS, FALSE);
				return;
			}
		}
		if (dev->vectors.get_inherited_prop) {
			push_a_string(env, pname);
			dev->vectors.get_inherited_prop(env);
			return;
		}
	}
	PUSH(DS, TRUE);
}

void
delete_property(fcode_env_t *env)
{
	CHECK_DEPTH(env, 2, "delete-property");
	if (MYSELF) {
		prop_t *p;

		p = stack_find_property(env, MYSELF->device);
		if (p) {
			/*
			 * write the name as NULL; the space will be free'd
			 * the next time a property lookup passes this node
			 */
			p->name = NULL;
		}
	} else {
		two_drop(env);
	}
}

void
get_my_property(fcode_env_t *env)
{
	CHECK_DEPTH(env, 2, "get-my-property");
	PUSH(DS, (fstack_t)MYSELF);
	ihandle_to_phandle(env);
	get_package_property(env);
}

void
encode_string(fcode_env_t *env)
{
	char *str;
	char *prop;
	int len;

	CHECK_DEPTH(env, 2, "encode-string");
	str = pop_a_string(env, &len);

	prop = add_property_buffer(env, len);
	memcpy(prop, str, len);
	prop[len] = 0;
	PUSH(DS, (fstack_t)prop);
	PUSH(DS, len + 1);
}

void
encode_int(fcode_env_t *env)
{
	uchar_t *ptr;
	uint32_t p;

	CHECK_DEPTH(env, 1, "encode-int");
	p = POP(DS);
	ptr = add_property_buffer(env, sizeof (uint32_t));

	memcpy(ptr, (char *)&p, sizeof (uint32_t));
	PUSH(DS, (fstack_t)ptr);
	PUSH(DS, sizeof (uint32_t));
}

void
encode_phys(fcode_env_t *env)
{
	uint_t ncells;

	ncells = get_number_of_parent_address_cells(env);
	CHECK_DEPTH(env, ncells, "encode-phys");
	encode_int(env);
	while (--ncells) {
		rot(env);
		encode_int(env);
		encode_plus(env);
	}
}

static fstack_t
get_decoded_int(uchar_t *dp)
{
	uint32_t d;

	memcpy((char *)&d, dp, sizeof (uint32_t));
	return (d);
}

int
get_default_intprop(fcode_env_t *env, char *name, device_t *d, int def)
{
	prop_t *p;

	if (!d)		/* Kludge for testing */
		return (def);
	p = lookup_package_property(env, name, d);
	if (p == NULL)
		return (def);
	return (get_decoded_int(p->data));
}

int
get_num_addr_cells(fcode_env_t *env, device_t *d)
{
	return (get_default_intprop(env, "#address-cells", d, 2));
}

int
get_num_size_cells(fcode_env_t *env, device_t *d)
{
	return (get_default_intprop(env, "#size-cells", d, 1));
}

void
decode_phys(fcode_env_t *env)
{
	char *ptr;
	int len;
	int adr_cells;
	int offset;

	CHECK_DEPTH(env, 2, "decode-phys");
	ptr = pop_a_string(env, &len);

	adr_cells = get_num_addr_cells(env, env->current_device->parent);

	offset = sizeof (uint32_t) * adr_cells;

	PUSH(DS, (fstack_t)(ptr + offset));
	PUSH(DS, len + offset);

	while (adr_cells--) {
		fstack_t d;
		offset -= sizeof (uint32_t);
		d = get_decoded_int((uchar_t *)(ptr + offset));
		PUSH(DS, d);
	}
}

/*
 * 'reg' Fcode 0x116
 */
void
reg_prop(fcode_env_t *env)
{
	fstack_t size;

	CHECK_DEPTH(env, 1, "reg");
	size = POP(DS);
	encode_phys(env);
	PUSH(DS, size);
	encode_int(env);
	encode_plus(env);
	create_prop(env, "reg");
}

void
encode_bytes(fcode_env_t *env)
{
	char *str;
	char *prop;
	int len;

	CHECK_DEPTH(env, 2, "encode-bytes");
	str = pop_a_string(env, &len);
	prop = add_property_buffer(env, len);
	memcpy(prop, str, len);
	prop[len] = 0;
	PUSH(DS, (fstack_t)prop);
	PUSH(DS, len);
}

void
decode_int(fcode_env_t *env)
{
	char *dp;
	fstack_t d;
	int len;

	CHECK_DEPTH(env, 2, "decode-int");
	dp = pop_a_string(env, &len);
	PUSH(DS, (fstack_t)(dp + sizeof (uint32_t)));
	PUSH(DS, len - sizeof (uint32_t));
	d = get_decoded_int((uchar_t *)dp);
	PUSH(DS, d);
}

void
decode_string(fcode_env_t *env)
{
	int plen, len;
	char *dp;

	CHECK_DEPTH(env, 2, "decode-string");
	dp = pop_a_string(env, &plen);
	len = strlen(dp) + 1;
	PUSH(DS, (fstack_t)(dp + len));
	PUSH(DS, plen - len);
	PUSH(DS, (fstack_t)dp);
	PUSH(DS, len - 1);
}

void
encode_plus(fcode_env_t *env)
{
	int len1, len2;
	char *src1, *src2;
	uchar_t *new;

	CHECK_DEPTH(env, 4, "encode+");
	src1 = pop_a_string(env, &len1);
	src2 = pop_a_string(env, &len2);
	new = add_property_buffer(env, len1 + len2);
	if (src2) {
		memcpy(new, src2, len2);
		free_property_buffer(env, src2);
	}
	if (src1) {
		memcpy(new + len2, src1, len1);
		free_property_buffer(env, src1);
	}
	PUSH(DS, (fstack_t)new);
	PUSH(DS, len1 + len2);
}

static void
make_special_property(fcode_env_t *env, char *name)
{
	push_a_string(env, name);
	property(env);
}

void
device_name(fcode_env_t *env)
{
	CHECK_DEPTH(env, 2, "device-name");
	encode_string(env);
	make_special_property(env, "name");
}

void
model_prop(fcode_env_t *env)
{
	CHECK_DEPTH(env, 2, "model");
	encode_string(env);
	make_special_property(env, "model");
}

void
device_type(fcode_env_t *env)
{
	CHECK_DEPTH(env, 2, "device-type");
	encode_string(env);
	make_special_property(env, "device_type");
}

/*
 * 'next-property' Fcode implementation.
 */
void
next_property(fcode_env_t *env)
{
	device_t *phandle;
	char *previous;
	prop_t *p;

	CHECK_DEPTH(env, 3, "next-property");
	phandle = (device_t *)POP(DS);
	previous = pop_a_string(env, NULL);
	p = phandle->properties;
	if (previous == NULL)
		p = phandle->properties;
	else if (p = find_property(phandle, previous))
		p = p->next;

	for (; p != NULL && p->name == NULL; p = p->next)
		;

	if (p)
		push_a_string(env, p->name);
	else
		push_a_string(env, "");
	PUSH(DS, TRUE);
}

void
get_property(fcode_env_t *env)
{
	if (MYSELF)
		get_my_property(env);
	else if (env->current_device) {
		fstack_t d;

		REVERT_PHANDLE(env, d, env->current_device);
		PUSH(DS, d);
		get_package_property(env);
	} else {
		two_drop(env);
		log_message(MSG_WARN, "No device context\n");
	}
}

#ifdef DEBUG

static void
print_indented(char *name)
{
	log_message(MSG_INFO, "%-28s", name);
}

static void
print_string(fcode_env_t *env, uchar_t *data, int len)
{
	while (len > 0) {
		int nlen = (strlen((char *)data)+1);
		log_message(MSG_INFO, "%s\n", data);
		len -= nlen;
		data += nlen;
		if (len > 0)
			print_indented("");
	}
}

static void
print_ints(uchar_t *data, int len, int crlf)
{
	uint32_t d;

	while (len--) {
		d = get_decoded_int(data);
		log_message(MSG_INFO, "%8.8lx ", d);
		data += sizeof (uint32_t);
	}
	if (crlf)
		log_message(MSG_INFO, "\n");
}

static void
print_integer(fcode_env_t *env, uchar_t *data, int len)
{
	print_ints(data, len/sizeof (uint32_t), 1);
}

static void
print_bytes(fcode_env_t *env, uchar_t *data, int len)
{
	while (len--) {
		log_message(MSG_INFO, "%2.2x ", *data++);
	}
	log_message(MSG_INFO, "\n");
}

static void
print_bytes_indented(fcode_env_t *env, uchar_t *data, int len)
{
	int nbytes;

	for (; ; ) {
		nbytes = min(len, 16);
		print_bytes(env, data, nbytes);
		len -= nbytes;
		data += nbytes;
		if (len == 0)
			break;
		print_indented("");
	}
}

static void
print_reg(fcode_env_t *env, uchar_t *data, int len)
{
	int pcells, nlen;

	if (env->current_device != NULL &&
	    env->current_device->parent != NULL) {
		pcells = get_num_size_cells(env, env->current_device->parent);
		pcells +=  get_num_addr_cells(env, env->current_device->parent);
		nlen = pcells*sizeof (uint32_t);
		while (len > 0) {
			print_ints(data, pcells, 1);
			len -= nlen;
			data += nlen;
			if (len > 0)
				print_indented("");
		}
	} else
		print_bytes_indented(env, data, len);
}

static void
print_imap(fcode_env_t *env, uchar_t *dp, int len)
{
	int n, icells;

	if (env->current_device == NULL) {
		print_bytes_indented(env, dp, len);
		return;
	}
	n = get_num_addr_cells(env, env->current_device);

	while (len) {
		int offset;
		fstack_t data;
		device_t *node;

		offset = 0;
		data = get_decoded_int(dp+((n+1)*sizeof (uint32_t)));
		CONVERT_PHANDLE(env, node, data);
		offset += (n+2)*sizeof (uint32_t);
		print_ints(dp, (n+2), 0);
		icells = get_default_intprop(env, "#interrupt-cells", node, 1);
		print_ints(dp+offset, icells, 1);
		offset += icells*sizeof (uint32_t);
		dp += offset;
		len -= offset;
		if (len)
			print_indented("");
	}
}

static void
print_ranges(fcode_env_t *env, uchar_t *data, int len)
{
	int pcells, nlen;

	if (env->current_device != NULL &&
	    env->current_device->parent != NULL) {
		pcells = get_num_addr_cells(env, env->current_device);
		pcells += get_num_addr_cells(env, env->current_device->parent);
		pcells += get_num_size_cells(env, env->current_device);
		nlen = pcells*sizeof (uint32_t);
		while (len > 0) {
			print_ints(data, pcells, 1);
			len -= nlen;
			data += nlen;
			if (len > 0)
				print_indented("");
		}
	} else
		print_bytes_indented(env, data, len);
}

typedef struct MAGIC_PROP {
	char *name;
	void (*fn)(fcode_env_t *env, uchar_t *data, int len);
} magic_prop_t;

static magic_prop_t magic_props[] = {
	{ "name",		print_string },
	{ "device_type",	print_string },
	{ "model",		print_string },
	{ "reg",		print_reg },
	{ "assigned-addresses",	print_reg },
	{ "interrupt-map",	print_imap },
	{ "#interrupt-cells",	print_integer },
	{ "interrupt-map-mask",	print_integer },
	{ "#size-cells",	print_integer },
	{ "#address-cells",	print_integer },
	{ "ranges",		print_ranges },
	{ "device-id",		print_integer },
	{ "vendor-id",		print_integer },
	{ "class-code",		print_integer },
	{ "compatible",		print_string },
	{ "version",		print_string },
	{ "manufacturer",	print_string },
	{ NULL, NULL }
};

static void
print_content(fcode_env_t *env, char *prop, uchar_t *data, int len)
{
	magic_prop_t *p;

	for (p = magic_props; p->name; p++)
		if (strcmp(prop, p->name) == 0) {
			(*p->fn)(env, data, len);
			return;
		}
	print_bytes_indented(env, data, len);
}

void
print_property(fcode_env_t *env, prop_t *p, char *prepend)
{
	char buf[40];
	char *name = (p->name ? p->name : "<noname>");

	if (prepend) {
		sprintf(buf, "%s %s", prepend, name);
		name = buf;
	}
	print_indented(name);
	if (p->name)
		print_content(env, p->name, p->data, p->size);
	else
		print_bytes_indented(env, p->data, p->size);
}

void
dot_properties(fcode_env_t *env)
{
	prop_t *p;
	instance_t *omyself;

	omyself = MYSELF;
	MYSELF = NULL;

	if (env->current_device) {
		for (p = env->current_device->properties; p; p = p->next)
			print_property(env, p, NULL);
	} else {
		log_message(MSG_INFO, "No device context\n");
	}
	MYSELF = omyself;
}

#endif

#pragma init(_init)

static void
_init(void)
{
	fcode_env_t *env = initial_env;

	ASSERT(env);
	NOTICE;

	P1275(0x110, 0,		"property",		property);
	P1275(0x111, 0,		"encode-int",		encode_int);
	P1275(0x112, 0,		"encode+",		encode_plus);
	P1275(0x113, 0,		"encode-phys",		encode_phys);
	P1275(0x114, 0,		"encode-string",	encode_string);
	P1275(0x115, 0,		"encode-bytes",		encode_bytes);
	P1275(0x116, 0,		"reg",			reg_prop);
	FCODE(0x117, 0,		"intr",			fc_obsolete);
	FCODE(0x118, 0,		"driver",		fc_historical);
	P1275(0x119, 0,		"model",		model_prop);
	P1275(0x11a, 0,		"device-type",		device_type);

	P1275(0x128, 0,		"decode-phys",		decode_phys);

	P1275(0x201, 0,		"device-name",		device_name);

	P1275(0x21a, 0,		"get-my-property",	get_my_property);
	P1275(0x21b, 0,		"decode-int",		decode_int);
	P1275(0x21c, 0,		"decode-string",	decode_string);
	P1275(0x21d, 0,		"get-inherited-property", get_inherited_prop);
	P1275(0x21e, 0,		"delete-property",	delete_property);
	P1275(0x21f, 0,		"get-package-property",	get_package_property);

	P1275(0x23d, 0,		"next-property",	next_property);

	FORTH(0,		"get-property",		get_property);
	FORTH(0,		".properties",		dot_properties);
}