/* * write new or original values to nvram */ int cpr_update_nvram(cprop_t *props) { cprop_t *tail; pnode_t node; int len, rc; if (rc = cpr_get_options_node(&node)) return (rc); if (cpr_show_props) prom_printf("\ncpr_show_props:\n"); for (tail = props + CPR_MAXPROP; props < tail; props++) { if (cpr_show_props) { prom_printf("mod=%c, name \"%s\",\tvalue \"%s\"\n", props->mod, props->name, props->value); } if (props->mod == PROP_NOMOD) continue; /* * Note: When doing a prom_setprop you must include the * trailing NULL in the length argument, but when calling * prom_getproplen() the NULL is excluded from the count! */ len = strlen(props->value); rc = prom_setprop(node, props->name, props->value, len + 1); if (rc < 0 || prom_getproplen(node, props->name) != len) { cpr_err(CE_WARN, "cannot set nvram \"%s\" to \"%s\"", props->name, props->value); return (ENXIO); } } return (0); }
int of_set_property(struct device_node *dp, const char *name, void *val, int len) { struct property **prevp; void *new_val; int err; new_val = kmalloc(len, GFP_KERNEL); if (!new_val) return -ENOMEM; memcpy(new_val, val, len); err = -ENODEV; mutex_lock(&of_set_property_mutex); write_lock(&devtree_lock); prevp = &dp->properties; while (*prevp) { struct property *prop = *prevp; if (!strcasecmp(prop->name, name)) { void *old_val = prop->value; int ret; ret = prom_setprop(dp->phandle, name, val, len); err = -EINVAL; if (ret >= 0) { prop->value = new_val; prop->length = len; if (OF_IS_DYNAMIC(prop)) kfree(old_val); OF_MARK_DYNAMIC(prop); err = 0; } break; } prevp = &(*prevp)->next; } write_unlock(&devtree_lock); mutex_unlock(&of_set_property_mutex); /* XXX Upate procfs if necessary... */ return err; }
/* * NetBSD /dev/openprom ioctl calls. */ static int openprom_bsd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { DATA *data = (DATA *) file->private_data; struct opiocdesc op; unsigned long flags; int error, node, len; char *str, *tmp; char buffer[64]; static int cnt; switch (cmd) { case OPIOCGET: if (copy_from_user(&op, (void *)arg, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; error = copyin_string(op.op_name, op.op_namelen, &str); if (error) return error; save_and_cli(flags); len = prom_getproplen(op.op_nodeid,str); restore_flags(flags); if (len > op.op_buflen) { kfree(str); return -ENOMEM; } op.op_buflen = len; if (len <= 0) { kfree(str); /* Verified by the above copy_from_user */ if (__copy_to_user((void *)arg, &op, sizeof(op))) return -EFAULT; return 0; } tmp = kmalloc(len + 1, GFP_KERNEL); if (!tmp) { kfree(str); return -ENOMEM; } save_and_cli(flags); prom_getproperty(op.op_nodeid, str, tmp, len); restore_flags(flags); tmp[len] = '\0'; error = __copy_to_user((void *)arg, &op, sizeof(op)); if (!error) error = copy_to_user(op.op_buf, tmp, len); kfree(tmp); kfree(str); return error; case OPIOCNEXTPROP: if (copy_from_user(&op, (void *)arg, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; error = copyin_string(op.op_name, op.op_namelen, &str); if (error) return error; save_and_cli(flags); tmp = prom_nextprop(op.op_nodeid,str,buffer); restore_flags(flags); if (tmp) { len = strlen(tmp); if (len > op.op_buflen) len = op.op_buflen; else op.op_buflen = len; } else { len = op.op_buflen = 0; } error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(op)); if (error) { kfree(str); return error; } error = verify_area(VERIFY_WRITE, op.op_buf, len); if (error) { kfree(str); return error; } error = __copy_to_user((void *)arg, &op, sizeof(op)); if (!error) error = __copy_to_user(op.op_buf, tmp, len); kfree(str); return error; case OPIOCSET: if (copy_from_user(&op, (void *)arg, sizeof(op))) return -EFAULT; if (!goodnode(op.op_nodeid,data)) return -EINVAL; error = copyin_string(op.op_name, op.op_namelen, &str); if (error) return error; error = copyin_string(op.op_buf, op.op_buflen, &tmp); if (error) { kfree(str); return error; } save_and_cli(flags); len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1); restore_flags(flags); if (len != op.op_buflen) return -EINVAL; kfree(str); kfree(tmp); return 0; case OPIOCGETOPTNODE: if (copy_to_user((void *)arg, &options_node, sizeof(int))) return -EFAULT; return 0; case OPIOCGETNEXT: case OPIOCGETCHILD: if (copy_from_user(&node, (void *)arg, sizeof(int))) return -EFAULT; save_and_cli(flags); if (cmd == OPIOCGETNEXT) node = __prom_getsibling(node); else node = __prom_getchild(node); restore_flags(flags); if (__copy_to_user((void *)arg, &node, sizeof(int))) return -EFAULT; return 0; default: if (cnt++ < 10) printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd); return -EINVAL; } }
/* * SunOS and Solaris /dev/openprom ioctl calls. */ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg, int node) { DATA *data = (DATA *) file->private_data; char buffer[OPROMMAXPARAM+1], *buf; struct openpromio *opp; unsigned long flags; int bufsize, len, error = 0; extern char saved_command_line[]; static int cnt; if (cmd == OPROMSETOPT) bufsize = getstrings((void *)arg, &opp); else bufsize = copyin((void *)arg, &opp); if (bufsize < 0) return bufsize; switch (cmd) { case OPROMGETOPT: case OPROMGETPROP: save_and_cli(flags); len = prom_getproplen(node, opp->oprom_array); restore_flags(flags); if (len <= 0 || len > bufsize) { error = copyout((void *)arg, opp, sizeof(int)); break; } save_and_cli(flags); len = prom_getproperty(node, opp->oprom_array, buffer, bufsize); restore_flags(flags); memcpy(opp->oprom_array, buffer, len); opp->oprom_array[len] = '\0'; opp->oprom_size = len; error = copyout((void *)arg, opp, sizeof(int) + bufsize); break; case OPROMNXTOPT: case OPROMNXTPROP: save_and_cli(flags); buf = prom_nextprop(node, opp->oprom_array, buffer); restore_flags(flags); len = strlen(buf); if (len == 0 || len + 1 > bufsize) { error = copyout((void *)arg, opp, sizeof(int)); break; } memcpy(opp->oprom_array, buf, len); opp->oprom_array[len] = '\0'; opp->oprom_size = ++len; error = copyout((void *)arg, opp, sizeof(int) + bufsize); break; case OPROMSETOPT: case OPROMSETOPT2: buf = opp->oprom_array + strlen(opp->oprom_array) + 1; len = opp->oprom_array + bufsize - buf; save_and_cli(flags); error = prom_setprop(options_node, opp->oprom_array, buf, len); restore_flags(flags); if (error < 0) error = -EINVAL; break; case OPROMNEXT: case OPROMCHILD: case OPROMSETCUR: if (bufsize < sizeof(int)) { error = -EINVAL; break; } node = *((int *) opp->oprom_array); save_and_cli(flags); switch (cmd) { case OPROMNEXT: node = __prom_getsibling(node); break; case OPROMCHILD: node = __prom_getchild(node); break; case OPROMSETCUR: break; } restore_flags(flags); data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); error = copyout((void *)arg, opp, bufsize + sizeof(int)); break; case OPROMPCI2NODE: error = -EINVAL; if (bufsize >= 2*sizeof(int)) { #ifdef CONFIG_PCI struct pci_dev *pdev; struct pcidev_cookie *pcp; pdev = pci_find_slot (((int *) opp->oprom_array)[0], ((int *) opp->oprom_array)[1]); pcp = pdev->sysdata; if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) { node = pcp->prom_node; data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); error = copyout((void *)arg, opp, bufsize + sizeof(int)); } #endif } break; case OPROMPATH2NODE: save_and_cli(flags); node = prom_finddevice(opp->oprom_array); restore_flags(flags); data->current_node = node; *((int *)opp->oprom_array) = node; opp->oprom_size = sizeof(int); error = copyout((void *)arg, opp, bufsize + sizeof(int)); break; case OPROMGETBOOTARGS: buf = saved_command_line; len = strlen(buf); if (len > bufsize) { error = -EINVAL; break; } strcpy(opp->oprom_array, buf); opp->oprom_size = len; error = copyout((void *)arg, opp, bufsize + sizeof(int)); break; case OPROMU2P: case OPROMGETCONS: case OPROMGETFBNAME: if (cnt++ < 10) printk(KERN_INFO "openprom_sunos_ioctl: unimplemented ioctl\n"); error = -EINVAL; break; default: if (cnt++ < 10) printk(KERN_INFO "openprom_sunos_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg); error = -EINVAL; break; } kfree(opp); return error; }
int openpromioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) { struct opiocdesc *op; int node, optionsnode, len, ok, error, s; char *name, *value, *nextprop; optionsnode = prom_getoptionsnode(); /* All too easy... */ if (cmd == OPIOCGETOPTNODE) { *(int *)data = optionsnode; return (0); } /* Verify node id */ op = (struct opiocdesc *)data; node = op->op_nodeid; if (node != 0 && node != lastnode && node != optionsnode) { /* Not an easy one, must search for it */ s = splhigh(); ok = openpromcheckid(findroot(), node); splx(s); if (!ok) return (EINVAL); lastnode = node; } name = value = NULL; error = 0; switch (cmd) { case OPIOCGET: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; s = splhigh(); len = prom_proplen(node, name); splx(s); if (len > op->op_buflen) { error = ENOMEM; break; } op->op_buflen = len; /* -1 means no entry; 0 means no value */ if (len <= 0) break; value = malloc(len, M_TEMP, M_WAITOK); s = splhigh(); error = prom_getprop(node, name, 1, &len, &value); splx(s); if (error != 0) break; error = copyout(value, op->op_buf, len); break; case OPIOCSET: if ((flags & FWRITE) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; error = openpromgetstr(op->op_buflen, op->op_buf, &value); if (error) break; s = splhigh(); len = prom_setprop(node, name, value, op->op_buflen + 1); splx(s); if (len != op->op_buflen) error = EINVAL; break; case OPIOCNEXTPROP: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; s = splhigh(); nextprop = prom_nextprop(node, name); splx(s); len = strlen(nextprop); if (len > op->op_buflen) len = op->op_buflen; else op->op_buflen = len; error = copyout(nextprop, op->op_buf, len); break; case OPIOCGETNEXT: if ((flags & FREAD) == 0) return (EBADF); s = splhigh(); node = nextsibling(node); splx(s); *(int *)data = lastnode = node; break; case OPIOCGETCHILD: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); s = splhigh(); node = firstchild(node); splx(s); *(int *)data = lastnode = node; break; case OPIOCFINDDEVICE: if ((flags & FREAD) == 0) return (EBADF); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; node = prom_finddevice(name); if (node == 0 || node == -1) { error = ENOENT; break; } op->op_nodeid = lastnode = node; break; default: return (ENOTTY); } if (name) free(name, M_TEMP); if (value) free(value, M_TEMP); return (error); }