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

📄 pcm_oss.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (err < 0)		goto failure;	n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);	err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);	snd_assert(err >= 0, goto failure);	err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,				     runtime->oss.periods, NULL);	snd_assert(err >= 0, goto failure);	snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) {		snd_printd("HW_PARAMS failed: %i\n", err);		goto failure;	}	memset(sw_params, 0, sizeof(*sw_params));	if (runtime->oss.trigger) {		sw_params->start_threshold = 1;	} else {		sw_params->start_threshold = runtime->boundary;	}	if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)		sw_params->stop_threshold = runtime->boundary;	else		sw_params->stop_threshold = runtime->buffer_size;	sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;	sw_params->period_step = 1;	sw_params->sleep_min = 0;	sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?		1 : runtime->period_size;	sw_params->xfer_align = 1;	if (atomic_read(&runtime->mmap_count) ||	    (substream->oss.setup && substream->oss.setup->nosilence)) {		sw_params->silence_threshold = 0;		sw_params->silence_size = 0;	} else {		snd_pcm_uframes_t frames;		frames = runtime->period_size + 16;		if (frames > runtime->buffer_size)			frames = runtime->buffer_size;		sw_params->silence_threshold = frames;		sw_params->silence_size = frames;	}	if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {		snd_printd("SW_PARAMS failed: %i\n", err);		goto failure;	}	runtime->oss.periods = params_periods(sparams);	oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));	snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);	if (runtime->oss.plugin_first) {		err = snd_pcm_plug_alloc(substream, oss_period_size);		if (err < 0)			goto failure;	}	oss_period_size *= oss_frame_size;	oss_buffer_size = oss_period_size * runtime->oss.periods;	snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);	runtime->oss.period_bytes = oss_period_size;	runtime->oss.buffer_bytes = oss_buffer_size;	pdprintf("oss: period bytes = %i, buffer bytes = %i\n",		 runtime->oss.period_bytes,		 runtime->oss.buffer_bytes);	pdprintf("slave: period_size = %i, buffer_size = %i\n",		 params_period_size(sparams),		 params_buffer_size(sparams));	runtime->oss.format = snd_pcm_oss_format_to(params_format(params));	runtime->oss.channels = params_channels(params);	runtime->oss.rate = params_rate(params);	runtime->oss.params = 0;	runtime->oss.prepare = 1;	vfree(runtime->oss.buffer);	runtime->oss.buffer = vmalloc(runtime->oss.period_bytes);	runtime->oss.buffer_used = 0;	if (runtime->dma_area)		snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));	runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);	err = 0;failure:	kfree(sw_params);	kfree(params);	kfree(sparams);	return err;}static int snd_pcm_oss_get_active_substream(snd_pcm_oss_file_t *pcm_oss_file, snd_pcm_substream_t **r_substream){	int idx, err;	snd_pcm_substream_t *asubstream = NULL, *substream;	for (idx = 0; idx < 2; idx++) {		substream = pcm_oss_file->streams[idx];		if (substream == NULL)			continue;		if (asubstream == NULL)			asubstream = substream;		if (substream->runtime->oss.params) {			err = snd_pcm_oss_change_params(substream);			if (err < 0)				return err;		}	}	snd_assert(asubstream != NULL, return -EIO);	if (r_substream)		*r_substream = asubstream;	return 0;}static int snd_pcm_oss_prepare(snd_pcm_substream_t *substream){	int err;	snd_pcm_runtime_t *runtime = substream->runtime;	err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);	if (err < 0) {		snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");		return err;	}	runtime->oss.prepare = 0;	runtime->oss.prev_hw_ptr_interrupt = 0;	runtime->oss.period_ptr = 0;	runtime->oss.buffer_used = 0;	return 0;}static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream){	snd_pcm_runtime_t *runtime;	int err;	if (substream == NULL)		return 0;	runtime = substream->runtime;	if (runtime->oss.params) {		err = snd_pcm_oss_change_params(substream);		if (err < 0)			return err;	}	if (runtime->oss.prepare) {		err = snd_pcm_oss_prepare(substream);		if (err < 0)			return err;	}	return 0;}static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, snd_pcm_sframes_t *delay){	snd_pcm_runtime_t *runtime;	snd_pcm_uframes_t frames;	int err = 0;	while (1) {		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay);		if (err < 0)			break;		runtime = substream->runtime;		if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)			break;		/* in case of overrun, skip whole periods like OSS/Linux driver does */		/* until avail(delay) <= buffer_size */		frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;		frames /= runtime->period_size;		frames *= runtime->period_size;		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames);		if (err < 0)			break;	}	return err;}snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel){	snd_pcm_runtime_t *runtime = substream->runtime;	int ret;	while (1) {		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)				printk("pcm_oss: write: recovering from XRUN\n");			else				printk("pcm_oss: write: recovering from SUSPEND\n");#endif			ret = snd_pcm_oss_prepare(substream);			if (ret < 0)				break;		}		if (in_kernel) {			mm_segment_t fs;			fs = snd_enter_user();			ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);			snd_leave_user(fs);		} else {			ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);		}		if (ret != -EPIPE && ret != -ESTRPIPE)			break;		/* test, if we can't store new data, because the stream */		/* has not been started */		if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)			return -EAGAIN;	}	return ret;}snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t delay;	int ret;	while (1) {		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)				printk("pcm_oss: read: recovering from XRUN\n");			else				printk("pcm_oss: read: recovering from SUSPEND\n");#endif			ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);			if (ret < 0)				break;		} else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {			ret = snd_pcm_oss_prepare(substream);			if (ret < 0)				break;		}		ret = snd_pcm_oss_capture_position_fixup(substream, &delay);		if (ret < 0)			break;		if (in_kernel) {			mm_segment_t fs;			fs = snd_enter_user();			ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);			snd_leave_user(fs);		} else {			ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);		}		if (ret == -EPIPE) {			if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {				ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);				if (ret < 0)					break;			}			continue;		}		if (ret != -ESTRPIPE)			break;	}	return ret;}snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel){	snd_pcm_runtime_t *runtime = substream->runtime;	int ret;	while (1) {		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)				printk("pcm_oss: writev: recovering from XRUN\n");			else				printk("pcm_oss: writev: recovering from SUSPEND\n");#endif			ret = snd_pcm_oss_prepare(substream);			if (ret < 0)				break;		}		if (in_kernel) {			mm_segment_t fs;			fs = snd_enter_user();			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);			snd_leave_user(fs);		} else {			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);		}		if (ret != -EPIPE && ret != -ESTRPIPE)			break;		/* test, if we can't store new data, because the stream */		/* has not been started */		if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)			return -EAGAIN;	}	return ret;}	snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel){	snd_pcm_runtime_t *runtime = substream->runtime;	int ret;	while (1) {		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||		    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {#ifdef OSS_DEBUG			if (runtime->status->state == SNDRV_PCM_STATE_XRUN)				printk("pcm_oss: readv: recovering from XRUN\n");			else				printk("pcm_oss: readv: recovering from SUSPEND\n");#endif			ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);			if (ret < 0)				break;		} else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {			ret = snd_pcm_oss_prepare(substream);			if (ret < 0)				break;		}		if (in_kernel) {			mm_segment_t fs;			fs = snd_enter_user();			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);			snd_leave_user(fs);		} else {			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);		}		if (ret != -EPIPE && ret != -ESTRPIPE)			break;	}	return ret;}static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *buf, size_t bytes, int in_kernel){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t frames, frames1;	if (runtime->oss.plugin_first) {		snd_pcm_plugin_channel_t *channels;		size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;		if (!in_kernel) {			if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes))				return -EFAULT;			buf = runtime->oss.buffer;		}		frames = bytes / oss_frame_bytes;		frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels);		if (frames1 < 0)			return frames1;		frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1);		if (frames1 <= 0)			return frames1;		bytes = frames1 * oss_frame_bytes;	} else {		frames = bytes_to_frames(runtime, bytes);		frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);		if (frames1 <= 0)			return frames1;		bytes = frames_to_bytes(runtime, frames1);	}	return bytes;}static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char __user *buf, size_t bytes){	size_t xfer = 0;	ssize_t tmp;	snd_pcm_runtime_t *runtime = substream->runtime;	if (atomic_read(&runtime->mmap_count))		return -ENXIO;	if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)		return tmp;	while (bytes > 0) {		if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {			tmp = bytes;			if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)				tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;			if (tmp > 0) {				if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp))					return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT;			}			runtime->oss.buffer_used += tmp;			buf += tmp;			bytes -= tmp;			xfer += tmp;			if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) ||			    runtime->oss.buffer_used == runtime->oss.period_bytes) {				tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr, 							 runtime->oss.buffer_used - runtime->oss.period_ptr, 1);				if (tmp <= 0)					return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;				runtime->oss.bytes += tmp;				runtime->oss.period_ptr += tmp;				runtime->oss.period_ptr %= runtime->oss.period_bytes;				if (runtime->oss.period_ptr == 0 ||				    runtime->oss.period_ptr == runtime->oss.buffer_used)					runtime->oss.buffer_used = 0;				else if ((substream->ffile->f_flags & O_NONBLOCK) != 0)					return xfer > 0 ? xfer : -EAGAIN;			}		} else {			tmp = snd_pcm_oss_write2(substream,						 (const char __force *)buf,						 runtime->oss.period_bytes, 0);			if (tmp <= 0)				return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;			runtime->oss.bytes += tmp;			buf += tmp;			bytes -= tmp;			xfer += tmp;			if ((substream->ffile->f_flags & O_NONBLOCK) != 0 &&			    tmp != runtime->oss.period_bytes)				break;		}	}	return xfer;}static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size_t bytes, int in_kernel){	snd_pcm_runtime_t *runtime = substream->runtime;	snd_pcm_sframes_t frames, frames1;	char __user *final_dst = (char __user *)buf;	if (runtime->oss.plugin_first) {		snd_pcm_plugin_channel_t *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 {

⌨️ 快捷键说明

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