int
openpromioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
{
	struct opiocdesc *op;
	int node, len, ok, error, s;
	char *name, *value, *nextprop;
	static char buf[32];	/* XXX */

	if (optionsnode == 0) {
		s = splhigh();
		optionsnode = OF_getnodebyname(0, "options");
		splx(s);
	}

	/* All too easy... */
	if (cmd == OPIOCGETOPTNODE) {
		*(int *)data = optionsnode;
		return (0);
	}

	/* Verify node id */
	op = (struct opiocdesc *)data;
	node = op->op_nodeid;
	if (node != 0 && node != lastnode && node != optionsnode) {
		/* Not an easy one, must search for it */
		s = splhigh();
		ok = openpromcheckid(OF_peer(0), node);
		splx(s);
		if (!ok)
			return (EINVAL);
		lastnode = node;
	}

	name = value = NULL;
	error = 0;
	switch (cmd) {

	case OPIOCGET:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openpromgetstr(op->op_namelen, op->op_name, &name);
		if (error)
			break;
		s = splhigh();
		strlcpy(buf, name, 32);	/* XXX */
		len = OF_getproplen(node, buf);
		splx(s);
		if (len > op->op_buflen) {
			error = ENOMEM;
			break;
		}
		op->op_buflen = len;
		/* -1 means no entry; 0 means no value */
		if (len <= 0)
			break;
		value = malloc(len, M_TEMP, M_WAITOK);
		s = splhigh();
		strlcpy(buf, name, 32);	/* XXX */
		OF_getprop(node, buf, value, len);
		splx(s);
		error = copyout(value, op->op_buf, len);
		break;

	case OPIOCSET:
		if ((flags & FWRITE) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openpromgetstr(op->op_namelen, op->op_name, &name);
		if (error)
			break;
		error = openpromgetstr(op->op_buflen, op->op_buf, &value);
		if (error)
			break;
		s = splhigh();
		strlcpy(buf, name, 32);	/* XXX */
		len = OF_setprop(node, buf, value, op->op_buflen + 1);
		splx(s);
		if (len != op->op_buflen)
			error = EINVAL;
		break;

	case OPIOCNEXTPROP:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openpromgetstr(op->op_namelen, op->op_name, &name);
		if (error)
			break;
		if (op->op_buflen <= 0) {
			error = ENAMETOOLONG;
			break;
		}
		value = nextprop = malloc(OPROMMAXPARAM, M_TEMP, M_WAITOK);
		if (nextprop == NULL) {
			error = ENOMEM;
			break;
		}
		s = splhigh();
		strlcpy(buf, name, 32);	/* XXX */
		error = OF_nextprop(node, buf, nextprop);
		splx(s);
		if (error == -1) {
			error = EINVAL;
			break;
		}
		if (error == 0) {
			char nul = '\0';

			op->op_buflen = 0;
			error = copyout(&nul, op->op_buf, sizeof(char));
			break;
		}
		len = strlen(nextprop);
		if (len > op->op_buflen)
			len = op->op_buflen;
		else
			op->op_buflen = len;
		error = copyout(nextprop, op->op_buf, len);
		break;

	case OPIOCGETNEXT:
		if ((flags & FREAD) == 0)
			return (EBADF);
		s = splhigh();
		node = OF_peer(node);
		splx(s);
		*(int *)data = lastnode = node;
		break;

	case OPIOCGETCHILD:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		s = splhigh();
		node = OF_child(node);
		splx(s);
		*(int *)data = lastnode = node;
		break;

	default:
		return (ENOTTY);
	}

	if (name)
		free(name, M_TEMP);
	if (value)
		free(value, M_TEMP);

	return (error);
}
Beispiel #2
0
int
openfirm_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
    struct thread *td)
{
	struct ofiocdesc *of;
	phandle_t node;
	int len, ok, error;
	char *name, *value;
	char newname[32];

	if ((flags & FREAD) == 0)
		return (EBADF);

	of = (struct ofiocdesc *)data;
	switch (cmd) {
	case OFIOCGETOPTNODE:
		*(phandle_t *) data = OF_finddevice("/options");
		return (0);
	case OFIOCGET:
	case OFIOCSET:
	case OFIOCNEXTPROP:
	case OFIOCFINDDEVICE:
	case OFIOCGETPROPLEN:
		node = of->of_nodeid;
		break;
	case OFIOCGETNEXT:
	case OFIOCGETCHILD:
		node = *(phandle_t *)data;
		break;
	default:
		return (ENOIOCTL);
	}

	if (node != 0 && node != lastnode) {
		/* Not an easy one, we must search for it. */
		ok = openfirm_checkid(OF_peer(0), node);
		if (!ok)
			return (EINVAL);
		lastnode = node;
	}

