Enscript Output

extractedLnx/linux-2.4.37/drivers/sound/i810_audio.c_i810_ioctl.c

static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct i810_state *state = (struct i810_state *)file->private_data;
	struct i810_channel *c = NULL;
	struct dmabuf *dmabuf = &state->dmabuf;
	unsigned long flags;
	audio_buf_info abinfo;
	count_info cinfo;
	unsigned int i_glob_cnt;
	int val = 0, ret;
	struct ac97_codec *codec = state->card->ac97_codec[0];

#ifdef DEBUG
	printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *(int *)arg : 0);
#endif

	switch (cmd) 
	{
	case OSS_GETVERSION:
#ifdef DEBUG
		printk("OSS_GETVERSION\n");
#endif
		return put_user(SOUND_VERSION, (int *)arg);

	case SNDCTL_DSP_RESET:
#ifdef DEBUG
		printk("SNDCTL_DSP_RESET\n");
#endif
		spin_lock_irqsave(&state->card->lock, flags);
		if (dmabuf->enable == DAC_RUNNING) {
			c = dmabuf->write_channel;
			__stop_dac(state);
		}
		if (dmabuf->enable == ADC_RUNNING) {
			c = dmabuf->read_channel;
			__stop_adc(state);
		}
		if (c != NULL) {
			I810_IOWRITEB(2, state->card, c->port+OFF_CR);   /* reset DMA machine */
			while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 )
				cpu_relax();
			I810_IOWRITEL((u32)state->card->chandma +
			    c->num*sizeof(struct i810_channel),
			    state->card, c->port+OFF_BDBAR);
			CIV_TO_LVI(state->card, c->port, 0);
		}

		spin_unlock_irqrestore(&state->card->lock, flags);
		synchronize_irq();
		dmabuf->ready = 0;
		dmabuf->swptr = dmabuf->hwptr = 0;
		dmabuf->count = dmabuf->total_bytes = 0;
		return 0;

	case SNDCTL_DSP_SYNC:
#ifdef DEBUG
		printk("SNDCTL_DSP_SYNC\n");
#endif
		if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK)
			return 0;
		if((val = drain_dac(state, 1)))
			return val;
		dmabuf->total_bytes = 0;
		return 0;

	case SNDCTL_DSP_SPEED: /* set smaple rate */
#ifdef DEBUG
		printk("SNDCTL_DSP_SPEED\n");
#endif
		if (get_user(val, (int *)arg))
			return -EFAULT;
		if (val >= 0) {
			if (file->f_mode & FMODE_WRITE) {
				if ( (state->card->ac97_status & SPDIF_ON) ) {  /* S/PDIF Enabled */
					/* AD1886 only supports 48000, need to check that */
					if ( i810_valid_spdif_rate ( codec, val ) ) {
						/* Set DAC rate */
                                        	i810_set_spdif_output ( state, -1, 0 );
						stop_dac(state);
						dmabuf->ready = 0;
						spin_lock_irqsave(&state->card->lock, flags);
						i810_set_dac_rate(state, val);
						spin_unlock_irqrestore(&state->card->lock, flags);
						/* Set S/PDIF transmitter rate. */
						i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val );
	                                        if ( ! (state->card->ac97_status & SPDIF_ON) ) {
							val = dmabuf->rate;
						}
					} else { /* Not a valid rate for S/PDIF, ignore it */
						val = dmabuf->rate;
					}
				} else {
					stop_dac(state);
					dmabuf->ready = 0;
					spin_lock_irqsave(&state->card->lock, flags);
					i810_set_dac_rate(state, val);
					spin_unlock_irqrestore(&state->card->lock, flags);
				}
			}
			if (file->f_mode & FMODE_READ) {
				stop_adc(state);
				dmabuf->ready = 0;
				spin_lock_irqsave(&state->card->lock, flags);
				i810_set_adc_rate(state, val);
				spin_unlock_irqrestore(&state->card->lock, flags);
			}
		}
		return put_user(dmabuf->rate, (int *)arg);

	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
#ifdef DEBUG
		printk("SNDCTL_DSP_STEREO\n");
