aboutsummaryrefslogtreecommitdiffstats
path: root/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'core.c')
-rw-r--r--core.c369
1 files changed, 132 insertions, 237 deletions
diff --git a/core.c b/core.c
index 6fd3ab3..2c643fc 100644
--- a/core.c
+++ b/core.c
@@ -40,220 +40,36 @@ static struct snd_avirt_core core = {
static LIST_HEAD(audiopath_list);
-struct snd_avirt_audiopath_obj {
- struct kobject kobj;
- struct list_head list;
- struct snd_avirt_audiopath *path;
-};
-
-static struct kset *snd_avirt_audiopath_kset;
-static struct kobject *kobj;
-
-#define to_audiopath_obj(d) \
- container_of(d, struct snd_avirt_audiopath_obj, kobj)
-#define to_audiopath_attr(a) \
- container_of(a, struct snd_avirt_audiopath_attribute, attr)
-
-/**
- * struct snd_avirt_audiopath_attribute - access the attributes of Audio Path
- * @attr: attributes of an Audio Path
- * @show: pointer to the show function
- * @store: pointer to the store function
- */
-struct snd_avirt_audiopath_attribute {
- struct attribute attr;
- ssize_t (*show)(struct snd_avirt_audiopath_obj *d,
- struct snd_avirt_audiopath_attribute *attr, char *buf);
- ssize_t (*store)(struct snd_avirt_audiopath_obj *d,
- struct snd_avirt_audiopath_attribute *attr,
- const char *buf, size_t count);
-};
-
-/**
- * audiopath_attr_show - show function of an Audio Path
- * @kobj: pointer to kobject
- * @attr: pointer to attribute struct
- * @buf: buffer
- */
-static ssize_t audiopath_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct snd_avirt_audiopath_attribute *audiopath_attr;
- struct snd_avirt_audiopath_obj *audiopath_obj;
-
- audiopath_attr = to_audiopath_attr(attr);
- audiopath_obj = to_audiopath_obj(kobj);
-
- if (!audiopath_attr->show)
- return -EIO;
-
- return audiopath_attr->show(audiopath_obj, audiopath_attr, buf);
-}
-
/**
- * audiopath_attr_store - attribute store function of Audio Path object
- * @kobj: pointer to kobject
- * @attr: pointer to attribute struct
- * @buf: buffer
- * @len: length of buffer
+ * pcm_private_free - callback function to free private data allocated to pcm
+ * @pcm: the PCM object
*/
-static ssize_t audiopath_attr_store(struct kobject *kobj,
- struct attribute *attr, const char *buf,
- size_t len)
-{
- struct snd_avirt_audiopath_attribute *audiopath_attr;
- struct snd_avirt_audiopath_obj *audiopath_obj;
-
- audiopath_attr = to_audiopath_attr(attr);
- audiopath_obj = to_audiopath_obj(kobj);
-
- if (!audiopath_attr->store)
- return -EIO;
- return audiopath_attr->store(audiopath_obj, audiopath_attr, buf, len);
-}
-
-static const struct sysfs_ops snd_avirt_audiopath_sysfs_ops = {
- .show = audiopath_attr_show,
- .store = audiopath_attr_store,
-};
-
-/**
- * snd_avirt_audiopath_release - Audio Path release function
- * @kobj: pointer to Audio Paths's kobject
- */
-static void snd_avirt_audiopath_release(struct kobject *kobj)
-{
- struct snd_avirt_audiopath_obj *audiopath_obj = to_audiopath_obj(kobj);
-
- kfree(audiopath_obj);
-}
-
-static ssize_t
- audiopath_name_show(struct snd_avirt_audiopath_obj *audiopath_obj,
- struct snd_avirt_audiopath_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", audiopath_obj->path->name);
-}
-
-static ssize_t
- audiopath_version_show(struct snd_avirt_audiopath_obj *audiopath_obj,
- struct snd_avirt_audiopath_attribute *attr,
- char *buf)
-{
- struct snd_avirt_audiopath *audiopath = audiopath_obj->path;
-
- return sprintf(buf, "%d.%d.%d\n", audiopath->version[0],
- audiopath->version[1], audiopath->version[2]);
-}
-
-static struct snd_avirt_audiopath_attribute snd_avirt_audiopath_attrs[] = {
- __ATTR_RO(audiopath_name),
- __ATTR_RO(audiopath_version),
-};
-
-static struct attribute *snd_avirt_audiopath_def_attrs[] = {
- &snd_avirt_audiopath_attrs[0].attr,
- &snd_avirt_audiopath_attrs[1].attr,
- NULL,
-};
-
-static struct kobj_type snd_avirt_audiopath_ktype = {
- .sysfs_ops = &snd_avirt_audiopath_sysfs_ops,
- .release = snd_avirt_audiopath_release,
- .default_attrs = snd_avirt_audiopath_def_attrs,
-};
-
-/**
- * create_snd_avirt_audiopath_obj - creates an Audio Path object
- * @uid: Unique ID of the Audio Path
- *
- * This creates an Audio Path object and assigns the kset and registers
- * it with sysfs.
- * @return: Pointer to the Audio Path object or NULL if it failed.
- */
-static struct snd_avirt_audiopath_obj *
- create_snd_avirt_audiopath_obj(const char *uid)
-{
- struct snd_avirt_audiopath_obj *snd_avirt_audiopath;
- int retval;
-
- snd_avirt_audiopath = kzalloc(sizeof(*snd_avirt_audiopath), GFP_KERNEL);
- if (!snd_avirt_audiopath)
- return NULL;
- snd_avirt_audiopath->kobj.kset = snd_avirt_audiopath_kset;
- retval = kobject_init_and_add(&snd_avirt_audiopath->kobj,
- &snd_avirt_audiopath_ktype, kobj, "%s",
- uid);
- if (retval) {
- kobject_put(&snd_avirt_audiopath->kobj);
- return NULL;
- }
- kobject_uevent(&snd_avirt_audiopath->kobj, KOBJ_ADD);
- return snd_avirt_audiopath;
-}
-
-/**
- * destroy_snd_avirt_audiopath_obj - destroys an Audio Path object
- * @name: the Audio Path object
- */
-static void destroy_snd_avirt_audiopath_obj(struct snd_avirt_audiopath_obj *p)
-{
- kobject_put(&p->kobj);
-}
-
-/**
- * pcm_private_data_free - callback function to free private data allocated to pcm
- * @pcm: the PCM with private data
- */
-static void pcm_private_data_free(struct snd_pcm *pcm)
+static void pcm_private_free(struct snd_pcm *pcm)
{
struct snd_avirt_private_data *avirt_private_data;
- D_PRINTK("Issuing free to private data struct");
- if (pcm->private_data) {
- avirt_private_data = pcm->private_data;
- if (avirt_private_data->ap_private_data)
+ /* Free Audio Path private data */
+ avirt_private_data = (struct snd_avirt_private_data *)pcm->private_data;
+ if (avirt_private_data) {
+ if (avirt_private_data->ap_private_data &&
+ avirt_private_data->ap_private_free)
avirt_private_data->ap_private_free(pcm);
}
kfree(pcm->private_data);
}
-static struct snd_pcm *pcm_create(struct snd_avirt_stream *stream)
+static struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream)
{
struct snd_avirt_private_data *avirt_private_data;
- struct snd_avirt_audiopath *audiopath;
- struct snd_pcm_ops *pcm_ops, *pcm_ops_ap;
struct snd_pcm *pcm;
bool playback = false, capture = false;
int err;
- audiopath = snd_avirt_audiopath_get(stream->map);
- if (!audiopath) {
- D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map);
- return ERR_PTR(-EFAULT);
- }
-
- if (!stream->direction) {
- pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_playback_ops;
+ if (!stream->direction)
playback = true;
- } else {
- pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_capture_ops;
+ else
capture = true;
- }
- pcm_ops = &pcm_ops_avirt;
-
- /* Set PCM ops for the Audio Path*/
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, close);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, prepare);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, trigger);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, pointer);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, get_time_info);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, silence);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, copy);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, mmap);
- PCM_OPS_SET(pcm_ops_ap, &pcm_ops, ack);
/** Special case: loopback */
if (!strcmp(stream->map, "ap_loopback")) {
@@ -264,14 +80,18 @@ static struct snd_pcm *pcm_create(struct snd_avirt_stream *stream)
err = snd_pcm_new(core.card, stream->name, stream->device, playback,
capture, &pcm);
- if (err < 0)
+ if (err < 0) {
+ D_ERRORK("Failed to create PCM device for stream: '%s'",
+ stream->name);
return ERR_PTR(err);
+ }
/** Register driver callbacks */
if (playback)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ stream->pcm_ops);
if (capture)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, stream->pcm_ops);
pcm->info_flags = 0;
strcpy(pcm->name, stream->name);
@@ -279,11 +99,66 @@ static struct snd_pcm *pcm_create(struct snd_avirt_stream *stream)
avirt_private_data = kzalloc(sizeof(*avirt_private_data), GFP_KERNEL);
pcm->private_data = avirt_private_data;
// Set the private free function for the private user data
- pcm->private_free = pcm_private_data_free;
+ pcm->private_free = pcm_private_free;
+
+ snd_device_register(core.card, pcm);
return pcm;
}
+int snd_avirt_stream_set_map(struct snd_avirt_stream *stream, const char *map)
+{
+ struct snd_avirt_audiopath *audiopath;
+ struct snd_pcm_ops *pcm_ops_ap;
+
+ /* If already sealed, we cannot create the stream */
+ if (snd_avirt_streams_sealed()) {
+ D_ERRORK("Streams already sealed. Cannot set map: '%s'", map);
+ return -EPERM;
+ }
+
+ if (!strcmp(stream->map, map))
+ return -1;
+
+ memcpy(stream->map, (char *)map, strlen(map));
+ audiopath = snd_avirt_audiopath_get(map);
+ if (!audiopath) {
+ D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map);
+ return -EFAULT;
+ }
+
+ if (!stream->direction)
+ pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_playback_ops;
+ else
+ pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_capture_ops;
+
+ if (!pcm_ops_ap) {
+ D_ERRORK("No PCM ops for direction '%s' for Audio Path: %s",
+ (stream->direction) ? "capture" : "playback",
+ stream->map);
+ return -EFAULT;
+ }
+
+ /* Set PCM ops for the Audio Path*/
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, prepare);
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, trigger);
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, pointer);
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, get_time_info);
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, silence);
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, copy);
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, mmap);
+ PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, ack);
+
+ /* If not created, create the PCM device now */
+ if (!stream->pcm) {
+ stream->pcm = snd_avirt_pcm_create(stream);
+ if (IS_ERR_OR_NULL(stream->pcm))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
static int snd_avirt_streams_get(const char *map,
struct snd_avirt_stream_array *stream_array)
{
@@ -311,14 +186,14 @@ struct snd_avirt_audiopath *snd_avirt_audiopath_get(const char *uid)
{
struct snd_avirt_audiopath_obj *ap_obj;
- list_for_each_entry(ap_obj, &audiopath_list, list) {
- // pr_info("get_ap %s\n", ap_obj->path->uid);
+ list_for_each_entry (ap_obj, &audiopath_list, list) {
if (!strcmp(ap_obj->path->uid, uid))
return ap_obj->path;
}
return NULL;
}
+EXPORT_SYMBOL_GPL(snd_avirt_audiopath_get);
/**
* snd_avirt_audiopath_register - register Audio Path with AVIRT
@@ -335,7 +210,7 @@ int snd_avirt_audiopath_register(struct snd_avirt_audiopath *audiopath)
return -EINVAL;
}
- audiopath_obj = create_snd_avirt_audiopath_obj(audiopath->uid);
+ audiopath_obj = snd_avirt_audiopath_create_obj(audiopath->uid);
if (!audiopath_obj) {
D_INFOK("Failed to alloc driver object");
return -ENOMEM;
@@ -380,7 +255,7 @@ int snd_avirt_audiopath_deregister(struct snd_avirt_audiopath *audiopath)
}
list_del(&audiopath_obj->list);
- destroy_snd_avirt_audiopath_obj(audiopath_obj);
+ snd_avirt_audiopath_destroy_obj(audiopath_obj);
D_INFOK("Deregistered Audio Path %s", audiopath->uid);
return 0;
@@ -388,6 +263,28 @@ int snd_avirt_audiopath_deregister(struct snd_avirt_audiopath *audiopath)
EXPORT_SYMBOL_GPL(snd_avirt_audiopath_deregister);
/**
+ * snd_avirt_route_create - Create audio route
+ * @name: The name designated to the audio route
+ * @direction: The PCM direction (SNDRV_PCM_STREAM_PLAYBACK or
+ * SNDRV_PCM_STREAM_CAPTURE)
+ * @return: The newly created audio route if successful, or an error pointer
+ */
+struct snd_avirt_route *snd_avirt_route_create(const char *name, int direction)
+{
+ struct snd_avirt_route *route;
+
+ route = kzalloc(sizeof(*route), GFP_KERNEL);
+ if (!route)
+ return ERR_PTR(-ENOMEM);
+
+ strcpy(route->name, name);
+ route->channels = 0;
+ route->direction = direction;
+
+ return route;
+}
+
+/**
* snd_avirt_stream_create - Create audio stream, including it's ALSA PCM device
* @name: The name designated to the audio stream
* @direction: The PCM direction (SNDRV_PCM_STREAM_PLAYBACK or
@@ -414,7 +311,16 @@ struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
stream->direction = direction;
stream->device = core.stream_count++;
- D_INFOK("name: %s device:%d", name, stream->device);
+ /* Initialize PCM ops table for this stream.
+ * Will be populated once map is known */
+ stream->pcm_ops = kzalloc(sizeof(struct snd_pcm_ops), GFP_KERNEL);
+ if (!stream->pcm_ops) {
+ D_ERRORK("Failed to allocate PCM ops table");
+ return ERR_PTR(-EFAULT);
+ }
+ memcpy(stream->pcm_ops, &pcm_ops_avirt, sizeof(struct snd_pcm_ops));
+
+ D_INFOK("name:%s device:%d", name, stream->device);
return stream;
}
@@ -423,39 +329,25 @@ int snd_avirt_streams_seal(void)
{
int err = 0, i = 0;
struct snd_avirt_audiopath_obj *ap_obj;
- struct snd_avirt_stream *stream;
struct snd_avirt_stream_array stream_array;
- struct config_item *item;
- struct list_head *entry;
if (core.streams_sealed) {
D_ERRORK("streams are already sealed!");
return -1;
}
- list_for_each(entry, &core.stream_group->cg_children) {
- item = container_of(entry, struct config_item, ci_entry);
- stream = snd_avirt_stream_from_config_item(item);
- if (!stream)
- return -EFAULT;
- stream->pcm = pcm_create(stream);
- if (IS_ERR_OR_NULL(stream->pcm))
- return (PTR_ERR(stream->pcm));
- }
-
- list_for_each_entry(ap_obj, &audiopath_list, list) {
- D_INFOK("configure() AP uid: %s", ap_obj->path->uid);
+ list_for_each_entry (ap_obj, &audiopath_list, list) {
for (i = 0; i < MAX_STREAMS; i++)
stream_array.streams[i] = NULL;
stream_array.count = 0;
- if (snd_avirt_streams_get(ap_obj->path->uid, &stream_array) > 0)
- ap_obj->path->configure(core.card, &stream_array);
- }
-
- err = snd_card_register(core.card);
- if (err < 0) {
- D_ERRORK("Sound card registration failed!");
- snd_card_free(core.card);
+ if (snd_avirt_streams_get(ap_obj->path->uid, &stream_array) <=
+ 0)
+ continue;
+
+ D_INFOK("Do configure for AP: %s streams:%d cb:%p",
+ ap_obj->path->uid, stream_array.count,
+ ap_obj->path->configure);
+ ap_obj->path->configure(core.card, &stream_array);
}
core.streams_sealed = true;
@@ -479,7 +371,7 @@ struct snd_avirt_stream *snd_avirt_stream_find_by_device(unsigned int device)
return ERR_PTR(-EINVAL);
}
- list_for_each(entry, &core.stream_group->cg_children) {
+ list_for_each (entry, &core.stream_group->cg_children) {
item = container_of(entry, struct config_item, ci_entry);
stream = snd_avirt_stream_from_config_item(item);
if (!stream)
@@ -554,27 +446,30 @@ static int __init snd_avirt_core_init(void)
return PTR_ERR(core.class);
}
- core.dev = device_create(core.class, NULL, 0, NULL, "avirtcore");
+ core.dev = device_create(core.class, NULL, 0, NULL, "core");
if (IS_ERR(core.dev)) {
err = PTR_ERR(core.dev);
goto exit_class;
}
- snd_avirt_audiopath_kset =
- kset_create_and_add("audiopaths", NULL, &core.dev->kobj);
- if (!snd_avirt_audiopath_kset) {
- err = -ENOMEM;
+ err = snd_avirt_sysfs_init(&core);
+ if (err < 0)
goto exit_class_container;
+
+ err = snd_card_register(core.card);
+ if (err < 0) {
+ D_ERRORK("Sound card registration failed!");
+ snd_card_free(core.card);
}
err = snd_avirt_configfs_init(&core);
if (err < 0)
- goto exit_kset;
+ goto exit_sysfs;
return 0;
-exit_kset:
- kset_unregister(snd_avirt_audiopath_kset);
+exit_sysfs:
+ snd_avirt_sysfs_exit(&core);
exit_class_container:
device_destroy(core.class, 0);
exit_class:
@@ -592,7 +487,7 @@ exit_platform_device:
static void __exit snd_avirt_core_exit(void)
{
snd_avirt_configfs_exit(&core);
- kset_unregister(snd_avirt_audiopath_kset);
+ snd_avirt_sysfs_exit(&core);
device_destroy(core.class, 0);
class_destroy(core.class);
platform_device_unregister(core.plat_dev);