	name = value = NULL;
	error = 0;
	switch (cmd) {

	case OFIOCGET:
	case OFIOCGETPROPLEN:
		if (node == 0)
			return (EINVAL);
		error = openfirm_getstr(of->of_namelen, of->of_name, &name);
		if (error)
			break;
		len = OF_getproplen(node, name);
		if (cmd == OFIOCGETPROPLEN) {
			of->of_buflen = len;
			break;
		}
		if (len > of->of_buflen) {
			error = ENOMEM;
			break;
		}
		of->of_buflen = len;
		/* -1 means no entry; 0 means no value. */
		if (len <= 0)
			break;
		value = malloc(len, M_TEMP, M_WAITOK);
		if (value == NULL) {
			error = ENOMEM;
			break;
		}
		len = OF_getprop(node, name, (void *)value, len);
		error = copyout(value, of->of_buf, len);
		break;

	case OFIOCSET:
		/*
		 * Note: Text string values for at least the /options node
		 * have to be null-terminated and the length parameter must
		 * include this terminating null.  However, like OF_getprop(),
		 * OF_setprop() will return the actual length of the text
		 * string, i.e. omitting the terminating null.
		 */
		if ((flags & FWRITE) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		if ((u_int)of->of_buflen > OFIOCMAXVALUE)
			return (ENAMETOOLONG);
		error = openfirm_getstr(of->of_namelen, of->of_name, &name);
		if (error)
			break;
		value = malloc(of->of_buflen, M_TEMP, M_WAITOK);
		if (value == NULL) {
			error = ENOMEM;
			break;
		}
		error = copyin(of->of_buf, value, of->of_buflen);
		if (error)
			break;
		len = OF_setprop(node, name, value, of->of_buflen);
		if (len < 0)
			error = EINVAL;
		of->of_buflen = len;
		break;

	case OFIOCNEXTPROP:
		if (node == 0 || of->of_buflen < 0)
			return (EINVAL);
		if (of->of_namelen != 0) {
			error = openfirm_getstr(of->of_namelen, of->of_name,
			    &name);
			if (error)
				break;
		}
		ok = OF_nextprop(node, name, newname, sizeof(newname));
		if (ok == 0) {
			error = ENOENT;
			break;
		}
		if (ok == -1) {
			error = EINVAL;
			break;
		}
		len = strlen(newname) + 1;
		if (len > of->of_buflen)
			len = of->of_buflen;
		else
			of->of_buflen = len;
		error = copyout(newname, of->of_buf, len);
		break;

	case OFIOCGETNEXT:
		node = OF_peer(node);
		*(phandle_t *)data = lastnode = node;
		break;

	case OFIOCGETCHILD:
		if (node == 0)
			return (EINVAL);
		node = OF_child(node);
		*(phandle_t *)data = lastnode = node;
		break;

	case OFIOCFINDDEVICE:
		error = openfirm_getstr(of->of_namelen, of->of_name, &name);
		if (error)
			break;
		node = OF_finddevice(name);
		if (node == 0 || node == -1) {
			error = ENOENT;
			break;
		}
		of->of_nodeid = lastnode = node;
		break;
	}

	if (name != NULL)
		free(name, M_TEMP);
	if (value != NULL)
		free(value, M_TEMP);

	return (error);
}
Beispiel #3
0
static int
openprom_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
    struct thread *td)
{
	struct openpromio *oprom;
	phandle_t node;
	uint32_t len;
	size_t done;
	int proplen;
	char *prop;
	char *buf;
	int error;

	if ((flags & FREAD) == 0)
		return (EPERM);

	prop = buf = NULL;
	error = 0;
	switch (cmd) {
	case OPROMCHILD:
	case OPROMNEXT:
		if (data == NULL || *(void **)data == NULL)
			return (EINVAL);
		oprom = *(void **)data;
		error = copyin(&oprom->oprom_size, &len, sizeof(len));
		if (error != 0)
			break;
		if (len != sizeof(node)) {
			error = EINVAL;
			break;
		}
		error = copyin(&oprom->oprom_array, &node, sizeof(node));
		if (error != 0)
			break;
		error = openprom_node_valid(node);
		if (error != 0)
			break;
		switch (cmd) {
		case OPROMCHILD:
			node = OF_child(node);
			break;
		case OPROMNEXT:
			node = OF_peer(node);
			break;
		}
		error = copyout(&node, &oprom->oprom_array, sizeof(node));
		if (error != 0)
			break;
		openprom_node = node;
		break;
	case OPROMGETPROP:
	case OPROMNXTPROP:
		if (data == NULL || *(void **)data == NULL)
			return (EINVAL);
		oprom = *(void **)data;
		error = copyin(&oprom->oprom_size, &len, sizeof(len));
		if (error != 0)
			break;
		if (len > OPROMMAXPARAM) {
			error = EINVAL;
			break;
		}
		prop = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
		if (prop == NULL) {
			error = ENOMEM;
			break;
		}
		error = copyinstr(&oprom->oprom_array, prop, len, &done);
		if (error != 0)
			break;
		buf = malloc(OPROMMAXPARAM, M_TEMP, M_WAITOK | M_ZERO);
		if (buf == NULL) {
			error = ENOMEM;
			break;
		}
		node = openprom_node;
		switch (cmd) {
		case OPROMGETPROP:
			proplen = OF_getproplen(node, prop);
			if (proplen > OPROMMAXPARAM) {
				error = EINVAL;
				break;
			}
			error = OF_getprop(node, prop, buf, proplen);
			break;
		case OPROMNXTPROP:
			error = OF_nextprop(node, prop, buf, OPROMMAXPARAM);
			proplen = strlen(buf);
			break;
		}
		if (error != -1) {
			error = copyout(&proplen, &oprom->oprom_size,
			    sizeof(proplen));
			if (error == 0)
				error = copyout(buf, &oprom->oprom_array,
				    proplen + 1);
		} else
			error = EINVAL;
		break;
	default:
		error = ENOIOCTL;
		break;
	}