#endif
		if (dmabuf->enable & DAC_RUNNING) {
			stop_dac(state);
		}
		if (dmabuf->enable & ADC_RUNNING) {
			stop_adc(state);
		}
		return put_user(1, (int *)arg);

	case SNDCTL_DSP_GETBLKSIZE:
		if (file->f_mode & FMODE_WRITE) {
			if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
				return val;
		}
		if (file->f_mode & FMODE_READ) {
			if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
				return val;
		}
#ifdef DEBUG
		printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
#endif
		return put_user(dmabuf->userfragsize, (int *)arg);

	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
#ifdef DEBUG
		printk("SNDCTL_DSP_GETFMTS\n");
#endif
		return put_user(AFMT_S16_LE, (int *)arg);

	case SNDCTL_DSP_SETFMT: /* Select sample format */
#ifdef DEBUG
		printk("SNDCTL_DSP_SETFMT\n");
#endif
		return put_user(AFMT_S16_LE, (int *)arg);

	case SNDCTL_DSP_CHANNELS:
#ifdef DEBUG
		printk("SNDCTL_DSP_CHANNELS\n");
#endif
		if (get_user(val, (int *)arg))
			return -EFAULT;

		if (val > 0) {
			if (dmabuf->enable & DAC_RUNNING) {
				stop_dac(state);
			}
			if (dmabuf->enable & ADC_RUNNING) {
				stop_adc(state);
			}
		} else {
			return put_user(state->card->channels, (int *)arg);
		}

		/* ICH and ICH0 only support 2 channels */
		if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5
		     || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5) 
			return put_user(2, (int *)arg);
	
		/* Multi-channel support was added with ICH2. Bits in */
		/* Global Status and Global Control register are now  */
		/* used to indicate this.                             */

                i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT);

		/* Current # of channels enabled */
		if ( i_glob_cnt & 0x0100000 )
			ret = 4;
		else if ( i_glob_cnt & 0x0200000 )
			ret = 6;
		else
			ret = 2;

		switch ( val ) {
			case 2: /* 2 channels is always supported */
				I810_IOWRITEL(i_glob_cnt & 0xffcfffff,
				     state->card, GLOB_CNT);
				/* Do we need to change mixer settings????  */
				break;
			case 4: /* Supported on some chipsets, better check first */
				if ( state->card->channels >= 4 ) {
					I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000,
					      state->card, GLOB_CNT);
					/* Do we need to change mixer settings??? */
				} else {
					val = ret;
				}
				break;
			case 6: /* Supported on some chipsets, better check first */
				if ( state->card->channels >= 6 ) {
					I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000,
					      state->card, GLOB_CNT);
					/* Do we need to change mixer settings??? */
				} else {
					val = ret;
				}
				break;
			default: /* nothing else is ever supported by the chipset */
				val = ret;
				break;
		}

		return put_user(val, (int *)arg);

	case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
		/* we update the swptr to the end of the last sg segment then return */
#ifdef DEBUG
		printk("SNDCTL_DSP_POST\n");
#endif
		if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
			return 0;
		if((dmabuf->swptr % dmabuf->fragsize) != 0) {
			val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
			dmabuf->swptr += val;
			dmabuf->count += val;
		}
		return 0;

	case SNDCTL_DSP_SUBDIVIDE:
		if (dmabuf->subdivision)
			return -EINVAL;
		if (get_user(val, (int *)arg))
			return -EFAULT;
		if (val != 1 && val != 2 && val != 4)
			return -EINVAL;
#ifdef DEBUG
		printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
