Commit c461482c authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela

[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: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent 746d4a02
...@@ -71,7 +71,6 @@ struct snd_device_ops { ...@@ -71,7 +71,6 @@ struct snd_device_ops {
int (*dev_free)(struct snd_device *dev); int (*dev_free)(struct snd_device *dev);
int (*dev_register)(struct snd_device *dev); int (*dev_register)(struct snd_device *dev);
int (*dev_disconnect)(struct snd_device *dev); int (*dev_disconnect)(struct snd_device *dev);
int (*dev_unregister)(struct snd_device *dev);
}; };
struct snd_device { struct snd_device {
...@@ -131,6 +130,7 @@ struct snd_card { ...@@ -131,6 +130,7 @@ struct snd_card {
state */ state */
spinlock_t files_lock; /* lock the files for this card */ spinlock_t files_lock; /* lock the files for this card */
int shutdown; /* this card is going down */ int shutdown; /* this card is going down */
int free_on_last_close; /* free in context of file_release */
wait_queue_head_t shutdown_sleep; wait_queue_head_t shutdown_sleep;
struct work_struct free_workq; /* for free in workqueue */ struct work_struct free_workq; /* for free in workqueue */
struct device *dev; struct device *dev;
...@@ -244,6 +244,7 @@ struct snd_card *snd_card_new(int idx, const char *id, ...@@ -244,6 +244,7 @@ struct snd_card *snd_card_new(int idx, const char *id,
struct module *module, int extra_size); struct module *module, int extra_size);
int snd_card_disconnect(struct snd_card *card); int snd_card_disconnect(struct snd_card *card);
int snd_card_free(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_free_in_thread(struct snd_card *card);
int snd_card_register(struct snd_card *card); int snd_card_register(struct snd_card *card);
int snd_card_info_init(void); int snd_card_info_init(void);
......
...@@ -129,7 +129,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam ...@@ -129,7 +129,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam
int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer); int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
int snd_timer_global_free(struct snd_timer *timer); int snd_timer_global_free(struct snd_timer *timer);
int snd_timer_global_register(struct snd_timer *timer); int snd_timer_global_register(struct snd_timer *timer);
int snd_timer_global_unregister(struct snd_timer *timer);
int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id); int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id);
int snd_timer_close(struct snd_timer_instance *timeri); int snd_timer_close(struct snd_timer_instance *timeri);
......
...@@ -1375,6 +1375,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) ...@@ -1375,6 +1375,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
struct snd_card *card = device->device_data; struct snd_card *card = device->device_data;
struct list_head *flist; struct list_head *flist;
struct snd_ctl_file *ctl; 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); down_read(&card->controls_rwsem);
list_for_each(flist, &card->ctl_files) { list_for_each(flist, &card->ctl_files) {
...@@ -1383,6 +1388,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) ...@@ -1383,6 +1388,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
} }
up_read(&card->controls_rwsem); up_read(&card->controls_rwsem);
if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
card, -1)) < 0)
return err;
return 0; return 0;
} }
...@@ -1403,23 +1412,6 @@ static int snd_ctl_dev_free(struct snd_device *device) ...@@ -1403,23 +1412,6 @@ static int snd_ctl_dev_free(struct snd_device *device)
return 0; return 0;
} }
/*
* de-registration of the control device
*/
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;
return snd_ctl_dev_free(device);
}
/* /*
* create control core: * create control core:
* called from init.c * called from init.c
...@@ -1430,7 +1422,6 @@ int snd_ctl_create(struct snd_card *card) ...@@ -1430,7 +1422,6 @@ int snd_ctl_create(struct snd_card *card)
.dev_free = snd_ctl_dev_free, .dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register, .dev_register = snd_ctl_dev_register,
.dev_disconnect = snd_ctl_dev_disconnect, .dev_disconnect = snd_ctl_dev_disconnect,
.dev_unregister = snd_ctl_dev_unregister
}; };
snd_assert(card != NULL, return -ENXIO); snd_assert(card != NULL, return -ENXIO);
......
...@@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new); ...@@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new);
* @device_data: the data pointer to release * @device_data: the data pointer to release
* *
* Removes the device from the list on the card and invokes the * Removes the device from the list on the card and invokes the
* callback, dev_unregister or dev_free, corresponding to the state. * callbacks, dev_disconnect and dev_free, corresponding to the state.
* Then release the device. * Then release the device.
* *
* Returns zero if successful, or a negative error code on failure or if the * Returns zero if successful, or a negative error code on failure or if the
...@@ -90,17 +90,15 @@ int snd_device_free(struct snd_card *card, void *device_data) ...@@ -90,17 +90,15 @@ int snd_device_free(struct snd_card *card, void *device_data)
continue; continue;
/* unlink */ /* unlink */
list_del(&dev->list); list_del(&dev->list);
if ((dev->state == SNDRV_DEV_REGISTERED || if (dev->state == SNDRV_DEV_REGISTERED &&
dev->state == SNDRV_DEV_DISCONNECTED) && dev->ops->dev_disconnect)
dev->ops->dev_unregister) { if (dev->ops->dev_disconnect(dev))
if (dev->ops->dev_unregister(dev)) snd_printk(KERN_ERR
snd_printk(KERN_ERR "device unregister failure\n"); "device disconnect failure\n");
} else {
if (dev->ops->dev_free) { if (dev->ops->dev_free) {
if (dev->ops->dev_free(dev)) if (dev->ops->dev_free(dev))
snd_printk(KERN_ERR "device free failure\n"); snd_printk(KERN_ERR "device free failure\n");
} }
}
kfree(dev); kfree(dev);
return 0; return 0;
} }
......
...@@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex); ...@@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex);
static int snd_hwdep_free(struct snd_hwdep *hwdep); static int snd_hwdep_free(struct snd_hwdep *hwdep);
static int snd_hwdep_dev_free(struct snd_device *device); 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_register(struct snd_device *device);
static int snd_hwdep_dev_unregister(struct snd_device *device); static int snd_hwdep_dev_disconnect(struct snd_device *device);
static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) static 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,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
static struct snd_device_ops ops = { static struct snd_device_ops ops = {
.dev_free = snd_hwdep_dev_free, .dev_free = snd_hwdep_dev_free,
.dev_register = snd_hwdep_dev_register, .dev_register = snd_hwdep_dev_register,
.dev_unregister = snd_hwdep_dev_unregister .dev_disconnect = snd_hwdep_dev_disconnect,
}; };
snd_assert(rhwdep != NULL, return -EINVAL); snd_assert(rhwdep != NULL, return -EINVAL);
...@@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device) ...@@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device)
return 0; 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; struct snd_hwdep *hwdep = device->device_data;
...@@ -454,9 +454,9 @@ static int snd_hwdep_dev_unregister(struct snd_device *device) ...@@ -454,9 +454,9 @@ static int snd_hwdep_dev_unregister(struct snd_device *device)
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
#endif #endif
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
list_del(&hwdep->list); list_del_init(&hwdep->list);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
return snd_hwdep_free(hwdep); return 0;
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -327,22 +327,10 @@ EXPORT_SYMBOL(snd_card_disconnect); ...@@ -327,22 +327,10 @@ EXPORT_SYMBOL(snd_card_disconnect);
* Returns zero. Frees all associated devices and frees the control * Returns zero. Frees all associated devices and frees the control
* interface associated to given soundcard. * interface associated to given soundcard.
*/ */
int snd_card_free(struct snd_card *card) static int snd_card_do_free(struct snd_card *card)
{ {
struct snd_shutdown_f_ops *s_f_ops; 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 defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback) if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
...@@ -371,10 +359,55 @@ int snd_card_free(struct snd_card *card) ...@@ -371,10 +359,55 @@ int snd_card_free(struct snd_card *card)
card->s_f_ops = s_f_ops->next; card->s_f_ops = s_f_ops->next;
kfree(s_f_ops); 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); mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
snd_cards_lock &= ~(1 << card->number); snd_cards_lock &= ~(1 << card->number);
mutex_unlock(&snd_card_mutex); 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; return 0;
} }
...@@ -718,6 +751,7 @@ EXPORT_SYMBOL(snd_card_file_add); ...@@ -718,6 +751,7 @@ EXPORT_SYMBOL(snd_card_file_add);
int snd_card_file_remove(struct snd_card *card, struct file *file) int snd_card_file_remove(struct snd_card *card, struct file *file)
{ {
struct snd_monitor_file *mfile, *pfile = NULL; struct snd_monitor_file *mfile, *pfile = NULL;
int last_close = 0;
spin_lock(&card->files_lock); spin_lock(&card->files_lock);
mfile = card->files; mfile = card->files;
...@@ -732,9 +766,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) ...@@ -732,9 +766,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
pfile = mfile; pfile = mfile;
mfile = mfile->next; mfile = mfile->next;
} }
spin_unlock(&card->files_lock);
if (card->files == NULL) if (card->files == NULL)
last_close = 1;
spin_unlock(&card->files_lock);
if (last_close) {
wake_up(&card->shutdown_sleep); wake_up(&card->shutdown_sleep);
if (card->free_on_last_close)
snd_card_do_free(card);
}
if (!mfile) { if (!mfile) {
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
return -ENOENT; return -ENOENT;
......
...@@ -1310,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) ...@@ -1310,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
card->mixer_oss = mixer; card->mixer_oss = mixer;
snd_mixer_oss_build(mixer); snd_mixer_oss_build(mixer);
snd_mixer_oss_proc_init(mixer); snd_mixer_oss_proc_init(mixer);
} else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) { } else {
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 */
mixer = card->mixer_oss; mixer = card->mixer_oss;
if (mixer == NULL) if (mixer == NULL)
return 0; return 0;
if (mixer->oss_dev_alloc) {
#ifdef SNDRV_OSS_INFO_DEV_MIXERS #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 #endif
if (mixer->oss_dev_alloc)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
mixer->oss_dev_alloc = 0;
}
if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
return 0;
snd_mixer_oss_proc_done(mixer); snd_mixer_oss_proc_done(mixer);
return snd_mixer_oss_free1(mixer); return snd_mixer_oss_free1(mixer);
} }
......
...@@ -2929,6 +2929,12 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm) ...@@ -2929,6 +2929,12 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, 1); pcm->card, 1);
} }
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);
#endif
}
pcm->oss.reg = 0;
} }
return 0; return 0;
} }
...@@ -2936,15 +2942,7 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm) ...@@ -2936,15 +2942,7 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm) static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
{ {
snd_pcm_oss_disconnect_minor(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);
#endif
}
pcm->oss.reg = 0;
snd_pcm_oss_proc_done(pcm); snd_pcm_oss_proc_done(pcm);
}
return 0; return 0;
} }
......
...@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm); ...@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm);
static int snd_pcm_dev_free(struct snd_device *device); static int snd_pcm_dev_free(struct snd_device *device);
static int snd_pcm_dev_register(struct snd_device *device); static int snd_pcm_dev_register(struct snd_device *device);
static int snd_pcm_dev_disconnect(struct snd_device *device); static int snd_pcm_dev_disconnect(struct snd_device *device);
static int snd_pcm_dev_unregister(struct snd_device *device);
static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
{ {
...@@ -680,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, ...@@ -680,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
.dev_free = snd_pcm_dev_free, .dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register, .dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect, .dev_disconnect = snd_pcm_dev_disconnect,
.dev_unregister = snd_pcm_dev_unregister
}; };
snd_assert(rpcm != NULL, return -EINVAL); snd_assert(rpcm != NULL, return -EINVAL);
...@@ -724,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) ...@@ -724,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
substream = pstr->substream; substream = pstr->substream;
while (substream) { while (substream) {
substream_next = substream->next; substream_next = substream->next;
snd_pcm_timer_done(substream);
snd_pcm_substream_proc_done(substream); snd_pcm_substream_proc_done(substream);
kfree(substream); kfree(substream);
substream = substream_next; substream = substream_next;
...@@ -740,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) ...@@ -740,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
static int snd_pcm_free(struct snd_pcm *pcm) static int snd_pcm_free(struct snd_pcm *pcm)
{ {
struct snd_pcm_notify *notify;
snd_assert(pcm != NULL, return -ENXIO); snd_assert(pcm != NULL, return -ENXIO);
list_for_each_entry(notify, &snd_pcm_notify_list, list) {
notify->n_unregister(pcm);
}
if (pcm->private_free) if (pcm->private_free)
pcm->private_free(pcm); pcm->private_free(pcm);
snd_pcm_lib_preallocate_free_for_all(pcm); snd_pcm_lib_preallocate_free_for_all(pcm);
...@@ -955,35 +959,22 @@ static int snd_pcm_dev_register(struct snd_device *device) ...@@ -955,35 +959,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
static int snd_pcm_dev_disconnect(struct snd_device *device) static int snd_pcm_dev_disconnect(struct snd_device *device)
{ {
struct snd_pcm *pcm = device->device_data; struct snd_pcm *pcm = device->device_data;
struct list_head *list; struct snd_pcm_notify *notify;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
int cidx; int cidx, devtype;
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
if (list_empty(&pcm->list))
goto unlock;
list_del_init(&pcm->list); list_del_init(&pcm->list);
for (cidx = 0; cidx < 2; cidx++) for (cidx = 0; cidx < 2; cidx++)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
if (substream->runtime) if (substream->runtime)
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
list_for_each(list, &snd_pcm_notify_list) { list_for_each_entry(notify, &snd_pcm_notify_list, list) {
struct snd_pcm_notify *notify;
notify = list_entry(list, struct snd_pcm_notify, list);
notify->n_disconnect(pcm); 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);
for (cidx = 0; cidx < 2; cidx++) { for (cidx = 0; cidx < 2; cidx++) {
devtype = -1; devtype = -1;
switch (cidx) { switch (cidx) {
...@@ -995,23 +986,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device) ...@@ -995,23 +986,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device)
break; break;
} }
snd_unregister_device(devtype, pcm->card, pcm->device); snd_unregister_device(devtype, pcm->card, pcm->device);
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);
notify->n_unregister(pcm);
} }
unlock:
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
return snd_pcm_free(pcm); return 0;
} }
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{ {
struct list_head *p; struct list_head *p;
snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); snd_assert(notify != NULL &&
notify->n_register != NULL &&
notify->n_unregister != NULL &&
notify->n_disconnect, return -EINVAL);
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
if (nfree) { if (nfree) {
list_del(&notify->list); list_del(&notify->list);
......
...@@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_rawmidi *rawmidi); ...@@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_rawmidi *rawmidi);
static int snd_rawmidi_dev_free(struct snd_device *device); static int snd_rawmidi_dev_free(struct snd_device *device);
static int snd_rawmidi_dev_register(struct snd_device *device); static int snd_rawmidi_dev_register(struct snd_device *device);
static int snd_rawmidi_dev_disconnect(struct snd_device *device); static int snd_rawmidi_dev_disconnect(struct snd_device *device);
static int snd_rawmidi_dev_unregister(struct snd_device *device);
static LIST_HEAD(snd_rawmidi_devices); static LIST_HEAD(snd_rawmidi_devices);
static DEFINE_MUTEX(register_mutex); static DEFINE_MUTEX(register_mutex);
...@@ -1426,7 +1425,6 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, ...@@ -1426,7 +1425,6 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
.dev_free = snd_rawmidi_dev_free, .dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register, .dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect, .dev_disconnect = snd_rawmidi_dev_disconnect,
.dev_unregister = snd_rawmidi_dev_unregister
}; };
snd_assert(rrawmidi != NULL, return -EINVAL); snd_assert(rrawmidi != NULL, return -EINVAL);
...@@ -1479,6 +1477,14 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) ...@@ -1479,6 +1477,14 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
static int snd_rawmidi_free(struct snd_rawmidi *rmidi) static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
{ {
snd_assert(rmidi != NULL, return -ENXIO); snd_assert(rmidi != NULL, return -ENXIO);
snd_info_free_entry(rmidi->proc_entry);
rmidi->proc_entry = NULL;
mutex_lock(&register_mutex);
if (rmidi->ops && rmidi->ops->dev_unregister)
rmidi->ops->dev_unregister(rmidi);
mutex_unlock(&register_mutex);
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
if (rmidi->private_free) if (rmidi->private_free)
...@@ -1587,21 +1593,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) ...@@ -1587,21 +1593,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
list_del_init(&rmidi->list); list_del_init(&rmidi->list);
mutex_unlock(&register_mutex);
return 0;
}
static int snd_rawmidi_dev_unregister(struct snd_device *device)
{
struct snd_rawmidi *rmidi = device->device_data;
snd_assert(rmidi != NULL, return -ENXIO);
mutex_lock(&register_mutex);
list_del(&rmidi->list);
if (rmidi->proc_entry) {
snd_info_free_entry(rmidi->proc_entry);
rmidi->proc_entry = NULL;
}
#ifdef CONFIG_SND_OSSEMUL #ifdef CONFIG_SND_OSSEMUL
if (rmidi->ossreg) { if (rmidi->ossreg) {
if ((int)rmidi->device == midi_map[rmidi->card->number]) { if ((int)rmidi->device == midi_map[rmidi->card->number]) {
...@@ -1615,17 +1606,9 @@ static int snd_rawmidi_dev_unregister(struct snd_device *device) ...@@ -1615,17 +1606,9 @@ static int snd_rawmidi_dev_unregister(struct snd_device *device)
rmidi->ossreg = 0; rmidi->ossreg = 0;
} }
#endif /* CONFIG_SND_OSSEMUL */ #endif /* CONFIG_SND_OSSEMUL */
if (rmidi->ops && rmidi->ops->dev_unregister)
rmidi->ops->dev_unregister(rmidi);
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) return 0;
if (rmidi->seq_dev) {
snd_device_free(rmidi->card, rmidi->seq_dev);
rmidi->seq_dev = NULL;
}
#endif
return snd_rawmidi_free(rmidi);
} }
/** /**
......
...@@ -156,7 +156,7 @@ static int __init rtctimer_init(void) ...@@ -156,7 +156,7 @@ static int __init rtctimer_init(void)
static void __exit rtctimer_exit(void) static void __exit rtctimer_exit(void)
{ {
if (rtctimer) { if (rtctimer) {
snd_timer_global_unregister(rtctimer); snd_timer_global_free(rtctimer);
rtctimer = NULL; rtctimer = NULL;
} }
} }
......
...@@ -90,7 +90,6 @@ static int snd_seq_device_free(struct snd_seq_device *dev); ...@@ -90,7 +90,6 @@ static int snd_seq_device_free(struct snd_seq_device *dev);
static int snd_seq_device_dev_free(struct snd_device *device); static int snd_seq_device_dev_free(struct snd_device *device);
static int snd_seq_device_dev_register(struct snd_device *device); static int snd_seq_device_dev_register(struct snd_device *device);
static int snd_seq_device_dev_disconnect(struct snd_device *device); static int snd_seq_device_dev_disconnect(struct snd_device *device);
static int snd_seq_device_dev_unregister(struct snd_device *device);
static int init_device(struct snd_seq_device *dev, struct ops_list *ops); static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
static int free_device(struct snd_seq_device *dev, struct ops_list *ops); static 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,7 +188,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
.dev_free = snd_seq_device_dev_free, .dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register, .dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect, .dev_disconnect = snd_seq_device_dev_disconnect,
.dev_unregister = snd_seq_device_dev_unregister
}; };
if (result) if (result)
...@@ -308,15 +306,6 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) ...@@ -308,15 +306,6 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
return 0; return 0;
} }
/*
* unregister the existing device
*/
static int snd_seq_device_dev_unregister(struct snd_device *device)
{
struct snd_seq_device *dev = device->device_data;
return snd_seq_device_free(dev);
}
/* /*
* register device driver * register device driver
* id = driver id * id = driver id
......
...@@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex); ...@@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex);
static int snd_timer_free(struct snd_timer *timer); static int snd_timer_free(struct snd_timer *timer);
static int snd_timer_dev_free(struct snd_device *device); 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_register(struct snd_device *device);
static int snd_timer_dev_unregister(struct snd_device *device); static int snd_timer_dev_disconnect(struct snd_device *device);
static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
...@@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, ...@@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
static struct snd_device_ops ops = { static struct snd_device_ops ops = {
.dev_free = snd_timer_dev_free, .dev_free = snd_timer_dev_free,
.dev_register = snd_timer_dev_register, .dev_register = snd_timer_dev_register,
.dev_unregister = snd_timer_dev_unregister .dev_disconnect = snd_timer_dev_disconnect,
}; };
snd_assert(tid != NULL, return -EINVAL); 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, ...@@ -813,6 +813,21 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
static int snd_timer_free(struct snd_timer *timer) static int snd_timer_free(struct snd_timer *timer)
{ {
snd_assert(timer != NULL, return -ENXIO); snd_assert(timer != NULL, return -ENXIO);
mutex_lock(&register_mutex);
if (! list_empty(&timer->open_list_head)) {
struct list_head *p, *n;
struct snd_timer_instance *ti;
snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
list_for_each_safe(p, n, &timer->open_list_head) {
list_del_init(p);
ti = list_entry(p, struct snd_timer_instance, open_list);
ti->timer = NULL;
}
}
list_del(&timer->device_list);
mutex_unlock(&register_mutex);
if (timer->private_free) if (timer->private_free)
timer->private_free(timer); timer->private_free(timer);
kfree(timer); kfree(timer);
...@@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct snd_device *dev) ...@@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct snd_device *dev)
return 0; return 0;
} }
static int snd_timer_unregister(struct snd_timer *timer) static int snd_timer_dev_disconnect(struct snd_device *device)
{ {
struct list_head *p, *n; struct snd_timer *timer = device->device_data;
struct snd_timer_instance *ti;
snd_assert(timer != NULL, return -ENXIO);
mutex_lock(&register_mutex); mutex_lock(&register_mutex);
if (! list_empty(&timer->open_list_head)) { list_del_init(&timer->device_list);
snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
list_for_each_safe(p, n, &timer->open_list_head) {
list_del_init(p);
ti = list_entry(p, struct snd_timer_instance, open_list);
ti->timer = NULL;
}
}
list_del(&timer->device_list);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
return snd_timer_free(timer); return 0;
}
static int snd_timer_dev_unregister(struct snd_device *device)
{
struct snd_timer *timer = device->device_data;
return snd_timer_unregister(timer);
} }
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) void 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,11 +953,6 @@ int snd_timer_global_register(struct snd_timer *timer)
return snd_timer_dev_register(&dev); return snd_timer_dev_register(&dev);
} }
int snd_timer_global_unregister(struct snd_timer *timer)
{
return snd_timer_unregister(timer);
}
/* /*
* System timer * System timer
*/ */
...@@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void) ...@@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void)
/* unregister the system timer */ /* unregister the system timer */
list_for_each_safe(p, n, &snd_timer_list) { list_for_each_safe(p, n, &snd_timer_list) {
struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
snd_timer_unregister(timer); snd_timer_free(timer);
} }
snd_timer_proc_done(); snd_timer_proc_done();
#ifdef SNDRV_OSS_INFO_DEV_TIMERS #ifdef SNDRV_OSS_INFO_DEV_TIMERS
...@@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify); ...@@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify);
EXPORT_SYMBOL(snd_timer_global_new); EXPORT_SYMBOL(snd_timer_global_new);
EXPORT_SYMBOL(snd_timer_global_free); EXPORT_SYMBOL(snd_timer_global_free);
EXPORT_SYMBOL(snd_timer_global_register); EXPORT_SYMBOL(snd_timer_global_register);
EXPORT_SYMBOL(snd_timer_global_unregister);
EXPORT_SYMBOL(snd_timer_interrupt); EXPORT_SYMBOL(snd_timer_interrupt);
...@@ -1817,13 +1817,13 @@ static int snd_ac97_dev_register(struct snd_device *device) ...@@ -1817,13 +1817,13 @@ static int snd_ac97_dev_register(struct snd_device *device)
return 0; return 0;
} }
/* unregister ac97 codec */ /* disconnect ac97 codec */
static int snd_ac97_dev_unregister(struct snd_device *device) static int snd_ac97_dev_disconnect(struct snd_device *device)
{ {
struct snd_ac97 *ac97 = device->device_data; struct snd_ac97 *ac97 = device->device_data;
if (ac97->dev.bus) if (ac97->dev.bus)
device_unregister(&ac97->dev); device_unregister(&ac97->dev);
return snd_ac97_free(ac97); return 0;
} }
/* build_ops to do nothing */ /* build_ops to do nothing */
...@@ -1860,7 +1860,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, ...@@ -1860,7 +1860,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template,
static struct snd_device_ops ops = { static struct snd_device_ops ops = {
.dev_free = snd_ac97_dev_free, .dev_free = snd_ac97_dev_free,
.dev_register = snd_ac97_dev_register, .dev_register = snd_ac97_dev_register,
.dev_unregister = snd_ac97_dev_unregister, .dev_disconnect = snd_ac97_dev_disconnect,
}; };
snd_assert(rac97 != NULL, return -EINVAL); snd_assert(rac97 != NULL, return -EINVAL);
......
...@@ -3499,7 +3499,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) ...@@ -3499,7 +3499,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
} }
usb_chip[chip->index] = NULL; usb_chip[chip->index] = NULL;
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
snd_card_free(card); snd_card_free_when_closed(card);
} else { } else {
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment