Commit a381a7a6 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] Decentralize PM control



Modules: ALSA Core,Control Midlevel,/oss/Makefile

Remove the centralized PM control in the sound core.
Each driver is responsible to get callbacks from bus/driver now.

SND_GENERIC_DRIVER is removed together with this action.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent fd66e0d0
Loading
Loading
Loading
Loading
+0 −28
Original line number Diff line number Diff line
@@ -134,14 +134,8 @@ struct snd_card {
	wait_queue_head_t shutdown_sleep;
	struct work_struct free_workq;	/* for free in workqueue */
	struct device *dev;
#ifdef CONFIG_SND_GENERIC_DRIVER
	struct snd_generic_device *generic_dev;
#endif

#ifdef CONFIG_PM
	int (*pm_suspend)(struct snd_card *card, pm_message_t state);
	int (*pm_resume)(struct snd_card *card);
	void *pm_private_data;
	unsigned int power_state;	/* power state */
	struct semaphore power_lock;	/* power lock */
	wait_queue_head_t power_sleep;
@@ -178,22 +172,6 @@ static inline void snd_power_change_state(struct snd_card *card, unsigned int st
/* init.c */
int snd_power_wait(struct snd_card *card, unsigned int power_state, struct file *file);

int snd_card_set_pm_callback(struct snd_card *card,
			     int (*suspend)(struct snd_card *, pm_message_t),
			     int (*resume)(struct snd_card *),
			     void *private_data);
int snd_card_set_generic_pm_callback(struct snd_card *card,
				     int (*suspend)(struct snd_card *, pm_message_t),
				     int (*resume)(struct snd_card *),
				     void *private_data);
#define snd_card_set_isa_pm_callback(card,suspend,resume,data) \
	snd_card_set_generic_pm_callback(card, suspend, resume, data)
struct pci_dev;
int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state);
int snd_card_pci_resume(struct pci_dev *dev);
#define SND_PCI_PM_CALLBACKS \
	.suspend = snd_card_pci_suspend,  .resume = snd_card_pci_resume

#else /* ! CONFIG_PM */

#define snd_power_lock(card)		do { (void)(card); } while (0)
@@ -201,10 +179,6 @@ int snd_card_pci_resume(struct pci_dev *dev);
static inline int snd_power_wait(struct snd_card *card, unsigned int state, struct file *file) { return 0; }
#define snd_power_get_state(card)	SNDRV_CTL_POWER_D0
#define snd_power_change_state(card, state)	do { (void)(card); } while (0)
#define snd_card_set_pm_callback(card,suspend,resume,data)
#define snd_card_set_generic_pm_callback(card,suspend,resume,data)
#define snd_card_set_isa_pm_callback(card,suspend,resume,data)
#define SND_PCI_PM_CALLBACKS

#endif /* CONFIG_PM */

@@ -280,8 +254,6 @@ int snd_card_file_remove(struct snd_card *card, struct file *file);
#ifndef snd_card_set_dev
#define snd_card_set_dev(card,devptr) ((card)->dev = (devptr))
#endif
/* register a generic device (for ISA, etc) */
int snd_card_set_generic_dev(struct snd_card *card);

/* device.c */

+0 −4
Original line number Diff line number Diff line
@@ -133,7 +133,3 @@ config SND_DEBUG_DETECT
	help
	  Say Y here to enable extra-verbose log messages printed when
	  detecting devices.

config SND_GENERIC_DRIVER
	bool
	depends on SND
+1 −43
Original line number Diff line number Diff line
@@ -1023,36 +1023,6 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
	return 0;
}

#ifdef CONFIG_PM
/*
 * change the power state
 */
static int snd_ctl_set_power_state(struct snd_card *card, unsigned int power_state)
{
	switch (power_state) {
	case SNDRV_CTL_POWER_D0:
		if (card->power_state != power_state) {
			card->pm_resume(card);
			snd_power_change_state(card, power_state);
		}
		break;
	case SNDRV_CTL_POWER_D3hot:
		if (card->power_state != power_state) {
			card->pm_suspend(card, PMSG_SUSPEND);
			snd_power_change_state(card, power_state);
		}
		break;
	case SNDRV_CTL_POWER_D1:
	case SNDRV_CTL_POWER_D2:
	case SNDRV_CTL_POWER_D3cold:
		/* not supported yet */
	default:
		return -EINVAL;
	}
	return 0;
}
#endif