#endif
		dmabuf->subdivision = val;
		dmabuf->ready = 0;
		return 0;

	case SNDCTL_DSP_SETFRAGMENT:
		if (get_user(val, (int *)arg))
			return -EFAULT;

		dmabuf->ossfragsize = 1<<(val & 0xffff);
		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
		if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
			return -EINVAL;
		/*
		 * Bound the frag size into our allowed range of 256 - 4096
		 */
		if (dmabuf->ossfragsize < 256)
			dmabuf->ossfragsize = 256;
		else if (dmabuf->ossfragsize > 4096)
			dmabuf->ossfragsize = 4096;
		/*
		 * The numfrags could be something reasonable, or it could
		 * be 0xffff meaning "Give me as much as possible".  So,
		 * we check the numfrags * fragsize doesn't exceed our
		 * 64k buffer limit, nor is it less than our 8k minimum.
		 * If it fails either one of these checks, then adjust the
		 * number of fragments, not the size of them.  It's OK if
		 * our number of fragments doesn't equal 32 or anything
		 * like our hardware based number now since we are using
		 * a different frag count for the hardware.  Before we get
		 * into this though, bound the maxfrags to avoid overflow
		 * issues.  A reasonable bound would be 64k / 256 since our
		 * maximum buffer size is 64k and our minimum frag size is
		 * 256.  On the other end, our minimum buffer size is 8k and
		 * our maximum frag size is 4k, so the lower bound should
		 * be 2.
		 */

		if(dmabuf->ossmaxfrags > 256)
			dmabuf->ossmaxfrags = 256;
		else if (dmabuf->ossmaxfrags < 2)
			dmabuf->ossmaxfrags = 2;

		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
		while (val < 8192) {
		    val <<= 1;
		    dmabuf->ossmaxfrags <<= 1;
		}
		while (val > 65536) {
		    val >>= 1;
		    dmabuf->ossmaxfrags >>= 1;
		}
		dmabuf->ready = 0;
#ifdef DEBUG
		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
			dmabuf->ossfragsize, dmabuf->ossmaxfrags);
#endif

		return 0;

	case SNDCTL_DSP_GETOSPACE:
		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
			return val;
		spin_lock_irqsave(&state->card->lock, flags);
		i810_update_ptr(state);
		abinfo.fragsize = dmabuf->userfragsize;
		abinfo.fragstotal = dmabuf->userfrags;
		if (dmabuf->mapped)
 			abinfo.bytes = dmabuf->dmasize;
  		else
 			abinfo.bytes = i810_get_free_write_space(state);
		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
		spin_unlock_irqrestore(&state->card->lock, flags);
#if defined(DEBUG) || defined(DEBUG_MMAP)
		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes,
			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
#endif
		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;

	case SNDCTL_DSP_GETOPTR:
		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
			return val;
		spin_lock_irqsave(&state->card->lock, flags);
		val = i810_get_free_write_space(state);
		cinfo.bytes = dmabuf->total_bytes;
		cinfo.ptr = dmabuf->hwptr;
		cinfo.blocks = val/dmabuf->userfragsize;
		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
			dmabuf->count += val;
			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
			__i810_update_lvi(state, 0);
		}
		spin_unlock_irqrestore(&state->card->lock, flags);
#if defined(DEBUG) || defined(DEBUG_MMAP)
		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
			cinfo.blocks, cinfo.ptr, dmabuf->count);
#endif
		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;

	case SNDCTL_DSP_GETISPACE:
		if (!(file->f_mode & FMODE_READ))
			return -EINVAL;
		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
			return val;
		spin_lock_irqsave(&state->card->lock, flags);
		abinfo.bytes = i810_get_available_read_data(state);
		abinfo.fragsize = dmabuf->userfragsize;
		abinfo.fragstotal = dmabuf->userfrags;
		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
		spin_unlock_irqrestore(&state->card->lock, flags);
#if defined(DEBUG) || defined(DEBUG_MMAP)
		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes,
			abinfo.fragsize, abinfo.fragments, abinfo.fragstotal);
#endif
		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;

	case SNDCTL_DSP_GETIPTR:
		if (!(file->f_mode & FMODE_READ))
			return -EINVAL;
		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
			return val;
		spin_lock_irqsave(&state->card->lock, flags);
		val = i810_get_available_read_data(state);
		cinfo.bytes = dmabuf->total_bytes;
		cinfo.blocks = val/dmabuf->userfragsize;
		cinfo.ptr = dmabuf->hwptr;
		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
			dmabuf->count -= val;
			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
			__i810_update_lvi(state, 1);
		}
		spin_unlock_irqrestore(&state->card->lock, flags);
#if defined(DEBUG) || defined(DEBUG_MMAP)
		printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
			cinfo.blocks, cinfo.ptr, dmabuf->count);
#endif
		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;

	case SNDCTL_DSP_NONBLOCK:
