Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[ALSA] Introduce snd_card_set_generic_dev()



ALSA Core
A new function snd_card_set_generic_dev() is introduced to add the
'generic device' support for devices without proper bus on sysfs.
It's a last resort, and should be removed in future when they have
a proper bus, instead.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6243008b
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -168,6 +168,9 @@ 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)(snd_card_t *card, pm_message_t state);
@@ -176,9 +179,6 @@ struct _snd_card {
	unsigned int power_state;	/* power state */
	struct semaphore power_lock;	/* power lock */
	wait_queue_head_t power_sleep;
#ifdef CONFIG_SND_GENERIC_PM
	struct snd_generic_device *pm_dev;	/* for ISA */
#endif
#endif

#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
@@ -348,6 +348,8 @@ int snd_card_file_remove(snd_card_t *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(snd_card_t *card);

/* device.c */

+1 −1
Original line number Diff line number Diff line
@@ -128,6 +128,6 @@ config SND_DEBUG_DETECT
	  Say Y here to enable extra-verbose log messages printed when
	  detecting devices.

config SND_GENERIC_PM
config SND_GENERIC_DRIVER
	bool
	depends on SND
+101 −84
Original line number Diff line number Diff line
@@ -226,8 +226,10 @@ int snd_card_disconnect(snd_card_t * card)
	return 0;	
}

#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
static void snd_generic_device_unregister(struct snd_generic_device *dev);
#ifdef CONFIG_SND_GENERIC_DRIVER
static void snd_generic_device_unregister(snd_card_t *card);
#else
#define snd_generic_device_unregister(x) /*NOP*/
#endif

/**
@@ -253,14 +255,7 @@ int snd_card_free(snd_card_t * card)

#ifdef CONFIG_PM
	wake_up(&card->power_sleep);
#ifdef CONFIG_SND_GENERIC_PM
	if (card->pm_dev) {
		snd_generic_device_unregister(card->pm_dev);
		card->pm_dev = NULL;
	}
#endif
#endif

	/* wait, until all devices are ready for the free operation */
	wait_event(card->shutdown_sleep, card->files == NULL);

@@ -288,6 +283,7 @@ int snd_card_free(snd_card_t * 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;
@@ -665,6 +661,96 @@ int snd_card_file_remove(snd_card_t *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;
	snd_card_t *card;
};

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

#define SND_GENERIC_NAME	"snd_generic"

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

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

void snd_generic_device_release(struct device *dev)
{
}

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

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

	dev = kcalloc(1, 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(snd_card_t *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(snd_card_t *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.
@@ -730,75 +816,7 @@ int snd_card_set_pm_callback(snd_card_t *card,
	return 0;
}

#ifdef CONFIG_SND_GENERIC_PM
/*
 * use platform_device for generic power-management without a proper bus
 * (e.g. ISA)
 */
struct snd_generic_device {
	struct platform_device pdev;
	snd_card_t *card;
};

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

#define SND_GENERIC_NAME	"snd_generic_pm"

static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level);
static int snd_generic_resume(struct device *dev, u32 level);

static struct device_driver snd_generic_driver = {
	.name		= SND_GENERIC_NAME,
	.bus		= &platform_bus_type,
	.suspend	= snd_generic_suspend,
	.resume		= snd_generic_resume,
};

static int generic_driver_registered;

static void generic_driver_unregister(void)
{
	if (generic_driver_registered) {
		generic_driver_registered--;
		if (! generic_driver_registered)
			driver_unregister(&snd_generic_driver);
	}
}

static struct snd_generic_device *snd_generic_device_register(snd_card_t *card)
{
	struct snd_generic_device *dev;

	if (! generic_driver_registered) {
		if (driver_register(&snd_generic_driver) < 0)
			return NULL;
	}
	generic_driver_registered++;

	dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
	if (! dev) {
		generic_driver_unregister();
		return NULL;
	}

	dev->pdev.name = SND_GENERIC_NAME;
	dev->pdev.id = card->number;
	dev->card = card;
	if (platform_device_register(&dev->pdev) < 0) {
		kfree(dev);
		generic_driver_unregister();
		return NULL;
	}
	return dev;
}

static void snd_generic_device_unregister(struct snd_generic_device *dev)
{
	platform_device_unregister(&dev->pdev);
	kfree(dev);
	generic_driver_unregister();
}

#ifdef CONFIG_SND_GENERIC_DRIVER
/* suspend/resume callbacks for snd_generic platform device */
static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level)
{
@@ -846,13 +864,12 @@ int snd_card_set_generic_pm_callback(snd_card_t *card,
				 int (*resume)(snd_card_t *),
				 void *private_data)
{
	card->pm_dev = snd_generic_device_register(card);
	if (! card->pm_dev)
		return -ENOMEM;
	snd_card_set_pm_callback(card, suspend, resume, private_data);
	return 0;
	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_PM */
#endif /* CONFIG_SND_GENERIC_DRIVER */

#ifdef CONFIG_PCI
int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state)
+14 −1
Original line number Diff line number Diff line
@@ -328,6 +328,10 @@ int __exit snd_minor_info_done(void)
 *  INIT PART
 */

#ifdef CONFIG_SND_GENERIC_DRIVER
extern struct device_driver snd_generic_driver;
#endif

static int __init alsa_sound_init(void)
{
	short controlnum;
@@ -354,6 +358,9 @@ static int __init alsa_sound_init(void)
		return -ENOMEM;
	}
	snd_info_minor_register();
#ifdef CONFIG_SND_GENERIC_DRIVER
	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
@@ -369,6 +376,9 @@ 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
	driver_unregister(&snd_generic_driver);
#endif
	snd_info_minor_unregister();
	snd_info_done();
	snd_memory_done();
@@ -416,10 +426,13 @@ 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);
#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
#ifdef CONFIG_SND_GENERIC_DRIVER
EXPORT_SYMBOL(snd_card_set_generic_pm_callback);
#endif
#ifdef CONFIG_PCI