⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcm_oss.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				break;		}	}	mutex_unlock(&runtime->oss.params_lock);	return xfer; err:	mutex_unlock(&runtime->oss.params_lock);	return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;}static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, size_t bytes, int in_kernel){	struct snd_pcm_runtime *runtime = substream->runtime;	snd_pcm_sframes_t frames, frames1;#ifdef CONFIG_SND_PCM_OSS_PLUGINS	char __user *final_dst = (char __user *)buf;	if (runtime->oss.plugin_first) {		struct snd_pcm_plugin_channel *channels;		size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;		if (!in_kernel)			buf = runtime->oss.buffer;		frames = bytes / oss_frame_bytes;		frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels);		if (frames1 < 0)			return frames1;		frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1);		if (frames1 <= 0)			return frames1;		bytes = frames1 * oss_frame_bytes;		if (!in_kernel && copy_to_user(final_dst, buf, bytes))			return -EFAULT;	} else#endif	{		frames = bytes_to_frames(runtime, bytes);		frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);		if (frames1 <= 0)			return frames1;		bytes = frames_to_bytes(runtime, frames1);	}	return bytes;}static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes){	size_t xfer = 0;	ssize_t tmp;	struct snd_pcm_runtime *runtime = substream->runtime;	if (atomic_read(&substream->mmap_count))		return -ENXIO;	if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)		return tmp;	mutex_lock(&runtime->oss.params_lock);	while (bytes > 0) {		if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {			if (runtime->oss.buffer_used == 0) {				tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);				if (tmp <= 0)					goto err;				runtime->oss.bytes += tmp;				runtime->oss.period_ptr = tmp;				runtime->oss.buffer_used = tmp;			}			tmp = bytes;			if ((size_t) tmp > runtime->oss.buffer_used)				tmp = runtime->oss.buffer_used;			if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) {				tmp = -EFAULT;				goto err;			}			buf += tmp;			bytes -= tmp;			xfer += tmp;			runtime->oss.buffer_used -= tmp;		} else {			tmp = snd_pcm_oss_read2(substream, (char __force *)buf,						runtime->oss.period_bytes, 0);			if (tmp <= 0)				goto err;			runtime->oss.bytes += tmp;			buf += tmp;			bytes -= tmp;			xfer += tmp;		}	}	mutex_unlock(&runtime->oss.params_lock);	return xfer; err:	mutex_unlock(&runtime->oss.params_lock);	return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;}static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file){	struct snd_pcm_substream *substream;	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];	if (substream != NULL) {		snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);		substream->runtime->oss.prepare = 1;	}	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];	if (substream != NULL) {		snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);		substream->runtime->oss.prepare = 1;	}	return 0;}static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file){	struct snd_pcm_substream *substream;	int err;	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];	if (substream != NULL) {		if ((err = snd_pcm_oss_make_ready(substream)) < 0)			return err;		snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);	}	/* note: all errors from the start action are ignored */	/* OSS apps do not know, how to handle them */	return 0;}static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size){	struct snd_pcm_runtime *runtime;	ssize_t result = 0;	long res;	wait_queue_t wait;	runtime = substream->runtime;	init_waitqueue_entry(&wait, current);	add_wait_queue(&runtime->sleep, &wait);#ifdef OSS_DEBUG	printk("sync1: size = %li\n", size);#endif	while (1) {		result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);		if (result > 0) {			runtime->oss.buffer_used = 0;			result = 0;			break;		}		if (result != 0 && result != -EAGAIN)			break;		result = 0;		set_current_state(TASK_INTERRUPTIBLE);		snd_pcm_stream_lock_irq(substream);		res = runtime->status->state;		snd_pcm_stream_unlock_irq(substream);		if (res != SNDRV_PCM_STATE_RUNNING) {			set_current_state(TASK_RUNNING);			break;		}		res = schedule_timeout(10 * HZ);		if (signal_pending(current)) {			result = -ERESTARTSYS;			break;		}		if (res == 0) {			snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");			result = -EIO;			break;		}	}	remove_wait_queue(&runtime->sleep, &wait);	return result;}static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file){	int err = 0;	unsigned int saved_f_flags;	struct snd_pcm_substream *substream;	struct snd_pcm_runtime *runtime;	snd_pcm_format_t format;	unsigned long width;	size_t size;	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];	if (substream != NULL) {		runtime = substream->runtime;		if (atomic_read(&substream->mmap_count))			goto __direct;		if ((err = snd_pcm_oss_make_ready(substream)) < 0)			return err;		format = snd_pcm_oss_format_from(runtime->oss.format);		width = snd_pcm_format_physical_width(format);		mutex_lock(&runtime->oss.params_lock);		if (runtime->oss.buffer_used > 0) {#ifdef OSS_DEBUG			printk("sync: buffer_used\n");#endif			size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;			snd_pcm_format_set_silence(format,						   runtime->oss.buffer + runtime->oss.buffer_used,						   size);			err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);			if (err < 0) {				mutex_unlock(&runtime->oss.params_lock);				return err;			}		} else if (runtime->oss.period_ptr > 0) {#ifdef OSS_DEBUG			printk("sync: period_ptr\n");#endif			size = runtime->oss.period_bytes - runtime->oss.period_ptr;			snd_pcm_format_set_silence(format,						   runtime->oss.buffer,						   size * 8 / width);			err = snd_pcm_oss_sync1(substream, size);			if (err < 0) {				mutex_unlock(&runtime->oss.params_lock);				return err;			}		}		/*		 * The ALSA's period might be a bit large than OSS one.		 * Fill the remain portion of ALSA period with zeros.		 */		size = runtime->control->appl_ptr % runtime->period_size;		if (size > 0) {			size = runtime->period_size - size;			if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {				size = (runtime->frame_bits * size) / 8;				while (size > 0) {					mm_segment_t fs;					size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes;					size -= size1;					size1 *= 8;					size1 /= runtime->sample_bits;					snd_pcm_format_set_silence(runtime->format,								   runtime->oss.buffer,								   size1);					fs = snd_enter_user();					snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);					snd_leave_user(fs);				}			} else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {				void __user *buffers[runtime->channels];				memset(buffers, 0, runtime->channels * sizeof(void *));				snd_pcm_lib_writev(substream, buffers, size);			}		}		mutex_unlock(&runtime->oss.params_lock);		/*		 * finish sync: drain the buffer		 */	      __direct:		saved_f_flags = substream->f_flags;		substream->f_flags &= ~O_NONBLOCK;		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);		substream->f_flags = saved_f_flags;		if (err < 0)			return err;		runtime->oss.prepare = 1;	}	substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];	if (substream != NULL) {		if ((err = snd_pcm_oss_make_ready(substream)) < 0)			return err;		runtime = substream->runtime;		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);		if (err < 0)			return err;		runtime->oss.buffer_used = 0;		runtime->oss.prepare = 1;	}	return 0;}static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate){	int idx;	for (idx = 1; idx >= 0; --idx) {		struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];		struct snd_pcm_runtime *runtime;		if (substream == NULL)			continue;		runtime = substream->runtime;		if (rate < 1000)			rate = 1000;		else if (rate > 192000)			rate = 192000;		if (runtime->oss.rate != rate) {			runtime->oss.params = 1;			runtime->oss.rate = rate;		}	}	return snd_pcm_oss_get_rate(pcm_oss_file);}static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file){	struct snd_pcm_substream *substream;	int err;		if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)		return err;	return substream->runtime->oss.rate;}static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsigned int channels){	int idx;	if (channels < 1)		channels = 1;	if (channels > 128)		return -EINVAL;	for (idx = 1; idx >= 0; --idx) {		struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];		struct snd_pcm_runtime *runtime;		if (substream == NULL)			continue;		runtime = substream->runtime;		if (runtime->oss.channels != channels) {			runtime->oss.params = 1;			runtime->oss.channels = channels;		}	}	return snd_pcm_oss_get_channels(pcm_oss_file);}static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file){	struct snd_pcm_substream *substream;	int err;		if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)		return err;	return substream->runtime->oss.channels;}static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file){	struct snd_pcm_substream *substream;	int err;		if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)		return err;	return substream->runtime->oss.period_bytes;}static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file){	struct snd_pcm_substream *substream;	int err;	int direct;	struct snd_pcm_hw_params *params;	unsigned int formats = 0;	struct snd_mask format_mask;	int fmt;	if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)		return err;	if (atomic_read(&substream->mmap_count))		direct = 1;	else		direct = substream->oss.setup.direct;	if (!direct)		return AFMT_MU_LAW | AFMT_U8 |		       AFMT_S16_LE | AFMT_S16_BE |		       AFMT_S8 | AFMT_U16_LE |		       AFMT_U16_BE |			AFMT_S32_LE | AFMT_S32_BE |			AFMT_S24_LE | AFMT_S24_LE |			AFMT_S24_PACKED;	params = kmalloc(sizeof(*params), GFP_KERNEL);	if (!params)		return -ENOMEM;	_snd_pcm_hw_params_any(params);	err = snd_pcm_hw_refine(substream, params);	format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 	kfree(params);	snd_assert(err >= 0, return err);	for (fmt = 0; fmt < 32; ++fmt) {		if (snd_mask_test(&format_mask, fmt)) {			int f = snd_pcm_oss_format_to(fmt);			if (f >= 0)				formats |= f;		}	}	return formats;}static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format){	int formats, idx;		if (format != AFMT_QUERY) {		formats = snd_pcm_oss_get_formats(pcm_oss_file);		if (formats < 0)			return formats;		if (!(formats & format))			format = AFMT_U8;		for (idx = 1; idx >= 0; --idx) {			struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];			struct snd_pcm_runtime *runtime;			if (substream == NULL)				continue;			runtime = substream->runtime;			if (runtime->oss.format != format) {				runtime->oss.params = 1;				runtime->oss.format = format;			}		}	}	return snd_pcm_oss_get_format(pcm_oss_file);}static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file){	struct snd_pcm_substream *substream;	int err;		if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)		return err;	return substream->runtime->oss.format;}static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int subdivide){	struct snd_pcm_runtime *runtime;	if (substream == NULL)		return 0;	runtime = substream->runtime;	if (subdivide == 0) {		subdivide = runtime->oss.subdivision;		if (subdivide == 0)			subdivide = 1;		return subdivide;	}	if (runtime->oss.subdivision || runtime->oss.fragshift)		return -EINVAL;	if (subdivide != 1 && subdivide != 2 && subdivide != 4 &&	    subdivide != 8 && subdivide != 16)		return -EINVAL;	runtime->oss.subdivision = subdivide;	runtime->oss.params = 1;	return subdivide;}static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int subdivide){	int err = -EINVAL, idx;	for (idx = 1; idx >= 0; --idx) {		struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];		if (substream == NULL)			continue;		if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)			return err;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -