forked from Minki/linux
61e77107fa
create sysfs device symlinks for snd-aoa in /sys/class/sound/controlC0 This allows hald to recognize the device as sound device. Furthermore it allows the desktop user to actually access the sound device nodes. hald and related packages will modify the acl attributes. Fixes https://bugzilla.novell.com/show_bug.cgi?id=106294 Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Olaf Hering <olaf@aepfle.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
163 lines
3.3 KiB
C
163 lines
3.3 KiB
C
/*
|
|
* Apple Onboard Audio driver core
|
|
*
|
|
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
|
|
*
|
|
* GPL v2, can be found in COPYING.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/list.h>
|
|
#include "../aoa.h"
|
|
#include "snd-aoa-alsa.h"
|
|
|
|
MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
|
|
MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
/* We allow only one fabric. This simplifies things,
|
|
* and more don't really make that much sense */
|
|
static struct aoa_fabric *fabric;
|
|
static LIST_HEAD(codec_list);
|
|
|
|
static int attach_codec_to_fabric(struct aoa_codec *c)
|
|
{
|
|
int err;
|
|
|
|
if (!try_module_get(c->owner))
|
|
return -EBUSY;
|
|
/* found_codec has to be assigned */
|
|
err = -ENOENT;
|
|
if (fabric->found_codec)
|
|
err = fabric->found_codec(c);
|
|
if (err) {
|
|
module_put(c->owner);
|
|
printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n",
|
|
c->name);
|
|
return err;
|
|
}
|
|
c->fabric = fabric;
|
|
|
|
err = 0;
|
|
if (c->init)
|
|
err = c->init(c);
|
|
if (err) {
|
|
printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name);
|
|
c->fabric = NULL;
|
|
if (fabric->remove_codec)
|
|
fabric->remove_codec(c);
|
|
module_put(c->owner);
|
|
return err;
|
|
}
|
|
if (fabric->attached_codec)
|
|
fabric->attached_codec(c);
|
|
return 0;
|
|
}
|
|
|
|
int aoa_codec_register(struct aoa_codec *codec)
|
|
{
|
|
int err = 0;
|
|
|
|
/* if there's a fabric already, we can tell if we
|
|
* will want to have this codec, so propagate error
|
|
* through. Otherwise, this will happen later... */
|
|
if (fabric)
|
|
err = attach_codec_to_fabric(codec);
|
|
if (!err)
|
|
list_add(&codec->list, &codec_list);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(aoa_codec_register);
|
|
|
|
void aoa_codec_unregister(struct aoa_codec *codec)
|
|
{
|
|
list_del(&codec->list);
|
|
if (codec->fabric && codec->exit)
|
|
codec->exit(codec);
|
|
if (fabric && fabric->remove_codec)
|
|
fabric->remove_codec(codec);
|
|
codec->fabric = NULL;
|
|
module_put(codec->owner);
|
|
}
|
|
EXPORT_SYMBOL_GPL(aoa_codec_unregister);
|
|
|
|
int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
|
|
{
|
|
struct aoa_codec *c;
|
|
int err;
|
|
|
|
/* allow querying for presence of fabric
|
|
* (i.e. do this test first!) */
|
|
if (new_fabric == fabric) {
|
|
err = -EALREADY;
|
|
goto attach;
|
|
}
|
|
if (fabric)
|
|
return -EEXIST;
|
|
if (!new_fabric)
|
|
return -EINVAL;
|
|
|
|
err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
|
|
if (err)
|
|
return err;
|
|
|
|
fabric = new_fabric;
|
|
|
|
attach:
|
|
list_for_each_entry(c, &codec_list, list) {
|
|
if (c->fabric != fabric)
|
|
attach_codec_to_fabric(c);
|
|
}
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(aoa_fabric_register);
|
|
|
|
void aoa_fabric_unregister(struct aoa_fabric *old_fabric)
|
|
{
|
|
struct aoa_codec *c;
|
|
|
|
if (fabric != old_fabric)
|
|
return;
|
|
|
|
list_for_each_entry(c, &codec_list, list) {
|
|
if (c->fabric)
|
|
aoa_fabric_unlink_codec(c);
|
|
}
|
|
|
|
aoa_alsa_cleanup();
|
|
|
|
fabric = NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
|
|
|
|
void aoa_fabric_unlink_codec(struct aoa_codec *codec)
|
|
{
|
|
if (!codec->fabric) {
|
|
printk(KERN_ERR "snd-aoa: fabric unassigned "
|
|
"in aoa_fabric_unlink_codec\n");
|
|
dump_stack();
|
|
return;
|
|
}
|
|
if (codec->exit)
|
|
codec->exit(codec);
|
|
if (codec->fabric->remove_codec)
|
|
codec->fabric->remove_codec(codec);
|
|
codec->fabric = NULL;
|
|
module_put(codec->owner);
|
|
}
|
|
EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
|
|
|
|
static int __init aoa_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void __exit aoa_exit(void)
|
|
{
|
|
aoa_alsa_cleanup();
|
|
}
|
|
|
|
module_init(aoa_init);
|
|
module_exit(aoa_exit);
|