X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Fcore%2Finit.c;h=127f70e33b80ec1d31f18c686bf40914b6956d43;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=115065061cbea05862978e476b787ae6826442fa;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/sound/core/init.c b/sound/core/init.c index 115065061..127f70e33 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -35,7 +37,6 @@ struct snd_shutdown_f_ops { struct snd_shutdown_f_ops *next; }; -int snd_cards_count = 0; unsigned int snd_cards_lock = 0; /* locked for registering/using */ snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL}; rwlock_t snd_card_rwlock = RW_LOCK_UNLOCKED; @@ -71,7 +72,7 @@ snd_card_t *snd_card_new(int idx, const char *xid, if (extra_size < 0) extra_size = 0; - card = (snd_card_t *) snd_kcalloc(sizeof(snd_card_t) + extra_size, GFP_KERNEL); + card = kcalloc(1, sizeof(*card) + extra_size, GFP_KERNEL); if (card == NULL) return NULL; if (xid) { @@ -123,7 +124,7 @@ snd_card_t *snd_card_new(int idx, const char *xid, #endif /* the control interface cannot be accessed from the user space until */ /* snd_cards_bitmask and snd_cards are set with snd_card_register */ - if ((err = snd_ctl_register(card)) < 0) { + if ((err = snd_ctl_create(card)) < 0) { snd_printd("unable to register control minors\n"); goto __error; } @@ -136,7 +137,7 @@ snd_card_t *snd_card_new(int idx, const char *xid, return card; __error_ctl: - snd_ctl_unregister(card); + snd_device_free_all(card, SNDRV_DEV_CMD_PRE); __error: kfree(card); return NULL; @@ -215,8 +216,6 @@ int snd_card_disconnect(snd_card_t * card) /* phase 3: notify all connected devices about disconnection */ /* at this point, they cannot respond to any calls except release() */ - snd_ctl_disconnect(card); - #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_DISCONNECT); @@ -249,11 +248,16 @@ int snd_card_free(snd_card_t * card) return -EINVAL; write_lock(&snd_card_rwlock); snd_cards[card->number] = NULL; - snd_cards_count--; write_unlock(&snd_card_rwlock); #ifdef CONFIG_PM wake_up(&card->power_sleep); +#ifdef CONFIG_ISA + if (card->pm_dev) { + pm_unregister(card->pm_dev); + card->pm_dev = NULL; + } +#endif #endif /* wait, until all devices are ready for the free operation */ @@ -271,10 +275,6 @@ int snd_card_free(snd_card_t * card) snd_printk(KERN_ERR "unable to free all devices (normal)\n"); /* Fatal, but this situation should never occur */ } - if (snd_ctl_unregister(card) < 0) { - snd_printk(KERN_ERR "unable to unregister control minors\n"); - /* Not fatal error */ - } 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 */ @@ -433,7 +433,6 @@ int snd_card_register(snd_card_t * card) if (card->id[0] == '\0') choose_default_id(card); snd_cards[card->number] = card; - snd_cards_count++; write_unlock(&snd_card_rwlock); if ((err = snd_info_card_register(card)) < 0) { snd_printd("unable to create card info\n"); @@ -657,12 +656,11 @@ int snd_card_file_remove(snd_card_t *card, struct file *file) spin_unlock(&card->files_lock); if (card->files == NULL) wake_up(&card->shutdown_sleep); - if (mfile) { - kfree(mfile); - } else { + if (!mfile) { snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); return -ENOENT; } + kfree(mfile); return 0; } @@ -708,4 +706,107 @@ int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file remove_wait_queue(&card->power_sleep, &wait); return result; } + +/** + * snd_card_set_pm_callback - set the PCI power-management callbacks + * @card: soundcard structure + * @suspend: suspend callback function + * @resume: resume callback function + * @private_data: private data to pass to the callback functions + * + * Sets the power-management callback functions of the card. + * These callbacks are called from ALSA's common PCI suspend/resume + * handler and from the control API. + */ +int snd_card_set_pm_callback(snd_card_t *card, + int (*suspend)(snd_card_t *, unsigned int), + int (*resume)(snd_card_t *, unsigned int), + void *private_data) +{ + card->pm_suspend = suspend; + card->pm_resume = resume; + card->pm_private_data = private_data; + return 0; +} + +static int snd_generic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + snd_card_t *card = dev->data; + + switch (rqst) { + case PM_SUSPEND: + if (card->power_state == SNDRV_CTL_POWER_D3hot) + break; + /* FIXME: the correct state value? */ + card->pm_suspend(card, 0); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + break; + case PM_RESUME: + if (card->power_state == SNDRV_CTL_POWER_D0) + break; + /* FIXME: the correct state value? */ + card->pm_resume(card, 0); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + break; + } + return 0; +} + +/** + * snd_card_set_dev_pm_callback - set the generic power-management callbacks + * @card: soundcard structure + * @type: PM device type (PM_XXX) + * @suspend: suspend callback function + * @resume: resume callback function + * @private_data: private data to pass to the callback functions + * + * Registers the power-management and sets the lowlevel callbacks for + * the given card with the given PM type. These callbacks are called + * from the ALSA's common PM handler and from the control API. + */ +int snd_card_set_dev_pm_callback(snd_card_t *card, int type, + int (*suspend)(snd_card_t *, unsigned int), + int (*resume)(snd_card_t *, unsigned int), + void *private_data) +{ + card->pm_dev = pm_register(type, 0, snd_generic_pm_callback); + if (! card->pm_dev) + return -ENOMEM; + card->pm_dev->data = card; + snd_card_set_pm_callback(card, suspend, resume, private_data); + return 0; +} + +#ifdef CONFIG_PCI +int snd_card_pci_suspend(struct pci_dev *dev, u32 state) +{ + snd_card_t *card = pci_get_drvdata(dev); + int err; + if (! card || ! card->pm_suspend) + return 0; + if (card->power_state == SNDRV_CTL_POWER_D3hot) + return 0; + /* FIXME: correct state value? */ + err = card->pm_suspend(card, 0); + pci_save_state(dev); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + return err; +} + +int snd_card_pci_resume(struct pci_dev *dev) +{ + snd_card_t *card = pci_get_drvdata(dev); + if (! card || ! card->pm_resume) + return 0; + if (card->power_state == SNDRV_CTL_POWER_D0) + return 0; + /* restore the PCI config space */ + pci_restore_state(dev); + /* FIXME: correct state value? */ + card->pm_resume(card, 0); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + #endif /* CONFIG_PM */