	if (prop != NULL)
		free(prop, M_TEMP);
	if (buf != NULL)
		free(buf, M_TEMP);

	return (error);
}
Beispiel #4
0
int
openfirmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
{
	struct ofiocdesc *of;
	int node, len, ok, error, s;
	char *name, *value;

	if (cmd == OFIOCGETOPTNODE) {
		s = splhigh();
		*(int *) data = OF_finddevice("/options");
		splx(s);
		return (0);
	}

	/* Verify node id */
	of = (struct ofiocdesc *)data;
	node = of->of_nodeid;
	if (node != 0 && node != lastnode) {
		/* Not an easy one, must search for it */
		s = splhigh();
		ok = openfirmcheckid(OF_peer(0), node);
		splx(s);
		if (!ok)
			return (EINVAL);
		lastnode = node;
	}

	name = value = NULL;
	error = 0;
	switch (cmd) {

	case OFIOCGET:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openfirmgetstr(of->of_namelen, of->of_name, &name);
		if (error)
			break;
		s = splhigh();
		len = OF_getproplen(node, name);
		splx(s);
		if (len > of->of_buflen) {
			error = ENOMEM;
			break;
		}
		of->of_buflen = len;
		/* -1 means no entry; 0 means no value */
		if (len <= 0)
			break;
		value = malloc(len, M_TEMP, M_WAITOK);
		if (value == NULL) {
			error = ENOMEM;
			break;
		}
		s = splhigh();
		len = OF_getprop(node, name, (void *)value, len);
		splx(s);
		error = copyout(value, of->of_buf, len);
		break;


	case OFIOCSET:
		if ((flags & FWRITE) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		error = openfirmgetstr(of->of_namelen, of->of_name, &name);
		if (error)
			break;
		error = openfirmgetstr(of->of_buflen, of->of_buf, &value);
		if (error)
			break;
		s = splhigh();
		len = OF_setprop(node, name, value, of->of_buflen + 1);
		splx(s);

		/* 
		 * XXX
		 * some OF implementations return the buffer length including 
		 * the trailing zero ( like macppc ) and some without ( like
		 * FirmWorks OF used in Shark )
		 */
		if ((len != (of->of_buflen + 1)) && (len != of->of_buflen))
			error = EINVAL;
		break;

	case OFIOCNEXTPROP: {
		char newname[32];
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		if (of->of_namelen != 0) {
			error = openfirmgetstr(of->of_namelen, of->of_name,
			    &name);
			if (error)
				break;
		}
		s = splhigh();
		ok = OF_nextprop(node, name, newname);
		splx(s);
		if (ok == 0) {
			error = ENOENT;
			break;
		}
		if (ok == -1) {
			error = EINVAL;
			break;
		}
		len = strlen(newname);
		if (len > of->of_buflen)
			len = of->of_buflen;
		else
			of->of_buflen = len;
		error = copyout(newname, of->of_buf, len);
		break;
	}

	case OFIOCGETNEXT:
		if ((flags & FREAD) == 0)
			return (EBADF);
		s = splhigh();
		node = OF_peer(node);
		splx(s);
		*(int *)data = lastnode = node;
		break;

	case OFIOCGETCHILD:
		if ((flags & FREAD) == 0)
			return (EBADF);
		if (node == 0)
			return (EINVAL);
		s = splhigh();
		node = OF_child(node);
		splx(s);
		*(int *)data = lastnode = node;
		break;

	case OFIOCFINDDEVICE:
		if ((flags & FREAD) == 0)
			return (EBADF);
		error = openfirmgetstr(of->of_namelen, of->of_name, &name);
		if (error)
			break;
		node = OF_finddevice(name);
		if (node == 0 || node == -1) {
			error = ENOENT;
			break;
		}
		of->of_nodeid = lastnode = node;
		break;

	default:
		return (ENOTTY);
	}

	if (name)
		free(name, M_TEMP);
	if (value)
		free(value, M_TEMP);

	return (error);
}