aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-06-23 08:38:23 -0400
committerJaroslav Kysela <perex@suse.cz>2006-09-23 04:36:58 -0400
commitc461482c8072bb073e6146db320d3da85cdc89ad (patch)
tree3b69cfd292a488a8cb57ac9b040bd2b1b1a1e26d /sound
parent746d4a02e68499fc6c1f8d0c43d2271853ade181 (diff)
[ALSA] Unregister device files at disconnection
Orignally proposed by Sam Revitch <sam.revitch@gmail.com>. Unregister device files at disconnection to avoid the futher accesses. Also, the dev_unregister callback is removed and replaced with the combination of disconnect + free. A new function snd_card_free_when_closed() is introduced, which is used in USB disconnect callback. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r--sound/core/control.c27
-rw-r--r--sound/core/device.c20
-rw-r--r--sound/core/hwdep.c10
-rw-r--r--sound/core/init.c69
-rw-r--r--sound/core/oss/mixer_oss.c16
-rw-r--r--sound/core/oss/pcm_oss.c16
-rw-r--r--sound/core/pcm.c48
-rw-r--r--sound/core/rawmidi.c35
-rw-r--r--sound/core/rtctimer.c2
-rw-r--r--sound/core/seq/seq_device.c11
-rw-r--r--sound/core/timer.c52
-rw-r--r--sound/pci/ac97/ac97_codec.c8
-rw-r--r--sound/usb/usbaudio.c2
13 files changed, 146 insertions, 170 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index e9c8854d2f7b..f0c7272a2d48 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1375,6 +1375,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
1375 struct snd_card *card = device->device_data; 1375 struct snd_card *card = device->device_data;
1376 struct list_head *flist; 1376 struct list_head *flist;
1377 struct snd_ctl_file *ctl; 1377 struct snd_ctl_file *ctl;
1378 int err, cardnum;
1379
1380 snd_assert(card != NULL, return -ENXIO);
1381 cardnum = card->number;
1382 snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
1378 1383
1379 down_read(&card->controls_rwsem); 1384 down_read(&card->controls_rwsem);
1380 list_for_each(flist, &card->ctl_files) { 1385 list_for_each(flist, &card->ctl_files) {
@@ -1383,6 +1388,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
1383 kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); 1388 kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
1384 } 1389 }
1385 up_read(&card->controls_rwsem); 1390 up_read(&card->controls_rwsem);
1391
1392 if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
1393 card, -1)) < 0)
1394 return err;
1386 return 0; 1395 return 0;
1387} 1396}
1388 1397
@@ -1404,23 +1413,6 @@ static int snd_ctl_dev_free(struct snd_device *device)
1404} 1413}
1405 1414
1406/* 1415/*
1407 * de-registration of the control device
1408 */
1409static int snd_ctl_dev_unregister(struct snd_device *device)
1410{
1411 struct snd_card *card = device->device_data;
1412 int err, cardnum;
1413
1414 snd_assert(card != NULL, return -ENXIO);
1415 cardnum = card->number;
1416 snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
1417 if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
1418 card, -1)) < 0)
1419 return err;
1420 return snd_ctl_dev_free(device);
1421}
1422
1423/*
1424 * create control core: 1416 * create control core:
1425 * called from init.c 1417 * called from init.c
1426 */ 1418 */
@@ -1430,7 +1422,6 @@ int snd_ctl_create(struct snd_card *card)
1430 .dev_free = snd_ctl_dev_free, 1422 .dev_free = snd_ctl_dev_free,
1431 .dev_register = snd_ctl_dev_register, 1423 .dev_register = snd_ctl_dev_register,
1432 .dev_disconnect = snd_ctl_dev_disconnect, 1424 .dev_disconnect = snd_ctl_dev_disconnect,
1433 .dev_unregister = snd_ctl_dev_unregister
1434 }; 1425 };
1435 1426
1436 snd_assert(card != NULL, return -ENXIO); 1427 snd_assert(card != NULL, return -ENXIO);
diff --git a/sound/core/device.c b/sound/core/device.c
index 6ce4da4a1081..ccb25816ac9e 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new);
71 * @device_data: the data pointer to release 71 * @device_data: the data pointer to release
72 * 72 *
73 * Removes the device from the list on the card and invokes the 73 * Removes the device from the list on the card and invokes the
74 * callback, dev_unregister or dev_free, corresponding to the state. 74 * callbacks, dev_disconnect and dev_free, corresponding to the state.
75 * Then release the device. 75 * Then release the device.
76 * 76 *
77 * Returns zero if successful, or a negative error code on failure or if the 77 * Returns zero if successful, or a negative error code on failure or if the
@@ -90,16 +90,14 @@ int snd_device_free(struct snd_card *card, void *device_data)
90 continue; 90 continue;
91 /* unlink */ 91 /* unlink */
92 list_del(&dev->list); 92 list_del(&dev->list);
93 if ((dev->state == SNDRV_DEV_REGISTERED || 93 if (dev->state == SNDRV_DEV_REGISTERED &&
94 dev->state == SNDRV_DEV_DISCONNECTED) && 94 dev->ops->dev_disconnect)
95 dev->ops->dev_unregister) { 95 if (dev->ops->dev_disconnect(dev))
96 if (dev->ops->dev_unregister(dev)) 96 snd_printk(KERN_ERR
97 snd_printk(KERN_ERR "device unregister failure\n"); 97 "device disconnect failure\n");
98 } else { 98 if (dev->ops->dev_free) {
99 if (dev->ops->dev_free) { 99 if (dev->ops->dev_free(dev))
100 if (dev->ops->dev_free(dev)) 100 snd_printk(KERN_ERR "device free failure\n");
101 snd_printk(KERN_ERR "device free failure\n");
102 }
103 } 101 }
104 kfree(dev); 102 kfree(dev);
105 return 0; 103 return 0;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index cbd8a63282b6..9aa9d94891f0 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex);
42static int snd_hwdep_free(struct snd_hwdep *hwdep); 42static int snd_hwdep_free(struct snd_hwdep *hwdep);
43static int snd_hwdep_dev_free(struct snd_device *device); 43static int snd_hwdep_dev_free(struct snd_device *device);
44static int snd_hwdep_dev_register(struct snd_device *device); 44static int snd_hwdep_dev_register(struct snd_device *device);
45static int snd_hwdep_dev_unregister(struct snd_device *device); 45static int snd_hwdep_dev_disconnect(struct snd_device *device);
46 46
47 47
48static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) 48static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
@@ -353,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
353 static struct snd_device_ops ops = { 353 static struct snd_device_ops ops = {
354 .dev_free = snd_hwdep_dev_free, 354 .dev_free = snd_hwdep_dev_free,
355 .dev_register = snd_hwdep_dev_register, 355 .dev_register = snd_hwdep_dev_register,
356 .dev_unregister = snd_hwdep_dev_unregister 356 .dev_disconnect = snd_hwdep_dev_disconnect,
357 }; 357 };
358 358
359 snd_assert(rhwdep != NULL, return -EINVAL); 359 snd_assert(rhwdep != NULL, return -EINVAL);
@@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device)
439 return 0; 439 return 0;
440} 440}
441 441
442static int snd_hwdep_dev_unregister(struct snd_device *device) 442static int snd_hwdep_dev_disconnect(struct snd_device *device)
443{ 443{
444 struct snd_hwdep *hwdep = device->device_data; 444 struct snd_hwdep *hwdep = device->device_data;
445 445
@@ -454,9 +454,9 @@ static int snd_hwdep_dev_unregister(struct snd_device *device)
454 snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); 454 snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
455#endif 455#endif
456 snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); 456 snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
457 list_del(&hwdep->list); 457 list_del_init(&hwdep->list);
458 mutex_unlock(&register_mutex); 458 mutex_unlock(&register_mutex);
459 return snd_hwdep_free(hwdep); 459 return 0;
460} 460}
461 461
462#ifdef CONFIG_PROC_FS 462#ifdef CONFIG_PROC_FS
diff --git a/sound/core/init.c b/sound/core/init.c
index 1ecb029ff4c9..5850d99d21e3 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -327,22 +327,10 @@ EXPORT_SYMBOL(snd_card_disconnect);
327 * Returns zero. Frees all associated devices and frees the control 327 * Returns zero. Frees all associated devices and frees the control
328 * interface associated to given soundcard. 328 * interface associated to given soundcard.
329 */ 329 */
330int snd_card_free(struct snd_card *card) 330static int snd_card_do_free(struct snd_card *card)
331{ 331{
332 struct snd_shutdown_f_ops *s_f_ops; 332 struct snd_shutdown_f_ops *s_f_ops;
333 333
334 if (card == NULL)
335 return -EINVAL;
336 mutex_lock(&snd_card_mutex);
337 snd_cards[card->number] = NULL;
338 mutex_unlock(&snd_card_mutex);
339
340#ifdef CONFIG_PM
341 wake_up(&card->power_sleep);
342#endif
343 /* wait, until all devices are ready for the free operation */
344 wait_event(card->shutdown_sleep, card->files == NULL);
345
346#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) 334#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
347 if (snd_mixer_oss_notify_callback) 335 if (snd_mixer_oss_notify_callback)
348 snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); 336 snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
@@ -371,10 +359,55 @@ int snd_card_free(struct snd_card *card)
371 card->s_f_ops = s_f_ops->next; 359 card->s_f_ops = s_f_ops->next;
372 kfree(s_f_ops); 360 kfree(s_f_ops);
373 } 361 }
362 kfree(card);
363 return 0;
364}
365
366static int snd_card_free_prepare(struct snd_card *card)
367{
368 if (card == NULL)
369 return -EINVAL;
370 (void) snd_card_disconnect(card);
374 mutex_lock(&snd_card_mutex); 371 mutex_lock(&snd_card_mutex);
372 snd_cards[card->number] = NULL;
375 snd_cards_lock &= ~(1 << card->number); 373 snd_cards_lock &= ~(1 << card->number);
376 mutex_unlock(&snd_card_mutex); 374 mutex_unlock(&snd_card_mutex);
377 kfree(card); 375#ifdef CONFIG_PM
376 wake_up(&card->power_sleep);
377#endif
378 return 0;
379}
380
381int snd_card_free_when_closed(struct snd_card *card)
382{
383 int free_now = 0;
384 int ret = snd_card_free_prepare(card);
385 if (ret)
386 return ret;
387
388 spin_lock(&card->files_lock);
389 if (card->files == NULL)
390 free_now = 1;
391 else
392 card->free_on_last_close = 1;
393 spin_unlock(&card->files_lock);
394
395 if (free_now)
396 snd_card_do_free(card);
397 return 0;
398}
399
400EXPORT_SYMBOL(snd_card_free_when_closed);
401
402int snd_card_free(struct snd_card *card)
403{
404 int ret = snd_card_free_prepare(card);
405 if (ret)
406 return ret;
407
408 /* wait, until all devices are ready for the free operation */
409 wait_event(card->shutdown_sleep, card->files == NULL);
410 snd_card_do_free(card);
378 return 0; 411 return 0;
379} 412}
380 413
@@ -718,6 +751,7 @@ EXPORT_SYMBOL(snd_card_file_add);
718int snd_card_file_remove(struct snd_card *card, struct file *file) 751int snd_card_file_remove(struct snd_card *card, struct file *file)
719{ 752{
720 struct snd_monitor_file *mfile, *pfile = NULL; 753 struct snd_monitor_file *mfile, *pfile = NULL;
754 int last_close = 0;
721 755
722 spin_lock(&card->files_lock); 756 spin_lock(&card->files_lock);
723 mfile = card->files; 757 mfile = card->files;
@@ -732,9 +766,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
732 pfile = mfile; 766 pfile = mfile;
733 mfile = mfile->next; 767 mfile = mfile->next;
734 } 768 }
735 spin_unlock(&card->files_lock);
736 if (card->files == NULL) 769 if (card->files == NULL)
770 last_close = 1;
771 spin_unlock(&card->files_lock);
772 if (last_close) {
737 wake_up(&card->shutdown_sleep); 773 wake_up(&card->shutdown_sleep);
774 if (card->free_on_last_close)
775 snd_card_do_free(card);
776 }
738 if (!mfile) { 777 if (!mfile) {
739 snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); 778 snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
740 return -ENOENT; 779 return -ENOENT;
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 00c95def95aa..f4c67042e3ac 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1310,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
1310 card->mixer_oss = mixer; 1310 card->mixer_oss = mixer;
1311 snd_mixer_oss_build(mixer); 1311 snd_mixer_oss_build(mixer);
1312 snd_mixer_oss_proc_init(mixer); 1312 snd_mixer_oss_proc_init(mixer);
1313 } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) { 1313 } else {
1314 mixer = card->mixer_oss;
1315 if (mixer == NULL || !mixer->oss_dev_alloc)
1316 return 0;
1317 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1318 mixer->oss_dev_alloc = 0;
1319 } else { /* free */
1320 mixer = card->mixer_oss; 1314 mixer = card->mixer_oss;
1321 if (mixer == NULL) 1315 if (mixer == NULL)
1322 return 0; 1316 return 0;
1317 if (mixer->oss_dev_alloc) {
1323#ifdef SNDRV_OSS_INFO_DEV_MIXERS 1318#ifdef SNDRV_OSS_INFO_DEV_MIXERS
1324 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); 1319 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
1325#endif 1320#endif
1326 if (mixer->oss_dev_alloc)
1327 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); 1321 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1322 mixer->oss_dev_alloc = 0;
1323 }
1324 if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
1325 return 0;
1328 snd_mixer_oss_proc_done(mixer); 1326 snd_mixer_oss_proc_done(mixer);
1329 return snd_mixer_oss_free1(mixer); 1327 return snd_mixer_oss_free1(mixer);
1330 } 1328 }
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index a92b93e5ebd5..505b23ec4058 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2929,25 +2929,23 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
2929 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, 2929 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2930 pcm->card, 1); 2930 pcm->card, 1);
2931 } 2931 }
2932 }
2933 return 0;
2934}
2935
2936static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
2937{
2938 snd_pcm_oss_disconnect_minor(pcm);
2939 if (pcm->oss.reg) {
2940 if (dsp_map[pcm->card->number] == (int)pcm->device) { 2932 if (dsp_map[pcm->card->number] == (int)pcm->device) {
2941#ifdef SNDRV_OSS_INFO_DEV_AUDIO 2933#ifdef SNDRV_OSS_INFO_DEV_AUDIO
2942 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); 2934 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
2943#endif 2935#endif
2944 } 2936 }
2945 pcm->oss.reg = 0; 2937 pcm->oss.reg = 0;
2946 snd_pcm_oss_proc_done(pcm);
2947 } 2938 }
2948 return 0; 2939 return 0;
2949} 2940}
2950 2941
2942static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
2943{
2944 snd_pcm_oss_disconnect_minor(pcm);
2945 snd_pcm_oss_proc_done(pcm);
2946 return 0;
2947}
2948
2951static struct snd_pcm_notify snd_pcm_oss_notify = 2949static struct snd_pcm_notify snd_pcm_oss_notify =
2952{ 2950{
2953 .n_register = snd_pcm_oss_register_minor, 2951 .n_register = snd_pcm_oss_register_minor,
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index b8602471f7e5..f52178abf120 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm);
42static int snd_pcm_dev_free(struct snd_device *device); 42static int snd_pcm_dev_free(struct snd_device *device);
43static int snd_pcm_dev_register(struct snd_device *device); 43static int snd_pcm_dev_register(struct snd_device *device);
44static int snd_pcm_dev_disconnect(struct snd_device *device); 44static int snd_pcm_dev_disconnect(struct snd_device *device);
45static int snd_pcm_dev_unregister(struct snd_device *device);
46 45
47static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) 46static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
48{ 47{
@@ -680,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
680 .dev_free = snd_pcm_dev_free, 679 .dev_free = snd_pcm_dev_free,
681 .dev_register = snd_pcm_dev_register, 680 .dev_register = snd_pcm_dev_register,
682 .dev_disconnect = snd_pcm_dev_disconnect, 681 .dev_disconnect = snd_pcm_dev_disconnect,
683 .dev_unregister = snd_pcm_dev_unregister
684 }; 682 };
685 683
686 snd_assert(rpcm != NULL, return -EINVAL); 684 snd_assert(rpcm != NULL, return -EINVAL);
@@ -724,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
724 substream = pstr->substream; 722 substream = pstr->substream;
725 while (substream) { 723 while (substream) {
726 substream_next = substream->next; 724 substream_next = substream->next;
725 snd_pcm_timer_done(substream);
727 snd_pcm_substream_proc_done(substream); 726 snd_pcm_substream_proc_done(substream);
728 kfree(substream); 727 kfree(substream);
729 substream = substream_next; 728 substream = substream_next;
@@ -740,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
740 739
741static int snd_pcm_free(struct snd_pcm *pcm) 740static int snd_pcm_free(struct snd_pcm *pcm)
742{ 741{
742 struct snd_pcm_notify *notify;
743
743 snd_assert(pcm != NULL, return -ENXIO); 744 snd_assert(pcm != NULL, return -ENXIO);
745 list_for_each_entry(notify, &snd_pcm_notify_list, list) {
746 notify->n_unregister(pcm);
747 }
744 if (pcm->private_free) 748 if (pcm->private_free)
745 pcm->private_free(pcm); 749 pcm->private_free(pcm);
746 snd_pcm_lib_preallocate_free_for_all(pcm); 750 snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -955,35 +959,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
955static int snd_pcm_dev_disconnect(struct snd_device *device) 959static int snd_pcm_dev_disconnect(struct snd_device *device)
956{ 960{
957 struct snd_pcm *pcm = device->device_data; 961 struct snd_pcm *pcm = device->device_data;
958 struct list_head *list; 962 struct snd_pcm_notify *notify;
959 struct snd_pcm_substream *substream; 963 struct snd_pcm_substream *substream;
960 int cidx; 964 int cidx, devtype;
961 965
962 mutex_lock(&register_mutex); 966 mutex_lock(&register_mutex);
967 if (list_empty(&pcm->list))
968 goto unlock;
969
963 list_del_init(&pcm->list); 970 list_del_init(&pcm->list);
964 for (cidx = 0; cidx < 2; cidx++) 971 for (cidx = 0; cidx < 2; cidx++)
965 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) 972 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
966 if (substream->runtime) 973 if (substream->runtime)
967 substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; 974 substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
968 list_for_each(list, &snd_pcm_notify_list) { 975 list_for_each_entry(notify, &snd_pcm_notify_list, list) {
969 struct snd_pcm_notify *notify;
970 notify = list_entry(list, struct snd_pcm_notify, list);
971 notify->n_disconnect(pcm); 976 notify->n_disconnect(pcm);
972 } 977 }
973 mutex_unlock(&register_mutex);
974 return 0;
975}
976
977static int snd_pcm_dev_unregister(struct snd_device *device)
978{
979 int cidx, devtype;
980 struct snd_pcm_substream *substream;
981 struct list_head *list;
982 struct snd_pcm *pcm = device->device_data;
983
984 snd_assert(pcm != NULL, return -ENXIO);
985 mutex_lock(&register_mutex);
986 list_del(&pcm->list);
987 for (cidx = 0; cidx < 2; cidx++) { 978 for (cidx = 0; cidx < 2; cidx++) {
988 devtype = -1; 979 devtype = -1;
989 switch (cidx) { 980 switch (cidx) {
@@ -995,23 +986,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device)
995 break; 986 break;
996 } 987 }
997 snd_unregister_device(devtype, pcm->card, pcm->device); 988 snd_unregister_device(devtype, pcm->card, pcm->device);
998 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
999 snd_pcm_timer_done(substream);
1000 }
1001 list_for_each(list, &snd_pcm_notify_list) {
1002 struct snd_pcm_notify *notify;
1003 notify = list_entry(list, struct snd_pcm_notify, list);
1004 notify->n_unregister(pcm);
1005 } 989 }
990 unlock:
1006 mutex_unlock(&register_mutex); 991 mutex_unlock(&register_mutex);
1007 return snd_pcm_free(pcm); 992 return 0;
1008} 993}
1009 994
1010int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) 995int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
1011{ 996{
1012 struct list_head *p; 997 struct list_head *p;
1013 998
1014 snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); 999 snd_assert(notify != NULL &&
1000 notify->n_register != NULL &&
1001 notify->n_unregister != NULL &&
1002 notify->n_disconnect, return -EINVAL);
1015 mutex_lock(&register_mutex); 1003 mutex_lock(&register_mutex);
1016 if (nfree) { 1004 if (nfree) {
1017 list_del(&notify->list); 1005 list_del(&notify->list);
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 51577c22f8ce..8a2bdfae63e3 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_rawmidi *rawmidi);
55static int snd_rawmidi_dev_free(struct snd_device *device); 55static int snd_rawmidi_dev_free(struct snd_device *device);
56static int snd_rawmidi_dev_register(struct snd_device *device); 56static int snd_rawmidi_dev_register(struct snd_device *device);
57static int snd_rawmidi_dev_disconnect(struct snd_device *device); 57static int snd_rawmidi_dev_disconnect(struct snd_device *device);
58static int snd_rawmidi_dev_unregister(struct snd_device *device);
59 58
60static LIST_HEAD(snd_rawmidi_devices); 59static LIST_HEAD(snd_rawmidi_devices);
61static DEFINE_MUTEX(register_mutex); 60static DEFINE_MUTEX(register_mutex);
@@ -1426,7 +1425,6 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
1426 .dev_free = snd_rawmidi_dev_free, 1425 .dev_free = snd_rawmidi_dev_free,
1427 .dev_register = snd_rawmidi_dev_register, 1426 .dev_register = snd_rawmidi_dev_register,
1428 .dev_disconnect = snd_rawmidi_dev_disconnect, 1427 .dev_disconnect = snd_rawmidi_dev_disconnect,
1429 .dev_unregister = snd_rawmidi_dev_unregister
1430 }; 1428 };
1431 1429
1432 snd_assert(rrawmidi != NULL, return -EINVAL); 1430 snd_assert(rrawmidi != NULL, return -EINVAL);
@@ -1479,6 +1477,14 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
1479static int snd_rawmidi_free(struct snd_rawmidi *rmidi) 1477static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
1480{ 1478{
1481 snd_assert(rmidi != NULL, return -ENXIO); 1479 snd_assert(rmidi != NULL, return -ENXIO);
1480
1481 snd_info_free_entry(rmidi->proc_entry);
1482 rmidi->proc_entry = NULL;
1483 mutex_lock(&register_mutex);
1484 if (rmidi->ops && rmidi->ops->dev_unregister)
1485 rmidi->ops->dev_unregister(rmidi);
1486 mutex_unlock(&register_mutex);
1487
1482 snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); 1488 snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
1483 snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); 1489 snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
1484 if (rmidi->private_free) 1490 if (rmidi->private_free)
@@ -1587,21 +1593,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
1587 1593
1588 mutex_lock(&register_mutex); 1594 mutex_lock(&register_mutex);
1589 list_del_init(&rmidi->list); 1595 list_del_init(&rmidi->list);
1590 mutex_unlock(&register_mutex);
1591 return 0;
1592}
1593
1594static int snd_rawmidi_dev_unregister(struct snd_device *device)
1595{
1596 struct snd_rawmidi *rmidi = device->device_data;
1597
1598 snd_assert(rmidi != NULL, return -ENXIO);
1599 mutex_lock(&register_mutex);
1600 list_del(&rmidi->list);
1601 if (rmidi->proc_entry) {
1602 snd_info_free_entry(rmidi->proc_entry);
1603 rmidi->proc_entry = NULL;
1604 }
1605#ifdef CONFIG_SND_OSSEMUL 1596#ifdef CONFIG_SND_OSSEMUL
1606 if (rmidi->ossreg) { 1597 if (rmidi->ossreg) {
1607 if ((int)rmidi->device == midi_map[rmidi->card->number]) { 1598 if ((int)rmidi->device == midi_map[rmidi->card->number]) {
@@ -1615,17 +1606,9 @@ static int snd_rawmidi_dev_unregister(struct snd_device *device)
1615 rmidi->ossreg = 0; 1606 rmidi->ossreg = 0;
1616 } 1607 }
1617#endif /* CONFIG_SND_OSSEMUL */ 1608#endif /* CONFIG_SND_OSSEMUL */
1618 if (rmidi->ops && rmidi->ops->dev_unregister)
1619 rmidi->ops->dev_unregister(rmidi);
1620 snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); 1609 snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
1621 mutex_unlock(&register_mutex); 1610 mutex_unlock(&register_mutex);
1622#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) 1611 return 0;
1623 if (rmidi->seq_dev) {
1624 snd_device_free(rmidi->card, rmidi->seq_dev);
1625 rmidi->seq_dev = NULL;
1626 }
1627#endif
1628 return snd_rawmidi_free(rmidi);
1629} 1612}
1630 1613
1631/** 1614/**
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 84704ccb1829..412dd62b654e 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -156,7 +156,7 @@ static int __init rtctimer_init(void)
156static void __exit rtctimer_exit(void) 156static void __exit rtctimer_exit(void)
157{ 157{
158 if (rtctimer) { 158 if (rtctimer) {
159 snd_timer_global_unregister(rtctimer); 159 snd_timer_global_free(rtctimer);
160 rtctimer = NULL; 160 rtctimer = NULL;
161 } 161 }
162} 162}
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index b85954e956d4..b79d011813c0 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -90,7 +90,6 @@ static int snd_seq_device_free(struct snd_seq_device *dev);
90static int snd_seq_device_dev_free(struct snd_device *device); 90static int snd_seq_device_dev_free(struct snd_device *device);
91static int snd_seq_device_dev_register(struct snd_device *device); 91static int snd_seq_device_dev_register(struct snd_device *device);
92static int snd_seq_device_dev_disconnect(struct snd_device *device); 92static int snd_seq_device_dev_disconnect(struct snd_device *device);
93static int snd_seq_device_dev_unregister(struct snd_device *device);
94 93
95static int init_device(struct snd_seq_device *dev, struct ops_list *ops); 94static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
96static int free_device(struct snd_seq_device *dev, struct ops_list *ops); 95static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
@@ -189,7 +188,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
189 .dev_free = snd_seq_device_dev_free, 188 .dev_free = snd_seq_device_dev_free,
190 .dev_register = snd_seq_device_dev_register, 189 .dev_register = snd_seq_device_dev_register,
191 .dev_disconnect = snd_seq_device_dev_disconnect, 190 .dev_disconnect = snd_seq_device_dev_disconnect,
192 .dev_unregister = snd_seq_device_dev_unregister
193 }; 191 };
194 192
195 if (result) 193 if (result)
@@ -309,15 +307,6 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
309} 307}
310 308
311/* 309/*
312 * unregister the existing device
313 */
314static int snd_seq_device_dev_unregister(struct snd_device *device)
315{
316 struct snd_seq_device *dev = device->device_data;
317 return snd_seq_device_free(dev);
318}
319
320/*
321 * register device driver 310 * register device driver
322 * id = driver id 311 * id = driver id
323 * entry = driver operators - duplicated to each instance 312 * entry = driver operators - duplicated to each instance
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 52ecbe1e9abb..7e5e562fe356 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex);
88static int snd_timer_free(struct snd_timer *timer); 88static int snd_timer_free(struct snd_timer *timer);
89static int snd_timer_dev_free(struct snd_device *device); 89static int snd_timer_dev_free(struct snd_device *device);
90static int snd_timer_dev_register(struct snd_device *device); 90static int snd_timer_dev_register(struct snd_device *device);
91static int snd_timer_dev_unregister(struct snd_device *device); 91static int snd_timer_dev_disconnect(struct snd_device *device);
92 92
93static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); 93static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
94 94
@@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
773 static struct snd_device_ops ops = { 773 static struct snd_device_ops ops = {
774 .dev_free = snd_timer_dev_free, 774 .dev_free = snd_timer_dev_free,
775 .dev_register = snd_timer_dev_register, 775 .dev_register = snd_timer_dev_register,
776 .dev_unregister = snd_timer_dev_unregister 776 .dev_disconnect = snd_timer_dev_disconnect,
777 }; 777 };
778 778
779 snd_assert(tid != NULL, return -EINVAL); 779 snd_assert(tid != NULL, return -EINVAL);
@@ -813,6 +813,21 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
813static int snd_timer_free(struct snd_timer *timer) 813static int snd_timer_free(struct snd_timer *timer)
814{ 814{
815 snd_assert(timer != NULL, return -ENXIO); 815 snd_assert(timer != NULL, return -ENXIO);
816
817 mutex_lock(&register_mutex);
818 if (! list_empty(&timer->open_list_head)) {
819 struct list_head *p, *n;
820 struct snd_timer_instance *ti;
821 snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
822 list_for_each_safe(p, n, &timer->open_list_head) {
823 list_del_init(p);
824 ti = list_entry(p, struct snd_timer_instance, open_list);
825 ti->timer = NULL;
826 }
827 }
828 list_del(&timer->device_list);
829 mutex_unlock(&register_mutex);
830
816 if (timer->private_free) 831 if (timer->private_free)
817 timer->private_free(timer); 832 timer->private_free(timer);
818 kfree(timer); 833 kfree(timer);
@@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct snd_device *dev)
867 return 0; 882 return 0;
868} 883}
869 884
870static int snd_timer_unregister(struct snd_timer *timer) 885static int snd_timer_dev_disconnect(struct snd_device *device)
871{ 886{
872 struct list_head *p, *n; 887 struct snd_timer *timer = device->device_data;
873 struct snd_timer_instance *ti;
874
875 snd_assert(timer != NULL, return -ENXIO);
876 mutex_lock(&register_mutex); 888 mutex_lock(&register_mutex);
877 if (! list_empty(&timer->open_list_head)) { 889 list_del_init(&timer->device_list);
878 snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
879 list_for_each_safe(p, n, &timer->open_list_head) {
880 list_del_init(p);
881 ti = list_entry(p, struct snd_timer_instance, open_list);
882 ti->timer = NULL;
883 }
884 }
885 list_del(&timer->device_list);
886 mutex_unlock(&register_mutex); 890 mutex_unlock(&register_mutex);
887 return snd_timer_free(timer); 891 return 0;
888}
889
890static int snd_timer_dev_unregister(struct snd_device *device)
891{
892 struct snd_timer *timer = device->device_data;
893 return snd_timer_unregister(timer);
894} 892}
895 893
896void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) 894void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
@@ -955,11 +953,6 @@ int snd_timer_global_register(struct snd_timer *timer)
955 return snd_timer_dev_register(&dev); 953 return snd_timer_dev_register(&dev);
956} 954}
957 955
958int snd_timer_global_unregister(struct snd_timer *timer)
959{
960 return snd_timer_unregister(timer);
961}
962
963/* 956/*
964 * System timer 957 * System timer
965 */ 958 */
@@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void)
1982 /* unregister the system timer */ 1975 /* unregister the system timer */
1983 list_for_each_safe(p, n, &snd_timer_list) { 1976 list_for_each_safe(p, n, &snd_timer_list) {
1984 struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); 1977 struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
1985 snd_timer_unregister(timer); 1978 snd_timer_free(timer);
1986 } 1979 }
1987 snd_timer_proc_done(); 1980 snd_timer_proc_done();
1988#ifdef SNDRV_OSS_INFO_DEV_TIMERS 1981#ifdef SNDRV_OSS_INFO_DEV_TIMERS
@@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify);
2005EXPORT_SYMBOL(snd_timer_global_new); 1998EXPORT_SYMBOL(snd_timer_global_new);
2006EXPORT_SYMBOL(snd_timer_global_free); 1999EXPORT_SYMBOL(snd_timer_global_free);
2007EXPORT_SYMBOL(snd_timer_global_register); 2000EXPORT_SYMBOL(snd_timer_global_register);
2008EXPORT_SYMBOL(snd_timer_global_unregister);
2009EXPORT_SYMBOL(snd_timer_interrupt); 2001EXPORT_SYMBOL(snd_timer_interrupt);
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 51e83d7a839a..b35280ca2465 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1817,13 +1817,13 @@ static int snd_ac97_dev_register(struct snd_device *device)
1817 return 0; 1817 return 0;
1818} 1818}
1819 1819
1820/* unregister ac97 codec */ 1820/* disconnect ac97 codec */
1821static int snd_ac97_dev_unregister(struct snd_device *device) 1821static int snd_ac97_dev_disconnect(struct snd_device *device)
1822{ 1822{
1823 struct snd_ac97 *ac97 = device->device_data; 1823 struct snd_ac97 *ac97 = device->device_data;
1824 if (ac97->dev.bus) 1824 if (ac97->dev.bus)
1825 device_unregister(&ac97->dev); 1825 device_unregister(&ac97->dev);
1826 return snd_ac97_free(ac97); 1826 return 0;
1827} 1827}
1828 1828
1829/* build_ops to do nothing */ 1829/* build_ops to do nothing */
@@ -1860,7 +1860,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
1860 static struct snd_device_ops ops = { 1860 static struct snd_device_ops ops = {
1861 .dev_free = snd_ac97_dev_free, 1861 .dev_free = snd_ac97_dev_free,
1862 .dev_register = snd_ac97_dev_register, 1862 .dev_register = snd_ac97_dev_register,
1863 .dev_unregister = snd_ac97_dev_unregister, 1863 .dev_disconnect = snd_ac97_dev_disconnect,
1864 }; 1864 };
1865 1865
1866 snd_assert(rac97 != NULL, return -EINVAL); 1866 snd_assert(rac97 != NULL, return -EINVAL);
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 1b7f499c549d..314431385913 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -3499,7 +3499,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
3499 } 3499 }
3500 usb_chip[chip->index] = NULL; 3500 usb_chip[chip->index] = NULL;
3501 mutex_unlock(&register_mutex); 3501 mutex_unlock(&register_mutex);
3502 snd_card_free(card); 3502 snd_card_free_when_closed(card);
3503 } else { 3503 } else {
3504 mutex_unlock(&register_mutex); 3504 mutex_unlock(&register_mutex);
3505 } 3505 }