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

📄 pcm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (pcm->private_free)		pcm->private_free(pcm);	snd_pcm_lib_preallocate_free_for_all(pcm);	snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]);	snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]);	kfree(pcm);	return 0;}static int snd_pcm_dev_free(struct snd_device *device){	struct snd_pcm *pcm = device->device_data;	return snd_pcm_free(pcm);}static void snd_pcm_tick_timer_func(unsigned long data){	struct snd_pcm_substream *substream = (struct snd_pcm_substream *) data;	snd_pcm_tick_elapsed(substream);}int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,			     struct file *file,			     struct snd_pcm_substream **rsubstream){	struct snd_pcm_str * pstr;	struct snd_pcm_substream *substream;	struct snd_pcm_runtime *runtime;	struct snd_ctl_file *kctl;	struct snd_card *card;	int prefer_subdevice = -1;	size_t size;	snd_assert(rsubstream != NULL, return -EINVAL);	*rsubstream = NULL;	snd_assert(pcm != NULL, return -ENXIO);	pstr = &pcm->streams[stream];	if (pstr->substream == NULL || pstr->substream_count == 0)		return -ENODEV;	card = pcm->card;	down_read(&card->controls_rwsem);	list_for_each_entry(kctl, &card->ctl_files, list) {		if (kctl->pid == current->pid) {			prefer_subdevice = kctl->prefer_pcm_subdevice;			if (prefer_subdevice != -1)				break;		}	}	up_read(&card->controls_rwsem);	switch (stream) {	case SNDRV_PCM_STREAM_PLAYBACK:		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {			for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {				if (SUBSTREAM_BUSY(substream))					return -EAGAIN;			}		}		break;	case SNDRV_PCM_STREAM_CAPTURE:		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {			for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {				if (SUBSTREAM_BUSY(substream))					return -EAGAIN;			}		}		break;	default:		return -EINVAL;	}	if (file->f_flags & O_APPEND) {		if (prefer_subdevice < 0) {			if (pstr->substream_count > 1)				return -EINVAL; /* must be unique */			substream = pstr->substream;		} else {			for (substream = pstr->substream; substream;			     substream = substream->next)				if (substream->number == prefer_subdevice)					break;		}		if (! substream)			return -ENODEV;		if (! SUBSTREAM_BUSY(substream))			return -EBADFD;		substream->ref_count++;		*rsubstream = substream;		return 0;	}	if (prefer_subdevice >= 0) {		for (substream = pstr->substream; substream; substream = substream->next)			if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)				goto __ok;	}	for (substream = pstr->substream; substream; substream = substream->next)		if (!SUBSTREAM_BUSY(substream))			break;      __ok:	if (substream == NULL)		return -EAGAIN;	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);	if (runtime == NULL)		return -ENOMEM;	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));	runtime->status = snd_malloc_pages(size, GFP_KERNEL);	if (runtime->status == NULL) {		kfree(runtime);		return -ENOMEM;	}	memset((void*)runtime->status, 0, size);	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));	runtime->control = snd_malloc_pages(size, GFP_KERNEL);	if (runtime->control == NULL) {		snd_free_pages((void*)runtime->status,			       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));		kfree(runtime);		return -ENOMEM;	}	memset((void*)runtime->control, 0, size);	init_waitqueue_head(&runtime->sleep);	init_timer(&runtime->tick_timer);	runtime->tick_timer.function = snd_pcm_tick_timer_func;	runtime->tick_timer.data = (unsigned long) substream;	runtime->status->state = SNDRV_PCM_STATE_OPEN;	substream->runtime = runtime;	substream->private_data = pcm->private_data;	substream->ref_count = 1;	substream->f_flags = file->f_flags;	pstr->substream_opened++;	*rsubstream = substream;	return 0;}void snd_pcm_detach_substream(struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime;	runtime = substream->runtime;	snd_assert(runtime != NULL, return);	if (runtime->private_free != NULL)		runtime->private_free(runtime);	snd_free_pages((void*)runtime->status,		       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));	snd_free_pages((void*)runtime->control,		       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));	kfree(runtime->hw_constraints.rules);	kfree(runtime);	substream->runtime = NULL;	substream->pstr->substream_opened--;}static ssize_t show_pcm_class(struct device *dev,			      struct device_attribute *attr, char *buf){	struct snd_pcm *pcm;	const char *str;	static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {		[SNDRV_PCM_CLASS_GENERIC] = "generic",		[SNDRV_PCM_CLASS_MULTI] = "multi",		[SNDRV_PCM_CLASS_MODEM] = "modem",		[SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",	};	if (! (pcm = dev_get_drvdata(dev)) ||	    pcm->dev_class > SNDRV_PCM_CLASS_LAST)		str = "none";	else		str = strs[pcm->dev_class];        return snprintf(buf, PAGE_SIZE, "%s\n", str);}static struct device_attribute pcm_attrs =	__ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);static int snd_pcm_dev_register(struct snd_device *device){	int cidx, err;	struct snd_pcm_substream *substream;	struct snd_pcm_notify *notify;	char str[16];	struct snd_pcm *pcm = device->device_data;	struct device *dev;	snd_assert(pcm != NULL && device != NULL, return -ENXIO);	mutex_lock(&register_mutex);	if (snd_pcm_search(pcm->card, pcm->device)) {		mutex_unlock(&register_mutex);		return -EBUSY;	}	list_add_tail(&pcm->list, &snd_pcm_devices);	for (cidx = 0; cidx < 2; cidx++) {		int devtype = -1;		if (pcm->streams[cidx].substream == NULL)			continue;		switch (cidx) {		case SNDRV_PCM_STREAM_PLAYBACK:			sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);			devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;			break;		case SNDRV_PCM_STREAM_CAPTURE:			sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);			devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;			break;		}		/* device pointer to use, pcm->dev takes precedence if		 * it is assigned, otherwise fall back to card's device		 * if possible */		dev = pcm->dev;		if (!dev)			dev = snd_card_get_device_link(pcm->card);		/* register pcm */		err = snd_register_device_for_dev(devtype, pcm->card,						  pcm->device,						  &snd_pcm_f_ops[cidx],						  pcm, str, dev);		if (err < 0) {			list_del(&pcm->list);			mutex_unlock(&register_mutex);			return err;		}		snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,					  &pcm_attrs);		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)			snd_pcm_timer_init(substream);	}	list_for_each_entry(notify, &snd_pcm_notify_list, list)		notify->n_register(pcm);	mutex_unlock(&register_mutex);	return 0;}static int snd_pcm_dev_disconnect(struct snd_device *device){	struct snd_pcm *pcm = device->device_data;	struct snd_pcm_notify *notify;	struct snd_pcm_substream *substream;	int cidx, devtype;	mutex_lock(&register_mutex);	if (list_empty(&pcm->list))		goto unlock;	list_del_init(&pcm->list);	for (cidx = 0; cidx < 2; cidx++)		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)			if (substream->runtime)				substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;	list_for_each_entry(notify, &snd_pcm_notify_list, list) {		notify->n_disconnect(pcm);	}	for (cidx = 0; cidx < 2; cidx++) {		devtype = -1;		switch (cidx) {		case SNDRV_PCM_STREAM_PLAYBACK:			devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;			break;		case SNDRV_PCM_STREAM_CAPTURE:			devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;			break;		}		snd_unregister_device(devtype, pcm->card, pcm->device);	} unlock:	mutex_unlock(&register_mutex);	return 0;}int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree){	struct snd_pcm *pcm;	snd_assert(notify != NULL &&		   notify->n_register != NULL &&		   notify->n_unregister != NULL &&		   notify->n_disconnect, return -EINVAL);	mutex_lock(&register_mutex);	if (nfree) {		list_del(&notify->list);		list_for_each_entry(pcm, &snd_pcm_devices, list)			notify->n_unregister(pcm);	} else {		list_add_tail(&notify->list, &snd_pcm_notify_list);		list_for_each_entry(pcm, &snd_pcm_devices, list)			notify->n_register(pcm);	}	mutex_unlock(&register_mutex);	return 0;}EXPORT_SYMBOL(snd_pcm_notify);#ifdef CONFIG_PROC_FS/* *  Info interface */static void snd_pcm_proc_read(struct snd_info_entry *entry,			      struct snd_info_buffer *buffer){	struct snd_pcm *pcm;	mutex_lock(&register_mutex);	list_for_each_entry(pcm, &snd_pcm_devices, list) {		snd_iprintf(buffer, "%02i-%02i: %s : %s",			    pcm->card->number, pcm->device, pcm->id, pcm->name);		if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)			snd_iprintf(buffer, " : playback %i",				    pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);		if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)			snd_iprintf(buffer, " : capture %i",				    pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);		snd_iprintf(buffer, "\n");	}	mutex_unlock(&register_mutex);}static struct snd_info_entry *snd_pcm_proc_entry;static void snd_pcm_proc_init(void){	struct snd_info_entry *entry;	if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {		snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);		if (snd_info_register(entry) < 0) {			snd_info_free_entry(entry);			entry = NULL;		}	}	snd_pcm_proc_entry = entry;}static void snd_pcm_proc_done(void){	snd_info_free_entry(snd_pcm_proc_entry);}#else /* !CONFIG_PROC_FS */#define snd_pcm_proc_init()#define snd_pcm_proc_done()#endif /* CONFIG_PROC_FS *//* *  ENTRY functions */static int __init alsa_pcm_init(void){	snd_ctl_register_ioctl(snd_pcm_control_ioctl);	snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);	snd_pcm_proc_init();	return 0;}static void __exit alsa_pcm_exit(void){	snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);	snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);	snd_pcm_proc_done();}module_init(alsa_pcm_init)module_exit(alsa_pcm_exit)

⌨️ 快捷键说明

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