Re: stateful reconnect with snd-usb-audio

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



At Thu, 15 Jun 2006 03:04:08 -0700,
Sam Revitch wrote:
> 
> For fun, here's a rough proof of concept patch to resolve the
> snd-usb-audio khubd hang.  It alters the behavior of snd_device
> dev_disconnect methods for abstract layers control, info, and pcm to
> also unregister sysfs/procfs entries.  It adds dev_disconnect methods
> to layers hwdep and timer to similar effect, and alters the behavior
> in the pcm_oss and mixer_oss modules through their special interfaces.
>  Omitted are the seq and rawmidi layers, which I haven't looked at.
> It moves the calls to snd_info_unregister() and snd_info_card_free()
> from snd_card_free() to snd_card_disconnect().  Finally, it breaks
> snd_card_free() into smaller functions, and leaves the
> wait-for-last-close semantic intact, but adds an
> snd_card_free_when_closed() function that causes the interesting parts
> of snd_card_free() to be called in the context of
> snd_card_file_remove().

The patch looks fine to me (as I also wanted to implement the same
stuff right now :)  Did you check whether it works with usb-audio
actually?

If it's confirmed to work, we can commit it together with the changes
for other components.  Then snd_card_free_in_thread() should be
replaced with snd_card_free_when_closed().


thanks,

Takashi