static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct snd_ctl_file *ctl;
@@ -1092,19 +1062,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
		return snd_ctl_subscribe_events(ctl, ip);
	case SNDRV_CTL_IOCTL_POWER:
		if (get_user(err, ip))
			return -EFAULT;
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;
#ifdef CONFIG_PM
		if (card->pm_suspend && card->pm_resume) {
			snd_power_lock(card);
			err = snd_ctl_set_power_state(card, err);
			snd_power_unlock(card);
		} else
#endif
			err = -ENOPROTOOPT;
		return err;
		return -ENOPROTOOPT;
	case SNDRV_CTL_IOCTL_POWER_STATE:
#ifdef CONFIG_PM
		return put_user(card->power_state, ip) ? -EFAULT : 0;
+2 −203
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@
#include <linux/ctype.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/platform_device.h>

#include <sound/core.h>
#include <sound/control.h>
@@ -229,12 +228,6 @@ int snd_card_disconnect(struct snd_card *card)
	return 0;	
}

#ifdef CONFIG_SND_GENERIC_DRIVER
static void snd_generic_device_unregister(struct snd_card *card);
#else
#define snd_generic_device_unregister(x) /*NOP*/
#endif

/**
 *  snd_card_free - frees given soundcard structure
 *  @card: soundcard structure
@@ -286,7 +279,6 @@ int snd_card_free(struct snd_card *card)
		snd_printk(KERN_WARNING "unable to free card info\n");
		/* Not fatal error */
	}
	snd_generic_device_unregister(card);
	while (card->s_f_ops) {
		s_f_ops = card->s_f_ops;
		card->s_f_ops = s_f_ops->next;
@@ -459,7 +451,8 @@ int snd_card_register(struct snd_card *card)

static struct snd_info_entry *snd_card_info_entry = NULL;

static void snd_card_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
static void snd_card_info_read(struct snd_info_entry *entry,
			       struct snd_info_buffer *buffer)
{
	int idx, count;
	struct snd_card *card;
@@ -666,97 +659,6 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
	return 0;
}

#ifdef CONFIG_SND_GENERIC_DRIVER
/*
 * generic device without a proper bus using platform_device
 * (e.g. ISA)
 */
struct snd_generic_device {
	struct platform_device pdev;
	struct snd_card *card;
};

#define get_snd_generic_card(dev)	container_of(dev, struct snd_generic_device, pdev)->card

#define SND_GENERIC_NAME	"snd_generic"

#ifdef CONFIG_PM
static int snd_generic_suspend(struct platform_device *dev, pm_message_t state);
static int snd_generic_resume(struct platform_device *dev);
#endif

/* initialized in sound.c */
struct platform_driver snd_generic_driver = {
#ifdef CONFIG_PM
	.suspend	= snd_generic_suspend,
	.resume		= snd_generic_resume,
#endif
	.driver		= {
		.name	= SND_GENERIC_NAME,
	},
};

void snd_generic_device_release(struct device *dev)
{
}

static int snd_generic_device_register(struct snd_card *card)
{
	struct snd_generic_device *dev;
	int err;

	if (card->generic_dev)
		return 0; /* already registered */

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (! dev) {
		snd_printk(KERN_ERR "can't allocate generic_device\n");
		return -ENOMEM;
	}

	dev->pdev.name = SND_GENERIC_NAME;
	dev->pdev.id = card->number;
	dev->pdev.dev.release = snd_generic_device_release;
	dev->card = card;
	if ((err = platform_device_register(&dev->pdev)) < 0) {
		kfree(dev);
		return err;
	}
	card->generic_dev = dev;
	return 0;
}

static void snd_generic_device_unregister(struct snd_card *card)
{
	struct snd_generic_device *dev = card->generic_dev;
	if (dev) {
		platform_device_unregister(&dev->pdev);
		kfree(dev);
		card->generic_dev = NULL;
	}
}

/**
 * snd_card_set_generic_dev - assign the generic device to the card
 * @card: soundcard structure
 *
 * Assigns a generic device to the card.  This function is provided as the
 * last resort, for devices without any proper bus.  Thus this won't override
 * the device already assigned to the card.
 * 
 * Returns zero if successful, or a negative error code.
 */
int snd_card_set_generic_dev(struct snd_card *card)
{
	int err;
	if ((err = snd_generic_device_register(card)) < 0)
		return err;
	if (! card->dev)
		snd_card_set_dev(card, &card->generic_dev->pdev.dev);
	return 0;
}
#endif /* CONFIG_SND_GENERIC_DRIVER */

#ifdef CONFIG_PM
/**
 *  snd_power_wait - wait until the power-state is changed.
@@ -800,107 +702,4 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state, struct file
	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(struct snd_card *card,
			     int (*suspend)(struct snd_card *, pm_message_t),
			     int (*resume)(struct snd_card *),
			     void *private_data)
{
	card->pm_suspend = suspend;
	card->pm_resume = resume;
	card->pm_private_data = private_data;
	return 0;
}

#ifdef CONFIG_SND_GENERIC_DRIVER
/* suspend/resume callbacks for snd_generic platform device */
static int snd_generic_suspend(struct platform_device *dev, pm_message_t state)
{
	struct snd_card *card;

	card = get_snd_generic_card(dev);
	if (card->power_state == SNDRV_CTL_POWER_D3hot)
		return 0;
	if (card->pm_suspend)
		card->pm_suspend(card, PMSG_SUSPEND);
	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
	return 0;
}

static int snd_generic_resume(struct platform_device *dev)
{
	struct snd_card *card;

	card = get_snd_generic_card(dev);
	if (card->power_state == SNDRV_CTL_POWER_D0)
		return 0;
	if (card->pm_resume)
		card->pm_resume(card);
	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
	return 0;
}

/**
 * snd_card_set_generic_pm_callback - set the generic power-management callbacks
 * @card: soundcard structure
 * @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.  These callbacks are called from the ALSA's common
 * PM handler and from the control API.
 */
int snd_card_set_generic_pm_callback(struct snd_card *card,
				 int (*suspend)(struct snd_card *, pm_message_t),
				 int (*resume)(struct snd_card *),
				 void *private_data)
{
	int err;
	if ((err = snd_generic_device_register(card)) < 0)
		return err;
	return snd_card_set_pm_callback(card, suspend, resume, private_data);
}
#endif /* CONFIG_SND_GENERIC_DRIVER */

#ifdef CONFIG_PCI
int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state)
{
	struct snd_card *card = pci_get_drvdata(dev);
	int err;
	if (! card || ! card->pm_suspend)
		return 0;
	if (card->power_state == SNDRV_CTL_POWER_D3hot)
		return 0;
	err = card->pm_suspend(card, PMSG_SUSPEND);
	pci_save_state(dev);
	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
	return err;
}

