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