int oss_ioctl_mixer(struct lwp *lwp, const struct oss_sys_ioctl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(u_long) com; syscallarg(void *) data; } */ file_t *fp; u_long com; struct audiodevinfo *di; mixer_ctrl_t mc; struct oss_mixer_info omi; struct audio_device adev; int idat; int i; int error; int l, r, n, e; int (*ioctlf)(file_t *, u_long, void *); if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) return (EBADF); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { error = EBADF; goto out; } com = SCARG(uap, com); DPRINTF(("oss_ioctl_mixer: com=%08lx\n", com)); retval[0] = 0; di = getdevinfo(fp); if (di == 0) { error = EINVAL; goto out; } ioctlf = fp->f_ops->fo_ioctl; switch (com) { case OSS_GET_VERSION: idat = OSS_SOUND_VERSION; break; case OSS_SOUND_MIXER_INFO: case OSS_SOUND_OLD_MIXER_INFO: error = ioctlf(fp, AUDIO_GETDEV, &adev); if (error) goto out; omi.modify_counter = 1; strncpy(omi.id, adev.name, sizeof omi.id); strncpy(omi.name, adev.name, sizeof omi.name); error = copyout(&omi, SCARG(uap, data), OSS_IOCTL_SIZE(com)); goto out; case OSS_SOUND_MIXER_READ_RECSRC: if (di->source == -1) { error = EINVAL; goto out; } mc.dev = di->source; if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { mc.type = AUDIO_MIXER_ENUM; error = ioctlf(fp, AUDIO_MIXER_READ, &mc); if (error) goto out; e = opaque_to_enum(di, NULL, mc.un.ord); if (e >= 0) idat = 1 << di->rdevmap[e]; } else { mc.type = AUDIO_MIXER_SET; error = ioctlf(fp, AUDIO_MIXER_READ, &mc); if (error) goto out; e = opaque_to_enum(di, NULL, mc.un.mask); if (e >= 0) idat = 1 << di->rdevmap[e]; } break; case OSS_SOUND_MIXER_READ_DEVMASK: idat = di->devmask; break; case OSS_SOUND_MIXER_READ_RECMASK: idat = di->recmask; break; case OSS_SOUND_MIXER_READ_STEREODEVS: idat = di->stereomask; break; case OSS_SOUND_MIXER_READ_CAPS: idat = di->caps; break; case OSS_SOUND_MIXER_WRITE_RECSRC: case OSS_SOUND_MIXER_WRITE_R_RECSRC: if (di->source == -1) { error = EINVAL; goto out; } mc.dev = di->source; error = copyin(SCARG(uap, data), &idat, sizeof idat); if (error) goto out; if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { mc.type = AUDIO_MIXER_ENUM; for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) if (idat & (1 << i)) break; if (i >= OSS_SOUND_MIXER_NRDEVICES || di->devmap[i] == -1) { error = EINVAL; goto out; } mc.un.ord = enum_to_ord(di, di->devmap[i]); } else { mc.type = AUDIO_MIXER_SET; mc.un.mask = 0; for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) { if (idat & (1 << i)) { if (di->devmap[i] == -1) { error = EINVAL; goto out; } mc.un.mask |= enum_to_mask(di, di->devmap[i]); } } } error = ioctlf(fp, AUDIO_MIXER_WRITE, &mc); goto out; default: if (OSS_MIXER_READ(OSS_SOUND_MIXER_FIRST) <= com && com < OSS_MIXER_READ(OSS_SOUND_MIXER_NRDEVICES)) { n = OSS_GET_DEV(com); if (di->devmap[n] == -1) { error = EINVAL; goto out; } doread: mc.dev = di->devmap[n]; mc.type = AUDIO_MIXER_VALUE; mc.un.value.num_channels = di->stereomask & (1<<n) ? 2 : 1; error = ioctlf(fp, AUDIO_MIXER_READ, &mc); if (error) goto out; if (mc.un.value.num_channels != 2) { l = r = mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; } else { l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; } idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); DPRINTF(("OSS_MIXER_READ n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", n, di->devmap[n], l, r, idat)); break; } else if ((OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_FIRST) <= com && com < OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_NRDEVICES)) || (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES))) { n = OSS_GET_DEV(com); if (di->devmap[n] == -1) { error = EINVAL; goto out; } error = copyin(SCARG(uap, data), &idat, sizeof idat); if (error) goto out; l = FROM_OSSVOL( idat & 0xff); r = FROM_OSSVOL((idat >> 8) & 0xff); mc.dev = di->devmap[n]; mc.type = AUDIO_MIXER_VALUE; if (di->stereomask & (1<<n)) { mc.un.value.num_channels = 2; mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; } else { mc.un.value.num_channels = 1; mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2; } DPRINTF(("OSS_MIXER_WRITE n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", n, di->devmap[n], l, r, idat)); error = ioctlf(fp, AUDIO_MIXER_WRITE, &mc); if (error) goto out; if (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES)) { error = 0; goto out; } goto doread; } else {
int mixer_ioctl(int fd, unsigned long com, void *argp) { struct audiodevinfo *di; struct mixer_info *omi; struct audio_device adev; mixer_ctrl_t mc; int idat = 0; int i; int retval; int l, r, n, error, e; di = getdevinfo(fd); if (di == 0) return -1; switch (com) { case OSS_GETVERSION: idat = SOUND_VERSION; break; case SOUND_MIXER_INFO: case SOUND_OLD_MIXER_INFO: error = ioctl(fd, AUDIO_GETDEV, &adev); if (error) return (error); omi = argp; if (com == SOUND_MIXER_INFO) omi->modify_counter = 1; strncpy(omi->id, adev.name, sizeof omi->id); strncpy(omi->name, adev.name, sizeof omi->name); return 0; case SOUND_MIXER_READ_RECSRC: if (di->recsource == -1) return EINVAL; mc.dev = di->recsource; if (di->caps & SOUND_CAP_EXCL_INPUT) { mc.type = AUDIO_MIXER_ENUM; retval = ioctl(fd, AUDIO_MIXER_READ, &mc); if (retval < 0) return retval; e = opaque_to_enum(di, NULL, mc.un.ord); if (e >= 0) idat = 1 << di->rdevmap[e]; } else { mc.type = AUDIO_MIXER_SET; retval = ioctl(fd, AUDIO_MIXER_READ, &mc); if (retval < 0) return retval; e = opaque_to_enum(di, NULL, mc.un.mask); if (e >= 0) idat = 1 << di->rdevmap[e]; } break; case SOUND_MIXER_READ_DEVMASK: idat = di->devmask; break; case SOUND_MIXER_READ_RECMASK: idat = di->recmask; break; case SOUND_MIXER_READ_STEREODEVS: idat = di->stereomask; break; case SOUND_MIXER_READ_CAPS: idat = di->caps; break; case SOUND_MIXER_WRITE_RECSRC: case SOUND_MIXER_WRITE_R_RECSRC: if (di->recsource == -1) return EINVAL; mc.dev = di->recsource; idat = INTARG; if (di->caps & SOUND_CAP_EXCL_INPUT) { mc.type = AUDIO_MIXER_ENUM; for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (idat & (1 << i)) break; if (i >= SOUND_MIXER_NRDEVICES || di->devmap[i] == -1) return EINVAL; mc.un.ord = enum_to_ord(di, di->devmap[i]); } else { mc.type = AUDIO_MIXER_SET; mc.un.mask = 0; for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (idat & (1 << i)) { if (di->devmap[i] == -1) return EINVAL; mc.un.mask |= enum_to_mask(di, di->devmap[i]); } } } return ioctl(fd, AUDIO_MIXER_WRITE, &mc); default: if (MIXER_READ(SOUND_MIXER_FIRST) <= com && com < MIXER_READ(SOUND_MIXER_NRDEVICES)) { n = GET_DEV(com); if (di->devmap[n] == -1) return EINVAL; mc.dev = di->devmap[n]; mc.type = AUDIO_MIXER_VALUE; doread: mc.un.value.num_channels = di->stereomask & (1<<n) ? 2 : 1; retval = ioctl(fd, AUDIO_MIXER_READ, &mc); if (retval < 0) return retval; if (mc.type != AUDIO_MIXER_VALUE) return EINVAL; if (mc.un.value.num_channels != 2) { l = r = mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; } else { l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; } idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); break; } else if ((MIXER_WRITE_R(SOUND_MIXER_FIRST) <= com && com < MIXER_WRITE_R(SOUND_MIXER_NRDEVICES)) || (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))) { n = GET_DEV(com); if (di->devmap[n] == -1) return EINVAL; idat = INTARG; l = FROM_OSSVOL( idat & 0xff); r = FROM_OSSVOL((idat >> 8) & 0xff); mc.dev = di->devmap[n]; mc.type = AUDIO_MIXER_VALUE; if (di->stereomask & (1<<n)) { mc.un.value.num_channels = 2; mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; } else { mc.un.value.num_channels = 1; mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2; } retval = ioctl(fd, AUDIO_MIXER_WRITE, &mc); if (retval < 0) return retval; if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && com < MIXER_WRITE(SOUND_MIXER_NRDEVICES)) return 0; goto doread; } else {