> 
> Thanks.
> -Sam Revitch
> [2 disconnect.patch <text/x-patch; ISO-8859-1 (base64)>]
> diff -r 08577d0b45ef core/control.c
> --- a/core/control.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/control.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -1375,6 +1375,11 @@ static int snd_ctl_dev_disconnect(struct
>  	struct snd_card *card = device->device_data;
>  	struct list_head *flist;
>  	struct snd_ctl_file *ctl;
> +	int err, cardnum;
> +
> +	snd_assert(card != NULL, return -ENXIO);
> +	cardnum = card->number;
> +	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
>  
>  	down_read(&card->controls_rwsem);
>  	list_for_each(flist, &card->ctl_files) {
> @@ -1383,6 +1388,10 @@ static int snd_ctl_dev_disconnect(struct
>  		kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
>  	}
>  	up_read(&card->controls_rwsem);
> +
> +	if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
> +					 card, -1)) < 0)
> +		return err;
>  	return 0;
>  }
>  
> @@ -1408,15 +1417,8 @@ static int snd_ctl_dev_free(struct snd_d
>   */
>  static int snd_ctl_dev_unregister(struct snd_device *device)
>  {
> -	struct snd_card *card = device->device_data;
> -	int err, cardnum;
> -
> -	snd_assert(card != NULL, return -ENXIO);
> -	cardnum = card->number;
> -	snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
> -	if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
> -					 card, -1)) < 0)
> -		return err;
> +	if (device->state == SNDRV_DEV_REGISTERED)
> +		(void) snd_ctl_dev_disconnect(device);
>  	return snd_ctl_dev_free(device);
>  }
>  
> diff -r 08577d0b45ef core/hwdep.c
> --- a/core/hwdep.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/hwdep.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -42,6 +42,7 @@ static int snd_hwdep_free(struct snd_hwd
>  static int snd_hwdep_free(struct snd_hwdep *hwdep);
>  static int snd_hwdep_dev_free(struct snd_device *device);
>  static int snd_hwdep_dev_register(struct snd_device *device);
> +static int snd_hwdep_dev_disconnect(struct snd_device *device);
>  static int snd_hwdep_dev_unregister(struct snd_device *device);
>  
>  
> @@ -353,6 +354,7 @@ int snd_hwdep_new(struct snd_card *card,
>  	static struct snd_device_ops ops = {
>  		.dev_free = snd_hwdep_dev_free,
>  		.dev_register = snd_hwdep_dev_register,
> +		.dev_disconnect = snd_hwdep_dev_disconnect,
>  		.dev_unregister = snd_hwdep_dev_unregister
>  	};
>  
> @@ -439,7 +441,7 @@ static int snd_hwdep_dev_register(struct
>  	return 0;
>  }
>  
> -static int snd_hwdep_dev_unregister(struct snd_device *device)
> +static int snd_hwdep_dev_disconnect(struct snd_device *device)
>  {
>  	struct snd_hwdep *hwdep = device->device_data;
>  
> @@ -454,8 +456,16 @@ static int snd_hwdep_dev_unregister(stru
>  		snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
>  #endif
>  	snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
> -	list_del(&hwdep->list);
> +	list_del_init(&hwdep->list);
>  	mutex_unlock(&register_mutex);
> +	return 0;
> +}
> +
> +static int snd_hwdep_dev_unregister(struct snd_device *device)
> +{
> +	struct snd_hwdep *hwdep = device->device_data;
> +	snd_assert(hwdep != NULL, return -ENXIO);
> +	(void) snd_hwdep_dev_disconnect(device);
>  	return snd_hwdep_free(hwdep);
>  }
>  
> diff -r 08577d0b45ef core/info.c
> --- a/core/info.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/info.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -820,6 +820,21 @@ struct snd_info_entry *snd_info_create_c
>  
>  EXPORT_SYMBOL(snd_info_create_card_entry);
>  
> +static int snd_info_disconnect(struct snd_info_entry *entry)
> +{
> +	struct proc_dir_entry *root;
> +	if (!entry->disconnected) {
> +		snd_assert(entry->p != NULL, return -ENXIO);
> +		root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
> +		snd_assert(root, return -ENXIO);
> +		mutex_lock(&info_mutex);
> +		snd_remove_proc_entry(root, entry->p);
> +		mutex_unlock(&info_mutex);
> +		entry->disconnected = 1;
> +	}
> +	return 0;
> +}
> +
>  static int snd_info_dev_free_entry(struct snd_device *device)
>  {
>  	struct snd_info_entry *entry = device->device_data;
> @@ -836,8 +851,7 @@ static int snd_info_dev_disconnect_entry
>  static int snd_info_dev_disconnect_entry(struct snd_device *device)
>  {
>  	struct snd_info_entry *entry = device->device_data;
> -	entry->disconnected = 1;
> -	return 0;
> +	return snd_info_disconnect(entry);
>  }
>  
>  static int snd_info_dev_unregister_entry(struct snd_device *device)
> @@ -952,16 +966,9 @@ EXPORT_SYMBOL(snd_info_register);
>   */
>  int snd_info_unregister(struct snd_info_entry * entry)
>  {
> -	struct proc_dir_entry *root;
> -
>  	if (! entry)
>  		return 0;
> -	snd_assert(entry->p != NULL, return -ENXIO);
> -	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
> -	snd_assert(root, return -ENXIO);
> -	mutex_lock(&info_mutex);
> -	snd_remove_proc_entry(root, entry->p);
> -	mutex_unlock(&info_mutex);
> +	(void) snd_info_disconnect(entry);
>  	snd_info_free_entry(entry);
>  	return 0;
>  }
> diff -r 08577d0b45ef core/init.c
> --- a/core/init.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/init.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -310,70 +310,104 @@ int snd_card_disconnect(struct snd_card 
>  	if (err < 0)
>  		snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
>  
> -	return 0;	
> -}
> -
> -EXPORT_SYMBOL(snd_card_disconnect);
> -
> -/**
> - *  snd_card_free - frees given soundcard structure
> - *  @card: soundcard structure
> - *
> - *  This function releases the soundcard structure and the all assigned
> - *  devices automatically.  That is, you don't have to release the devices
> - *  by yourself.
> - *
> - *  Returns zero. Frees all associated devices and frees the control
> - *  interface associated to given soundcard.
> - */
> -int snd_card_free(struct snd_card *card)
> -{
> -	struct snd_shutdown_f_ops *s_f_ops;
> -
> -	if (card == NULL)
> -		return -EINVAL;
> -	mutex_lock(&snd_card_mutex);
> -	snd_cards[card->number] = NULL;
> -	mutex_unlock(&snd_card_mutex);
> -
> -#ifdef CONFIG_PM
> -	wake_up(&card->power_sleep);
> -#endif
> -	/* wait, until all devices are ready for the free operation */
> -	wait_event(card->shutdown_sleep, card->files == NULL);
> -
> -#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
> -	if (snd_mixer_oss_notify_callback)
> -		snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
> -#endif
> -	if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
> -		snd_printk(KERN_ERR "unable to free all devices (pre)\n");
> -		/* Fatal, but this situation should never occur */
> -	}
> -	if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) {
> -		snd_printk(KERN_ERR "unable to free all devices (normal)\n");
> -		/* Fatal, but this situation should never occur */
> -	}
> -	if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) {
> -		snd_printk(KERN_ERR "unable to free all devices (post)\n");
> -		/* Fatal, but this situation should never occur */
> -	}
> -	if (card->private_free)
> -		card->private_free(card);
>  	snd_info_unregister(card->proc_id);
>  	if (snd_info_card_free(card) < 0) {
>  		snd_printk(KERN_WARNING "unable to free card info\n");
>  		/* Not fatal error */
>  	}
> +
> +	return 0;	
> +}
> +
> +EXPORT_SYMBOL(snd_card_disconnect);
> +
> +/**
> + *  snd_card_free - frees given soundcard structure
> + *  @card: soundcard structure
> + *
> + *  This function releases the soundcard structure and the all assigned
> + *  devices automatically.  That is, you don't have to release the devices
> + *  by yourself.
> + *
> + *  Returns zero. Frees all associated devices and frees the control
> + *  interface associated to given soundcard.
> + */
> +static int snd_card_do_free(struct snd_card *card)
> +{
> +	struct snd_shutdown_f_ops *s_f_ops;
> +
> +#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
> +	if (snd_mixer_oss_notify_callback)
> +		snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
> +#endif
> +	if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
> +		snd_printk(KERN_ERR "unable to free all devices (pre)\n");
> +		/* Fatal, but this situation should never occur */
> +	}
> +	if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) {
> +		snd_printk(KERN_ERR "unable to free all devices (normal)\n");
> +		/* Fatal, but this situation should never occur */
> +	}
> +	if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) {
> +		snd_printk(KERN_ERR "unable to free all devices (post)\n");
> +		/* Fatal, but this situation should never occur */
> +	}
> +	if (card->private_free)
> +		card->private_free(card);
>  	while (card->s_f_ops) {
>  		s_f_ops = card->s_f_ops;
>  		card->s_f_ops = s_f_ops->next;
>  		kfree(s_f_ops);
>  	}
> +	kfree(card);
> +	return 0;
> +}
> +
> +static int snd_card_free_prepare(struct snd_card *card)
> +{
> +	if (card == NULL)
> +		return -EINVAL;
> +	(void) snd_card_disconnect(card);
>  	mutex_lock(&snd_card_mutex);
> +	snd_cards[card->number] = NULL;
>  	snd_cards_lock &= ~(1 << card->number);
>  	mutex_unlock(&snd_card_mutex);
> -	kfree(card);
> +#ifdef CONFIG_PM
> +	wake_up(&card->power_sleep);
> +#endif
> +	return 0;
> +}
> +
> +int snd_card_free_when_closed(struct snd_card *card)
> +{
> +	int free_now = 0;
> +	int ret = snd_card_free_prepare(card);
> +	if (ret)
> +		return ret;
> +
> +	spin_lock(&card->files_lock);
> +	if (card->files == NULL)
> +		free_now = 1;
> +	else
> +		card->free_on_last_close = 1;
> +	spin_unlock(&card->files_lock);
> +
> +	if (free_now)
> +		snd_card_do_free(card);
> +	return 0;
> +}
> +
> +EXPORT_SYMBOL(snd_card_free_when_closed);
> +
> +int snd_card_free(struct snd_card *card)
> +{
> +	int ret = snd_card_free_prepare(card);
> +	if (ret)
> +		return ret;
> +
> +	/* wait, until all devices are ready for the free operation */
> +	wait_event(card->shutdown_sleep, card->files == NULL);
> +	snd_card_do_free(card);
>  	return 0;
>  }
>  
> @@ -717,6 +751,7 @@ int snd_card_file_remove(struct snd_card
>  int snd_card_file_remove(struct snd_card *card, struct file *file)
>  {
>  	struct snd_monitor_file *mfile, *pfile = NULL;
> +	int last_close = 0;
>  
>  	spin_lock(&card->files_lock);
>  	mfile = card->files;
> @@ -731,9 +766,14 @@ int snd_card_file_remove(struct snd_card
>  		pfile = mfile;
>  		mfile = mfile->next;
>  	}
> +	if (card->files == NULL)
> +		last_close = 1;
>  	spin_unlock(&card->files_lock);
> -	if (card->files == NULL)
> +	if (last_close) {
>  		wake_up(&card->shutdown_sleep);
> +		if (card->free_on_last_close)
> +			snd_card_do_free(card);
> +	}
>  	if (!mfile) {
>  		snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
>  		return -ENOENT;
> diff -r 08577d0b45ef core/oss/mixer_oss.c
> --- a/core/oss/mixer_oss.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/oss/mixer_oss.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -1313,22 +1313,20 @@ static int snd_mixer_oss_notify_handler(
>  		card->mixer_oss = mixer;
>  		snd_mixer_oss_build(mixer);
>  		snd_mixer_oss_proc_init(mixer);
> -	} else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
> -		mixer = card->mixer_oss;
> -		if (mixer == NULL || !mixer->oss_dev_alloc)
> -			return 0;
> -		snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
> -		mixer->oss_dev_alloc = 0;
> -	} else {		/* free */
> +	} else {
>  		mixer = card->mixer_oss;
>  		if (mixer == NULL)
>  			return 0;
> +		if (mixer->oss_dev_alloc) {
>  #ifdef SNDRV_OSS_INFO_DEV_MIXERS
> -		snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
> +			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
>  #endif
> -		if (mixer->oss_dev_alloc)
>  			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
> -		snd_mixer_oss_proc_done(mixer);
> +			snd_mixer_oss_proc_done(mixer);
> +			mixer->oss_dev_alloc = 0;
> +		}
> +		if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
> +			return 0;
>  		return snd_mixer_oss_free1(mixer);
>  	}
>  	return 0;
> diff -r 08577d0b45ef core/oss/pcm_oss.c
> --- a/core/oss/pcm_oss.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/oss/pcm_oss.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -2929,14 +2929,6 @@ static int snd_pcm_oss_disconnect_minor(
>  			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
>  						  pcm->card, 1);
>  		}
> -	}
> -	return 0;
> -}
> -
> -static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
> -{
> -	snd_pcm_oss_disconnect_minor(pcm);
> -	if (pcm->oss.reg) {
>  		if (dsp_map[pcm->card->number] == (int)pcm->device) {
>  #ifdef SNDRV_OSS_INFO_DEV_AUDIO
>  			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
> @@ -2945,6 +2937,12 @@ static int snd_pcm_oss_unregister_minor(
>  		pcm->oss.reg = 0;
>  		snd_pcm_oss_proc_done(pcm);
>  	}
> +	return 0;
> +}
> +
> +static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
> +{
> +	snd_pcm_oss_disconnect_minor(pcm);
>  	return 0;
>  }
>  
> diff -r 08577d0b45ef core/pcm.c
> --- a/core/pcm.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/pcm.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -968,39 +968,29 @@ static int snd_pcm_dev_register(struct s
>  	return 0;
>  }
>  
> -static int snd_pcm_dev_disconnect(struct snd_device *device)
> -{
> -	struct snd_pcm *pcm = device->device_data;
> +static int snd_pcm_do_disconnect(struct snd_pcm *pcm, int notify)
> +{
>  	struct list_head *list;
>  	struct snd_pcm_substream *substream;
> -	int cidx;
> -
> -	mutex_lock(&register_mutex);
> +	int cidx, devtype;
> +
> +	if (list_empty(&pcm->list))
> +		return 0;
> +
>  	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(list, &snd_pcm_notify_list) {
> -		struct snd_pcm_notify *notify;
> -		notify = list_entry(list, struct snd_pcm_notify, list);
> -		notify->n_disconnect(pcm);
> -	}
> -	mutex_unlock(&register_mutex);
> -	return 0;
> -}
> -
> -static int snd_pcm_dev_unregister(struct snd_device *device)
> -{
> -	int cidx, devtype;
> -	struct snd_pcm_substream *substream;
> -	struct list_head *list;
> -	struct snd_pcm *pcm = device->device_data;
> -
> -	snd_assert(pcm != NULL, return -ENXIO);
> -	mutex_lock(&register_mutex);
> -	list_del(&pcm->list);
> +	if (notify) {
> +		list_for_each(list, &snd_pcm_notify_list) {
> +			struct snd_pcm_notify *notify;
> +			notify = list_entry(list, struct snd_pcm_notify, list);
> +			notify->n_disconnect(pcm);
> +		}
> +	}
>  	for (cidx = 0; cidx < 2; cidx++) {
> +		int err;
>  		devtype = -1;
>  		switch (cidx) {
>  		case SNDRV_PCM_STREAM_PLAYBACK:
> @@ -1010,10 +1000,38 @@ static int snd_pcm_dev_unregister(struct
>  			devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
>  			break;
>  		}
> -		snd_unregister_device(devtype, pcm->card, pcm->device);
> +		err = snd_unregister_device(devtype, pcm->card, pcm->device);
> +		if (err < 0)
> +			snd_printk(KERN_ERR "snd_unregister_device %d/%d = %i\n",
> +					pcm->card->number, devtype, err);
> +	}
> +	return 0;
> +}
> +
> +static int snd_pcm_dev_disconnect(struct snd_device *device)
> +{
> +	struct snd_pcm *pcm = device->device_data;
> +	int err = 0;
> +
> +	mutex_lock(&register_mutex);
> +	err = snd_pcm_do_disconnect(pcm, 1);
> +	mutex_unlock(&register_mutex);
> +	return err;
> +}
> +
> +static int snd_pcm_dev_unregister(struct snd_device *device)
> +{
> +	int cidx;
> +	struct snd_pcm_substream *substream;
> +	struct list_head *list;
> +	struct snd_pcm *pcm = device->device_data;
> +
> +	snd_assert(pcm != NULL, return -ENXIO);
> +	mutex_lock(&register_mutex);
> +	snd_pcm_do_disconnect(pcm, 0);
> +	for (cidx = 0; cidx < 2; cidx++)
>  		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
>  			snd_pcm_timer_done(substream);
> -	}
>  	list_for_each(list, &snd_pcm_notify_list) {
>  		struct snd_pcm_notify *notify;
>  		notify = list_entry(list, struct snd_pcm_notify, list);
> diff -r 08577d0b45ef core/timer.c
> --- a/core/timer.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/timer.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -88,6 +88,7 @@ static int snd_timer_free(struct snd_tim
>  static int snd_timer_free(struct snd_timer *timer);
>  static int snd_timer_dev_free(struct snd_device *device);
>  static int snd_timer_dev_register(struct snd_device *device);
> +static int snd_timer_dev_disconnect(struct snd_device *device);
>  static int snd_timer_dev_unregister(struct snd_device *device);
>  
>  static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
> @@ -772,6 +773,7 @@ int snd_timer_new(struct snd_card *card,
>  	static struct snd_device_ops ops = {
>  		.dev_free = snd_timer_dev_free,
>  		.dev_register = snd_timer_dev_register,
> +		.dev_disconnect = snd_timer_dev_disconnect,
>  		.dev_unregister = snd_timer_dev_unregister
>  	};
>  
> @@ -884,6 +886,15 @@ static int snd_timer_unregister(struct s
>  	list_del(&timer->device_list);
>  	mutex_unlock(&register_mutex);
>  	return snd_timer_free(timer);
> +}
> +
> +static int snd_timer_dev_disconnect(struct snd_device *device)
> +{
> +	struct snd_timer *timer = device->device_data;
> +	mutex_lock(&register_mutex);
> +	list_del_init(&timer->device_list);
> +	mutex_unlock(&register_mutex);
> +	return 0;
>  }
>  
>  static int snd_timer_dev_unregister(struct snd_device *device)
> diff -r 08577d0b45ef include/core.h
> --- a/include/core.h	Tue Jun 13 12:01:14 2006 +0200
> +++ b/include/core.h	Thu Jun 15 03:02:53 2006 -0700
> @@ -131,6 +131,7 @@ struct snd_card {
>  								state */
>  	spinlock_t files_lock;		/* lock the files for this card */
>  	int shutdown;			/* this card is going down */
> +	int free_on_last_close;		/* free in context of file_release */
>  	wait_queue_head_t shutdown_sleep;
>  	struct work_struct free_workq;	/* for free in workqueue */
>  	struct device *dev;
> @@ -246,6 +247,7 @@ struct snd_card *snd_card_new(int idx, c
>  			 struct module *module, int extra_size);
>  int snd_card_disconnect(struct snd_card *card);
>  int snd_card_free(struct snd_card *card);
> +int snd_card_free_when_closed(struct snd_card *card);
>  int snd_card_free_in_thread(struct snd_card *card);
>  int snd_card_register(struct snd_card *card);
>  int snd_card_info_init(void);
> diff -r 08577d0b45ef usb/usbaudio.c
> --- a/usb/usbaudio.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/usb/usbaudio.c	Thu Jun 15 03:02:53 2006 -0700
> @@ -3469,7 +3469,7 @@ static void snd_usb_audio_disconnect(str
>  		}
>  		usb_chip[chip->index] = NULL;
>  		mutex_unlock(&register_mutex);
> -		snd_card_free(card);
> +		snd_card_free_when_closed(card);
>  	} else {
>  		mutex_unlock(&register_mutex);
>  	}
> [3  <text/plain; us-ascii (7bit)>]
> 
> [4  <text/plain; us-ascii (7bit)>]
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
> https://lists.sourceforge.net/lists/listinfo/alsa-devel


_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux