Enscript Output

extractedLnx/linux-2.6.9/sound/oss/cmpci.c_cm_ioctl.c

static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct cm_state *s = (struct cm_state *)file->private_data;
	unsigned long flags;
        audio_buf_info abinfo;
        count_info cinfo;
	int val, mapped, ret;
	unsigned char fmtm, fmtd;
	void __user *argp = (void __user *)arg;
	int __user *p = argp;

	VALIDATE_STATE(s);
        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
	switch (cmd) {
	case OSS_GETVERSION:
		return put_user(SOUND_VERSION, p);

	case SNDCTL_DSP_SYNC:
		if (file->f_mode & FMODE_WRITE)
			return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
		return 0;

	case SNDCTL_DSP_SETDUPLEX:
		return 0;

	case SNDCTL_DSP_GETCAPS:
		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, p);

        case SNDCTL_DSP_RESET:
		if (file->f_mode & FMODE_WRITE) {
			stop_dac(s);
			synchronize_irq(s->irq);
			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
			if (s->status & DO_DUAL_DAC)
				s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
		}
		if (file->f_mode & FMODE_READ) {
			stop_adc(s);
			synchronize_irq(s->irq);
			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
		}
		return 0;

        case SNDCTL_DSP_SPEED:
		if (get_user(val, p))
			return -EFAULT;
		if (val >= 0) {
			if (file->f_mode & FMODE_READ) {
			 	spin_lock_irqsave(&s->lock, flags);
				stop_adc_unlocked(s);
				s->dma_adc.ready = 0;
				set_adc_rate_unlocked(s, val);
				spin_unlock_irqrestore(&s->lock, flags);
			}
			if (file->f_mode & FMODE_WRITE) {
				stop_dac(s);
				s->dma_dac.ready = 0;
				if (s->status & DO_DUAL_DAC)
					s->dma_adc.ready = 0;
				set_dac_rate(s, val);
			}
		}
		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);

        case SNDCTL_DSP_STEREO:
		if (get_user(val, p))
			return -EFAULT;
		fmtd = 0;
		fmtm = ~0;
		if (file->f_mode & FMODE_READ) {
			stop_adc(s);
			s->dma_adc.ready = 0;
			if (val)
				fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
			else
				fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
		}
		if (file->f_mode & FMODE_WRITE) {
			stop_dac(s);
			s->dma_dac.ready = 0;
			if (val)
				fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
			else
				fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
			if (s->status & DO_DUAL_DAC) {
				s->dma_adc.ready = 0;
				if (val)
					fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
				else
					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
			}
		}
		set_fmt(s, fmtm, fmtd);
		return 0;

        case SNDCTL_DSP_CHANNELS:
		if (get_user(val, p))
			return -EFAULT;
		if (val != 0) {
			fmtd = 0;
			fmtm = ~0;
			if (file->f_mode & FMODE_READ) {
				stop_adc(s);
				s->dma_adc.ready = 0;
				if (val >= 2)
					fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
				else
					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
			}
			if (file->f_mode & FMODE_WRITE) {
				stop_dac(s);
				s->dma_dac.ready = 0;
				if (val >= 2)
					fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
				else
					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
				if (s->status & DO_DUAL_DAC) {
					s->dma_adc.ready = 0;
					if (val >= 2)
						fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
					else
						fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
				}
			}
			set_fmt(s, fmtm, fmtd);
			if ((s->capability & CAN_MULTI_CH)
			     && (file->f_mode & FMODE_WRITE)) {
				val = set_dac_channels(s, val);
				return put_user(val, p);
			}
		}
		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT)
					   : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);

	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
                return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8|
			((s->capability & CAN_AC3) ? AFMT_AC3 : 0), p);

	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
		if (get_user(val, p))
			return -EFAULT;
		if (val != AFMT_QUERY) {
			fmtd = 0;
			fmtm = ~0;
			if (file->f_mode & FMODE_READ) {
				stop_adc(s);
				s->dma_adc.ready = 0;
				if (val == AFMT_S16_BE || val == AFMT_S16_LE)
					fmtd |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
				else
					fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_ADCSHIFT);
				if (val == AFMT_S16_BE)
					s->status |= DO_BIGENDIAN_R;
				else
					s->status &= ~DO_BIGENDIAN_R;
			}
			if (file->f_mode & FMODE_WRITE) {
				stop_dac(s);
				s->dma_dac.ready = 0;
				if (val == AFMT_S16_BE || val == AFMT_S16_LE || val == AFMT_AC3)
					fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
				else
					fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
				if (val == AFMT_AC3) {
					fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
					set_ac3(s, 48000);
				} else
					set_ac3(s, 0);
				if (s->status & DO_DUAL_DAC) {
					s->dma_adc.ready = 0;
					if (val == AFMT_S16_BE || val == AFMT_S16_LE)
						fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
					else
						fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
				}
				if (val == AFMT_S16_BE)
					s->status |= DO_BIGENDIAN_W;
				else
					s->status &= ~DO_BIGENDIAN_W;
			}
			set_fmt(s, fmtm, fmtd);
		}
		if (s->status & DO_AC3) return put_user(AFMT_AC3, p);
		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
					   : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, p);

	case SNDCTL_DSP_POST:
                return 0;

        case SNDCTL_DSP_GETTRIGGER:
		val = 0;
		if (s->status & DO_DUAL_DAC) {
			if (file->f_mode & FMODE_WRITE &&
			 (s->enable & ENDAC) &&
			 (s->enable & ENADC))
				val |= PCM_ENABLE_OUTPUT;
			return put_user(val, p);
		}
		if (file->f_mode & FMODE_READ && s->enable & ENADC)
			val |= PCM_ENABLE_INPUT;
		if (file->f_mode & FMODE_WRITE && s->enable & ENDAC)
			val |= PCM_ENABLE_OUTPUT;
		return put_user(val, p);

	case SNDCTL_DSP_SETTRIGGER:
		if (get_user(val, p))
			return -EFAULT;
		if (file->f_mode & FMODE_READ) {
			if (val & PCM_ENABLE_INPUT) {
				if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
					return ret;
				s->dma_adc.enabled = 1;
				start_adc(s);
			} else {
				s->dma_adc.enabled = 0;
				stop_adc(s);
			}
		}
		if (file->f_mode & FMODE_WRITE) {
			if (val & PCM_ENABLE_OUTPUT) {
				if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
					return ret;
				if (s->status & DO_DUAL_DAC) {
					if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
						return ret;
				}
				s->dma_dac.enabled = 1;
				start_dac(s);
			} else {
				s->dma_dac.enabled = 0;
				stop_dac(s);
			}
		}
		return 0;

	case SNDCTL_DSP_GETOSPACE:
		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		if (!(s->enable & ENDAC) && (val = prog_dmabuf(s, 0)) != 0)
			return val;
		spin_lock_irqsave(&s->lock, flags);
		cm_update_ptr(s);
		abinfo.fragsize = s->dma_dac.fragsize;
                abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
                abinfo.fragstotal = s->dma_dac.numfrag;
                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
		spin_unlock_irqrestore(&s->lock, flags);
		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;

	case SNDCTL_DSP_GETISPACE:
		if (!(file->f_mode & FMODE_READ))
			return -EINVAL;
		if (!(s->enable & ENADC) && (val = prog_dmabuf(s, 1)) != 0)
			return val;
		spin_lock_irqsave(&s->lock, flags);
		cm_update_ptr(s);
		abinfo.fragsize = s->dma_adc.fragsize;
                abinfo.bytes = s->dma_adc.count;
                abinfo.fragstotal = s->dma_adc.numfrag;
                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
		spin_unlock_irqrestore(&s->lock, flags);
		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;

        case SNDCTL_DSP_NONBLOCK:
                file->f_flags |= O_NONBLOCK;
                return 0;

        case SNDCTL_DSP_GETODELAY:
		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		spin_lock_irqsave(&s->lock, flags);
		cm_update_ptr(s);
                val = s->dma_dac.count;
		spin_unlock_irqrestore(&s->lock, flags);
		return put_user(val, p);

        case SNDCTL_DSP_GETIPTR:
		if (!(file->f_mode & FMODE_READ))
			return -EINVAL;
		spin_lock_irqsave(&s->lock, flags);
		cm_update_ptr(s);
                cinfo.bytes = s->dma_adc.total_bytes;
                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
                cinfo.ptr = s->dma_adc.hwptr;
		if (s->dma_adc.mapped)
			s->dma_adc.count &= s->dma_adc.fragsize-1;
		spin_unlock_irqrestore(&s->lock, flags);
                return copy_to_user(argp, &cinfo, sizeof(cinfo))  ? -EFAULT : 0;

        case SNDCTL_DSP_GETOPTR:
		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		spin_lock_irqsave(&s->lock, flags);
		cm_update_ptr(s);
                cinfo.bytes = s->dma_dac.total_bytes;
                cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
                cinfo.ptr = s->dma_dac.hwptr;
		if (s->dma_dac.mapped)
			s->dma_dac.count &= s->dma_dac.fragsize-1;
		if (s->status & DO_DUAL_DAC) {
			if (s->dma_adc.mapped)
				s->dma_adc.count &= s->dma_adc.fragsize-1;
		}
		spin_unlock_irqrestore(&s->lock, flags);
                return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;

        case SNDCTL_DSP_GETBLKSIZE:
		if (file->f_mode & FMODE_WRITE) {
			if ((val = prog_dmabuf(s, 0)))
				return val;
			if (s->status & DO_DUAL_DAC) {
				if ((val = prog_dmabuf(s, 1)))
					return val;
				return put_user(2 * s->dma_dac.fragsize, p);
			}
			return put_user(s->dma_dac.fragsize, p);
		}
		if ((val = prog_dmabuf(s, 1)))
			return val;
		return put_user(s->dma_adc.fragsize, p);

        case SNDCTL_DSP_SETFRAGMENT:
		if (get_user(val, p))
			return -EFAULT;
		if (file->f_mode & FMODE_READ) {
			s->dma_adc.ossfragshift = val & 0xffff;
			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
			if (s->dma_adc.ossfragshift < 4)
				s->dma_adc.ossfragshift = 4;
			if (s->dma_adc.ossfragshift > 15)
				s->dma_adc.ossfragshift = 15;
			if (s->dma_adc.ossmaxfrags < 4)
				s->dma_adc.ossmaxfrags = 4;
		}
		if (file->f_mode & FMODE_WRITE) {
			s->dma_dac.ossfragshift = val & 0xffff;
			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
			if (s->dma_dac.ossfragshift < 4)
				s->dma_dac.ossfragshift = 4;
			if (s->dma_dac.ossfragshift > 15)
				s->dma_dac.ossfragshift = 15;
			if (s->dma_dac.ossmaxfrags < 4)
				s->dma_dac.ossmaxfrags = 4;
			if (s->status & DO_DUAL_DAC) {
				s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
				s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
			}
		}
		return 0;

        case SNDCTL_DSP_SUBDIVIDE:
		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
			return -EINVAL;
		if (get_user(val, p))
			return -EFAULT;
		if (val != 1 && val != 2 && val != 4)
			return -EINVAL;
		if (file->f_mode & FMODE_READ)
			s->dma_adc.subdivision = val;
		if (file->f_mode & FMODE_WRITE) {
			s->dma_dac.subdivision = val;
			if (s->status & DO_DUAL_DAC)
				s->dma_adc.subdivision = val;
		}
		return 0;

        case SOUND_PCM_READ_RATE:
		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);

        case SOUND_PCM_READ_CHANNELS:
		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);

        case SOUND_PCM_READ_BITS:
		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, p);

        case SOUND_PCM_READ_FILTER:
		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);

	case SNDCTL_DSP_GETCHANNELMASK:
		return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, p);

	case SNDCTL_DSP_BIND_CHANNEL:
		if (get_user(val, p))
			return -EFAULT;
		if (val == DSP_BIND_QUERY) {
			val = DSP_BIND_FRONT;
			if (s->status & DO_SPDIF_OUT)
				val |= DSP_BIND_SPDIF;
			else {
				if (s->curr_channels == 4)
					val |= DSP_BIND_SURR;
				if (s->curr_channels > 4)
					val |= DSP_BIND_CENTER_LFE;
			}
		} else {
			if (file->f_mode & FMODE_READ) {
				stop_adc(s);
				s->dma_adc.ready = 0;
				if (val & DSP_BIND_SPDIF) {
					set_spdifin(s, s->rateadc);
					if (!(s->status & DO_SPDIF_OUT))
						val &= ~DSP_BIND_SPDIF;
				}
			}
			if (file->f_mode & FMODE_WRITE) {
				stop_dac(s);
				s->dma_dac.ready = 0;
				if (val & DSP_BIND_SPDIF) {
					set_spdifout(s, s->ratedac);
					set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
					if (!(s->status & DO_SPDIF_OUT))
						val &= ~DSP_BIND_SPDIF;
				} else {
					int channels;
					int mask;

					mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE);
					switch (mask) {
					    case DSP_BIND_FRONT:
						channels = 2;
						break;
					    case DSP_BIND_FRONT|DSP_BIND_SURR:
						channels = 4;
						break;
					    case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
						channels = 6;
						break;
					    default:
						channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
						break;
					}
					set_dac_channels(s, channels);
				}
			}
		}
		return put_user(val, p);

	case SOUND_PCM_WRITE_FILTER:
	case SNDCTL_DSP_MAPINBUF:
	case SNDCTL_DSP_MAPOUTBUF:
        case SNDCTL_DSP_SETSYNCRO:
                return -EINVAL;
	case SNDCTL_SPDIF_COPYRIGHT:
		if (get_user(val, p))
			return -EFAULT;
		set_spdif_copyright(s, val);
                return 0;
	case SNDCTL_SPDIF_LOOP:
		if (get_user(val, p))
			return -EFAULT;
		set_spdif_loop(s, val);
                return 0;
	case SNDCTL_SPDIF_MONITOR:
		if (get_user(val, p))
			return -EFAULT;
		set_spdif_monitor(s, val);
                return 0;
	case SNDCTL_SPDIF_LEVEL:
		if (get_user(val, p))
			return -EFAULT;
		set_spdifout_level(s, val);
                return 0;
	case SNDCTL_SPDIF_INV:
		if (get_user(val, p))
			return -EFAULT;
		set_spdifin_inverse(s, val);
                return 0;
	case SNDCTL_SPDIF_SEL2:
		if (get_user(val, p))
			return -EFAULT;
		set_spdifin_channel2(s, val);
                return 0;
	case SNDCTL_SPDIF_VALID:
		if (get_user(val, p))
			return -EFAULT;
		set_spdifin_valid(s, val);
                return 0;
	case SNDCTL_SPDIFOUT:
		if (get_user(val, p))
			return -EFAULT;
		set_spdifout(s, val ? s->ratedac : 0);
                return 0;
	case SNDCTL_SPDIFIN:
		if (get_user(val, p))
			return -EFAULT;
		set_spdifin(s, val ? s->rateadc : 0);
                return 0;
	}
	return mixer_ioctl(s, cmd, arg);
}

Generated by GNU enscript 1.6.4.