+static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
+{
+ void *pval;
+ int len;
+
+ if (!dp ||
+ !(pval = of_get_property(dp, op->oprom_array, &len)) ||
+ len <= 0 || len > bufsize)
+ return copyout(argp, op, sizeof(int));
+
+ memcpy(op->oprom_array, pval, len);
+ op->oprom_array[len] = '\0';
+ op->oprom_size = len;
+
+ return copyout(argp, op, sizeof(int) + bufsize);
+}
+
+static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
+{
+ struct property *prop;
+ int len;
+
+ if (!dp)
+ return copyout(argp, op, sizeof(int));
+ if (op->oprom_array[0] == '\0') {
+ prop = dp->properties;
+ if (!prop)
+ return copyout(argp, op, sizeof(int));
+ len = strlen(prop->name);
+ } else {
+ prop = of_find_property(dp, op->oprom_array, NULL);
+
+ if (!prop ||
+ !prop->next ||
+ (len = strlen(prop->next->name)) + 1 > bufsize)
+ return copyout(argp, op, sizeof(int));
+
+ prop = prop->next;
+ }
+
+ memcpy(op->oprom_array, prop->name, len);
+ op->oprom_array[len] = '\0';
+ op->oprom_size = ++len;
+
+ return copyout(argp, op, sizeof(int) + bufsize);
+}
+
+static int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize)
+{
+ char *buf = op->oprom_array + strlen(op->oprom_array) + 1;
+ int len = op->oprom_array + bufsize - buf;
+
+ return of_set_property(options_node, op->oprom_array, buf, len);
+}
+
+static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+ phandle ph;
+
+ BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
+
+ if (bufsize < sizeof(phandle))
+ return -EINVAL;
+
+ ph = *((int *) op->oprom_array);
+ if (ph) {
+ dp = of_find_node_by_phandle(ph);
+ if (!dp)
+ return -EINVAL;
+
+ switch (cmd) {
+ case OPROMNEXT:
+ dp = dp->sibling;
+ break;
+
+ case OPROMCHILD:
+ dp = dp->child;
+ break;
+
+ case OPROMSETCUR:
+ default:
+ break;
+ };
+ } else {
+ /* Sibling of node zero is the root node. */
+ if (cmd != OPROMNEXT)
+ return -EINVAL;
+
+ dp = of_find_node_by_path("/");
+ }
+
+ ph = 0;
+ if (dp)
+ ph = dp->node;
+
+ data->current_node = dp;
+ *((int *) op->oprom_array) = ph;
+ op->oprom_size = sizeof(phandle);
+
+ return copyout(argp, op, bufsize + sizeof(int));
+}
+
+static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+ int err = -EINVAL;
+
+ if (bufsize >= 2*sizeof(int)) {
+#ifdef CONFIG_PCI
+ struct pci_dev *pdev;
+ struct pcidev_cookie *pcp;
+ pdev = pci_find_slot (((int *) op->oprom_array)[0],
+ ((int *) op->oprom_array)[1]);
+
+ pcp = pdev->sysdata;
+ if (pcp != NULL) {
+ dp = pcp->prom_node;
+ data->current_node = dp;
+ *((int *)op->oprom_array) = dp->node;
+ op->oprom_size = sizeof(int);
+ err = copyout(argp, op, bufsize + sizeof(int));
+ }
+#endif
+ }
+
+ return err;
+}
+
+static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+ phandle ph = 0;
+
+ dp = of_find_node_by_path(op->oprom_array);
+ if (dp)
+ ph = dp->node;
+ data->current_node = dp;
+ *((int *)op->oprom_array) = ph;
+ op->oprom_size = sizeof(int);
+
+ return copyout(argp, op, bufsize + sizeof(int));
+}
+
+static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize)
+{
+ char *buf = saved_command_line;
+ int len = strlen(buf);
+
+ if (len > bufsize)
+ return -EINVAL;
+
+ strcpy(op->oprom_array, buf);
+ op->oprom_size = len;
+
+ return copyout(argp, op, bufsize + sizeof(int));
+}
+