#ifdef DEBUG
		printk("SNDCTL_DSP_NONBLOCK\n");
#endif
		file->f_flags |= O_NONBLOCK;
		return 0;

	case SNDCTL_DSP_GETCAPS:
#ifdef DEBUG
		printk("SNDCTL_DSP_GETCAPS\n");
#endif
	    return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
			    (int *)arg);

	case SNDCTL_DSP_GETTRIGGER:
		val = 0;
#ifdef DEBUG
		printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
#endif
		return put_user(dmabuf->trigger, (int *)arg);

	case SNDCTL_DSP_SETTRIGGER:
		if (get_user(val, (int *)arg))
			return -EFAULT;
#if defined(DEBUG) || defined(DEBUG_MMAP)
		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
#endif
		/* silently ignore invalid PCM_ENABLE_xxx bits,
		 * like the other drivers do
		 */
		if (!(file->f_mode & FMODE_READ ))
			val &= ~PCM_ENABLE_INPUT;
		if (!(file->f_mode & FMODE_WRITE ))
			val &= ~PCM_ENABLE_OUTPUT;
		if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
			stop_adc(state);
		}
		if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
			stop_dac(state);
		}
		dmabuf->trigger = val;
		if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
			if (!dmabuf->write_channel) {
				dmabuf->ready = 0;
				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
				if (!dmabuf->write_channel)
					return -EBUSY;
			}
			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
				return ret;
			if (dmabuf->mapped) {
				spin_lock_irqsave(&state->card->lock, flags);
				i810_update_ptr(state);
				dmabuf->count = 0;
				dmabuf->swptr = dmabuf->hwptr;
				dmabuf->count = i810_get_free_write_space(state);
				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
				spin_unlock_irqrestore(&state->card->lock, flags);
			}
			i810_update_lvi(state, 0);
			start_dac(state);
		}
		if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
			if (!dmabuf->read_channel) {
				dmabuf->ready = 0;
				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
				if (!dmabuf->read_channel)
					return -EBUSY;
			}
			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
				return ret;
			if (dmabuf->mapped) {
				spin_lock_irqsave(&state->card->lock, flags);
				i810_update_ptr(state);
				dmabuf->swptr = dmabuf->hwptr;
				dmabuf->count = 0;
				spin_unlock_irqrestore(&state->card->lock, flags);
			}
			i810_update_lvi(state, 1);
			start_adc(state);
		}
		return 0;

	case SNDCTL_DSP_SETDUPLEX:
#ifdef DEBUG
		printk("SNDCTL_DSP_SETDUPLEX\n");
#endif
		return -EINVAL;

	case SNDCTL_DSP_GETODELAY:
		if (!(file->f_mode & FMODE_WRITE))
			return -EINVAL;
		spin_lock_irqsave(&state->card->lock, flags);
		i810_update_ptr(state);
		val = dmabuf->count;
		spin_unlock_irqrestore(&state->card->lock, flags);
#ifdef DEBUG
		printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
#endif
		return put_user(val, (int *)arg);

	case SOUND_PCM_READ_RATE:
#ifdef DEBUG
		printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
#endif
		return put_user(dmabuf->rate, (int *)arg);

	case SOUND_PCM_READ_CHANNELS:
#ifdef DEBUG
		printk("SOUND_PCM_READ_CHANNELS\n");
#endif
		return put_user(2, (int *)arg);

	case SOUND_PCM_READ_BITS:
#ifdef DEBUG
		printk("SOUND_PCM_READ_BITS\n");
#endif
		return put_user(AFMT_S16_LE, (int *)arg);

	case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
#ifdef DEBUG
		printk("SNDCTL_DSP_SETSPDIF\n");
#endif
		if (get_user(val, (int *)arg))
			return -EFAULT;

		/* Check to make sure the codec supports S/PDIF transmitter */

		if((state->card->ac97_features & 4)) {
			/* mask out the transmitter speed bits so the user can't set them */
			val &= ~0x3000;

			/* Add the current transmitter speed bits to the passed value */
			ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
			val |= (ret & 0x3000);

			i810_ac97_set(codec, AC97_SPDIF_CONTROL, val);
			if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) {
				printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
				return -EFAULT;
			}
		}