int snd_card_pci_resume(struct pci_dev *dev)
{
	struct snd_card *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);
	card->pm_resume(card);
	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
	return 0;
}
#endif

#endif /* CONFIG_PM */
+0 −22
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@
#include <sound/initval.h>
#include <linux/kmod.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/platform_device.h>

#define SNDRV_OS_MINORS 256

@@ -328,10 +327,6 @@ int __exit snd_minor_info_done(void)
 *  INIT PART
 */

#ifdef CONFIG_SND_GENERIC_DRIVER
extern struct platform_driver snd_generic_driver;
#endif

static int __init alsa_sound_init(void)
{
	short controlnum;
@@ -356,9 +351,6 @@ static int __init alsa_sound_init(void)
		return -ENOMEM;
	}
	snd_info_minor_register();
#ifdef CONFIG_SND_GENERIC_DRIVER
	platform_driver_register(&snd_generic_driver);
#endif
	for (controlnum = 0; controlnum < cards_limit; controlnum++)
		devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum);
#ifndef MODULE
@@ -374,9 +366,6 @@ static void __exit alsa_sound_exit(void)
	for (controlnum = 0; controlnum < cards_limit; controlnum++)
		devfs_remove("snd/controlC%d", controlnum);

#ifdef CONFIG_SND_GENERIC_DRIVER
	platform_driver_unregister(&snd_generic_driver);
#endif
	snd_info_minor_unregister();
	snd_info_done();
	if (unregister_chrdev(major, "alsa") != 0)
@@ -415,19 +404,8 @@ EXPORT_SYMBOL(snd_card_register);
EXPORT_SYMBOL(snd_component_add);
EXPORT_SYMBOL(snd_card_file_add);
EXPORT_SYMBOL(snd_card_file_remove);
#ifdef CONFIG_SND_GENERIC_DRIVER
EXPORT_SYMBOL(snd_card_set_generic_dev);
#endif
#ifdef CONFIG_PM
EXPORT_SYMBOL(snd_power_wait);
EXPORT_SYMBOL(snd_card_set_pm_callback);
#ifdef CONFIG_SND_GENERIC_DRIVER
EXPORT_SYMBOL(snd_card_set_generic_pm_callback);
#endif
#ifdef CONFIG_PCI
EXPORT_SYMBOL(snd_card_pci_suspend);
EXPORT_SYMBOL(snd_card_pci_resume);
#endif
#endif
  /* device.c */
EXPORT_SYMBOL(snd_device_new);