int openpromioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { struct opiocdesc *op; int node, len, ok, error, s; char *name, *value, *nextprop; static char buf[32]; /* XXX */ if (optionsnode == 0) { s = splhigh(); optionsnode = OF_getnodebyname(0, "options"); splx(s); } /* All too easy... */ if (cmd == OPIOCGETOPTNODE) { *(int *)data = optionsnode; return (0); } /* Verify node id */ op = (struct opiocdesc *)data; node = op->op_nodeid; if (node != 0 && node != lastnode && node != optionsnode) { /* Not an easy one, must search for it */ s = splhigh(); ok = openpromcheckid(OF_peer(0), node); splx(s); if (!ok) return (EINVAL); lastnode = node; } name = value = NULL; error = 0; switch (cmd) { case OPIOCGET: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; s = splhigh(); strlcpy(buf, name, 32); /* XXX */ len = OF_getproplen(node, buf); splx(s); if (len > op->op_buflen) { error = ENOMEM; break; } op->op_buflen = len; /* -1 means no entry; 0 means no value */ if (len <= 0) break; value = malloc(len, M_TEMP, M_WAITOK); s = splhigh(); strlcpy(buf, name, 32); /* XXX */ OF_getprop(node, buf, value, len); splx(s); error = copyout(value, op->op_buf, len); break; case OPIOCSET: if ((flags & FWRITE) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; error = openpromgetstr(op->op_buflen, op->op_buf, &value); if (error) break; s = splhigh(); strlcpy(buf, name, 32); /* XXX */ len = OF_setprop(node, buf, value, op->op_buflen + 1); splx(s); if (len != op->op_buflen) error = EINVAL; break; case OPIOCNEXTPROP: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openpromgetstr(op->op_namelen, op->op_name, &name); if (error) break; if (op->op_buflen <= 0) { error = ENAMETOOLONG; break; } value = nextprop = malloc(OPROMMAXPARAM, M_TEMP, M_WAITOK); if (nextprop == NULL) { error = ENOMEM; break; } s = splhigh(); strlcpy(buf, name, 32); /* XXX */ error = OF_nextprop(node, buf, nextprop); splx(s); if (error == -1) { error = EINVAL; break; } if (error == 0) { char nul = '\0'; op->op_buflen = 0; error = copyout(&nul, op->op_buf, sizeof(char)); break; } len = strlen(nextprop); if (len > op->op_buflen) len = op->op_buflen; else op->op_buflen = len; error = copyout(nextprop, op->op_buf, len); break; case OPIOCGETNEXT: if ((flags & FREAD) == 0) return (EBADF); s = splhigh(); node = OF_peer(node); splx(s); *(int *)data = lastnode = node; break; case OPIOCGETCHILD: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); s = splhigh(); node = OF_child(node); splx(s); *(int *)data = lastnode = node; break; default: return (ENOTTY); } if (name) free(name, M_TEMP); if (value) free(value, M_TEMP); return (error); }
int openfirm_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { struct ofiocdesc *of; phandle_t node; int len, ok, error; char *name, *value; char newname[32]; if ((flags & FREAD) == 0) return (EBADF); of = (struct ofiocdesc *)data; switch (cmd) { case OFIOCGETOPTNODE: *(phandle_t *) data = OF_finddevice("/options"); return (0); case OFIOCGET: case OFIOCSET: case OFIOCNEXTPROP: case OFIOCFINDDEVICE: case OFIOCGETPROPLEN: node = of->of_nodeid; break; case OFIOCGETNEXT: case OFIOCGETCHILD: node = *(phandle_t *)data; break; default: return (ENOIOCTL); } if (node != 0 && node != lastnode) { /* Not an easy one, we must search for it. */ ok = openfirm_checkid(OF_peer(0), node); if (!ok) return (EINVAL); lastnode = node; } name = value = NULL; error = 0; switch (cmd) { case OFIOCGET: case OFIOCGETPROPLEN: if (node == 0) return (EINVAL); error = openfirm_getstr(of->of_namelen, of->of_name, &name); if (error) break; len = OF_getproplen(node, name); if (cmd == OFIOCGETPROPLEN) { of->of_buflen = len; break; } if (len > of->of_buflen) { error = ENOMEM; break; } of->of_buflen = len; /* -1 means no entry; 0 means no value. */ if (len <= 0) break; value = malloc(len, M_TEMP, M_WAITOK); if (value == NULL) { error = ENOMEM; break; } len = OF_getprop(node, name, (void *)value, len); error = copyout(value, of->of_buf, len); break; case OFIOCSET: /* * Note: Text string values for at least the /options node * have to be null-terminated and the length parameter must * include this terminating null. However, like OF_getprop(), * OF_setprop() will return the actual length of the text * string, i.e. omitting the terminating null. */ if ((flags & FWRITE) == 0) return (EBADF); if (node == 0) return (EINVAL); if ((u_int)of->of_buflen > OFIOCMAXVALUE) return (ENAMETOOLONG); error = openfirm_getstr(of->of_namelen, of->of_name, &name); if (error) break; value = malloc(of->of_buflen, M_TEMP, M_WAITOK); if (value == NULL) { error = ENOMEM; break; } error = copyin(of->of_buf, value, of->of_buflen); if (error) break; len = OF_setprop(node, name, value, of->of_buflen); if (len < 0) error = EINVAL; of->of_buflen = len; break; case OFIOCNEXTPROP: if (node == 0 || of->of_buflen < 0) return (EINVAL); if (of->of_namelen != 0) { error = openfirm_getstr(of->of_namelen, of->of_name, &name); if (error) break; } ok = OF_nextprop(node, name, newname, sizeof(newname)); if (ok == 0) { error = ENOENT; break; } if (ok == -1) { error = EINVAL; break; } len = strlen(newname) + 1; if (len > of->of_buflen) len = of->of_buflen; else of->of_buflen = len; error = copyout(newname, of->of_buf, len); break; case OFIOCGETNEXT: node = OF_peer(node); *(phandle_t *)data = lastnode = node; break; case OFIOCGETCHILD: if (node == 0) return (EINVAL); node = OF_child(node); *(phandle_t *)data = lastnode = node; break; case OFIOCFINDDEVICE: error = openfirm_getstr(of->of_namelen, of->of_name, &name); if (error) break; node = OF_finddevice(name); if (node == 0 || node == -1) { error = ENOENT; break; } of->of_nodeid = lastnode = node; break; } if (name != NULL) free(name, M_TEMP); if (value != NULL) free(value, M_TEMP); return (error); }
static int openprom_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { struct openpromio *oprom; phandle_t node; uint32_t len; size_t done; int proplen; char *prop; char *buf; int error; if ((flags & FREAD) == 0) return (EPERM); prop = buf = NULL; error = 0; switch (cmd) { case OPROMCHILD: case OPROMNEXT: if (data == NULL || *(void **)data == NULL) return (EINVAL); oprom = *(void **)data; error = copyin(&oprom->oprom_size, &len, sizeof(len)); if (error != 0) break; if (len != sizeof(node)) { error = EINVAL; break; } error = copyin(&oprom->oprom_array, &node, sizeof(node)); if (error != 0) break; error = openprom_node_valid(node); if (error != 0) break; switch (cmd) { case OPROMCHILD: node = OF_child(node); break; case OPROMNEXT: node = OF_peer(node); break; } error = copyout(&node, &oprom->oprom_array, sizeof(node)); if (error != 0) break; openprom_node = node; break; case OPROMGETPROP: case OPROMNXTPROP: if (data == NULL || *(void **)data == NULL) return (EINVAL); oprom = *(void **)data; error = copyin(&oprom->oprom_size, &len, sizeof(len)); if (error != 0) break; if (len > OPROMMAXPARAM) { error = EINVAL; break; } prop = malloc(len, M_TEMP, M_WAITOK | M_ZERO); if (prop == NULL) { error = ENOMEM; break; } error = copyinstr(&oprom->oprom_array, prop, len, &done); if (error != 0) break; buf = malloc(OPROMMAXPARAM, M_TEMP, M_WAITOK | M_ZERO); if (buf == NULL) { error = ENOMEM; break; } node = openprom_node; switch (cmd) { case OPROMGETPROP: proplen = OF_getproplen(node, prop); if (proplen > OPROMMAXPARAM) { error = EINVAL; break; } error = OF_getprop(node, prop, buf, proplen); break; case OPROMNXTPROP: error = OF_nextprop(node, prop, buf, OPROMMAXPARAM); proplen = strlen(buf); break; } if (error != -1) { error = copyout(&proplen, &oprom->oprom_size, sizeof(proplen)); if (error == 0) error = copyout(buf, &oprom->oprom_array, proplen + 1); } else error = EINVAL; break; default: error = ENOIOCTL; break; } if (prop != NULL) free(prop, M_TEMP); if (buf != NULL) free(buf, M_TEMP); return (error); }
int openfirmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) { struct ofiocdesc *of; int node, len, ok, error, s; char *name, *value; if (cmd == OFIOCGETOPTNODE) { s = splhigh(); *(int *) data = OF_finddevice("/options"); splx(s); return (0); } /* Verify node id */ of = (struct ofiocdesc *)data; node = of->of_nodeid; if (node != 0 && node != lastnode) { /* Not an easy one, must search for it */ s = splhigh(); ok = openfirmcheckid(OF_peer(0), node); splx(s); if (!ok) return (EINVAL); lastnode = node; } name = value = NULL; error = 0; switch (cmd) { case OFIOCGET: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; s = splhigh(); len = OF_getproplen(node, name); splx(s); if (len > of->of_buflen) { error = ENOMEM; break; } of->of_buflen = len; /* -1 means no entry; 0 means no value */ if (len <= 0) break; value = malloc(len, M_TEMP, M_WAITOK); if (value == NULL) { error = ENOMEM; break; } s = splhigh(); len = OF_getprop(node, name, (void *)value, len); splx(s); error = copyout(value, of->of_buf, len); break; case OFIOCSET: if ((flags & FWRITE) == 0) return (EBADF); if (node == 0) return (EINVAL); error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; error = openfirmgetstr(of->of_buflen, of->of_buf, &value); if (error) break; s = splhigh(); len = OF_setprop(node, name, value, of->of_buflen + 1); splx(s); /* * XXX * some OF implementations return the buffer length including * the trailing zero ( like macppc ) and some without ( like * FirmWorks OF used in Shark ) */ if ((len != (of->of_buflen + 1)) && (len != of->of_buflen)) error = EINVAL; break; case OFIOCNEXTPROP: { char newname[32]; if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); if (of->of_namelen != 0) { error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; } s = splhigh(); ok = OF_nextprop(node, name, newname); splx(s); if (ok == 0) { error = ENOENT; break; } if (ok == -1) { error = EINVAL; break; } len = strlen(newname); if (len > of->of_buflen) len = of->of_buflen; else of->of_buflen = len; error = copyout(newname, of->of_buf, len); break; } case OFIOCGETNEXT: if ((flags & FREAD) == 0) return (EBADF); s = splhigh(); node = OF_peer(node); splx(s); *(int *)data = lastnode = node; break; case OFIOCGETCHILD: if ((flags & FREAD) == 0) return (EBADF); if (node == 0) return (EINVAL); s = splhigh(); node = OF_child(node); splx(s); *(int *)data = lastnode = node; break; case OFIOCFINDDEVICE: if ((flags & FREAD) == 0) return (EBADF); error = openfirmgetstr(of->of_namelen, of->of_name, &name); if (error) break; node = OF_finddevice(name); if (node == 0 || node == -1) { error = ENOENT; break; } of->of_nodeid = lastnode = node; break; default: return (ENOTTY); } if (name) free(name, M_TEMP); if (value) free(value, M_TEMP); return (error); }