[go: nahoru, domu]

11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux/SPARC PROM Configuration Driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1996 Eddie C. Dost  (ecd@skynet.be)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This character device driver allows user programs to access the
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PROM device tree. It is compatible with the SunOS /dev/openprom
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver and the NetBSD /dev/openprom driver. The SunOS eeprom
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * utility works without any modifications.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The driver uses a minor number under the misc device major. The
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file read/write mode determines the type of access to the PROM.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interrupts are disabled whenever the driver calls into the PROM for
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sanity's sake.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This program is free software; you can redistribute it and/or
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License as
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation; either version 2 of the
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License, or (at your option) any later version.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, but
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License for more details.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
36a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmann#include <linux/mutex.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/oplib.h>
428e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller#include <asm/prom.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/openpromio.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PCI
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
498e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. MillerMODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost  (ecd@skynet.be)");
508e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. MillerMODULE_DESCRIPTION("OPENPROM Configuration Driver");
518e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. MillerMODULE_LICENSE("GPL");
528e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. MillerMODULE_VERSION("1.0");
531c339eb183bb48095feaa46057ac4f4f0603dbf9Scott James RemnantMODULE_ALIAS_MISCDEV(SUN_OPENPROM_MINOR);
548e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Private data kept by the driver for each descriptor. */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct openprom_private_data
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
588e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *current_node; /* Current node for SunOS ioctls. */
598e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *lastnode; /* Last valid node used by BSD ioctls. */
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} DATA;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ID of the PROM node containing all of the EEPROM options. */
63a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmannstatic DEFINE_MUTEX(openprom_mutex);
648e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic struct device_node *options_node;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy an openpromio structure into kernel space from user space.
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine does error checking to make sure that all memory
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * accesses are within bounds. A pointer to the allocated openpromio
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * structure will be placed in "*opp_p". Return value is the length
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the user supplied buffer.
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int copyin(struct openpromio __user *info, struct openpromio **opp_p)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int bufsize;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info || !opp_p)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(bufsize, &info->oprom_size))
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bufsize == 0)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If the bufsize is too large, just limit it.
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Fix from Jason Rappleye.
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bufsize > OPROMMAXPARAM)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufsize = OPROMMAXPARAM;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
928e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&(*opp_p)->oprom_array,
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   &info->oprom_array, bufsize)) {
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(*opp_p);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return bufsize;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int n, bufsize;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!info || !opp_p)
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1118e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (!(*opp_p = kzalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(*opp_p)->oprom_size = 0;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = bufsize = 0;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((n < 2) && (bufsize < OPROMMAXPARAM)) {
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (get_user(c, &info->oprom_array[bufsize])) {
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(*opp_p);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EFAULT;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (c == '\0')
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			n++;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(*opp_p)->oprom_array[bufsize++] = c;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!n) {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(*opp_p);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return bufsize;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy an openpromio structure in kernel space back to user space.
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int copyout(void __user *info, struct openpromio *opp, int len)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(info, opp, len))
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1438e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
1448e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
145ccf0dec6fcadb4e1c877b9bafb031a6bdb7112b9Stephen Rothwell	const void *pval;
1468e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int len;
1478e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
148b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller	if (!dp ||
149b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller	    !(pval = of_get_property(dp, op->oprom_array, &len)) ||
150b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller	    len <= 0 || len > bufsize)
1518e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return copyout(argp, op, sizeof(int));
1528e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1538e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	memcpy(op->oprom_array, pval, len);
1548e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	op->oprom_array[len] = '\0';
1558e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	op->oprom_size = len;
1568e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1578e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return copyout(argp, op, sizeof(int) + bufsize);
1588e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
1598e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1608e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
1618e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
1628e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct property *prop;
1638e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int len;
1648e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
165b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller	if (!dp)
166b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller		return copyout(argp, op, sizeof(int));
1678e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (op->oprom_array[0] == '\0') {
1688e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		prop = dp->properties;
1698e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (!prop)
1708e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			return copyout(argp, op, sizeof(int));
1718e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		len = strlen(prop->name);
1728e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	} else {
1738e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		prop = of_find_property(dp, op->oprom_array, NULL);
1748e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1758e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (!prop ||
1768e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		    !prop->next ||
1778e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		    (len = strlen(prop->next->name)) + 1 > bufsize)
1788e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			return copyout(argp, op, sizeof(int));
1798e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1808e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		prop = prop->next;
1818e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
1828e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1838e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	memcpy(op->oprom_array, prop->name, len);
1848e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	op->oprom_array[len] = '\0';
1858e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	op->oprom_size = ++len;
1868e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1878e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return copyout(argp, op, sizeof(int) + bufsize);
1888e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
1898e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1908e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize)
1918e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
1928e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	char *buf = op->oprom_array + strlen(op->oprom_array) + 1;
1938e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int len = op->oprom_array + bufsize - buf;
1948e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1958e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return of_set_property(options_node, op->oprom_array, buf, len);
1968e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
1978e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
1988e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
1998e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
2008e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	phandle ph;
2018e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2028e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
2038e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2048e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (bufsize < sizeof(phandle))
2058e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EINVAL;
2068e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2078e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	ph = *((int *) op->oprom_array);
2088e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (ph) {
2098e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		dp = of_find_node_by_phandle(ph);
2108e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (!dp)
2118e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			return -EINVAL;
2128e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2138e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		switch (cmd) {
2148e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		case OPROMNEXT:
2158e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			dp = dp->sibling;
2168e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			break;
2178e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2188e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		case OPROMCHILD:
2198e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			dp = dp->child;
2208e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			break;
2218e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2228e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		case OPROMSETCUR:
2238e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		default:
2248e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			break;
225da201161662b8ee9c8d7bd8cc50ce3cb3366d400Peter Senna Tschudin		}
2268e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	} else {
2278e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		/* Sibling of node zero is the root node.  */
2288e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (cmd != OPROMNEXT)
2298e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			return -EINVAL;
2308e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2318e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		dp = of_find_node_by_path("/");
2328e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
2338e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2348e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	ph = 0;
2358e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (dp)
2366016a363f6b56b46b24655bcfc0499b715851cf3Grant Likely		ph = dp->phandle;
2378e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2388e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	data->current_node = dp;
2398e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	*((int *) op->oprom_array) = ph;
2408e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	op->oprom_size = sizeof(phandle);
2418e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2428e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return copyout(argp, op, bufsize + sizeof(int));
2438e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
2448e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2458e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
2468e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
2478e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int err = -EINVAL;
2488e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2498e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (bufsize >= 2*sizeof(int)) {
2508e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller#ifdef CONFIG_PCI
2518e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		struct pci_dev *pdev;
252fa449bd602c8871da48e6dbadfa0faaf4d33d32eDavid S. Miller		struct device_node *dp;
253fa449bd602c8871da48e6dbadfa0faaf4d33d32eDavid S. Miller
2547e9f33461521180ef2c148c0b77eeb412d18ffaeAlan Cox		pdev = pci_get_bus_and_slot (((int *) op->oprom_array)[0],
2558e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller				      ((int *) op->oprom_array)[1]);
2568e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
257fa449bd602c8871da48e6dbadfa0faaf4d33d32eDavid S. Miller		dp = pci_device_to_OF_node(pdev);
258fa449bd602c8871da48e6dbadfa0faaf4d33d32eDavid S. Miller		data->current_node = dp;
2596016a363f6b56b46b24655bcfc0499b715851cf3Grant Likely		*((int *)op->oprom_array) = dp->phandle;
260fa449bd602c8871da48e6dbadfa0faaf4d33d32eDavid S. Miller		op->oprom_size = sizeof(int);
261fa449bd602c8871da48e6dbadfa0faaf4d33d32eDavid S. Miller		err = copyout(argp, op, bufsize + sizeof(int));
262fa449bd602c8871da48e6dbadfa0faaf4d33d32eDavid S. Miller
2637e9f33461521180ef2c148c0b77eeb412d18ffaeAlan Cox		pci_dev_put(pdev);
2648e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller#endif
2658e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
2668e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2678e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return err;
2688e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
2698e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2708e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
2718e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
272b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller	phandle ph = 0;
273b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller
2748e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	dp = of_find_node_by_path(op->oprom_array);
275b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller	if (dp)
2766016a363f6b56b46b24655bcfc0499b715851cf3Grant Likely		ph = dp->phandle;
2778e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	data->current_node = dp;
278b9b64e6e89fc5a6ef220747115c5b7764614ca3fDavid S. Miller	*((int *)op->oprom_array) = ph;
2798e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	op->oprom_size = sizeof(int);
2808e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2818e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return copyout(argp, op, bufsize + sizeof(int));
2828e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
2838e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2848e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize)
2858e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
2868e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	char *buf = saved_command_line;
2878e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int len = strlen(buf);
2888e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2898e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (len > bufsize)
2908e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EINVAL;
2918e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2928e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	strcpy(op->oprom_array, buf);
2938e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	op->oprom_size = len;
2948e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2958e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return copyout(argp, op, bufsize + sizeof(int));
2968e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
2978e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	SunOS and Solaris /dev/openprom ioctl calls.
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
30155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic long openprom_sunos_ioctl(struct file * file,
30255929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann				 unsigned int cmd, unsigned long arg,
30355929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann				 struct device_node *dp)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3058e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	DATA *data = file->private_data;
30632e5897da1fc5180aa817c81e6aca74a8f6b6957David S. Miller	struct openpromio *opp = NULL;
3078e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int bufsize, error = 0;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int cnt;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void __user *argp = (void __user *)arg;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cmd == OPROMSETOPT)
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufsize = getstrings(argp, &opp);
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bufsize = copyin(argp, &opp);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bufsize < 0)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return bufsize;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
319a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmann	mutex_lock(&openprom_mutex);
32055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETOPT:
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETPROP:
3248e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		error = opromgetprop(argp, dp, opp, bufsize);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMNXTOPT:
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMNXTPROP:
3298e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		error = opromnxtprop(argp, dp, opp, bufsize);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMSETOPT:
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMSETOPT2:
3348e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		error = opromsetopt(dp, opp, bufsize);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMNEXT:
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMCHILD:
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMSETCUR:
3408e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		error = opromnext(argp, cmd, dp, opp, bufsize, data);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMPCI2NODE:
3448e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		error = oprompci2node(argp, dp, opp, bufsize, data);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMPATH2NODE:
3488e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		error = oprompath2node(argp, dp, opp, bufsize, data);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETBOOTARGS:
3528e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		error = opromgetbootargs(argp, opp, bufsize);
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMU2P:
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETCONS:
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETFBNAME:
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cnt++ < 10)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_INFO "openprom_sunos_ioctl: unimplemented ioctl\n");
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = -EINVAL;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cnt++ < 10)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_INFO "openprom_sunos_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = -EINVAL;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(opp);
370a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmann	mutex_unlock(&openprom_mutex);
37155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3758e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic struct device_node *get_node(phandle n, DATA *data)
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3778e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *dp = of_find_node_by_phandle(n);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3798e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (dp)
3808e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		data->lastnode = dp;
3818e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
3828e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return dp;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Copy in a whole string from userspace into kernelspace. */
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int copyin_string(char __user *user, size_t len, char **ptr)
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *tmp;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ssize_t)len < 0 || (ssize_t)(len + 1) < 0)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = kmalloc(len + 1, GFP_KERNEL);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tmp)
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3978e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (copy_from_user(tmp, user, len)) {
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(tmp);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp[len] = '\0';
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ptr = tmp;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	NetBSD /dev/openprom ioctl calls.
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4128e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opiocget(void __user *argp, DATA *data)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct opiocdesc op;
4158e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *dp;
4168e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	char *str;
417ccf0dec6fcadb4e1c877b9bafb031a6bdb7112b9Stephen Rothwell	const void *pval;
4188e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int err, len;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4208e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (copy_from_user(&op, argp, sizeof(op)))
4218e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EFAULT;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4238e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	dp = get_node(op.op_nodeid, data);
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4258e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	err = copyin_string(op.op_name, op.op_namelen, &str);
4268e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (err)
4278e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return err;
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4298e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	pval = of_get_property(dp, str, &len);
4308e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	err = 0;
4318e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (!pval || len > op.op_buflen) {
4328e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		err = -EINVAL;
4338e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	} else {
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		op.op_buflen = len;
4358e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (copy_to_user(argp, &op, sizeof(op)) ||
4368e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		    copy_to_user(op.op_buf, pval, len))
4378e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			err = -EFAULT;
4388e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
4398e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	kfree(str);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4418e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return err;
4428e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4448e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opiocnextprop(void __user *argp, DATA *data)
4458e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
4468e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct opiocdesc op;
4478e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *dp;
4488e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct property *prop;
4498e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	char *str;
4508e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int err, len;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4528e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (copy_from_user(&op, argp, sizeof(op)))
4538e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EFAULT;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4558e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	dp = get_node(op.op_nodeid, data);
4568e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (!dp)
4578e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EINVAL;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4598e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	err = copyin_string(op.op_name, op.op_namelen, &str);
4608e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (err)
4618e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return err;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4638e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (str[0] == '\0') {
4648e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		prop = dp->properties;
4658e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	} else {
4668e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		prop = of_find_property(dp, str, NULL);
4678e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (prop)
4688e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			prop = prop->next;
4698e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
4708e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	kfree(str);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4728e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (!prop)
4738e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		len = 0;
4748e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	else
4758e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		len = prop->length;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4778e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (len > op.op_buflen)
4788e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		len = op.op_buflen;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4808e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (copy_to_user(argp, &op, sizeof(op)))
4818e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EFAULT;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4838e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (len &&
4848e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	    copy_to_user(op.op_buf, prop->value, len))
4858e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EFAULT;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4878e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return 0;
4888e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4908e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opiocset(void __user *argp, DATA *data)
4918e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
4928e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct opiocdesc op;
4938e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *dp;
4948e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	char *str, *tmp;
4958e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int err;
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4978e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (copy_from_user(&op, argp, sizeof(op)))
4988e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EFAULT;
4998e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
5008e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	dp = get_node(op.op_nodeid, data);
5018e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (!dp)
5028e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EINVAL;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5048e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	err = copyin_string(op.op_name, op.op_namelen, &str);
5058e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (err)
5068e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return err;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5088e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	err = copyin_string(op.op_buf, op.op_buflen, &tmp);
5098e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (err) {
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(str);
5118e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return err;
5128e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5148e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	err = of_set_property(dp, str, tmp, op.op_buflen);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5168e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	kfree(str);
5178e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	kfree(tmp);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5198e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return err;
5208e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5228e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Millerstatic int opiocgetnext(unsigned int cmd, void __user *argp)
5238e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
5248e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *dp;
5258e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	phandle nd;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5278e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5298e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (copy_from_user(&nd, argp, sizeof(phandle)))
5308e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EFAULT;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5328e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (nd == 0) {
5338e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (cmd != OPIOCGETNEXT)
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
5358e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		dp = of_find_node_by_path("/");
5368e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	} else {
5378e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		dp = of_find_node_by_phandle(nd);
5388e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		nd = 0;
5398e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (dp) {
5408e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			if (cmd == OPIOCGETNEXT)
5418e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller				dp = dp->sibling;
5428e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			else
5438e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller				dp = dp->child;
5448e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		}
5458e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
5468e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (dp)
5476016a363f6b56b46b24655bcfc0499b715851cf3Grant Likely		nd = dp->phandle;
5488e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (copy_to_user(argp, &nd, sizeof(phandle)))
5498e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return -EFAULT;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5518e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return 0;
5528e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller}
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55455929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic int openprom_bsd_ioctl(struct file * file,
5558e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			      unsigned int cmd, unsigned long arg)
5568e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller{
55733cfe65a786cf3d048688b932f41df937282a7bbJoe Perches	DATA *data = file->private_data;
5588e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	void __user *argp = (void __user *)arg;
5598e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int err;
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmann	mutex_lock(&openprom_mutex);
5628e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	switch (cmd) {
5638e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	case OPIOCGET:
5648e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		err = opiocget(argp, data);
5658e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		break;
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5678e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	case OPIOCNEXTPROP:
5688e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		err = opiocnextprop(argp, data);
5698e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		break;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5718e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	case OPIOCSET:
5728e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		err = opiocset(argp, data);
5738e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		break;
5748e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
5758e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	case OPIOCGETOPTNODE:
5768e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
57855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		err = 0;
5796016a363f6b56b46b24655bcfc0499b715851cf3Grant Likely		if (copy_to_user(argp, &options_node->phandle, sizeof(phandle)))
58055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann			err = -EFAULT;
58155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		break;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5838e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	case OPIOCGETNEXT:
5848e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	case OPIOCGETCHILD:
5858e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		err = opiocgetnext(cmd, argp);
5868e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		break;
5878e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
58955929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		err = -EINVAL;
59055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		break;
591da201161662b8ee9c8d7bd8cc50ce3cb3366d400Peter Senna Tschudin	}
592a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmann	mutex_unlock(&openprom_mutex);
5938e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller
5948e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	return err;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Handoff control to the correct ioctl handler.
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
60155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic long openprom_ioctl(struct file * file,
60255929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann			   unsigned int cmd, unsigned long arg)
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
60433cfe65a786cf3d048688b932f41df937282a7bbJoe Perches	DATA *data = file->private_data;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETOPT:
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMNXTOPT:
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((file->f_mode & FMODE_READ) == 0)
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
61155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		return openprom_sunos_ioctl(file, cmd, arg,
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    options_node);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMSETOPT:
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMSETOPT2:
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((file->f_mode & FMODE_WRITE) == 0)
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
61855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		return openprom_sunos_ioctl(file, cmd, arg,
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    options_node);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMNEXT:
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMCHILD:
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETPROP:
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMNXTPROP:
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((file->f_mode & FMODE_READ) == 0)
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
62755929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		return openprom_sunos_ioctl(file, cmd, arg,
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					    data->current_node);
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMU2P:
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETCONS:
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETFBNAME:
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMGETBOOTARGS:
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMSETCUR:
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMPCI2NODE:
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPROMPATH2NODE:
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((file->f_mode & FMODE_READ) == 0)
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EPERM;
63955929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		return openprom_sunos_ioctl(file, cmd, arg, NULL);
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPIOCGET:
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPIOCNEXTPROP:
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPIOCGETOPTNODE:
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPIOCGETNEXT:
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPIOCGETCHILD:
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((file->f_mode & FMODE_READ) == 0)
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EBADF;
64855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		return openprom_bsd_ioctl(file,cmd,arg);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPIOCSET:
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((file->f_mode & FMODE_WRITE) == 0)
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EBADF;
65355929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		return openprom_bsd_ioctl(file,cmd,arg);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
6578e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	};
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
660b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwigstatic long openprom_compat_ioctl(struct file *file, unsigned int cmd,
661b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig		unsigned long arg)
662b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig{
663b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	long rval = -ENOTTY;
664b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig
665b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	/*
666b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	 * SunOS/Solaris only, the NetBSD one's have embedded pointers in
667b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	 * the arg which we'd need to clean up...
668b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	 */
669b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	switch (cmd) {
670b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMGETOPT:
671b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMSETOPT:
672b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMNXTOPT:
673b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMSETOPT2:
674b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMNEXT:
675b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMCHILD:
676b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMGETPROP:
677b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMNXTPROP:
678b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMU2P:
679b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMGETCONS:
680b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMGETFBNAME:
681b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMGETBOOTARGS:
682b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMSETCUR:
683b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMPCI2NODE:
684b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	case OPROMPATH2NODE:
68555929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann		rval = openprom_ioctl(file, cmd, arg);
686b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig		break;
687b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig	}
688d5a858bc148fe97996af9cf685cc124b70519adfDavid S. Miller
689d5a858bc148fe97996af9cf685cc124b70519adfDavid S. Miller	return rval;
690b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig}
691b31023fc24e5c39d246e9c6fc75dba1a2902c1d6Christoph Hellwig
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int openprom_open(struct inode * inode, struct file * file)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DATA *data;
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6968e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	data = kmalloc(sizeof(DATA), GFP_KERNEL);
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!data)
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
700a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmann	mutex_lock(&openprom_mutex);
7018e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	data->current_node = of_find_node_by_path("/");
7028e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	data->lastnode = data->current_node;
7038e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	file->private_data = (void *) data;
704a3108ca2323dec0f6321c3f7706cdaed51f694eaArnd Bergmann	mutex_unlock(&openprom_mutex);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int openprom_release(struct inode * inode, struct file * file)
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(file->private_data);
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71500977a59b951207d38380c75f03a36829950265cArjan van de Venstatic const struct file_operations openprom_fops = {
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =	THIS_MODULE,
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek =	no_llseek,
71855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann	.unlocked_ioctl = openprom_ioctl,
719d5a858bc148fe97996af9cf685cc124b70519adfDavid S. Miller	.compat_ioctl =	openprom_compat_ioctl,
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open =		openprom_open,
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release =	openprom_release,
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct miscdevice openprom_dev = {
7258e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	.minor		= SUN_OPENPROM_MINOR,
7268e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	.name		= "openprom",
7278e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	.fops		= &openprom_fops,
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init openprom_init(void)
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7328e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	struct device_node *dp;
7338e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	int err;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7358e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	err = misc_register(&openprom_dev);
7368e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (err)
7378e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		return err;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7398e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	dp = of_find_node_by_path("/");
7408e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	dp = dp->child;
7418e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	while (dp) {
7428e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		if (!strcmp(dp->name, "options"))
7438e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller			break;
7448e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller		dp = dp->sibling;
7458e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	}
7468e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	options_node = dp;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7488e48aec714f1faf581949f23ae0e3d6e2317433bDavid S. Miller	if (!options_node) {
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		misc_deregister(&openprom_dev);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EIO;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit openprom_cleanup(void)
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	misc_deregister(&openprom_dev);
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(openprom_init);
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(openprom_cleanup);
763