Re: stateful reconnect with snd-usb-audio

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

 



On 6/16/06, Takashi Iwai <tiwai@xxxxxxx> wrote:
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().

Apparently the last patch had some problems tearing down the
/proc/asound/cardX/pcmYZ entries at disconnect time.  The attached one
should fix that.  The original one was developed on the driver bundled
with a recent -mm kernel that didn't seem to create those entries.
Anyway, it seems to work as advertised with the usb-audio driver, at
least in my configuration.  The whole /proc/asound/cardX tree goes
away immediately when the card is unplugged without hanging khubd, and
with an old handle held open, playback seems to work through the new
device instance on the same slot when the card is plugged back in.

Now, there has got to be some way to make usb-audio retain its
snd_card structure at disconnect time.  Perhaps it could optionally
leave things hanging for some period of time before calling
snd_card_disconnect(), leaving a window for the same device to be
reconnected...?  Does this sound too kludgy?

Thanks..
-Sam Revitch
diff -r 08577d0b45ef core/control.c
--- a/core/control.c	Tue Jun 13 12:01:14 2006 +0200
+++ b/core/control.c	Sat Jun 17 01:12:46 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	Sat Jun 17 01:12:46 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	Sat Jun 17 01:12:46 2006 -0700
@@ -820,6 +820,23 @@ struct snd_info_entry *snd_info_create_c
 
 EXPORT_SYMBOL(snd_info_create_card_entry);
 
+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;
+}
+
+EXPORT_SYMBOL(snd_info_disconnect);
+
 static int snd_info_dev_free_entry(struct snd_device *device)
 {
 	struct snd_info_entry *entry = device->device_data;
@@ -836,8 +853,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 +968,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	Sat Jun 17 01:12:46 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	Sat Jun 17 01:12:46 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	Sat Jun 17 01:12:46 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	Sat Jun 17 01:12:46 2006 -0700
@@ -491,6 +491,18 @@ static int snd_pcm_stream_proc_init(stru
 	return 0;
 }
 
+static void snd_pcm_stream_proc_disconnect(struct snd_pcm_str *pstr)
+{
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+	if (pstr->proc_xrun_debug_entry)
+		snd_info_disconnect(pstr->proc_xrun_debug_entry);
+#endif
+	if (pstr->proc_info_entry)
+		snd_info_disconnect(pstr->proc_info_entry);
+	if (pstr->proc_root)
+		snd_info_disconnect(pstr->proc_root);
+}
+
 static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
 {
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
@@ -569,6 +581,24 @@ static int snd_pcm_substream_proc_init(s
 	substream->proc_status_entry = entry;
 
 	return 0;
+}
+
+/* Non-exported utility function defined in pcm_memory.c */
+extern void snd_pcm_lib_disconnect(struct snd_pcm_substream *);
+
+static void snd_pcm_substream_proc_disconnect(struct snd_pcm_substream *substream)
+{
+	snd_pcm_lib_disconnect(substream);
+	if (substream->proc_info_entry)
+		snd_info_disconnect(substream->proc_info_entry);
+	if (substream->proc_hw_params_entry)
+		snd_info_disconnect(substream->proc_hw_params_entry);
+	if (substream->proc_sw_params_entry)
+		snd_info_disconnect(substream->proc_sw_params_entry);
+	if (substream->proc_status_entry)
+		snd_info_disconnect(substream->proc_status_entry);
+	if (substream->proc_root)
+		snd_info_disconnect(substream->proc_root);
 }
 		
 static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
@@ -968,40 +998,34 @@ 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++) {
+		struct snd_pcm_str *pstr = &pcm->streams[cidx];
+		int err;
 		devtype = -1;
+		for (substream = pstr->substream; substream; substream = substream->next)
+			snd_pcm_substream_proc_disconnect(substream);
+		snd_pcm_stream_proc_disconnect(pstr);
 		switch (cidx) {
 		case SNDRV_PCM_STREAM_PLAYBACK:
 			devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
@@ -1010,10 +1034,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/pcm_memory.c
--- a/core/pcm_memory.c	Tue Jun 13 12:01:14 2006 +0200
+++ b/core/pcm_memory.c	Sat Jun 17 01:12:46 2006 -0700
@@ -255,6 +255,16 @@ int snd_pcm_lib_preallocate_pages(struct
 
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
 
+
+void snd_pcm_lib_disconnect(struct snd_pcm_substream *substream)
+{
+#ifdef CONFIG_SND_VERBOSE_PROCFS
+	if (substream->proc_prealloc_entry)
+		snd_info_disconnect(substream->proc_prealloc_entry);
+#endif
+}
+
+
 /**
  * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams)
  * @pcm: the pcm instance
diff -r 08577d0b45ef core/timer.c
--- a/core/timer.c	Tue Jun 13 12:01:14 2006 +0200
+++ b/core/timer.c	Sat Jun 17 01:12:46 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	Sat Jun 17 01:12:46 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 include/info.h
--- a/include/info.h	Tue Jun 13 12:01:14 2006 +0200
+++ b/include/info.h	Sat Jun 17 01:12:46 2006 -0700
@@ -123,6 +123,7 @@ int snd_info_card_register(struct snd_ca
 int snd_info_card_register(struct snd_card * card);
 int snd_info_card_free(struct snd_card * card);
 int snd_info_register(struct snd_info_entry * entry);
+int snd_info_disconnect(struct snd_info_entry * entry);
 int snd_info_unregister(struct snd_info_entry * entry);
 
 /* for card drivers */
diff -r 08577d0b45ef usb/usbaudio.c
--- a/usb/usbaudio.c	Tue Jun 13 12:01:14 2006 +0200
+++ b/usb/usbaudio.c	Sat Jun 17 01:12:46 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);
 	}

_______________________________________________
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