예제 #1
0
static int find_output_space(int dev, char **buf, int *size)
{
	struct audio_operations *adev = audio_devs[dev];
	struct dma_buffparms *dmap = adev->dmap_out;
	unsigned long flags;
	unsigned long active_offs;
	long len, offs;
	int maxfrags;
	int occupied_bytes = (dmap->user_counter % dmap->fragment_size);

	*buf = dmap->raw_buf;
	if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes)
		return 0;
	save_flags(flags);
	cli();

#ifdef BE_CONSERVATIVE
	active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size;
#else
	active_offs = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT);
	/* Check for pointer wrapping situation */
	if (active_offs < 0 || active_offs >= dmap->bytes_in_use)
		active_offs = 0;
	active_offs += dmap->byte_counter;
#endif

	offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP;
	if (offs < 0 || offs >= dmap->bytes_in_use) {
		restore_flags(flags);
		printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs);
		printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use);
		return 0;
	}
	*buf = dmap->raw_buf + offs;

	len = active_offs + dmap->bytes_in_use - dmap->user_counter;	/* Number of unused bytes in buffer */

	if ((offs + len) > dmap->bytes_in_use)
		len = dmap->bytes_in_use - offs;
	if (len < 0) {
		restore_flags(flags);
		return 0;
	}
	if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes))
		len = (maxfrags * dmap->fragment_size) - occupied_bytes;
	*size = len & ~SAMPLE_ROUNDUP;
	restore_flags(flags);
	return (*size > 0);
}
예제 #2
0
int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg)
{
	int val, count;
	unsigned long flags;
	struct dma_buffparms *dmap;
	int __user *p = arg;

	dev = dev >> 4;

	if (_IOC_TYPE(cmd) == 'C')	{
		if (audio_devs[dev]->coproc)	/* Coprocessor ioctl */
			return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
		/* else
		        printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */
		return -ENXIO;
	}
	else switch (cmd) 
	{
		case SNDCTL_DSP_SYNC:
			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
				return 0;
			if (audio_devs[dev]->dmap_out->fragment_size == 0)
				return 0;
			sync_output(dev);
			DMAbuf_sync(dev);
			DMAbuf_reset(dev);
			return 0;

		case SNDCTL_DSP_POST:
			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
				return 0;
			if (audio_devs[dev]->dmap_out->fragment_size == 0)
				return 0;
			audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
			sync_output(dev);
			dma_ioctl(dev, SNDCTL_DSP_POST, NULL);
			return 0;

		case SNDCTL_DSP_RESET:
			audio_devs[dev]->audio_mode = AM_NONE;
			DMAbuf_reset(dev);
			return 0;

		case SNDCTL_DSP_GETFMTS:
			val = audio_devs[dev]->format_mask | AFMT_MU_LAW;
			break;
	
		case SNDCTL_DSP_SETFMT:
			if (get_user(val, p))
				return -EFAULT;
			val = set_format(dev, val);
			break;

		case SNDCTL_DSP_GETISPACE:
			if (!(audio_devs[dev]->open_mode & OPEN_READ))
				return 0;
  			if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
  				return -EBUSY;
			return dma_ioctl(dev, cmd, arg);

		case SNDCTL_DSP_GETOSPACE:
			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
				return -EPERM;
  			if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
  				return -EBUSY;
			return dma_ioctl(dev, cmd, arg);
		
		case SNDCTL_DSP_NONBLOCK:
			spin_lock(&file->f_lock);
			file->f_flags |= O_NONBLOCK;
			spin_unlock(&file->f_lock);
			return 0;

		case SNDCTL_DSP_GETCAPS:
				val = 1 | DSP_CAP_MMAP;	/* Revision level of this ioctl() */
				if (audio_devs[dev]->flags & DMA_DUPLEX &&
					audio_devs[dev]->open_mode == OPEN_READWRITE)
					val |= DSP_CAP_DUPLEX;
				if (audio_devs[dev]->coproc)
					val |= DSP_CAP_COPROC;
				if (audio_devs[dev]->d->local_qlen)	/* Device has hidden buffers */
					val |= DSP_CAP_BATCH;
				if (audio_devs[dev]->d->trigger)	/* Supports SETTRIGGER */
					val |= DSP_CAP_TRIGGER;
				break;
			
		case SOUND_PCM_WRITE_RATE:
			if (get_user(val, p))
				return -EFAULT;
			val = audio_devs[dev]->d->set_speed(dev, val);
			break;

		case SOUND_PCM_READ_RATE:
			val = audio_devs[dev]->d->set_speed(dev, 0);
			break;
			
		case SNDCTL_DSP_STEREO:
			if (get_user(val, p))
				return -EFAULT;
			if (val > 1 || val < 0)
				return -EINVAL;
			val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1;
			break;

		case SOUND_PCM_WRITE_CHANNELS:
			if (get_user(val, p))
				return -EFAULT;
			val = audio_devs[dev]->d->set_channels(dev, val);
			break;

		case SOUND_PCM_READ_CHANNELS:
			val = audio_devs[dev]->d->set_channels(dev, 0);
			break;
		
		case SOUND_PCM_READ_BITS:
			val = audio_devs[dev]->d->set_bits(dev, 0);
			break;

		case SNDCTL_DSP_SETDUPLEX:
			if (audio_devs[dev]->open_mode != OPEN_READWRITE)
				return -EPERM;
			return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO;

		case SNDCTL_DSP_PROFILE:
			if (get_user(val, p))
				return -EFAULT;
			if (audio_devs[dev]->open_mode & OPEN_WRITE)
				audio_devs[dev]->dmap_out->applic_profile = val;
			if (audio_devs[dev]->open_mode & OPEN_READ)
				audio_devs[dev]->dmap_in->applic_profile = val;
			return 0;
		
		case SNDCTL_DSP_GETODELAY:
			dmap = audio_devs[dev]->dmap_out;
			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
				return -EINVAL;
			if (!(dmap->flags & DMA_ALLOC_DONE))
			{
				val=0;
				break;
			}
		
			spin_lock_irqsave(&dmap->lock,flags);
			/* Compute number of bytes that have been played */
			count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
			if (count < dmap->fragment_size && dmap->qhead != 0)
				count += dmap->bytes_in_use;	/* Pointer wrap not handled yet */
			count += dmap->byte_counter;
		
			/* Subtract current count from the number of bytes written by app */
			count = dmap->user_counter - count;
			if (count < 0)
				count = 0;
			spin_unlock_irqrestore(&dmap->lock,flags);
			val = count;
			break;
		
		default:
			return dma_ioctl(dev, cmd, arg);
	}
	return put_user(val, p);
}