Enscript Output

extractedLnx/linux-2.5.9/drivers/sbus/audio/audio.c_sparcaudio_ioctl.c

static int sparcaudio_ioctl(struct inode * inode, struct file * file,
			    unsigned int cmd, unsigned long arg)
{
	int retval = 0, i, j, k;
	int minor = minor(inode->i_rdev);
	struct audio_info ainfo;
	audio_buf_info binfo;
	count_info cinfo;
	struct sparcaudio_driver *drv = 
                drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)];

	switch (minor & 0xf) {
	case SPARCAUDIO_MIXER_MINOR:
                return sparcaudio_mixer_ioctl(inode, file, cmd, (unsigned int *)arg);
	case SPARCAUDIO_DSP16_MINOR:
        case SPARCAUDIO_DSP_MINOR:
	case SPARCAUDIO_AUDIO_MINOR:
	case SPARCAUDIO_AUDIOCTL_MINOR:
                /* According to the OSS prog int, you can mixer ioctl /dev/dsp */
                if (_IOC_TYPE(cmd) == 'M')
                        return sparcaudio_mixer_ioctl(inode, 
                                                      file, cmd, (unsigned int *)arg);
                switch (cmd) {
                case I_GETSIG:
                case I_GETSIG_SOLARIS:
                        j = (int) lis_get_elist_ent(drv->sd_siglist,current->pid);
                        put_user(j, (int *)arg);
                        retval = drv->input_count;
                        break;

                case I_SETSIG:
                case I_SETSIG_SOLARIS:
                        if ((minor & 0xf) == SPARCAUDIO_AUDIOCTL_MINOR) {
                                if (!arg) {
                                        if (lis_del_from_elist(&(drv->sd_siglist),
                                                               current->pid,S_ALL)) {
                                                retval = -EINVAL;
                                        } else if (!drv->sd_siglist) {
                                                drv->sd_sigflags=0;
                                        }
                                } else if (lis_add_to_elist(&(drv->sd_siglist),
                                                            current->pid,
                                                            (short)arg)) {
                                        retval = -EAGAIN;
                                } else {
                                        ((drv->sd_sigflags) |= (arg));
                                }
                        }
                        break;
                case I_NREAD:
                case I_NREAD_SOLARIS:
                        /* According to the Solaris man page, this copies out
                         * the size of the first streams buffer and returns 
                         * the number of streams messages on the read queue as
                         * as its retval. (streamio(7I)) This should work.
                         */
                        j = (drv->input_count > 0) ? drv->input_buffer_size : 0;
                        put_user(j, (int *)arg);
                        retval = drv->input_count;
                        break;

                        /* A poor substitute until we do true resizable buffers. */
                case SNDCTL_DSP_GETISPACE:
                        binfo.fragstotal = drv->num_input_buffers;
                        binfo.fragments = drv->num_input_buffers - 
                                (drv->input_count + drv->recording_count);
                        binfo.fragsize = drv->input_buffer_size;
                        binfo.bytes = binfo.fragments*binfo.fragsize;
	    
                        retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo));
                        if (retval)
                                break;
                        copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo));
                        break;
                case SNDCTL_DSP_GETOSPACE:
                        binfo.fragstotal = drv->num_output_buffers;
                        binfo.fragments = drv->num_output_buffers - 
                                (drv->output_count + drv->playing_count + 
                                 (drv->output_offset ? 1 : 0));
                        binfo.fragsize = drv->output_buffer_size;
                        binfo.bytes = binfo.fragments*binfo.fragsize + 
                                (drv->output_buffer_size - drv->output_offset);
	    
                        retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo));
                        if (retval)
                                break;
                        copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo));
                        break;
                case SNDCTL_DSP_GETIPTR:
                case SNDCTL_DSP_GETOPTR:
                        /* int bytes (number of bytes read/written since last)
                         * int blocks (number of frags read/wrote since last call)
                         * int ptr (current position of dma in buffer)
                         */
                        retval = 0;
                        cinfo.bytes = 0;
                        cinfo.ptr = 0;
                        cinfo.blocks = 0;
                        cinfo.bytes += cinfo.ptr;
	    
                        retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(cinfo));
                        if (retval)
                                break;
                        copy_to_user(&((char *)arg)[0], (char *)&cinfo, sizeof(cinfo));
                        break;
                case SNDCTL_DSP_SETFRAGMENT:
                        /* XXX Small hack to get ESD/Enlightenment to work.  --DaveM */
                        retval = 0;
                        break;

                case SNDCTL_DSP_SUBDIVIDE:
                        /* I don't understand what I need to do yet. */
                        retval = -EINVAL;
                        break;
                case SNDCTL_DSP_SETTRIGGER:
                        /* This may not be 100% correct */
                        if ((arg & PCM_ENABLE_INPUT) && drv->ops->get_input_pause &&
                            drv->ops->set_input_pause) {
                                if (drv->ops->get_input_pause(drv))
                                        drv->ops->set_input_pause(drv, 0);
                        } else {
                                if (!drv->ops->get_input_pause(drv))
                                        drv->ops->set_input_pause(drv, 1);
                        }
                        if ((arg & PCM_ENABLE_OUTPUT) && drv->ops->get_output_pause &&
                            drv->ops->set_output_pause) {
                                if (drv->ops->get_output_pause(drv))
                                        drv->ops->set_output_pause(drv, 0);
                        } else {
                                if (!drv->ops->get_output_pause(drv))
                                        drv->ops->set_output_pause(drv, 1);
                        }
                        break;
                case SNDCTL_DSP_GETTRIGGER:
                        j = 0;
                        if (drv->ops->get_input_pause) {
                                if (drv->ops->get_input_pause(drv))
                                        j = PCM_ENABLE_INPUT;
                        }
                        if (drv->ops->get_output_pause) {
                                if (drv->ops->get_output_pause(drv))
                                        j |= PCM_ENABLE_OUTPUT;
                        }
                        put_user(j, (int *)arg);
                        break;
                case SNDCTL_DSP_GETBLKSIZE:
                        j = drv->input_buffer_size;
                        put_user(j, (int *)arg);
                        break;
                case SNDCTL_DSP_SPEED:
                        if ((!drv->ops->set_output_rate) && 
                            (!drv->ops->set_input_rate)) {
                                retval = -EINVAL;
                                break;
                        }
                        get_user(i, (int *)arg)
                        tprintk(("setting speed to %d\n", i));
                        drv->ops->set_input_rate(drv, i);
                        drv->ops->set_output_rate(drv, i);
                        j = drv->ops->get_output_rate(drv);
                        put_user(j, (int *)arg);
                        break;
                case SNDCTL_DSP_GETCAPS:
                        /* All Sparc audio hardware is full duplex.
                         * 4231 supports DMA pointer reading, 7930 is byte at a time.
                         * Pause functionality emulates trigger
                         */
                        j = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER | DSP_CAP_REALTIME;
                        put_user(j, (int *)arg);
                        break;
                case SNDCTL_DSP_GETFMTS:
                        if (drv->ops->get_formats) {
                                j = drv->ops->get_formats(drv);
                                put_user(j, (int *)arg);
                        } else {
                                retval = -EINVAL;
                        }
                        break;
                case SNDCTL_DSP_SETFMT:
                        /* need to decode into encoding, precision */
                        get_user(i, (int *)arg);
	    
                        /* handle special case here */
                        if (i == AFMT_QUERY) {
                                j = drv->ops->get_output_encoding(drv);
                                k = drv->ops->get_output_precision(drv);
                                if (j == AUDIO_ENCODING_DVI) {
                                        i = AFMT_IMA_ADPCM;
                                } else if (k == 8) {
                                        switch (j) {
                                        case AUDIO_ENCODING_ULAW:
                                                i = AFMT_MU_LAW;
                                                break;
                                        case AUDIO_ENCODING_ALAW:
                                                i = AFMT_A_LAW;
                                                break;
                                        case AUDIO_ENCODING_LINEAR8:
                                                i = AFMT_U8;
                                                break;
                                        };
                                } else if (k == 16) {
                                        switch (j) {
                                        case AUDIO_ENCODING_LINEAR:
                                                i = AFMT_S16_BE;
                                                break;
                                        case AUDIO_ENCODING_LINEARLE:
                                                i = AFMT_S16_LE;
                                                break;
                                        };
                                } 
                                put_user(i, (int *)arg);
                                break;
                        }

                        /* Without these there's no point in trying */
                        if (!drv->ops->set_input_precision ||
                            !drv->ops->set_input_encoding ||
                            !drv->ops->set_output_precision ||
                            !drv->ops->set_output_encoding) {
                                eprintk(("missing set routines: failed\n"));
                                retval = -EINVAL;
                                break;
                        }

                        if (drv->ops->get_formats) {
                                if (!(drv->ops->get_formats(drv) & i)) {
                                        dprintk(("format not supported\n"));
                                        return -EINVAL;
                                }
                        }
                        switch (i) {
                        case AFMT_S16_LE:
                                ainfo.record.precision = ainfo.play.precision = 16;
                                ainfo.record.encoding = ainfo.play.encoding =
                                        AUDIO_ENCODING_LINEARLE;
                                break;
                        case AFMT_S16_BE:
                                ainfo.record.precision = ainfo.play.precision = 16;
                                ainfo.record.encoding = ainfo.play.encoding =
                                        AUDIO_ENCODING_LINEAR;
                                break;
                        case AFMT_MU_LAW:
                                ainfo.record.precision = ainfo.play.precision = 8;
                                ainfo.record.encoding = ainfo.play.encoding =
                                        AUDIO_ENCODING_ULAW;
                                break;
                        case AFMT_A_LAW:
                                ainfo.record.precision = ainfo.play.precision = 8;
                                ainfo.record.encoding = ainfo.play.encoding =
                                        AUDIO_ENCODING_ALAW;
                                break;
                        case AFMT_U8:
                                ainfo.record.precision = ainfo.play.precision = 8;
                                ainfo.record.encoding = ainfo.play.encoding =
                                        AUDIO_ENCODING_LINEAR8;
                                break;
                        };
                        tprintk(("setting fmt to enc %d pr %d\n",
                                 ainfo.play.encoding,
                                 ainfo.play.precision));
                        if ((drv->ops->set_input_precision(drv,
                                                           ainfo.record.precision) 
                             < 0) ||
                            (drv->ops->set_output_precision(drv,
                                                            ainfo.play.precision)  
                             < 0) ||
                            (drv->ops->set_input_encoding(drv,
                                                          ainfo.record.encoding)
                             < 0) ||
                            (drv->ops->set_output_encoding(drv,
                                                           ainfo.play.encoding)
                             < 0)) {
                                dprintk(("setting format: failed\n"));
                                return -EINVAL;
                        }
                        put_user(i, (int *)arg);
                        break;
                case SNDCTL_DSP_CHANNELS:
                        if ((!drv->ops->set_output_channels) && 
                            (!drv->ops->set_input_channels)) {
                                retval = -EINVAL;
                                break;
                        }
                        get_user(i, (int *)arg);
                        drv->ops->set_input_channels(drv, i);
                        drv->ops->set_output_channels(drv, i);
                        i = drv->ops->get_output_channels(drv);
                        put_user(i, (int *)arg);
                        break;
                case SNDCTL_DSP_STEREO:
                        if ((!drv->ops->set_output_channels) && 
                            (!drv->ops->set_input_channels)) {
                                retval = -EINVAL;
                                break;
                        }
                        get_user(i, (int *)arg);
                        drv->ops->set_input_channels(drv, (i + 1));
                        drv->ops->set_output_channels(drv, (i + 1));
                        i = ((drv->ops->get_output_channels(drv)) - 1);
                        put_user(i, (int *)arg);
                        break;
                case SNDCTL_DSP_POST:
                case SNDCTL_DSP_SYNC:
                case AUDIO_DRAIN:
                        /* Deal with weirdness so we can fill buffers */
                        if (drv->output_offset) {
                                drv->output_offset = 0;
                                drv->output_rear = (drv->output_rear + 1)
                                        % drv->num_output_buffers;
                                drv->output_count++;
                        }
                        if (drv->output_count > 0) {
                                sparcaudio_sync_output(drv);
                                /* Only pause for DRAIN/SYNC, not POST */
                                if (cmd != SNDCTL_DSP_POST) {
                                        interruptible_sleep_on(&drv->output_drain_wait);
                                        retval = (signal_pending(current)) ? -EINTR : 0;
                                }
                        }
                        break;
                case I_FLUSH:
                case I_FLUSH_SOLARIS:
                        if (((unsigned int)arg == FLUSHW) || 
                            ((unsigned int)arg == FLUSHRW)) {
                                if (file->f_mode & FMODE_WRITE) {
                                        sparcaudio_sync_output(drv);
                                        if (drv->output_active) {
                                                wake_up_interruptible(&drv->output_write_wait);
                                                drv->ops->stop_output(drv);
                                        }
                                        drv->output_offset = 0;
                                        drv->output_active = 0;
                                        drv->output_front = 0;
                                        drv->output_rear = 0;
                                        drv->output_count = 0;
                                        drv->output_size = 0;
                                        drv->playing_count = 0;
                                        drv->output_eof = 0;
                                }
                        }
                        if (((unsigned int)arg == FLUSHR) || 
                            ((unsigned int)arg == FLUSHRW)) {
                                if (drv->input_active && (file->f_mode & FMODE_READ)) {
                                        wake_up_interruptible(&drv->input_read_wait);
                                        drv->ops->stop_input(drv);
                                        drv->input_active = 0;
                                        drv->input_front = 0;
                                        drv->input_rear = 0;
                                        drv->input_count = 0;
                                        drv->input_size = 0;
                                        drv->input_offset = 0;
                                        drv->recording_count = 0;
                                }
                                if ((file->f_mode & FMODE_READ) && 
                                    (drv->flags & SDF_OPEN_READ)) {
                                        if (drv->duplex == 2)
                                                drv->input_count = drv->output_count;
                                        drv->ops->start_input(drv, 
                                                              drv->input_buffers[drv->input_front],
                                                              drv->input_buffer_size);
                                        drv->input_active = 1;
                                }
                        }
                        if (((unsigned int)arg == FLUSHW) || 
                            ((unsigned int)arg == FLUSHRW)) {
                                if ((file->f_mode & FMODE_WRITE) && 
                                    !(drv->flags & SDF_OPEN_WRITE)) {
                                        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
                                        sparcaudio_sync_output(drv);
                                }
                        }
                        break;
                case SNDCTL_DSP_RESET:
                case AUDIO_FLUSH:
                        if (drv->output_active && (file->f_mode & FMODE_WRITE)) {
                                wake_up_interruptible(&drv->output_write_wait);
                                drv->ops->stop_output(drv);
                                drv->output_active = 0;
                                drv->output_front = 0;
                                drv->output_rear = 0;
                                drv->output_count = 0;
                                drv->output_size = 0;
                                drv->playing_count = 0;
                                drv->output_offset = 0;
                                drv->output_eof = 0;
                        }
                        if (drv->input_active && (file->f_mode & FMODE_READ)) {
                                wake_up_interruptible(&drv->input_read_wait);
                                drv->ops->stop_input(drv);
                                drv->input_active = 0;
                                drv->input_front = 0;
                                drv->input_rear = 0;
                                drv->input_count = 0;
                                drv->input_size = 0;
                                drv->input_offset = 0;
                                drv->recording_count = 0;
                        }
                        if ((file->f_mode & FMODE_READ) && 
                            !(drv->flags & SDF_OPEN_READ)) {
                                drv->ops->start_input(drv, 
                                                      drv->input_buffers[drv->input_front],
                                                      drv->input_buffer_size);
                                drv->input_active = 1;
                        }
                        if ((file->f_mode & FMODE_WRITE) && 
                            !(drv->flags & SDF_OPEN_WRITE)) {
                                sparcaudio_sync_output(drv);
                        }
                        break;
                case AUDIO_GETDEV:
                        if (drv->ops->sunaudio_getdev) {
                                audio_device_t tmp;
	      
                                retval = verify_area(VERIFY_WRITE, (void *)arg, 
                                                     sizeof(audio_device_t));
                                if (!retval)
                                        drv->ops->sunaudio_getdev(drv, &tmp);
                                copy_to_user((audio_device_t *)arg, &tmp, sizeof(tmp));
                        } else {
                                retval = -EINVAL;
                        }
                        break;
                case AUDIO_GETDEV_SUNOS:
                        if (drv->ops->sunaudio_getdev_sunos) {
                                int tmp = drv->ops->sunaudio_getdev_sunos(drv);

                                retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
                                if (!retval)
                                        copy_to_user((int *)arg, &tmp, sizeof(tmp));
                        } else {
                                retval = -EINVAL;
                        }
                        break;
                case AUDIO_GETINFO:
                        AUDIO_INITINFO(&ainfo);

                        if (drv->ops->get_input_rate)
                                ainfo.record.sample_rate =
                                        drv->ops->get_input_rate(drv);
                        else
                                ainfo.record.sample_rate = (8000);
                        if (drv->ops->get_input_channels)
                                ainfo.record.channels =
                                        drv->ops->get_input_channels(drv);
                        else
                                ainfo.record.channels = (1);
                        if (drv->ops->get_input_precision)
                                ainfo.record.precision =
                                        drv->ops->get_input_precision(drv);
                        else
                                ainfo.record.precision = (8);
                        if (drv->ops->get_input_encoding)
                                ainfo.record.encoding =
                                        drv->ops->get_input_encoding(drv);
                        else
                                ainfo.record.encoding = (AUDIO_ENCODING_ULAW);
                        if (drv->ops->get_input_volume)
                                ainfo.record.gain =
                                        drv->ops->get_input_volume(drv);
                        else
                                ainfo.record.gain = (0);
                        if (drv->ops->get_input_port)
                                ainfo.record.port =
                                        drv->ops->get_input_port(drv);
                        else
                                ainfo.record.port = (0);
                        if (drv->ops->get_input_ports)
                                ainfo.record.avail_ports = 
                                        drv->ops->get_input_ports(drv);
                        else
                                ainfo.record.avail_ports = (0);

                        /* To make e.g. vat happy, we let them think they control this */
                        ainfo.record.buffer_size = drv->buffer_size;
                        if (drv->ops->get_input_samples)
                                ainfo.record.samples = drv->ops->get_input_samples(drv);
                        else
                                ainfo.record.samples = 0;

                        /* This is undefined in the record context in Solaris */
                        ainfo.record.eof = 0;
                        if (drv->ops->get_input_pause)
                                ainfo.record.pause =
                                        drv->ops->get_input_pause(drv);
                        else
                                ainfo.record.pause = 0;
                        if (drv->ops->get_input_error)
                                ainfo.record.error = 
                                        (unsigned char) drv->ops->get_input_error(drv);
                        else
                                ainfo.record.error = 0;
                        ainfo.record.waiting = 0;
                        if (drv->ops->get_input_balance)
                                ainfo.record.balance =
                                        (unsigned char) drv->ops->get_input_balance(drv);
                        else
                                ainfo.record.balance = (unsigned char)(AUDIO_MID_BALANCE);
                        ainfo.record.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT);
                        ainfo.record.open = (drv->flags & SDF_OPEN_READ);
                        ainfo.record.active = 0;

                        if (drv->ops->get_output_rate)
                                ainfo.play.sample_rate =
                                        drv->ops->get_output_rate(drv);
                        else
                                ainfo.play.sample_rate = (8000);
                        if (drv->ops->get_output_channels)
                                ainfo.play.channels =
                                        drv->ops->get_output_channels(drv);
                        else
                                ainfo.play.channels = (1);
                        if (drv->ops->get_output_precision)
                                ainfo.play.precision =
                                        drv->ops->get_output_precision(drv);
                        else
                                ainfo.play.precision = (8);
                        if (drv->ops->get_output_encoding)
                                ainfo.play.encoding =
                                        drv->ops->get_output_encoding(drv);
                        else
                                ainfo.play.encoding = (AUDIO_ENCODING_ULAW);
                        if (drv->ops->get_output_volume)
                                ainfo.play.gain =
                                        drv->ops->get_output_volume(drv);
                        else
                                ainfo.play.gain = (0);
                        if (drv->ops->get_output_port)
                                ainfo.play.port =
                                        drv->ops->get_output_port(drv);
                        else
                                ainfo.play.port = (0);
                        if (drv->ops->get_output_ports)
                                ainfo.play.avail_ports = 
                                        drv->ops->get_output_ports(drv);
                        else
                                ainfo.play.avail_ports = (0);

                        /* This is not defined in the play context in Solaris */
                        ainfo.play.buffer_size = 0;
                        if (drv->ops->get_output_samples)
                                ainfo.play.samples = drv->ops->get_output_samples(drv);
                        else
                                ainfo.play.samples = 0;
                        ainfo.play.eof = drv->output_eof;
                        if (drv->ops->get_output_pause)
                                ainfo.play.pause =
                                        drv->ops->get_output_pause(drv);
                        else
                                ainfo.play.pause = 0;
                        if (drv->ops->get_output_error)
                                ainfo.play.error =
                                        (unsigned char)drv->ops->get_output_error(drv);
                        else
                                ainfo.play.error = 0;
                        ainfo.play.waiting = waitqueue_active(&drv->open_wait);
                        if (drv->ops->get_output_balance)
                                ainfo.play.balance =
                                        (unsigned char)drv->ops->get_output_balance(drv);
                        else
                                ainfo.play.balance = (unsigned char)(AUDIO_MID_BALANCE);
                        ainfo.play.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT);
                        ainfo.play.open = (drv->flags & SDF_OPEN_WRITE);
                        ainfo.play.active = drv->output_active;
	    
                        if (drv->ops->get_monitor_volume)
                                ainfo.monitor_gain =
                                        drv->ops->get_monitor_volume(drv);
                        else
                                ainfo.monitor_gain = (0);

                        if (drv->ops->get_output_muted)
                                ainfo.output_muted = 
                                        (unsigned char)drv->ops->get_output_muted(drv);
                        else
                                ainfo.output_muted = (unsigned char)(0);

                        retval = verify_area(VERIFY_WRITE, (void *)arg,
                                             sizeof(struct audio_info));
                        if (retval < 0)
                                break;

                        copy_to_user((struct audio_info *)arg, &ainfo, sizeof(ainfo));
                        break;
                case AUDIO_SETINFO:
                {
                        audio_info_t curinfo, newinfo;
	      
                        if (verify_area(VERIFY_READ, (audio_info_t *)arg, 
                                        sizeof(audio_info_t))) {
                                dprintk(("verify_area failed\n"));
                                return -EINVAL;
                        }
                        copy_from_user(&ainfo, (audio_info_t *)arg, sizeof(audio_info_t));

                        /* Without these there's no point in trying */
                        if (!drv->ops->get_input_precision ||
                            !drv->ops->get_input_channels ||
                            !drv->ops->get_input_rate ||
                            !drv->ops->get_input_encoding ||
                            !drv->ops->get_output_precision ||
                            !drv->ops->get_output_channels ||
                            !drv->ops->get_output_rate ||
                            !drv->ops->get_output_encoding) {
                                eprintk(("missing get routines: failed\n"));
                                retval = -EINVAL;
                                break;
                        }

                        /* Do bounds checking for things which always apply.
                         * Follow with enforcement of basic tenets of certain
                         * encodings. Everything over and above generic is
                         * enforced by the driver, which can assume that
                         * Martian cases are taken care of here.
                         */
                        if (Modify(ainfo.play.gain) && 
                            ((ainfo.play.gain > AUDIO_MAX_GAIN) || 
                             (ainfo.play.gain < AUDIO_MIN_GAIN))) {
                                /* Need to differentiate this from e.g. the above error */
                                eprintk(("play gain bounds: failed %d\n", ainfo.play.gain));
                                retval = -EINVAL;
                                break;
                        }
                        if (Modify(ainfo.record.gain) &&
                            ((ainfo.record.gain > AUDIO_MAX_GAIN) ||
                             (ainfo.record.gain < AUDIO_MIN_GAIN))) {
                                eprintk(("rec gain bounds: failed %d\n", ainfo.record.gain));
                                retval = -EINVAL;
                                break;
                        }
                        if (Modify(ainfo.monitor_gain) &&
                            ((ainfo.monitor_gain > AUDIO_MAX_GAIN) ||
                             (ainfo.monitor_gain < AUDIO_MIN_GAIN))) {
                                eprintk(("monitor gain bounds: failed\n"));
                                retval = -EINVAL;
                                break;
                        }

                        /* Don't need to check less than zero on these */
                        if (Modifyc(ainfo.play.balance) &&
                            (ainfo.play.balance > AUDIO_RIGHT_BALANCE)) {
                                eprintk(("play balance bounds: %d failed\n", 
                                         (int)ainfo.play.balance));
                                retval = -EINVAL;
                                break;
                        }
                        if (Modifyc(ainfo.record.balance) &&
                            (ainfo.record.balance > AUDIO_RIGHT_BALANCE)) {
                                eprintk(("rec balance bounds: failed\n"));
                                retval = -EINVAL;
                                break;
                        }
	      
                        /* If any of these changed, record them all, then make
                         * changes atomically. If something fails, back it all out.
                         */
                        if (Modify(ainfo.record.precision) || 
                            Modify(ainfo.record.sample_rate) ||
                            Modify(ainfo.record.channels) ||
                            Modify(ainfo.record.encoding) || 
                            Modify(ainfo.play.precision) || 
                            Modify(ainfo.play.sample_rate) ||
                            Modify(ainfo.play.channels) ||
                            Modify(ainfo.play.encoding)) {
                                /* If they're trying to change something we
                                 * have no routine for, they lose.
                                 */
                                if ((!drv->ops->set_input_encoding && 
                                     Modify(ainfo.record.encoding)) ||
                                    (!drv->ops->set_input_rate && 
                                     Modify(ainfo.record.sample_rate)) ||
                                    (!drv->ops->set_input_precision && 
                                     Modify(ainfo.record.precision)) ||
                                    (!drv->ops->set_input_channels && 
                                     Modify(ainfo.record.channels))) {
                                        eprintk(("rec set no routines: failed\n"));
                                        retval = -EINVAL;
                                        break;
                                }		  
		  
                                curinfo.record.encoding = 
                                        drv->ops->get_input_encoding(drv);
                                curinfo.record.sample_rate = 
                                        drv->ops->get_input_rate(drv);	   
                                curinfo.record.precision = 
                                        drv->ops->get_input_precision(drv);	   
                                curinfo.record.channels = 
                                        drv->ops->get_input_channels(drv);	   
                                newinfo.record.encoding =
                                        Modify(ainfo.record.encoding) ? 
                                        ainfo.record.encoding :
                                        curinfo.record.encoding;
                                newinfo.record.sample_rate =
                                        Modify(ainfo.record.sample_rate) ?
                                        ainfo.record.sample_rate :
                                        curinfo.record.sample_rate;
                                newinfo.record.precision =
                                        Modify(ainfo.record.precision) ? 
                                        ainfo.record.precision :
                                        curinfo.record.precision;
                                newinfo.record.channels =
                                        Modify(ainfo.record.channels) ? 
                                        ainfo.record.channels :
                                        curinfo.record.channels;
		    
                                switch (newinfo.record.encoding) {
                                case AUDIO_ENCODING_ALAW:
                                case AUDIO_ENCODING_ULAW:
                                        if (newinfo.record.precision != 8) {
                                                eprintk(("rec law precision bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        if (newinfo.record.channels != 1) {
                                                eprintk(("rec law channel bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        break;
                                case AUDIO_ENCODING_LINEAR:
                                case AUDIO_ENCODING_LINEARLE:
                                        if (newinfo.record.precision != 16) {
                                                eprintk(("rec lin precision bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        if (newinfo.record.channels != 1 &&
                                            newinfo.record.channels != 2) {
                                                eprintk(("rec lin channel bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        break;
                                case AUDIO_ENCODING_LINEAR8:
                                        if (newinfo.record.precision != 8) {
                                                eprintk(("rec lin8 precision bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        if (newinfo.record.channels != 1 && 
                                            newinfo.record.channels != 2) {
                                                eprintk(("rec lin8 channel bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                };
		  
                                if (retval < 0)
                                        break;
		  
                                /* If they're trying to change something we
                                 * have no routine for, they lose.
                                 */
                                if ((!drv->ops->set_output_encoding && 
                                     Modify(ainfo.play.encoding)) ||
                                    (!drv->ops->set_output_rate && 
                                     Modify(ainfo.play.sample_rate)) ||
                                    (!drv->ops->set_output_precision && 
                                     Modify(ainfo.play.precision)) ||
                                    (!drv->ops->set_output_channels && 
                                     Modify(ainfo.play.channels))) {
                                        eprintk(("play set no routine: failed\n"));
                                        retval = -EINVAL;
                                        break;
                                }		  
		  
                                curinfo.play.encoding = 
                                        drv->ops->get_output_encoding(drv);
                                curinfo.play.sample_rate = 
                                        drv->ops->get_output_rate(drv);	   
                                curinfo.play.precision = 
                                        drv->ops->get_output_precision(drv);	   
                                curinfo.play.channels = 
                                        drv->ops->get_output_channels(drv);	   
                                newinfo.play.encoding =
                                        Modify(ainfo.play.encoding) ? 
                                        ainfo.play.encoding :
                                                curinfo.play.encoding;
                                newinfo.play.sample_rate =
                                        Modify(ainfo.play.sample_rate) ? 
                                        ainfo.play.sample_rate :
                                                curinfo.play.sample_rate;
                                newinfo.play.precision =
                                        Modify(ainfo.play.precision) ? 
                                        ainfo.play.precision :
                                                curinfo.play.precision;
                                newinfo.play.channels =
                                        Modify(ainfo.play.channels) ? 
                                        ainfo.play.channels :
                                                curinfo.play.channels;
		  
                                switch (newinfo.play.encoding) {
                                case AUDIO_ENCODING_ALAW:
                                case AUDIO_ENCODING_ULAW:
                                        if (newinfo.play.precision != 8) {
                                                eprintk(("play law precision bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        if (newinfo.play.channels != 1) {
                                                eprintk(("play law channel bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        break;
                                case AUDIO_ENCODING_LINEAR:
                                case AUDIO_ENCODING_LINEARLE:
                                        if (newinfo.play.precision != 16) {
                                                eprintk(("play lin precision bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        if (newinfo.play.channels != 1 && 
                                            newinfo.play.channels != 2) {
                                                eprintk(("play lin channel bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        break;
                                case AUDIO_ENCODING_LINEAR8:
                                        if (newinfo.play.precision != 8) {
                                                eprintk(("play lin8 precision bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                        if (newinfo.play.channels != 1 && 
                                            newinfo.play.channels != 2) {
                                                eprintk(("play lin8 channel bounds: "
                                                         "failed\n"));
                                                retval = -EINVAL;
                                                break;
                                        }
                                };
		  
                                if (retval < 0)
                                        break;
		  
                                /* If we got this far, we're at least sane with
                                 * respect to generics. Try the changes.
                                 */
                                if ((drv->ops->set_input_channels &&
                                     (drv->ops->set_input_channels(drv, 
                                                                   newinfo.record.channels)
                                      < 0)) ||
                                    (drv->ops->set_output_channels &&
                                     (drv->ops->set_output_channels(drv, 
                                                                    newinfo.play.channels)
                                      < 0)) ||
                                    (drv->ops->set_input_rate &&
                                     (drv->ops->set_input_rate(drv, 
                                                               newinfo.record.sample_rate) 
                                      < 0)) ||
                                    (drv->ops->set_output_rate &&
                                     (drv->ops->set_output_rate(drv, 
                                                                newinfo.play.sample_rate) 
                                      < 0)) ||
                                    (drv->ops->set_input_precision &&
                                     (drv->ops->set_input_precision(drv, 
                                                                    newinfo.record.precision)
                                      < 0)) ||
                                    (drv->ops->set_output_precision &&
                                     (drv->ops->set_output_precision(drv, 
                                                                     newinfo.play.precision)
                                      < 0)) ||
                                    (drv->ops->set_input_encoding &&
                                     (drv->ops->set_input_encoding(drv, 
                                                                   newinfo.record.encoding)
                                      < 0)) ||
                                    (drv->ops->set_output_encoding &&
                                     (drv->ops->set_output_encoding(drv, 
                                                                    newinfo.play.encoding)
                                      < 0))) 
                                {
                                        dprintk(("setting format: failed\n"));
                                        /* Pray we can set it all back. If not, uh... */
                                        if (drv->ops->set_input_channels)
                                                drv->ops->set_input_channels(drv, 
						     curinfo.record.channels);
                                        if (drv->ops->set_output_channels)
                                                drv->ops->set_output_channels(drv, 
                                                                              curinfo.play.channels);
                                        if (drv->ops->set_input_rate)
                                                drv->ops->set_input_rate(drv, 
                                                                         curinfo.record.sample_rate);
                                        if (drv->ops->set_output_rate)
                                                drv->ops->set_output_rate(drv, 
                                                                          curinfo.play.sample_rate);
                                        if (drv->ops->set_input_precision)
                                                drv->ops->set_input_precision(drv, 
                                                                              curinfo.record.precision);
                                        if (drv->ops->set_output_precision)
                                                drv->ops->set_output_precision(drv, 
                                                                               curinfo.play.precision);
                                        if (drv->ops->set_input_encoding)
                                                drv->ops->set_input_encoding(drv, 
                                                                             curinfo.record.encoding);
                                        if (drv->ops->set_output_encoding)
                                                drv->ops->set_output_encoding(drv, 
                                                                              curinfo.play.encoding);
                                        retval = -EINVAL;
                                        break;
                                }
                        }
                        
                        if (retval < 0)
                                break;
                        
                        newinfo.record.balance =
                                __sparcaudio_if_setc_do(drv, 
                                                        drv->ops->set_input_balance, 
                                                        drv->ops->get_input_balance,
                                                        ainfo.record.balance);
                        newinfo.play.balance =
                                __sparcaudio_if_setc_do(drv, 
                                                        drv->ops->set_output_balance, 
                                                        drv->ops->get_output_balance,
                                                        ainfo.play.balance);
                        newinfo.record.error =
                                __sparcaudio_if_setc_do(drv, 
                                                        drv->ops->set_input_error, 
                                                        drv->ops->get_input_error,
                                                        ainfo.record.error);
                        newinfo.play.error =
                                __sparcaudio_if_setc_do(drv, 
                                                        drv->ops->set_output_error, 
                                                        drv->ops->get_output_error,
                                                        ainfo.play.error);
                        newinfo.output_muted =
                                __sparcaudio_if_setc_do(drv, 
                                                        drv->ops->set_output_muted, 
                                                        drv->ops->get_output_muted,
                                                        ainfo.output_muted);
                        newinfo.record.gain =
                                __sparcaudio_if_set_do(drv, 
                                                       drv->ops->set_input_volume, 
                                                       drv->ops->get_input_volume,
                                                       ainfo.record.gain);
                        newinfo.play.gain =
                                __sparcaudio_if_set_do(drv, 
                                                       drv->ops->set_output_volume, 
                                                       drv->ops->get_output_volume,
                                                       ainfo.play.gain);
                        newinfo.record.port =
                                __sparcaudio_if_set_do(drv, 
                                                       drv->ops->set_input_port, 
                                                       drv->ops->get_input_port,
                                                       ainfo.record.port);
                        newinfo.play.port =
                                __sparcaudio_if_set_do(drv, 
                                                       drv->ops->set_output_port, 
                                                       drv->ops->get_output_port,
                                                       ainfo.play.port);
                        newinfo.record.samples =
                                __sparcaudio_if_set_do(drv, 
                                                       drv->ops->set_input_samples, 
                                                       drv->ops->get_input_samples,
                                                       ainfo.record.samples);
                        newinfo.play.samples =
                                __sparcaudio_if_set_do(drv, 
                                                       drv->ops->set_output_samples, 
                                                       drv->ops->get_output_samples,
                                                       ainfo.play.samples);
                        newinfo.monitor_gain =
                                __sparcaudio_if_set_do(drv, 
                                                       drv->ops->set_monitor_volume, 
                                                       drv->ops->get_monitor_volume,
                                                       ainfo.monitor_gain);

                        if (Modify(ainfo.record.buffer_size)) {
                                /* Should sanity check this */
                                newinfo.record.buffer_size = ainfo.record.buffer_size;
                                drv->buffer_size = ainfo.record.buffer_size;
                        } else {
                                newinfo.record.buffer_size = drv->buffer_size;
                        }

                        if (Modify(ainfo.play.eof)) {
                                ainfo.play.eof = newinfo.play.eof;
                                newinfo.play.eof = drv->output_eof;
                                drv->output_eof = ainfo.play.eof;
                        } else {
                                newinfo.play.eof = drv->output_eof;
                        }		

                        if (drv->flags & SDF_OPEN_READ) {
                                newinfo.record.pause =
                                        __sparcaudio_if_setc_do(drv, 
                                                                drv->ops->set_input_pause, 
                                                                drv->ops->get_input_pause,
                                                                ainfo.record.pause);
                        } else if (drv->ops->get_input_pause) {
                                newinfo.record.pause = drv->ops->get_input_pause(drv);
                        } else {
                                newinfo.record.pause = 0;
                        }

                        if (drv->flags & SDF_OPEN_WRITE) {
                                newinfo.play.pause =
                                        __sparcaudio_if_setc_do(drv, 
                                                                drv->ops->set_output_pause, 
                                                                drv->ops->get_output_pause,
                                                                ainfo.play.pause);
                        } else if (drv->ops->get_output_pause) {
                                newinfo.play.pause = drv->ops->get_output_pause(drv);
                        } else {
                                newinfo.play.pause = 0;
                        }
	      
                        retval = verify_area(VERIFY_WRITE, (void *)arg,
                                             sizeof(struct audio_info));

                        /* Even if we fail, if we made changes let's try notification */
                        if (!retval) 
                                copy_to_user((struct audio_info *)arg, &newinfo, 
                                             sizeof(newinfo));
	    
#ifdef REAL_AUDIO_SIGNALS
                        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
#endif
                        break;
                }
	  
                default:
                        if (drv->ops->ioctl)
                                retval = drv->ops->ioctl(inode,file,cmd,arg,drv);
                        else
                                retval = -EINVAL;
                };
                break;
	case SPARCAUDIO_STATUS_MINOR:
                eprintk(("status minor not yet implemented\n"));
                retval = -EINVAL;
	default:
                eprintk(("unknown minor device number\n"));
                retval = -EINVAL;
	}
	
	return retval;
}

Generated by GNU enscript 1.6.4.