#ifdef DEBUG
		else 
			printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
#endif
		return put_user(val, (int *)arg);

	case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
#ifdef DEBUG
		printk("SNDCTL_DSP_GETSPDIF\n");
#endif
		if (get_user(val, (int *)arg))
			return -EFAULT;

		/* Check to make sure the codec supports S/PDIF transmitter */

		if(!(state->card->ac97_features & 4)) {
#ifdef DEBUG
			printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
#endif
			val = 0;
		} else {
			val = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
		}
		//return put_user((val & 0xcfff), (int *)arg);
		return put_user(val, (int *)arg);
   			
	case SNDCTL_DSP_GETCHANNELMASK:
#ifdef DEBUG
		printk("SNDCTL_DSP_GETCHANNELMASK\n");
#endif
		if (get_user(val, (int *)arg))
			return -EFAULT;
		
		/* Based on AC'97 DAC support, not ICH hardware */
		val = DSP_BIND_FRONT;
		if ( state->card->ac97_features & 0x0004 )
			val |= DSP_BIND_SPDIF;

		if ( state->card->ac97_features & 0x0080 )
			val |= DSP_BIND_SURR;
		if ( state->card->ac97_features & 0x0140 )
			val |= DSP_BIND_CENTER_LFE;

		return put_user(val, (int *)arg);

	case SNDCTL_DSP_BIND_CHANNEL:
#ifdef DEBUG
		printk("SNDCTL_DSP_BIND_CHANNEL\n");
#endif
		if (get_user(val, (int *)arg))
			return -EFAULT;
		if ( val == DSP_BIND_QUERY ) {
			val = DSP_BIND_FRONT; /* Always report this as being enabled */
			if ( state->card->ac97_status & SPDIF_ON ) 
				val |= DSP_BIND_SPDIF;
			else {
				if ( state->card->ac97_status & SURR_ON )
					val |= DSP_BIND_SURR;
				if ( state->card->ac97_status & CENTER_LFE_ON )
					val |= DSP_BIND_CENTER_LFE;
			}
		} else {  /* Not a query, set it */
			if (!(file->f_mode & FMODE_WRITE))
				return -EINVAL;
			if ( dmabuf->enable == DAC_RUNNING ) {
				stop_dac(state);
			}
			if ( val & DSP_BIND_SPDIF ) {  /* Turn on SPDIF */
				/*  Ok, this should probably define what slots
				 *  to use. For now, we'll only set it to the
				 *  defaults:
				 * 
				 *   non multichannel codec maps to slots 3&4
				 *   2 channel codec maps to slots 7&8
				 *   4 channel codec maps to slots 6&9
				 *   6 channel codec maps to slots 10&11
				 *
				 *  there should be some way for the app to
				 *  select the slot assignment.
				 */
	
				i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, dmabuf->rate );
				if ( !(state->card->ac97_status & SPDIF_ON) )
					val &= ~DSP_BIND_SPDIF;
			} else {
				int mask;
				int channels;

				/* Turn off S/PDIF if it was on */
				if ( state->card->ac97_status & SPDIF_ON ) 
					i810_set_spdif_output ( state, -1, 0 );
				
				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:
						val = DSP_BIND_FRONT;
						channels = 2;
						break;
				}
				i810_set_dac_channels ( state, channels );

				/* check that they really got turned on */
				if (!(state->card->ac97_status & SURR_ON))
					val &= ~DSP_BIND_SURR;
				if (!(state->card->ac97_status & CENTER_LFE_ON))
					val &= ~DSP_BIND_CENTER_LFE;
			}
		}
		return put_user(val, (int *)arg);
		
	case SNDCTL_DSP_MAPINBUF:
	case SNDCTL_DSP_MAPOUTBUF:
	case SNDCTL_DSP_SETSYNCRO:
	case SOUND_PCM_WRITE_FILTER:
	case SOUND_PCM_READ_FILTER:
#ifdef DEBUG
		printk("SNDCTL_* -EINVAL\n");
#endif
		return -EINVAL;
	}
	return -EINVAL;
}

Generated by GNU enscript 1.6.4.