Skip to content

Commit

Permalink
[ALSA] Unregister device files at disconnection
Browse files Browse the repository at this point in the history
Orignally proposed by Sam Revitch <[email protected]>.
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 <[email protected]>
Signed-off-by: Jaroslav Kysela <[email protected]>
  • Loading branch information
tiwai authored and Jaroslav Kysela committed Sep 23, 2006
1 parent 746d4a0 commit c461482
Show file tree
Hide file tree
Showing 15 changed files with 148 additions and 172 deletions.
3 changes: 2 additions & 1 deletion include/sound/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ struct snd_device_ops {
int (*dev_free)(struct snd_device *dev);
int (*dev_register)(struct snd_device *dev);
int (*dev_disconnect)(struct snd_device *dev);
int (*dev_unregister)(struct snd_device *dev);
};

struct snd_device {
Expand Down Expand Up @@ -131,6 +130,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;
Expand Down Expand Up @@ -244,6 +244,7 @@ struct snd_card *snd_card_new(int idx, const char *id,
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);
Expand Down
1 change: 0 additions & 1 deletion include/sound/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_free(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_close(struct snd_timer_instance *timeri);
Expand Down
27 changes: 9 additions & 18 deletions sound/core/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
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) {
Expand All @@ -1383,6 +1388,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
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;
}

Expand All @@ -1403,23 +1412,6 @@ static int snd_ctl_dev_free(struct snd_device *device)
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:
* called from init.c
Expand All @@ -1430,7 +1422,6 @@ int snd_ctl_create(struct snd_card *card)
.dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register,
.dev_disconnect = snd_ctl_dev_disconnect,
.dev_unregister = snd_ctl_dev_unregister
};

snd_assert(card != NULL, return -ENXIO);
Expand Down
20 changes: 9 additions & 11 deletions sound/core/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new);
* @device_data: the data pointer to release
*
* 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.
*
* Returns zero if successful, or a negative error code on failure or if the
Expand All @@ -90,16 +90,14 @@ int snd_device_free(struct snd_card *card, void *device_data)
continue;
/* unlink */
list_del(&dev->list);
if ((dev->state == SNDRV_DEV_REGISTERED ||
dev->state == SNDRV_DEV_DISCONNECTED) &&
dev->ops->dev_unregister) {
if (dev->ops->dev_unregister(dev))
snd_printk(KERN_ERR "device unregister failure\n");
} else {
if (dev->ops->dev_free) {
if (dev->ops->dev_free(dev))
snd_printk(KERN_ERR "device free failure\n");
}
if (dev->state == SNDRV_DEV_REGISTERED &&
dev->ops->dev_disconnect)
if (dev->ops->dev_disconnect(dev))
snd_printk(KERN_ERR
"device disconnect failure\n");
if (dev->ops->dev_free) {
if (dev->ops->dev_free(dev))
snd_printk(KERN_ERR "device free failure\n");
}
kfree(dev);
return 0;
Expand Down
10 changes: 5 additions & 5 deletions sound/core/hwdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex);
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_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)
Expand Down Expand Up @@ -353,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
static struct snd_device_ops ops = {
.dev_free = snd_hwdep_dev_free,
.dev_register = snd_hwdep_dev_register,
.dev_unregister = snd_hwdep_dev_unregister
.dev_disconnect = snd_hwdep_dev_disconnect,
};

snd_assert(rhwdep != NULL, return -EINVAL);
Expand Down Expand Up @@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device)
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;

Expand All @@ -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);
#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 snd_hwdep_free(hwdep);
return 0;
}

#ifdef CONFIG_PROC_FS
Expand Down
69 changes: 54 additions & 15 deletions sound/core/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,22 +327,10 @@ EXPORT_SYMBOL(snd_card_disconnect);
* Returns zero. Frees all associated devices and frees the control
* 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;

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);
Expand Down Expand Up @@ -371,10 +359,55 @@ int snd_card_free(struct snd_card *card)
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;
}

Expand Down Expand Up @@ -718,6 +751,7 @@ EXPORT_SYMBOL(snd_card_file_add);
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;
Expand All @@ -732,9 +766,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
pfile = mfile;
mfile = mfile->next;
}
spin_unlock(&card->files_lock);
if (card->files == NULL)
last_close = 1;
spin_unlock(&card->files_lock);
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;
Expand Down
16 changes: 7 additions & 9 deletions sound/core/oss/mixer_oss.c
Original file line number Diff line number Diff line change
Expand Up @@ -1310,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
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);
mixer->oss_dev_alloc = 0;
}
if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
return 0;
snd_mixer_oss_proc_done(mixer);
return snd_mixer_oss_free1(mixer);
}
Expand Down
16 changes: 7 additions & 9 deletions sound/core/oss/pcm_oss.c
Original file line number Diff line number Diff line change
Expand Up @@ -2929,25 +2929,23 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
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);
#endif
}
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);
snd_pcm_oss_proc_done(pcm);
return 0;
}

static struct snd_pcm_notify snd_pcm_oss_notify =
{
.n_register = snd_pcm_oss_register_minor,
Expand Down
Loading

0 comments on commit c461482

Please sign in to comment.